feat(Phase1): Implement Scout API, Stripe Webhooks, and Builder Whitelisting
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 7s
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 7s
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
"next": "16.2.7",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"stripe": "^22.2.0",
|
||||
"zod": "^3.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -7,10 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
Decimal,
|
||||
DbNull,
|
||||
JsonNull,
|
||||
AnyNull,
|
||||
NullTypes,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Public,
|
||||
getRuntime,
|
||||
@@ -24,12 +21,12 @@ exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 7.8.0
|
||||
* Query Engine version: 3c6e192761c0362d496ed980de936e2f3cebcd3a
|
||||
* Prisma Client JS version: 6.19.3
|
||||
* Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "7.8.0",
|
||||
engine: "3c6e192761c0362d496ed980de936e2f3cebcd3a"
|
||||
client: "6.19.3",
|
||||
engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = () => {
|
||||
@@ -101,11 +98,15 @@ In case this error is unexpected for you, please report it in https://pris.ly/pr
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = DbNull
|
||||
Prisma.JsonNull = JsonNull
|
||||
Prisma.AnyNull = AnyNull
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = NullTypes
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -134,14 +135,18 @@ exports.Prisma.TaskScalarFieldEnum = {
|
||||
required_stack: 'required_stack',
|
||||
retry_count: 'retry_count',
|
||||
stripe_payment_intent_id: 'stripe_payment_intent_id',
|
||||
stripe_checkout_session_id: 'stripe_checkout_session_id',
|
||||
expires_at: 'expires_at',
|
||||
created_at: 'created_at',
|
||||
updated_at: 'updated_at'
|
||||
updated_at: 'updated_at',
|
||||
scout_id: 'scout_id',
|
||||
builder_id: 'builder_id'
|
||||
};
|
||||
|
||||
exports.Prisma.ClaimScalarFieldEnum = {
|
||||
id: 'id',
|
||||
task_id: 'task_id',
|
||||
agent_id: 'agent_id',
|
||||
developer_wallet: 'developer_wallet',
|
||||
status: 'status',
|
||||
claim_token: 'claim_token',
|
||||
@@ -202,6 +207,16 @@ exports.Prisma.LedgerEntryScalarFieldEnum = {
|
||||
updated_at: 'updated_at'
|
||||
};
|
||||
|
||||
exports.Prisma.AgentProfileScalarFieldEnum = {
|
||||
id: 'id',
|
||||
agent_id: 'agent_id',
|
||||
type: 'type',
|
||||
wallet_address: 'wallet_address',
|
||||
status: 'status',
|
||||
created_at: 'created_at',
|
||||
updated_at: 'updated_at'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
@@ -239,7 +254,8 @@ exports.Prisma.ModelName = {
|
||||
Submission: 'Submission',
|
||||
JudgeResult: 'JudgeResult',
|
||||
AuditEvent: 'AuditEvent',
|
||||
LedgerEntry: 'LedgerEntry'
|
||||
LedgerEntry: 'LedgerEntry',
|
||||
AgentProfile: 'AgentProfile'
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
2673
apps/web/prisma/generated/client/index.d.ts
vendored
2673
apps/web/prisma/generated/client/index.d.ts
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
BIN
apps/web/prisma/generated/client/libquery_engine-darwin-arm64.dylib.node
Executable file
BIN
apps/web/prisma/generated/client/libquery_engine-darwin-arm64.dylib.node
Executable file
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "prisma-client-e5a0d29448aef14ee47356f474ec26ee939c82359a834a5929b1331dfd872836",
|
||||
"name": "prisma-client-3cb8d001424c53952725f92eb8ceb9df5c6eed9994572f107c72f10a31e6bf6d",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"browser": "default.js",
|
||||
@@ -7,17 +7,17 @@
|
||||
"./client": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./edge.js",
|
||||
"workerd": "./edge.js",
|
||||
"worker": "./edge.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./edge.js",
|
||||
"workerd": "./edge.js",
|
||||
"worker": "./edge.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
@@ -27,22 +27,34 @@
|
||||
".": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./edge.js",
|
||||
"workerd": "./edge.js",
|
||||
"worker": "./edge.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./edge.js",
|
||||
"workerd": "./edge.js",
|
||||
"worker": "./edge.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./edge": {
|
||||
"types": "./edge.d.ts",
|
||||
"require": "./edge.js",
|
||||
"import": "./edge.js",
|
||||
"default": "./edge.js"
|
||||
},
|
||||
"./react-native": {
|
||||
"types": "./react-native.d.ts",
|
||||
"require": "./react-native.js",
|
||||
"import": "./react-native.js",
|
||||
"default": "./react-native.js"
|
||||
},
|
||||
"./extension": {
|
||||
"types": "./extension.d.ts",
|
||||
"require": "./extension.js",
|
||||
@@ -61,11 +73,11 @@
|
||||
"import": "./index.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./edge": {
|
||||
"types": "./edge.d.ts",
|
||||
"require": "./edge.js",
|
||||
"import": "./edge.js",
|
||||
"default": "./edge.js"
|
||||
"./wasm": {
|
||||
"types": "./wasm.d.ts",
|
||||
"require": "./wasm.js",
|
||||
"import": "./wasm.mjs",
|
||||
"default": "./wasm.mjs"
|
||||
},
|
||||
"./runtime/client": {
|
||||
"types": "./runtime/client.d.ts",
|
||||
@@ -77,12 +89,42 @@
|
||||
"import": "./runtime/client.mjs",
|
||||
"default": "./runtime/client.mjs"
|
||||
},
|
||||
"./runtime/library": {
|
||||
"types": "./runtime/library.d.ts",
|
||||
"require": "./runtime/library.js",
|
||||
"import": "./runtime/library.mjs",
|
||||
"default": "./runtime/library.mjs"
|
||||
},
|
||||
"./runtime/binary": {
|
||||
"types": "./runtime/binary.d.ts",
|
||||
"require": "./runtime/binary.js",
|
||||
"import": "./runtime/binary.mjs",
|
||||
"default": "./runtime/binary.mjs"
|
||||
},
|
||||
"./runtime/wasm-engine-edge": {
|
||||
"types": "./runtime/wasm-engine-edge.d.ts",
|
||||
"require": "./runtime/wasm-engine-edge.js",
|
||||
"import": "./runtime/wasm-engine-edge.mjs",
|
||||
"default": "./runtime/wasm-engine-edge.mjs"
|
||||
},
|
||||
"./runtime/wasm-compiler-edge": {
|
||||
"types": "./runtime/wasm-compiler-edge.d.ts",
|
||||
"require": "./runtime/wasm-compiler-edge.js",
|
||||
"import": "./runtime/wasm-compiler-edge.mjs",
|
||||
"default": "./runtime/wasm-compiler-edge.mjs"
|
||||
},
|
||||
"./runtime/edge": {
|
||||
"types": "./runtime/edge.d.ts",
|
||||
"require": "./runtime/edge.js",
|
||||
"import": "./runtime/edge-esm.js",
|
||||
"default": "./runtime/edge-esm.js"
|
||||
},
|
||||
"./runtime/react-native": {
|
||||
"types": "./runtime/react-native.d.ts",
|
||||
"require": "./runtime/react-native.js",
|
||||
"import": "./runtime/react-native.js",
|
||||
"default": "./runtime/react-native.js"
|
||||
},
|
||||
"./runtime/index-browser": {
|
||||
"types": "./runtime/index-browser.d.ts",
|
||||
"require": "./runtime/index-browser.js",
|
||||
@@ -109,13 +151,10 @@
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"version": "7.8.0",
|
||||
"version": "6.19.3",
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"@prisma/client-runtime-utils": "7.8.0"
|
||||
},
|
||||
"imports": {
|
||||
"#wasm-compiler-loader": {
|
||||
"#wasm-engine-loader": {
|
||||
"edge-light": "./wasm-edge-light-loader.mjs",
|
||||
"workerd": "./wasm-worker-loader.mjs",
|
||||
"worker": "./wasm-worker-loader.mjs",
|
||||
@@ -124,17 +163,17 @@
|
||||
"#main-entry-point": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./edge.js",
|
||||
"workerd": "./edge.js",
|
||||
"worker": "./edge.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./edge.js",
|
||||
"workerd": "./edge.js",
|
||||
"worker": "./edge.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
|
||||
2
apps/web/prisma/generated/client/query_engine_bg.js
Normal file
2
apps/web/prisma/generated/client/query_engine_bg.js
Normal file
File diff suppressed because one or more lines are too long
BIN
apps/web/prisma/generated/client/query_engine_bg.wasm
Normal file
BIN
apps/web/prisma/generated/client/query_engine_bg.wasm
Normal file
Binary file not shown.
35
apps/web/prisma/generated/client/runtime/edge-esm.js
Normal file
35
apps/web/prisma/generated/client/runtime/edge-esm.js
Normal file
File diff suppressed because one or more lines are too long
35
apps/web/prisma/generated/client/runtime/edge.js
Normal file
35
apps/web/prisma/generated/client/runtime/edge.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,14 +1,6 @@
|
||||
import { AnyNull } from '@prisma/client-runtime-utils';
|
||||
import { DbNull } from '@prisma/client-runtime-utils';
|
||||
import { Decimal } from '@prisma/client-runtime-utils';
|
||||
import { isAnyNull } from '@prisma/client-runtime-utils';
|
||||
import { isDbNull } from '@prisma/client-runtime-utils';
|
||||
import { isJsonNull } from '@prisma/client-runtime-utils';
|
||||
import { isObjectEnumValue } from '@prisma/client-runtime-utils';
|
||||
import { JsonNull } from '@prisma/client-runtime-utils';
|
||||
import { NullTypes } from '@prisma/client-runtime-utils';
|
||||
|
||||
export { AnyNull }
|
||||
declare class AnyNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
declare type Args<T, F extends Operation> = T extends {
|
||||
[K: symbol]: {
|
||||
@@ -22,9 +14,278 @@ declare type Args<T, F extends Operation> = T extends {
|
||||
};
|
||||
} ? T[symbol]['types']['operations'][F]['args'] : any;
|
||||
|
||||
export { DbNull }
|
||||
declare class DbNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
export { Decimal }
|
||||
export declare function Decimal(n: Decimal.Value): Decimal;
|
||||
|
||||
export declare namespace Decimal {
|
||||
export type Constructor = typeof Decimal;
|
||||
export type Instance = Decimal;
|
||||
export type Rounding = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||
export type Modulo = Rounding | 9;
|
||||
export type Value = string | number | Decimal;
|
||||
|
||||
// http://mikemcl.github.io/decimal.js/#constructor-properties
|
||||
export interface Config {
|
||||
precision?: number;
|
||||
rounding?: Rounding;
|
||||
toExpNeg?: number;
|
||||
toExpPos?: number;
|
||||
minE?: number;
|
||||
maxE?: number;
|
||||
crypto?: boolean;
|
||||
modulo?: Modulo;
|
||||
defaults?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export declare class Decimal {
|
||||
readonly d: number[];
|
||||
readonly e: number;
|
||||
readonly s: number;
|
||||
|
||||
constructor(n: Decimal.Value);
|
||||
|
||||
absoluteValue(): Decimal;
|
||||
abs(): Decimal;
|
||||
|
||||
ceil(): Decimal;
|
||||
|
||||
clampedTo(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
clamp(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
|
||||
comparedTo(n: Decimal.Value): number;
|
||||
cmp(n: Decimal.Value): number;
|
||||
|
||||
cosine(): Decimal;
|
||||
cos(): Decimal;
|
||||
|
||||
cubeRoot(): Decimal;
|
||||
cbrt(): Decimal;
|
||||
|
||||
decimalPlaces(): number;
|
||||
dp(): number;
|
||||
|
||||
dividedBy(n: Decimal.Value): Decimal;
|
||||
div(n: Decimal.Value): Decimal;
|
||||
|
||||
dividedToIntegerBy(n: Decimal.Value): Decimal;
|
||||
divToInt(n: Decimal.Value): Decimal;
|
||||
|
||||
equals(n: Decimal.Value): boolean;
|
||||
eq(n: Decimal.Value): boolean;
|
||||
|
||||
floor(): Decimal;
|
||||
|
||||
greaterThan(n: Decimal.Value): boolean;
|
||||
gt(n: Decimal.Value): boolean;
|
||||
|
||||
greaterThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
gte(n: Decimal.Value): boolean;
|
||||
|
||||
hyperbolicCosine(): Decimal;
|
||||
cosh(): Decimal;
|
||||
|
||||
hyperbolicSine(): Decimal;
|
||||
sinh(): Decimal;
|
||||
|
||||
hyperbolicTangent(): Decimal;
|
||||
tanh(): Decimal;
|
||||
|
||||
inverseCosine(): Decimal;
|
||||
acos(): Decimal;
|
||||
|
||||
inverseHyperbolicCosine(): Decimal;
|
||||
acosh(): Decimal;
|
||||
|
||||
inverseHyperbolicSine(): Decimal;
|
||||
asinh(): Decimal;
|
||||
|
||||
inverseHyperbolicTangent(): Decimal;
|
||||
atanh(): Decimal;
|
||||
|
||||
inverseSine(): Decimal;
|
||||
asin(): Decimal;
|
||||
|
||||
inverseTangent(): Decimal;
|
||||
atan(): Decimal;
|
||||
|
||||
isFinite(): boolean;
|
||||
|
||||
isInteger(): boolean;
|
||||
isInt(): boolean;
|
||||
|
||||
isNaN(): boolean;
|
||||
|
||||
isNegative(): boolean;
|
||||
isNeg(): boolean;
|
||||
|
||||
isPositive(): boolean;
|
||||
isPos(): boolean;
|
||||
|
||||
isZero(): boolean;
|
||||
|
||||
lessThan(n: Decimal.Value): boolean;
|
||||
lt(n: Decimal.Value): boolean;
|
||||
|
||||
lessThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
lte(n: Decimal.Value): boolean;
|
||||
|
||||
logarithm(n?: Decimal.Value): Decimal;
|
||||
log(n?: Decimal.Value): Decimal;
|
||||
|
||||
minus(n: Decimal.Value): Decimal;
|
||||
sub(n: Decimal.Value): Decimal;
|
||||
|
||||
modulo(n: Decimal.Value): Decimal;
|
||||
mod(n: Decimal.Value): Decimal;
|
||||
|
||||
naturalExponential(): Decimal;
|
||||
exp(): Decimal;
|
||||
|
||||
naturalLogarithm(): Decimal;
|
||||
ln(): Decimal;
|
||||
|
||||
negated(): Decimal;
|
||||
neg(): Decimal;
|
||||
|
||||
plus(n: Decimal.Value): Decimal;
|
||||
add(n: Decimal.Value): Decimal;
|
||||
|
||||
precision(includeZeros?: boolean): number;
|
||||
sd(includeZeros?: boolean): number;
|
||||
|
||||
round(): Decimal;
|
||||
|
||||
sine() : Decimal;
|
||||
sin() : Decimal;
|
||||
|
||||
squareRoot(): Decimal;
|
||||
sqrt(): Decimal;
|
||||
|
||||
tangent() : Decimal;
|
||||
tan() : Decimal;
|
||||
|
||||
times(n: Decimal.Value): Decimal;
|
||||
mul(n: Decimal.Value) : Decimal;
|
||||
|
||||
toBinary(significantDigits?: number): string;
|
||||
toBinary(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toDecimalPlaces(decimalPlaces?: number): Decimal;
|
||||
toDecimalPlaces(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
toDP(decimalPlaces?: number): Decimal;
|
||||
toDP(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toExponential(decimalPlaces?: number): string;
|
||||
toExponential(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFixed(decimalPlaces?: number): string;
|
||||
toFixed(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFraction(max_denominator?: Decimal.Value): Decimal[];
|
||||
|
||||
toHexadecimal(significantDigits?: number): string;
|
||||
toHexadecimal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
toHex(significantDigits?: number): string;
|
||||
toHex(significantDigits: number, rounding?: Decimal.Rounding): string;
|
||||
|
||||
toJSON(): string;
|
||||
|
||||
toNearest(n: Decimal.Value, rounding?: Decimal.Rounding): Decimal;
|
||||
|
||||
toNumber(): number;
|
||||
|
||||
toOctal(significantDigits?: number): string;
|
||||
toOctal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toPower(n: Decimal.Value): Decimal;
|
||||
pow(n: Decimal.Value): Decimal;
|
||||
|
||||
toPrecision(significantDigits?: number): string;
|
||||
toPrecision(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toSignificantDigits(significantDigits?: number): Decimal;
|
||||
toSignificantDigits(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
toSD(significantDigits?: number): Decimal;
|
||||
toSD(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toString(): string;
|
||||
|
||||
truncated(): Decimal;
|
||||
trunc(): Decimal;
|
||||
|
||||
valueOf(): string;
|
||||
|
||||
static abs(n: Decimal.Value): Decimal;
|
||||
static acos(n: Decimal.Value): Decimal;
|
||||
static acosh(n: Decimal.Value): Decimal;
|
||||
static add(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static asin(n: Decimal.Value): Decimal;
|
||||
static asinh(n: Decimal.Value): Decimal;
|
||||
static atan(n: Decimal.Value): Decimal;
|
||||
static atanh(n: Decimal.Value): Decimal;
|
||||
static atan2(y: Decimal.Value, x: Decimal.Value): Decimal;
|
||||
static cbrt(n: Decimal.Value): Decimal;
|
||||
static ceil(n: Decimal.Value): Decimal;
|
||||
static clamp(n: Decimal.Value, min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
static clone(object?: Decimal.Config): Decimal.Constructor;
|
||||
static config(object: Decimal.Config): Decimal.Constructor;
|
||||
static cos(n: Decimal.Value): Decimal;
|
||||
static cosh(n: Decimal.Value): Decimal;
|
||||
static div(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static exp(n: Decimal.Value): Decimal;
|
||||
static floor(n: Decimal.Value): Decimal;
|
||||
static hypot(...n: Decimal.Value[]): Decimal;
|
||||
static isDecimal(object: any): object is Decimal;
|
||||
static ln(n: Decimal.Value): Decimal;
|
||||
static log(n: Decimal.Value, base?: Decimal.Value): Decimal;
|
||||
static log2(n: Decimal.Value): Decimal;
|
||||
static log10(n: Decimal.Value): Decimal;
|
||||
static max(...n: Decimal.Value[]): Decimal;
|
||||
static min(...n: Decimal.Value[]): Decimal;
|
||||
static mod(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static mul(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static noConflict(): Decimal.Constructor; // Browser only
|
||||
static pow(base: Decimal.Value, exponent: Decimal.Value): Decimal;
|
||||
static random(significantDigits?: number): Decimal;
|
||||
static round(n: Decimal.Value): Decimal;
|
||||
static set(object: Decimal.Config): Decimal.Constructor;
|
||||
static sign(n: Decimal.Value): number;
|
||||
static sin(n: Decimal.Value): Decimal;
|
||||
static sinh(n: Decimal.Value): Decimal;
|
||||
static sqrt(n: Decimal.Value): Decimal;
|
||||
static sub(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static sum(...n: Decimal.Value[]): Decimal;
|
||||
static tan(n: Decimal.Value): Decimal;
|
||||
static tanh(n: Decimal.Value): Decimal;
|
||||
static trunc(n: Decimal.Value): Decimal;
|
||||
|
||||
static readonly default?: Decimal.Constructor;
|
||||
static readonly Decimal?: Decimal.Constructor;
|
||||
|
||||
static readonly precision: number;
|
||||
static readonly rounding: Decimal.Rounding;
|
||||
static readonly toExpNeg: number;
|
||||
static readonly toExpPos: number;
|
||||
static readonly minE: number;
|
||||
static readonly maxE: number;
|
||||
static readonly crypto: boolean;
|
||||
static readonly modulo: Decimal.Modulo;
|
||||
|
||||
static readonly ROUND_UP: 0;
|
||||
static readonly ROUND_DOWN: 1;
|
||||
static readonly ROUND_CEIL: 2;
|
||||
static readonly ROUND_FLOOR: 3;
|
||||
static readonly ROUND_HALF_UP: 4;
|
||||
static readonly ROUND_HALF_DOWN: 5;
|
||||
static readonly ROUND_HALF_EVEN: 6;
|
||||
static readonly ROUND_HALF_CEIL: 7;
|
||||
static readonly ROUND_HALF_FLOOR: 8;
|
||||
static readonly EUCLID: 9;
|
||||
}
|
||||
|
||||
declare type Exact<A, W> = (A extends unknown ? (W extends A ? {
|
||||
[K in keyof A]: Exact<A[K], W[K]>;
|
||||
@@ -38,15 +299,9 @@ declare type GetRuntimeOutput = {
|
||||
isEdge: boolean;
|
||||
};
|
||||
|
||||
export { isAnyNull }
|
||||
|
||||
export { isDbNull }
|
||||
|
||||
export { isJsonNull }
|
||||
|
||||
export { isObjectEnumValue }
|
||||
|
||||
export { JsonNull }
|
||||
declare class JsonNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates more strict variant of an enum which, unlike regular enum,
|
||||
@@ -68,7 +323,32 @@ export declare function makeStrictEnum<T extends Record<PropertyKey, string | nu
|
||||
|
||||
declare type Narrowable = string | number | bigint | boolean | [];
|
||||
|
||||
export { NullTypes }
|
||||
declare class NullTypesEnumValue extends ObjectEnumValue {
|
||||
_getNamespace(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for unique values of object-valued enums.
|
||||
*/
|
||||
declare abstract class ObjectEnumValue {
|
||||
constructor(arg?: symbol);
|
||||
abstract _getNamespace(): string;
|
||||
_getName(): string;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
export declare const objectEnumValues: {
|
||||
classes: {
|
||||
DbNull: typeof DbNull;
|
||||
JsonNull: typeof JsonNull;
|
||||
AnyNull: typeof AnyNull;
|
||||
};
|
||||
instances: {
|
||||
DbNull: DbNull;
|
||||
JsonNull: JsonNull;
|
||||
AnyNull: AnyNull;
|
||||
};
|
||||
};
|
||||
|
||||
declare type Operation = 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'findMany' | 'create' | 'createMany' | 'createManyAndReturn' | 'update' | 'updateMany' | 'updateManyAndReturn' | 'upsert' | 'delete' | 'deleteMany' | 'aggregate' | 'count' | 'groupBy' | '$queryRaw' | '$executeRaw' | '$queryRawUnsafe' | '$executeRawUnsafe' | 'findRaw' | 'aggregateRaw' | '$runCommandRaw';
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
3982
apps/web/prisma/generated/client/runtime/library.d.ts
vendored
Normal file
3982
apps/web/prisma/generated/client/runtime/library.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
147
apps/web/prisma/generated/client/runtime/library.js
Normal file
147
apps/web/prisma/generated/client/runtime/library.js
Normal file
File diff suppressed because one or more lines are too long
84
apps/web/prisma/generated/client/runtime/react-native.js
vendored
Normal file
84
apps/web/prisma/generated/client/runtime/react-native.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
38
apps/web/prisma/generated/client/runtime/wasm-engine-edge.js
Normal file
38
apps/web/prisma/generated/client/runtime/wasm-engine-edge.js
Normal file
File diff suppressed because one or more lines are too long
@@ -5,42 +5,51 @@ generator client {
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model Task {
|
||||
id String @id @default(uuid())
|
||||
title String
|
||||
description String
|
||||
status String // Enum: TaskStatus (OPEN, EXECUTING, VERIFYING, COMPLETED, FAILED, etc)
|
||||
difficulty String // Enum: TaskDifficulty (HELLO_WORLD, COMPONENT, VIEW, EPIC)
|
||||
scope_clarity_score Float
|
||||
error_classification String? // Enum: TaskErrorClassification
|
||||
reward_amount Int // Stored in cents
|
||||
reward_currency String // USD, TWD, USDC
|
||||
acceptance_criteria Json // Contains validation_mode, test_file_content, rules
|
||||
required_stack String[]
|
||||
retry_count Int @default(0)
|
||||
stripe_payment_intent_id String?
|
||||
expires_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
id String @id @default(uuid())
|
||||
title String
|
||||
description String
|
||||
status String // Enum: TaskStatus (OPEN, EXECUTING, VERIFYING, COMPLETED, FAILED, etc)
|
||||
difficulty String // Enum: TaskDifficulty (HELLO_WORLD, COMPONENT, VIEW, EPIC)
|
||||
scope_clarity_score Float
|
||||
error_classification String? // Enum: TaskErrorClassification
|
||||
reward_amount Int // Stored in cents
|
||||
reward_currency String // USD, TWD, USDC
|
||||
acceptance_criteria Json // Contains validation_mode, test_file_content, rules
|
||||
required_stack String[]
|
||||
retry_count Int @default(0)
|
||||
stripe_payment_intent_id String?
|
||||
stripe_checkout_session_id String? // Used for Scout flow
|
||||
expires_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
scout_id String?
|
||||
scout_agent AgentProfile? @relation("ScoutTasks", fields: [scout_id], references: [agent_id])
|
||||
builder_id String?
|
||||
builder_agent AgentProfile? @relation("BuilderTasks", fields: [builder_id], references: [agent_id])
|
||||
|
||||
claims Claim[]
|
||||
submissions Submission[]
|
||||
}
|
||||
|
||||
model Claim {
|
||||
id String @id @default(uuid())
|
||||
id String @id @default(uuid())
|
||||
task_id String
|
||||
task Task @relation(fields: [task_id], references: [id])
|
||||
task Task @relation(fields: [task_id], references: [id])
|
||||
agent_id String
|
||||
agent AgentProfile @relation(fields: [agent_id], references: [agent_id])
|
||||
developer_wallet String
|
||||
status String // EXECUTING, CANCELLED, VERIFYING, COMPLETED
|
||||
claim_token String @unique // Idempotency token for this claim
|
||||
claim_token String @unique // Idempotency token for this claim
|
||||
held_amount Int
|
||||
held_currency String
|
||||
expires_at DateTime
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
submissions Submission[]
|
||||
}
|
||||
@@ -99,3 +108,17 @@ model LedgerEntry {
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
}
|
||||
|
||||
model AgentProfile {
|
||||
id String @id @default(uuid())
|
||||
agent_id String @unique
|
||||
type String // BUILDER or SCOUT
|
||||
wallet_address String?
|
||||
status String // WHITELISTED, BANNED, PENDING
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
tasks_as_scout Task[] @relation("ScoutTasks")
|
||||
tasks_as_builder Task[] @relation("BuilderTasks")
|
||||
claims Claim[]
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
export default import('./query_compiler_fast_bg.wasm?module')
|
||||
export default import('./query_engine_bg.wasm?module')
|
||||
@@ -2,4 +2,4 @@
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
export default import('./query_compiler_fast_bg.wasm')
|
||||
export default import('./query_engine_bg.wasm')
|
||||
1
apps/web/prisma/generated/client/wasm.d.ts
vendored
Normal file
1
apps/web/prisma/generated/client/wasm.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./default"
|
||||
310
apps/web/prisma/generated/client/wasm.js
Normal file
310
apps/web/prisma/generated/client/wasm.js
Normal file
File diff suppressed because one or more lines are too long
@@ -22,10 +22,16 @@ model Task {
|
||||
required_stack String[]
|
||||
retry_count Int @default(0)
|
||||
stripe_payment_intent_id String?
|
||||
stripe_checkout_session_id String? // Used for Scout flow
|
||||
expires_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
scout_id String?
|
||||
scout_agent AgentProfile? @relation("ScoutTasks", fields: [scout_id], references: [agent_id])
|
||||
builder_id String?
|
||||
builder_agent AgentProfile? @relation("BuilderTasks", fields: [builder_id], references: [agent_id])
|
||||
|
||||
claims Claim[]
|
||||
submissions Submission[]
|
||||
}
|
||||
@@ -34,6 +40,8 @@ model Claim {
|
||||
id String @id @default(uuid())
|
||||
task_id String
|
||||
task Task @relation(fields: [task_id], references: [id])
|
||||
agent_id String
|
||||
agent AgentProfile @relation(fields: [agent_id], references: [agent_id])
|
||||
developer_wallet String
|
||||
status String // EXECUTING, CANCELLED, VERIFYING, COMPLETED
|
||||
claim_token String @unique // Idempotency token for this claim
|
||||
@@ -100,3 +108,17 @@ model LedgerEntry {
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
}
|
||||
|
||||
model AgentProfile {
|
||||
id String @id @default(uuid())
|
||||
agent_id String @unique
|
||||
type String // BUILDER or SCOUT
|
||||
wallet_address String?
|
||||
status String // WHITELISTED, BANNED, PENDING
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
tasks_as_scout Task[] @relation("ScoutTasks")
|
||||
tasks_as_builder Task[] @relation("BuilderTasks")
|
||||
claims Claim[]
|
||||
}
|
||||
|
||||
@@ -65,11 +65,19 @@ export async function POST(request: NextRequest, props: { params: Promise<{ tool
|
||||
|
||||
case "claim_task": {
|
||||
const parsed = ClaimTaskRequestSchema.parse(body);
|
||||
|
||||
// Verify Agent Whitelist
|
||||
const agent = await prisma.agentProfile.findUnique({
|
||||
where: { agent_id: parsed.agent_id }
|
||||
});
|
||||
if (!agent || agent.status !== "WHITELISTED") {
|
||||
return NextResponse.json({ error: "Forbidden: Agent is not whitelisted" }, { status: 403 });
|
||||
}
|
||||
|
||||
const claim = await prisma.$transaction(async (tx) => {
|
||||
const updated = await tx.task.updateMany({
|
||||
where: { id: parsed.task_id, status: TaskStatus.OPEN },
|
||||
data: { status: TaskStatus.EXECUTING }
|
||||
data: { status: TaskStatus.EXECUTING, builder_id: agent.agent_id }
|
||||
});
|
||||
|
||||
if (updated.count === 0) {
|
||||
@@ -81,6 +89,7 @@ export async function POST(request: NextRequest, props: { params: Promise<{ tool
|
||||
const newClaim = await tx.claim.create({
|
||||
data: {
|
||||
task_id: task.id,
|
||||
agent_id: agent.agent_id,
|
||||
developer_wallet: parsed.developer_wallet,
|
||||
status: TaskStatus.EXECUTING,
|
||||
claim_token: crypto.randomUUID(),
|
||||
|
||||
106
apps/web/src/app/api/scout/draft/route.ts
Normal file
106
apps/web/src/app/api/scout/draft/route.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { ScoutDraftRequestSchema, ScoutDraftResponseSchema, TaskStatus } from "@agent-bounty/contracts";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import Stripe from "stripe";
|
||||
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
||||
apiVersion: "2026-05-27.dahlia",
|
||||
});
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const authHeader = request.headers.get("Authorization");
|
||||
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||
return NextResponse.json({ error: "Unauthorized: Missing Bearer token" }, { status: 401 });
|
||||
}
|
||||
|
||||
const token = authHeader.split(" ")[1];
|
||||
if (process.env.API_KEY && token !== process.env.API_KEY) {
|
||||
return NextResponse.json({ error: "Forbidden: Invalid API Key" }, { status: 403 });
|
||||
}
|
||||
|
||||
try {
|
||||
const body = await request.json();
|
||||
const parsed = ScoutDraftRequestSchema.parse(body);
|
||||
|
||||
// Validate scout_id exists and is whitelisted
|
||||
const scout = await prisma.agentProfile.findUnique({
|
||||
where: { agent_id: parsed.scout_id }
|
||||
});
|
||||
|
||||
if (!scout || scout.status !== "WHITELISTED") {
|
||||
return NextResponse.json({ error: "Forbidden: Scout Agent is not whitelisted" }, { status: 403 });
|
||||
}
|
||||
|
||||
// Create DRAFT task
|
||||
const task = await prisma.task.create({
|
||||
data: {
|
||||
title: parsed.title,
|
||||
description: parsed.description,
|
||||
status: TaskStatus.DRAFT,
|
||||
difficulty: "COMPONENT", // Defaulting for Phase 1
|
||||
scope_clarity_score: 1.0,
|
||||
reward_amount: parsed.reward_amount,
|
||||
reward_currency: parsed.reward_currency,
|
||||
required_stack: parsed.required_stack,
|
||||
scout_id: scout.agent_id,
|
||||
acceptance_criteria: {
|
||||
validation_mode: "VITEST_UNIT",
|
||||
test_file_content: parsed.test_file_content,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Create Stripe Checkout Session
|
||||
// We do a manual capture session so the funds are only captured when Judge passes
|
||||
const session = await stripe.checkout.sessions.create({
|
||||
payment_method_types: ["card"],
|
||||
mode: "payment",
|
||||
line_items: [
|
||||
{
|
||||
price_data: {
|
||||
currency: parsed.reward_currency.toLowerCase(),
|
||||
product_data: {
|
||||
name: `VibeWork Task: ${parsed.title}`,
|
||||
description: "Auth-Hold. Funds will only be captured when task is judged PASS.",
|
||||
},
|
||||
unit_amount: parsed.reward_amount,
|
||||
},
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
payment_intent_data: {
|
||||
capture_method: "manual",
|
||||
metadata: {
|
||||
task_id: task.id,
|
||||
scout_id: scout.agent_id,
|
||||
}
|
||||
},
|
||||
// You should set these to actual frontend URLs
|
||||
success_url: `${process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'}/tasks/${task.id}?success=true`,
|
||||
cancel_url: `${process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'}/tasks/create`,
|
||||
});
|
||||
|
||||
// Save session ID so webhook can find it
|
||||
await prisma.task.update({
|
||||
where: { id: task.id },
|
||||
data: { stripe_checkout_session_id: session.id }
|
||||
});
|
||||
|
||||
const responseData = {
|
||||
task_id: task.id,
|
||||
checkout_url: session.url!,
|
||||
status: TaskStatus.DRAFT,
|
||||
};
|
||||
|
||||
ScoutDraftResponseSchema.parse(responseData); // strict output validation
|
||||
|
||||
return NextResponse.json(responseData);
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("[Scout API Error]", error);
|
||||
if (error.name === "ZodError") {
|
||||
return NextResponse.json({ error_type: "InvalidParams", message: error.errors }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ error_type: "InternalError", message: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
62
apps/web/src/app/api/webhooks/stripe/route.ts
Normal file
62
apps/web/src/app/api/webhooks/stripe/route.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import Stripe from "stripe";
|
||||
import { TaskStatus } from "@agent-bounty/contracts";
|
||||
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
||||
apiVersion: "2026-05-27.dahlia",
|
||||
});
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const payload = await request.text();
|
||||
const signature = request.headers.get("stripe-signature");
|
||||
|
||||
if (!signature || !process.env.STRIPE_WEBHOOK_SECRET) {
|
||||
return NextResponse.json({ error: "Missing signature or webhook secret" }, { status: 400 });
|
||||
}
|
||||
|
||||
let event: Stripe.Event;
|
||||
|
||||
try {
|
||||
event = stripe.webhooks.constructEvent(
|
||||
payload,
|
||||
signature,
|
||||
process.env.STRIPE_WEBHOOK_SECRET
|
||||
);
|
||||
} catch (err: any) {
|
||||
console.error(`[Webhook Error]`, err.message);
|
||||
return NextResponse.json({ error: `Webhook Error: ${err.message}` }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
if (event.type === "checkout.session.completed") {
|
||||
const session = event.data.object as Stripe.Checkout.Session;
|
||||
|
||||
const task = await prisma.task.findFirst({
|
||||
where: { stripe_checkout_session_id: session.id }
|
||||
});
|
||||
|
||||
if (!task) {
|
||||
console.error(`[Webhook] Task not found for session: ${session.id}`);
|
||||
return NextResponse.json({ received: true });
|
||||
}
|
||||
|
||||
// Payment is authorized (Auth Hold)
|
||||
// Save the payment_intent_id and set status to OPEN
|
||||
await prisma.task.update({
|
||||
where: { id: task.id },
|
||||
data: {
|
||||
stripe_payment_intent_id: session.payment_intent as string,
|
||||
status: TaskStatus.OPEN
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[Webhook] Task ${task.id} is now OPEN. Payment Intent: ${session.payment_intent}`);
|
||||
}
|
||||
|
||||
return NextResponse.json({ received: true });
|
||||
} catch (error: any) {
|
||||
console.error("[Webhook Processing Error]", error);
|
||||
return NextResponse.json({ error: "Internal Error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Prisma } from "../../prisma/generated/client";
|
||||
import Stripe from "stripe";
|
||||
|
||||
// In Phase 2, we use a Mock implementation for Stripe to ensure our DB state machine
|
||||
// and idempotency rules are solid before integrating the real Stripe SDK.
|
||||
// Initialize Stripe with the secret key from env
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
||||
apiVersion: "2026-05-27.dahlia", // Use latest or your specific API version
|
||||
});
|
||||
|
||||
export async function authHold(
|
||||
tx: Prisma.TransactionClient,
|
||||
@@ -20,17 +23,23 @@ export async function authHold(
|
||||
throw new Error(`Previous authHold failed for idempotencyKey: ${idempotencyKey}`);
|
||||
}
|
||||
|
||||
// --- MOCK STRIPE CALL ---
|
||||
// In real life: const intent = await stripe.paymentIntents.create({ amount, currency, payment_method_types: ['card'], capture_method: 'manual', metadata: { taskId, wallet } });
|
||||
const mockStripeObjectId = `pi_mock_hold_${crypto.randomUUID()}`;
|
||||
// ------------------------
|
||||
// Check if we already have a payment intent for this task
|
||||
const task = await tx.task.findUnique({ where: { id: taskId } });
|
||||
if (!task || !task.stripe_payment_intent_id) {
|
||||
throw new Error("Task does not have a stripe_payment_intent_id. It must be created via Scout checkout first.");
|
||||
}
|
||||
|
||||
// In Phase 1 real flow, the Auth Hold is done by the user before the task becomes OPEN.
|
||||
// When an AI claims the task, we don't actually create a new PaymentIntent.
|
||||
// We just verify the PaymentIntent has enough funds or is capturable.
|
||||
|
||||
// To keep it simple, we just record that the claim successfully locked the existing intent
|
||||
return await tx.ledgerEntry.create({
|
||||
data: {
|
||||
task_id: taskId,
|
||||
phase: "AUTH_HOLD",
|
||||
idempotency_key: idempotencyKey,
|
||||
stripe_object_id: mockStripeObjectId,
|
||||
stripe_object_id: task.stripe_payment_intent_id,
|
||||
response_status: "SUCCESS",
|
||||
http_status: 200,
|
||||
},
|
||||
@@ -50,27 +59,47 @@ export async function capturePayment(
|
||||
throw new Error(`Previous capturePayment failed for idempotencyKey: ${idempotencyKey}`);
|
||||
}
|
||||
|
||||
// We should find the AUTH_HOLD record to get the intent ID in real life
|
||||
const holdEntry = await tx.ledgerEntry.findFirst({
|
||||
where: { task_id: taskId, phase: "AUTH_HOLD", response_status: "SUCCESS" },
|
||||
const task = await tx.task.findUnique({ where: { id: taskId } });
|
||||
if (!task || !task.stripe_payment_intent_id) {
|
||||
throw new Error("Cannot capture without a valid stripe_payment_intent_id on the task");
|
||||
}
|
||||
|
||||
const claim = await tx.claim.findFirst({
|
||||
where: { task_id: taskId, status: "COMPLETED" },
|
||||
orderBy: { created_at: "desc" }
|
||||
});
|
||||
|
||||
if (!holdEntry || !holdEntry.stripe_object_id) {
|
||||
throw new Error("Cannot capture without a successful AUTH_HOLD");
|
||||
if (!claim) {
|
||||
throw new Error("Cannot capture without a COMPLETED claim");
|
||||
}
|
||||
|
||||
// --- MOCK STRIPE CALL ---
|
||||
// In real life: const capture = await stripe.paymentIntents.capture(holdEntry.stripe_object_id);
|
||||
const mockStripeObjectId = `ch_mock_capture_${crypto.randomUUID()}`;
|
||||
// ------------------------
|
||||
let capturedIntent;
|
||||
try {
|
||||
// Perform real Stripe capture
|
||||
capturedIntent = await stripe.paymentIntents.capture(task.stripe_payment_intent_id, undefined, {
|
||||
idempotencyKey
|
||||
});
|
||||
} catch (error: any) {
|
||||
// Record failed capture
|
||||
await tx.ledgerEntry.create({
|
||||
data: {
|
||||
task_id: taskId,
|
||||
phase: "CAPTURE",
|
||||
idempotency_key: idempotencyKey,
|
||||
stripe_object_id: task.stripe_payment_intent_id,
|
||||
response_status: "FAILED",
|
||||
http_status: error.statusCode || 500,
|
||||
},
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
return await tx.ledgerEntry.create({
|
||||
data: {
|
||||
task_id: taskId,
|
||||
phase: "CAPTURE",
|
||||
idempotency_key: idempotencyKey,
|
||||
stripe_object_id: mockStripeObjectId,
|
||||
stripe_object_id: capturedIntent.id,
|
||||
response_status: "SUCCESS",
|
||||
http_status: 200,
|
||||
},
|
||||
@@ -90,13 +119,8 @@ export async function releasePayment(
|
||||
throw new Error(`Previous releasePayment failed for idempotencyKey: ${idempotencyKey}`);
|
||||
}
|
||||
|
||||
const holdEntry = await tx.ledgerEntry.findFirst({
|
||||
where: { task_id: taskId, phase: "AUTH_HOLD", response_status: "SUCCESS" },
|
||||
orderBy: { created_at: "desc" }
|
||||
});
|
||||
|
||||
if (!holdEntry || !holdEntry.stripe_object_id) {
|
||||
// If there was no hold to begin with, releasing is a no-op but we log it as SUCCESS
|
||||
const task = await tx.task.findUnique({ where: { id: taskId } });
|
||||
if (!task || !task.stripe_payment_intent_id) {
|
||||
return await tx.ledgerEntry.create({
|
||||
data: {
|
||||
task_id: taskId,
|
||||
@@ -109,17 +133,31 @@ export async function releasePayment(
|
||||
});
|
||||
}
|
||||
|
||||
// --- MOCK STRIPE CALL ---
|
||||
// In real life: const cancel = await stripe.paymentIntents.cancel(holdEntry.stripe_object_id);
|
||||
const mockStripeObjectId = `re_mock_release_${crypto.randomUUID()}`;
|
||||
// ------------------------
|
||||
let canceledIntent;
|
||||
try {
|
||||
canceledIntent = await stripe.paymentIntents.cancel(task.stripe_payment_intent_id, undefined, {
|
||||
idempotencyKey
|
||||
});
|
||||
} catch (error: any) {
|
||||
await tx.ledgerEntry.create({
|
||||
data: {
|
||||
task_id: taskId,
|
||||
phase: "RELEASE",
|
||||
idempotency_key: idempotencyKey,
|
||||
stripe_object_id: task.stripe_payment_intent_id,
|
||||
response_status: "FAILED",
|
||||
http_status: error.statusCode || 500,
|
||||
},
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
return await tx.ledgerEntry.create({
|
||||
data: {
|
||||
task_id: taskId,
|
||||
phase: "RELEASE",
|
||||
idempotency_key: idempotencyKey,
|
||||
stripe_object_id: mockStripeObjectId,
|
||||
stripe_object_id: canceledIntent.id,
|
||||
response_status: "SUCCESS",
|
||||
http_status: 200,
|
||||
},
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
* ARCHIVED → (終態)
|
||||
*/
|
||||
export const TaskStatus = {
|
||||
DRAFT: "DRAFT",
|
||||
OPEN: "OPEN",
|
||||
EXECUTING: "EXECUTING",
|
||||
VERIFYING: "VERIFYING",
|
||||
|
||||
@@ -82,6 +82,7 @@ export const TaskBountySchema = z.object({
|
||||
title: z.string().min(5).max(120),
|
||||
description: z.string().min(20).max(2000),
|
||||
status: z.enum([
|
||||
TaskStatus.DRAFT,
|
||||
TaskStatus.OPEN,
|
||||
TaskStatus.EXECUTING,
|
||||
TaskStatus.VERIFYING,
|
||||
@@ -137,6 +138,7 @@ export const TaskBountySchema = z.object({
|
||||
|
||||
export const ClaimTaskRequestSchema = z.object({
|
||||
task_id: UUIDSchema,
|
||||
agent_id: z.string().min(1, "必須提供 agent_id 進行白名單驗證"),
|
||||
/** Agent 收款錢包(Stripe Connect account 或 EVM 地址) */
|
||||
developer_wallet: z
|
||||
.string()
|
||||
@@ -286,9 +288,25 @@ export const SettlementLedgerEntrySchema = z.object({
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Lead Schema(Scout 導流任務草案)
|
||||
// Scout Draft / Lead Schemas
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
export const ScoutDraftRequestSchema = z.object({
|
||||
scout_id: z.string().min(1, "必須提供 scout_id 進行歸因"),
|
||||
title: z.string().min(5).max(120),
|
||||
description: z.string().min(20).max(2000),
|
||||
reward_amount: MoneyAmountSchema,
|
||||
reward_currency: z.enum([SupportedCurrency.USD, SupportedCurrency.TWD]),
|
||||
required_stack: z.array(z.string()).default(["React", "Tailwind CSS"]),
|
||||
test_file_content: z.string().min(20, "必須提供測試檔以便自動驗收"),
|
||||
});
|
||||
|
||||
export const ScoutDraftResponseSchema = z.object({
|
||||
task_id: UUIDSchema,
|
||||
checkout_url: z.string().url(),
|
||||
status: z.literal(TaskStatus.DRAFT),
|
||||
});
|
||||
|
||||
export const LeadSchema = z.object({
|
||||
lead_id: UUIDSchema,
|
||||
scout_agent_id: z.string().optional(),
|
||||
|
||||
32
pnpm-lock.yaml
generated
32
pnpm-lock.yaml
generated
@@ -35,6 +35,9 @@ importers:
|
||||
react-dom:
|
||||
specifier: 19.2.4
|
||||
version: 19.2.4(react@19.2.4)
|
||||
stripe:
|
||||
specifier: ^22.2.0
|
||||
version: 22.2.0(@types/node@20.19.42)
|
||||
zod:
|
||||
specifier: ^3.23.0
|
||||
version: 3.25.76
|
||||
@@ -2583,6 +2586,15 @@ packages:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
stripe@22.2.0:
|
||||
resolution: {integrity: sha512-WFGpMOom9QZqso1kcnSwJsCdC1QHDlMoCOxBZRf3JraMzhkfw7dgSdD2a1CFZrqC+mzAfqeEtYILrZhWKIDruA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
styled-jsx@5.1.6:
|
||||
resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
@@ -4182,8 +4194,8 @@ snapshots:
|
||||
'@next/eslint-plugin-next': 16.2.7
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
eslint-import-resolver-node: 0.3.10
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0))
|
||||
@@ -4205,7 +4217,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)):
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.3
|
||||
@@ -4216,22 +4228,22 @@ snapshots:
|
||||
tinyglobby: 0.2.17
|
||||
unrs-resolver: 1.12.2
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)):
|
||||
eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
eslint-import-resolver-node: 0.3.10
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)):
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.9
|
||||
@@ -4242,7 +4254,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
eslint-import-resolver-node: 0.3.10
|
||||
eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0))
|
||||
hasown: 2.0.4
|
||||
is-core-module: 2.16.2
|
||||
is-glob: 4.0.3
|
||||
@@ -5499,6 +5511,10 @@ snapshots:
|
||||
|
||||
strip-json-comments@3.1.1: {}
|
||||
|
||||
stripe@22.2.0(@types/node@20.19.42):
|
||||
optionalDependencies:
|
||||
'@types/node': 20.19.42
|
||||
|
||||
styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.4):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
|
||||
40
setup_188.sh
Normal file
40
setup_188.sh
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
certbot certonly --webroot -w /var/www/html -d agent.wooo.work --non-interactive --agree-tos --account 957a0a8ba3c1393f153d98b8aa7e6c07
|
||||
|
||||
cat << 'NGINX_CONF_SSL' > /etc/nginx/sites-available/agent.wooo.work.conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name agent.wooo.work;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name agent.wooo.work;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/agent.wooo.work/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/agent.wooo.work/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://192.168.0.110;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# WebSocket support
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
NGINX_CONF_SSL
|
||||
|
||||
nginx -t && systemctl reload nginx
|
||||
Reference in New Issue
Block a user