@beignet/core 0.0.48 → 0.0.50

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 (173) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +224 -20
  3. package/dist/client/client.d.ts +0 -2
  4. package/dist/client/client.d.ts.map +1 -1
  5. package/dist/client/client.js +28 -25
  6. package/dist/client/client.js.map +1 -1
  7. package/dist/contracts/contract-builder.d.ts +7 -2
  8. package/dist/contracts/contract-builder.d.ts.map +1 -1
  9. package/dist/contracts/contract-builder.js +20 -2
  10. package/dist/contracts/contract-builder.js.map +1 -1
  11. package/dist/contracts/contract-group.d.ts.map +1 -1
  12. package/dist/contracts/contract-group.js +1 -0
  13. package/dist/contracts/contract-group.js.map +1 -1
  14. package/dist/contracts/contract-like.d.ts +2 -0
  15. package/dist/contracts/contract-like.d.ts.map +1 -1
  16. package/dist/contracts/contract-like.js +27 -1
  17. package/dist/contracts/contract-like.js.map +1 -1
  18. package/dist/contracts/index.d.ts +4 -0
  19. package/dist/contracts/index.d.ts.map +1 -1
  20. package/dist/contracts/index.js +4 -0
  21. package/dist/contracts/index.js.map +1 -1
  22. package/dist/contracts/query-transport.d.ts +126 -0
  23. package/dist/contracts/query-transport.d.ts.map +1 -0
  24. package/dist/contracts/query-transport.js +406 -0
  25. package/dist/contracts/query-transport.js.map +1 -0
  26. package/dist/contracts/schema-shape.d.ts +11 -0
  27. package/dist/contracts/schema-shape.d.ts.map +1 -1
  28. package/dist/contracts/schema-shape.js +13 -0
  29. package/dist/contracts/schema-shape.js.map +1 -1
  30. package/dist/contracts/types.d.ts +5 -0
  31. package/dist/contracts/types.d.ts.map +1 -1
  32. package/dist/contracts/types.js.map +1 -1
  33. package/dist/events/index.d.ts +54 -5
  34. package/dist/events/index.d.ts.map +1 -1
  35. package/dist/events/index.js +183 -32
  36. package/dist/events/index.js.map +1 -1
  37. package/dist/idempotency/index.d.ts +7 -3
  38. package/dist/idempotency/index.d.ts.map +1 -1
  39. package/dist/idempotency/index.js +45 -12
  40. package/dist/idempotency/index.js.map +1 -1
  41. package/dist/mail/index.d.ts.map +1 -1
  42. package/dist/mail/index.js +6 -3
  43. package/dist/mail/index.js.map +1 -1
  44. package/dist/openapi/index.d.ts +8 -0
  45. package/dist/openapi/index.d.ts.map +1 -1
  46. package/dist/openapi/index.js +79 -5
  47. package/dist/openapi/index.js.map +1 -1
  48. package/dist/outbox/index.d.ts +8 -5
  49. package/dist/outbox/index.d.ts.map +1 -1
  50. package/dist/outbox/index.js +17 -3
  51. package/dist/outbox/index.js.map +1 -1
  52. package/dist/ports/best-effort-work.d.ts +21 -0
  53. package/dist/ports/best-effort-work.d.ts.map +1 -0
  54. package/dist/ports/best-effort-work.js +2 -0
  55. package/dist/ports/best-effort-work.js.map +1 -0
  56. package/dist/ports/cache.d.ts +9 -1
  57. package/dist/ports/cache.d.ts.map +1 -1
  58. package/dist/ports/cache.js +20 -5
  59. package/dist/ports/cache.js.map +1 -1
  60. package/dist/ports/events.d.ts +7 -5
  61. package/dist/ports/events.d.ts.map +1 -1
  62. package/dist/ports/index.d.ts +7 -2
  63. package/dist/ports/index.d.ts.map +1 -1
  64. package/dist/ports/index.js +2 -1
  65. package/dist/ports/index.js.map +1 -1
  66. package/dist/ports/testing.d.ts +15 -0
  67. package/dist/ports/testing.d.ts.map +1 -1
  68. package/dist/ports/testing.js +38 -0
  69. package/dist/ports/testing.js.map +1 -1
  70. package/dist/providers/provider.d.ts +8 -5
  71. package/dist/providers/provider.d.ts.map +1 -1
  72. package/dist/providers/provider.js.map +1 -1
  73. package/dist/server/hooks/cors.d.ts +2 -2
  74. package/dist/server/hooks/cors.d.ts.map +1 -1
  75. package/dist/server/hooks/cors.js +2 -1
  76. package/dist/server/hooks/cors.js.map +1 -1
  77. package/dist/server/hooks/logging.d.ts +2 -2
  78. package/dist/server/hooks/logging.d.ts.map +1 -1
  79. package/dist/server/hooks/logging.js.map +1 -1
  80. package/dist/server/hooks/rate-limit.d.ts +16 -8
  81. package/dist/server/hooks/rate-limit.d.ts.map +1 -1
  82. package/dist/server/hooks/rate-limit.js +31 -17
  83. package/dist/server/hooks/rate-limit.js.map +1 -1
  84. package/dist/server/hooks/security.d.ts +2 -2
  85. package/dist/server/hooks/security.d.ts.map +1 -1
  86. package/dist/server/hooks/security.js.map +1 -1
  87. package/dist/server/http.d.ts +21 -2
  88. package/dist/server/http.d.ts.map +1 -1
  89. package/dist/server/index.d.ts +4 -0
  90. package/dist/server/index.d.ts.map +1 -1
  91. package/dist/server/index.js +4 -0
  92. package/dist/server/index.js.map +1 -1
  93. package/dist/server/instrumentation.d.ts.map +1 -1
  94. package/dist/server/instrumentation.js +5 -3
  95. package/dist/server/instrumentation.js.map +1 -1
  96. package/dist/server/request-executor.d.ts.map +1 -1
  97. package/dist/server/request-executor.js +18 -9
  98. package/dist/server/request-executor.js.map +1 -1
  99. package/dist/server/request-preparation.d.ts.map +1 -1
  100. package/dist/server/request-preparation.js +31 -11
  101. package/dist/server/request-preparation.js.map +1 -1
  102. package/dist/server/response-finalization.d.ts +2 -2
  103. package/dist/server/response-finalization.d.ts.map +1 -1
  104. package/dist/server/response-finalization.js +25 -8
  105. package/dist/server/response-finalization.js.map +1 -1
  106. package/dist/server/route-matching.d.ts.map +1 -1
  107. package/dist/server/route-matching.js +12 -1
  108. package/dist/server/route-matching.js.map +1 -1
  109. package/dist/server/server-sent-events.d.ts +94 -0
  110. package/dist/server/server-sent-events.d.ts.map +1 -0
  111. package/dist/server/server-sent-events.js +275 -0
  112. package/dist/server/server-sent-events.js.map +1 -0
  113. package/dist/server/server.d.ts.map +1 -1
  114. package/dist/server/server.js +43 -22
  115. package/dist/server/server.js.map +1 -1
  116. package/dist/server/trusted-proxy-internal.d.ts +4 -0
  117. package/dist/server/trusted-proxy-internal.d.ts.map +1 -1
  118. package/dist/server/trusted-proxy-internal.js +20 -0
  119. package/dist/server/trusted-proxy-internal.js.map +1 -1
  120. package/dist/server/trusted-proxy.d.ts.map +1 -1
  121. package/dist/server/trusted-proxy.js +3 -8
  122. package/dist/server/trusted-proxy.js.map +1 -1
  123. package/dist/server/use-case-route.d.ts +8 -5
  124. package/dist/server/use-case-route.d.ts.map +1 -1
  125. package/dist/server/use-case-route.js +44 -17
  126. package/dist/server/use-case-route.js.map +1 -1
  127. package/dist/testing/index.d.ts +17 -0
  128. package/dist/testing/index.d.ts.map +1 -1
  129. package/dist/testing/index.js +6 -1
  130. package/dist/testing/index.js.map +1 -1
  131. package/package.json +3 -3
  132. package/skills/app-architecture/SKILL.md +50 -4
  133. package/src/client/client.ts +29 -28
  134. package/src/contracts/contract-builder.ts +32 -2
  135. package/src/contracts/contract-group.ts +1 -0
  136. package/src/contracts/contract-like.ts +40 -1
  137. package/src/contracts/index.ts +23 -0
  138. package/src/contracts/query-transport.ts +697 -0
  139. package/src/contracts/schema-shape.ts +24 -0
  140. package/src/contracts/types.ts +5 -0
  141. package/src/events/index.ts +263 -38
  142. package/src/idempotency/index.ts +65 -17
  143. package/src/mail/index.ts +7 -3
  144. package/src/openapi/index.ts +126 -2
  145. package/src/outbox/index.ts +26 -5
  146. package/src/ports/best-effort-work.ts +21 -0
  147. package/src/ports/cache.ts +29 -7
  148. package/src/ports/events.ts +9 -4
  149. package/src/ports/index.ts +10 -1
  150. package/src/ports/testing.ts +45 -0
  151. package/src/providers/provider.ts +8 -5
  152. package/src/server/hooks/cors.ts +11 -5
  153. package/src/server/hooks/logging.ts +6 -2
  154. package/src/server/hooks/rate-limit.ts +50 -24
  155. package/src/server/hooks/security.ts +8 -4
  156. package/src/server/http.ts +23 -2
  157. package/src/server/index.ts +4 -0
  158. package/src/server/instrumentation.ts +12 -4
  159. package/src/server/request-executor.ts +31 -9
  160. package/src/server/request-preparation.ts +45 -12
  161. package/src/server/response-finalization.ts +51 -15
  162. package/src/server/route-matching.ts +24 -1
  163. package/src/server/server-sent-events.ts +415 -0
  164. package/src/server/server.ts +48 -22
  165. package/src/server/trusted-proxy-internal.ts +20 -0
  166. package/src/server/trusted-proxy.ts +6 -7
  167. package/src/server/use-case-route.ts +62 -23
  168. package/src/testing/index.ts +30 -0
  169. package/dist/query-codec.d.ts +0 -3
  170. package/dist/query-codec.d.ts.map +0 -1
  171. package/dist/query-codec.js +0 -110
  172. package/dist/query-codec.js.map +0 -1
  173. package/src/query-codec.ts +0 -130
@@ -5,6 +5,7 @@ import {
5
5
  mergeCatalogErrors,
6
6
  responsesFromErrors,
7
7
  } from "./catalog-errors.js";
8
+ import { assertContractQueryTransport } from "./contract-like.js";
8
9
  import {
9
10
  assertValidContractDeprecation,
10
11
  assertValidContractLifecycle,
@@ -13,6 +14,10 @@ import {
13
14
  import { mergeContractMeta } from "./metadata.js";
14
15
  import type { OpenAPIOperationMeta } from "./openapi-meta.js";
15
16
  import { parsePathTemplate } from "./path-template.js";
17
+ import type {
18
+ QueryTransport,
19
+ QueryTransportCompatibility,
20
+ } from "./query-transport.js";
16
21
  import type {
17
22
  BodyHttpMethod,
18
23
  ContractErrorResponses,
@@ -56,6 +61,7 @@ export class ContractBuilder<
56
61
  private readonly _path: TPath;
57
62
  private readonly _pathParams: TPathParams;
58
63
  private readonly _query: TQuery;
64
+ private readonly _queryTransport: QueryTransport | null;
59
65
  private readonly _body: TBody;
60
66
  private readonly _headers: THeaders;
61
67
  private readonly _responses: TResponses;
@@ -74,6 +80,7 @@ export class ContractBuilder<
74
80
  >,
75
81
  ) {
76
82
  assertValidContractLifecycle(config);
83
+ assertContractQueryTransport(config);
77
84
  if (config.body && !methodSupportsRequestBody(config.method)) {
78
85
  throw new Error(
79
86
  `Request bodies are not supported for ${config.method} contracts. Use POST, PUT, or PATCH for contract request bodies.`,
@@ -87,6 +94,7 @@ export class ContractBuilder<
87
94
  this._path = config.path;
88
95
  this._pathParams = config.pathParams;
89
96
  this._query = config.query;
97
+ this._queryTransport = config.queryTransport ?? null;
90
98
  this._body = config.body;
91
99
  this._headers = config.headers ?? (null as THeaders);
92
100
  this._responses = config.responses;
@@ -152,6 +160,7 @@ export class ContractBuilder<
152
160
  path: this._path,
153
161
  pathParams: this._pathParams,
154
162
  query: this._query,
163
+ queryTransport: this._queryTransport,
155
164
  headers: this._headers,
156
165
  body: this._body,
157
166
  responses: this._responses,
@@ -186,6 +195,7 @@ export class ContractBuilder<
186
195
  path: this._path,
187
196
  pathParams: schema as unknown as TNewPathParams,
188
197
  query: this._query,
198
+ queryTransport: this._queryTransport,
189
199
  headers: this._headers,
190
200
  body: this._body,
191
201
  responses: this._responses,
@@ -194,10 +204,21 @@ export class ContractBuilder<
194
204
  }
195
205
 
196
206
  /**
197
- * Attach a schema for query parameters.
207
+ * Attach a query schema and the deterministic URL transport for its input.
208
+ *
209
+ * The schema owns validation, defaults, and transforms. The transport owns
210
+ * client encoding, server decoding, and OpenAPI serialization.
198
211
  */
199
- query<TNewQuery extends StandardSchemaV1>(
212
+ query<
213
+ TNewQuery extends StandardSchemaV1,
214
+ const TTransport extends QueryTransport,
215
+ >(
200
216
  schema: TNewQuery,
217
+ transport: TTransport &
218
+ QueryTransportCompatibility<
219
+ StandardSchemaV1.InferInput<TNewQuery>,
220
+ TTransport
221
+ >,
201
222
  ): ContractBuilder<
202
223
  TMethod,
203
224
  TPathParams,
@@ -217,6 +238,7 @@ export class ContractBuilder<
217
238
  path: this._path,
218
239
  pathParams: this._pathParams,
219
240
  query: schema as unknown as TNewQuery,
241
+ queryTransport: transport,
220
242
  headers: this._headers,
221
243
  body: this._body,
222
244
  responses: this._responses,
@@ -270,6 +292,7 @@ export class ContractBuilder<
270
292
  path: self._path,
271
293
  pathParams: self._pathParams,
272
294
  query: self._query,
295
+ queryTransport: self._queryTransport,
273
296
  headers: self._headers,
274
297
  body: schema as unknown as TNewBody,
275
298
  responses: self._responses,
@@ -315,6 +338,7 @@ export class ContractBuilder<
315
338
  path: this._path,
316
339
  pathParams: this._pathParams,
317
340
  query: this._query,
341
+ queryTransport: this._queryTransport,
318
342
  headers: [
319
343
  ...existingHeaders,
320
344
  schema,
@@ -360,6 +384,7 @@ export class ContractBuilder<
360
384
  path: this._path,
361
385
  pathParams: this._pathParams,
362
386
  query: this._query,
387
+ queryTransport: this._queryTransport,
363
388
  headers: this._headers,
364
389
  body: this._body,
365
390
  responses: {
@@ -410,6 +435,7 @@ export class ContractBuilder<
410
435
  path: this._path,
411
436
  pathParams: this._pathParams,
412
437
  query: this._query,
438
+ queryTransport: this._queryTransport,
413
439
  headers: this._headers,
414
440
  body: this._body,
415
441
  responses: {
@@ -456,6 +482,7 @@ export class ContractBuilder<
456
482
  path: this._path,
457
483
  pathParams: this._pathParams,
458
484
  query: this._query,
485
+ queryTransport: this._queryTransport,
459
486
  headers: this._headers,
460
487
  body: this._body,
461
488
  responses: this._responses,
@@ -488,6 +515,7 @@ export class ContractBuilder<
488
515
  path: this._path,
489
516
  pathParams: this._pathParams,
490
517
  query: this._query,
518
+ queryTransport: this._queryTransport,
491
519
  headers: this._headers,
492
520
  body: this._body,
493
521
  responses: this._responses,
@@ -519,6 +547,7 @@ export class ContractBuilder<
519
547
  path: this._path,
520
548
  pathParams: this._pathParams,
521
549
  query: this._query,
550
+ queryTransport: this._queryTransport,
522
551
  headers: this._headers,
523
552
  body: this._body,
524
553
  responses: this._responses,
@@ -588,6 +617,7 @@ export function defineContract<
588
617
  path: options.path,
589
618
  pathParams: null,
590
619
  query: null,
620
+ queryTransport: null,
591
621
  headers: null,
592
622
  body: null,
593
623
  responses: {},
@@ -467,6 +467,7 @@ export class ContractGroup<
467
467
  path: fullPath,
468
468
  pathParams: null,
469
469
  query: null,
470
+ queryTransport: null,
470
471
  headers: this._headers,
471
472
  body: null,
472
473
  responses: { ...this._responses } as unknown as TSharedResponses,
@@ -1,5 +1,42 @@
1
+ import {
2
+ compareQueryTransportFields,
3
+ formatQueryTransportMismatch,
4
+ getObjectSchemaShape,
5
+ } from "./schema-shape.js";
1
6
  import type { HttpContractConfig } from "./types.js";
2
7
 
8
+ /** Assert that a plain contract config declares one transport per query. */
9
+ export function assertContractQueryTransport(
10
+ contract: HttpContractConfig,
11
+ ): void {
12
+ if (contract.query && !contract.queryTransport) {
13
+ throw new Error(
14
+ `Contract "${contract.name}" declares a query schema without a query transport. Pass defineQueryTransport(...) as the second argument to .query(...).`,
15
+ );
16
+ }
17
+ if (!contract.query && contract.queryTransport) {
18
+ throw new Error(
19
+ `Contract "${contract.name}" declares a query transport without a query schema.`,
20
+ );
21
+ }
22
+ if (contract.query && contract.queryTransport) {
23
+ const shape = getObjectSchemaShape(contract.query);
24
+ if (!shape) return;
25
+
26
+ const schemaKeys = Object.keys(shape);
27
+ const transportKeys = Object.keys(contract.queryTransport.fields);
28
+ if (!compareQueryTransportFields({ schemaKeys, transportKeys })) {
29
+ throw new Error(
30
+ formatQueryTransportMismatch({
31
+ contractName: contract.name,
32
+ schemaKeys,
33
+ transportKeys,
34
+ }),
35
+ );
36
+ }
37
+ }
38
+ }
39
+
3
40
  /**
4
41
  * Contract input accepted by APIs that can unwrap builders.
5
42
  */
@@ -25,5 +62,7 @@ export type ResolveContract<T> = T extends { config: infer C }
25
62
  export function resolveContract<T extends ContractLike>(
26
63
  c: T,
27
64
  ): ResolveContract<T> {
28
- return ("config" in c ? c.config : c) as ResolveContract<T>;
65
+ const contract = ("config" in c ? c.config : c) as ResolveContract<T>;
66
+ assertContractQueryTransport(contract);
67
+ return contract;
29
68
  }
@@ -55,6 +55,29 @@ export {
55
55
  type PathTemplateSegment,
56
56
  parsePathTemplate,
57
57
  } from "./path-template.js";
58
+ /**
59
+ * Query transport declarations shared by servers, clients, and OpenAPI.
60
+ */
61
+ export {
62
+ decodeQueryTransport,
63
+ defineQueryTransport,
64
+ encodeQueryTransport,
65
+ type QueryArrayTransport,
66
+ type QueryDeepObjectFields,
67
+ type QueryDeepObjectTransport,
68
+ type QueryEmptyBehavior,
69
+ type QueryFieldTransport,
70
+ type QueryFieldTransportInput,
71
+ type QueryScalarTransport,
72
+ type QueryTransport,
73
+ type QueryTransportCompatibility,
74
+ QueryTransportError,
75
+ type QueryTransportFields,
76
+ type QueryTransportInput,
77
+ type QueryTransportIssue,
78
+ query,
79
+ queryTransportSchema,
80
+ } from "./query-transport.js";
58
81
  /**
59
82
  * Rate limit metadata types for contracts.
60
83
  */