@distilled.cloud/core 1.0.0-rc.12 → 1.0.0-rc.13

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 (149) hide show
  1. package/lib/api.d.ts +4 -4
  2. package/lib/api.d.ts.map +1 -1
  3. package/lib/api.js +1 -1
  4. package/lib/api.js.map +1 -1
  5. package/lib/category.js +1 -1
  6. package/lib/category.js.map +1 -1
  7. package/lib/codegen/boolean-string-enums.d.ts +8 -8
  8. package/lib/codegen/boolean-string-enums.d.ts.map +1 -1
  9. package/lib/codegen/boolean-string-enums.js +84 -27
  10. package/lib/codegen/boolean-string-enums.js.map +1 -1
  11. package/lib/codegen/boolean-string-enums.test.js +130 -0
  12. package/lib/codegen/boolean-string-enums.test.js.map +1 -1
  13. package/lib/codegen/cli.js +2 -2
  14. package/lib/codegen/cli.js.map +1 -1
  15. package/lib/codegen/generator.d.ts +20 -3
  16. package/lib/codegen/generator.d.ts.map +1 -1
  17. package/lib/codegen/generator.js +36 -9
  18. package/lib/codegen/generator.js.map +1 -1
  19. package/lib/codegen/generator.test.d.ts +2 -0
  20. package/lib/codegen/generator.test.d.ts.map +1 -0
  21. package/lib/codegen/generator.test.js +126 -0
  22. package/lib/codegen/generator.test.js.map +1 -0
  23. package/lib/codegen/graphql-client.d.ts +7 -1
  24. package/lib/codegen/graphql-client.d.ts.map +1 -1
  25. package/lib/codegen/graphql-client.js +262 -125
  26. package/lib/codegen/graphql-client.js.map +1 -1
  27. package/lib/codegen/graphql-client.test.js +104 -236
  28. package/lib/codegen/graphql-client.test.js.map +1 -1
  29. package/lib/codegen/openapi-binary.test.d.ts +2 -0
  30. package/lib/codegen/openapi-binary.test.d.ts.map +1 -0
  31. package/lib/codegen/openapi-binary.test.js +67 -0
  32. package/lib/codegen/openapi-binary.test.js.map +1 -0
  33. package/lib/codegen/openapi.d.ts +7 -1
  34. package/lib/codegen/openapi.d.ts.map +1 -1
  35. package/lib/codegen/openapi.js +15 -4
  36. package/lib/codegen/openapi.js.map +1 -1
  37. package/lib/codegen/patches.d.ts +16 -1
  38. package/lib/codegen/patches.d.ts.map +1 -1
  39. package/lib/codegen/patches.js +70 -4
  40. package/lib/codegen/patches.js.map +1 -1
  41. package/lib/codegen/patches.test.js +48 -2
  42. package/lib/codegen/patches.test.js.map +1 -1
  43. package/lib/codegen/untagged-unions.test.d.ts +2 -0
  44. package/lib/codegen/untagged-unions.test.d.ts.map +1 -0
  45. package/lib/codegen/untagged-unions.test.js +80 -0
  46. package/lib/codegen/untagged-unions.test.js.map +1 -0
  47. package/lib/errors.d.ts +2 -1
  48. package/lib/errors.d.ts.map +1 -1
  49. package/lib/errors.js +5 -2
  50. package/lib/errors.js.map +1 -1
  51. package/lib/fixtures/xml/upstream-validator.json +397 -0
  52. package/lib/graphql.d.ts +296 -205
  53. package/lib/graphql.d.ts.map +1 -1
  54. package/lib/graphql.js +968 -631
  55. package/lib/graphql.js.map +1 -1
  56. package/lib/graphql.test.js +134 -763
  57. package/lib/graphql.test.js.map +1 -1
  58. package/lib/graphql.types.d.ts +10 -0
  59. package/lib/graphql.types.d.ts.map +1 -1
  60. package/lib/graphql.types.js +4 -44
  61. package/lib/graphql.types.js.map +1 -1
  62. package/lib/index.d.ts +27 -0
  63. package/lib/index.d.ts.map +1 -0
  64. package/lib/index.js +27 -0
  65. package/lib/index.js.map +1 -0
  66. package/lib/pagination.d.ts +2 -1
  67. package/lib/pagination.d.ts.map +1 -1
  68. package/lib/pagination.js +24 -16
  69. package/lib/pagination.js.map +1 -1
  70. package/lib/pagination.test.d.ts +2 -0
  71. package/lib/pagination.test.d.ts.map +1 -0
  72. package/lib/pagination.test.js +134 -0
  73. package/lib/pagination.test.js.map +1 -0
  74. package/lib/protocol-http.d.ts +12 -17
  75. package/lib/protocol-http.d.ts.map +1 -1
  76. package/lib/protocol-http.js +100 -45
  77. package/lib/protocol-http.js.map +1 -1
  78. package/lib/protocol-http.test.js +130 -0
  79. package/lib/protocol-http.test.js.map +1 -1
  80. package/lib/protocol-rest.d.ts +18 -1
  81. package/lib/protocol-rest.d.ts.map +1 -1
  82. package/lib/protocol-rest.js +24 -4
  83. package/lib/protocol-rest.js.map +1 -1
  84. package/lib/query.d.ts +29 -0
  85. package/lib/query.d.ts.map +1 -0
  86. package/lib/query.js +27 -0
  87. package/lib/query.js.map +1 -0
  88. package/lib/response-validation.d.ts +67 -0
  89. package/lib/response-validation.d.ts.map +1 -0
  90. package/lib/response-validation.js +76 -0
  91. package/lib/response-validation.js.map +1 -0
  92. package/lib/response-validation.test.d.ts +2 -0
  93. package/lib/response-validation.test.d.ts.map +1 -0
  94. package/lib/response-validation.test.js +67 -0
  95. package/lib/response-validation.test.js.map +1 -0
  96. package/lib/testing.d.ts +39 -0
  97. package/lib/testing.d.ts.map +1 -0
  98. package/lib/testing.js +41 -0
  99. package/lib/testing.js.map +1 -0
  100. package/lib/trait.d.ts +29 -9
  101. package/lib/trait.d.ts.map +1 -1
  102. package/lib/trait.js +8 -0
  103. package/lib/trait.js.map +1 -1
  104. package/lib/xml.d.ts +44 -0
  105. package/lib/xml.d.ts.map +1 -0
  106. package/lib/xml.js +315 -0
  107. package/lib/xml.js.map +1 -0
  108. package/lib/xml.test.d.ts +2 -0
  109. package/lib/xml.test.d.ts.map +1 -0
  110. package/lib/xml.test.js +211 -0
  111. package/lib/xml.test.js.map +1 -0
  112. package/package.json +4 -4
  113. package/src/api.ts +4 -4
  114. package/src/category.ts +1 -1
  115. package/src/codegen/boolean-string-enums.test.ts +147 -0
  116. package/src/codegen/boolean-string-enums.ts +84 -27
  117. package/src/codegen/cli.ts +2 -2
  118. package/src/codegen/generator.test.ts +151 -0
  119. package/src/codegen/generator.ts +70 -12
  120. package/src/codegen/graphql-client.test.ts +116 -283
  121. package/src/codegen/graphql-client.ts +326 -169
  122. package/src/codegen/openapi-binary.test.ts +98 -0
  123. package/src/codegen/openapi.ts +26 -4
  124. package/src/codegen/patches.test.ts +66 -1
  125. package/src/codegen/patches.ts +84 -4
  126. package/src/codegen/untagged-unions.test.ts +89 -0
  127. package/src/errors.ts +5 -2
  128. package/src/fixtures/xml/upstream-validator.json +397 -0
  129. package/src/graphql.test.ts +174 -948
  130. package/src/graphql.ts +1592 -1167
  131. package/src/graphql.types.ts +92 -163
  132. package/src/index.ts +26 -0
  133. package/src/pagination.test.ts +191 -0
  134. package/src/pagination.ts +35 -25
  135. package/src/protocol-http.test.ts +163 -0
  136. package/src/protocol-http.ts +122 -46
  137. package/src/protocol-rest.ts +62 -13
  138. package/src/query.ts +39 -0
  139. package/src/response-validation.test.ts +95 -0
  140. package/src/response-validation.ts +116 -0
  141. package/src/testing.ts +78 -0
  142. package/src/trait.ts +39 -8
  143. package/src/xml.test.ts +269 -0
  144. package/src/xml.ts +339 -0
  145. package/lib/graphql.fixture.d.ts +0 -249
  146. package/lib/graphql.fixture.d.ts.map +0 -1
  147. package/lib/graphql.fixture.js +0 -240
  148. package/lib/graphql.fixture.js.map +0 -1
  149. package/src/graphql.fixture.ts +0 -371
@@ -196,6 +196,8 @@ export interface SdkSpec {
196
196
  readonly prelude?: Record<string, string>;
197
197
  /** Prelude scalar → TS type map. Default {@link TS_JSON_PRELUDE}. */
198
198
  readonly tsPrelude?: Record<string, string>;
199
+ /** Use Codec for service-free, same-type schemas; Schema leaves services unspecified. */
200
+ readonly schemaType?: "Schema" | "Codec";
199
201
  /** Wire member name → TS-facing name. Default: identity. */
200
202
  readonly memberName?: (name: string) => string;
201
203
  /** Operation shape name → exported const name. Default: lowerFirst. */
@@ -272,6 +274,11 @@ export interface SdkSpec {
272
274
  readonly memberExtraPipes?: (m: EmittedMember) => string[];
273
275
  /** Full override of member pipe emission (rarely needed). */
274
276
  readonly memberPipes?: (m: EmittedMember) => string[];
277
+ /** Override the value schema before nullability, bindings and optionality. */
278
+ readonly memberSchema?: (
279
+ m: EmittedMember,
280
+ ref: (target: string) => string,
281
+ ) => string | undefined;
275
282
  /** Function override for member TS types beyond the binding table. */
276
283
  readonly memberTsType?: (
277
284
  m: EmittedMember,
@@ -353,8 +360,10 @@ export interface SdkSpec {
353
360
  * and the schema is `S.Unknown.pipe(T.UnionCases([...case key sets]))` —
354
361
  * the protocol discriminates by key-set at decode time (for APIs that
355
362
  * return every case's keys with nulls, like Cloudflare's).
363
+ * `"untagged"`: validate the value directly against the case schemas.
364
+ * `"primitive"`: emit unwrapped unions of primitive or enum values.
356
365
  */
357
- readonly unionStyle?: "opaque-cases";
366
+ readonly unionStyle?: "opaque-cases" | "untagged" | "primitive";
358
367
  /** Full override of union emission. */
359
368
  readonly union?: (ctx: {
360
369
  readonly name: string;
@@ -407,13 +416,26 @@ export interface SdkSpec {
407
416
  /** Error classes appended to every op's `errors: [...]` list. */
408
417
  readonly commonErrorClasses: readonly string[];
409
418
  readonly protocol: string;
410
- /** The retry tag expression (e.g. `Retry.Retry`). */
411
- readonly retry: string;
419
+ /** The retry tag expression (e.g. `Retry.Retry`). Omit to disable retries. */
420
+ readonly retry?: string;
412
421
  /**
413
422
  * Extra config lines inserted before the pagination entry (e.g. AWS's
414
423
  * `operationName` and `endpointHostPrefix`).
415
424
  */
416
425
  readonly extraConfig?: (ctx: OperationEmit) => string[];
426
+ /**
427
+ * Per-operation `protocol` / `contextType` replacing the declared
428
+ * defaults, e.g. an unauthenticated login endpoint on a public protocol
429
+ * whose context has no credentials. Return `undefined` for the defaults.
430
+ * The header only imports the defaults; a spec that overrides must add
431
+ * the extra imports itself (see {@link SdkSpec.postProcess}).
432
+ */
433
+ readonly overrides?: (ctx: OperationEmit) =>
434
+ | {
435
+ readonly protocol?: string;
436
+ readonly contextType?: string;
437
+ }
438
+ | undefined;
417
439
  };
418
440
  /** Full override of operation const emission. */
419
441
  readonly operation?: (ctx: OperationEmit) => string;
@@ -733,7 +755,9 @@ export const generateService = (
733
755
  )?.tsType;
734
756
 
735
757
  const emitMember = (info: EmittedMember, selfIdx: number): string => {
736
- let expr = ref(info.target, selfIdx);
758
+ let expr =
759
+ spec.memberSchema?.(info, (target) => ref(target, selfIdx)) ??
760
+ ref(info.target, selfIdx);
737
761
  if (info.nullable) expr = `S.NullOr(${expr})`;
738
762
  const pipes = memberPipes(info);
739
763
  if (pipes.length) expr = `${expr}.pipe(${pipes.join(", ")})`;
@@ -918,6 +942,7 @@ export const generateService = (
918
942
  pure,
919
943
  multiline: true,
920
944
  annotateIdentifier: true,
945
+ castTo: `S.${spec.schemaType ?? "Schema"}<${name}>`,
921
946
  expr: `${ref(m.target, i)}.pipe(${rootPipes.join(", ")})`,
922
947
  }),
923
948
  );
@@ -996,6 +1021,7 @@ export const generateService = (
996
1021
  pure,
997
1022
  multiline: true,
998
1023
  annotateIdentifier: true,
1024
+ castTo: `S.${spec.schemaType ?? "Schema"}<${name}>`,
999
1025
  expr: `${struct}${tail}`,
1000
1026
  }),
1001
1027
  );
@@ -1009,7 +1035,7 @@ export const generateService = (
1009
1035
  `export type ${name} = Array<${tsRefAt(d.member.target, id)}${nullable ? " | null" : ""}>;`,
1010
1036
  );
1011
1037
  out.push(
1012
- `export const ${name} = ${pure}S.Array(${nullable ? `S.NullOr(${item})` : item}) as any as S.Schema<${name}>;\n`,
1038
+ `export const ${name} = ${pure}S.Array(${nullable ? `S.NullOr(${item})` : item}) as any as S.${spec.schemaType ?? "Schema"}<${name}>;\n`,
1013
1039
  );
1014
1040
  } else if (d.type === "map") {
1015
1041
  const nullable =
@@ -1020,7 +1046,7 @@ export const generateService = (
1020
1046
  `export type ${name} = { [key: string]: ${tsRefAt(d.value.target, id)}${nullable ? " | null" : ""} | undefined };`,
1021
1047
  );
1022
1048
  out.push(
1023
- `export const ${name} = ${pure}S.Record(S.String, ${nullable ? `S.NullOr(${value})` : value}) as any as S.Schema<${name}>;\n`,
1049
+ `export const ${name} = ${pure}S.Record(S.String, ${nullable ? `S.NullOr(${value})` : value}) as any as S.${spec.schemaType ?? "Schema"}<${name}>;\n`,
1024
1050
  );
1025
1051
  } else if (d.type === "union") {
1026
1052
  // A union arm targeting the union itself carries no information
@@ -1039,6 +1065,33 @@ export const generateService = (
1039
1065
  });
1040
1066
  if (spec.union) {
1041
1067
  out.push(...spec.union({ name, caseTargets, caseKeys, tsRef }));
1068
+ } else if (spec.unionStyle === "untagged") {
1069
+ out.push(
1070
+ `export type ${name} = ${caseTargets.map((t) => tsRefAt(t, id)).join(" | ") || "never"};`,
1071
+ `export const ${name} = ${pure}S.Union([${caseTargets.map((t) => ref(t, i)).join(", ")}]) as any as S.${spec.schemaType ?? "Schema"}<${name}>;\n`,
1072
+ );
1073
+ } else if (
1074
+ spec.unionStyle === "primitive" &&
1075
+ caseTargets.length > 0 &&
1076
+ caseTargets.every(
1077
+ (target) =>
1078
+ ["string", "number", "boolean"].includes(tsRef(target)) ||
1079
+ shapes[target]?.type === "enum" ||
1080
+ shapes[target]?.type === "intEnum",
1081
+ )
1082
+ ) {
1083
+ // Primitive unions keep response enums open to match S.String/S.Number.
1084
+ const primitiveType = (target: string) => {
1085
+ const type = tsRef(target);
1086
+ if (shapes[target]?.type === "enum") return `${type} | (string & {})`;
1087
+ if (shapes[target]?.type === "intEnum")
1088
+ return `${type} | (number & {})`;
1089
+ return type;
1090
+ };
1091
+ out.push(
1092
+ `export type ${name} = ${caseTargets.map(primitiveType).join(" | ")};`,
1093
+ `export const ${name}: S.Codec<${name}> = ${pure}S.Union([${caseTargets.map((t) => ref(t, i)).join(", ")}]);\n`,
1094
+ );
1042
1095
  } else if (spec.unionStyle === "opaque-cases") {
1043
1096
  const disc = unionDiscriminator(caseTargets);
1044
1097
  out.push(
@@ -1123,6 +1176,9 @@ export const generateService = (
1123
1176
  throw new Error("SdkSpec needs either operationDecl or operation");
1124
1177
  }
1125
1178
  const errList = [...ctx.errorNames, ...decl.commonErrorClasses];
1179
+ const overrides = decl.overrides?.(ctx);
1180
+ const contextType = overrides?.contextType ?? decl.contextType;
1181
+ const protocol = overrides?.protocol ?? decl.protocol;
1126
1182
  const paginated = ctx.pagination !== undefined;
1127
1183
  const itemTsType = paginated
1128
1184
  ? paginatedItemTsType(
@@ -1135,7 +1191,7 @@ export const generateService = (
1135
1191
  ` ${ctx.inputName},\n` +
1136
1192
  ` ${ctx.outputTsType},\n` +
1137
1193
  ` ${ctx.opName}Error,\n` +
1138
- ` ${decl.contextType}` +
1194
+ ` ${contextType}` +
1139
1195
  (itemTsType ? `,\n ${itemTsType}\n` : `\n`) +
1140
1196
  `>`;
1141
1197
  const config =
@@ -1143,8 +1199,8 @@ export const generateService = (
1143
1199
  ` input: ${ctx.inputName},\n` +
1144
1200
  ` output: ${ctx.outputSchema},\n` +
1145
1201
  ` errors: [${errList.join(", ")}],\n` +
1146
- ` protocol: ${(paginated && opProfile.get(ctx.op.id)?.protocol) || decl.protocol},\n` +
1147
- ` retry: ${decl.retry},\n` +
1202
+ ` protocol: ${(paginated && opProfile.get(ctx.op.id)?.protocol) || protocol},\n` +
1203
+ (decl.retry ? ` retry: ${decl.retry},\n` : "") +
1148
1204
  (decl.extraConfig?.(ctx) ?? []).map((l) => ` ${l},\n`).join("") +
1149
1205
  (paginated
1150
1206
  ? ` pagination: ${JSON.stringify(ctx.pagination)} as const,\n`
@@ -1218,7 +1274,7 @@ export const generateService = (
1218
1274
  "the default header needs operationDecl — or pass header",
1219
1275
  );
1220
1276
  }
1221
- const retryNs = decl.retry.split(".")[0];
1277
+ const retryNs = decl.retry?.split(".")[0];
1222
1278
  // Imports the used pagination profiles pull in: their protocol consts
1223
1279
  // (from the protocol module) and strategy/injected-member names (from
1224
1280
  // the pagination module).
@@ -1256,8 +1312,10 @@ export const generateService = (
1256
1312
  (ctx.hasPaginated && pagImports.length
1257
1313
  ? `import { ${pagImports.join(", ")} } from "../pagination.ts";\n`
1258
1314
  : "") +
1259
- `import { ${[...decl.commonErrorClasses].sort().join(", ")} } from "../errors.ts";\n` +
1260
- `import * as ${retryNs} from "../retry.ts";\n\n` +
1315
+ (decl.commonErrorClasses.length
1316
+ ? `import { ${[...decl.commonErrorClasses].sort().join(", ")} } from "../errors.ts";\n`
1317
+ : "") +
1318
+ (retryNs ? `import * as ${retryNs} from "../retry.ts";\n\n` : "\n") +
1261
1319
  // Re-exported so inferred provider types downstream can always name them.
1262
1320
  `export type { ${decl.commonErrorType}, ${decl.contextType} };\n\n` +
1263
1321
  (spec.rootKeyDictionary