@beignet/core 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +173 -0
- package/README.md +821 -30
- package/dist/application/index.d.ts +28 -2
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +140 -12
- package/dist/application/index.js.map +1 -1
- package/dist/client/client.d.ts +2 -2
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +136 -48
- package/dist/client/client.js.map +1 -1
- package/dist/client/error-messages.d.ts +14 -0
- package/dist/client/error-messages.d.ts.map +1 -0
- package/dist/client/error-messages.js +23 -0
- package/dist/client/error-messages.js.map +1 -0
- package/dist/client/index.d.ts +8 -4
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +35 -5
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client-only.d.ts +8 -0
- package/dist/client-only.d.ts.map +1 -0
- package/dist/client-only.js +8 -0
- package/dist/client-only.js.map +1 -0
- package/dist/config/index.d.ts +5 -5
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -2
- package/dist/config/index.js.map +1 -1
- package/dist/contracts/catalog-errors.d.ts +27 -0
- package/dist/contracts/catalog-errors.d.ts.map +1 -0
- package/dist/contracts/catalog-errors.js +69 -0
- package/dist/contracts/catalog-errors.js.map +1 -0
- package/dist/contracts/contract-builder.d.ts +15 -12
- package/dist/contracts/contract-builder.d.ts.map +1 -1
- package/dist/contracts/contract-builder.js +15 -41
- package/dist/contracts/contract-builder.js.map +1 -1
- package/dist/contracts/contract-group.d.ts +11 -8
- package/dist/contracts/contract-group.d.ts.map +1 -1
- package/dist/contracts/contract-group.js +13 -40
- package/dist/contracts/contract-group.js.map +1 -1
- package/dist/contracts/contract-like.d.ts +1 -1
- package/dist/contracts/contract-like.d.ts.map +1 -1
- package/dist/contracts/index.d.ts +13 -9
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +9 -5
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/openapi-meta.d.ts +48 -0
- package/dist/contracts/openapi-meta.d.ts.map +1 -1
- package/dist/contracts/openapi-meta.js +3 -0
- package/dist/contracts/openapi-meta.js.map +1 -1
- package/dist/contracts/path-template.d.ts +1 -1
- package/dist/contracts/path-template.js +2 -2
- package/dist/contracts/path-template.js.map +1 -1
- package/dist/contracts/schema-shape.d.ts +37 -0
- package/dist/contracts/schema-shape.d.ts.map +1 -0
- package/dist/contracts/schema-shape.js +61 -0
- package/dist/contracts/schema-shape.js.map +1 -0
- package/dist/contracts/success-status.d.ts +32 -0
- package/dist/contracts/success-status.d.ts.map +1 -0
- package/dist/contracts/success-status.js +18 -0
- package/dist/contracts/success-status.js.map +1 -0
- package/dist/contracts/types.d.ts +25 -5
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/contracts/types.js.map +1 -1
- package/dist/contracts/utils.d.ts +1 -1
- package/dist/contracts/utils.d.ts.map +1 -1
- package/dist/contracts/utils.js +1 -1
- package/dist/contracts/utils.js.map +1 -1
- package/dist/domain/events.d.ts +1 -1
- package/dist/domain/events.d.ts.map +1 -1
- package/dist/domain/events.js +1 -1
- package/dist/domain/events.js.map +1 -1
- package/dist/domain/index.d.ts +3 -3
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +3 -3
- package/dist/domain/index.js.map +1 -1
- package/dist/errors/catalog.d.ts +9 -1
- package/dist/errors/catalog.d.ts.map +1 -1
- package/dist/errors/catalog.js +7 -1
- package/dist/errors/catalog.js.map +1 -1
- package/dist/errors/http.d.ts +10 -0
- package/dist/errors/http.d.ts.map +1 -1
- package/dist/errors/http.js +11 -1
- package/dist/errors/http.js.map +1 -1
- package/dist/errors/index.d.ts +4 -4
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +4 -4
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/response.d.ts +4 -1
- package/dist/errors/response.d.ts.map +1 -1
- package/dist/errors/response.js.map +1 -1
- package/dist/events/index.d.ts +10 -12
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +10 -10
- package/dist/events/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +5 -3
- package/dist/idempotency/index.d.ts.map +1 -1
- package/dist/idempotency/index.js.map +1 -1
- package/dist/jobs/index.d.ts +148 -16
- package/dist/jobs/index.d.ts.map +1 -1
- package/dist/jobs/index.js +174 -14
- package/dist/jobs/index.js.map +1 -1
- package/dist/notifications/index.d.ts +14 -16
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +14 -14
- package/dist/notifications/index.js.map +1 -1
- package/dist/openapi/index.d.ts +8 -3
- package/dist/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +41 -29
- package/dist/openapi/index.js.map +1 -1
- package/dist/openapi/schema-introspector.d.ts +37 -0
- package/dist/openapi/schema-introspector.d.ts.map +1 -1
- package/dist/openapi/schema-introspector.js +23 -17
- package/dist/openapi/schema-introspector.js.map +1 -1
- package/dist/outbox/index.d.ts +18 -4
- package/dist/outbox/index.d.ts.map +1 -1
- package/dist/outbox/index.js +104 -4
- package/dist/outbox/index.js.map +1 -1
- package/dist/ports/audit.d.ts +56 -10
- package/dist/ports/audit.d.ts.map +1 -1
- package/dist/ports/audit.js +71 -3
- package/dist/ports/audit.js.map +1 -1
- package/dist/ports/auth.d.ts +92 -0
- package/dist/ports/auth.d.ts.map +1 -1
- package/dist/ports/auth.js +92 -0
- package/dist/ports/auth.js.map +1 -1
- package/dist/ports/events.d.ts +2 -2
- package/dist/ports/events.d.ts.map +1 -1
- package/dist/ports/index.d.ts +62 -33
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +28 -34
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/policy.d.ts +32 -3
- package/dist/ports/policy.d.ts.map +1 -1
- package/dist/ports/policy.js +13 -2
- package/dist/ports/policy.js.map +1 -1
- package/dist/ports/testing.d.ts +1030 -2
- package/dist/ports/testing.d.ts.map +1 -1
- package/dist/ports/testing.js +1031 -1
- package/dist/ports/testing.js.map +1 -1
- package/dist/ports/unbound.d.ts +21 -0
- package/dist/ports/unbound.d.ts.map +1 -0
- package/dist/ports/unbound.js +57 -0
- package/dist/ports/unbound.js.map +1 -0
- package/dist/ports/unit-of-work.d.ts +1 -1
- package/dist/ports/unit-of-work.d.ts.map +1 -1
- package/dist/ports/unit-of-work.js +1 -1
- package/dist/ports/unit-of-work.js.map +1 -1
- package/dist/providers/index.d.ts +3 -2
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +3 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/instrumentation.d.ts +46 -5
- package/dist/providers/instrumentation.d.ts.map +1 -1
- package/dist/providers/instrumentation.js +25 -6
- package/dist/providers/instrumentation.js.map +1 -1
- package/dist/providers/metadata.d.ts +39 -0
- package/dist/providers/metadata.d.ts.map +1 -0
- package/dist/providers/metadata.js +169 -0
- package/dist/providers/metadata.js.map +1 -0
- package/dist/providers/provider.d.ts +114 -9
- package/dist/providers/provider.d.ts.map +1 -1
- package/dist/providers/provider.js +3 -20
- package/dist/providers/provider.js.map +1 -1
- package/dist/schedules/index.d.ts +94 -13
- package/dist/schedules/index.d.ts.map +1 -1
- package/dist/schedules/index.js +66 -12
- package/dist/schedules/index.js.map +1 -1
- package/dist/server/audit-context.d.ts +29 -0
- package/dist/server/audit-context.d.ts.map +1 -0
- package/dist/server/audit-context.js +44 -0
- package/dist/server/audit-context.js.map +1 -0
- package/dist/server/context.d.ts +141 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +39 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/contract-like.d.ts +1 -1
- package/dist/server/contract-like.d.ts.map +1 -1
- package/dist/server/contract-like.js +1 -1
- package/dist/server/contract-like.js.map +1 -1
- package/dist/server/health.d.ts +2 -2
- package/dist/server/health.d.ts.map +1 -1
- package/dist/server/hooks/auth.d.ts +89 -65
- package/dist/server/hooks/auth.d.ts.map +1 -1
- package/dist/server/hooks/auth.js +84 -55
- package/dist/server/hooks/auth.js.map +1 -1
- package/dist/server/hooks/cors.d.ts +1 -1
- package/dist/server/hooks/cors.d.ts.map +1 -1
- package/dist/server/hooks/errors.d.ts +2 -2
- package/dist/server/hooks/errors.d.ts.map +1 -1
- package/dist/server/hooks/errors.js +2 -2
- package/dist/server/hooks/errors.js.map +1 -1
- package/dist/server/hooks/idempotency.d.ts +78 -0
- package/dist/server/hooks/idempotency.d.ts.map +1 -0
- package/dist/server/hooks/idempotency.js +154 -0
- package/dist/server/hooks/idempotency.js.map +1 -0
- package/dist/server/hooks/index.d.ts +8 -7
- package/dist/server/hooks/index.d.ts.map +1 -1
- package/dist/server/hooks/index.js +6 -5
- package/dist/server/hooks/index.js.map +1 -1
- package/dist/server/hooks/logging.d.ts +2 -2
- package/dist/server/hooks/logging.d.ts.map +1 -1
- package/dist/server/hooks/logging.js +1 -1
- package/dist/server/hooks/logging.js.map +1 -1
- package/dist/server/hooks/rate-limit.d.ts +25 -7
- package/dist/server/hooks/rate-limit.d.ts.map +1 -1
- package/dist/server/hooks/rate-limit.js +47 -12
- package/dist/server/hooks/rate-limit.js.map +1 -1
- package/dist/server/hooks.d.ts +1 -1
- package/dist/server/hooks.d.ts.map +1 -1
- package/dist/server/hooks.js +1 -1
- package/dist/server/hooks.js.map +1 -1
- package/dist/server/http.d.ts +84 -6
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/index.d.ts +36 -12
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +24 -8
- package/dist/server/index.js.map +1 -1
- package/dist/server/instrumentation.d.ts +108 -0
- package/dist/server/instrumentation.d.ts.map +1 -0
- package/dist/server/instrumentation.js +297 -0
- package/dist/server/instrumentation.js.map +1 -0
- package/dist/server/openapi.d.ts +3 -3
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/openapi.js +1 -1
- package/dist/server/openapi.js.map +1 -1
- package/dist/server/providers/index.d.ts +3 -3
- package/dist/server/providers/index.d.ts.map +1 -1
- package/dist/server/providers/index.js +3 -3
- package/dist/server/providers/index.js.map +1 -1
- package/dist/server/providers/loadProviderConfig.d.ts +2 -2
- package/dist/server/providers/loadProviderConfig.d.ts.map +1 -1
- package/dist/server/providers/loadProviderConfig.js +2 -2
- package/dist/server/providers/loadProviderConfig.js.map +1 -1
- package/dist/server/request-context.d.ts +67 -0
- package/dist/server/request-context.d.ts.map +1 -0
- package/dist/server/request-context.js +79 -0
- package/dist/server/request-context.js.map +1 -0
- package/dist/server/server-context.d.ts +38 -0
- package/dist/server/server-context.d.ts.map +1 -0
- package/dist/server/server-context.js +38 -0
- package/dist/server/server-context.js.map +1 -0
- package/dist/server/server.d.ts +148 -35
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +482 -145
- package/dist/server/server.js.map +1 -1
- package/dist/server/types.d.ts +2 -2
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +2 -2
- package/dist/server/types.js.map +1 -1
- package/dist/server/use-case-route.d.ts +263 -0
- package/dist/server/use-case-route.d.ts.map +1 -0
- package/dist/server/use-case-route.js +77 -0
- package/dist/server/use-case-route.js.map +1 -0
- package/dist/server-only.d.ts +8 -0
- package/dist/server-only.d.ts.map +1 -0
- package/dist/server-only.js +8 -0
- package/dist/server-only.js.map +1 -0
- package/dist/tasks/index.d.ts +139 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +98 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/testing/index.d.ts +611 -5
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +434 -4
- package/dist/testing/index.js.map +1 -1
- package/dist/tracing/index.d.ts +89 -0
- package/dist/tracing/index.d.ts.map +1 -0
- package/dist/tracing/index.js +101 -0
- package/dist/tracing/index.js.map +1 -0
- package/dist/uploads/client.d.ts +278 -0
- package/dist/uploads/client.d.ts.map +1 -0
- package/dist/uploads/client.js +428 -0
- package/dist/uploads/client.js.map +1 -0
- package/dist/uploads/index.d.ts +361 -0
- package/dist/uploads/index.d.ts.map +1 -0
- package/dist/uploads/index.js +543 -0
- package/dist/uploads/index.js.map +1 -0
- package/package.json +34 -3
- package/src/application/index.ts +193 -10
- package/src/client/client.ts +148 -150
- package/src/client/error-messages.ts +35 -0
- package/src/client/index.ts +12 -4
- package/src/client/types.ts +44 -5
- package/src/client-only.ts +7 -0
- package/src/config/index.ts +6 -6
- package/src/contracts/catalog-errors.ts +115 -0
- package/src/contracts/contract-builder.ts +39 -76
- package/src/contracts/contract-group.ts +33 -68
- package/src/contracts/contract-like.ts +1 -1
- package/src/contracts/index.ts +24 -11
- package/src/contracts/openapi-meta.ts +55 -0
- package/src/contracts/path-template.ts +2 -2
- package/src/contracts/schema-shape.ts +75 -0
- package/src/contracts/success-status.ts +68 -0
- package/src/contracts/types.ts +32 -5
- package/src/contracts/utils.ts +5 -2
- package/src/domain/events.ts +6 -2
- package/src/domain/index.ts +3 -3
- package/src/errors/catalog.ts +9 -1
- package/src/errors/http.ts +11 -1
- package/src/errors/index.ts +4 -4
- package/src/errors/response.ts +4 -1
- package/src/events/index.ts +12 -26
- package/src/idempotency/index.ts +5 -3
- package/src/jobs/index.ts +340 -29
- package/src/notifications/index.ts +17 -27
- package/src/openapi/index.ts +73 -38
- package/src/openapi/schema-introspector.ts +68 -17
- package/src/outbox/index.ts +151 -6
- package/src/ports/audit.ts +120 -11
- package/src/ports/auth.ts +132 -0
- package/src/ports/events.ts +2 -2
- package/src/ports/index.ts +104 -35
- package/src/ports/policy.ts +50 -3
- package/src/ports/testing.ts +2220 -33
- package/src/ports/unbound.ts +64 -0
- package/src/ports/unit-of-work.ts +6 -2
- package/src/providers/index.ts +16 -3
- package/src/providers/instrumentation.ts +93 -8
- package/src/providers/metadata.ts +234 -0
- package/src/providers/provider.ts +168 -9
- package/src/schedules/index.ts +173 -23
- package/src/server/audit-context.ts +45 -0
- package/src/server/context.ts +224 -0
- package/src/server/contract-like.ts +1 -1
- package/src/server/health.ts +2 -2
- package/src/server/hooks/auth.ts +175 -158
- package/src/server/hooks/cors.ts +1 -1
- package/src/server/hooks/errors.ts +7 -4
- package/src/server/hooks/idempotency.ts +263 -0
- package/src/server/hooks/index.ts +15 -12
- package/src/server/hooks/logging.ts +3 -3
- package/src/server/hooks/rate-limit.ts +85 -17
- package/src/server/hooks.ts +1 -1
- package/src/server/http.ts +112 -6
- package/src/server/index.ts +63 -12
- package/src/server/instrumentation.ts +470 -0
- package/src/server/openapi.ts +4 -4
- package/src/server/providers/index.ts +6 -3
- package/src/server/providers/loadProviderConfig.ts +4 -4
- package/src/server/request-context.ts +116 -0
- package/src/server/server-context.ts +44 -0
- package/src/server/server.ts +1045 -229
- package/src/server/types.ts +2 -2
- package/src/server/use-case-route.ts +430 -0
- package/src/server-only.ts +7 -0
- package/src/tasks/index.ts +275 -0
- package/src/testing/index.ts +1153 -6
- package/src/tracing/index.ts +176 -0
- package/src/uploads/client.ts +861 -0
- package/src/uploads/index.ts +1071 -0
- package/dist/ports/mailer.d.ts +0 -6
- package/dist/ports/mailer.d.ts.map +0 -1
- package/dist/ports/mailer.js +0 -2
- package/dist/ports/mailer.js.map +0 -1
- package/dist/ports/schedules.d.ts +0 -9
- package/dist/ports/schedules.d.ts.map +0 -1
- package/dist/ports/schedules.js +0 -2
- package/dist/ports/schedules.js.map +0 -1
package/src/openapi/index.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* OpenAPI 3.1 generation from Beignet contracts
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { type ZodTypeAny, z } from "zod";
|
|
8
7
|
import {
|
|
9
8
|
type AnyContract,
|
|
10
9
|
type ContractLike,
|
|
@@ -13,17 +12,26 @@ import {
|
|
|
13
12
|
parsePathTemplate,
|
|
14
13
|
resolveContract,
|
|
15
14
|
STANDARD_ERROR_RESPONSE_SCHEMA,
|
|
16
|
-
} from "../contracts";
|
|
15
|
+
} from "../contracts/index.js";
|
|
16
|
+
import {
|
|
17
|
+
comparePathParamsToTemplate,
|
|
18
|
+
formatPathParamsMismatch,
|
|
19
|
+
} from "../contracts/schema-shape.js";
|
|
17
20
|
import {
|
|
18
21
|
createZodIntrospector,
|
|
22
|
+
createZodSchemaConverter,
|
|
23
|
+
type SchemaConverter,
|
|
19
24
|
type SchemaIntrospector,
|
|
20
|
-
|
|
25
|
+
type SchemaIO,
|
|
26
|
+
} from "./schema-introspector.js";
|
|
21
27
|
|
|
22
28
|
// Re-export the introspector types for consumers who want custom implementations
|
|
23
29
|
export {
|
|
24
30
|
createZodIntrospector,
|
|
31
|
+
createZodSchemaConverter,
|
|
32
|
+
type SchemaConverter,
|
|
25
33
|
type SchemaIntrospector,
|
|
26
|
-
} from "./schema-introspector";
|
|
34
|
+
} from "./schema-introspector.js";
|
|
27
35
|
|
|
28
36
|
/**
|
|
29
37
|
* OpenAPI 3.1 info object.
|
|
@@ -338,6 +346,11 @@ export interface OpenAPIGeneratorOptions {
|
|
|
338
346
|
* to support other schema libraries.
|
|
339
347
|
*/
|
|
340
348
|
schemaIntrospector?: SchemaIntrospector;
|
|
349
|
+
/**
|
|
350
|
+
* Schema converters used to turn contract schemas into OpenAPI schemas.
|
|
351
|
+
* Custom converters run before Beignet's default Zod converter.
|
|
352
|
+
*/
|
|
353
|
+
schemaConverters?: readonly SchemaConverter[];
|
|
341
354
|
}
|
|
342
355
|
|
|
343
356
|
/**
|
|
@@ -347,10 +360,9 @@ type GeneratorState = {
|
|
|
347
360
|
components: ComponentsObject;
|
|
348
361
|
jsonMediaType: string;
|
|
349
362
|
introspector: SchemaIntrospector;
|
|
363
|
+
schemaConverters: readonly SchemaConverter[];
|
|
350
364
|
};
|
|
351
365
|
|
|
352
|
-
type SchemaIO = "input" | "output";
|
|
353
|
-
|
|
354
366
|
/**
|
|
355
367
|
* Contract input accepted by the OpenAPI generator.
|
|
356
368
|
*/
|
|
@@ -392,6 +404,10 @@ export function contractsToOpenAPI(
|
|
|
392
404
|
components,
|
|
393
405
|
jsonMediaType: options.jsonMediaType ?? "application/json",
|
|
394
406
|
introspector: options.schemaIntrospector ?? createZodIntrospector(),
|
|
407
|
+
schemaConverters: [
|
|
408
|
+
...(options.schemaConverters ?? []),
|
|
409
|
+
createZodSchemaConverter(),
|
|
410
|
+
],
|
|
395
411
|
};
|
|
396
412
|
|
|
397
413
|
for (const contract of contracts) {
|
|
@@ -456,6 +472,7 @@ function addContractToPaths(
|
|
|
456
472
|
addHeaderParams(contract, operation, state);
|
|
457
473
|
addRequestBody(contract, operation, state);
|
|
458
474
|
addResponses(contract, operation, state);
|
|
475
|
+
applyOpenAPIOverrides(operation, meta);
|
|
459
476
|
|
|
460
477
|
// Clean up empty parameters array
|
|
461
478
|
if (operation.parameters?.length === 0) {
|
|
@@ -474,6 +491,25 @@ function addContractToPaths(
|
|
|
474
491
|
pathItem[methodKey] = operation;
|
|
475
492
|
}
|
|
476
493
|
|
|
494
|
+
function applyOpenAPIOverrides(
|
|
495
|
+
operation: OperationObject,
|
|
496
|
+
meta: AnyContract["metadata"]["openapi"] | undefined,
|
|
497
|
+
): void {
|
|
498
|
+
if (!meta) return;
|
|
499
|
+
|
|
500
|
+
for (const parameter of meta.parameters ?? []) {
|
|
501
|
+
addParameter(operation, parameter);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (meta.requestBody) {
|
|
505
|
+
operation.requestBody = meta.requestBody;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
for (const [status, response] of Object.entries(meta.responses ?? {})) {
|
|
509
|
+
operation.responses[status] = response;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
477
513
|
function addParameter(
|
|
478
514
|
operation: OperationObject,
|
|
479
515
|
parameter: ParameterObject,
|
|
@@ -525,20 +561,12 @@ function addPathParams(
|
|
|
525
561
|
return;
|
|
526
562
|
}
|
|
527
563
|
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
|
|
564
|
+
const { missingKeys, extraKeys } = comparePathParamsToTemplate({
|
|
565
|
+
pathKeys,
|
|
566
|
+
shapeKeys: Object.keys(shape),
|
|
567
|
+
});
|
|
531
568
|
if (missingKeys.length > 0 || extraKeys.length > 0) {
|
|
532
|
-
const details =
|
|
533
|
-
missingKeys.length > 0
|
|
534
|
-
? `missing pathParams keys: ${missingKeys.join(", ")}`
|
|
535
|
-
: undefined,
|
|
536
|
-
extraKeys.length > 0
|
|
537
|
-
? `extra pathParams keys: ${extraKeys.join(", ")}`
|
|
538
|
-
: undefined,
|
|
539
|
-
]
|
|
540
|
-
.filter(Boolean)
|
|
541
|
-
.join("; ");
|
|
569
|
+
const details = formatPathParamsMismatch({ missingKeys, extraKeys });
|
|
542
570
|
throw new Error(
|
|
543
571
|
`Path parameters for contract "${contract.name}" must match "${contract.path}" (${details}).`,
|
|
544
572
|
);
|
|
@@ -546,8 +574,8 @@ function addPathParams(
|
|
|
546
574
|
|
|
547
575
|
for (const key of pathKeys) {
|
|
548
576
|
const field = shape[key];
|
|
549
|
-
const paramSchemaRef =
|
|
550
|
-
field
|
|
577
|
+
const paramSchemaRef = schemaToConvertedSchemaRef(
|
|
578
|
+
field,
|
|
551
579
|
`${contract.name}_path_${key}`,
|
|
552
580
|
state,
|
|
553
581
|
"input",
|
|
@@ -593,8 +621,8 @@ function addQueryParams(
|
|
|
593
621
|
description = state.introspector.getDescription(field);
|
|
594
622
|
}
|
|
595
623
|
|
|
596
|
-
const paramSchemaRef =
|
|
597
|
-
field
|
|
624
|
+
const paramSchemaRef = schemaToConvertedSchemaRef(
|
|
625
|
+
field,
|
|
598
626
|
`${contract.name}_query_${key}`,
|
|
599
627
|
state,
|
|
600
628
|
"input",
|
|
@@ -630,8 +658,8 @@ function addHeaderParams(
|
|
|
630
658
|
const optional = state.introspector.isOptional(originalField);
|
|
631
659
|
const description = state.introspector.getDescription(originalField);
|
|
632
660
|
|
|
633
|
-
const paramSchemaRef =
|
|
634
|
-
originalField
|
|
661
|
+
const paramSchemaRef = schemaToConvertedSchemaRef(
|
|
662
|
+
originalField,
|
|
635
663
|
`${contract.name}_header_${key}`,
|
|
636
664
|
state,
|
|
637
665
|
"input",
|
|
@@ -663,8 +691,8 @@ function addRequestBody(
|
|
|
663
691
|
);
|
|
664
692
|
}
|
|
665
693
|
|
|
666
|
-
const schemaRef =
|
|
667
|
-
contract.body
|
|
694
|
+
const schemaRef = schemaToConvertedSchemaRef(
|
|
695
|
+
contract.body,
|
|
668
696
|
`${contract.name}_body`,
|
|
669
697
|
state,
|
|
670
698
|
"input",
|
|
@@ -889,10 +917,10 @@ function normalizeExampleKey(key: string): string {
|
|
|
889
917
|
}
|
|
890
918
|
|
|
891
919
|
/**
|
|
892
|
-
* Convert a
|
|
920
|
+
* Convert a validation schema to a JSON Schema reference, registering it in components.
|
|
893
921
|
*/
|
|
894
|
-
function
|
|
895
|
-
schema:
|
|
922
|
+
function schemaToConvertedSchemaRef(
|
|
923
|
+
schema: unknown,
|
|
896
924
|
nameHint: string,
|
|
897
925
|
state: GeneratorState,
|
|
898
926
|
io: SchemaIO,
|
|
@@ -905,14 +933,21 @@ function zodToSchemaRef(
|
|
|
905
933
|
const schemaName = normalizeSchemaName(nameHint, state);
|
|
906
934
|
|
|
907
935
|
if (!state.components.schemas[schemaName]) {
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
936
|
+
const converter = state.schemaConverters.find((candidate) =>
|
|
937
|
+
candidate.canConvert(schema),
|
|
938
|
+
);
|
|
939
|
+
|
|
940
|
+
if (!converter) {
|
|
941
|
+
throw new Error(
|
|
942
|
+
`Unable to convert schema "${nameHint}" to OpenAPI. ` +
|
|
943
|
+
"Pass a schemaConverters entry to contractsToOpenAPI for this schema library.",
|
|
944
|
+
);
|
|
945
|
+
}
|
|
913
946
|
|
|
914
|
-
|
|
915
|
-
|
|
947
|
+
const jsonSchema = converter.toJSONSchema(schema, {
|
|
948
|
+
nameHint,
|
|
949
|
+
io,
|
|
950
|
+
});
|
|
916
951
|
|
|
917
952
|
state.components.schemas[schemaName] = jsonSchema;
|
|
918
953
|
}
|
|
@@ -930,7 +965,7 @@ function schemaToSchemaRef(
|
|
|
930
965
|
return standardErrorResponseSchemaRef(nameHint, state);
|
|
931
966
|
}
|
|
932
967
|
|
|
933
|
-
return
|
|
968
|
+
return schemaToConvertedSchemaRef(schema, nameHint, state, io);
|
|
934
969
|
}
|
|
935
970
|
|
|
936
971
|
function standardErrorResponseSchemaRef(
|
|
@@ -1,3 +1,45 @@
|
|
|
1
|
+
import { type ZodTypeAny, z } from "zod";
|
|
2
|
+
import { getObjectSchemaShape } from "../contracts/schema-shape.js";
|
|
3
|
+
|
|
4
|
+
export type SchemaIO = "input" | "output";
|
|
5
|
+
|
|
6
|
+
type ConvertedSchemaObject = Record<string, unknown>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Context passed to an OpenAPI schema converter.
|
|
10
|
+
*/
|
|
11
|
+
export type SchemaConverterContext = {
|
|
12
|
+
/**
|
|
13
|
+
* Whether the schema is documenting request input or response output.
|
|
14
|
+
*/
|
|
15
|
+
io: SchemaIO;
|
|
16
|
+
/**
|
|
17
|
+
* Component name hint Beignet will use when registering the converted schema.
|
|
18
|
+
*/
|
|
19
|
+
nameHint: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Converts a validation schema into an OpenAPI-compatible JSON Schema object.
|
|
24
|
+
*/
|
|
25
|
+
export interface SchemaConverter {
|
|
26
|
+
/**
|
|
27
|
+
* Human-readable converter name used in diagnostics.
|
|
28
|
+
*/
|
|
29
|
+
name: string;
|
|
30
|
+
/**
|
|
31
|
+
* Return true when this converter owns the schema value.
|
|
32
|
+
*/
|
|
33
|
+
canConvert(schema: unknown): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Convert the schema into an OpenAPI-compatible JSON Schema object.
|
|
36
|
+
*/
|
|
37
|
+
toJSONSchema(
|
|
38
|
+
schema: unknown,
|
|
39
|
+
context: SchemaConverterContext,
|
|
40
|
+
): ConvertedSchemaObject;
|
|
41
|
+
}
|
|
42
|
+
|
|
1
43
|
/**
|
|
2
44
|
* Schema introspection adapter.
|
|
3
45
|
*
|
|
@@ -31,6 +73,31 @@ export interface SchemaIntrospector {
|
|
|
31
73
|
unwrapOptional(schema: unknown): unknown;
|
|
32
74
|
}
|
|
33
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Create the default schema converter for Zod schemas.
|
|
78
|
+
*/
|
|
79
|
+
export function createZodSchemaConverter(): SchemaConverter {
|
|
80
|
+
return {
|
|
81
|
+
name: "zod",
|
|
82
|
+
canConvert(schema: unknown): boolean {
|
|
83
|
+
return schema instanceof z.ZodType;
|
|
84
|
+
},
|
|
85
|
+
toJSONSchema(
|
|
86
|
+
schema: unknown,
|
|
87
|
+
context: SchemaConverterContext,
|
|
88
|
+
): ConvertedSchemaObject {
|
|
89
|
+
const jsonSchema = z.toJSONSchema(schema as ZodTypeAny, {
|
|
90
|
+
target: "draft-2020-12",
|
|
91
|
+
unrepresentable: "any",
|
|
92
|
+
io: context.io,
|
|
93
|
+
}) as ConvertedSchemaObject;
|
|
94
|
+
|
|
95
|
+
delete jsonSchema.$schema;
|
|
96
|
+
return jsonSchema;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
34
101
|
/**
|
|
35
102
|
* Create a schema introspector for Zod schemas.
|
|
36
103
|
*
|
|
@@ -41,23 +108,7 @@ export interface SchemaIntrospector {
|
|
|
41
108
|
export function createZodIntrospector(): SchemaIntrospector {
|
|
42
109
|
return {
|
|
43
110
|
getShape(schema: unknown): Record<string, unknown> | undefined {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const schemaDef = (schema as Record<string, unknown>)?._def;
|
|
47
|
-
if (!schemaDef || typeof schemaDef !== "object") return undefined;
|
|
48
|
-
|
|
49
|
-
if (!("shape" in schemaDef)) return undefined;
|
|
50
|
-
|
|
51
|
-
let shape: unknown;
|
|
52
|
-
if (typeof schemaDef.shape === "function") {
|
|
53
|
-
shape = schemaDef.shape();
|
|
54
|
-
} else if (typeof schemaDef.shape === "object") {
|
|
55
|
-
shape = schemaDef.shape;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (!shape || typeof shape !== "object") return undefined;
|
|
59
|
-
|
|
60
|
-
return shape as Record<string, unknown>;
|
|
111
|
+
return getObjectSchemaShape(schema);
|
|
61
112
|
},
|
|
62
113
|
|
|
63
114
|
getDescription(schema: unknown): string | undefined {
|
package/src/outbox/index.ts
CHANGED
|
@@ -9,13 +9,25 @@ import {
|
|
|
9
9
|
type EventPayloadDef,
|
|
10
10
|
type InferEventPayload,
|
|
11
11
|
parseEventPayload,
|
|
12
|
-
} from "../events";
|
|
13
|
-
import {
|
|
14
|
-
|
|
12
|
+
} from "../events/index.js";
|
|
13
|
+
import {
|
|
14
|
+
getJobRetryDelayMs,
|
|
15
|
+
getJobRetryMaxAttempts,
|
|
16
|
+
type InferJobPayload,
|
|
17
|
+
type JobDef,
|
|
18
|
+
parseJobPayload,
|
|
19
|
+
shouldRetryJob,
|
|
20
|
+
} from "../jobs/index.js";
|
|
21
|
+
import type { JobDispatcherPort } from "../ports/events.js";
|
|
15
22
|
import type {
|
|
16
23
|
BufferedDomainEventRecorder,
|
|
17
24
|
DomainEventRecorderPort,
|
|
18
|
-
} from "../ports/unit-of-work";
|
|
25
|
+
} from "../ports/unit-of-work.js";
|
|
26
|
+
import {
|
|
27
|
+
type BaseProviderInstrumentationEvent,
|
|
28
|
+
createProviderInstrumentation,
|
|
29
|
+
type ProviderInstrumentationTarget,
|
|
30
|
+
} from "../providers/index.js";
|
|
19
31
|
|
|
20
32
|
/**
|
|
21
33
|
* Value or promise of that value.
|
|
@@ -354,6 +366,14 @@ export interface DefineOutboxRegistryInput {
|
|
|
354
366
|
jobs?: readonly JobDef[];
|
|
355
367
|
}
|
|
356
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Correlation fields attached to outbox instrumentation events.
|
|
371
|
+
*/
|
|
372
|
+
export type OutboxInstrumentationContext = Pick<
|
|
373
|
+
BaseProviderInstrumentationEvent,
|
|
374
|
+
"requestId" | "traceId" | "spanId" | "parentSpanId" | "traceparent"
|
|
375
|
+
>;
|
|
376
|
+
|
|
357
377
|
/**
|
|
358
378
|
* Options for draining one outbox batch.
|
|
359
379
|
*/
|
|
@@ -401,6 +421,15 @@ export interface DrainOutboxOptions {
|
|
|
401
421
|
error: unknown;
|
|
402
422
|
now: Date;
|
|
403
423
|
}) => number);
|
|
424
|
+
/**
|
|
425
|
+
* Optional instrumentation target for delivery, retry, and dead-letter
|
|
426
|
+
* visibility.
|
|
427
|
+
*/
|
|
428
|
+
instrumentation?: ProviderInstrumentationTarget;
|
|
429
|
+
/**
|
|
430
|
+
* Optional correlation fields attached to outbox instrumentation events.
|
|
431
|
+
*/
|
|
432
|
+
instrumentationContext?: OutboxInstrumentationContext;
|
|
404
433
|
/**
|
|
405
434
|
* Observer called when delivery fails. Observer failures are ignored so the
|
|
406
435
|
* original delivery failure still controls retry/dead-letter behavior.
|
|
@@ -852,7 +881,7 @@ export async function enqueueJob<J extends JobDef>(
|
|
|
852
881
|
name: job.name,
|
|
853
882
|
payload: toOutboxJsonValue(parsed),
|
|
854
883
|
availableAt: options.availableAt,
|
|
855
|
-
maxAttempts: options.maxAttempts,
|
|
884
|
+
maxAttempts: options.maxAttempts ?? getJobRetryMaxAttempts(job.retry),
|
|
856
885
|
});
|
|
857
886
|
}
|
|
858
887
|
|
|
@@ -906,9 +935,52 @@ function resolveRetryDelayMs(
|
|
|
906
935
|
return options.retryDelayMs;
|
|
907
936
|
}
|
|
908
937
|
|
|
938
|
+
if (message.kind === "job") {
|
|
939
|
+
const job = options.registry.jobs.get(message.name);
|
|
940
|
+
if (job?.retry) {
|
|
941
|
+
return getJobRetryDelayMs(job.retry, {
|
|
942
|
+
attempt: message.attempts,
|
|
943
|
+
error,
|
|
944
|
+
jobName: message.name,
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
909
949
|
return Math.min(60_000, 1000 * 2 ** Math.max(0, message.attempts - 1));
|
|
910
950
|
}
|
|
911
951
|
|
|
952
|
+
function shouldRetryOutboxMessage(
|
|
953
|
+
options: DrainOutboxOptions,
|
|
954
|
+
message: ClaimedOutboxMessage,
|
|
955
|
+
error: unknown,
|
|
956
|
+
): boolean {
|
|
957
|
+
if (message.kind !== "job") {
|
|
958
|
+
return message.attempts < message.maxAttempts;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
const job = options.registry.jobs.get(message.name);
|
|
962
|
+
return shouldRetryJob(job?.retry, {
|
|
963
|
+
attempt: message.attempts,
|
|
964
|
+
error,
|
|
965
|
+
jobName: message.name,
|
|
966
|
+
maxAttempts: message.maxAttempts,
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
function outboxInstrumentationDetails(
|
|
971
|
+
message: ClaimedOutboxMessage,
|
|
972
|
+
details?: Record<string, unknown>,
|
|
973
|
+
): Record<string, unknown> {
|
|
974
|
+
return {
|
|
975
|
+
attempt: message.attempts,
|
|
976
|
+
maxAttempts: message.maxAttempts,
|
|
977
|
+
messageId: message.id,
|
|
978
|
+
messageKind: message.kind,
|
|
979
|
+
messageName: message.name,
|
|
980
|
+
...details,
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
|
|
912
984
|
async function deliverOutboxMessage(
|
|
913
985
|
options: DrainOutboxOptions,
|
|
914
986
|
message: ClaimedOutboxMessage,
|
|
@@ -962,6 +1034,20 @@ export async function drainOutbox(
|
|
|
962
1034
|
): Promise<DrainOutboxResult> {
|
|
963
1035
|
const batchSize = options.batchSize ?? 100;
|
|
964
1036
|
assertPositiveInteger("batchSize", batchSize);
|
|
1037
|
+
const instrumentation = createProviderInstrumentation(
|
|
1038
|
+
options.instrumentation,
|
|
1039
|
+
{
|
|
1040
|
+
providerName: "outbox",
|
|
1041
|
+
watcher: "outbox",
|
|
1042
|
+
},
|
|
1043
|
+
);
|
|
1044
|
+
const jobInstrumentation = createProviderInstrumentation(
|
|
1045
|
+
options.instrumentation,
|
|
1046
|
+
{
|
|
1047
|
+
providerName: "outbox",
|
|
1048
|
+
watcher: "jobs",
|
|
1049
|
+
},
|
|
1050
|
+
);
|
|
965
1051
|
|
|
966
1052
|
const now = options.now ?? new Date();
|
|
967
1053
|
const messages = await options.outbox.claimBatch({
|
|
@@ -984,6 +1070,15 @@ export async function drainOutbox(
|
|
|
984
1070
|
claimToken: message.claimToken,
|
|
985
1071
|
now,
|
|
986
1072
|
});
|
|
1073
|
+
instrumentation.record({
|
|
1074
|
+
type: "outbox",
|
|
1075
|
+
...options.instrumentationContext,
|
|
1076
|
+
messageId: message.id,
|
|
1077
|
+
messageKind: message.kind,
|
|
1078
|
+
messageName: message.name,
|
|
1079
|
+
status: "delivered",
|
|
1080
|
+
details: outboxInstrumentationDetails(message),
|
|
1081
|
+
});
|
|
987
1082
|
result.delivered += 1;
|
|
988
1083
|
} catch (error) {
|
|
989
1084
|
try {
|
|
@@ -992,7 +1087,8 @@ export async function drainOutbox(
|
|
|
992
1087
|
// Preserve the delivery failure path so the message is retried or
|
|
993
1088
|
// dead-lettered even if the observer fails.
|
|
994
1089
|
}
|
|
995
|
-
const
|
|
1090
|
+
const shouldRetry = shouldRetryOutboxMessage(options, message, error);
|
|
1091
|
+
const deadLetter = !shouldRetry;
|
|
996
1092
|
const retryDelayMs = deadLetter
|
|
997
1093
|
? 0
|
|
998
1094
|
: resolveRetryDelayMs(options, message, error, now);
|
|
@@ -1008,8 +1104,57 @@ export async function drainOutbox(
|
|
|
1008
1104
|
});
|
|
1009
1105
|
|
|
1010
1106
|
if (deadLetter) {
|
|
1107
|
+
instrumentation.record({
|
|
1108
|
+
type: "outbox",
|
|
1109
|
+
...options.instrumentationContext,
|
|
1110
|
+
messageId: message.id,
|
|
1111
|
+
messageKind: message.kind,
|
|
1112
|
+
messageName: message.name,
|
|
1113
|
+
status: "deadLettered",
|
|
1114
|
+
details: outboxInstrumentationDetails(message, {
|
|
1115
|
+
error: serializeOutboxError(error),
|
|
1116
|
+
}),
|
|
1117
|
+
});
|
|
1118
|
+
if (message.kind === "job") {
|
|
1119
|
+
jobInstrumentation.record({
|
|
1120
|
+
type: "job",
|
|
1121
|
+
...options.instrumentationContext,
|
|
1122
|
+
jobName: message.name,
|
|
1123
|
+
status: "deadLettered",
|
|
1124
|
+
details: outboxInstrumentationDetails(message, {
|
|
1125
|
+
error: serializeOutboxError(error),
|
|
1126
|
+
}),
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1011
1129
|
result.deadLettered += 1;
|
|
1012
1130
|
} else {
|
|
1131
|
+
const retryAt = new Date(now.getTime() + retryDelayMs).toISOString();
|
|
1132
|
+
instrumentation.record({
|
|
1133
|
+
type: "outbox",
|
|
1134
|
+
...options.instrumentationContext,
|
|
1135
|
+
messageId: message.id,
|
|
1136
|
+
messageKind: message.kind,
|
|
1137
|
+
messageName: message.name,
|
|
1138
|
+
status: "retryScheduled",
|
|
1139
|
+
details: outboxInstrumentationDetails(message, {
|
|
1140
|
+
retryDelayMs,
|
|
1141
|
+
retryAt,
|
|
1142
|
+
error: serializeOutboxError(error),
|
|
1143
|
+
}),
|
|
1144
|
+
});
|
|
1145
|
+
if (message.kind === "job") {
|
|
1146
|
+
jobInstrumentation.record({
|
|
1147
|
+
type: "job",
|
|
1148
|
+
...options.instrumentationContext,
|
|
1149
|
+
jobName: message.name,
|
|
1150
|
+
status: "retryScheduled",
|
|
1151
|
+
details: outboxInstrumentationDetails(message, {
|
|
1152
|
+
retryDelayMs,
|
|
1153
|
+
retryAt,
|
|
1154
|
+
error: serializeOutboxError(error),
|
|
1155
|
+
}),
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1013
1158
|
result.retried += 1;
|
|
1014
1159
|
}
|
|
1015
1160
|
}
|