@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/jobs/index.ts
CHANGED
|
@@ -16,6 +16,48 @@ export type MaybePromise<T> = T | Promise<T>;
|
|
|
16
16
|
export type InferSchemaOutput<T extends StandardSchemaV1> =
|
|
17
17
|
StandardSchemaV1.InferOutput<T>;
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Duration accepted by retry helpers. Numbers are milliseconds.
|
|
21
|
+
*/
|
|
22
|
+
export type JobRetryDuration =
|
|
23
|
+
| number
|
|
24
|
+
| `${number}ms`
|
|
25
|
+
| `${number}s`
|
|
26
|
+
| `${number}m`
|
|
27
|
+
| `${number}h`;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Retry strategy understood by Beignet job adapters.
|
|
31
|
+
*/
|
|
32
|
+
export type JobRetryStrategy = "none" | "fixed" | "exponential";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Arguments passed to a retry predicate.
|
|
36
|
+
*/
|
|
37
|
+
export interface JobRetryPredicateArgs {
|
|
38
|
+
/**
|
|
39
|
+
* Error thrown by the previous attempt.
|
|
40
|
+
*/
|
|
41
|
+
error: unknown;
|
|
42
|
+
/**
|
|
43
|
+
* One-based attempt number that just failed.
|
|
44
|
+
*/
|
|
45
|
+
attempt: number;
|
|
46
|
+
/**
|
|
47
|
+
* Maximum attempts allowed for this delivery.
|
|
48
|
+
*/
|
|
49
|
+
maxAttempts: number;
|
|
50
|
+
/**
|
|
51
|
+
* Job name when the retry decision is for a job.
|
|
52
|
+
*/
|
|
53
|
+
jobName?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Return whether a failed attempt should be retried.
|
|
58
|
+
*/
|
|
59
|
+
export type JobRetryPredicate = (args: JobRetryPredicateArgs) => boolean;
|
|
60
|
+
|
|
19
61
|
/**
|
|
20
62
|
* Job definition created by `defineJob(...)`.
|
|
21
63
|
*/
|
|
@@ -81,12 +123,38 @@ export interface JobHandleArgs<J extends JobDef, Ctx> {
|
|
|
81
123
|
*/
|
|
82
124
|
export interface JobRetryOptions {
|
|
83
125
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
|
|
126
|
+
* Retry strategy. Raw objects without a strategy default to exponential
|
|
127
|
+
* backoff so existing `{ attempts }` style definitions stay meaningful.
|
|
128
|
+
*/
|
|
129
|
+
strategy?: JobRetryStrategy;
|
|
130
|
+
/**
|
|
131
|
+
* Maximum total attempts, including the first attempt.
|
|
88
132
|
*/
|
|
89
133
|
attempts?: number;
|
|
134
|
+
/**
|
|
135
|
+
* Delay between attempts for fixed retry policies.
|
|
136
|
+
*/
|
|
137
|
+
delay?: JobRetryDuration;
|
|
138
|
+
/**
|
|
139
|
+
* Initial delay for exponential retry policies.
|
|
140
|
+
*/
|
|
141
|
+
initialDelay?: JobRetryDuration;
|
|
142
|
+
/**
|
|
143
|
+
* Maximum delay for exponential retry policies.
|
|
144
|
+
*/
|
|
145
|
+
maxDelay?: JobRetryDuration;
|
|
146
|
+
/**
|
|
147
|
+
* Exponential multiplier. Defaults to `2`.
|
|
148
|
+
*/
|
|
149
|
+
factor?: number;
|
|
150
|
+
/**
|
|
151
|
+
* Whether adapters that compute delays should add jitter.
|
|
152
|
+
*/
|
|
153
|
+
jitter?: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Optional app-owned retry classifier.
|
|
156
|
+
*/
|
|
157
|
+
retryIf?: JobRetryPredicate;
|
|
90
158
|
}
|
|
91
159
|
|
|
92
160
|
/**
|
|
@@ -117,6 +185,96 @@ export interface DefineJobOptions<
|
|
|
117
185
|
): MaybePromise<void>;
|
|
118
186
|
}
|
|
119
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Options for a fixed job retry policy.
|
|
190
|
+
*/
|
|
191
|
+
export interface FixedJobRetryOptions {
|
|
192
|
+
/**
|
|
193
|
+
* Maximum total attempts, including the first attempt.
|
|
194
|
+
*/
|
|
195
|
+
attempts: number;
|
|
196
|
+
/**
|
|
197
|
+
* Delay between attempts.
|
|
198
|
+
*/
|
|
199
|
+
delay: JobRetryDuration;
|
|
200
|
+
/**
|
|
201
|
+
* Optional app-owned retry classifier.
|
|
202
|
+
*/
|
|
203
|
+
retryIf?: JobRetryPredicate;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Options for an exponential job retry policy.
|
|
208
|
+
*/
|
|
209
|
+
export interface ExponentialJobRetryOptions {
|
|
210
|
+
/**
|
|
211
|
+
* Maximum total attempts, including the first attempt.
|
|
212
|
+
*/
|
|
213
|
+
attempts: number;
|
|
214
|
+
/**
|
|
215
|
+
* Initial delay. Defaults to `1s`.
|
|
216
|
+
*/
|
|
217
|
+
initialDelay?: JobRetryDuration;
|
|
218
|
+
/**
|
|
219
|
+
* Maximum delay. Defaults to `1m`.
|
|
220
|
+
*/
|
|
221
|
+
maxDelay?: JobRetryDuration;
|
|
222
|
+
/**
|
|
223
|
+
* Exponential multiplier. Defaults to `2`.
|
|
224
|
+
*/
|
|
225
|
+
factor?: number;
|
|
226
|
+
/**
|
|
227
|
+
* Whether computed delays should include jitter.
|
|
228
|
+
*/
|
|
229
|
+
jitter?: boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Optional app-owned retry classifier.
|
|
232
|
+
*/
|
|
233
|
+
retryIf?: JobRetryPredicate;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Retry helper namespace for job definitions.
|
|
238
|
+
*/
|
|
239
|
+
export const retry = {
|
|
240
|
+
/**
|
|
241
|
+
* Disable retries. The first failure is terminal.
|
|
242
|
+
*/
|
|
243
|
+
none(): JobRetryOptions {
|
|
244
|
+
return {
|
|
245
|
+
strategy: "none",
|
|
246
|
+
attempts: 1,
|
|
247
|
+
};
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Retry with the same delay between attempts.
|
|
252
|
+
*/
|
|
253
|
+
fixed(options: FixedJobRetryOptions): JobRetryOptions {
|
|
254
|
+
return validateJobRetryOptions({
|
|
255
|
+
strategy: "fixed",
|
|
256
|
+
attempts: options.attempts,
|
|
257
|
+
delay: options.delay,
|
|
258
|
+
retryIf: options.retryIf,
|
|
259
|
+
});
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Retry with exponential backoff.
|
|
264
|
+
*/
|
|
265
|
+
exponential(options: ExponentialJobRetryOptions): JobRetryOptions {
|
|
266
|
+
return validateJobRetryOptions({
|
|
267
|
+
strategy: "exponential",
|
|
268
|
+
attempts: options.attempts,
|
|
269
|
+
initialDelay: options.initialDelay,
|
|
270
|
+
maxDelay: options.maxDelay,
|
|
271
|
+
factor: options.factor,
|
|
272
|
+
jitter: options.jitter,
|
|
273
|
+
retryIf: options.retryIf,
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
} as const;
|
|
277
|
+
|
|
120
278
|
/**
|
|
121
279
|
* Options for the inline job dispatcher.
|
|
122
280
|
*/
|
|
@@ -148,7 +306,7 @@ export interface InlineJobDispatcher<Ctx = unknown> {
|
|
|
148
306
|
/**
|
|
149
307
|
* Context-bound job helper factory.
|
|
150
308
|
*/
|
|
151
|
-
export interface
|
|
309
|
+
export interface Jobs<Ctx> {
|
|
152
310
|
/**
|
|
153
311
|
* Define a job with the bound context type.
|
|
154
312
|
*/
|
|
@@ -156,13 +314,6 @@ export interface JobHandlers<Ctx> {
|
|
|
156
314
|
name: Name,
|
|
157
315
|
options: DefineJobOptions<Name, Payload, Ctx>,
|
|
158
316
|
): JobDef<Name, Payload, Ctx>;
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Create an inline dispatcher with the bound context type.
|
|
162
|
-
*/
|
|
163
|
-
createInlineJobDispatcher(
|
|
164
|
-
options?: InlineJobDispatcherOptions<Ctx>,
|
|
165
|
-
): InlineJobDispatcher<Ctx>;
|
|
166
317
|
}
|
|
167
318
|
|
|
168
319
|
/**
|
|
@@ -207,6 +358,165 @@ function formatIssues(issues: readonly StandardSchemaV1.Issue[]): string {
|
|
|
207
358
|
.join("; ");
|
|
208
359
|
}
|
|
209
360
|
|
|
361
|
+
function assertPositiveInteger(name: string, value: number): void {
|
|
362
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
363
|
+
throw new Error(`${name} must be a positive integer`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function assertPositiveNumber(name: string, value: number): void {
|
|
368
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
369
|
+
throw new Error(`${name} must be a positive number`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function durationToMs(name: string, value: JobRetryDuration): number {
|
|
374
|
+
if (typeof value === "number") {
|
|
375
|
+
assertPositiveInteger(name, value);
|
|
376
|
+
return value;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const match = /^(\d+)(ms|s|m|h)$/.exec(value);
|
|
380
|
+
if (!match) {
|
|
381
|
+
throw new Error(
|
|
382
|
+
`${name} must be a positive millisecond value or duration string like "500ms", "30s", "5m", or "1h".`,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const amount = Number(match[1]);
|
|
387
|
+
assertPositiveInteger(name, amount);
|
|
388
|
+
|
|
389
|
+
switch (match[2]) {
|
|
390
|
+
case "ms":
|
|
391
|
+
return amount;
|
|
392
|
+
case "s":
|
|
393
|
+
return amount * 1000;
|
|
394
|
+
case "m":
|
|
395
|
+
return amount * 60_000;
|
|
396
|
+
case "h":
|
|
397
|
+
return amount * 3_600_000;
|
|
398
|
+
default:
|
|
399
|
+
throw new Error(`${name} has an unsupported duration unit.`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function validateJobRetryOptions(options: JobRetryOptions): JobRetryOptions {
|
|
404
|
+
const strategy = options.strategy ?? "exponential";
|
|
405
|
+
|
|
406
|
+
if (!["none", "fixed", "exponential"].includes(strategy)) {
|
|
407
|
+
throw new Error("retry.strategy must be none, fixed, or exponential");
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const attempts = options.attempts ?? (strategy === "none" ? 1 : undefined);
|
|
411
|
+
if (attempts === undefined) {
|
|
412
|
+
throw new Error("retry.attempts is required");
|
|
413
|
+
}
|
|
414
|
+
assertPositiveInteger("retry.attempts", attempts);
|
|
415
|
+
|
|
416
|
+
if (strategy === "none" && attempts !== 1) {
|
|
417
|
+
throw new Error("retry.none() must use exactly one attempt");
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (strategy === "fixed") {
|
|
421
|
+
if (options.delay === undefined) {
|
|
422
|
+
throw new Error("retry.delay is required for fixed retry policies");
|
|
423
|
+
}
|
|
424
|
+
durationToMs("retry.delay", options.delay);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (strategy === "exponential") {
|
|
428
|
+
if (options.initialDelay !== undefined) {
|
|
429
|
+
durationToMs("retry.initialDelay", options.initialDelay);
|
|
430
|
+
}
|
|
431
|
+
if (options.maxDelay !== undefined) {
|
|
432
|
+
durationToMs("retry.maxDelay", options.maxDelay);
|
|
433
|
+
}
|
|
434
|
+
if (options.factor !== undefined) {
|
|
435
|
+
assertPositiveNumber("retry.factor", options.factor);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return {
|
|
440
|
+
...options,
|
|
441
|
+
strategy,
|
|
442
|
+
attempts,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Return the maximum total attempts configured by a retry policy.
|
|
448
|
+
*/
|
|
449
|
+
export function getJobRetryMaxAttempts(
|
|
450
|
+
options: JobRetryOptions | undefined,
|
|
451
|
+
): number | undefined {
|
|
452
|
+
return options ? validateJobRetryOptions(options).attempts : undefined;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Return whether a failed job attempt should be retried.
|
|
457
|
+
*/
|
|
458
|
+
export function shouldRetryJob(
|
|
459
|
+
options: JobRetryOptions | undefined,
|
|
460
|
+
args: JobRetryPredicateArgs,
|
|
461
|
+
): boolean {
|
|
462
|
+
if (!options) return args.attempt < args.maxAttempts;
|
|
463
|
+
|
|
464
|
+
const retryOptions = validateJobRetryOptions(options);
|
|
465
|
+
const maxAttempts = Math.min(
|
|
466
|
+
args.maxAttempts,
|
|
467
|
+
retryOptions.attempts ?? args.maxAttempts,
|
|
468
|
+
);
|
|
469
|
+
if (retryOptions.strategy === "none") return false;
|
|
470
|
+
if (args.attempt >= maxAttempts) return false;
|
|
471
|
+
|
|
472
|
+
return retryOptions.retryIf?.({ ...args, maxAttempts }) ?? true;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Compute the next retry delay in milliseconds for a failed job attempt.
|
|
477
|
+
*/
|
|
478
|
+
export function getJobRetryDelayMs(
|
|
479
|
+
options: JobRetryOptions | undefined,
|
|
480
|
+
args: Pick<JobRetryPredicateArgs, "attempt" | "error" | "jobName">,
|
|
481
|
+
): number {
|
|
482
|
+
const retryOptions = options
|
|
483
|
+
? validateJobRetryOptions(options)
|
|
484
|
+
: retry.exponential({ attempts: 3 });
|
|
485
|
+
|
|
486
|
+
let delayMs: number;
|
|
487
|
+
if (retryOptions.strategy === "fixed") {
|
|
488
|
+
delayMs = durationToMs("retry.delay", retryOptions.delay ?? "1s");
|
|
489
|
+
} else if (retryOptions.strategy === "none") {
|
|
490
|
+
delayMs = 0;
|
|
491
|
+
} else {
|
|
492
|
+
const initialDelayMs = durationToMs(
|
|
493
|
+
"retry.initialDelay",
|
|
494
|
+
retryOptions.initialDelay ?? "1s",
|
|
495
|
+
);
|
|
496
|
+
const maxDelayMs = durationToMs(
|
|
497
|
+
"retry.maxDelay",
|
|
498
|
+
retryOptions.maxDelay ?? "1m",
|
|
499
|
+
);
|
|
500
|
+
const factor = retryOptions.factor ?? 2;
|
|
501
|
+
delayMs = Math.min(
|
|
502
|
+
maxDelayMs,
|
|
503
|
+
initialDelayMs * factor ** Math.max(0, args.attempt - 1),
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (retryOptions.jitter && delayMs > 0) {
|
|
508
|
+
delayMs = Math.ceil(delayMs * (0.5 + Math.random()));
|
|
509
|
+
if (retryOptions.strategy === "exponential") {
|
|
510
|
+
delayMs = Math.min(
|
|
511
|
+
delayMs,
|
|
512
|
+
durationToMs("retry.maxDelay", retryOptions.maxDelay ?? "1m"),
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return delayMs;
|
|
518
|
+
}
|
|
519
|
+
|
|
210
520
|
async function parsePayload<Schema extends StandardSchemaV1>(
|
|
211
521
|
schema: Schema,
|
|
212
522
|
input: unknown,
|
|
@@ -238,14 +548,7 @@ async function resolveCtx<Ctx>(
|
|
|
238
548
|
return ctx as Ctx;
|
|
239
549
|
}
|
|
240
550
|
|
|
241
|
-
|
|
242
|
-
* Define a typed job.
|
|
243
|
-
*
|
|
244
|
-
* Retry options are provider hints. Inline dispatchers validate payloads and
|
|
245
|
-
* call `handle(...)` immediately; durable providers may enqueue or schedule the
|
|
246
|
-
* job according to their own runtime.
|
|
247
|
-
*/
|
|
248
|
-
export function defineJob<
|
|
551
|
+
function defineJobImpl<
|
|
249
552
|
Name extends string,
|
|
250
553
|
Payload extends StandardSchema,
|
|
251
554
|
Ctx = unknown,
|
|
@@ -253,12 +556,16 @@ export function defineJob<
|
|
|
253
556
|
name: Name,
|
|
254
557
|
options: DefineJobOptions<Name, Payload, Ctx>,
|
|
255
558
|
): JobDef<Name, Payload, Ctx> {
|
|
559
|
+
const retryOptions = options.retry
|
|
560
|
+
? validateJobRetryOptions(options.retry)
|
|
561
|
+
: undefined;
|
|
562
|
+
|
|
256
563
|
return {
|
|
257
564
|
kind: "job",
|
|
258
565
|
name,
|
|
259
566
|
payload: options.payload,
|
|
260
567
|
description: options.description,
|
|
261
|
-
retry:
|
|
568
|
+
retry: retryOptions,
|
|
262
569
|
handle: options.handle as JobDef<Name, Payload, Ctx>["handle"],
|
|
263
570
|
};
|
|
264
571
|
}
|
|
@@ -303,20 +610,24 @@ export function createInlineJobDispatcher<Ctx>(
|
|
|
303
610
|
|
|
304
611
|
/**
|
|
305
612
|
* Create job helper methods bound to an application context type.
|
|
613
|
+
*
|
|
614
|
+
* Call it once in `lib/jobs.ts`:
|
|
615
|
+
*
|
|
616
|
+
* ```ts
|
|
617
|
+
* export const { defineJob } = createJobs<AppContext>();
|
|
618
|
+
* ```
|
|
619
|
+
*
|
|
620
|
+
* Retry options are provider hints. Inline dispatchers validate payloads and
|
|
621
|
+
* call `handle(...)` immediately; durable providers may enqueue or schedule the
|
|
622
|
+
* job according to their own runtime.
|
|
306
623
|
*/
|
|
307
|
-
export function
|
|
624
|
+
export function createJobs<Ctx>(): Jobs<Ctx> {
|
|
308
625
|
return {
|
|
309
626
|
defineJob<Name extends string, Payload extends StandardSchema>(
|
|
310
627
|
name: Name,
|
|
311
628
|
options: DefineJobOptions<Name, Payload, Ctx>,
|
|
312
629
|
): JobDef<Name, Payload, Ctx> {
|
|
313
|
-
return
|
|
314
|
-
},
|
|
315
|
-
|
|
316
|
-
createInlineJobDispatcher(
|
|
317
|
-
options: InlineJobDispatcherOptions<Ctx> = {},
|
|
318
|
-
): InlineJobDispatcher<Ctx> {
|
|
319
|
-
return createInlineJobDispatcher(options);
|
|
630
|
+
return defineJobImpl(name, options);
|
|
320
631
|
},
|
|
321
632
|
};
|
|
322
633
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
-
import type { SendMailOptions } from "../mail";
|
|
3
|
-
import type { ProviderInstrumentationTarget } from "../providers";
|
|
4
|
-
import { createProviderInstrumentation } from "../providers";
|
|
2
|
+
import type { SendMailOptions } from "../mail/index.js";
|
|
3
|
+
import type { ProviderInstrumentationTarget } from "../providers/index.js";
|
|
4
|
+
import { createProviderInstrumentation } from "../providers/index.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Any Standard Schema compatible validator.
|
|
@@ -336,7 +336,7 @@ export type MailNotificationRenderer<
|
|
|
336
336
|
/**
|
|
337
337
|
* Context-bound notification helper factory.
|
|
338
338
|
*/
|
|
339
|
-
export interface
|
|
339
|
+
export interface Notifications<Ctx> {
|
|
340
340
|
/**
|
|
341
341
|
* Define a notification with the bound context type.
|
|
342
342
|
*/
|
|
@@ -344,13 +344,6 @@ export interface NotificationHandlers<Ctx> {
|
|
|
344
344
|
name: Name,
|
|
345
345
|
options: DefineNotificationOptions<Payload, Ctx>,
|
|
346
346
|
): NotificationDef<Name, Payload, Ctx>;
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Create an inline dispatcher with the bound context type.
|
|
350
|
-
*/
|
|
351
|
-
createInlineNotificationDispatcher(
|
|
352
|
-
options?: InlineNotificationDispatcherOptions<Ctx>,
|
|
353
|
-
): NotificationPort;
|
|
354
347
|
}
|
|
355
348
|
|
|
356
349
|
/**
|
|
@@ -495,14 +488,7 @@ function summarizeResults(results: readonly NotificationChannelResult[]) {
|
|
|
495
488
|
return { sent, skipped, failed };
|
|
496
489
|
}
|
|
497
490
|
|
|
498
|
-
|
|
499
|
-
* Define a typed notification.
|
|
500
|
-
*
|
|
501
|
-
* Notifications represent user-facing communication intent. Channel handlers
|
|
502
|
-
* decide how that intent becomes mail, SMS, push, in-app delivery, or another
|
|
503
|
-
* app-owned channel.
|
|
504
|
-
*/
|
|
505
|
-
export function defineNotification<
|
|
491
|
+
function defineNotificationImpl<
|
|
506
492
|
Name extends string,
|
|
507
493
|
Payload extends StandardSchema,
|
|
508
494
|
Ctx = unknown,
|
|
@@ -752,20 +738,24 @@ export function createMemoryNotificationPort(
|
|
|
752
738
|
|
|
753
739
|
/**
|
|
754
740
|
* Create notification helper methods bound to an application context type.
|
|
741
|
+
*
|
|
742
|
+
* Call it once in `lib/notifications.ts`:
|
|
743
|
+
*
|
|
744
|
+
* ```ts
|
|
745
|
+
* export const { defineNotification } = createNotifications<AppContext>();
|
|
746
|
+
* ```
|
|
747
|
+
*
|
|
748
|
+
* Notifications represent user-facing communication intent. Channel handlers
|
|
749
|
+
* decide how that intent becomes mail, SMS, push, in-app delivery, or another
|
|
750
|
+
* app-owned channel.
|
|
755
751
|
*/
|
|
756
|
-
export function
|
|
752
|
+
export function createNotifications<Ctx>(): Notifications<Ctx> {
|
|
757
753
|
return {
|
|
758
754
|
defineNotification<Name extends string, Payload extends StandardSchema>(
|
|
759
755
|
name: Name,
|
|
760
756
|
options: DefineNotificationOptions<Payload, Ctx>,
|
|
761
757
|
): NotificationDef<Name, Payload, Ctx> {
|
|
762
|
-
return
|
|
763
|
-
},
|
|
764
|
-
|
|
765
|
-
createInlineNotificationDispatcher(
|
|
766
|
-
options: InlineNotificationDispatcherOptions<Ctx> = {},
|
|
767
|
-
): NotificationPort {
|
|
768
|
-
return createInlineNotificationDispatcher(options);
|
|
758
|
+
return defineNotificationImpl(name, options);
|
|
769
759
|
},
|
|
770
760
|
};
|
|
771
761
|
}
|