@supacloud/compiler 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/cli.js +259 -10
- package/dist/index.js +259 -10
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -495,6 +495,11 @@ route 会自动按 HTTP status 执行内置 response decoder,并返回 schema
|
|
|
495
495
|
OpenAPI。`buildRouteUrl` 和 `createApiClient` 可直接复用,也支持动态 headers
|
|
496
496
|
和请求拦截器。
|
|
497
497
|
|
|
498
|
+
每个生成 route 还会按 HTTP 方法暴露 `.query()` 或 `.mutate()` procedure
|
|
499
|
+
facade,并在 `API_PROCEDURES` 中输出 Command/幂等元数据。声明
|
|
500
|
+
`idempotency: "required"` 的 mutation 必须显式传入稳定的 `idempotencyKey`;
|
|
501
|
+
客户端不会静默生成新 key。
|
|
502
|
+
|
|
498
503
|
### Migration from manual decoders
|
|
499
504
|
|
|
500
505
|
旧版本要求调用方为每个有响应 schema 的 route 传入 decoder。升级后删除该
|
package/dist/cli.js
CHANGED
|
@@ -2245,6 +2245,8 @@ function renderClient(graph, options) {
|
|
|
2245
2245
|
const schemaLocals = new Map;
|
|
2246
2246
|
const usedTypeNames = new Set;
|
|
2247
2247
|
const allRoutes = [];
|
|
2248
|
+
const allProcedures = [];
|
|
2249
|
+
const commandByClassName = new Map(graph.modules.flatMap((module) => module.commands.map((command) => [command.className, command])));
|
|
2248
2250
|
let usesStatic = false;
|
|
2249
2251
|
let usesValue = false;
|
|
2250
2252
|
const uniqueTypeName = (candidate) => {
|
|
@@ -2375,8 +2377,30 @@ function renderClient(graph, options) {
|
|
|
2375
2377
|
const responseSchemaEntries = hasResponseMap ? Object.entries(responseSchemas).map(([status, ref]) => [status, ref.local]) : responseSchema ? [["200", responseSchema.local]] : [];
|
|
2376
2378
|
const responseSchemaArgument = responseSchemaEntries.length > 0 ? `{ ${responseSchemaEntries.map(([status, local]) => `${JSON.stringify(status)}: ${local}`).join(", ")} }` : "undefined";
|
|
2377
2379
|
const responseKindArgument = responseKind === undefined ? "undefined" : JSON.stringify(responseKind);
|
|
2380
|
+
const command = route.command === undefined ? undefined : commandByClassName.get(route.command);
|
|
2381
|
+
const procedureKind = route.method === "GET" || route.method === "HEAD" ? "query" : "mutation";
|
|
2382
|
+
const idempotencyMode = command?.idempotency ?? "none";
|
|
2383
|
+
const procedureMetadata = {
|
|
2384
|
+
key: `${controller.className}.${route.handler}`,
|
|
2385
|
+
method: route.method,
|
|
2386
|
+
path: fullPath,
|
|
2387
|
+
controller: controller.className,
|
|
2388
|
+
handler: route.handler,
|
|
2389
|
+
kind: procedureKind,
|
|
2390
|
+
idempotency: idempotencyMode
|
|
2391
|
+
};
|
|
2392
|
+
allProcedures.push({
|
|
2393
|
+
method: route.method,
|
|
2394
|
+
path: fullPath,
|
|
2395
|
+
controller: controller.className,
|
|
2396
|
+
handler: route.handler,
|
|
2397
|
+
kind: procedureKind,
|
|
2398
|
+
...command?.name === undefined ? {} : { command: command.name },
|
|
2399
|
+
...command?.permission === undefined ? {} : { permission: command.permission },
|
|
2400
|
+
idempotency: idempotencyMode
|
|
2401
|
+
});
|
|
2378
2402
|
routeMethods.push(`
|
|
2379
|
-
${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}),`);
|
|
2403
|
+
${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}, ${JSON.stringify(procedureKind)}, ${JSON.stringify(idempotencyMode)}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}, ${JSON.stringify(procedureKind)}, ${JSON.stringify(idempotencyMode)}, ${JSON.stringify(procedureMetadata)}),`);
|
|
2380
2404
|
}
|
|
2381
2405
|
controllerEntries.push(`
|
|
2382
2406
|
${controllerKey}: {${routeMethods.join("")}
|
|
@@ -2407,6 +2431,66 @@ function renderClient(graph, options) {
|
|
|
2407
2431
|
"",
|
|
2408
2432
|
"export type ResponseDecoder<T> = (value: unknown) => T;",
|
|
2409
2433
|
"",
|
|
2434
|
+
'export type ProcedureKind = "query" | "mutation";',
|
|
2435
|
+
'export type IdempotencyMode = "required" | "none";',
|
|
2436
|
+
"",
|
|
2437
|
+
"export interface ProcedureMetadata<",
|
|
2438
|
+
" Kind extends ProcedureKind = ProcedureKind,",
|
|
2439
|
+
" Idempotency extends IdempotencyMode = IdempotencyMode,",
|
|
2440
|
+
"> {",
|
|
2441
|
+
" key: string;",
|
|
2442
|
+
" method: string;",
|
|
2443
|
+
" path: string;",
|
|
2444
|
+
" controller: string;",
|
|
2445
|
+
" handler: string;",
|
|
2446
|
+
" kind: Kind;",
|
|
2447
|
+
" idempotency: Idempotency;",
|
|
2448
|
+
"}",
|
|
2449
|
+
"",
|
|
2450
|
+
"export interface ProcedureExecutionOptions {",
|
|
2451
|
+
" /** Reuse the same key when retrying an uncertain mutation. */",
|
|
2452
|
+
" idempotencyKey?: string;",
|
|
2453
|
+
" signal?: AbortSignal;",
|
|
2454
|
+
"}",
|
|
2455
|
+
"",
|
|
2456
|
+
"export type RequiredProcedureExecutionOptions = ProcedureExecutionOptions & { idempotencyKey: string };",
|
|
2457
|
+
"",
|
|
2458
|
+
"type ProcedureResult<Result> = [Result] extends [never] ? unknown : Result;",
|
|
2459
|
+
"",
|
|
2460
|
+
"type ProcedureArgs<Options extends ClientRequestOptions, Idempotency extends IdempotencyMode> =",
|
|
2461
|
+
' Idempotency extends "required"',
|
|
2462
|
+
" ? {} extends Options",
|
|
2463
|
+
" ? [execution: RequiredProcedureExecutionOptions] | [input: Options, execution: RequiredProcedureExecutionOptions]",
|
|
2464
|
+
" : [input: Options, execution: RequiredProcedureExecutionOptions]",
|
|
2465
|
+
" : {} extends Options",
|
|
2466
|
+
" ? [input?: Options, execution?: ProcedureExecutionOptions]",
|
|
2467
|
+
" : [input: Options, execution?: ProcedureExecutionOptions];",
|
|
2468
|
+
"",
|
|
2469
|
+
"export type ProcedureCall<",
|
|
2470
|
+
" Options extends ClientRequestOptions = ClientRequestOptions,",
|
|
2471
|
+
" Result = never,",
|
|
2472
|
+
' Idempotency extends IdempotencyMode = "none",',
|
|
2473
|
+
"> = (...args: ProcedureArgs<Options, Idempotency>) => Promise<ProcedureResult<Result>>;",
|
|
2474
|
+
"",
|
|
2475
|
+
"export type QueryableProcedure<",
|
|
2476
|
+
" Options extends ClientRequestOptions,",
|
|
2477
|
+
" Result,",
|
|
2478
|
+
" Idempotency extends IdempotencyMode,",
|
|
2479
|
+
" Kind extends ProcedureKind,",
|
|
2480
|
+
"> = ProcedureCall<Options, Result, Idempotency> & {",
|
|
2481
|
+
" readonly __supacloudProcedure: ProcedureMetadata<Kind, Idempotency>;",
|
|
2482
|
+
" readonly __supacloudInput?: Options;",
|
|
2483
|
+
"};",
|
|
2484
|
+
"",
|
|
2485
|
+
"export type ProcedureMember<",
|
|
2486
|
+
" Options extends ClientRequestOptions,",
|
|
2487
|
+
" Result,",
|
|
2488
|
+
" Kind extends ProcedureKind,",
|
|
2489
|
+
" Idempotency extends IdempotencyMode,",
|
|
2490
|
+
'> = Kind extends "query"',
|
|
2491
|
+
' ? { query: QueryableProcedure<Options, Result, Idempotency, "query"> }',
|
|
2492
|
+
' : { mutate: QueryableProcedure<Options, Result, Idempotency, "mutation"> };',
|
|
2493
|
+
"",
|
|
2410
2494
|
'export type ApiClientErrorCode = "API_HTTP_ERROR" | "API_RESPONSE_INVALID" | "API_RESPONSE_UNDECLARED";',
|
|
2411
2495
|
"",
|
|
2412
2496
|
"export interface ApiClientErrorDetails {",
|
|
@@ -2450,6 +2534,17 @@ function renderClient(graph, options) {
|
|
|
2450
2534
|
" : { (options: Options): Promise<Result>; <T>(options: Options, decode: ResponseDecoder<T>): Promise<T> }",
|
|
2451
2535
|
") & ((...args: {} extends Options ? [options?: Options] : [options: Options]) => Promise<[Result] extends [never] ? unknown : Result>);",
|
|
2452
2536
|
"",
|
|
2537
|
+
"export interface ApiProcedureDefinition {",
|
|
2538
|
+
" method: string;",
|
|
2539
|
+
" path: string;",
|
|
2540
|
+
" controller: string;",
|
|
2541
|
+
" handler: string;",
|
|
2542
|
+
" kind: ProcedureKind;",
|
|
2543
|
+
" command?: string;",
|
|
2544
|
+
" permission?: string;",
|
|
2545
|
+
" idempotency: IdempotencyMode;",
|
|
2546
|
+
"}",
|
|
2547
|
+
"",
|
|
2453
2548
|
...routeTypes,
|
|
2454
2549
|
...routeTypes.length > 0 ? [""] : [],
|
|
2455
2550
|
"export interface HttpInterceptorRequest {",
|
|
@@ -2457,6 +2552,7 @@ function renderClient(graph, options) {
|
|
|
2457
2552
|
" url: string;",
|
|
2458
2553
|
" headers: Record<string, string>;",
|
|
2459
2554
|
" body?: unknown;",
|
|
2555
|
+
" signal?: AbortSignal;",
|
|
2460
2556
|
"}",
|
|
2461
2557
|
"",
|
|
2462
2558
|
"export type HttpInterceptorFn = (",
|
|
@@ -2475,6 +2571,8 @@ function renderClient(graph, options) {
|
|
|
2475
2571
|
"",
|
|
2476
2572
|
"export const API_ROUTES = " + JSON.stringify(allRoutes, null, 2) + " as const;",
|
|
2477
2573
|
"",
|
|
2574
|
+
"export const API_PROCEDURES: readonly ApiProcedureDefinition[] = " + JSON.stringify(allProcedures, null, 2) + ";",
|
|
2575
|
+
"",
|
|
2478
2576
|
"export type AppRoutePath = typeof API_ROUTES[number]['path'];",
|
|
2479
2577
|
"",
|
|
2480
2578
|
"export const API_SCHEMAS = [",
|
|
@@ -2700,6 +2798,7 @@ function renderClient(graph, options) {
|
|
|
2700
2798
|
` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
|
|
2701
2799
|
" responseKind?: string,",
|
|
2702
2800
|
" raw?: boolean,",
|
|
2801
|
+
" execution?: ProcedureExecutionOptions,",
|
|
2703
2802
|
" ): Promise<T>;",
|
|
2704
2803
|
" async function request<T>(",
|
|
2705
2804
|
" method: string,",
|
|
@@ -2709,6 +2808,7 @@ function renderClient(graph, options) {
|
|
|
2709
2808
|
` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
|
|
2710
2809
|
" responseKind?: string,",
|
|
2711
2810
|
" raw?: boolean,",
|
|
2811
|
+
" execution?: ProcedureExecutionOptions,",
|
|
2712
2812
|
" ): Promise<T | unknown>;",
|
|
2713
2813
|
" async function request(",
|
|
2714
2814
|
" method: string,",
|
|
@@ -2723,6 +2823,7 @@ function renderClient(graph, options) {
|
|
|
2723
2823
|
` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
|
|
2724
2824
|
" responseKind?: string,",
|
|
2725
2825
|
" raw = false,",
|
|
2826
|
+
" execution?: ProcedureExecutionOptions,",
|
|
2726
2827
|
" ): Promise<T | unknown> {",
|
|
2727
2828
|
" const url = `${baseUrl}${buildRouteUrl(path, options.params, options.query)}`;",
|
|
2728
2829
|
' const customHeaders = typeof config.headers === "function" ? await config.headers() : config.headers;',
|
|
@@ -2748,9 +2849,10 @@ function renderClient(graph, options) {
|
|
|
2748
2849
|
" headers: reqPayload.headers,",
|
|
2749
2850
|
" ...(reqPayload.body === undefined ? {} : { body: raw ? rawBody(reqPayload.body) : JSON.stringify(reqPayload.body) }),",
|
|
2750
2851
|
' ...(raw && reqPayload.body instanceof ReadableStream ? { duplex: "half" } : {}),',
|
|
2852
|
+
" ...(reqPayload.signal === undefined ? {} : { signal: reqPayload.signal }),",
|
|
2751
2853
|
" });",
|
|
2752
2854
|
" };",
|
|
2753
|
-
" const response = await executeChain(0, { method, url, headers, body: options.body });",
|
|
2855
|
+
" const response = await executeChain(0, { method, url, headers, body: options.body, ...(execution?.signal === undefined ? {} : { signal: execution.signal }) });",
|
|
2754
2856
|
" const declaredSchema = responseSchemas ? selectResponseSchema(response.status, responseSchemas) : undefined;",
|
|
2755
2857
|
" const failure = (code: ApiClientErrorCode, message: string) => new ApiClientError(message, {",
|
|
2756
2858
|
' code, method, path, status: response.status, requestId: response.headers.get("x-request-id"),',
|
|
@@ -2788,7 +2890,44 @@ function renderClient(graph, options) {
|
|
|
2788
2890
|
" return decode ? decode(checked) : checked;",
|
|
2789
2891
|
" }",
|
|
2790
2892
|
"",
|
|
2791
|
-
|
|
2893
|
+
" function hasHeader(headers: Record<string, string>, name: string): boolean {",
|
|
2894
|
+
" return Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());",
|
|
2895
|
+
" }",
|
|
2896
|
+
"",
|
|
2897
|
+
" function withProcedureExecution(",
|
|
2898
|
+
" options: ClientRequestOptions,",
|
|
2899
|
+
" execution: ProcedureExecutionOptions | undefined,",
|
|
2900
|
+
" idempotency: IdempotencyMode,",
|
|
2901
|
+
" ): ClientRequestOptions {",
|
|
2902
|
+
" const headers = { ...(options.headers as Record<string, string> | undefined) };",
|
|
2903
|
+
" if (execution?.idempotencyKey !== undefined) {",
|
|
2904
|
+
" if (!/^[A-Za-z0-9._:-]{1,512}$/.test(execution.idempotencyKey)) {",
|
|
2905
|
+
' throw new TypeError("idempotencyKey must contain only safe header characters and be at most 512 characters");',
|
|
2906
|
+
" }",
|
|
2907
|
+
' headers["idempotency-key"] = execution.idempotencyKey;',
|
|
2908
|
+
" }",
|
|
2909
|
+
' if (idempotency === "required" && !hasHeader(headers, "idempotency-key")) {',
|
|
2910
|
+
' throw new TypeError("This mutation requires an idempotencyKey");',
|
|
2911
|
+
" }",
|
|
2912
|
+
" return Object.keys(headers).length === 0 ? options : { ...options, headers };",
|
|
2913
|
+
" }",
|
|
2914
|
+
"",
|
|
2915
|
+
" function isProcedureExecution(value: unknown): value is ProcedureExecutionOptions {",
|
|
2916
|
+
' if (value === null || typeof value !== "object" || Array.isArray(value)) return false;',
|
|
2917
|
+
' return Object.hasOwn(value, "idempotencyKey") || Object.hasOwn(value, "signal");',
|
|
2918
|
+
" }",
|
|
2919
|
+
"",
|
|
2920
|
+
` function makeProcedure<Options extends ClientRequestOptions, Result = never, Idempotency extends IdempotencyMode = "none", Kind extends ProcedureKind = ProcedureKind>(metadata: ProcedureMetadata<Kind, Idempotency>, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false): QueryableProcedure<Options, Result, Idempotency, Kind> {`,
|
|
2921
|
+
" const procedure = async (first?: Options | ProcedureExecutionOptions, second?: ProcedureExecutionOptions): Promise<unknown> => {",
|
|
2922
|
+
" const execution = second ?? (isProcedureExecution(first) ? first : undefined);",
|
|
2923
|
+
" const input = (execution === first ? undefined : first) ?? {};",
|
|
2924
|
+
" const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, metadata.idempotency);",
|
|
2925
|
+
" return request(metadata.method, metadata.path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
|
|
2926
|
+
" };",
|
|
2927
|
+
" return Object.assign(procedure, { __supacloudProcedure: Object.freeze(metadata) }) as QueryableProcedure<Options, Result, Idempotency, Kind>;",
|
|
2928
|
+
" }",
|
|
2929
|
+
"",
|
|
2930
|
+
` function makeRoute<Options extends ClientRequestOptions, Result = never, Kind extends ProcedureKind = never, Idempotency extends IdempotencyMode = "none">(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false, kind?: Kind, idempotency: Idempotency = "none" as Idempotency, metadata?: ProcedureMetadata<Kind, Idempotency>): RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency> {`,
|
|
2792
2931
|
" function route<T>(options: Options, decode: ResponseDecoder<T>): Promise<T>;",
|
|
2793
2932
|
" function route(options: Options): Promise<Result>;",
|
|
2794
2933
|
" function route(options?: Options): Promise<unknown>;",
|
|
@@ -2796,13 +2935,16 @@ function renderClient(graph, options) {
|
|
|
2796
2935
|
" const requestOptions = options ?? {};",
|
|
2797
2936
|
" return request(method, path, requestOptions, decode, responseSchemas, responseKind, raw);",
|
|
2798
2937
|
" }",
|
|
2799
|
-
|
|
2938
|
+
' if (kind === "query" && metadata) Object.assign(route, { query: makeProcedure<Options, Result, Idempotency, "query">(metadata as ProcedureMetadata<"query", Idempotency>, responseSchemas, responseKind, raw) });',
|
|
2939
|
+
' if (kind === "mutation" && metadata) Object.assign(route, { mutate: makeProcedure<Options, Result, Idempotency, "mutation">(metadata as ProcedureMetadata<"mutation", Idempotency>, responseSchemas, responseKind, raw) });',
|
|
2940
|
+
" return route as RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency>;",
|
|
2800
2941
|
" }",
|
|
2801
2942
|
"",
|
|
2802
2943
|
" return {",
|
|
2803
2944
|
" request,",
|
|
2804
2945
|
" buildRouteUrl,",
|
|
2805
2946
|
" routes: API_ROUTES,",
|
|
2947
|
+
" procedures: API_PROCEDURES,",
|
|
2806
2948
|
...controllerEntries,
|
|
2807
2949
|
" };",
|
|
2808
2950
|
"}",
|
|
@@ -15670,6 +15812,9 @@ function parseDeliveryBuildManifest(value) {
|
|
|
15670
15812
|
if (!Check2(DeliveryBuildManifestSchema, value))
|
|
15671
15813
|
throw new Error("Invalid delivery build manifest.");
|
|
15672
15814
|
validateWorkerExecution(value.plan.targets.flatMap((target) => target.execution ? [target.execution] : []));
|
|
15815
|
+
if (value.plan.targets.reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
|
|
15816
|
+
throw new Error("Invalid delivery replica count.");
|
|
15817
|
+
}
|
|
15673
15818
|
for (const target of value.plan.targets) {
|
|
15674
15819
|
if (target.execution && (target.kind !== "jobs" || target.isolation !== "process" || target.execution.target !== target.name || target.jobs.length !== 1 || target.jobs[0]?.name !== target.execution.taskKey || value.objects.find((object) => object.name === target.name)?.entryKind !== "bun-worker-application")) {
|
|
15675
15820
|
throw new Error("Invalid delivery execution binding.");
|
|
@@ -15683,7 +15828,7 @@ function parseDeliveryBuildManifest(value) {
|
|
|
15683
15828
|
}
|
|
15684
15829
|
for (const object of value.objects) {
|
|
15685
15830
|
const target = value.plan.targets.find((target) => target.name === object.name);
|
|
15686
|
-
if (
|
|
15831
|
+
if (["bun-worker-application", "go-worker-application", "scriptc-worker-application"].includes(object.entryKind) && target?.kind !== "jobs" || object.entryKind === "bun-http-application" && target?.kind === "jobs") {
|
|
15687
15832
|
throw new Error("Delivery executable kind does not match its target.");
|
|
15688
15833
|
}
|
|
15689
15834
|
if (new Set(object.files.map((file) => file.path)).size !== object.files.length || !object.files.some((file) => file.path === object.entrypoint) || deliveryObjectDigest(object) !== object.objectId) {
|
|
@@ -15721,7 +15866,9 @@ var init_delivery_build_schema = __esm(() => {
|
|
|
15721
15866
|
entryKind: Union([
|
|
15722
15867
|
Literal("compiled-module-factory"),
|
|
15723
15868
|
Literal("bun-http-application"),
|
|
15724
|
-
Literal("bun-worker-application")
|
|
15869
|
+
Literal("bun-worker-application"),
|
|
15870
|
+
Literal("go-worker-application"),
|
|
15871
|
+
Literal("scriptc-worker-application")
|
|
15725
15872
|
]),
|
|
15726
15873
|
runtimeImports: _Array_(String2()),
|
|
15727
15874
|
files: _Array_(_Object_({
|
|
@@ -16252,6 +16399,107 @@ var init_application_activation = __esm(() => {
|
|
|
16252
16399
|
}, { additionalProperties: false });
|
|
16253
16400
|
});
|
|
16254
16401
|
|
|
16402
|
+
// node_modules/@supacloud/delivery/src/deployment-evidence.ts
|
|
16403
|
+
var closed6, sha256, isoDate, status, evidenceStatus, DEPLOYMENT_EVIDENCE_SCHEMA = "supacloud.deployment-evidence.v1", DatabaseProviderSchema, componentName, DeploymentComponentEvidenceSchema, DeploymentEvidenceSchema;
|
|
16404
|
+
var init_deployment_evidence = __esm(() => {
|
|
16405
|
+
init_build();
|
|
16406
|
+
init_value2();
|
|
16407
|
+
init_application_configuration();
|
|
16408
|
+
init_application_release();
|
|
16409
|
+
closed6 = { additionalProperties: false };
|
|
16410
|
+
sha256 = String2({ pattern: "^[a-f0-9]{64}$" });
|
|
16411
|
+
isoDate = String2({ minLength: 20, maxLength: 40 });
|
|
16412
|
+
status = Union([
|
|
16413
|
+
Literal("confirmed"),
|
|
16414
|
+
Literal("failed"),
|
|
16415
|
+
Literal("unknown")
|
|
16416
|
+
]);
|
|
16417
|
+
evidenceStatus = Union([
|
|
16418
|
+
Literal("confirmed"),
|
|
16419
|
+
Literal("failed"),
|
|
16420
|
+
Literal("unknown"),
|
|
16421
|
+
Literal("incomplete")
|
|
16422
|
+
]);
|
|
16423
|
+
DatabaseProviderSchema = _Object_({
|
|
16424
|
+
provider: String2({ minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9_.-]*$" }),
|
|
16425
|
+
version: String2({ minLength: 1, maxLength: 64 }),
|
|
16426
|
+
topology: Union([Literal("single-node"), Literal("distributed")]),
|
|
16427
|
+
migration: _Object_({
|
|
16428
|
+
status,
|
|
16429
|
+
inventory_sha256: Union([sha256, Null()]),
|
|
16430
|
+
compatibility: Union([
|
|
16431
|
+
Literal("verified"),
|
|
16432
|
+
Literal("not-proven"),
|
|
16433
|
+
Literal("failed")
|
|
16434
|
+
])
|
|
16435
|
+
}, closed6),
|
|
16436
|
+
backup: _Object_({
|
|
16437
|
+
status,
|
|
16438
|
+
latest_success_at: Union([isoDate, Null()]),
|
|
16439
|
+
freshness_seconds: Union([Integer({ minimum: 0 }), Null()])
|
|
16440
|
+
}, closed6),
|
|
16441
|
+
recovery: _Object_({
|
|
16442
|
+
status,
|
|
16443
|
+
drill_id: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
|
|
16444
|
+
rpo_seconds: Union([Integer({ minimum: 0 }), Null()]),
|
|
16445
|
+
rto_seconds: Union([Integer({ minimum: 0 }), Null()])
|
|
16446
|
+
}, closed6)
|
|
16447
|
+
}, closed6);
|
|
16448
|
+
componentName = Union([
|
|
16449
|
+
Literal("management-api"),
|
|
16450
|
+
Literal("web-console"),
|
|
16451
|
+
Literal("edge-runtime"),
|
|
16452
|
+
Literal("worker"),
|
|
16453
|
+
Literal("postgres"),
|
|
16454
|
+
Literal("postgrest"),
|
|
16455
|
+
Literal("gotrue"),
|
|
16456
|
+
Literal("storage"),
|
|
16457
|
+
Literal("realtime")
|
|
16458
|
+
]);
|
|
16459
|
+
DeploymentComponentEvidenceSchema = _Object_({
|
|
16460
|
+
name: componentName,
|
|
16461
|
+
version: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
|
|
16462
|
+
status,
|
|
16463
|
+
health_check: Union([String2({ minLength: 1, maxLength: 256 }), Null()]),
|
|
16464
|
+
checked_at: Union([isoDate, Null()])
|
|
16465
|
+
}, closed6);
|
|
16466
|
+
DeploymentEvidenceSchema = _Object_({
|
|
16467
|
+
schema: Literal(DEPLOYMENT_EVIDENCE_SCHEMA),
|
|
16468
|
+
status: evidenceStatus,
|
|
16469
|
+
recorded_at: isoDate,
|
|
16470
|
+
scope: _Object_({
|
|
16471
|
+
project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
|
|
16472
|
+
application_id: ApplicationIdSchema,
|
|
16473
|
+
environment_id: ApplicationIdSchema
|
|
16474
|
+
}, closed6),
|
|
16475
|
+
source: _Object_({
|
|
16476
|
+
commit_sha: Union([String2({ pattern: "^[0-9a-f]{7,64}$" }), Null()]),
|
|
16477
|
+
manifest_sha256: sha256,
|
|
16478
|
+
contract_schema: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
|
|
16479
|
+
environment_binding_version: Union([sha256, Null()])
|
|
16480
|
+
}, closed6),
|
|
16481
|
+
database: DatabaseProviderSchema,
|
|
16482
|
+
components: _Array_(DeploymentComponentEvidenceSchema, { minItems: 1, maxItems: 32 }),
|
|
16483
|
+
activation: _Object_({
|
|
16484
|
+
release_id: ApplicationReleaseIdSchema,
|
|
16485
|
+
configuration_id: ApplicationConfigurationIdSchema,
|
|
16486
|
+
activation_id: ApplicationConfigurationIdSchema
|
|
16487
|
+
}, closed6),
|
|
16488
|
+
health: _Object_({
|
|
16489
|
+
status,
|
|
16490
|
+
checked_at: Union([isoDate, Null()]),
|
|
16491
|
+
authenticated_smoke: status
|
|
16492
|
+
}, closed6),
|
|
16493
|
+
rollback: _Object_({
|
|
16494
|
+
release_id: Union([ApplicationReleaseIdSchema, Null()]),
|
|
16495
|
+
configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
|
|
16496
|
+
status: Union([Literal("ready"), Literal("not-ready"), Literal("unknown")]),
|
|
16497
|
+
result: Union([status, Null()])
|
|
16498
|
+
}, closed6),
|
|
16499
|
+
notes: _Array_(String2({ minLength: 1, maxLength: 512 }), { maxItems: 32 })
|
|
16500
|
+
}, closed6);
|
|
16501
|
+
});
|
|
16502
|
+
|
|
16255
16503
|
// node_modules/@supacloud/delivery/src/application-runtime-identity.ts
|
|
16256
16504
|
var APPLICATION_RUNTIME_PROBE_PATH = "/.well-known/supacloud/runtime", ApplicationRuntimeIdentitySchema, ApplicationReadinessReportSchema;
|
|
16257
16505
|
var init_application_runtime_identity = __esm(() => {
|
|
@@ -16374,6 +16622,7 @@ var init_src = __esm(() => {
|
|
|
16374
16622
|
init_application_activation();
|
|
16375
16623
|
init_application_release();
|
|
16376
16624
|
init_application_configuration();
|
|
16625
|
+
init_deployment_evidence();
|
|
16377
16626
|
init_application_runtime_identity();
|
|
16378
16627
|
init_delivery_build_schema();
|
|
16379
16628
|
init_delivery_migration_archive();
|
|
@@ -23408,7 +23657,7 @@ function isRecord2(value) {
|
|
|
23408
23657
|
function arrayLength(value) {
|
|
23409
23658
|
return Array.isArray(value) ? value.length : undefined;
|
|
23410
23659
|
}
|
|
23411
|
-
async function
|
|
23660
|
+
async function sha2562(path) {
|
|
23412
23661
|
return createHash10("sha256").update(await readFile11(path)).digest("hex");
|
|
23413
23662
|
}
|
|
23414
23663
|
function overallStatus(findings) {
|
|
@@ -23482,7 +23731,7 @@ async function assessMigration(options) {
|
|
|
23482
23731
|
contractsManifest = {
|
|
23483
23732
|
path: contractsManifestPath,
|
|
23484
23733
|
present: true,
|
|
23485
|
-
sha256: await
|
|
23734
|
+
sha256: await sha2562(contractsManifestPath),
|
|
23486
23735
|
version: 1,
|
|
23487
23736
|
...arrayLength(parsed.commands) === undefined ? {} : { commands: arrayLength(parsed.commands) },
|
|
23488
23737
|
...arrayLength(parsed.routes) === undefined ? {} : { routes: arrayLength(parsed.routes) },
|
|
@@ -23505,9 +23754,9 @@ async function assessMigration(options) {
|
|
|
23505
23754
|
const diff = diffOpenApiDocuments(await readOpenApiJson(baselinePath), await readOpenApiJson(currentPath));
|
|
23506
23755
|
openApi = {
|
|
23507
23756
|
baselinePath,
|
|
23508
|
-
baselineSha256: await
|
|
23757
|
+
baselineSha256: await sha2562(baselinePath),
|
|
23509
23758
|
currentPath,
|
|
23510
|
-
currentSha256: await
|
|
23759
|
+
currentSha256: await sha2562(currentPath),
|
|
23511
23760
|
diff
|
|
23512
23761
|
};
|
|
23513
23762
|
if (!diff.ok) {
|
package/dist/index.js
CHANGED
|
@@ -2244,6 +2244,8 @@ function renderClient(graph, options) {
|
|
|
2244
2244
|
const schemaLocals = new Map;
|
|
2245
2245
|
const usedTypeNames = new Set;
|
|
2246
2246
|
const allRoutes = [];
|
|
2247
|
+
const allProcedures = [];
|
|
2248
|
+
const commandByClassName = new Map(graph.modules.flatMap((module) => module.commands.map((command) => [command.className, command])));
|
|
2247
2249
|
let usesStatic = false;
|
|
2248
2250
|
let usesValue = false;
|
|
2249
2251
|
const uniqueTypeName = (candidate) => {
|
|
@@ -2374,8 +2376,30 @@ function renderClient(graph, options) {
|
|
|
2374
2376
|
const responseSchemaEntries = hasResponseMap ? Object.entries(responseSchemas).map(([status, ref]) => [status, ref.local]) : responseSchema ? [["200", responseSchema.local]] : [];
|
|
2375
2377
|
const responseSchemaArgument = responseSchemaEntries.length > 0 ? `{ ${responseSchemaEntries.map(([status, local]) => `${JSON.stringify(status)}: ${local}`).join(", ")} }` : "undefined";
|
|
2376
2378
|
const responseKindArgument = responseKind === undefined ? "undefined" : JSON.stringify(responseKind);
|
|
2379
|
+
const command = route.command === undefined ? undefined : commandByClassName.get(route.command);
|
|
2380
|
+
const procedureKind = route.method === "GET" || route.method === "HEAD" ? "query" : "mutation";
|
|
2381
|
+
const idempotencyMode = command?.idempotency ?? "none";
|
|
2382
|
+
const procedureMetadata = {
|
|
2383
|
+
key: `${controller.className}.${route.handler}`,
|
|
2384
|
+
method: route.method,
|
|
2385
|
+
path: fullPath,
|
|
2386
|
+
controller: controller.className,
|
|
2387
|
+
handler: route.handler,
|
|
2388
|
+
kind: procedureKind,
|
|
2389
|
+
idempotency: idempotencyMode
|
|
2390
|
+
};
|
|
2391
|
+
allProcedures.push({
|
|
2392
|
+
method: route.method,
|
|
2393
|
+
path: fullPath,
|
|
2394
|
+
controller: controller.className,
|
|
2395
|
+
handler: route.handler,
|
|
2396
|
+
kind: procedureKind,
|
|
2397
|
+
...command?.name === undefined ? {} : { command: command.name },
|
|
2398
|
+
...command?.permission === undefined ? {} : { permission: command.permission },
|
|
2399
|
+
idempotency: idempotencyMode
|
|
2400
|
+
});
|
|
2377
2401
|
routeMethods.push(`
|
|
2378
|
-
${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}),`);
|
|
2402
|
+
${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}, ${JSON.stringify(procedureKind)}, ${JSON.stringify(idempotencyMode)}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}, ${JSON.stringify(procedureKind)}, ${JSON.stringify(idempotencyMode)}, ${JSON.stringify(procedureMetadata)}),`);
|
|
2379
2403
|
}
|
|
2380
2404
|
controllerEntries.push(`
|
|
2381
2405
|
${controllerKey}: {${routeMethods.join("")}
|
|
@@ -2406,6 +2430,66 @@ function renderClient(graph, options) {
|
|
|
2406
2430
|
"",
|
|
2407
2431
|
"export type ResponseDecoder<T> = (value: unknown) => T;",
|
|
2408
2432
|
"",
|
|
2433
|
+
'export type ProcedureKind = "query" | "mutation";',
|
|
2434
|
+
'export type IdempotencyMode = "required" | "none";',
|
|
2435
|
+
"",
|
|
2436
|
+
"export interface ProcedureMetadata<",
|
|
2437
|
+
" Kind extends ProcedureKind = ProcedureKind,",
|
|
2438
|
+
" Idempotency extends IdempotencyMode = IdempotencyMode,",
|
|
2439
|
+
"> {",
|
|
2440
|
+
" key: string;",
|
|
2441
|
+
" method: string;",
|
|
2442
|
+
" path: string;",
|
|
2443
|
+
" controller: string;",
|
|
2444
|
+
" handler: string;",
|
|
2445
|
+
" kind: Kind;",
|
|
2446
|
+
" idempotency: Idempotency;",
|
|
2447
|
+
"}",
|
|
2448
|
+
"",
|
|
2449
|
+
"export interface ProcedureExecutionOptions {",
|
|
2450
|
+
" /** Reuse the same key when retrying an uncertain mutation. */",
|
|
2451
|
+
" idempotencyKey?: string;",
|
|
2452
|
+
" signal?: AbortSignal;",
|
|
2453
|
+
"}",
|
|
2454
|
+
"",
|
|
2455
|
+
"export type RequiredProcedureExecutionOptions = ProcedureExecutionOptions & { idempotencyKey: string };",
|
|
2456
|
+
"",
|
|
2457
|
+
"type ProcedureResult<Result> = [Result] extends [never] ? unknown : Result;",
|
|
2458
|
+
"",
|
|
2459
|
+
"type ProcedureArgs<Options extends ClientRequestOptions, Idempotency extends IdempotencyMode> =",
|
|
2460
|
+
' Idempotency extends "required"',
|
|
2461
|
+
" ? {} extends Options",
|
|
2462
|
+
" ? [execution: RequiredProcedureExecutionOptions] | [input: Options, execution: RequiredProcedureExecutionOptions]",
|
|
2463
|
+
" : [input: Options, execution: RequiredProcedureExecutionOptions]",
|
|
2464
|
+
" : {} extends Options",
|
|
2465
|
+
" ? [input?: Options, execution?: ProcedureExecutionOptions]",
|
|
2466
|
+
" : [input: Options, execution?: ProcedureExecutionOptions];",
|
|
2467
|
+
"",
|
|
2468
|
+
"export type ProcedureCall<",
|
|
2469
|
+
" Options extends ClientRequestOptions = ClientRequestOptions,",
|
|
2470
|
+
" Result = never,",
|
|
2471
|
+
' Idempotency extends IdempotencyMode = "none",',
|
|
2472
|
+
"> = (...args: ProcedureArgs<Options, Idempotency>) => Promise<ProcedureResult<Result>>;",
|
|
2473
|
+
"",
|
|
2474
|
+
"export type QueryableProcedure<",
|
|
2475
|
+
" Options extends ClientRequestOptions,",
|
|
2476
|
+
" Result,",
|
|
2477
|
+
" Idempotency extends IdempotencyMode,",
|
|
2478
|
+
" Kind extends ProcedureKind,",
|
|
2479
|
+
"> = ProcedureCall<Options, Result, Idempotency> & {",
|
|
2480
|
+
" readonly __supacloudProcedure: ProcedureMetadata<Kind, Idempotency>;",
|
|
2481
|
+
" readonly __supacloudInput?: Options;",
|
|
2482
|
+
"};",
|
|
2483
|
+
"",
|
|
2484
|
+
"export type ProcedureMember<",
|
|
2485
|
+
" Options extends ClientRequestOptions,",
|
|
2486
|
+
" Result,",
|
|
2487
|
+
" Kind extends ProcedureKind,",
|
|
2488
|
+
" Idempotency extends IdempotencyMode,",
|
|
2489
|
+
'> = Kind extends "query"',
|
|
2490
|
+
' ? { query: QueryableProcedure<Options, Result, Idempotency, "query"> }',
|
|
2491
|
+
' : { mutate: QueryableProcedure<Options, Result, Idempotency, "mutation"> };',
|
|
2492
|
+
"",
|
|
2409
2493
|
'export type ApiClientErrorCode = "API_HTTP_ERROR" | "API_RESPONSE_INVALID" | "API_RESPONSE_UNDECLARED";',
|
|
2410
2494
|
"",
|
|
2411
2495
|
"export interface ApiClientErrorDetails {",
|
|
@@ -2449,6 +2533,17 @@ function renderClient(graph, options) {
|
|
|
2449
2533
|
" : { (options: Options): Promise<Result>; <T>(options: Options, decode: ResponseDecoder<T>): Promise<T> }",
|
|
2450
2534
|
") & ((...args: {} extends Options ? [options?: Options] : [options: Options]) => Promise<[Result] extends [never] ? unknown : Result>);",
|
|
2451
2535
|
"",
|
|
2536
|
+
"export interface ApiProcedureDefinition {",
|
|
2537
|
+
" method: string;",
|
|
2538
|
+
" path: string;",
|
|
2539
|
+
" controller: string;",
|
|
2540
|
+
" handler: string;",
|
|
2541
|
+
" kind: ProcedureKind;",
|
|
2542
|
+
" command?: string;",
|
|
2543
|
+
" permission?: string;",
|
|
2544
|
+
" idempotency: IdempotencyMode;",
|
|
2545
|
+
"}",
|
|
2546
|
+
"",
|
|
2452
2547
|
...routeTypes,
|
|
2453
2548
|
...routeTypes.length > 0 ? [""] : [],
|
|
2454
2549
|
"export interface HttpInterceptorRequest {",
|
|
@@ -2456,6 +2551,7 @@ function renderClient(graph, options) {
|
|
|
2456
2551
|
" url: string;",
|
|
2457
2552
|
" headers: Record<string, string>;",
|
|
2458
2553
|
" body?: unknown;",
|
|
2554
|
+
" signal?: AbortSignal;",
|
|
2459
2555
|
"}",
|
|
2460
2556
|
"",
|
|
2461
2557
|
"export type HttpInterceptorFn = (",
|
|
@@ -2474,6 +2570,8 @@ function renderClient(graph, options) {
|
|
|
2474
2570
|
"",
|
|
2475
2571
|
"export const API_ROUTES = " + JSON.stringify(allRoutes, null, 2) + " as const;",
|
|
2476
2572
|
"",
|
|
2573
|
+
"export const API_PROCEDURES: readonly ApiProcedureDefinition[] = " + JSON.stringify(allProcedures, null, 2) + ";",
|
|
2574
|
+
"",
|
|
2477
2575
|
"export type AppRoutePath = typeof API_ROUTES[number]['path'];",
|
|
2478
2576
|
"",
|
|
2479
2577
|
"export const API_SCHEMAS = [",
|
|
@@ -2699,6 +2797,7 @@ function renderClient(graph, options) {
|
|
|
2699
2797
|
` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
|
|
2700
2798
|
" responseKind?: string,",
|
|
2701
2799
|
" raw?: boolean,",
|
|
2800
|
+
" execution?: ProcedureExecutionOptions,",
|
|
2702
2801
|
" ): Promise<T>;",
|
|
2703
2802
|
" async function request<T>(",
|
|
2704
2803
|
" method: string,",
|
|
@@ -2708,6 +2807,7 @@ function renderClient(graph, options) {
|
|
|
2708
2807
|
` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
|
|
2709
2808
|
" responseKind?: string,",
|
|
2710
2809
|
" raw?: boolean,",
|
|
2810
|
+
" execution?: ProcedureExecutionOptions,",
|
|
2711
2811
|
" ): Promise<T | unknown>;",
|
|
2712
2812
|
" async function request(",
|
|
2713
2813
|
" method: string,",
|
|
@@ -2722,6 +2822,7 @@ function renderClient(graph, options) {
|
|
|
2722
2822
|
` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
|
|
2723
2823
|
" responseKind?: string,",
|
|
2724
2824
|
" raw = false,",
|
|
2825
|
+
" execution?: ProcedureExecutionOptions,",
|
|
2725
2826
|
" ): Promise<T | unknown> {",
|
|
2726
2827
|
" const url = `${baseUrl}${buildRouteUrl(path, options.params, options.query)}`;",
|
|
2727
2828
|
' const customHeaders = typeof config.headers === "function" ? await config.headers() : config.headers;',
|
|
@@ -2747,9 +2848,10 @@ function renderClient(graph, options) {
|
|
|
2747
2848
|
" headers: reqPayload.headers,",
|
|
2748
2849
|
" ...(reqPayload.body === undefined ? {} : { body: raw ? rawBody(reqPayload.body) : JSON.stringify(reqPayload.body) }),",
|
|
2749
2850
|
' ...(raw && reqPayload.body instanceof ReadableStream ? { duplex: "half" } : {}),',
|
|
2851
|
+
" ...(reqPayload.signal === undefined ? {} : { signal: reqPayload.signal }),",
|
|
2750
2852
|
" });",
|
|
2751
2853
|
" };",
|
|
2752
|
-
" const response = await executeChain(0, { method, url, headers, body: options.body });",
|
|
2854
|
+
" const response = await executeChain(0, { method, url, headers, body: options.body, ...(execution?.signal === undefined ? {} : { signal: execution.signal }) });",
|
|
2753
2855
|
" const declaredSchema = responseSchemas ? selectResponseSchema(response.status, responseSchemas) : undefined;",
|
|
2754
2856
|
" const failure = (code: ApiClientErrorCode, message: string) => new ApiClientError(message, {",
|
|
2755
2857
|
' code, method, path, status: response.status, requestId: response.headers.get("x-request-id"),',
|
|
@@ -2787,7 +2889,44 @@ function renderClient(graph, options) {
|
|
|
2787
2889
|
" return decode ? decode(checked) : checked;",
|
|
2788
2890
|
" }",
|
|
2789
2891
|
"",
|
|
2790
|
-
|
|
2892
|
+
" function hasHeader(headers: Record<string, string>, name: string): boolean {",
|
|
2893
|
+
" return Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());",
|
|
2894
|
+
" }",
|
|
2895
|
+
"",
|
|
2896
|
+
" function withProcedureExecution(",
|
|
2897
|
+
" options: ClientRequestOptions,",
|
|
2898
|
+
" execution: ProcedureExecutionOptions | undefined,",
|
|
2899
|
+
" idempotency: IdempotencyMode,",
|
|
2900
|
+
" ): ClientRequestOptions {",
|
|
2901
|
+
" const headers = { ...(options.headers as Record<string, string> | undefined) };",
|
|
2902
|
+
" if (execution?.idempotencyKey !== undefined) {",
|
|
2903
|
+
" if (!/^[A-Za-z0-9._:-]{1,512}$/.test(execution.idempotencyKey)) {",
|
|
2904
|
+
' throw new TypeError("idempotencyKey must contain only safe header characters and be at most 512 characters");',
|
|
2905
|
+
" }",
|
|
2906
|
+
' headers["idempotency-key"] = execution.idempotencyKey;',
|
|
2907
|
+
" }",
|
|
2908
|
+
' if (idempotency === "required" && !hasHeader(headers, "idempotency-key")) {',
|
|
2909
|
+
' throw new TypeError("This mutation requires an idempotencyKey");',
|
|
2910
|
+
" }",
|
|
2911
|
+
" return Object.keys(headers).length === 0 ? options : { ...options, headers };",
|
|
2912
|
+
" }",
|
|
2913
|
+
"",
|
|
2914
|
+
" function isProcedureExecution(value: unknown): value is ProcedureExecutionOptions {",
|
|
2915
|
+
' if (value === null || typeof value !== "object" || Array.isArray(value)) return false;',
|
|
2916
|
+
' return Object.hasOwn(value, "idempotencyKey") || Object.hasOwn(value, "signal");',
|
|
2917
|
+
" }",
|
|
2918
|
+
"",
|
|
2919
|
+
` function makeProcedure<Options extends ClientRequestOptions, Result = never, Idempotency extends IdempotencyMode = "none", Kind extends ProcedureKind = ProcedureKind>(metadata: ProcedureMetadata<Kind, Idempotency>, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false): QueryableProcedure<Options, Result, Idempotency, Kind> {`,
|
|
2920
|
+
" const procedure = async (first?: Options | ProcedureExecutionOptions, second?: ProcedureExecutionOptions): Promise<unknown> => {",
|
|
2921
|
+
" const execution = second ?? (isProcedureExecution(first) ? first : undefined);",
|
|
2922
|
+
" const input = (execution === first ? undefined : first) ?? {};",
|
|
2923
|
+
" const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, metadata.idempotency);",
|
|
2924
|
+
" return request(metadata.method, metadata.path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
|
|
2925
|
+
" };",
|
|
2926
|
+
" return Object.assign(procedure, { __supacloudProcedure: Object.freeze(metadata) }) as QueryableProcedure<Options, Result, Idempotency, Kind>;",
|
|
2927
|
+
" }",
|
|
2928
|
+
"",
|
|
2929
|
+
` function makeRoute<Options extends ClientRequestOptions, Result = never, Kind extends ProcedureKind = never, Idempotency extends IdempotencyMode = "none">(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false, kind?: Kind, idempotency: Idempotency = "none" as Idempotency, metadata?: ProcedureMetadata<Kind, Idempotency>): RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency> {`,
|
|
2791
2930
|
" function route<T>(options: Options, decode: ResponseDecoder<T>): Promise<T>;",
|
|
2792
2931
|
" function route(options: Options): Promise<Result>;",
|
|
2793
2932
|
" function route(options?: Options): Promise<unknown>;",
|
|
@@ -2795,13 +2934,16 @@ function renderClient(graph, options) {
|
|
|
2795
2934
|
" const requestOptions = options ?? {};",
|
|
2796
2935
|
" return request(method, path, requestOptions, decode, responseSchemas, responseKind, raw);",
|
|
2797
2936
|
" }",
|
|
2798
|
-
|
|
2937
|
+
' if (kind === "query" && metadata) Object.assign(route, { query: makeProcedure<Options, Result, Idempotency, "query">(metadata as ProcedureMetadata<"query", Idempotency>, responseSchemas, responseKind, raw) });',
|
|
2938
|
+
' if (kind === "mutation" && metadata) Object.assign(route, { mutate: makeProcedure<Options, Result, Idempotency, "mutation">(metadata as ProcedureMetadata<"mutation", Idempotency>, responseSchemas, responseKind, raw) });',
|
|
2939
|
+
" return route as RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency>;",
|
|
2799
2940
|
" }",
|
|
2800
2941
|
"",
|
|
2801
2942
|
" return {",
|
|
2802
2943
|
" request,",
|
|
2803
2944
|
" buildRouteUrl,",
|
|
2804
2945
|
" routes: API_ROUTES,",
|
|
2946
|
+
" procedures: API_PROCEDURES,",
|
|
2805
2947
|
...controllerEntries,
|
|
2806
2948
|
" };",
|
|
2807
2949
|
"}",
|
|
@@ -14551,6 +14693,9 @@ function parseDeliveryBuildManifest(value) {
|
|
|
14551
14693
|
if (!Check2(DeliveryBuildManifestSchema, value))
|
|
14552
14694
|
throw new Error("Invalid delivery build manifest.");
|
|
14553
14695
|
validateWorkerExecution(value.plan.targets.flatMap((target) => target.execution ? [target.execution] : []));
|
|
14696
|
+
if (value.plan.targets.reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
|
|
14697
|
+
throw new Error("Invalid delivery replica count.");
|
|
14698
|
+
}
|
|
14554
14699
|
for (const target of value.plan.targets) {
|
|
14555
14700
|
if (target.execution && (target.kind !== "jobs" || target.isolation !== "process" || target.execution.target !== target.name || target.jobs.length !== 1 || target.jobs[0]?.name !== target.execution.taskKey || value.objects.find((object) => object.name === target.name)?.entryKind !== "bun-worker-application")) {
|
|
14556
14701
|
throw new Error("Invalid delivery execution binding.");
|
|
@@ -14564,7 +14709,7 @@ function parseDeliveryBuildManifest(value) {
|
|
|
14564
14709
|
}
|
|
14565
14710
|
for (const object of value.objects) {
|
|
14566
14711
|
const target = value.plan.targets.find((target) => target.name === object.name);
|
|
14567
|
-
if (
|
|
14712
|
+
if (["bun-worker-application", "go-worker-application", "scriptc-worker-application"].includes(object.entryKind) && target?.kind !== "jobs" || object.entryKind === "bun-http-application" && target?.kind === "jobs") {
|
|
14568
14713
|
throw new Error("Delivery executable kind does not match its target.");
|
|
14569
14714
|
}
|
|
14570
14715
|
if (new Set(object.files.map((file) => file.path)).size !== object.files.length || !object.files.some((file) => file.path === object.entrypoint) || deliveryObjectDigest(object) !== object.objectId) {
|
|
@@ -14602,7 +14747,9 @@ var init_delivery_build_schema = __esm(() => {
|
|
|
14602
14747
|
entryKind: Union([
|
|
14603
14748
|
Literal("compiled-module-factory"),
|
|
14604
14749
|
Literal("bun-http-application"),
|
|
14605
|
-
Literal("bun-worker-application")
|
|
14750
|
+
Literal("bun-worker-application"),
|
|
14751
|
+
Literal("go-worker-application"),
|
|
14752
|
+
Literal("scriptc-worker-application")
|
|
14606
14753
|
]),
|
|
14607
14754
|
runtimeImports: _Array_(String2()),
|
|
14608
14755
|
files: _Array_(_Object_({
|
|
@@ -15703,6 +15850,107 @@ var init_application_activation = __esm(() => {
|
|
|
15703
15850
|
}, { additionalProperties: false });
|
|
15704
15851
|
});
|
|
15705
15852
|
|
|
15853
|
+
// node_modules/@supacloud/delivery/src/deployment-evidence.ts
|
|
15854
|
+
var closed6, sha256, isoDate, status, evidenceStatus, DEPLOYMENT_EVIDENCE_SCHEMA = "supacloud.deployment-evidence.v1", DatabaseProviderSchema, componentName, DeploymentComponentEvidenceSchema, DeploymentEvidenceSchema;
|
|
15855
|
+
var init_deployment_evidence = __esm(() => {
|
|
15856
|
+
init_build();
|
|
15857
|
+
init_value2();
|
|
15858
|
+
init_application_configuration();
|
|
15859
|
+
init_application_release();
|
|
15860
|
+
closed6 = { additionalProperties: false };
|
|
15861
|
+
sha256 = String2({ pattern: "^[a-f0-9]{64}$" });
|
|
15862
|
+
isoDate = String2({ minLength: 20, maxLength: 40 });
|
|
15863
|
+
status = Union([
|
|
15864
|
+
Literal("confirmed"),
|
|
15865
|
+
Literal("failed"),
|
|
15866
|
+
Literal("unknown")
|
|
15867
|
+
]);
|
|
15868
|
+
evidenceStatus = Union([
|
|
15869
|
+
Literal("confirmed"),
|
|
15870
|
+
Literal("failed"),
|
|
15871
|
+
Literal("unknown"),
|
|
15872
|
+
Literal("incomplete")
|
|
15873
|
+
]);
|
|
15874
|
+
DatabaseProviderSchema = _Object_({
|
|
15875
|
+
provider: String2({ minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9_.-]*$" }),
|
|
15876
|
+
version: String2({ minLength: 1, maxLength: 64 }),
|
|
15877
|
+
topology: Union([Literal("single-node"), Literal("distributed")]),
|
|
15878
|
+
migration: _Object_({
|
|
15879
|
+
status,
|
|
15880
|
+
inventory_sha256: Union([sha256, Null()]),
|
|
15881
|
+
compatibility: Union([
|
|
15882
|
+
Literal("verified"),
|
|
15883
|
+
Literal("not-proven"),
|
|
15884
|
+
Literal("failed")
|
|
15885
|
+
])
|
|
15886
|
+
}, closed6),
|
|
15887
|
+
backup: _Object_({
|
|
15888
|
+
status,
|
|
15889
|
+
latest_success_at: Union([isoDate, Null()]),
|
|
15890
|
+
freshness_seconds: Union([Integer({ minimum: 0 }), Null()])
|
|
15891
|
+
}, closed6),
|
|
15892
|
+
recovery: _Object_({
|
|
15893
|
+
status,
|
|
15894
|
+
drill_id: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
|
|
15895
|
+
rpo_seconds: Union([Integer({ minimum: 0 }), Null()]),
|
|
15896
|
+
rto_seconds: Union([Integer({ minimum: 0 }), Null()])
|
|
15897
|
+
}, closed6)
|
|
15898
|
+
}, closed6);
|
|
15899
|
+
componentName = Union([
|
|
15900
|
+
Literal("management-api"),
|
|
15901
|
+
Literal("web-console"),
|
|
15902
|
+
Literal("edge-runtime"),
|
|
15903
|
+
Literal("worker"),
|
|
15904
|
+
Literal("postgres"),
|
|
15905
|
+
Literal("postgrest"),
|
|
15906
|
+
Literal("gotrue"),
|
|
15907
|
+
Literal("storage"),
|
|
15908
|
+
Literal("realtime")
|
|
15909
|
+
]);
|
|
15910
|
+
DeploymentComponentEvidenceSchema = _Object_({
|
|
15911
|
+
name: componentName,
|
|
15912
|
+
version: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
|
|
15913
|
+
status,
|
|
15914
|
+
health_check: Union([String2({ minLength: 1, maxLength: 256 }), Null()]),
|
|
15915
|
+
checked_at: Union([isoDate, Null()])
|
|
15916
|
+
}, closed6);
|
|
15917
|
+
DeploymentEvidenceSchema = _Object_({
|
|
15918
|
+
schema: Literal(DEPLOYMENT_EVIDENCE_SCHEMA),
|
|
15919
|
+
status: evidenceStatus,
|
|
15920
|
+
recorded_at: isoDate,
|
|
15921
|
+
scope: _Object_({
|
|
15922
|
+
project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
|
|
15923
|
+
application_id: ApplicationIdSchema,
|
|
15924
|
+
environment_id: ApplicationIdSchema
|
|
15925
|
+
}, closed6),
|
|
15926
|
+
source: _Object_({
|
|
15927
|
+
commit_sha: Union([String2({ pattern: "^[0-9a-f]{7,64}$" }), Null()]),
|
|
15928
|
+
manifest_sha256: sha256,
|
|
15929
|
+
contract_schema: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
|
|
15930
|
+
environment_binding_version: Union([sha256, Null()])
|
|
15931
|
+
}, closed6),
|
|
15932
|
+
database: DatabaseProviderSchema,
|
|
15933
|
+
components: _Array_(DeploymentComponentEvidenceSchema, { minItems: 1, maxItems: 32 }),
|
|
15934
|
+
activation: _Object_({
|
|
15935
|
+
release_id: ApplicationReleaseIdSchema,
|
|
15936
|
+
configuration_id: ApplicationConfigurationIdSchema,
|
|
15937
|
+
activation_id: ApplicationConfigurationIdSchema
|
|
15938
|
+
}, closed6),
|
|
15939
|
+
health: _Object_({
|
|
15940
|
+
status,
|
|
15941
|
+
checked_at: Union([isoDate, Null()]),
|
|
15942
|
+
authenticated_smoke: status
|
|
15943
|
+
}, closed6),
|
|
15944
|
+
rollback: _Object_({
|
|
15945
|
+
release_id: Union([ApplicationReleaseIdSchema, Null()]),
|
|
15946
|
+
configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
|
|
15947
|
+
status: Union([Literal("ready"), Literal("not-ready"), Literal("unknown")]),
|
|
15948
|
+
result: Union([status, Null()])
|
|
15949
|
+
}, closed6),
|
|
15950
|
+
notes: _Array_(String2({ minLength: 1, maxLength: 512 }), { maxItems: 32 })
|
|
15951
|
+
}, closed6);
|
|
15952
|
+
});
|
|
15953
|
+
|
|
15706
15954
|
// node_modules/@supacloud/delivery/src/application-runtime-identity.ts
|
|
15707
15955
|
var APPLICATION_RUNTIME_PROBE_PATH = "/.well-known/supacloud/runtime", ApplicationRuntimeIdentitySchema, ApplicationReadinessReportSchema;
|
|
15708
15956
|
var init_application_runtime_identity = __esm(() => {
|
|
@@ -15825,6 +16073,7 @@ var init_src = __esm(() => {
|
|
|
15825
16073
|
init_application_activation();
|
|
15826
16074
|
init_application_release();
|
|
15827
16075
|
init_application_configuration();
|
|
16076
|
+
init_deployment_evidence();
|
|
15828
16077
|
init_application_runtime_identity();
|
|
15829
16078
|
init_delivery_build_schema();
|
|
15830
16079
|
init_delivery_migration_archive();
|
|
@@ -23140,7 +23389,7 @@ function isRecord2(value) {
|
|
|
23140
23389
|
function arrayLength(value) {
|
|
23141
23390
|
return Array.isArray(value) ? value.length : undefined;
|
|
23142
23391
|
}
|
|
23143
|
-
async function
|
|
23392
|
+
async function sha2562(path) {
|
|
23144
23393
|
return createHash10("sha256").update(await readFile11(path)).digest("hex");
|
|
23145
23394
|
}
|
|
23146
23395
|
function overallStatus(findings) {
|
|
@@ -23214,7 +23463,7 @@ async function assessMigration(options) {
|
|
|
23214
23463
|
contractsManifest = {
|
|
23215
23464
|
path: contractsManifestPath,
|
|
23216
23465
|
present: true,
|
|
23217
|
-
sha256: await
|
|
23466
|
+
sha256: await sha2562(contractsManifestPath),
|
|
23218
23467
|
version: 1,
|
|
23219
23468
|
...arrayLength(parsed.commands) === undefined ? {} : { commands: arrayLength(parsed.commands) },
|
|
23220
23469
|
...arrayLength(parsed.routes) === undefined ? {} : { routes: arrayLength(parsed.routes) },
|
|
@@ -23237,9 +23486,9 @@ async function assessMigration(options) {
|
|
|
23237
23486
|
const diff = diffOpenApiDocuments(await readOpenApiJson(baselinePath), await readOpenApiJson(currentPath));
|
|
23238
23487
|
openApi = {
|
|
23239
23488
|
baselinePath,
|
|
23240
|
-
baselineSha256: await
|
|
23489
|
+
baselineSha256: await sha2562(baselinePath),
|
|
23241
23490
|
currentPath,
|
|
23242
|
-
currentSha256: await
|
|
23491
|
+
currentSha256: await sha2562(currentPath),
|
|
23243
23492
|
diff
|
|
23244
23493
|
};
|
|
23245
23494
|
if (!diff.ok) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supacloud/compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Static compiler for @supacloud/app metadata: builds the application graph from AST, validates it, and generates reflection-free factory code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"directory": "packages/compiler"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@supacloud/delivery": "0.
|
|
57
|
+
"@supacloud/delivery": "0.7.0",
|
|
58
58
|
"typebox": "1.3.34",
|
|
59
59
|
"@graphql-codegen/core": "^6.2.0",
|
|
60
60
|
"@graphql-codegen/typed-document-node": "^7.1.0",
|