@contractspec/lib.jobs 1.57.0 → 1.59.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 (92) hide show
  1. package/dist/contracts/index.d.ts +494 -500
  2. package/dist/contracts/index.d.ts.map +1 -1
  3. package/dist/contracts/index.js +298 -461
  4. package/dist/entities/index.d.ts +117 -122
  5. package/dist/entities/index.d.ts.map +1 -1
  6. package/dist/entities/index.js +170 -193
  7. package/dist/events.d.ts +297 -303
  8. package/dist/events.d.ts.map +1 -1
  9. package/dist/events.js +199 -351
  10. package/dist/handlers/gmail-sync-handler.d.ts +5 -9
  11. package/dist/handlers/gmail-sync-handler.d.ts.map +1 -1
  12. package/dist/handlers/gmail-sync-handler.js +8 -8
  13. package/dist/handlers/index.d.ts +5 -9
  14. package/dist/handlers/index.d.ts.map +1 -1
  15. package/dist/handlers/index.js +53 -10
  16. package/dist/handlers/ping-job.d.ts +6 -10
  17. package/dist/handlers/ping-job.d.ts.map +1 -1
  18. package/dist/handlers/ping-job.js +13 -12
  19. package/dist/handlers/storage-document-handler.d.ts +7 -11
  20. package/dist/handlers/storage-document-handler.d.ts.map +1 -1
  21. package/dist/handlers/storage-document-handler.js +15 -13
  22. package/dist/index.d.ts +7 -24
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1366 -64
  25. package/dist/jobs.capability.d.ts +2 -7
  26. package/dist/jobs.capability.d.ts.map +1 -1
  27. package/dist/jobs.capability.js +29 -33
  28. package/dist/jobs.feature.d.ts +1 -6
  29. package/dist/jobs.feature.d.ts.map +1 -1
  30. package/dist/jobs.feature.js +45 -108
  31. package/dist/node/contracts/index.js +318 -0
  32. package/dist/node/entities/index.js +174 -0
  33. package/dist/node/events.js +200 -0
  34. package/dist/node/handlers/gmail-sync-handler.js +9 -0
  35. package/dist/node/handlers/index.js +55 -0
  36. package/dist/node/handlers/ping-job.js +14 -0
  37. package/dist/node/handlers/storage-document-handler.js +16 -0
  38. package/dist/node/index.js +1368 -0
  39. package/dist/node/jobs.capability.js +28 -0
  40. package/dist/node/jobs.feature.js +46 -0
  41. package/dist/node/queue/gcp-cloud-tasks.js +66 -0
  42. package/dist/node/queue/gcp-pubsub.js +54 -0
  43. package/dist/node/queue/index.js +478 -0
  44. package/dist/node/queue/memory-queue.js +160 -0
  45. package/dist/node/queue/register-defined-job.js +15 -0
  46. package/dist/node/queue/scaleway-sqs-queue.js +206 -0
  47. package/dist/node/queue/types.js +10 -0
  48. package/dist/node/scheduler/index.js +117 -0
  49. package/dist/queue/gcp-cloud-tasks.d.ts +33 -36
  50. package/dist/queue/gcp-cloud-tasks.d.ts.map +1 -1
  51. package/dist/queue/gcp-cloud-tasks.js +65 -59
  52. package/dist/queue/gcp-pubsub.d.ts +18 -21
  53. package/dist/queue/gcp-pubsub.d.ts.map +1 -1
  54. package/dist/queue/gcp-pubsub.js +53 -45
  55. package/dist/queue/index.d.ts +6 -15
  56. package/dist/queue/index.d.ts.map +1 -1
  57. package/dist/queue/index.js +476 -20
  58. package/dist/queue/memory-queue.d.ts +25 -29
  59. package/dist/queue/memory-queue.d.ts.map +1 -1
  60. package/dist/queue/memory-queue.js +159 -138
  61. package/dist/queue/register-defined-job.d.ts +3 -7
  62. package/dist/queue/register-defined-job.d.ts.map +1 -1
  63. package/dist/queue/register-defined-job.js +14 -14
  64. package/dist/queue/scaleway-sqs-queue.d.ts +31 -35
  65. package/dist/queue/scaleway-sqs-queue.d.ts.map +1 -1
  66. package/dist/queue/scaleway-sqs-queue.js +205 -173
  67. package/dist/queue/types.d.ts +2 -8
  68. package/dist/queue/types.d.ts.map +1 -1
  69. package/dist/queue/types.js +11 -12
  70. package/dist/scheduler/index.d.ts +68 -72
  71. package/dist/scheduler/index.d.ts.map +1 -1
  72. package/dist/scheduler/index.js +113 -141
  73. package/package.json +176 -50
  74. package/dist/_virtual/_rolldown/runtime.js +0 -36
  75. package/dist/contracts/index.js.map +0 -1
  76. package/dist/entities/index.js.map +0 -1
  77. package/dist/events.js.map +0 -1
  78. package/dist/handlers/gmail-sync-handler.js.map +0 -1
  79. package/dist/handlers/index.js.map +0 -1
  80. package/dist/handlers/ping-job.js.map +0 -1
  81. package/dist/handlers/storage-document-handler.js.map +0 -1
  82. package/dist/index.js.map +0 -1
  83. package/dist/jobs.capability.js.map +0 -1
  84. package/dist/jobs.feature.js.map +0 -1
  85. package/dist/queue/gcp-cloud-tasks.js.map +0 -1
  86. package/dist/queue/gcp-pubsub.js.map +0 -1
  87. package/dist/queue/index.js.map +0 -1
  88. package/dist/queue/memory-queue.js.map +0 -1
  89. package/dist/queue/register-defined-job.js.map +0 -1
  90. package/dist/queue/scaleway-sqs-queue.js.map +0 -1
  91. package/dist/queue/types.js.map +0 -1
  92. package/dist/scheduler/index.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.js","names":[],"sources":["../src/events.ts"],"sourcesContent":["import { ScalarTypeEnum, defineSchemaModel } from '@contractspec/lib.schema';\nimport { defineEvent, StabilityEnum } from '@contractspec/lib.contracts';\n\n// ============ Event Payloads ============\n\nconst JobEnqueuedPayload = defineSchemaModel({\n name: 'JobEnqueuedEventPayload',\n description: 'Payload when a job is added to the queue',\n fields: {\n jobId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n priority: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n scheduledAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },\n tenantId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },\n enqueuedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n },\n});\n\nconst JobStartedPayload = defineSchemaModel({\n name: 'JobStartedEventPayload',\n description: 'Payload when a job starts processing',\n fields: {\n jobId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n attempt: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n startedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n },\n});\n\nconst JobCompletedPayload = defineSchemaModel({\n name: 'JobCompletedEventPayload',\n description: 'Payload when a job completes successfully',\n fields: {\n jobId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n attempt: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n durationMs: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n completedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n },\n});\n\nconst JobFailedPayload = defineSchemaModel({\n name: 'JobFailedEventPayload',\n description: 'Payload when a job attempt fails',\n fields: {\n jobId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n attempt: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n error: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n willRetry: { type: ScalarTypeEnum.Boolean(), isOptional: false },\n failedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n },\n});\n\nconst JobRetryingPayload = defineSchemaModel({\n name: 'JobRetryingEventPayload',\n description: 'Payload when a job is scheduled for retry',\n fields: {\n jobId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n attempt: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n nextAttemptAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n backoffMs: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n },\n});\n\nconst JobDeadLetteredPayload = defineSchemaModel({\n name: 'JobDeadLetteredEventPayload',\n description: 'Payload when a job is moved to dead letter queue',\n fields: {\n jobId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n attempts: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n lastError: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n deadLetteredAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n },\n});\n\nconst JobCancelledPayload = defineSchemaModel({\n name: 'JobCancelledEventPayload',\n description: 'Payload when a job is cancelled',\n fields: {\n jobId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n cancelledBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },\n cancelledAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n },\n});\n\nconst ScheduledJobTriggeredPayload = defineSchemaModel({\n name: 'ScheduledJobTriggeredEventPayload',\n description: 'Payload when a scheduled job is triggered',\n fields: {\n scheduleName: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n jobId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n jobType: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n triggeredAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n nextRunAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },\n },\n});\n\n// ============ Events ============\n\n/**\n * Emitted when a job is enqueued.\n */\nexport const JobEnqueuedEvent = defineEvent({\n meta: {\n key: 'job.enqueued',\n version: '1.0.0',\n description: 'A job has been added to the queue.',\n stability: StabilityEnum.Stable,\n owners: ['@contractspec.libs.jobs'],\n tags: ['job-queue', 'lifecycle'],\n },\n payload: JobEnqueuedPayload,\n});\n\n/**\n * Emitted when a job starts processing.\n */\nexport const JobStartedEvent = defineEvent({\n meta: {\n key: 'job.started',\n version: '1.0.0',\n description: 'A job has started processing.',\n stability: StabilityEnum.Stable,\n owners: ['@contractspec.libs.jobs'],\n tags: ['job-queue', 'lifecycle'],\n },\n payload: JobStartedPayload,\n});\n\n/**\n * Emitted when a job completes successfully.\n */\nexport const JobCompletedEvent = defineEvent({\n meta: {\n key: 'job.completed',\n version: '1.0.0',\n description: 'A job has completed successfully.',\n stability: StabilityEnum.Stable,\n owners: ['@contractspec.libs.jobs'],\n tags: ['job-queue', 'lifecycle'],\n },\n payload: JobCompletedPayload,\n});\n\n/**\n * Emitted when a job fails (single attempt).\n */\nexport const JobFailedEvent = defineEvent({\n meta: {\n key: 'job.failed',\n version: '1.0.0',\n description: 'A job attempt has failed.',\n stability: StabilityEnum.Stable,\n owners: ['@contractspec.libs.jobs'],\n tags: ['job-queue', 'lifecycle', 'error'],\n },\n payload: JobFailedPayload,\n});\n\n/**\n * Emitted when a job is being retried.\n */\nexport const JobRetryingEvent = defineEvent({\n meta: {\n key: 'job.retrying',\n version: '1.0.0',\n description: 'A job is being scheduled for retry.',\n stability: StabilityEnum.Stable,\n owners: ['@contractspec.libs.jobs'],\n tags: ['job-queue', 'lifecycle', 'retry'],\n },\n payload: JobRetryingPayload,\n});\n\n/**\n * Emitted when a job is moved to dead letter queue.\n */\nexport const JobDeadLetteredEvent = defineEvent({\n meta: {\n key: 'job.dead_lettered',\n version: '1.0.0',\n description:\n 'A job has exhausted all retries and moved to dead letter queue.',\n stability: StabilityEnum.Stable,\n owners: ['@contractspec.libs.jobs'],\n tags: ['job-queue', 'lifecycle', 'error'],\n },\n payload: JobDeadLetteredPayload,\n});\n\n/**\n * Emitted when a job is cancelled.\n */\nexport const JobCancelledEvent = defineEvent({\n meta: {\n key: 'job.cancelled',\n version: '1.0.0',\n description: 'A job has been cancelled.',\n stability: StabilityEnum.Stable,\n owners: ['@contractspec.libs.jobs'],\n tags: ['job-queue', 'lifecycle'],\n },\n payload: JobCancelledPayload,\n});\n\n/**\n * Emitted when a scheduled job is triggered.\n */\nexport const ScheduledJobTriggeredEvent = defineEvent({\n meta: {\n key: 'scheduler.job_triggered',\n version: '1.0.0',\n description: 'A scheduled job has been triggered.',\n stability: StabilityEnum.Stable,\n owners: ['@contractspec.libs.jobs'],\n tags: ['job-queue', 'scheduler'],\n },\n payload: ScheduledJobTriggeredPayload,\n});\n\n/**\n * All job events.\n */\nexport const JobEvents = {\n JobEnqueuedEvent,\n JobStartedEvent,\n JobCompletedEvent,\n JobFailedEvent,\n JobRetryingEvent,\n JobDeadLetteredEvent,\n JobCancelledEvent,\n ScheduledJobTriggeredEvent,\n};\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"gmail-sync-handler.js","names":[],"sources":["../../src/handlers/gmail-sync-handler.ts"],"sourcesContent":["import type { JobHandler } from '@contractspec/lib.contracts/jobs/queue';\nimport type { GmailIngestionAdapter } from '@contractspec/lib.knowledge/ingestion/gmail-adapter';\nimport type { EmailThreadListQuery } from '@contractspec/lib.contracts/integrations/providers/email';\n\nexport type GmailSyncJobPayload = EmailThreadListQuery;\n\nexport function createGmailSyncHandler(\n adapter: GmailIngestionAdapter\n): JobHandler<GmailSyncJobPayload> {\n return async (job) => {\n await adapter.syncThreads(job.payload);\n };\n}\n"],"mappings":";AAMA,SAAgB,uBACd,SACiC;AACjC,QAAO,OAAO,QAAQ;AACpB,QAAM,QAAQ,YAAY,IAAI,QAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/handlers/index.ts"],"sourcesContent":["export * from './ping-job';\nexport * from './gmail-sync-handler';\nexport * from './storage-document-handler';\nimport type { JobQueue } from '@contractspec/lib.contracts/jobs/queue';\nimport { registerDefinedJob } from '../queue/register-defined-job';\n\nimport { pingJob } from './ping-job';\n// import { equityaRecomputePlanJob } from './types/equitya.recompute-plan';\n// import { artisanosGenerateQuoteJob } from './types/artisanos.generate-quote';\n\nexport function registerAllJobs(queue: JobQueue): void {\n registerDefinedJob(queue, pingJob);\n // registerDefinedJob(queue, equityaRecomputePlanJob);\n // registerDefinedJob(queue, artisanosGenerateQuoteJob);\n}\n"],"mappings":";;;;;;AAUA,SAAgB,gBAAgB,OAAuB;AACrD,oBAAmB,OAAO,QAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ping-job.js","names":[],"sources":["../../src/handlers/ping-job.ts"],"sourcesContent":["import * as z from 'zod';\nimport type { DefinedJob } from '@contractspec/lib.contracts/jobs/define-job';\nimport type { Job } from '@contractspec/lib.contracts/jobs/queue';\n\nexport const PING_JOB_TYPE = 'core.ping' as const;\n\nexport const PingPayloadSchema = z.object({});\n\nexport type PingPayload = z.infer<typeof PingPayloadSchema>;\n\nexport const pingJob: DefinedJob<PingPayload> = {\n type: PING_JOB_TYPE,\n schema: PingPayloadSchema,\n handler: async (_payload: PingPayload, _job: Job<PingPayload>) => {\n /* noop - ping job has no operation */\n },\n};\n"],"mappings":";;;AAIA,MAAa,gBAAgB;AAE7B,MAAa,oBAAoB,EAAE,OAAO,EAAE,CAAC;AAI7C,MAAa,UAAmC;CAC9C,MAAM;CACN,QAAQ;CACR,SAAS,OAAO,UAAuB,SAA2B;CAGnE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage-document-handler.js","names":[],"sources":["../../src/handlers/storage-document-handler.ts"],"sourcesContent":["import type { ObjectStorageProvider } from '@contractspec/lib.contracts/integrations/providers/storage';\nimport type { StorageIngestionAdapter } from '@contractspec/lib.knowledge/ingestion/storage-adapter';\nimport type { JobHandler } from '@contractspec/lib.contracts/jobs/queue';\n\nexport interface StorageDocumentJobPayload {\n bucket: string;\n key: string;\n}\n\nexport function createStorageDocumentHandler(\n storage: ObjectStorageProvider,\n adapter: StorageIngestionAdapter\n): JobHandler<StorageDocumentJobPayload> {\n return async (job) => {\n const object = await storage.getObject({\n bucket: job.payload.bucket,\n key: job.payload.key,\n });\n if (!object) {\n throw new Error(\n `Object ${job.payload.bucket}/${job.payload.key} not found`\n );\n }\n await adapter.ingestObject(object);\n };\n}\n"],"mappings":";AASA,SAAgB,6BACd,SACA,SACuC;AACvC,QAAO,OAAO,QAAQ;EACpB,MAAM,SAAS,MAAM,QAAQ,UAAU;GACrC,QAAQ,IAAI,QAAQ;GACpB,KAAK,IAAI,QAAQ;GAClB,CAAC;AACF,MAAI,CAAC,OACH,OAAM,IAAI,MACR,UAAU,IAAI,QAAQ,OAAO,GAAG,IAAI,QAAQ,IAAI,YACjD;AAEH,QAAM,QAAQ,aAAa,OAAO"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["// Entity definitions for schema generation\nexport * from './entities';\n\n// Queue implementations\nexport * from './queue';\n\n// Job handlers (runtime wiring)\nexport * from './handlers';\n\n// Scheduler\nexport * from './scheduler';\n\n// Contract specifications\nexport * from './contracts';\n\n// Domain events\nexport * from './events';\n\n// Feature module specification\nexport * from './jobs.feature';\n"],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"jobs.capability.js","names":[],"sources":["../src/jobs.capability.ts"],"sourcesContent":["import { defineCapability, StabilityEnum } from '@contractspec/lib.contracts';\n\nexport const JobsCapability = defineCapability({\n meta: {\n key: 'jobs',\n version: '1.0.0',\n kind: 'api',\n stability: StabilityEnum.Experimental,\n description: 'Background job processing',\n owners: ['@platform.core'],\n tags: ['jobs', 'background', 'async'],\n },\n});\n\nexport const SchedulerCapability = defineCapability({\n meta: {\n key: 'scheduler',\n version: '1.0.0',\n kind: 'api',\n stability: StabilityEnum.Experimental,\n description: 'Scheduled job execution',\n owners: ['@platform.core'],\n tags: ['scheduler', 'cron', 'jobs'],\n },\n});\n"],"mappings":";;;AAEA,MAAa,iBAAiB,iBAAiB,EAC7C,MAAM;CACJ,KAAK;CACL,SAAS;CACT,MAAM;CACN,WAAW,cAAc;CACzB,aAAa;CACb,QAAQ,CAAC,iBAAiB;CAC1B,MAAM;EAAC;EAAQ;EAAc;EAAQ;CACtC,EACF,CAAC;AAEF,MAAa,sBAAsB,iBAAiB,EAClD,MAAM;CACJ,KAAK;CACL,SAAS;CACT,MAAM;CACN,WAAW,cAAc;CACzB,aAAa;CACb,QAAQ,CAAC,iBAAiB;CAC1B,MAAM;EAAC;EAAa;EAAQ;EAAO;CACpC,EACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"jobs.feature.js","names":[],"sources":["../src/jobs.feature.ts"],"sourcesContent":["/**\n * Jobs Feature Module Specification\n *\n * Defines the feature module for background job processing and scheduling.\n */\nimport { defineFeature } from '@contractspec/lib.contracts';\n\n/**\n * Jobs feature module that bundles background job processing,\n * queues, and scheduling capabilities.\n */\nexport const JobsFeature = defineFeature({\n meta: {\n key: 'jobs',\n title: 'Background Jobs',\n description: 'Background job processing, scheduling, and queue management',\n domain: 'platform',\n owners: ['@platform.jobs'],\n tags: ['jobs', 'queue', 'background', 'scheduler'],\n stability: 'stable',\n version: '1.0.0',\n },\n\n // All contract operations included in this feature\n operations: [\n // Job operations\n { key: 'jobs.enqueue', version: '1.0.0' },\n { key: 'jobs.cancel', version: '1.0.0' },\n { key: 'jobs.get', version: '1.0.0' },\n { key: 'jobs.stats', version: '1.0.0' },\n\n // Schedule operations\n { key: 'jobs.schedule.create', version: '1.0.0' },\n { key: 'jobs.schedule.toggle', version: '1.0.0' },\n { key: 'jobs.schedule.list', version: '1.0.0' },\n ],\n\n // Events emitted by this feature\n events: [\n // Job lifecycle events\n { key: 'job.enqueued', version: '1.0.0' },\n { key: 'job.started', version: '1.0.0' },\n { key: 'job.completed', version: '1.0.0' },\n { key: 'job.failed', version: '1.0.0' },\n { key: 'job.retrying', version: '1.0.0' },\n { key: 'job.dead_lettered', version: '1.0.0' },\n { key: 'job.cancelled', version: '1.0.0' },\n\n // Scheduler events\n { key: 'scheduler.job_triggered', version: '1.0.0' },\n ],\n\n // No presentations for this library feature\n presentations: [],\n opToPresentation: [],\n presentationsTargets: [],\n\n // Capability definitions\n capabilities: {\n provides: [\n { key: 'jobs', version: '1.0.0' },\n { key: 'scheduler', version: '1.0.0' },\n ],\n requires: [],\n },\n});\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,cAAc,cAAc;CACvC,MAAM;EACJ,KAAK;EACL,OAAO;EACP,aAAa;EACb,QAAQ;EACR,QAAQ,CAAC,iBAAiB;EAC1B,MAAM;GAAC;GAAQ;GAAS;GAAc;GAAY;EAClD,WAAW;EACX,SAAS;EACV;CAGD,YAAY;EAEV;GAAE,KAAK;GAAgB,SAAS;GAAS;EACzC;GAAE,KAAK;GAAe,SAAS;GAAS;EACxC;GAAE,KAAK;GAAY,SAAS;GAAS;EACrC;GAAE,KAAK;GAAc,SAAS;GAAS;EAGvC;GAAE,KAAK;GAAwB,SAAS;GAAS;EACjD;GAAE,KAAK;GAAwB,SAAS;GAAS;EACjD;GAAE,KAAK;GAAsB,SAAS;GAAS;EAChD;CAGD,QAAQ;EAEN;GAAE,KAAK;GAAgB,SAAS;GAAS;EACzC;GAAE,KAAK;GAAe,SAAS;GAAS;EACxC;GAAE,KAAK;GAAiB,SAAS;GAAS;EAC1C;GAAE,KAAK;GAAc,SAAS;GAAS;EACvC;GAAE,KAAK;GAAgB,SAAS;GAAS;EACzC;GAAE,KAAK;GAAqB,SAAS;GAAS;EAC9C;GAAE,KAAK;GAAiB,SAAS;GAAS;EAG1C;GAAE,KAAK;GAA2B,SAAS;GAAS;EACrD;CAGD,eAAe,EAAE;CACjB,kBAAkB,EAAE;CACpB,sBAAsB,EAAE;CAGxB,cAAc;EACZ,UAAU,CACR;GAAE,KAAK;GAAQ,SAAS;GAAS,EACjC;GAAE,KAAK;GAAa,SAAS;GAAS,CACvC;EACD,UAAU,EAAE;EACb;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"gcp-cloud-tasks.js","names":["DEFAULT_RETRY_POLICY"],"sources":["../../src/queue/gcp-cloud-tasks.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport {\n DEFAULT_RETRY_POLICY,\n type EnqueueOptions,\n type Job,\n type JobHandler,\n type JobQueue,\n} from './types';\n\ninterface CloudTasksClientLike {\n createTask(request: {\n parent: string;\n task: {\n httpRequest: {\n httpMethod: number | string;\n url: string;\n body: Buffer;\n headers?: Record<string, string>;\n oidcToken?: { serviceAccountEmail: string };\n };\n scheduleTime?: { seconds: number };\n };\n }): Promise<unknown>;\n}\n\nexport interface GcpCloudTasksQueueOptions {\n client: CloudTasksClientLike;\n projectId: string;\n location: string;\n queue: string;\n resolveUrl(jobType: string): string;\n serviceAccountEmail?: string;\n}\n\nexport class GcpCloudTasksQueue implements JobQueue {\n private readonly handlers = new Map<string, JobHandler>();\n\n constructor(private readonly options: GcpCloudTasksQueueOptions) {}\n\n async enqueue<TPayload>(\n jobType: string,\n payload: TPayload,\n options: EnqueueOptions = {}\n ): Promise<Job<TPayload>> {\n const now = new Date();\n const enqueueTime =\n options.delaySeconds != null\n ? { seconds: Math.floor(Date.now() / 1000) + options.delaySeconds }\n : undefined;\n const body = Buffer.from(\n JSON.stringify({\n id: randomUUID(),\n type: jobType,\n payload,\n }),\n 'utf-8'\n );\n await this.options.client.createTask({\n parent: `projects/${this.options.projectId}/locations/${this.options.location}/queues/${this.options.queue}`,\n task: {\n httpRequest: {\n httpMethod: 'POST',\n url: this.options.resolveUrl(jobType),\n body,\n headers: { 'Content-Type': 'application/json' },\n oidcToken: this.options.serviceAccountEmail\n ? { serviceAccountEmail: this.options.serviceAccountEmail }\n : undefined,\n },\n scheduleTime: enqueueTime,\n },\n });\n\n return {\n id: randomUUID(),\n type: jobType,\n version: '1.0.0',\n payload,\n status: 'pending',\n priority: options.priority ?? 0,\n attempts: 0,\n maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY.maxRetries,\n createdAt: now,\n updatedAt: now,\n scheduledAt: options.delaySeconds\n ? new Date(now.getTime() + options.delaySeconds * 1000)\n : now,\n dedupeKey: options.dedupeKey,\n tenantId: options.tenantId,\n userId: options.userId,\n traceId: options.traceId,\n metadata: options.metadata,\n };\n }\n\n register<TPayload, TResult = void>(\n jobType: string,\n handler: JobHandler<TPayload, TResult>\n ): void {\n this.handlers.set(jobType, handler as JobHandler);\n }\n\n start(): void {\n // Execution is handled by Cloud Tasks via HTTP callbacks.\n }\n\n async stop(): Promise<void> {\n this.handlers.clear();\n }\n}\n"],"mappings":";;;;AAmCA,IAAa,qBAAb,MAAoD;CAClD,AAAiB,2BAAW,IAAI,KAAyB;CAEzD,YAAY,AAAiB,SAAoC;EAApC;;CAE7B,MAAM,QACJ,SACA,SACA,UAA0B,EAAE,EACJ;EACxB,MAAM,sBAAM,IAAI,MAAM;EACtB,MAAM,cACJ,QAAQ,gBAAgB,OACpB,EAAE,SAAS,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,GAAG,QAAQ,cAAc,GACjE;EACN,MAAM,OAAO,OAAO,KAClB,KAAK,UAAU;GACb,IAAI,YAAY;GAChB,MAAM;GACN;GACD,CAAC,EACF,QACD;AACD,QAAM,KAAK,QAAQ,OAAO,WAAW;GACnC,QAAQ,YAAY,KAAK,QAAQ,UAAU,aAAa,KAAK,QAAQ,SAAS,UAAU,KAAK,QAAQ;GACrG,MAAM;IACJ,aAAa;KACX,YAAY;KACZ,KAAK,KAAK,QAAQ,WAAW,QAAQ;KACrC;KACA,SAAS,EAAE,gBAAgB,oBAAoB;KAC/C,WAAW,KAAK,QAAQ,sBACpB,EAAE,qBAAqB,KAAK,QAAQ,qBAAqB,GACzD;KACL;IACD,cAAc;IACf;GACF,CAAC;AAEF,SAAO;GACL,IAAI,YAAY;GAChB,MAAM;GACN,SAAS;GACT;GACA,QAAQ;GACR,UAAU,QAAQ,YAAY;GAC9B,UAAU;GACV,YAAY,QAAQ,cAAcA,mCAAqB;GACvD,WAAW;GACX,WAAW;GACX,aAAa,QAAQ,eACjB,IAAI,KAAK,IAAI,SAAS,GAAG,QAAQ,eAAe,IAAK,GACrD;GACJ,WAAW,QAAQ;GACnB,UAAU,QAAQ;GAClB,QAAQ,QAAQ;GAChB,SAAS,QAAQ;GACjB,UAAU,QAAQ;GACnB;;CAGH,SACE,SACA,SACM;AACN,OAAK,SAAS,IAAI,SAAS,QAAsB;;CAGnD,QAAc;CAId,MAAM,OAAsB;AAC1B,OAAK,SAAS,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"gcp-pubsub.js","names":["DEFAULT_RETRY_POLICY"],"sources":["../../src/queue/gcp-pubsub.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport {\n DEFAULT_RETRY_POLICY,\n type EnqueueOptions,\n type Job,\n type JobHandler,\n type JobQueue,\n} from './types';\n\ninterface PubSubClientLike {\n topic(name: string): {\n publishMessage(message: { data: Buffer }): Promise<string>;\n };\n}\n\nexport interface GcpPubSubQueueOptions {\n client: PubSubClientLike;\n topicName: string;\n}\n\nexport class GcpPubSubQueue implements JobQueue {\n private readonly handlers = new Map<string, JobHandler>();\n\n constructor(private readonly options: GcpPubSubQueueOptions) {}\n\n async enqueue<TPayload>(\n jobType: string,\n payload: TPayload,\n options: EnqueueOptions = {}\n ): Promise<Job<TPayload>> {\n const now = new Date();\n await this.options.client.topic(this.options.topicName).publishMessage({\n data: Buffer.from(\n JSON.stringify({\n id: randomUUID(),\n type: jobType,\n payload,\n }),\n 'utf-8'\n ),\n });\n\n return {\n id: randomUUID(),\n type: jobType,\n version: '1.0.0',\n payload,\n status: 'pending',\n priority: options.priority ?? 0,\n attempts: 0,\n maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY.maxRetries,\n createdAt: now,\n updatedAt: now,\n scheduledAt: options.delaySeconds\n ? new Date(now.getTime() + options.delaySeconds * 1000)\n : now,\n dedupeKey: options.dedupeKey,\n tenantId: options.tenantId,\n userId: options.userId,\n traceId: options.traceId,\n metadata: options.metadata,\n };\n }\n\n register<TPayload, TResult = void>(\n jobType: string,\n handler: JobHandler<TPayload, TResult>\n ): void {\n this.handlers.set(jobType, handler as JobHandler);\n }\n\n start(): void {\n // Message consumption handled externally via Pub/Sub subscription.\n }\n\n async stop(): Promise<void> {\n this.handlers.clear();\n }\n}\n"],"mappings":";;;;AAqBA,IAAa,iBAAb,MAAgD;CAC9C,AAAiB,2BAAW,IAAI,KAAyB;CAEzD,YAAY,AAAiB,SAAgC;EAAhC;;CAE7B,MAAM,QACJ,SACA,SACA,UAA0B,EAAE,EACJ;EACxB,MAAM,sBAAM,IAAI,MAAM;AACtB,QAAM,KAAK,QAAQ,OAAO,MAAM,KAAK,QAAQ,UAAU,CAAC,eAAe,EACrE,MAAM,OAAO,KACX,KAAK,UAAU;GACb,IAAI,YAAY;GAChB,MAAM;GACN;GACD,CAAC,EACF,QACD,EACF,CAAC;AAEF,SAAO;GACL,IAAI,YAAY;GAChB,MAAM;GACN,SAAS;GACT;GACA,QAAQ;GACR,UAAU,QAAQ,YAAY;GAC9B,UAAU;GACV,YAAY,QAAQ,cAAcA,mCAAqB;GACvD,WAAW;GACX,WAAW;GACX,aAAa,QAAQ,eACjB,IAAI,KAAK,IAAI,SAAS,GAAG,QAAQ,eAAe,IAAK,GACrD;GACJ,WAAW,QAAQ;GACnB,UAAU,QAAQ;GAClB,QAAQ,QAAQ;GAChB,SAAS,QAAQ;GACjB,UAAU,QAAQ;GACnB;;CAGH,SACE,SACA,SACM;AACN,OAAK,SAAS,IAAI,SAAS,QAAsB;;CAGnD,QAAc;CAId,MAAM,OAAsB;AAC1B,OAAK,SAAS,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/queue/index.ts"],"sourcesContent":["export * from './types';\nexport * from './memory-queue';\nexport * from './scaleway-sqs-queue';\nexport * from './gcp-cloud-tasks';\nexport * from './gcp-pubsub';\nexport * from './register-defined-job';\n"],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-queue.js","names":["DEFAULT_RETRY_POLICY"],"sources":["../../src/queue/memory-queue.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport type {\n Job,\n JobHandler,\n JobQueue,\n EnqueueOptions,\n QueueStats,\n RetryPolicy,\n} from './types';\nimport { calculateBackoff, DEFAULT_RETRY_POLICY } from './types';\n\nexport interface MemoryQueueOptions {\n /** Poll interval in milliseconds */\n pollIntervalMs?: number;\n /** Maximum concurrent jobs */\n concurrency?: number;\n /** Default retry policy */\n retryPolicy?: RetryPolicy;\n}\n\n/**\n * In-memory job queue for development and testing.\n */\nexport class MemoryJobQueue implements JobQueue {\n private readonly jobs = new Map<string, Job>();\n private readonly handlers = new Map<string, JobHandler>();\n private timer?: ReturnType<typeof setInterval>;\n private activeCount = 0;\n private readonly pollIntervalMs: number;\n private readonly concurrency: number;\n private readonly retryPolicy: RetryPolicy;\n\n constructor(options: MemoryQueueOptions = {}) {\n this.pollIntervalMs = options.pollIntervalMs ?? 200;\n this.concurrency = options.concurrency ?? 5;\n this.retryPolicy = options.retryPolicy ?? DEFAULT_RETRY_POLICY;\n }\n\n async enqueue<TPayload>(\n jobType: string,\n payload: TPayload,\n options: EnqueueOptions = {}\n ): Promise<Job<TPayload>> {\n // Check for duplicate\n if (options.dedupeKey) {\n const existing = Array.from(this.jobs.values()).find(\n (j) => j.dedupeKey === options.dedupeKey && j.status === 'pending'\n );\n if (existing) {\n return existing as Job<TPayload>;\n }\n }\n\n const now = new Date();\n const scheduledAt = options.delaySeconds\n ? new Date(now.getTime() + options.delaySeconds * 1000)\n : now;\n\n const job: Job<TPayload> = {\n id: randomUUID(),\n type: jobType,\n version: '1.0.0',\n payload,\n status: 'pending',\n priority: options.priority ?? 0,\n attempts: 0,\n maxRetries: options.maxRetries ?? this.retryPolicy.maxRetries,\n createdAt: now,\n updatedAt: now,\n scheduledAt,\n dedupeKey: options.dedupeKey,\n tenantId: options.tenantId,\n userId: options.userId,\n traceId: options.traceId,\n metadata: options.metadata,\n };\n\n if (options.timeoutMs) {\n job.timeoutAt = new Date(now.getTime() + options.timeoutMs);\n }\n\n this.jobs.set(job.id, job);\n return job;\n }\n\n register<TPayload, TResult = void>(\n jobType: string,\n handler: JobHandler<TPayload, TResult>\n ): void {\n this.handlers.set(jobType, handler as JobHandler);\n }\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => {\n void this.processNext();\n }, this.pollIntervalMs);\n }\n\n async stop(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = undefined;\n }\n // Wait for active jobs to complete\n while (this.activeCount > 0) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n }\n\n async getJob(jobId: string): Promise<Job | null> {\n return this.jobs.get(jobId) ?? null;\n }\n\n async cancelJob(jobId: string): Promise<boolean> {\n const job = this.jobs.get(jobId);\n if (!job || job.status !== 'pending') {\n return false;\n }\n job.status = 'cancelled';\n job.updatedAt = new Date();\n return true;\n }\n\n async getStats(): Promise<QueueStats> {\n const stats: QueueStats = {\n pending: 0,\n running: 0,\n completed: 0,\n failed: 0,\n deadLetter: 0,\n };\n\n for (const job of this.jobs.values()) {\n switch (job.status) {\n case 'pending':\n stats.pending++;\n break;\n case 'running':\n stats.running++;\n break;\n case 'completed':\n stats.completed++;\n break;\n case 'failed':\n stats.failed++;\n break;\n case 'dead_letter':\n stats.deadLetter++;\n break;\n }\n }\n\n return stats;\n }\n\n private async processNext(): Promise<void> {\n if (this.activeCount >= this.concurrency) return;\n\n const now = new Date();\n const pendingJobs = Array.from(this.jobs.values())\n .filter(\n (j) =>\n j.status === 'pending' && (!j.scheduledAt || j.scheduledAt <= now)\n )\n .sort((a, b) => {\n // Higher priority first\n if (a.priority !== b.priority) {\n return b.priority - a.priority;\n }\n // Earlier scheduled first\n return (\n (a.scheduledAt?.getTime() ?? 0) - (b.scheduledAt?.getTime() ?? 0)\n );\n });\n\n const job = pendingJobs[0];\n if (!job) return;\n\n const handler = this.handlers.get(job.type);\n if (!handler) return;\n\n this.activeCount++;\n job.status = 'running';\n job.startedAt = new Date();\n job.updatedAt = new Date();\n job.attempts += 1;\n\n try {\n const result = await handler(job);\n job.status = 'completed';\n job.completedAt = new Date();\n job.result = result;\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n job.lastError = errorMessage;\n\n if (job.attempts >= job.maxRetries) {\n job.status = 'dead_letter';\n } else {\n // Schedule retry with backoff\n const backoff = calculateBackoff(job.attempts, this.retryPolicy);\n job.status = 'pending';\n job.scheduledAt = new Date(Date.now() + backoff);\n }\n } finally {\n job.updatedAt = new Date();\n this.activeCount--;\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"register-defined-job.js","names":[],"sources":["../../src/queue/register-defined-job.ts"],"sourcesContent":["import type { DefinedJob } from '@contractspec/lib.contracts/jobs/define-job';\nimport type {\n Job,\n JobHandler,\n JobQueue,\n} from '@contractspec/lib.contracts/jobs/queue';\n\nexport function registerDefinedJob<TPayload>(\n queue: JobQueue,\n def: DefinedJob<TPayload>\n): void {\n const wrapped: JobHandler<unknown> = async (job) => {\n const payload = def.schema.parse(job.payload);\n const typedJob: Job<TPayload> = {\n ...(job as Job<unknown>),\n payload,\n } as Job<TPayload>;\n\n await def.handler(payload, typedJob);\n };\n\n queue.register<TPayload>(def.type, wrapped as JobHandler<TPayload>);\n}\n"],"mappings":";AAOA,SAAgB,mBACd,OACA,KACM;CACN,MAAM,UAA+B,OAAO,QAAQ;EAClD,MAAM,UAAU,IAAI,OAAO,MAAM,IAAI,QAAQ;EAC7C,MAAM,WAA0B;GAC9B,GAAI;GACJ;GACD;AAED,QAAM,IAAI,QAAQ,SAAS,SAAS;;AAGtC,OAAM,SAAmB,IAAI,MAAM,QAAgC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"scaleway-sqs-queue.js","names":["DEFAULT_RETRY_POLICY"],"sources":["../../src/queue/scaleway-sqs-queue.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport {\n DeleteMessageCommand,\n ReceiveMessageCommand,\n SendMessageCommand,\n SQSClient,\n} from '@aws-sdk/client-sqs';\nimport type { Logger } from '@contractspec/lib.logger';\nimport { DEFAULT_RETRY_POLICY } from './types';\nimport type { EnqueueOptions, Job, JobHandler, JobQueue } from './types';\n\nexport interface ScalewaySqsQueueCredentials {\n accessKeyId: string;\n secretAccessKey: string;\n}\n\nexport interface ScalewaySqsQueueConfig {\n queueUrl: string;\n region?: string;\n endpoint?: string;\n waitTimeSeconds?: number;\n maxNumberOfMessages?: number;\n visibilityTimeoutSeconds?: number;\n credentials?: ScalewaySqsQueueCredentials;\n logger?: Logger;\n}\n\ninterface RawJobEnvelope<TPayload = unknown> {\n id: string;\n type: string;\n payload: TPayload;\n}\n\nexport class ScalewaySqsJobQueue implements JobQueue {\n private readonly sqs: SQSClient;\n private readonly queueUrl: string;\n private readonly waitTimeSeconds: number;\n private readonly maxNumberOfMessages: number;\n private readonly visibilityTimeoutSeconds: number;\n private readonly handlers = new Map<string, JobHandler>();\n private readonly logger?: Logger;\n private running = false;\n\n constructor(config: ScalewaySqsQueueConfig) {\n this.logger = config.logger;\n\n const accessKeyId =\n config.credentials?.accessKeyId ?? process.env.SCALEWAY_ACCESS_KEY_QUEUE;\n const secretAccessKey =\n config.credentials?.secretAccessKey ??\n process.env.SCALEWAY_SECRET_KEY_QUEUE;\n\n if (!accessKeyId || !secretAccessKey) {\n throw new Error(\n 'Missing SCALEWAY_ACCESS_KEY_QUEUE / SCALEWAY_SECRET_KEY_QUEUE in env'\n );\n }\n\n const region = config.region ?? process.env.SCALEWAY_REGION ?? 'par';\n const endpoint = config.endpoint ?? 'https://sqs.mnq.fr-par.scaleway.com';\n\n this.sqs = new SQSClient({\n region,\n endpoint,\n credentials: {\n accessKeyId,\n secretAccessKey,\n },\n });\n\n this.queueUrl = config.queueUrl;\n this.waitTimeSeconds = config.waitTimeSeconds ?? 20;\n this.maxNumberOfMessages = config.maxNumberOfMessages ?? 5;\n this.visibilityTimeoutSeconds = config.visibilityTimeoutSeconds ?? 60;\n }\n\n async enqueue<TPayload>(\n jobType: string,\n payload: TPayload,\n options: EnqueueOptions = {}\n ): Promise<Job<TPayload>> {\n const id = randomUUID();\n const now = new Date();\n const scheduledAt = options.delaySeconds\n ? new Date(now.getTime() + options.delaySeconds * 1000)\n : now;\n\n const envelope: RawJobEnvelope<TPayload> = {\n id,\n type: jobType,\n payload,\n };\n\n await this.sqs.send(\n new SendMessageCommand({\n QueueUrl: this.queueUrl,\n MessageBody: JSON.stringify(envelope),\n DelaySeconds: options.delaySeconds ?? 0,\n // If you use FIFO queues later, you'd set MessageGroupId / MessageDeduplicationId here.\n })\n );\n\n return {\n id,\n type: jobType,\n version: '1.0.0',\n payload,\n status: 'pending',\n priority: options.priority ?? 0,\n attempts: 0,\n maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY.maxRetries,\n createdAt: now,\n updatedAt: now,\n scheduledAt,\n dedupeKey: options.dedupeKey,\n tenantId: options.tenantId,\n userId: options.userId,\n traceId: options.traceId,\n metadata: options.metadata,\n };\n }\n\n register<TPayload, TResult = void>(\n jobType: string,\n handler: JobHandler<TPayload, TResult>\n ): void {\n if (this.handlers.has(jobType)) {\n throw new Error(`Handler already registered for job type \"${jobType}\"`);\n }\n this.handlers.set(jobType, handler as JobHandler);\n }\n\n start(): void {\n if (this.running) return;\n this.running = true;\n void this.pollLoop().catch((error) => {\n this.logger?.error?.('jobs.queue.scaleway_sqs.poll_loop_fatal', {\n error: error instanceof Error ? error.message : String(error),\n });\n this.running = false;\n });\n }\n\n async stop(): Promise<void> {\n this.running = false;\n // Worst-case we wait for the current ReceiveMessage to finish (<= waitTimeSeconds)\n }\n\n private async pollLoop(): Promise<void> {\n this.logger?.info?.('jobs.queue.scaleway_sqs.started', {\n queueUrl: this.queueUrl,\n });\n\n while (this.running) {\n try {\n const res = await this.sqs.send(\n new ReceiveMessageCommand({\n QueueUrl: this.queueUrl,\n MaxNumberOfMessages: this.maxNumberOfMessages,\n WaitTimeSeconds: this.waitTimeSeconds,\n VisibilityTimeout: this.visibilityTimeoutSeconds,\n MessageSystemAttributeNames: ['ApproximateReceiveCount'],\n })\n );\n\n const messages = res.Messages ?? [];\n\n if (messages.length === 0) {\n continue;\n }\n\n for (const msg of messages) {\n if (!msg.Body || !msg.ReceiptHandle) {\n this.logger?.warn?.('jobs.queue.scaleway_sqs.invalid_message', {\n messageId: msg.MessageId,\n reason: 'missing_body_or_receipt',\n });\n continue;\n }\n\n let envelope: RawJobEnvelope;\n\n try {\n envelope = JSON.parse(msg.Body) as RawJobEnvelope;\n } catch (err) {\n this.logger?.warn?.('jobs.queue.scaleway_sqs.parse_failed', {\n messageId: msg.MessageId,\n error: err instanceof Error ? err.message : String(err),\n });\n await this.deleteMessage(msg.ReceiptHandle);\n continue;\n }\n\n const handler = this.handlers.get(envelope.type);\n if (!handler) {\n this.logger?.warn?.('jobs.queue.scaleway_sqs.missing_handler', {\n jobType: envelope.type,\n messageId: msg.MessageId,\n });\n await this.deleteMessage(msg.ReceiptHandle);\n continue;\n }\n\n const now = new Date();\n const attempts = parseInt(\n (msg.Attributes?.ApproximateReceiveCount as string | undefined) ??\n '1',\n 10\n );\n\n const job: Job = {\n id: envelope.id,\n type: envelope.type,\n version: '1.0.0',\n payload: envelope.payload,\n status: 'pending',\n priority: 0,\n attempts,\n maxRetries: DEFAULT_RETRY_POLICY.maxRetries,\n createdAt: now,\n updatedAt: now,\n };\n\n job.status = 'running';\n job.updatedAt = new Date();\n\n try {\n await handler(job);\n job.status = 'completed';\n job.updatedAt = new Date();\n await this.deleteMessage(msg.ReceiptHandle);\n } catch (err) {\n job.status = 'failed';\n job.lastError =\n err instanceof Error ? err.message : 'Unknown job error';\n job.updatedAt = new Date();\n\n this.logger?.error?.('jobs.queue.scaleway_sqs.job_failed', {\n jobType: job.type,\n jobId: job.id,\n error: err instanceof Error ? err.message : String(err),\n });\n // Do NOT delete message on failure:\n // - SQS/Scaleway will redeliver until MaxReceiveCount, then DLQ takes over.\n }\n }\n } catch (err) {\n this.logger?.error?.('jobs.queue.scaleway_sqs.poll_error', {\n error: err instanceof Error ? err.message : String(err),\n });\n await this.sleep(5000);\n }\n }\n\n this.logger?.info?.('jobs.queue.scaleway_sqs.stopped', {\n queueUrl: this.queueUrl,\n });\n }\n\n private async deleteMessage(receiptHandle: string): Promise<void> {\n try {\n await this.sqs.send(\n new DeleteMessageCommand({\n QueueUrl: this.queueUrl,\n ReceiptHandle: receiptHandle,\n })\n );\n } catch (err) {\n this.logger?.warn?.('jobs.queue.scaleway_sqs.delete_failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n private async sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../src/queue/types.ts"],"sourcesContent":["export * from '@contractspec/lib.contracts/jobs/queue';\n"],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/scheduler/index.ts"],"sourcesContent":["import type { JobQueue, EnqueueOptions } from '../queue/types';\n\n/**\n * Scheduled job configuration.\n */\nexport interface ScheduledJobConfig {\n /** Unique name for the schedule */\n name: string;\n /** Cron expression (e.g., '0 0 * * *' for daily at midnight) */\n cronExpression: string;\n /** Job type to enqueue */\n jobType: string;\n /** Job payload (can be a function for dynamic payloads) */\n payload?: unknown | (() => unknown | Promise<unknown>);\n /** Enqueue options */\n options?: EnqueueOptions;\n /** Timezone for cron evaluation (default: UTC) */\n timezone?: string;\n /** Whether the schedule is enabled */\n enabled?: boolean;\n /** Description */\n description?: string;\n}\n\n/**\n * Active scheduled job with next run time.\n */\nexport interface ActiveSchedule extends ScheduledJobConfig {\n nextRun: Date | null;\n lastRun: Date | null;\n}\n\n/**\n * Parse a cron expression to get the next run time.\n * Simple implementation supporting: minute hour day month weekday\n */\nfunction getNextCronRun(\n cronExpression: string,\n after: Date = new Date()\n): Date | null {\n try {\n // Dynamically import cron-parser\n // This is a simplified fallback if cron-parser isn't available\n const parts = cronExpression.trim().split(/\\s+/);\n if (parts.length !== 5) {\n console.warn(`Invalid cron expression: ${cronExpression}`);\n return null;\n }\n\n // Simple parsing for common patterns\n const minute = parts[0];\n const hour = parts[1];\n const dayOfMonth = parts[2];\n const month = parts[3];\n const next = new Date(after);\n next.setSeconds(0);\n next.setMilliseconds(0);\n\n // Handle simple cases\n if (\n minute &&\n hour &&\n minute !== '*' &&\n hour !== '*' &&\n dayOfMonth === '*' &&\n month === '*'\n ) {\n // Daily at specific time\n const targetMinute = Number.parseInt(minute, 10);\n const targetHour = Number.parseInt(hour, 10);\n\n next.setHours(targetHour, targetMinute, 0, 0);\n if (next <= after) {\n next.setDate(next.getDate() + 1);\n }\n return next;\n }\n\n // For other patterns, add 1 minute as fallback\n next.setMinutes(next.getMinutes() + 1);\n return next;\n } catch {\n return null;\n }\n}\n\n/**\n * Job scheduler for recurring jobs.\n */\nexport class JobScheduler {\n private readonly schedules = new Map<string, ActiveSchedule>();\n private timer?: ReturnType<typeof setInterval>;\n private readonly checkIntervalMs: number;\n\n constructor(\n private readonly queue: JobQueue,\n options: { checkIntervalMs?: number } = {}\n ) {\n this.checkIntervalMs = options.checkIntervalMs ?? 60000; // 1 minute default\n }\n\n /**\n * Add a scheduled job.\n */\n schedule(config: ScheduledJobConfig): void {\n const nextRun =\n config.enabled !== false ? getNextCronRun(config.cronExpression) : null;\n\n this.schedules.set(config.name, {\n ...config,\n enabled: config.enabled ?? true,\n nextRun,\n lastRun: null,\n });\n }\n\n /**\n * Remove a scheduled job.\n */\n unschedule(name: string): boolean {\n return this.schedules.delete(name);\n }\n\n /**\n * Enable a scheduled job.\n */\n enable(name: string): boolean {\n const schedule = this.schedules.get(name);\n if (!schedule) return false;\n\n schedule.enabled = true;\n schedule.nextRun = getNextCronRun(schedule.cronExpression);\n return true;\n }\n\n /**\n * Disable a scheduled job.\n */\n disable(name: string): boolean {\n const schedule = this.schedules.get(name);\n if (!schedule) return false;\n\n schedule.enabled = false;\n schedule.nextRun = null;\n return true;\n }\n\n /**\n * Get all schedules.\n */\n getSchedules(): ActiveSchedule[] {\n return Array.from(this.schedules.values());\n }\n\n /**\n * Get a specific schedule.\n */\n getSchedule(name: string): ActiveSchedule | undefined {\n return this.schedules.get(name);\n }\n\n /**\n * Start the scheduler.\n */\n start(): void {\n if (this.timer) return;\n\n // Initial check\n void this.checkSchedules();\n\n // Periodic check\n this.timer = setInterval(() => {\n void this.checkSchedules();\n }, this.checkIntervalMs);\n }\n\n /**\n * Stop the scheduler.\n */\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = undefined;\n }\n }\n\n /**\n * Check and enqueue due schedules.\n */\n private async checkSchedules(): Promise<void> {\n const now = new Date();\n\n for (const schedule of this.schedules.values()) {\n if (!schedule.enabled || !schedule.nextRun) continue;\n\n if (schedule.nextRun <= now) {\n try {\n // Resolve payload if it's a function\n const payload =\n typeof schedule.payload === 'function'\n ? await schedule.payload()\n : schedule.payload;\n\n // Enqueue the job\n await this.queue.enqueue(schedule.jobType, payload, schedule.options);\n\n // Update schedule\n schedule.lastRun = now;\n schedule.nextRun = getNextCronRun(schedule.cronExpression, now);\n } catch (error) {\n console.error(\n `Failed to enqueue scheduled job ${schedule.name}:`,\n error\n );\n }\n }\n }\n }\n}\n\n/**\n * Create a job scheduler instance.\n */\nexport function createScheduler(\n queue: JobQueue,\n options?: { checkIntervalMs?: number }\n): JobScheduler {\n return new JobScheduler(queue, options);\n}\n\n/**\n * Helper to define a scheduled job configuration.\n */\nexport function defineSchedule(config: ScheduledJobConfig): ScheduledJobConfig {\n return config;\n}\n"],"mappings":"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"}