@distilled.cloud/core 0.30.3 → 1.0.0-rc.10

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 (216) hide show
  1. package/LICENSE +201 -0
  2. package/lib/api.d.ts +165 -0
  3. package/lib/api.d.ts.map +1 -0
  4. package/lib/api.js +190 -0
  5. package/lib/api.js.map +1 -0
  6. package/lib/category.d.ts +4 -4
  7. package/lib/category.js +4 -4
  8. package/lib/codegen/boolean-string-enums.d.ts +36 -0
  9. package/lib/codegen/boolean-string-enums.d.ts.map +1 -0
  10. package/lib/codegen/boolean-string-enums.js +94 -0
  11. package/lib/codegen/boolean-string-enums.js.map +1 -0
  12. package/lib/codegen/boolean-string-enums.test.d.ts +2 -0
  13. package/lib/codegen/boolean-string-enums.test.d.ts.map +1 -0
  14. package/lib/codegen/boolean-string-enums.test.js +147 -0
  15. package/lib/codegen/boolean-string-enums.test.js.map +1 -0
  16. package/lib/codegen/cli.d.ts +79 -0
  17. package/lib/codegen/cli.d.ts.map +1 -0
  18. package/lib/codegen/cli.js +149 -0
  19. package/lib/codegen/cli.js.map +1 -0
  20. package/lib/codegen/emit.d.ts +125 -0
  21. package/lib/codegen/emit.d.ts.map +1 -0
  22. package/lib/codegen/emit.js +101 -0
  23. package/lib/codegen/emit.js.map +1 -0
  24. package/lib/codegen/format.d.ts +23 -0
  25. package/lib/codegen/format.d.ts.map +1 -0
  26. package/lib/codegen/format.js +28 -0
  27. package/lib/codegen/format.js.map +1 -0
  28. package/lib/codegen/generator.d.ts +334 -0
  29. package/lib/codegen/generator.d.ts.map +1 -0
  30. package/lib/codegen/generator.js +813 -0
  31. package/lib/codegen/generator.js.map +1 -0
  32. package/lib/codegen/graph.d.ts +36 -0
  33. package/lib/codegen/graph.d.ts.map +1 -0
  34. package/lib/codegen/graph.js +136 -0
  35. package/lib/codegen/graph.js.map +1 -0
  36. package/lib/codegen/graphql-client.d.ts +62 -0
  37. package/lib/codegen/graphql-client.d.ts.map +1 -0
  38. package/lib/codegen/graphql-client.js +294 -0
  39. package/lib/codegen/graphql-client.js.map +1 -0
  40. package/lib/codegen/graphql-client.test.d.ts +2 -0
  41. package/lib/codegen/graphql-client.test.d.ts.map +1 -0
  42. package/lib/codegen/graphql-client.test.js +311 -0
  43. package/lib/codegen/graphql-client.test.js.map +1 -0
  44. package/lib/codegen/graphql.d.ts +207 -0
  45. package/lib/codegen/graphql.d.ts.map +1 -0
  46. package/lib/codegen/graphql.js +799 -0
  47. package/lib/codegen/graphql.js.map +1 -0
  48. package/lib/codegen/members.d.ts +25 -0
  49. package/lib/codegen/members.d.ts.map +1 -0
  50. package/lib/codegen/members.js +55 -0
  51. package/lib/codegen/members.js.map +1 -0
  52. package/lib/codegen/naming.d.ts +29 -0
  53. package/lib/codegen/naming.d.ts.map +1 -0
  54. package/lib/codegen/naming.js +74 -0
  55. package/lib/codegen/naming.js.map +1 -0
  56. package/lib/codegen/openapi-cli.d.ts +52 -0
  57. package/lib/codegen/openapi-cli.d.ts.map +1 -0
  58. package/lib/codegen/openapi-cli.js +109 -0
  59. package/lib/codegen/openapi-cli.js.map +1 -0
  60. package/lib/codegen/openapi.d.ts +178 -0
  61. package/lib/codegen/openapi.d.ts.map +1 -0
  62. package/lib/codegen/openapi.js +1377 -0
  63. package/lib/codegen/openapi.js.map +1 -0
  64. package/lib/codegen/operations.d.ts +24 -0
  65. package/lib/codegen/operations.d.ts.map +1 -0
  66. package/lib/codegen/operations.js +56 -0
  67. package/lib/codegen/operations.js.map +1 -0
  68. package/lib/codegen/pagination.d.ts +39 -0
  69. package/lib/codegen/pagination.d.ts.map +1 -0
  70. package/lib/codegen/pagination.js +33 -0
  71. package/lib/codegen/pagination.js.map +1 -0
  72. package/lib/codegen/patches.d.ts +65 -0
  73. package/lib/codegen/patches.d.ts.map +1 -0
  74. package/lib/codegen/patches.js +236 -0
  75. package/lib/codegen/patches.js.map +1 -0
  76. package/lib/codegen/patches.test.d.ts +2 -0
  77. package/lib/codegen/patches.test.d.ts.map +1 -0
  78. package/lib/codegen/patches.test.js +105 -0
  79. package/lib/codegen/patches.test.js.map +1 -0
  80. package/lib/codegen/prelude.d.ts +15 -0
  81. package/lib/codegen/prelude.d.ts.map +1 -0
  82. package/lib/codegen/prelude.js +60 -0
  83. package/lib/codegen/prelude.js.map +1 -0
  84. package/lib/codegen/proto.d.ts +121 -0
  85. package/lib/codegen/proto.d.ts.map +1 -0
  86. package/lib/codegen/proto.js +962 -0
  87. package/lib/codegen/proto.js.map +1 -0
  88. package/lib/codegen/rewrite-operation-ids.d.ts +131 -0
  89. package/lib/codegen/rewrite-operation-ids.d.ts.map +1 -0
  90. package/lib/codegen/rewrite-operation-ids.js +1079 -0
  91. package/lib/codegen/rewrite-operation-ids.js.map +1 -0
  92. package/lib/codegen/rewrite-operation-ids.test.d.ts +2 -0
  93. package/lib/codegen/rewrite-operation-ids.test.d.ts.map +1 -0
  94. package/lib/codegen/rewrite-operation-ids.test.js +533 -0
  95. package/lib/codegen/rewrite-operation-ids.test.js.map +1 -0
  96. package/lib/codegen/spec-path.d.ts +16 -0
  97. package/lib/codegen/spec-path.d.ts.map +1 -0
  98. package/lib/codegen/spec-path.js +101 -0
  99. package/lib/codegen/spec-path.js.map +1 -0
  100. package/lib/error-category.d.ts +28 -0
  101. package/lib/error-category.d.ts.map +1 -0
  102. package/lib/error-category.js +46 -0
  103. package/lib/error-category.js.map +1 -0
  104. package/lib/errors.d.ts +1 -0
  105. package/lib/errors.d.ts.map +1 -1
  106. package/lib/errors.js +18 -13
  107. package/lib/errors.js.map +1 -1
  108. package/lib/graphql.d.ts +284 -0
  109. package/lib/graphql.d.ts.map +1 -0
  110. package/lib/graphql.fixture.d.ts +249 -0
  111. package/lib/graphql.fixture.d.ts.map +1 -0
  112. package/lib/graphql.fixture.js +240 -0
  113. package/lib/graphql.fixture.js.map +1 -0
  114. package/lib/graphql.js +718 -0
  115. package/lib/graphql.js.map +1 -0
  116. package/lib/graphql.test.d.ts +2 -0
  117. package/lib/graphql.test.d.ts.map +1 -0
  118. package/lib/graphql.test.js +780 -0
  119. package/lib/graphql.test.js.map +1 -0
  120. package/lib/graphql.types.d.ts +2 -0
  121. package/lib/graphql.types.d.ts.map +1 -0
  122. package/lib/graphql.types.js +45 -0
  123. package/lib/graphql.types.js.map +1 -0
  124. package/lib/json-patch.d.ts +30 -30
  125. package/lib/json-patch.d.ts.map +1 -1
  126. package/lib/json-patch.js +73 -107
  127. package/lib/json-patch.js.map +1 -1
  128. package/lib/pagination.d.ts +77 -51
  129. package/lib/pagination.d.ts.map +1 -1
  130. package/lib/pagination.js +162 -94
  131. package/lib/pagination.js.map +1 -1
  132. package/lib/protocol-http.d.ts +74 -0
  133. package/lib/protocol-http.d.ts.map +1 -0
  134. package/lib/protocol-http.js +590 -0
  135. package/lib/protocol-http.js.map +1 -0
  136. package/lib/protocol-http.test.d.ts +2 -0
  137. package/lib/protocol-http.test.d.ts.map +1 -0
  138. package/lib/protocol-http.test.js +88 -0
  139. package/lib/protocol-http.test.js.map +1 -0
  140. package/lib/protocol-rest.d.ts +134 -0
  141. package/lib/protocol-rest.d.ts.map +1 -0
  142. package/lib/protocol-rest.js +256 -0
  143. package/lib/protocol-rest.js.map +1 -0
  144. package/lib/retry.d.ts +8 -2
  145. package/lib/retry.d.ts.map +1 -1
  146. package/lib/retry.js +22 -16
  147. package/lib/retry.js.map +1 -1
  148. package/lib/schema.d.ts +8 -9
  149. package/lib/schema.d.ts.map +1 -1
  150. package/lib/schema.js +8 -9
  151. package/lib/schema.js.map +1 -1
  152. package/lib/trait.d.ts +174 -0
  153. package/lib/trait.d.ts.map +1 -0
  154. package/lib/trait.js +123 -0
  155. package/lib/trait.js.map +1 -0
  156. package/package.json +24 -78
  157. package/src/api.ts +460 -0
  158. package/src/category.ts +4 -4
  159. package/src/codegen/boolean-string-enums.test.ts +168 -0
  160. package/src/codegen/boolean-string-enums.ts +106 -0
  161. package/src/codegen/cli.ts +285 -0
  162. package/src/codegen/emit.ts +203 -0
  163. package/src/codegen/format.ts +47 -0
  164. package/src/codegen/generator.ts +1283 -0
  165. package/src/codegen/graph.ts +151 -0
  166. package/src/codegen/graphql-client.test.ts +386 -0
  167. package/src/codegen/graphql-client.ts +419 -0
  168. package/src/codegen/graphql.ts +1217 -0
  169. package/src/codegen/members.ts +71 -0
  170. package/src/codegen/naming.ts +86 -0
  171. package/src/codegen/openapi-cli.ts +182 -0
  172. package/src/codegen/openapi.ts +1689 -0
  173. package/src/codegen/operations.ts +76 -0
  174. package/src/codegen/pagination.ts +71 -0
  175. package/src/codegen/patches.test.ts +130 -0
  176. package/src/codegen/patches.ts +291 -0
  177. package/src/codegen/prelude.ts +70 -0
  178. package/src/codegen/proto.ts +1128 -0
  179. package/src/codegen/rewrite-operation-ids.test.ts +563 -0
  180. package/src/codegen/rewrite-operation-ids.ts +1206 -0
  181. package/src/codegen/spec-path.ts +115 -0
  182. package/src/error-category.ts +84 -0
  183. package/src/errors.ts +22 -25
  184. package/src/graphql.fixture.ts +371 -0
  185. package/src/graphql.test.ts +974 -0
  186. package/src/graphql.ts +1321 -0
  187. package/src/graphql.types.ts +185 -0
  188. package/src/json-patch.ts +95 -122
  189. package/src/pagination.ts +217 -146
  190. package/src/protocol-http.test.ts +107 -0
  191. package/src/protocol-http.ts +735 -0
  192. package/src/protocol-rest.ts +391 -0
  193. package/src/retry.ts +21 -22
  194. package/src/schema.ts +9 -10
  195. package/src/trait.ts +274 -0
  196. package/README.md +0 -30
  197. package/lib/client.d.ts +0 -167
  198. package/lib/client.d.ts.map +0 -1
  199. package/lib/client.js +0 -659
  200. package/lib/client.js.map +0 -1
  201. package/lib/schemas.d.ts +0 -60
  202. package/lib/schemas.d.ts.map +0 -1
  203. package/lib/schemas.js +0 -79
  204. package/lib/schemas.js.map +0 -1
  205. package/lib/sensitive.d.ts +0 -71
  206. package/lib/sensitive.d.ts.map +0 -1
  207. package/lib/sensitive.js +0 -96
  208. package/lib/sensitive.js.map +0 -1
  209. package/lib/traits.d.ts +0 -421
  210. package/lib/traits.d.ts.map +0 -1
  211. package/lib/traits.js +0 -737
  212. package/lib/traits.js.map +0 -1
  213. package/src/client.ts +0 -1177
  214. package/src/schemas.ts +0 -128
  215. package/src/sensitive.ts +0 -119
  216. package/src/traits.ts +0 -996
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Generic REST protocol machinery, shared by SDK protocol layers.
3
+ *
4
+ * Everything here is driven purely by the trait annotations in
5
+ * `core/trait.ts` — nothing is provider-specific. An SDK protocol (e.g.
6
+ * cloudflare's) supplies credentials/base-URL, calls {@link buildRequest} to
7
+ * encode, and layers its own response-envelope handling on top of the
8
+ * decode-side helpers ({@link getProps}/{@link mapKeys}/
9
+ * {@link matchTypedError}).
10
+ */
11
+ import type * as AST from "effect/SchemaAST";
12
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
13
+ import { type ErrorMatcher, type KeyDictionaryEntries } from "./trait.ts";
14
+ export declare const getProps: (ast: AST.AST) => readonly AST.PropertySignature[];
15
+ export declare const getAnn: (ast: AST.AST, symbol: symbol) => unknown;
16
+ export declare const getPropAnn: (prop: AST.PropertySignature, symbol: symbol) => unknown;
17
+ export declare const hasPropAnn: (prop: AST.PropertySignature, symbol: symbol) => boolean;
18
+ export declare const nameOf: (prop: AST.PropertySignature, symbol: symbol) => string;
19
+ /** Resolve wrappers to the real node: Suspend, encoding, optional/null unions. */
20
+ export declare const resolveNode: (ast: AST.AST) => AST.AST;
21
+ /** Binary/opaque values that must never be treated as key-value objects. */
22
+ export declare const isOpaqueValue: (v: unknown) => boolean;
23
+ /**
24
+ * Deep-rename keys via a plain dictionary (see `T.KeyDictionary`). An entry
25
+ * may list several wire spellings; encode uses the first (canonical) one and
26
+ * decode maps every listed spelling back to the TS name.
27
+ */
28
+ export declare const mapKeysByDictionary: (dict: KeyDictionaryEntries, value: unknown, direction: "encode" | "decode") => unknown;
29
+ /**
30
+ * Recursively rename keys between TS names and wire names, per the schema.
31
+ *
32
+ * `fallback` is the nearest ancestor `T.KeyDictionary` — schema-known members
33
+ * always map via their own annotations, but opaque values (Document members,
34
+ * keys the schema doesn't know) deep-rename via the dictionary so nested
35
+ * TS-cased content still reaches the wire in wire case. Content with no
36
+ * dictionary in scope passes through verbatim.
37
+ */
38
+ export declare const mapKeys: (ast: AST.AST, value: unknown, direction: "encode" | "decode", fallback?: KeyDictionaryEntries) => unknown;
39
+ export interface BuildRequestOptions {
40
+ readonly input: unknown;
41
+ readonly inputAst: AST.AST;
42
+ /** Base URL the operation's URI template is appended to. */
43
+ readonly baseUrl: string;
44
+ /** Headers applied before member-bound headers (credentials etc.). */
45
+ readonly headers?: Record<string, string>;
46
+ /**
47
+ * Transform a member-bound header value before it is set (e.g.
48
+ * Bearer-prefixing a raw token supplied as an Authorization member).
49
+ */
50
+ readonly mapMemberHeader?: (name: string, value: string) => string;
51
+ /**
52
+ * Wire name for input keys the schema doesn't declare (spec drift —
53
+ * unknown keys pass through as body fields rather than being dropped).
54
+ * Defaults to the key verbatim.
55
+ */
56
+ readonly unknownKeyToWire?: (key: string) => string;
57
+ }
58
+ export declare const buildRequest: ({ input, inputAst, baseUrl, headers: baseHeaders, mapMemberHeader, unknownKeyToWire, }: BuildRequestOptions) => HttpClientRequest.HttpClientRequest;
59
+ /**
60
+ * Whether one matcher matches one wire error: every present field must
61
+ * match; a matcher (or a message object) with no constraints matches
62
+ * nothing.
63
+ */
64
+ export declare const matchesExpression: (m: ErrorMatcher, code: number | undefined, status: number, message: string) => boolean;
65
+ /**
66
+ * Pick the operation's typed error class for a failed response: among all
67
+ * declared classes whose matchers (see `applyErrorMatchers`) match the wire
68
+ * failure, the most specific matcher wins (ties break by declaration order).
69
+ */
70
+ export declare const matchTypedError: (errorClasses: ReadonlyArray<unknown>, status: number, errors: ReadonlyArray<{
71
+ code?: number;
72
+ message: string;
73
+ }>) => unknown | undefined;
74
+ //# sourceMappingURL=protocol-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol-http.d.ts","sourceRoot":"","sources":["../src/protocol-http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,iBAAiB,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAaL,KAAK,YAAY,EAEjB,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAIpB,eAAO,MAAM,QAAQ,QAAS,GAAG,CAAC,GAAG,KAAG,SAAS,GAAG,CAAC,iBAAiB,EAMrE,CAAC;AAEF,eAAO,MAAM,MAAM,QAAS,GAAG,CAAC,GAAG,UAAU,MAAM,KAAG,OAkBrD,CAAC;AAEF,eAAO,MAAM,UAAU,SACf,GAAG,CAAC,iBAAiB,UACnB,MAAM,KACb,OAAoC,CAAC;AACxC,eAAO,MAAM,UAAU,SACf,GAAG,CAAC,iBAAiB,UACnB,MAAM,KACb,OAAiD,CAAC;AACrD,eAAO,MAAM,MAAM,SAAU,GAAG,CAAC,iBAAiB,UAAU,MAAM,KAAG,MAGpE,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,WAAW,QAAS,GAAG,CAAC,GAAG,KAAG,GAAG,CAAC,GAc9C,CAAC;AAKF,4EAA4E;AAC5E,eAAO,MAAM,aAAa,MAAO,OAAO,KAAG,OAKxB,CAAC;AAEpB;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,SACxB,oBAAoB,SACnB,OAAO,aACH,QAAQ,GAAG,QAAQ,KAC7B,OA4BF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,QACb,GAAG,CAAC,GAAG,SACL,OAAO,aACH,QAAQ,GAAG,QAAQ,aACnB,oBAAoB,KAC9B,OAmKF,CAAC;AAiDF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC;IAC3B,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACnE;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACrD;AAqDD,eAAO,MAAM,YAAY,2FAOtB,mBAAmB,KAAG,iBAAiB,CAAC,iBAyN1C,CAAC;AAKF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,MACzB,YAAY,QACT,MAAM,GAAG,SAAS,UAChB,MAAM,WACL,MAAM,KACd,OAiBF,CAAC;AAOF;;;;GAIG;AACH,eAAO,MAAM,eAAe,iBACZ,aAAa,CAAC,OAAO,CAAC,UAC5B,MAAM,UACN,aAAa,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,KACxD,OAAO,GAAG,SAsBZ,CAAC"}
@@ -0,0 +1,590 @@
1
+ import * as HttpBody from "effect/unstable/http/HttpBody";
2
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
3
+ import { bodySymbol, deepQuerySymbol, formDataFileSymbol, getErrorMatchers, headerSymbol, httpBodySymbol, httpSymbol, keyDictionarySymbol, labelSymbol, querySymbol, stringEncodedSymbol, unionCasesSymbol, } from "./trait.js";
4
+ //#region AST helpers (survive S.optional / Suspend / transforms)
5
+ export const getProps = (ast) => {
6
+ if (ast._tag === "Objects")
7
+ return ast.propertySignatures;
8
+ if (ast._tag === "Suspend")
9
+ return getProps(ast.thunk());
10
+ if (ast.encoding && ast.encoding.length > 0)
11
+ return getProps(ast.encoding[0].to);
12
+ return [];
13
+ };
14
+ export const getAnn = (ast, symbol) => {
15
+ const direct = ast.annotations?.[symbol];
16
+ if (direct !== undefined)
17
+ return direct;
18
+ if (ast._tag === "Suspend")
19
+ return getAnn(ast.thunk(), symbol);
20
+ if (ast.encoding && ast.encoding.length > 0)
21
+ return getAnn(ast.encoding[0].to, symbol);
22
+ // S.optional → Union[self, Undefined]; descend into the single real member.
23
+ if (ast._tag === "Union") {
24
+ const real = ast.types.filter((t) => t._tag !== "Undefined" &&
25
+ !(t._tag === "Literal" && t.literal === null));
26
+ if (real.length === 1)
27
+ return getAnn(real[0], symbol);
28
+ }
29
+ return undefined;
30
+ };
31
+ export const getPropAnn = (prop, symbol) => getAnn(prop.type, symbol);
32
+ export const hasPropAnn = (prop, symbol) => getPropAnn(prop, symbol) !== undefined;
33
+ export const nameOf = (prop, symbol) => {
34
+ const v = getPropAnn(prop, symbol);
35
+ return typeof v === "string" ? v : String(prop.name);
36
+ };
37
+ /** Resolve wrappers to the real node: Suspend, encoding, optional/null unions. */
38
+ export const resolveNode = (ast) => {
39
+ if (ast._tag === "Suspend")
40
+ return resolveNode(ast.thunk());
41
+ if (ast.encoding && ast.encoding.length > 0)
42
+ return resolveNode(ast.encoding[0].to);
43
+ if (ast._tag === "Union") {
44
+ const real = ast.types.filter((t) => t._tag !== "Undefined" &&
45
+ t._tag !== "Null" &&
46
+ !(t._tag === "Literal" && t.literal === null));
47
+ if (real.length === 1)
48
+ return resolveNode(real[0]);
49
+ }
50
+ return ast;
51
+ };
52
+ //#endregion
53
+ //#region Recursive wire-name mapping
54
+ /** Binary/opaque values that must never be treated as key-value objects. */
55
+ export const isOpaqueValue = (v) => v instanceof Blob ||
56
+ v instanceof File ||
57
+ v instanceof ArrayBuffer ||
58
+ v instanceof Uint8Array ||
59
+ v instanceof Date;
60
+ /**
61
+ * Deep-rename keys via a plain dictionary (see `T.KeyDictionary`). An entry
62
+ * may list several wire spellings; encode uses the first (canonical) one and
63
+ * decode maps every listed spelling back to the TS name.
64
+ */
65
+ export const mapKeysByDictionary = (dict, value, direction) => {
66
+ if (value === null || typeof value !== "object" || isOpaqueValue(value)) {
67
+ return value;
68
+ }
69
+ if (Array.isArray(value)) {
70
+ return value.map((v) => mapKeysByDictionary(dict, v, direction));
71
+ }
72
+ const rename = direction === "decode"
73
+ ? Object.fromEntries(Object.entries(dict).flatMap(([ts, wire]) => typeof wire === "string"
74
+ ? [[wire, ts]]
75
+ : wire.map((w) => [w, ts])))
76
+ : Object.fromEntries(Object.entries(dict).map(([ts, wire]) => [
77
+ ts,
78
+ typeof wire === "string" ? wire : wire[0],
79
+ ]));
80
+ const out = {};
81
+ for (const [k, v] of Object.entries(value)) {
82
+ if (v === undefined)
83
+ continue;
84
+ out[rename[k] ?? k] = mapKeysByDictionary(dict, v, direction);
85
+ }
86
+ return out;
87
+ };
88
+ /**
89
+ * Recursively rename keys between TS names and wire names, per the schema.
90
+ *
91
+ * `fallback` is the nearest ancestor `T.KeyDictionary` — schema-known members
92
+ * always map via their own annotations, but opaque values (Document members,
93
+ * keys the schema doesn't know) deep-rename via the dictionary so nested
94
+ * TS-cased content still reaches the wire in wire case. Content with no
95
+ * dictionary in scope passes through verbatim.
96
+ */
97
+ export const mapKeys = (ast, value, direction, fallback) => {
98
+ if (value === null ||
99
+ value === undefined ||
100
+ typeof value !== "object" ||
101
+ isOpaqueValue(value)) {
102
+ return value;
103
+ }
104
+ const dict = getAnn(ast, keyDictionarySymbol) ??
105
+ fallback;
106
+ // Discriminated union whose cases the API returns merged (every case's
107
+ // keys present, `null` for the inactive ones). Map wire names, then keep
108
+ // only the active case's keys. The case is read off the union's
109
+ // discriminator when it has one — cases that share a key set (every
110
+ // resource kind of `resource_tagging`, every page-rule action) are
111
+ // indistinguishable by keys alone. Without one, a case does NOT need every
112
+ // key present — arms carry optional members the wire may omit — so the
113
+ // active case is the one that best EXPLAINS the value: most present,
114
+ // non-null keys covered, minus present keys the case cannot explain (ties
115
+ // break by coverage, then declaration order).
116
+ const unionCases = getAnn(ast, unionCasesSymbol);
117
+ if (unionCases && direction === "decode" && !Array.isArray(value)) {
118
+ const obj = (dict ? mapKeysByDictionary(dict, value, "decode") : value);
119
+ const present = Object.keys(obj).filter((k) => obj[k] !== undefined && obj[k] !== null);
120
+ const disc = unionCases.discriminator;
121
+ const tag = disc ? obj[disc.key] : undefined;
122
+ const tagged = typeof tag === "string" ? disc.values.indexOf(tag) : -1;
123
+ let best;
124
+ if (tagged >= 0) {
125
+ best = { keys: unionCases.cases[tagged], score: 0, matched: 0 };
126
+ }
127
+ else {
128
+ for (const keys of unionCases.cases) {
129
+ const set = new Set(keys);
130
+ let matched = 0;
131
+ let excess = 0;
132
+ for (const k of present) {
133
+ if (set.has(k))
134
+ matched++;
135
+ else
136
+ excess++;
137
+ }
138
+ const score = matched - excess;
139
+ if (matched > 0 &&
140
+ (!best ||
141
+ score > best.score ||
142
+ (score === best.score && matched > best.matched))) {
143
+ best = { keys, score, matched };
144
+ }
145
+ }
146
+ }
147
+ if (best) {
148
+ const out = {};
149
+ for (const k of best.keys)
150
+ out[k] = obj[k];
151
+ return out;
152
+ }
153
+ return obj;
154
+ }
155
+ const node = resolveNode(ast);
156
+ // Schema-level union member (a merged response struct whose arms disagree
157
+ // on a member's type — see the codegen's response-union merge): pick the
158
+ // arm that explains the value best and map with it. Object values score
159
+ // arms by how many of their declared keys are present; array values take
160
+ // the first array arm. Anything unmatched deep-renames via the dictionary
161
+ // fallback, like other opaque content. (Single-real-member unions —
162
+ // optional/null wrappers — were already collapsed by resolveNode; the
163
+ // opaque `T.UnionCases` mechanism never produces a Union node and is
164
+ // handled above.)
165
+ if (node._tag === "Union") {
166
+ const arms = node.types.map(resolveNode);
167
+ if (Array.isArray(value)) {
168
+ const arr = arms.find((t) => t._tag === "Arrays");
169
+ if (arr)
170
+ return mapKeys(arr, value, direction, dict);
171
+ }
172
+ else {
173
+ let best;
174
+ let bestScore = 0;
175
+ for (const t of arms) {
176
+ if (t._tag !== "Objects")
177
+ continue;
178
+ let score = 0;
179
+ for (const p of t
180
+ .propertySignatures) {
181
+ const from = direction === "encode" ? String(p.name) : nameOf(p, bodySymbol);
182
+ if (value[from] !== undefined)
183
+ score++;
184
+ }
185
+ if (score > bestScore) {
186
+ best = t;
187
+ bestScore = score;
188
+ }
189
+ }
190
+ if (best)
191
+ return mapKeys(best, value, direction, dict);
192
+ }
193
+ return dict ? mapKeysByDictionary(dict, value, direction) : value;
194
+ }
195
+ if (node._tag === "Arrays") {
196
+ if (!Array.isArray(value))
197
+ return value;
198
+ const elem = node.rest?.[0];
199
+ return elem
200
+ ? value.map((v) => mapKeys(elem, v, direction, dict))
201
+ : dict
202
+ ? mapKeysByDictionary(dict, value, direction)
203
+ : value;
204
+ }
205
+ if (node._tag === "Objects" && !Array.isArray(value)) {
206
+ const props = node
207
+ .propertySignatures;
208
+ const isigs = node.indexSignatures;
209
+ if (props.length === 0 && !(isigs && isigs.length)) {
210
+ // opaque object — dictionary fallback or verbatim
211
+ return dict ? mapKeysByDictionary(dict, value, direction) : value;
212
+ }
213
+ const out = {};
214
+ const consumed = new Set();
215
+ for (const p of props) {
216
+ const tsName = String(p.name);
217
+ const wire = nameOf(p, bodySymbol);
218
+ const from = direction === "encode" ? tsName : wire;
219
+ const to = direction === "encode" ? wire : tsName;
220
+ consumed.add(from);
221
+ const v = value[from];
222
+ if (v === undefined)
223
+ continue;
224
+ out[to] = mapKeys(p.type, v, direction, dict);
225
+ }
226
+ for (const [k, v] of Object.entries(value)) {
227
+ if (consumed.has(k) || v === undefined)
228
+ continue;
229
+ const renamed = dict
230
+ ? direction === "encode"
231
+ ? (dict[k] ?? k)
232
+ : (Object.entries(dict).find(([, w]) => w === k)?.[0] ?? k)
233
+ : k;
234
+ out[typeof renamed === "string" ? renamed : renamed[0]] =
235
+ isigs && isigs.length
236
+ ? mapKeys(isigs[0].type, v, direction, dict)
237
+ : dict
238
+ ? mapKeysByDictionary(dict, v, direction)
239
+ : v;
240
+ }
241
+ return out;
242
+ }
243
+ // Scalar-typed schema node holding object content (spec drift) —
244
+ // dictionary fallback or verbatim.
245
+ return dict ? mapKeysByDictionary(dict, value, direction) : value;
246
+ };
247
+ //#endregion
248
+ //#region Request building
249
+ const BODYLESS = new Set(["GET", "HEAD"]);
250
+ /**
251
+ * Serialize one query member. Scalars go as `k=v`, arrays as repeated `k=v`
252
+ * pairs, and nested plain objects recurse as DOTTED params — several list
253
+ * endpoints model their filters as structs (e.g. Cloudflare DNS listRecords
254
+ * takes `name: { exact, contains, ... }`) that must go over the wire as
255
+ * `name.exact=value`. Without this they fell through to `String(value)` and
256
+ * were sent as `name=[object Object]`, which servers happily treat as a
257
+ * filter matching nothing — the call "succeeds" with zero results and the
258
+ * bug is invisible to the caller.
259
+ */
260
+ /**
261
+ * Value form for a `StringEncoded()` member: the string spelling of the
262
+ * value, element-wise for lists. `null` stays `null` — an API that models a
263
+ * flag as `"true" | "false"` still means "unset" by null, not `"null"`.
264
+ */
265
+ const stringEncode = (value) => value === null
266
+ ? null
267
+ : Array.isArray(value)
268
+ ? value.map(stringEncode)
269
+ : String(value);
270
+ const appendQuery = (query, name, value) => {
271
+ if (Array.isArray(value)) {
272
+ for (const v of value)
273
+ appendQuery(query, name, v);
274
+ }
275
+ else if (value !== null &&
276
+ typeof value === "object" &&
277
+ !(value instanceof Date)) {
278
+ for (const [k, v] of Object.entries(value)) {
279
+ if (v !== undefined)
280
+ appendQuery(query, `${name}.${k}`, v);
281
+ }
282
+ }
283
+ else {
284
+ query.append(name, String(value));
285
+ }
286
+ };
287
+ /**
288
+ * Build an HTTP request from an operation input and its schema, driven by
289
+ * the trait annotations: `Http()` supplies method + URI template, `Label()`
290
+ * members fill URI placeholders, `Header()`/`Query()` members bind to
291
+ * headers/query params, `DeepQuery()` struct members expand into dotted
292
+ * query params, `HttpBody()` sends the member as the whole body,
293
+ * `FormDataFile()` members become multipart file parts, and everything else
294
+ * is a JSON body field (wire-named via `Body()` / `KeyDictionary`).
295
+ *
296
+ * Throws when the input schema is missing the `Http()` trait — a codegen
297
+ * bug, surfaced as a defect by the calling protocol's Effect context.
298
+ */
299
+ /**
300
+ * Flatten a nested object into Stripe-style bracket notation pairs for
301
+ * form-urlencoded bodies: nested objects become `a[b][c]`, arrays index as
302
+ * `a[0]`; null/undefined dropped, booleans as "true"/"false".
303
+ */
304
+ const flattenToFormPairs = (obj, prefix = "") => {
305
+ const pairs = [];
306
+ for (const [key, value] of Object.entries(obj)) {
307
+ if (value === undefined || value === null)
308
+ continue;
309
+ const fullKey = prefix ? `${prefix}[${key}]` : key;
310
+ if (Array.isArray(value)) {
311
+ for (let i = 0; i < value.length; i++) {
312
+ const item = value[i];
313
+ if (item === undefined || item === null)
314
+ continue;
315
+ if (typeof item === "object" && !Array.isArray(item)) {
316
+ pairs.push(...flattenToFormPairs(item, `${fullKey}[${i}]`));
317
+ }
318
+ else {
319
+ pairs.push([`${fullKey}[${i}]`, String(item)]);
320
+ }
321
+ }
322
+ }
323
+ else if (typeof value === "object") {
324
+ pairs.push(...flattenToFormPairs(value, fullKey));
325
+ }
326
+ else {
327
+ pairs.push([fullKey, String(value)]);
328
+ }
329
+ }
330
+ return pairs;
331
+ };
332
+ export const buildRequest = ({ input, inputAst, baseUrl, headers: baseHeaders, mapMemberHeader, unknownKeyToWire, }) => {
333
+ const inputObj = (input ?? {});
334
+ const http = getAnn(inputAst, httpSymbol);
335
+ if (!http) {
336
+ throw new Error("operation input is missing the Http() trait");
337
+ }
338
+ // Root key dictionary: fallback wire mapping for opaque/unknown content
339
+ // the schema doesn't model.
340
+ const rootDict = getAnn(inputAst, keyDictionarySymbol);
341
+ const headers = { ...baseHeaders };
342
+ const body = {};
343
+ let rawBody; // whole-body member (T.HttpBody) — sent as-is
344
+ const files = [];
345
+ const query = new URLSearchParams();
346
+ let uri = http.uri;
347
+ const consumed = new Set();
348
+ let hasBodyMembers = false;
349
+ for (const prop of getProps(inputAst)) {
350
+ const key = String(prop.name);
351
+ consumed.add(key);
352
+ const value = inputObj[key];
353
+ const isBodyMember = !hasPropAnn(prop, labelSymbol) &&
354
+ !hasPropAnn(prop, headerSymbol) &&
355
+ !hasPropAnn(prop, querySymbol) &&
356
+ !hasPropAnn(prop, deepQuerySymbol);
357
+ if (isBodyMember)
358
+ hasBodyMembers = true;
359
+ if (value === undefined)
360
+ continue;
361
+ if (hasPropAnn(prop, labelSymbol)) {
362
+ const token = nameOf(prop, labelSymbol);
363
+ uri = uri.replace(`{${token}}`, encodeURIComponent(String(value)));
364
+ }
365
+ else if (hasPropAnn(prop, headerSymbol)) {
366
+ const hName = nameOf(prop, headerSymbol).toLowerCase();
367
+ const hVal = String(value);
368
+ headers[hName] = mapMemberHeader ? mapMemberHeader(hName, hVal) : hVal;
369
+ }
370
+ else if (hasPropAnn(prop, querySymbol)) {
371
+ appendQuery(query, nameOf(prop, querySymbol), value);
372
+ }
373
+ else if (hasPropAnn(prop, deepQuerySymbol)) {
374
+ // Deep-object query member (T.DeepQuery): a nested struct expands into
375
+ // dotted query keys (`account.id=…`) under the member's wire name.
376
+ // Wire-name the nested content via the schema first, skip null/
377
+ // undefined entries; deeper nesting recurses through appendQuery.
378
+ const base = nameOf(prop, deepQuerySymbol);
379
+ const mapped = mapKeys(prop.type, value, "encode", rootDict);
380
+ if (mapped !== null && typeof mapped === "object") {
381
+ for (const [k, v] of Object.entries(mapped)) {
382
+ if (v !== undefined && v !== null) {
383
+ appendQuery(query, `${base}.${k}`, v);
384
+ }
385
+ }
386
+ }
387
+ }
388
+ else if (hasPropAnn(prop, formDataFileSymbol)) {
389
+ for (const f of Array.isArray(value) ? value : [value]) {
390
+ files.push(f);
391
+ }
392
+ }
393
+ else if (hasPropAnn(prop, httpBodySymbol)) {
394
+ rawBody = mapKeys(prop.type, value, "encode", rootDict);
395
+ }
396
+ else {
397
+ // T.StringEncoded(): the API takes this member's value only as its
398
+ // string spelling (`true` → `"true"`), while the TS surface keeps the
399
+ // natural type. Explicit here so a JSON body carries the string too,
400
+ // rather than relying on the multipart encoder's own `String()`.
401
+ body[nameOf(prop, bodySymbol)] = hasPropAnn(prop, stringEncodedSymbol)
402
+ ? stringEncode(value)
403
+ : mapKeys(prop.type, value, "encode", rootDict);
404
+ }
405
+ }
406
+ // Input keys the schema doesn't know pass through as body fields — the
407
+ // generated schemas can lag the real API, and silently dropping them
408
+ // would break working callers. The key dictionary maps them when it knows
409
+ // the key, otherwise `unknownKeyToWire` decides the wire name.
410
+ for (const [key, value] of Object.entries(inputObj)) {
411
+ if (consumed.has(key) || value === undefined)
412
+ continue;
413
+ const wire = rootDict?.[key] ?? (unknownKeyToWire ? unknownKeyToWire(key) : key);
414
+ body[typeof wire === "string" ? wire : wire[0]] = rootDict
415
+ ? mapKeysByDictionary(rootDict, value, "encode")
416
+ : value;
417
+ hasBodyMembers = true;
418
+ }
419
+ const qs = query.toString();
420
+ const url = `${baseUrl}${uri}${qs ? `?${qs}` : ""}`;
421
+ if (process.env.DISTILLED_DEBUG_HTTP) {
422
+ console.error(`[distilled] ${http.method} ${url}` +
423
+ (Object.keys(body).length
424
+ ? ` body=${JSON.stringify(body).slice(0, 400)}`
425
+ : ""));
426
+ }
427
+ let request = HttpClientRequest.make(http.method)(url).pipe(HttpClientRequest.setHeaders(headers));
428
+ if (http.contentType === "multipart") {
429
+ // Multipart upload: each body member is a form part (objects
430
+ // JSON-encoded under their wire name), each file appends under its own
431
+ // filename. A whole-body member (T.HttpBody) that is a record of files
432
+ // becomes one part per entry (e.g. asset upload: { <hash>: File }).
433
+ // File/Blob → binary part (filename = File.name), array of files → each
434
+ // appended, object → JSON string, primitive → string.
435
+ const form = new FormData();
436
+ const parts = rawBody !== undefined && typeof rawBody === "object"
437
+ ? rawBody
438
+ : body;
439
+ const isFileOrBlob = (v) => v instanceof Blob || v instanceof File;
440
+ for (const [key, value] of Object.entries(parts)) {
441
+ if (value === undefined || value === null)
442
+ continue;
443
+ if (isFileOrBlob(value)) {
444
+ form.append(key, value, value instanceof File ? value.name : key);
445
+ }
446
+ else if (Array.isArray(value) &&
447
+ value.length > 0 &&
448
+ isFileOrBlob(value[0])) {
449
+ for (const file of value) {
450
+ if (isFileOrBlob(file)) {
451
+ form.append(file instanceof File ? file.name : key, file, file instanceof File ? file.name : undefined);
452
+ }
453
+ }
454
+ }
455
+ else if (typeof value === "object") {
456
+ form.append(key, JSON.stringify(value));
457
+ }
458
+ else {
459
+ form.append(key, String(value));
460
+ }
461
+ }
462
+ for (const f of files) {
463
+ const filename = f.name ?? "file";
464
+ form.append(filename, f, filename);
465
+ }
466
+ request = request.pipe(HttpClientRequest.bodyFormData(form));
467
+ }
468
+ else if (http.contentType === "form-urlencoded" &&
469
+ !BODYLESS.has(http.method)) {
470
+ // application/x-www-form-urlencoded with Stripe-style deepObject bracket
471
+ // notation: { shipping: { address: { city } } } → shipping[address][city],
472
+ // arrays indexed ({ expand: ["a"] } → expand[0]=a).
473
+ const source = rawBody !== undefined && typeof rawBody === "object"
474
+ ? rawBody
475
+ : body;
476
+ const params = new URLSearchParams();
477
+ for (const [k, v] of flattenToFormPairs(source))
478
+ params.append(k, v);
479
+ request = request.pipe(HttpClientRequest.setBody(HttpBody.text(params.toString(), "application/x-www-form-urlencoded")));
480
+ }
481
+ else if (rawBody !== undefined && !BODYLESS.has(http.method)) {
482
+ // Whole-body member (raw arrays/scalars) — sent as the body itself.
483
+ // Binary payloads (Blob / ArrayBuffer / Uint8Array) send verbatim
484
+ // (raw object uploads — the Content-Type header member, when modeled,
485
+ // rides alongside). With a bodyMediaType, the member is a
486
+ // preserialized payload (string / bytes) sent verbatim under that
487
+ // media type (e.g. application/x-ndjson for Vectorize
488
+ // insert/upsert); otherwise it's JSON.
489
+ if (rawBody instanceof Blob || rawBody instanceof ArrayBuffer) {
490
+ // Honor the declared media type (e.g. application/x-ndjson for
491
+ // Vectorize insert/upsert) — without it the server may fall back to
492
+ // JSON parsing. When no bodyMediaType is modeled the header is left
493
+ // untouched (a modeled Content-Type header member rides alongside).
494
+ request = request.pipe(HttpClientRequest.setBody(HttpBody.raw(rawBody, { contentType: http.bodyMediaType })));
495
+ }
496
+ else if (rawBody instanceof Uint8Array) {
497
+ request = request.pipe(HttpClientRequest.setBody(HttpBody.uint8Array(rawBody, http.bodyMediaType)));
498
+ }
499
+ else if (http.bodyMediaType) {
500
+ request = request.pipe(HttpClientRequest.setBody(typeof rawBody === "string"
501
+ ? HttpBody.text(rawBody, http.bodyMediaType)
502
+ : HttpBody.uint8Array(rawBody, http.bodyMediaType)));
503
+ }
504
+ else {
505
+ request = request.pipe(HttpClientRequest.bodyJsonUnsafe(rawBody));
506
+ }
507
+ }
508
+ else if (
509
+ // A GET/HEAD sends a body only when body members actually carry values.
510
+ // Some APIs really do document GET-with-body: MongoDB Atlas's
511
+ // `…/lineItems:search` declares a `requestBody` on `get`, and AWS EFS's
512
+ // DescribeAccountPreferences takes `{ MaxResults, NextToken }` on a GET.
513
+ // Suppressing it outright dropped those members silently — the request
514
+ // succeeded, unfiltered, with nothing on the wire to show why.
515
+ //
516
+ // The `{}`-when-empty rule below stays limited to methods that expect a
517
+ // body, so a bodyless method with nothing set still sends nothing.
518
+ Object.keys(body).length > 0 ||
519
+ (hasBodyMembers && !BODYLESS.has(http.method) && http.method !== "DELETE")) {
520
+ // Send `{}` rather than no body when the schema declares body members —
521
+ // some endpoints reject a missing JSON body outright.
522
+ request = request.pipe(HttpClientRequest.bodyJsonUnsafe(body));
523
+ }
524
+ return request;
525
+ };
526
+ //#endregion
527
+ //#region Typed error matching
528
+ /**
529
+ * Whether one matcher matches one wire error: every present field must
530
+ * match; a matcher (or a message object) with no constraints matches
531
+ * nothing.
532
+ */
533
+ export const matchesExpression = (m, code, status, message) => {
534
+ if (m.code === undefined && m.status === undefined && m.message === undefined)
535
+ return false;
536
+ if (m.code !== undefined && m.code !== code)
537
+ return false;
538
+ if (m.status !== undefined && m.status !== status)
539
+ return false;
540
+ if (m.message !== undefined) {
541
+ if (typeof m.message === "string") {
542
+ if (m.message !== message)
543
+ return false;
544
+ }
545
+ else {
546
+ const { includes, matches } = m.message;
547
+ if (includes === undefined && matches === undefined)
548
+ return false;
549
+ if (includes !== undefined && !message.includes(includes))
550
+ return false;
551
+ if (matches !== undefined && !new RegExp(matches).test(message))
552
+ return false;
553
+ }
554
+ }
555
+ return true;
556
+ };
557
+ const matcherSpecificity = (m) => (m.code !== undefined ? 1 : 0) +
558
+ (m.status !== undefined ? 1 : 0) +
559
+ (m.message !== undefined ? 1 : 0);
560
+ /**
561
+ * Pick the operation's typed error class for a failed response: among all
562
+ * declared classes whose matchers (see `applyErrorMatchers`) match the wire
563
+ * failure, the most specific matcher wins (ties break by declaration order).
564
+ */
565
+ export const matchTypedError = (errorClasses, status, errors) => {
566
+ let best;
567
+ for (const cls of errorClasses) {
568
+ const matchers = getErrorMatchers(cls);
569
+ if (!matchers)
570
+ continue;
571
+ for (const m of matchers) {
572
+ for (const e of errors) {
573
+ if (!matchesExpression(m, e.code, status, e.message))
574
+ continue;
575
+ const specificity = matcherSpecificity(m);
576
+ if (!best || specificity > best.specificity) {
577
+ best = { cls, specificity, code: e.code, message: e.message };
578
+ }
579
+ }
580
+ }
581
+ }
582
+ if (!best)
583
+ return undefined;
584
+ return new best.cls({
585
+ code: best.code ?? 0,
586
+ message: best.message,
587
+ });
588
+ };
589
+ //#endregion
590
+ //# sourceMappingURL=protocol-http.js.map