@beignet/core 0.0.3 → 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 +157 -0
- package/README.md +785 -43
- 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 +12 -14
- package/dist/jobs/index.d.ts.map +1 -1
- package/dist/jobs/index.js +13 -13
- 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 +15 -6
- package/dist/outbox/index.d.ts.map +1 -1
- package/dist/outbox/index.js +60 -16
- 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 +45 -4
- 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 +49 -10
- package/dist/server/hooks/auth.d.ts.map +1 -1
- package/dist/server/hooks/auth.js +77 -37
- 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 +61 -35
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +1 -20
- package/dist/server/http.js.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 +105 -33
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +434 -118
- 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 +607 -5
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +426 -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 +1 -1
- package/dist/uploads/client.d.ts.map +1 -1
- package/dist/uploads/index.d.ts +2 -2
- package/dist/uploads/index.d.ts.map +1 -1
- package/dist/uploads/index.js +1 -1
- package/dist/uploads/index.js.map +1 -1
- package/package.json +24 -2
- 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 +14 -24
- 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 +84 -19
- 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 +86 -7
- 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 +141 -51
- 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 +14 -7
- 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 +78 -51
- package/src/server/index.ts +62 -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 +886 -238
- 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 +1142 -6
- package/src/tracing/index.ts +176 -0
- package/src/uploads/client.ts +1 -1
- package/src/uploads/index.ts +7 -3
- 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
|
@@ -43,20 +43,50 @@ export interface ProviderConfigDef<CfgSchema extends StandardSchemaV1> {
|
|
|
43
43
|
*/
|
|
44
44
|
export type MaybePromise<T> = T | Promise<T>;
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Late-bound service context factory exposed to providers.
|
|
48
|
+
*
|
|
49
|
+
* Calling it before all providers have started throws, so providers should
|
|
50
|
+
* only invoke it from runtime entrypoints such as job dispatch, listeners, or
|
|
51
|
+
* scheduled work.
|
|
52
|
+
*
|
|
53
|
+
* App-local providers can type the factory by declaring `Context` and
|
|
54
|
+
* `ServiceInput` through the curried `createProvider<Requires, Context,
|
|
55
|
+
* ServiceInput>()` form. Untyped providers see `(input: void) =>
|
|
56
|
+
* Promise<unknown>`.
|
|
57
|
+
*/
|
|
58
|
+
export type ProviderServiceContextFactory<
|
|
59
|
+
Context = unknown,
|
|
60
|
+
ServiceInput = void,
|
|
61
|
+
> = (input: ServiceInput) => Promise<Context>;
|
|
62
|
+
|
|
46
63
|
/**
|
|
47
64
|
* Context passed to provider lifecycle hooks.
|
|
48
65
|
*/
|
|
49
|
-
export type ProviderLifecycleContext
|
|
66
|
+
export type ProviderLifecycleContext<
|
|
67
|
+
Ports = ProviderPorts,
|
|
68
|
+
Context = unknown,
|
|
69
|
+
ServiceInput = void,
|
|
70
|
+
> = {
|
|
50
71
|
/**
|
|
51
72
|
* Final app ports after provider setup.
|
|
52
73
|
*/
|
|
53
|
-
ports: Readonly<
|
|
74
|
+
ports: Readonly<Ports>;
|
|
75
|
+
/**
|
|
76
|
+
* Build an app service context through the server context blueprint.
|
|
77
|
+
*/
|
|
78
|
+
createServiceContext: ProviderServiceContextFactory<Context, ServiceInput>;
|
|
54
79
|
};
|
|
55
80
|
|
|
56
81
|
/**
|
|
57
82
|
* Result returned from provider setup.
|
|
58
83
|
*/
|
|
59
|
-
export type ProviderSetupResult<
|
|
84
|
+
export type ProviderSetupResult<
|
|
85
|
+
ProvidedPorts extends ProviderPorts,
|
|
86
|
+
Ports = ProviderPorts,
|
|
87
|
+
Context = unknown,
|
|
88
|
+
ServiceInput = void,
|
|
89
|
+
> = {
|
|
60
90
|
/**
|
|
61
91
|
* Ports contributed by this provider.
|
|
62
92
|
* Keys overwrite earlier ports with the same name at runtime. Prefer unique
|
|
@@ -66,15 +96,60 @@ export type ProviderSetupResult<ProvidedPorts extends ProviderPorts> = {
|
|
|
66
96
|
|
|
67
97
|
/**
|
|
68
98
|
* Optional hook called after all providers have contributed their ports.
|
|
99
|
+
*
|
|
100
|
+
* Declared as a method so typed providers stay assignable to loosely typed
|
|
101
|
+
* provider lists. Hooks that take `ctx` with an unannotated parameter keep
|
|
102
|
+
* TypeScript from inferring `ProvidedPorts` from the returned `ports`.
|
|
103
|
+
* Prefer closing over setup locals, or annotate `ctx` with
|
|
104
|
+
* `ProviderLifecycleContext<...>`.
|
|
69
105
|
*/
|
|
70
|
-
start
|
|
106
|
+
start?(
|
|
107
|
+
ctx: ProviderLifecycleContext<Ports & ProvidedPorts, Context, ServiceInput>,
|
|
108
|
+
): MaybePromise<void>;
|
|
71
109
|
|
|
72
110
|
/**
|
|
73
111
|
* Optional hook called when the server is stopped.
|
|
74
112
|
*/
|
|
75
|
-
stop
|
|
113
|
+
stop?(
|
|
114
|
+
ctx: ProviderLifecycleContext<Ports & ProvidedPorts, Context, ServiceInput>,
|
|
115
|
+
): MaybePromise<void>;
|
|
76
116
|
};
|
|
77
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Static provider metadata used by docs and app-local tooling.
|
|
120
|
+
*
|
|
121
|
+
* Metadata is descriptive. It does not change provider setup, ordering, or
|
|
122
|
+
* runtime port merging behavior.
|
|
123
|
+
*
|
|
124
|
+
* Reusable provider packages should also declare package-owned
|
|
125
|
+
* `beignet.provider` metadata in package.json so external tooling can inspect
|
|
126
|
+
* provider facts without importing runtime code.
|
|
127
|
+
*/
|
|
128
|
+
export interface ServiceProviderMetadata {
|
|
129
|
+
/**
|
|
130
|
+
* Package that exports this provider, when it comes from a reusable package.
|
|
131
|
+
*/
|
|
132
|
+
packageName?: string;
|
|
133
|
+
/**
|
|
134
|
+
* App port keys this provider contributes or replaces.
|
|
135
|
+
*/
|
|
136
|
+
ports?: readonly string[];
|
|
137
|
+
/**
|
|
138
|
+
* App port keys this provider expects previous providers or base app ports to
|
|
139
|
+
* have installed before setup runs.
|
|
140
|
+
*/
|
|
141
|
+
requires?: readonly string[];
|
|
142
|
+
/**
|
|
143
|
+
* Environment variables this provider reads directly or via config loading.
|
|
144
|
+
*/
|
|
145
|
+
env?: readonly string[];
|
|
146
|
+
/**
|
|
147
|
+
* Devtools watcher names this provider can emit through provider
|
|
148
|
+
* instrumentation.
|
|
149
|
+
*/
|
|
150
|
+
watchers?: readonly string[];
|
|
151
|
+
}
|
|
152
|
+
|
|
78
153
|
/**
|
|
79
154
|
* A service provider that can extend or replace ports during app initialization.
|
|
80
155
|
*
|
|
@@ -111,12 +186,19 @@ export interface ServiceProvider<
|
|
|
111
186
|
Ports,
|
|
112
187
|
CfgSchema extends StandardSchemaV1 = StandardSchemaV1<void, void>,
|
|
113
188
|
ProvidedPorts extends ProviderPorts = NoProvidedPorts,
|
|
189
|
+
Context = unknown,
|
|
190
|
+
ServiceInput = void,
|
|
114
191
|
> {
|
|
115
192
|
/**
|
|
116
193
|
* Unique name for this provider (used for logging/debugging)
|
|
117
194
|
*/
|
|
118
195
|
name: string;
|
|
119
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Optional static metadata for docs and diagnostics.
|
|
199
|
+
*/
|
|
200
|
+
metadata?: ServiceProviderMetadata;
|
|
201
|
+
|
|
120
202
|
/**
|
|
121
203
|
* Optional configuration definition.
|
|
122
204
|
* If provided, the config will be loaded and validated before calling setup.
|
|
@@ -130,11 +212,17 @@ export interface ServiceProvider<
|
|
|
130
212
|
*
|
|
131
213
|
* @param ctx.ports - Ports contributed by previous providers
|
|
132
214
|
* @param ctx.config - Validated config (if config was defined), or undefined
|
|
215
|
+
* @param ctx.createServiceContext - Late-bound service context factory.
|
|
216
|
+
* Throws until all providers have started, so call it lazily from runtime
|
|
217
|
+
* entrypoints such as job dispatchers and event listeners.
|
|
133
218
|
*/
|
|
134
219
|
setup(ctx: {
|
|
135
220
|
ports: Readonly<Ports>;
|
|
136
221
|
config: InferOutput<CfgSchema> | undefined;
|
|
137
|
-
|
|
222
|
+
createServiceContext: ProviderServiceContextFactory<Context, ServiceInput>;
|
|
223
|
+
}): MaybePromise<
|
|
224
|
+
ProviderSetupResult<ProvidedPorts, Ports, Context, ServiceInput>
|
|
225
|
+
>;
|
|
138
226
|
|
|
139
227
|
/**
|
|
140
228
|
* Type-only marker for ports this provider contributes.
|
|
@@ -143,6 +231,25 @@ export interface ServiceProvider<
|
|
|
143
231
|
readonly __providedPorts?: ProvidedPorts;
|
|
144
232
|
}
|
|
145
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Loosely typed service provider.
|
|
236
|
+
*
|
|
237
|
+
* Required-port, config, app-context, and service-input generics are erased
|
|
238
|
+
* here so any provider created with `createProvider(...)` — including the
|
|
239
|
+
* typed curried form — stays assignable. Use this for code that works across
|
|
240
|
+
* arbitrary providers, such as provider lists and test helpers.
|
|
241
|
+
*/
|
|
242
|
+
export type AnyServiceProvider = ServiceProvider<
|
|
243
|
+
unknown,
|
|
244
|
+
// biome-ignore lint/suspicious/noExplicitAny: provider config types are erased at this level
|
|
245
|
+
StandardSchemaV1<any, any>,
|
|
246
|
+
ProviderPorts,
|
|
247
|
+
// biome-ignore lint/suspicious/noExplicitAny: provider context types are erased at this level
|
|
248
|
+
any,
|
|
249
|
+
// biome-ignore lint/suspicious/noExplicitAny: provider service-input types are erased at this level
|
|
250
|
+
any
|
|
251
|
+
>;
|
|
252
|
+
|
|
146
253
|
/**
|
|
147
254
|
* Extract the ports a provider contributes.
|
|
148
255
|
*/
|
|
@@ -150,7 +257,9 @@ export type ProvidedPortsOf<TProvider> =
|
|
|
150
257
|
TProvider extends ServiceProvider<
|
|
151
258
|
infer _Ports,
|
|
152
259
|
infer _CfgSchema,
|
|
153
|
-
infer ProvidedPorts
|
|
260
|
+
infer ProvidedPorts,
|
|
261
|
+
infer _Context,
|
|
262
|
+
infer _ServiceInput
|
|
154
263
|
>
|
|
155
264
|
? ProvidedPorts
|
|
156
265
|
: NoProvidedPorts;
|
|
@@ -165,8 +274,20 @@ type UnionToIntersection<T> = (
|
|
|
165
274
|
|
|
166
275
|
/**
|
|
167
276
|
* Extract and merge the ports contributed by a provider list.
|
|
277
|
+
*
|
|
278
|
+
* Use this with `typeof providers` to type provider-contributed ports in app
|
|
279
|
+
* code without hand-written casts:
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```ts
|
|
283
|
+
* import type { InferProviderPorts } from "@beignet/core/providers";
|
|
284
|
+
* import type { providers } from "@/server/providers";
|
|
285
|
+
* import type { AppPorts } from "@/ports";
|
|
286
|
+
*
|
|
287
|
+
* export type AppRuntimePorts = AppPorts & InferProviderPorts<typeof providers>;
|
|
288
|
+
* ```
|
|
168
289
|
*/
|
|
169
|
-
export type
|
|
290
|
+
export type InferProviderPorts<TProviders> =
|
|
170
291
|
TProviders extends readonly unknown[]
|
|
171
292
|
? [TProviders[number]] extends [never]
|
|
172
293
|
? NoProvidedPorts
|
|
@@ -179,6 +300,11 @@ export type ProvidedPortsOfList<TProviders> =
|
|
|
179
300
|
* This is a simple identity function that helps TypeScript infer the correct types
|
|
180
301
|
* for the provider definition.
|
|
181
302
|
*
|
|
303
|
+
* App-local providers can use the curried zero-argument form to declare the
|
|
304
|
+
* ports they require from earlier providers plus their app context and
|
|
305
|
+
* service-context input. The required ports, `ctx.ports`, and
|
|
306
|
+
* `ctx.createServiceContext` are then fully typed with no casts.
|
|
307
|
+
*
|
|
182
308
|
* @example
|
|
183
309
|
* ```ts
|
|
184
310
|
* export const myProvider = createProvider({
|
|
@@ -191,14 +317,47 @@ export type ProvidedPortsOfList<TProviders> =
|
|
|
191
317
|
* return { ports: { myService: createMyService(config) } };
|
|
192
318
|
* },
|
|
193
319
|
* });
|
|
320
|
+
*
|
|
321
|
+
* // Typed app-local provider:
|
|
322
|
+
* export const appDatabaseProvider = createProvider<
|
|
323
|
+
* { db: DbPort<typeof schema>; devtools?: DevtoolsPort },
|
|
324
|
+
* AppContext,
|
|
325
|
+
* AppServiceContextInput
|
|
326
|
+
* >()({
|
|
327
|
+
* name: "app-database",
|
|
328
|
+
* async setup({ ports, createServiceContext }) {
|
|
329
|
+
* const repositories = createRepositories(ports.db.db);
|
|
330
|
+
* return { ports: repositories };
|
|
331
|
+
* },
|
|
332
|
+
* });
|
|
194
333
|
* ```
|
|
195
334
|
*/
|
|
335
|
+
export function createProvider<
|
|
336
|
+
Requires = unknown,
|
|
337
|
+
Context = unknown,
|
|
338
|
+
ServiceInput = void,
|
|
339
|
+
>(): <
|
|
340
|
+
CfgSchema extends StandardSchemaV1 = StandardSchemaV1<void, void>,
|
|
341
|
+
Provided extends ProviderPorts = NoProvidedPorts,
|
|
342
|
+
>(
|
|
343
|
+
def: ServiceProvider<Requires, CfgSchema, Provided, Context, ServiceInput>,
|
|
344
|
+
) => ServiceProvider<Requires, CfgSchema, Provided, Context, ServiceInput>;
|
|
196
345
|
export function createProvider<
|
|
197
346
|
Ports = unknown,
|
|
198
347
|
CfgSchema extends StandardSchemaV1 = StandardSchemaV1<void, void>,
|
|
199
348
|
ProvidedPorts extends ProviderPorts = NoProvidedPorts,
|
|
200
349
|
>(
|
|
201
350
|
def: ServiceProvider<Ports, CfgSchema, ProvidedPorts>,
|
|
202
|
-
): ServiceProvider<Ports, CfgSchema, ProvidedPorts
|
|
351
|
+
): ServiceProvider<Ports, CfgSchema, ProvidedPorts>;
|
|
352
|
+
export function createProvider(
|
|
353
|
+
def?: ServiceProvider<unknown, StandardSchemaV1, ProviderPorts>,
|
|
354
|
+
):
|
|
355
|
+
| ServiceProvider<unknown, StandardSchemaV1, ProviderPorts>
|
|
356
|
+
| ((
|
|
357
|
+
definition: ServiceProvider<unknown, StandardSchemaV1, ProviderPorts>,
|
|
358
|
+
) => ServiceProvider<unknown, StandardSchemaV1, ProviderPorts>) {
|
|
359
|
+
if (def === undefined) {
|
|
360
|
+
return (definition) => definition;
|
|
361
|
+
}
|
|
203
362
|
return def;
|
|
204
363
|
}
|
package/src/schedules/index.ts
CHANGED
|
@@ -29,6 +29,10 @@ export interface ScheduleRunContext {
|
|
|
29
29
|
* Optional provider run ID.
|
|
30
30
|
*/
|
|
31
31
|
readonly id?: string;
|
|
32
|
+
/**
|
|
33
|
+
* One-based provider attempt number for this run, when available.
|
|
34
|
+
*/
|
|
35
|
+
readonly attempt?: number;
|
|
32
36
|
/**
|
|
33
37
|
* Time the provider planned the run.
|
|
34
38
|
*/
|
|
@@ -190,6 +194,10 @@ export interface ScheduleRunOptions<Payload = unknown> {
|
|
|
190
194
|
* Optional provider run ID.
|
|
191
195
|
*/
|
|
192
196
|
id?: string;
|
|
197
|
+
/**
|
|
198
|
+
* One-based provider attempt number for this run, when available.
|
|
199
|
+
*/
|
|
200
|
+
attempt?: number;
|
|
193
201
|
/**
|
|
194
202
|
* Time the provider planned the run.
|
|
195
203
|
*/
|
|
@@ -262,6 +270,72 @@ export interface ScheduleErrorArgs<S extends ScheduleDef = ScheduleDef> {
|
|
|
262
270
|
*/
|
|
263
271
|
export type ScheduleHookName = "start" | "success" | "error";
|
|
264
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Devtools event recorded by the inline schedule runner for each run.
|
|
275
|
+
*/
|
|
276
|
+
export interface ScheduleDevtoolsEvent {
|
|
277
|
+
/**
|
|
278
|
+
* Devtools event type.
|
|
279
|
+
*/
|
|
280
|
+
type: "schedule";
|
|
281
|
+
/**
|
|
282
|
+
* Watcher category used by devtools.
|
|
283
|
+
*/
|
|
284
|
+
watcher: "schedules";
|
|
285
|
+
/**
|
|
286
|
+
* Stable schedule name.
|
|
287
|
+
*/
|
|
288
|
+
scheduleName: string;
|
|
289
|
+
/**
|
|
290
|
+
* Schedule run lifecycle status.
|
|
291
|
+
*/
|
|
292
|
+
status: "started" | "completed" | "failed";
|
|
293
|
+
/**
|
|
294
|
+
* Cron expression for the schedule.
|
|
295
|
+
*/
|
|
296
|
+
cron: string;
|
|
297
|
+
/**
|
|
298
|
+
* IANA timezone for the schedule, when declared.
|
|
299
|
+
*/
|
|
300
|
+
timezone?: string;
|
|
301
|
+
/**
|
|
302
|
+
* Request correlation ID, when the trigger ran inside a request.
|
|
303
|
+
*/
|
|
304
|
+
requestId?: string;
|
|
305
|
+
/**
|
|
306
|
+
* Trace identifier for distributed tracing integrations.
|
|
307
|
+
*/
|
|
308
|
+
traceId?: string;
|
|
309
|
+
/**
|
|
310
|
+
* Structured run details such as `source`, `scheduledAt`, and `error`.
|
|
311
|
+
*/
|
|
312
|
+
details?: Record<string, unknown>;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Sink for schedule devtools events, usually `ctx.ports.devtools`.
|
|
317
|
+
*/
|
|
318
|
+
export interface ScheduleInstrumentation {
|
|
319
|
+
/**
|
|
320
|
+
* Record one schedule devtools event.
|
|
321
|
+
*/
|
|
322
|
+
record(event: ScheduleDevtoolsEvent): unknown;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Correlation fields attached to schedule instrumentation events.
|
|
327
|
+
*/
|
|
328
|
+
export interface ScheduleInstrumentationContext {
|
|
329
|
+
/**
|
|
330
|
+
* Request correlation ID for the triggering invocation.
|
|
331
|
+
*/
|
|
332
|
+
requestId?: string;
|
|
333
|
+
/**
|
|
334
|
+
* Trace identifier for the triggering invocation.
|
|
335
|
+
*/
|
|
336
|
+
traceId?: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
265
339
|
/**
|
|
266
340
|
* Arguments passed when a schedule lifecycle hook itself fails.
|
|
267
341
|
*/
|
|
@@ -304,6 +378,18 @@ export interface InlineScheduleRunnerOptions<Ctx> {
|
|
|
304
378
|
* Clock used when run timestamps are not provided.
|
|
305
379
|
*/
|
|
306
380
|
now?: () => Date;
|
|
381
|
+
/**
|
|
382
|
+
* Devtools-compatible sink that receives `schedule` events for each run.
|
|
383
|
+
*
|
|
384
|
+
* The runner records `started`, `completed`, and `failed` events. Recording
|
|
385
|
+
* failures are isolated from schedule execution and reported to
|
|
386
|
+
* `onHookError` when provided.
|
|
387
|
+
*/
|
|
388
|
+
instrumentation?: ScheduleInstrumentation;
|
|
389
|
+
/**
|
|
390
|
+
* Correlation fields attached to recorded schedule events.
|
|
391
|
+
*/
|
|
392
|
+
instrumentationContext?: ScheduleInstrumentationContext;
|
|
307
393
|
/**
|
|
308
394
|
* Called after payload validation and before the schedule handler.
|
|
309
395
|
*/
|
|
@@ -352,7 +438,7 @@ export interface InlineScheduleRunner<Ctx = unknown>
|
|
|
352
438
|
/**
|
|
353
439
|
* Context-bound schedule helper factory.
|
|
354
440
|
*/
|
|
355
|
-
export interface
|
|
441
|
+
export interface Schedules<Ctx> {
|
|
356
442
|
/**
|
|
357
443
|
* Define a schedule with the bound context type.
|
|
358
444
|
*/
|
|
@@ -360,13 +446,6 @@ export interface ScheduleHandlers<Ctx> {
|
|
|
360
446
|
name: Name,
|
|
361
447
|
options: DefineScheduleOptions<Name, Payload, Ctx>,
|
|
362
448
|
): ScheduleDef<Name, Payload, Ctx>;
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Create an inline schedule runner with the bound context type.
|
|
366
|
-
*/
|
|
367
|
-
createInlineScheduleRunner(
|
|
368
|
-
options?: InlineScheduleRunnerOptions<Ctx>,
|
|
369
|
-
): InlineScheduleRunner<Ctx>;
|
|
370
449
|
}
|
|
371
450
|
|
|
372
451
|
/**
|
|
@@ -469,12 +548,27 @@ function normalizeOptionalDate(
|
|
|
469
548
|
return normalizeDate(value, field, () => new Date());
|
|
470
549
|
}
|
|
471
550
|
|
|
551
|
+
function normalizeOptionalAttempt(
|
|
552
|
+
value: number | undefined,
|
|
553
|
+
): number | undefined {
|
|
554
|
+
if (value === undefined) return undefined;
|
|
555
|
+
|
|
556
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
557
|
+
throw new ScheduleRunContextError(
|
|
558
|
+
"Schedule run attempt must be a positive integer.",
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return value;
|
|
563
|
+
}
|
|
564
|
+
|
|
472
565
|
function createRunContext(
|
|
473
566
|
options: ScheduleRunOptions<unknown>,
|
|
474
567
|
now: () => Date,
|
|
475
568
|
): ScheduleRunContext {
|
|
476
569
|
return {
|
|
477
570
|
id: options.id,
|
|
571
|
+
attempt: normalizeOptionalAttempt(options.attempt),
|
|
478
572
|
scheduledAt: normalizeOptionalDate(options.scheduledAt, "scheduledAt"),
|
|
479
573
|
triggeredAt: normalizeDate(options.triggeredAt, "triggeredAt", now),
|
|
480
574
|
source: options.source,
|
|
@@ -556,13 +650,52 @@ async function runErrorHook<
|
|
|
556
650
|
}
|
|
557
651
|
}
|
|
558
652
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
653
|
+
async function recordScheduleEvent<
|
|
654
|
+
Ctx,
|
|
655
|
+
S extends ScheduleDef<string, StandardSchema, Ctx>,
|
|
656
|
+
>(
|
|
657
|
+
options: InlineScheduleRunnerOptions<Ctx>,
|
|
658
|
+
schedule: S,
|
|
659
|
+
status: ScheduleDevtoolsEvent["status"],
|
|
660
|
+
run: ScheduleRunContext,
|
|
661
|
+
args: {
|
|
662
|
+
payload?: InferSchedulePayload<S>;
|
|
663
|
+
hook: ScheduleHookName;
|
|
664
|
+
scheduleError?: unknown;
|
|
665
|
+
details?: Record<string, unknown>;
|
|
666
|
+
},
|
|
667
|
+
): Promise<void> {
|
|
668
|
+
if (!options.instrumentation) return;
|
|
669
|
+
|
|
670
|
+
try {
|
|
671
|
+
options.instrumentation.record({
|
|
672
|
+
type: "schedule",
|
|
673
|
+
watcher: "schedules",
|
|
674
|
+
requestId: options.instrumentationContext?.requestId,
|
|
675
|
+
traceId: options.instrumentationContext?.traceId,
|
|
676
|
+
scheduleName: schedule.name,
|
|
677
|
+
status,
|
|
678
|
+
cron: schedule.cron,
|
|
679
|
+
timezone: schedule.timezone,
|
|
680
|
+
details: {
|
|
681
|
+
source: run.source,
|
|
682
|
+
scheduledAt: run.scheduledAt?.toISOString(),
|
|
683
|
+
...args.details,
|
|
684
|
+
},
|
|
685
|
+
});
|
|
686
|
+
} catch (error) {
|
|
687
|
+
await reportHookError(options.onHookError, {
|
|
688
|
+
schedule,
|
|
689
|
+
payload: args.payload,
|
|
690
|
+
run,
|
|
691
|
+
hook: args.hook,
|
|
692
|
+
error,
|
|
693
|
+
scheduleError: args.scheduleError,
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
function defineScheduleImpl<
|
|
566
699
|
Name extends string,
|
|
567
700
|
Payload extends StandardSchema,
|
|
568
701
|
Ctx = unknown,
|
|
@@ -637,6 +770,10 @@ export function createInlineScheduleRunner<Ctx>(
|
|
|
637
770
|
payload = await resolveSchedulePayload(schedule, runOptions, run);
|
|
638
771
|
|
|
639
772
|
const lifecycleArgs = { schedule, payload, run };
|
|
773
|
+
await recordScheduleEvent(options, schedule, "started", run, {
|
|
774
|
+
payload,
|
|
775
|
+
hook: "start",
|
|
776
|
+
});
|
|
640
777
|
await runLifecycleHook(
|
|
641
778
|
"start",
|
|
642
779
|
options.onStart,
|
|
@@ -649,6 +786,10 @@ export function createInlineScheduleRunner<Ctx>(
|
|
|
649
786
|
ctx: await resolveCtx(options.ctx),
|
|
650
787
|
run,
|
|
651
788
|
});
|
|
789
|
+
await recordScheduleEvent(options, schedule, "completed", run, {
|
|
790
|
+
payload,
|
|
791
|
+
hook: "success",
|
|
792
|
+
});
|
|
652
793
|
await runLifecycleHook(
|
|
653
794
|
"success",
|
|
654
795
|
options.onSuccess,
|
|
@@ -656,6 +797,12 @@ export function createInlineScheduleRunner<Ctx>(
|
|
|
656
797
|
lifecycleArgs,
|
|
657
798
|
);
|
|
658
799
|
} catch (error) {
|
|
800
|
+
await recordScheduleEvent(options, schedule, "failed", run, {
|
|
801
|
+
payload,
|
|
802
|
+
hook: "error",
|
|
803
|
+
scheduleError: error,
|
|
804
|
+
details: { error },
|
|
805
|
+
});
|
|
659
806
|
await runErrorHook(options.onError, options.onHookError, {
|
|
660
807
|
error,
|
|
661
808
|
schedule,
|
|
@@ -670,20 +817,23 @@ export function createInlineScheduleRunner<Ctx>(
|
|
|
670
817
|
|
|
671
818
|
/**
|
|
672
819
|
* Create schedule helper methods bound to an application context type.
|
|
820
|
+
*
|
|
821
|
+
* Call it once in `lib/schedules.ts`:
|
|
822
|
+
*
|
|
823
|
+
* ```ts
|
|
824
|
+
* export const { defineSchedule } = createSchedules<AppContext>();
|
|
825
|
+
* ```
|
|
826
|
+
*
|
|
827
|
+
* Cron and timezone are metadata for schedule providers. The inline runner only
|
|
828
|
+
* runs schedules when its `run(...)` method is called.
|
|
673
829
|
*/
|
|
674
|
-
export function
|
|
830
|
+
export function createSchedules<Ctx>(): Schedules<Ctx> {
|
|
675
831
|
return {
|
|
676
832
|
defineSchedule<Name extends string, Payload extends StandardSchema>(
|
|
677
833
|
name: Name,
|
|
678
834
|
options: DefineScheduleOptions<Name, Payload, Ctx>,
|
|
679
835
|
): ScheduleDef<Name, Payload, Ctx> {
|
|
680
|
-
return
|
|
681
|
-
},
|
|
682
|
-
|
|
683
|
-
createInlineScheduleRunner(
|
|
684
|
-
options: InlineScheduleRunnerOptions<Ctx> = {},
|
|
685
|
-
): InlineScheduleRunner<Ctx> {
|
|
686
|
-
return createInlineScheduleRunner(options);
|
|
836
|
+
return defineScheduleImpl(name, options);
|
|
687
837
|
},
|
|
688
838
|
};
|
|
689
839
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { AuditLogPort } from "../ports/index.js";
|
|
2
|
+
import { getActiveRequestContext } from "./request-context.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Wrap an audit log port so missing `actor`, `tenant`, `requestId`, and
|
|
6
|
+
* `traceId` fields are filled from the ambient request context at record time.
|
|
7
|
+
*
|
|
8
|
+
* The server keeps the ambient context current for requests (including
|
|
9
|
+
* identity elevated by hooks) and for service contexts created for jobs,
|
|
10
|
+
* listeners, schedules, and tasks. Because enrichment happens when
|
|
11
|
+
* `record(...)` runs, the wrapper also works for ports rebuilt per
|
|
12
|
+
* transaction inside a unit of work — wrap both the top-level audit port and
|
|
13
|
+
* the per-transaction rebuild.
|
|
14
|
+
*
|
|
15
|
+
* Fields provided on the entry always win; only missing fields are filled.
|
|
16
|
+
* When no ambient context is active (for example on runtimes without
|
|
17
|
+
* `AsyncLocalStorage` propagation), entries pass through unchanged.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const audit = createAmbientAuditLog(
|
|
22
|
+
* createInstrumentedAuditLog({ audit: createDrizzleAuditLog(db), instrumentation: ports }),
|
|
23
|
+
* );
|
|
24
|
+
* await audit.record({ action: "posts.publish", resource: { type: "post", id } });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @param audit - Underlying audit log port to write enriched entries to.
|
|
28
|
+
* @returns An audit log port that fills missing context fields before writing.
|
|
29
|
+
*/
|
|
30
|
+
export function createAmbientAuditLog(audit: AuditLogPort): AuditLogPort {
|
|
31
|
+
return {
|
|
32
|
+
record(entry) {
|
|
33
|
+
const context = getActiveRequestContext();
|
|
34
|
+
if (!context) return audit.record(entry);
|
|
35
|
+
|
|
36
|
+
return audit.record({
|
|
37
|
+
...entry,
|
|
38
|
+
actor: entry.actor ?? context.actor,
|
|
39
|
+
tenant: entry.tenant ?? context.tenant,
|
|
40
|
+
requestId: entry.requestId ?? context.requestId,
|
|
41
|
+
traceId: entry.traceId ?? context.traceId,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|