@supacloud/compiler 0.33.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.
Files changed (3) hide show
  1. package/dist/cli.js +42 -10
  2. package/dist/index.js +42 -10
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2380,6 +2380,15 @@ function renderClient(graph, options) {
2380
2380
  const command = route.command === undefined ? undefined : commandByClassName.get(route.command);
2381
2381
  const procedureKind = route.method === "GET" || route.method === "HEAD" ? "query" : "mutation";
2382
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
+ };
2383
2392
  allProcedures.push({
2384
2393
  method: route.method,
2385
2394
  path: fullPath,
@@ -2391,7 +2400,7 @@ function renderClient(graph, options) {
2391
2400
  idempotency: idempotencyMode
2392
2401
  });
2393
2402
  routeMethods.push(`
2394
- ${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)}),`);
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)}),`);
2395
2404
  }
2396
2405
  controllerEntries.push(`
2397
2406
  ${controllerKey}: {${routeMethods.join("")}
@@ -2425,6 +2434,19 @@ function renderClient(graph, options) {
2425
2434
  'export type ProcedureKind = "query" | "mutation";',
2426
2435
  'export type IdempotencyMode = "required" | "none";',
2427
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
+ "",
2428
2450
  "export interface ProcedureExecutionOptions {",
2429
2451
  " /** Reuse the same key when retrying an uncertain mutation. */",
2430
2452
  " idempotencyKey?: string;",
@@ -2450,14 +2472,24 @@ function renderClient(graph, options) {
2450
2472
  ' Idempotency extends IdempotencyMode = "none",',
2451
2473
  "> = (...args: ProcedureArgs<Options, Idempotency>) => Promise<ProcedureResult<Result>>;",
2452
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
+ "",
2453
2485
  "export type ProcedureMember<",
2454
2486
  " Options extends ClientRequestOptions,",
2455
2487
  " Result,",
2456
2488
  " Kind extends ProcedureKind,",
2457
2489
  " Idempotency extends IdempotencyMode,",
2458
2490
  '> = Kind extends "query"',
2459
- " ? { query: ProcedureCall<Options, Result, Idempotency> }",
2460
- " : { mutate: ProcedureCall<Options, Result, Idempotency> };",
2491
+ ' ? { query: QueryableProcedure<Options, Result, Idempotency, "query"> }',
2492
+ ' : { mutate: QueryableProcedure<Options, Result, Idempotency, "mutation"> };',
2461
2493
  "",
2462
2494
  'export type ApiClientErrorCode = "API_HTTP_ERROR" | "API_RESPONSE_INVALID" | "API_RESPONSE_UNDECLARED";',
2463
2495
  "",
@@ -2885,17 +2917,17 @@ function renderClient(graph, options) {
2885
2917
  ' return Object.hasOwn(value, "idempotencyKey") || Object.hasOwn(value, "signal");',
2886
2918
  " }",
2887
2919
  "",
2888
- ` function makeProcedure<Options extends ClientRequestOptions, Result = never, Idempotency extends IdempotencyMode = "none">(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false, idempotency: Idempotency = "none" as Idempotency): ProcedureCall<Options, Result, Idempotency> {`,
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> {`,
2889
2921
  " const procedure = async (first?: Options | ProcedureExecutionOptions, second?: ProcedureExecutionOptions): Promise<unknown> => {",
2890
2922
  " const execution = second ?? (isProcedureExecution(first) ? first : undefined);",
2891
2923
  " const input = (execution === first ? undefined : first) ?? {};",
2892
- " const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, idempotency);",
2893
- " return request(method, path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
2924
+ " const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, metadata.idempotency);",
2925
+ " return request(metadata.method, metadata.path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
2894
2926
  " };",
2895
- " return procedure as ProcedureCall<Options, Result, Idempotency>;",
2927
+ " return Object.assign(procedure, { __supacloudProcedure: Object.freeze(metadata) }) as QueryableProcedure<Options, Result, Idempotency, Kind>;",
2896
2928
  " }",
2897
2929
  "",
2898
- ` 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): RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency> {`,
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> {`,
2899
2931
  " function route<T>(options: Options, decode: ResponseDecoder<T>): Promise<T>;",
2900
2932
  " function route(options: Options): Promise<Result>;",
2901
2933
  " function route(options?: Options): Promise<unknown>;",
@@ -2903,8 +2935,8 @@ function renderClient(graph, options) {
2903
2935
  " const requestOptions = options ?? {};",
2904
2936
  " return request(method, path, requestOptions, decode, responseSchemas, responseKind, raw);",
2905
2937
  " }",
2906
- ' if (kind === "query") Object.assign(route, { query: makeProcedure<Options, Result, Idempotency>(method, path, responseSchemas, responseKind, raw, idempotency) });',
2907
- ' if (kind === "mutation") Object.assign(route, { mutate: makeProcedure<Options, Result, Idempotency>(method, path, responseSchemas, responseKind, raw, idempotency) });',
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) });',
2908
2940
  " return route as RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency>;",
2909
2941
  " }",
2910
2942
  "",
package/dist/index.js CHANGED
@@ -2379,6 +2379,15 @@ function renderClient(graph, options) {
2379
2379
  const command = route.command === undefined ? undefined : commandByClassName.get(route.command);
2380
2380
  const procedureKind = route.method === "GET" || route.method === "HEAD" ? "query" : "mutation";
2381
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
+ };
2382
2391
  allProcedures.push({
2383
2392
  method: route.method,
2384
2393
  path: fullPath,
@@ -2390,7 +2399,7 @@ function renderClient(graph, options) {
2390
2399
  idempotency: idempotencyMode
2391
2400
  });
2392
2401
  routeMethods.push(`
2393
- ${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)}),`);
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)}),`);
2394
2403
  }
2395
2404
  controllerEntries.push(`
2396
2405
  ${controllerKey}: {${routeMethods.join("")}
@@ -2424,6 +2433,19 @@ function renderClient(graph, options) {
2424
2433
  'export type ProcedureKind = "query" | "mutation";',
2425
2434
  'export type IdempotencyMode = "required" | "none";',
2426
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
+ "",
2427
2449
  "export interface ProcedureExecutionOptions {",
2428
2450
  " /** Reuse the same key when retrying an uncertain mutation. */",
2429
2451
  " idempotencyKey?: string;",
@@ -2449,14 +2471,24 @@ function renderClient(graph, options) {
2449
2471
  ' Idempotency extends IdempotencyMode = "none",',
2450
2472
  "> = (...args: ProcedureArgs<Options, Idempotency>) => Promise<ProcedureResult<Result>>;",
2451
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
+ "",
2452
2484
  "export type ProcedureMember<",
2453
2485
  " Options extends ClientRequestOptions,",
2454
2486
  " Result,",
2455
2487
  " Kind extends ProcedureKind,",
2456
2488
  " Idempotency extends IdempotencyMode,",
2457
2489
  '> = Kind extends "query"',
2458
- " ? { query: ProcedureCall<Options, Result, Idempotency> }",
2459
- " : { mutate: ProcedureCall<Options, Result, Idempotency> };",
2490
+ ' ? { query: QueryableProcedure<Options, Result, Idempotency, "query"> }',
2491
+ ' : { mutate: QueryableProcedure<Options, Result, Idempotency, "mutation"> };',
2460
2492
  "",
2461
2493
  'export type ApiClientErrorCode = "API_HTTP_ERROR" | "API_RESPONSE_INVALID" | "API_RESPONSE_UNDECLARED";',
2462
2494
  "",
@@ -2884,17 +2916,17 @@ function renderClient(graph, options) {
2884
2916
  ' return Object.hasOwn(value, "idempotencyKey") || Object.hasOwn(value, "signal");',
2885
2917
  " }",
2886
2918
  "",
2887
- ` function makeProcedure<Options extends ClientRequestOptions, Result = never, Idempotency extends IdempotencyMode = "none">(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false, idempotency: Idempotency = "none" as Idempotency): ProcedureCall<Options, Result, Idempotency> {`,
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> {`,
2888
2920
  " const procedure = async (first?: Options | ProcedureExecutionOptions, second?: ProcedureExecutionOptions): Promise<unknown> => {",
2889
2921
  " const execution = second ?? (isProcedureExecution(first) ? first : undefined);",
2890
2922
  " const input = (execution === first ? undefined : first) ?? {};",
2891
- " const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, idempotency);",
2892
- " return request(method, path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
2923
+ " const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, metadata.idempotency);",
2924
+ " return request(metadata.method, metadata.path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
2893
2925
  " };",
2894
- " return procedure as ProcedureCall<Options, Result, Idempotency>;",
2926
+ " return Object.assign(procedure, { __supacloudProcedure: Object.freeze(metadata) }) as QueryableProcedure<Options, Result, Idempotency, Kind>;",
2895
2927
  " }",
2896
2928
  "",
2897
- ` 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): RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency> {`,
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> {`,
2898
2930
  " function route<T>(options: Options, decode: ResponseDecoder<T>): Promise<T>;",
2899
2931
  " function route(options: Options): Promise<Result>;",
2900
2932
  " function route(options?: Options): Promise<unknown>;",
@@ -2902,8 +2934,8 @@ function renderClient(graph, options) {
2902
2934
  " const requestOptions = options ?? {};",
2903
2935
  " return request(method, path, requestOptions, decode, responseSchemas, responseKind, raw);",
2904
2936
  " }",
2905
- ' if (kind === "query") Object.assign(route, { query: makeProcedure<Options, Result, Idempotency>(method, path, responseSchemas, responseKind, raw, idempotency) });',
2906
- ' if (kind === "mutation") Object.assign(route, { mutate: makeProcedure<Options, Result, Idempotency>(method, path, responseSchemas, responseKind, raw, idempotency) });',
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) });',
2907
2939
  " return route as RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency>;",
2908
2940
  " }",
2909
2941
  "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/compiler",
3
- "version": "0.33.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",