glasswork 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/auth/abilities.d.ts +41 -0
  2. package/dist/auth/abilities.d.ts.map +1 -0
  3. package/dist/auth/abilities.js +62 -0
  4. package/dist/auth/abilities.js.map +1 -0
  5. package/dist/auth/assert.d.ts +20 -0
  6. package/dist/auth/assert.d.ts.map +1 -0
  7. package/dist/auth/assert.js +28 -0
  8. package/dist/auth/assert.js.map +1 -0
  9. package/dist/auth/better-auth-provider.d.ts +56 -0
  10. package/dist/auth/better-auth-provider.d.ts.map +1 -0
  11. package/dist/auth/better-auth-provider.js +62 -0
  12. package/dist/auth/better-auth-provider.js.map +1 -0
  13. package/dist/auth/index.d.ts +6 -0
  14. package/dist/auth/index.d.ts.map +1 -0
  15. package/dist/auth/index.js +5 -0
  16. package/dist/auth/index.js.map +1 -0
  17. package/dist/auth/middleware.d.ts +31 -0
  18. package/dist/auth/middleware.d.ts.map +1 -0
  19. package/dist/auth/middleware.js +92 -0
  20. package/dist/auth/middleware.js.map +1 -0
  21. package/dist/auth/types.d.ts +54 -0
  22. package/dist/auth/types.d.ts.map +1 -0
  23. package/dist/auth/types.js +2 -0
  24. package/dist/auth/types.js.map +1 -0
  25. package/dist/core/bootstrap.d.ts.map +1 -1
  26. package/dist/core/bootstrap.js +5 -2
  27. package/dist/core/bootstrap.js.map +1 -1
  28. package/dist/core/types.d.ts +14 -3
  29. package/dist/core/types.d.ts.map +1 -1
  30. package/dist/http/route-helpers.d.ts +47 -9
  31. package/dist/http/route-helpers.d.ts.map +1 -1
  32. package/dist/http/route-helpers.js +91 -40
  33. package/dist/http/route-helpers.js.map +1 -1
  34. package/dist/index.d.ts +9 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +7 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/jobs/define-job.d.ts +57 -0
  39. package/dist/jobs/define-job.d.ts.map +1 -0
  40. package/dist/jobs/define-job.js +12 -0
  41. package/dist/jobs/define-job.js.map +1 -0
  42. package/dist/jobs/drivers/eventbridge-scheduler-driver.d.ts +75 -0
  43. package/dist/jobs/drivers/eventbridge-scheduler-driver.d.ts.map +1 -0
  44. package/dist/jobs/drivers/eventbridge-scheduler-driver.js +135 -0
  45. package/dist/jobs/drivers/eventbridge-scheduler-driver.js.map +1 -0
  46. package/dist/jobs/drivers/mock-driver.d.ts +73 -0
  47. package/dist/jobs/drivers/mock-driver.d.ts.map +1 -0
  48. package/dist/jobs/drivers/mock-driver.js +95 -0
  49. package/dist/jobs/drivers/mock-driver.js.map +1 -0
  50. package/dist/jobs/drivers/sqs-driver.d.ts +59 -0
  51. package/dist/jobs/drivers/sqs-driver.d.ts.map +1 -0
  52. package/dist/jobs/drivers/sqs-driver.js +176 -0
  53. package/dist/jobs/drivers/sqs-driver.js.map +1 -0
  54. package/dist/jobs/errors.d.ts +44 -0
  55. package/dist/jobs/errors.d.ts.map +1 -0
  56. package/dist/jobs/errors.js +67 -0
  57. package/dist/jobs/errors.js.map +1 -0
  58. package/dist/jobs/index.d.ts +12 -0
  59. package/dist/jobs/index.d.ts.map +1 -0
  60. package/dist/jobs/index.js +11 -0
  61. package/dist/jobs/index.js.map +1 -0
  62. package/dist/jobs/job-registry.d.ts +33 -0
  63. package/dist/jobs/job-registry.d.ts.map +1 -0
  64. package/dist/jobs/job-registry.js +56 -0
  65. package/dist/jobs/job-registry.js.map +1 -0
  66. package/dist/jobs/job-service.d.ts +44 -0
  67. package/dist/jobs/job-service.d.ts.map +1 -0
  68. package/dist/jobs/job-service.js +105 -0
  69. package/dist/jobs/job-service.js.map +1 -0
  70. package/dist/jobs/periodic-job.d.ts +6 -0
  71. package/dist/jobs/periodic-job.d.ts.map +1 -0
  72. package/dist/jobs/periodic-job.js +11 -0
  73. package/dist/jobs/periodic-job.js.map +1 -0
  74. package/dist/jobs/schedule-constants.d.ts +5 -0
  75. package/dist/jobs/schedule-constants.d.ts.map +1 -0
  76. package/dist/jobs/schedule-constants.js +5 -0
  77. package/dist/jobs/schedule-constants.js.map +1 -0
  78. package/dist/jobs/scheduler.d.ts +17 -0
  79. package/dist/jobs/scheduler.d.ts.map +1 -0
  80. package/dist/jobs/scheduler.js +83 -0
  81. package/dist/jobs/scheduler.js.map +1 -0
  82. package/dist/jobs/types.d.ts +165 -0
  83. package/dist/jobs/types.d.ts.map +1 -0
  84. package/dist/jobs/types.js +2 -0
  85. package/dist/jobs/types.js.map +1 -0
  86. package/dist/jobs/utils.d.ts +15 -0
  87. package/dist/jobs/utils.d.ts.map +1 -0
  88. package/dist/jobs/utils.js +49 -0
  89. package/dist/jobs/utils.js.map +1 -0
  90. package/dist/jobs/worker.d.ts +35 -0
  91. package/dist/jobs/worker.d.ts.map +1 -0
  92. package/dist/jobs/worker.js +361 -0
  93. package/dist/jobs/worker.js.map +1 -0
  94. package/dist/list-query/casl.d.ts +18 -19
  95. package/dist/list-query/casl.d.ts.map +1 -1
  96. package/dist/list-query/casl.js +40 -46
  97. package/dist/list-query/casl.js.map +1 -1
  98. package/dist/uploads/file-upload.d.ts +44 -0
  99. package/dist/uploads/file-upload.d.ts.map +1 -0
  100. package/dist/uploads/file-upload.js +145 -0
  101. package/dist/uploads/file-upload.js.map +1 -0
  102. package/dist/uploads/index.d.ts +6 -0
  103. package/dist/uploads/index.d.ts.map +1 -0
  104. package/dist/uploads/index.js +7 -0
  105. package/dist/uploads/index.js.map +1 -0
  106. package/dist/uploads/uploads.service.d.ts +98 -0
  107. package/dist/uploads/uploads.service.d.ts.map +1 -0
  108. package/dist/uploads/uploads.service.js +134 -0
  109. package/dist/uploads/uploads.service.js.map +1 -0
  110. package/dist/uploads/validators.d.ts +41 -0
  111. package/dist/uploads/validators.d.ts.map +1 -0
  112. package/dist/uploads/validators.js +94 -0
  113. package/dist/uploads/validators.js.map +1 -0
  114. package/package.json +34 -3
@@ -0,0 +1,165 @@
1
+ import type { BaseIssue, BaseSchema } from 'valibot';
2
+ import type { Logger } from '../utils/logger.js';
3
+ /**
4
+ * Duration expressed as human-readable string (e.g. "5m") or seconds as number.
5
+ */
6
+ export type Duration = string | number;
7
+ /**
8
+ * Retry configuration for jobs.
9
+ *
10
+ * Glasswork relies on SQS visibility timeout for retry timing, but this
11
+ * configuration influences how the worker handles failures and determines
12
+ * when a job should be considered "dead" (retries exhausted).
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // Default: 25 retries, send to DLQ
17
+ * defineJob({ name: 'my-job', handler: ... })
18
+ *
19
+ * // Custom retry count
20
+ * defineJob({ name: 'my-job', retry: { maxAttempts: 5 }, handler: ... })
21
+ *
22
+ * // No retries, discard on failure
23
+ * defineJob({ name: 'my-job', retry: false, handler: ... })
24
+ *
25
+ * // Retry but don't save to DLQ
26
+ * defineJob({ name: 'my-job', retry: { maxAttempts: 10, dead: false }, handler: ... })
27
+ * ```
28
+ */
29
+ export interface RetryConfig {
30
+ /**
31
+ * Maximum number of retries before the job is considered dead.
32
+ * The default is 25 retries.
33
+ *
34
+ * @default 25
35
+ */
36
+ maxAttempts?: number;
37
+ /**
38
+ * Whether to save failed jobs to the dead letter queue after exhausting retries.
39
+ * If false, jobs will be discarded (not re-thrown to SQS) after max attempts.
40
+ *
41
+ * @default true
42
+ */
43
+ dead?: boolean;
44
+ }
45
+ /**
46
+ * Execution context passed to job handlers.
47
+ */
48
+ export interface JobContext {
49
+ /** DI container services (shaped by user module) */
50
+ services: Record<string, unknown>;
51
+ /** Job identifier */
52
+ jobId: string;
53
+ /** Current attempt number (starts at 1) */
54
+ attemptNumber: number;
55
+ /** Timestamp when the job was enqueued */
56
+ enqueuedAt: Date;
57
+ /** Optional logger scoped to the job */
58
+ logger?: Logger;
59
+ }
60
+ /**
61
+ * Job handler signature.
62
+ */
63
+ export type JobHandler<TPayload> = (payload: TPayload, context: JobContext) => Promise<void> | void;
64
+ /**
65
+ * Job definition with optional schema validation and retry configuration.
66
+ */
67
+ export interface JobDefinition<TPayload> {
68
+ /** Unique job name */
69
+ name: string;
70
+ /** Target queue (default resolved by JobService) */
71
+ queue?: string;
72
+ /**
73
+ * Dead-letter queue name for operational documentation.
74
+ * Configure the actual DLQ/redrive policy in your queue infrastructure
75
+ * (e.g., SQS redrive policy pointing the primary queue to this DLQ).
76
+ */
77
+ deadLetterQueue?: string;
78
+ /** Optional payload schema for validation */
79
+ schema?: BaseSchema<TPayload, TPayload, BaseIssue<unknown>>;
80
+ /**
81
+ * Retry configuration for this job.
82
+ *
83
+ * - `undefined`: Default (25 retries, send to DLQ)
84
+ * - `number`: Shorthand for { maxAttempts: N }
85
+ * - `false`: Disable retries (discard on first failure)
86
+ * - `RetryConfig`: Full configuration object
87
+ */
88
+ retry?: RetryConfig | number | false;
89
+ /**
90
+ * Optional uniqueness constraint. Intended for FIFO queues.
91
+ * The deduplication key should be stable for the same logical job.
92
+ */
93
+ unique?: {
94
+ key: (payload: TPayload) => string;
95
+ /** Deduplication window (advisory; FIFO queues cap at 5 minutes) */
96
+ window?: Duration;
97
+ };
98
+ /** Handler invoked by the worker */
99
+ handler: JobHandler<TPayload>;
100
+ }
101
+ /**
102
+ * Type-erased job definition for use in module registration.
103
+ *
104
+ * Use this type when registering jobs in modules to avoid the awkward
105
+ * `as JobDefinition<unknown>` cast. This works because module registration
106
+ * only needs to access the `name` property and invoke the handler dynamically.
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * // In your module:
111
+ * export const MyModule = defineModule({
112
+ * jobs: [myJob], // No cast needed!
113
+ * });
114
+ * ```
115
+ */
116
+ export type AnyJobDefinition = JobDefinition<any>;
117
+ /**
118
+ * Job message sent to a queue.
119
+ */
120
+ export interface JobMessage {
121
+ /** Job type identifier */
122
+ jobName: string;
123
+ /** Serialized job payload */
124
+ payload: unknown;
125
+ /** Queue to use (default resolved by JobService/driver) */
126
+ queue?: string;
127
+ /** Optional client-provided job ID */
128
+ jobId?: string;
129
+ /** Additional metadata */
130
+ metadata?: Record<string, string>;
131
+ }
132
+ /**
133
+ * Result returned after enqueuing a job.
134
+ */
135
+ export interface EnqueueResult {
136
+ /** Queue-assigned message ID */
137
+ messageId: string;
138
+ /** Generated or provided job ID */
139
+ jobId: string;
140
+ }
141
+ /**
142
+ * Queue driver interface.
143
+ *
144
+ * Methods beyond `enqueue` are placeholders for later phases and may throw
145
+ * until implemented by a driver.
146
+ */
147
+ export interface QueueDriver {
148
+ /** Driver name for logging/debugging */
149
+ readonly name: string;
150
+ /** Default queue name resolved by the driver (optional) */
151
+ readonly defaultQueue?: string;
152
+ /**
153
+ * Enqueue a job for immediate processing.
154
+ */
155
+ enqueue(message: JobMessage): Promise<EnqueueResult>;
156
+ /**
157
+ * Enqueue a job for processing at a specific time.
158
+ */
159
+ enqueueAt?(message: JobMessage, at: Date): Promise<EnqueueResult>;
160
+ /**
161
+ * Enqueue a job for processing after a delay.
162
+ */
163
+ enqueueIn?(message: JobMessage, delay: Duration): Promise<EnqueueResult>;
164
+ }
165
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/jobs/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/jobs/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ import type { Duration } from './types.js';
2
+ /**
3
+ * Generate a unique job identifier.
4
+ */
5
+ export declare function generateJobId(): string;
6
+ /**
7
+ * Calculate the size of a payload once serialized.
8
+ */
9
+ export declare function calculatePayloadSizeBytes(payload: unknown): number;
10
+ /**
11
+ * Parse a duration value into seconds.
12
+ * Supports number (seconds) or string like "5m", "30s", "1h", "1d".
13
+ */
14
+ export declare function durationToSeconds(duration: Duration): number;
15
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/jobs/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAKlE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CA2B5D"}
@@ -0,0 +1,49 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ /**
3
+ * Generate a unique job identifier.
4
+ */
5
+ export function generateJobId() {
6
+ if (typeof randomUUID === 'function') {
7
+ return randomUUID();
8
+ }
9
+ return `job-${Date.now()}-${Math.random().toString(16).slice(2)}`;
10
+ }
11
+ /**
12
+ * Calculate the size of a payload once serialized.
13
+ */
14
+ export function calculatePayloadSizeBytes(payload) {
15
+ // JSON.stringify(undefined) returns undefined, not a string
16
+ const serialized = payload === undefined ? 'null' : JSON.stringify(payload);
17
+ const encoded = new TextEncoder().encode(serialized);
18
+ return encoded.length;
19
+ }
20
+ /**
21
+ * Parse a duration value into seconds.
22
+ * Supports number (seconds) or string like "5m", "30s", "1h", "1d".
23
+ */
24
+ export function durationToSeconds(duration) {
25
+ if (typeof duration === 'number') {
26
+ return duration;
27
+ }
28
+ const trimmed = duration.trim();
29
+ const match = /^(\d+(?:\.\d+)?)([smhd]?)$/i.exec(trimmed);
30
+ if (!match) {
31
+ throw new Error(`Invalid duration format: "${duration}"`);
32
+ }
33
+ const value = Number.parseFloat(match[1]);
34
+ const unit = match[2].toLowerCase();
35
+ switch (unit) {
36
+ case 's':
37
+ case '':
38
+ return value;
39
+ case 'm':
40
+ return value * 60;
41
+ case 'h':
42
+ return value * 60 * 60;
43
+ case 'd':
44
+ return value * 60 * 60 * 24;
45
+ default:
46
+ throw new Error(`Unsupported duration unit: "${unit}"`);
47
+ }
48
+ }
49
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/jobs/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;QACrC,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IACD,OAAO,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAgB;IACxD,4DAA4D;IAC5D,MAAM,UAAU,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC5E,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACrD,OAAO,OAAO,CAAC,MAAM,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAkB;IAClD,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,6BAA6B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAEpC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,GAAG,CAAC;QACT,KAAK,EAAE;YACL,OAAO,KAAK,CAAC;QACf,KAAK,GAAG;YACN,OAAO,KAAK,GAAG,EAAE,CAAC;QACpB,KAAK,GAAG;YACN,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,CAAC;QACzB,KAAK,GAAG;YACN,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QAC9B;YACE,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,GAAG,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { Context, EventBridgeEvent, SQSEvent } from 'aws-lambda';
2
+ import type { ModuleConfig } from '../core/types.js';
3
+ import { type Logger } from '../utils/logger.js';
4
+ import type { JobContext } from './types.js';
5
+ interface WorkerHooks {
6
+ onJobStart?: (job: JobExecution, context: JobContext) => Promise<void> | void;
7
+ onJobComplete?: (job: JobExecution, context: JobContext) => Promise<void> | void;
8
+ onJobFailed?: (job: JobExecution, context: JobContext, error: Error) => Promise<void> | void;
9
+ onJobDeadLetter?: (job: JobExecution, context: JobContext, error: Error) => Promise<void> | void;
10
+ }
11
+ export interface WorkerConfig {
12
+ module: ModuleConfig;
13
+ hooks?: WorkerHooks;
14
+ logger?: Logger;
15
+ }
16
+ export interface JobExecution {
17
+ jobId: string;
18
+ jobName: string;
19
+ payload: unknown;
20
+ attemptNumber: number;
21
+ enqueuedAt: Date;
22
+ metadata?: Record<string, string>;
23
+ }
24
+ /**
25
+ * Bootstrap a worker Lambda handler for processing jobs.
26
+ */
27
+ export declare function bootstrapWorker(config: WorkerConfig): (event: SQSEvent | EventBridgeEvent<string, unknown> | Record<string, unknown>, ctx?: Context) => Promise<{
28
+ batchItemFailures: import("aws-lambda").SQSBatchItemFailure[];
29
+ success?: undefined;
30
+ } | {
31
+ success: boolean;
32
+ batchItemFailures?: undefined;
33
+ }>;
34
+ export {};
35
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/jobs/worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAoB,QAAQ,EAAa,MAAM,YAAY,CAAC;AAGnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAQ/D,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAmB1D,UAAU,WAAW;IACnB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9E,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjF,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7F,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAClG;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AASD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,IAKhD,OAAO,QAAQ,GAAG,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7E,MAAM,OAAO;;;;;;GA8ChB"}
@@ -0,0 +1,361 @@
1
+ import { asValue, createContainer, InjectionMode } from 'awilix';
2
+ import { object, optional, record, safeParse, string, unknown } from 'valibot';
3
+ import { collectModules, registerModuleProviders, validateNoCycles } from '../core/bootstrap.js';
4
+ import { createLogger } from '../utils/logger.js';
5
+ import { InvalidJobPayloadError, PermanentJobError, RetryExhaustedError, TransientJobError, } from './errors.js';
6
+ import { createJobRegistry } from './job-registry.js';
7
+ import { generateJobId } from './utils.js';
8
+ /**
9
+ * Default maximum retry attempts before a job is considered dead.
10
+ */
11
+ const DEFAULT_MAX_ATTEMPTS = 25;
12
+ /**
13
+ * Valibot schema for validating SQS job message structure.
14
+ */
15
+ const JobMessageSchema = object({
16
+ jobName: string(),
17
+ payload: optional(unknown()),
18
+ jobId: optional(string()),
19
+ enqueuedAt: optional(string()),
20
+ metadata: optional(record(string(), string())),
21
+ });
22
+ /**
23
+ * Bootstrap a worker Lambda handler for processing jobs.
24
+ */
25
+ export function bootstrapWorker(config) {
26
+ const logger = config.logger ?? createLogger('JobsWorker');
27
+ const statePromise = buildWorkerState(config.module, logger);
28
+ return async (event, ctx) => {
29
+ const { container, registry } = await statePromise;
30
+ if (isSQSEvent(event)) {
31
+ const batchItemFailures = [];
32
+ for (const record of event.Records) {
33
+ try {
34
+ await processRecord(record, {
35
+ registry,
36
+ moduleContainer: container,
37
+ hooks: config.hooks,
38
+ logger,
39
+ });
40
+ }
41
+ catch (_error) {
42
+ batchItemFailures.push({ itemIdentifier: record.messageId });
43
+ }
44
+ }
45
+ return { batchItemFailures };
46
+ }
47
+ // Non-SQS invocation (e.g., EventBridge periodic jobs)
48
+ const jobName = extractJobName(event);
49
+ const payload = extractPayload(event);
50
+ if (!jobName) {
51
+ throw new Error('Job name is required for non-SQS invocation');
52
+ }
53
+ // Extract attempt number from Lambda context retry metadata if available
54
+ const attemptNumber = extractAttemptNumber(ctx);
55
+ await executeJob({
56
+ jobName,
57
+ jobId: `eb-${generateJobId()}`,
58
+ payload,
59
+ attemptNumber,
60
+ enqueuedAt: new Date(),
61
+ }, { registry, moduleContainer: container, hooks: config.hooks, logger });
62
+ return { success: true };
63
+ };
64
+ }
65
+ async function resolveAsyncFactories(container, names, logger) {
66
+ const resolutions = names.map(async (name) => {
67
+ const resolved = container.resolve(name);
68
+ const value = resolved instanceof Promise ? await resolved : resolved;
69
+ container.register({ [name]: asValue(value) });
70
+ });
71
+ await Promise.all(resolutions).catch((error) => {
72
+ logger.error('Failed to resolve async providers', { error });
73
+ throw error;
74
+ });
75
+ }
76
+ async function buildWorkerState(module, logger) {
77
+ const container = createContainer({
78
+ injectionMode: InjectionMode.PROXY,
79
+ strict: true,
80
+ });
81
+ const allModules = collectModules(module);
82
+ validateNoCycles(allModules);
83
+ // Register providers
84
+ const asyncFactories = [];
85
+ for (const mod of allModules) {
86
+ const names = registerModuleProviders(mod, container, logger);
87
+ asyncFactories.push(...names);
88
+ }
89
+ // Resolve async factories before processing jobs
90
+ if (asyncFactories.length > 0) {
91
+ await resolveAsyncFactories(container, asyncFactories, logger);
92
+ }
93
+ const registry = buildJobRegistry(allModules);
94
+ return { container, registry };
95
+ }
96
+ function buildJobRegistry(modules) {
97
+ const registry = createJobRegistry();
98
+ for (const mod of modules) {
99
+ if (mod.jobs) {
100
+ for (const job of mod.jobs) {
101
+ registry.register(job);
102
+ }
103
+ }
104
+ }
105
+ return registry;
106
+ }
107
+ async function processRecord(record, context) {
108
+ let parsed;
109
+ try {
110
+ parsed = JSON.parse(record.body);
111
+ }
112
+ catch (error) {
113
+ context.logger.error('Failed to parse job message body', {
114
+ error,
115
+ messageId: record.messageId,
116
+ });
117
+ throw error;
118
+ }
119
+ if (!parsed || typeof parsed !== 'object') {
120
+ throw new Error('Invalid job message payload');
121
+ }
122
+ // Validate message structure using Valibot
123
+ const validationResult = safeParse(JobMessageSchema, parsed);
124
+ if (!validationResult.success) {
125
+ context.logger.error('Invalid job message structure', {
126
+ messageId: record.messageId,
127
+ issues: validationResult.issues,
128
+ });
129
+ throw new Error('Invalid job message structure');
130
+ }
131
+ const parsedMessage = parsed;
132
+ const jobName = parsedMessage.jobName;
133
+ const payload = parsedMessage.payload;
134
+ const jobId = parsedMessage.jobId ?? record.messageId;
135
+ const enqueuedAt = parsedMessage.enqueuedAt ? new Date(parsedMessage.enqueuedAt) : new Date();
136
+ const metadata = parsedMessage.metadata;
137
+ const attemptNumber = record.attributes?.ApproximateReceiveCount
138
+ ? Number.parseInt(record.attributes.ApproximateReceiveCount, 10) || 1
139
+ : 1;
140
+ const execution = {
141
+ jobId,
142
+ jobName,
143
+ payload,
144
+ attemptNumber,
145
+ enqueuedAt,
146
+ metadata,
147
+ };
148
+ await executeJob(execution, context);
149
+ }
150
+ async function executeJob(execution, context) {
151
+ const job = context.registry.getOrThrow(execution.jobName);
152
+ // Normalize retry configuration
153
+ const retryConfig = normalizeRetryConfig(job.retry);
154
+ const scope = context.moduleContainer.createScope();
155
+ const services = scope.cradle;
156
+ const jobLogger = resolveJobLogger(context, execution);
157
+ const jobContext = {
158
+ services,
159
+ jobId: execution.jobId,
160
+ attemptNumber: execution.attemptNumber,
161
+ enqueuedAt: execution.enqueuedAt,
162
+ logger: jobLogger,
163
+ };
164
+ try {
165
+ await context.hooks?.onJobStart?.(execution, jobContext);
166
+ if (job.schema) {
167
+ const result = safeParse(job.schema, execution.payload);
168
+ if (!result.success) {
169
+ throw new InvalidJobPayloadError(job.name, result.issues);
170
+ }
171
+ }
172
+ await job.handler(execution.payload, jobContext);
173
+ await context.hooks?.onJobComplete?.(execution, jobContext);
174
+ }
175
+ catch (error) {
176
+ await handleJobError(error, execution, jobContext, context, retryConfig, jobLogger);
177
+ }
178
+ finally {
179
+ await scope.dispose();
180
+ }
181
+ }
182
+ /**
183
+ * Resolve the logger for job execution, scoped to the job if possible.
184
+ */
185
+ function resolveJobLogger(context, execution) {
186
+ if (!context.moduleContainer.hasRegistration('logger')) {
187
+ return context.logger;
188
+ }
189
+ const baseLogger = context.moduleContainer.resolve('logger');
190
+ return baseLogger?.child
191
+ ? baseLogger.child({ jobId: execution.jobId, jobName: execution.jobName })
192
+ : baseLogger;
193
+ }
194
+ /**
195
+ * Handle job execution errors with retry logic.
196
+ */
197
+ async function handleJobError(err, execution, jobContext, context, retryConfig, jobLogger) {
198
+ const { maxAttempts, dead: sendToDead } = retryConfig;
199
+ // PermanentJobError: Never retry, go straight to DLQ
200
+ if (err instanceof PermanentJobError) {
201
+ jobLogger?.error('Job permanently failed', { err });
202
+ await context.hooks?.onJobFailed?.(execution, jobContext, err);
203
+ await context.hooks?.onJobDeadLetter?.(execution, jobContext, err);
204
+ throw err;
205
+ }
206
+ // No retries configured: discard the job silently
207
+ if (maxAttempts === false) {
208
+ jobLogger?.warn('Job failed with retries disabled, discarding', {
209
+ err,
210
+ jobName: execution.jobName,
211
+ jobId: execution.jobId,
212
+ });
213
+ await context.hooks?.onJobFailed?.(execution, jobContext, err);
214
+ // Return without throwing to acknowledge and discard the message
215
+ return undefined;
216
+ }
217
+ // Check if retries are exhausted
218
+ if (execution.attemptNumber >= maxAttempts) {
219
+ return handleExhaustedRetries(err, execution, jobContext, context, maxAttempts, sendToDead, jobLogger);
220
+ }
221
+ // Normal failure: log and throw to trigger SQS retry
222
+ await context.hooks?.onJobFailed?.(execution, jobContext, err);
223
+ logRetryableError(err, execution, maxAttempts, jobLogger);
224
+ throw err;
225
+ }
226
+ /**
227
+ * Handle the case when all retries are exhausted.
228
+ */
229
+ async function handleExhaustedRetries(err, execution, jobContext, context, maxAttempts, sendToDead, jobLogger) {
230
+ const exhaustedError = new RetryExhaustedError(execution.jobName, execution.attemptNumber, maxAttempts, err);
231
+ jobLogger?.error('Job retries exhausted', {
232
+ err,
233
+ attemptNumber: execution.attemptNumber,
234
+ maxAttempts,
235
+ cause: err.message,
236
+ });
237
+ await context.hooks?.onJobFailed?.(execution, jobContext, err);
238
+ await context.hooks?.onJobDeadLetter?.(execution, jobContext, exhaustedError);
239
+ if (!sendToDead) {
240
+ jobLogger?.info('Job discarded (dead: false)', {
241
+ jobName: execution.jobName,
242
+ jobId: execution.jobId,
243
+ });
244
+ // Return without throwing to discard
245
+ return undefined;
246
+ }
247
+ throw exhaustedError;
248
+ }
249
+ /**
250
+ * Log a retriable error with appropriate context.
251
+ */
252
+ function logRetryableError(err, execution, maxAttempts, jobLogger) {
253
+ if (err instanceof InvalidJobPayloadError) {
254
+ jobLogger?.warn('Invalid job payload, retrying until DLQ', {
255
+ err,
256
+ jobName: execution.jobName,
257
+ jobId: execution.jobId,
258
+ attemptNumber: execution.attemptNumber,
259
+ maxAttempts,
260
+ });
261
+ }
262
+ else if (err instanceof TransientJobError) {
263
+ jobLogger?.warn('Job transient failure, retrying', {
264
+ err,
265
+ retryAfter: err.retryAfter,
266
+ attemptNumber: execution.attemptNumber,
267
+ maxAttempts,
268
+ });
269
+ }
270
+ else {
271
+ jobLogger?.warn('Job failed, will retry', {
272
+ err,
273
+ attemptNumber: execution.attemptNumber,
274
+ maxAttempts,
275
+ remainingAttempts: maxAttempts - execution.attemptNumber,
276
+ });
277
+ }
278
+ }
279
+ /**
280
+ * Normalize retry configuration to a consistent format.
281
+ * Zero or negative maxAttempts are treated as "no retries" (same as retry: false).
282
+ */
283
+ function normalizeRetryConfig(config) {
284
+ if (config === false) {
285
+ return { maxAttempts: false, dead: false };
286
+ }
287
+ if (typeof config === 'number') {
288
+ // Treat zero or negative as "no retries"
289
+ if (config <= 0) {
290
+ return { maxAttempts: false, dead: false };
291
+ }
292
+ return { maxAttempts: config, dead: true };
293
+ }
294
+ if (config === undefined) {
295
+ return { maxAttempts: DEFAULT_MAX_ATTEMPTS, dead: true };
296
+ }
297
+ // Handle object config with potential invalid maxAttempts
298
+ const maxAttempts = config.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
299
+ if (maxAttempts <= 0) {
300
+ return { maxAttempts: false, dead: false };
301
+ }
302
+ return {
303
+ maxAttempts,
304
+ dead: config.dead ?? true,
305
+ };
306
+ }
307
+ /**
308
+ * Type guard to check if an event is an SQS event.
309
+ * Validates presence of Records array with SQS-specific properties.
310
+ */
311
+ function isSQSEvent(event) {
312
+ const maybeEvent = event;
313
+ if (!Array.isArray(maybeEvent?.Records) || maybeEvent.Records.length === 0) {
314
+ return false;
315
+ }
316
+ const firstRecord = maybeEvent.Records[0];
317
+ // Check for SQS-specific properties to distinguish from other AWS event types
318
+ return (typeof firstRecord.messageId === 'string' &&
319
+ typeof firstRecord.body === 'string' &&
320
+ typeof firstRecord.receiptHandle === 'string');
321
+ }
322
+ function extractJobName(event) {
323
+ if (typeof event.jobName === 'string')
324
+ return event.jobName;
325
+ const detail = event.detail;
326
+ if (detail && typeof detail.jobName === 'string')
327
+ return detail.jobName;
328
+ if (detail && typeof detail.name === 'string')
329
+ return detail.name;
330
+ return undefined;
331
+ }
332
+ function extractPayload(event) {
333
+ if ('payload' in event)
334
+ return event.payload;
335
+ const detail = event.detail;
336
+ if (detail && 'payload' in detail)
337
+ return detail.payload;
338
+ return undefined;
339
+ }
340
+ /**
341
+ * Extract attempt number from Lambda context.
342
+ * For EventBridge retries, checks for retry metadata in the context.
343
+ */
344
+ function extractAttemptNumber(ctx) {
345
+ if (!ctx)
346
+ return 1;
347
+ // EventBridge retry information may be available in client context
348
+ // or through environment variables in some configurations
349
+ try {
350
+ const clientContext = ctx
351
+ .clientContext;
352
+ if (clientContext?.custom?.retryAttempt !== undefined) {
353
+ return clientContext.custom.retryAttempt + 1;
354
+ }
355
+ }
356
+ catch {
357
+ // Ignore parsing errors
358
+ }
359
+ return 1;
360
+ }
361
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/jobs/worker.ts"],"names":[],"mappings":"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"}