@lunora/scheduler 1.0.0-alpha.13 → 1.0.0-alpha.15
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/README.md +1 -0
- package/dist/index.d.mts +59 -3
- package/dist/index.d.ts +59 -3
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/CRON_SCHEDULE_KINDS-DgupPI9t.mjs +1 -0
- package/dist/packem_shared/createScheduler-CsRAEtdb.mjs +1 -0
- package/dist/packem_shared/createSchedulerHost-C5XacwXv.mjs +1 -0
- package/package.json +2 -1
- package/dist/packem_shared/CRON_SCHEDULE_KINDS-CZFw97XW.mjs +0 -1
- package/dist/packem_shared/createScheduler-B2YOy_ph.mjs +0 -1
package/README.md
CHANGED
|
@@ -98,6 +98,7 @@ import { internal } from "@/lunora/_generated/api";
|
|
|
98
98
|
const crons = cronJobs();
|
|
99
99
|
|
|
100
100
|
crons.interval("clear presence", { minutes: 30 }, internal.presence.clear, {});
|
|
101
|
+
crons.hourly("sweep sessions", { minuteUTC: 17 }, internal.presence.sweep, {});
|
|
101
102
|
crons.daily("send digest", { hourUTC: 9, minuteUTC: 0 }, internal.email.digest, {});
|
|
102
103
|
|
|
103
104
|
export default crons;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SchedulerHost } from '@lunora/platform';
|
|
1
2
|
/**
|
|
2
3
|
* Opaque reference to a Lunora function. Mirrors the `FunctionReference` shape
|
|
3
4
|
* emitted by `@lunora/codegen` (and consumed by `@lunora/client`). We avoid a
|
|
@@ -140,6 +141,19 @@ interface Scheduler {
|
|
|
140
141
|
cancel: (id: string) => Promise<{
|
|
141
142
|
cancelled: boolean;
|
|
142
143
|
}>;
|
|
144
|
+
/**
|
|
145
|
+
* Jobs that exhausted their retry budget and were parked under `dead:`
|
|
146
|
+
* (the DO's `/dead` view). Deliberately absent from {@link Scheduler.list} —
|
|
147
|
+
* the park deletes the `id:` header — so this is the only view of a job
|
|
148
|
+
* that failed permanently rather than being silently dropped.
|
|
149
|
+
*/
|
|
150
|
+
dead: () => Promise<ScheduleRecord[]>;
|
|
151
|
+
/**
|
|
152
|
+
* Resurrect a parked job with a fresh attempt budget (the DO's
|
|
153
|
+
* `POST /dead/retry`). `false` when the id is not parked; a racing double
|
|
154
|
+
* recover is a no-op rather than an error.
|
|
155
|
+
*/
|
|
156
|
+
deadRetry: (id: string) => Promise<boolean>;
|
|
143
157
|
/** Resolve a single pending job by id, or `null` when absent (derived from {@link Scheduler.list}). */
|
|
144
158
|
get: (id: string) => Promise<ScheduleRecord | null>;
|
|
145
159
|
/** All pending scheduled jobs (the DO's `/list` view). */
|
|
@@ -426,6 +440,19 @@ interface DailySchedule {
|
|
|
426
440
|
/** 0–59. */
|
|
427
441
|
minuteUTC: number;
|
|
428
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* Hourly recurrence at a fixed minute past the hour.
|
|
445
|
+
*
|
|
446
|
+
* `crons.interval({ hours: 1 })` compiles to the same expression, but the
|
|
447
|
+
* asymmetry of having `daily`/`weekly`/`monthly` and no `hourly` is its own
|
|
448
|
+
* papercut — and unlike the interval form this one lets
|
|
449
|
+
* the caller place the job off the hour boundary, which is how you stop a
|
|
450
|
+
* dozen hourly jobs from stampeding at `:00`.
|
|
451
|
+
*/
|
|
452
|
+
interface HourlySchedule {
|
|
453
|
+
/** 0–59. */
|
|
454
|
+
minuteUTC: number;
|
|
455
|
+
}
|
|
429
456
|
/** Weekly recurrence at a fixed UTC time on a given weekday. */
|
|
430
457
|
interface WeeklySchedule extends DailySchedule {
|
|
431
458
|
/** Long weekday name, case-insensitive (e.g. `"monday"`). */
|
|
@@ -463,7 +490,7 @@ interface CronJob {
|
|
|
463
490
|
workflow?: string;
|
|
464
491
|
}
|
|
465
492
|
/** The ergonomic builder methods, excluding the raw `.cron` escape hatch. */
|
|
466
|
-
type CronScheduleKind = "daily" | "interval" | "monthly" | "weekly";
|
|
493
|
+
type CronScheduleKind = "daily" | "hourly" | "interval" | "monthly" | "weekly";
|
|
467
494
|
/** The ergonomic schedule kinds as a runtime set (codegen reads this to detect cron builder methods). */
|
|
468
495
|
declare const CRON_SCHEDULE_KINDS: ReadonlySet<CronScheduleKind>;
|
|
469
496
|
/**
|
|
@@ -472,7 +499,7 @@ declare const CRON_SCHEDULE_KINDS: ReadonlySet<CronScheduleKind>;
|
|
|
472
499
|
* compilation when it statically lifts a `crons.{kind}(...)` call out of the
|
|
473
500
|
* AST — codegen imports this directly (no duplicated mirror).
|
|
474
501
|
*/
|
|
475
|
-
declare const compileCronSchedule: (kind: CronScheduleKind, schedule: DailySchedule | IntervalSchedule | MonthlySchedule | WeeklySchedule) => string;
|
|
502
|
+
declare const compileCronSchedule: (kind: CronScheduleKind, schedule: DailySchedule | HourlySchedule | IntervalSchedule | MonthlySchedule | WeeklySchedule) => string;
|
|
476
503
|
/**
|
|
477
504
|
* Builder returned by {@link cronJobs}. Each method registers one recurring
|
|
478
505
|
* job; the compiled expression is validated immediately so authoring mistakes
|
|
@@ -487,6 +514,8 @@ interface CronJobsBuilder {
|
|
|
487
514
|
cron: <T extends CronTarget>(name: string, cronExpr: string, target: T, args?: CronTargetArgs<T>) => CronJobsBuilder;
|
|
488
515
|
/** Daily at `hourUTC:minuteUTC` (UTC). The target may be a function or a durable workflow (`workflows.<name>`). */
|
|
489
516
|
daily: <T extends CronTarget>(name: string, schedule: DailySchedule, target: T, args?: CronTargetArgs<T>) => CronJobsBuilder;
|
|
517
|
+
/** Hourly at `minuteUTC` past the hour. The target may be a function or a durable workflow (`workflows.<name>`). */
|
|
518
|
+
hourly: <T extends CronTarget>(name: string, schedule: HourlySchedule, target: T, args?: CronTargetArgs<T>) => CronJobsBuilder;
|
|
490
519
|
/** Every `{ seconds | minutes | hours }`. The target may be a function or a durable workflow (`workflows.<name>`). */
|
|
491
520
|
interval: <T extends CronTarget>(name: string, schedule: IntervalSchedule, target: T, args?: CronTargetArgs<T>) => CronJobsBuilder;
|
|
492
521
|
/** Snapshot of the registered jobs, in declaration order. */
|
|
@@ -842,6 +871,33 @@ declare class SchedulerDO {
|
|
|
842
871
|
private armAlarmIfEarlier;
|
|
843
872
|
private rescheduleAlarm;
|
|
844
873
|
}
|
|
874
|
+
/** What the Cloudflare scheduler host needs from the Worker's environment. */
|
|
875
|
+
interface SchedulerHostOptions {
|
|
876
|
+
/**
|
|
877
|
+
* Named scheduler instance — one `SchedulerDO` per name, useful for tenant
|
|
878
|
+
* isolation. Defaults to `"default"`.
|
|
879
|
+
*/
|
|
880
|
+
instanceName?: string;
|
|
881
|
+
/**
|
|
882
|
+
* Data-residency jurisdiction for the `SchedulerDO`. Pass the same value as
|
|
883
|
+
* the worker's own jurisdiction so scheduled state co-resides with app data.
|
|
884
|
+
*/
|
|
885
|
+
jurisdiction?: "eu" | "fedramp" | "us";
|
|
886
|
+
/** The `SchedulerDO` namespace binding. */
|
|
887
|
+
namespace: Parameters<typeof createScheduler>[0]["namespace"];
|
|
888
|
+
/**
|
|
889
|
+
* Public origin the Worker is mounted at. `SchedulerDO` dispatches back to
|
|
890
|
+
* this base URL when an alarm fires, so a wrong value means jobs fire into
|
|
891
|
+
* nothing.
|
|
892
|
+
*/
|
|
893
|
+
originUrl: string;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Build the Cloudflare {@link SchedulerHost}.
|
|
897
|
+
*
|
|
898
|
+
* The returned host has no `cron` member — see the module docstring.
|
|
899
|
+
*/
|
|
900
|
+
declare const createSchedulerHost: (options: SchedulerHostOptions) => SchedulerHost;
|
|
845
901
|
/** Standard cron expression (5- or 6-field) or a supported `@macro`, per `cron-parser`. */
|
|
846
902
|
declare const isValidCronExpression: (schedule: string) => boolean;
|
|
847
903
|
/**
|
|
@@ -850,4 +906,4 @@ declare const isValidCronExpression: (schedule: string) => boolean;
|
|
|
850
906
|
* job (`cron job "send digest"`) vs. the bare trigger.
|
|
851
907
|
*/
|
|
852
908
|
declare const assertValidCronExpression: (schedule: string, context?: string) => void;
|
|
853
|
-
export { type ArgsOf, CRON_SCHEDULE_KINDS, type CronJob, type CronJobsBuilder, type CronScheduleKind, type CronTarget, type CronTriggerOptions, type CronTriggerSnippet, type DailySchedule, type DurableObjectIdLike, type DurableObjectJurisdiction, type DurableObjectNamespaceLike, type DurableObjectStubLike, type EnqueueOptions, type FunctionReference, type HttpDispatcherOptions, type IntervalSchedule, type LunoraSchedulerOptions, type MessageBatchLike, type MonthlySchedule, type QueueConsumerOptions, type QueueDispatch, type QueueEnqueueOptions, type QueueJob, type QueueLike, type QueueMessageLike, type QueueSendOptionsLike, type QueueSendRequestLike, type QueueWorkpool, type QueueWorkpoolOptions, type RetryPolicy, type RunOptions, type ScheduleRecord, type Scheduler, SchedulerDO, type SchedulerDOState, type SchedulerEnv, type SchedulerPoolStatus, type SchedulerStatus, type WeeklySchedule, type WorkflowReference, type Workpool, type WorkpoolOptions, assertValidCronExpression, compileCronSchedule, createCronTrigger, createQueueConsumer, createQueueWorkpool, createScheduler, createWorkpool, cronJobs, httpDispatcher, isValidCronExpression, isWorkflowReference };
|
|
909
|
+
export { type ArgsOf, CRON_SCHEDULE_KINDS, type CronJob, type CronJobsBuilder, type CronScheduleKind, type CronTarget, type CronTriggerOptions, type CronTriggerSnippet, type DailySchedule, type DurableObjectIdLike, type DurableObjectJurisdiction, type DurableObjectNamespaceLike, type DurableObjectStubLike, type EnqueueOptions, type FunctionReference, type HourlySchedule, type HttpDispatcherOptions, type IntervalSchedule, type LunoraSchedulerOptions, type MessageBatchLike, type MonthlySchedule, type QueueConsumerOptions, type QueueDispatch, type QueueEnqueueOptions, type QueueJob, type QueueLike, type QueueMessageLike, type QueueSendOptionsLike, type QueueSendRequestLike, type QueueWorkpool, type QueueWorkpoolOptions, type RetryPolicy, type RunOptions, type ScheduleRecord, type Scheduler, SchedulerDO, type SchedulerDOState, type SchedulerEnv, type SchedulerHostOptions, type SchedulerPoolStatus, type SchedulerStatus, type WeeklySchedule, type WorkflowReference, type Workpool, type WorkpoolOptions, assertValidCronExpression, compileCronSchedule, createCronTrigger, createQueueConsumer, createQueueWorkpool, createScheduler, createSchedulerHost, createWorkpool, cronJobs, httpDispatcher, isValidCronExpression, isWorkflowReference };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SchedulerHost } from '@lunora/platform';
|
|
1
2
|
/**
|
|
2
3
|
* Opaque reference to a Lunora function. Mirrors the `FunctionReference` shape
|
|
3
4
|
* emitted by `@lunora/codegen` (and consumed by `@lunora/client`). We avoid a
|
|
@@ -140,6 +141,19 @@ interface Scheduler {
|
|
|
140
141
|
cancel: (id: string) => Promise<{
|
|
141
142
|
cancelled: boolean;
|
|
142
143
|
}>;
|
|
144
|
+
/**
|
|
145
|
+
* Jobs that exhausted their retry budget and were parked under `dead:`
|
|
146
|
+
* (the DO's `/dead` view). Deliberately absent from {@link Scheduler.list} —
|
|
147
|
+
* the park deletes the `id:` header — so this is the only view of a job
|
|
148
|
+
* that failed permanently rather than being silently dropped.
|
|
149
|
+
*/
|
|
150
|
+
dead: () => Promise<ScheduleRecord[]>;
|
|
151
|
+
/**
|
|
152
|
+
* Resurrect a parked job with a fresh attempt budget (the DO's
|
|
153
|
+
* `POST /dead/retry`). `false` when the id is not parked; a racing double
|
|
154
|
+
* recover is a no-op rather than an error.
|
|
155
|
+
*/
|
|
156
|
+
deadRetry: (id: string) => Promise<boolean>;
|
|
143
157
|
/** Resolve a single pending job by id, or `null` when absent (derived from {@link Scheduler.list}). */
|
|
144
158
|
get: (id: string) => Promise<ScheduleRecord | null>;
|
|
145
159
|
/** All pending scheduled jobs (the DO's `/list` view). */
|
|
@@ -426,6 +440,19 @@ interface DailySchedule {
|
|
|
426
440
|
/** 0–59. */
|
|
427
441
|
minuteUTC: number;
|
|
428
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* Hourly recurrence at a fixed minute past the hour.
|
|
445
|
+
*
|
|
446
|
+
* `crons.interval({ hours: 1 })` compiles to the same expression, but the
|
|
447
|
+
* asymmetry of having `daily`/`weekly`/`monthly` and no `hourly` is its own
|
|
448
|
+
* papercut — and unlike the interval form this one lets
|
|
449
|
+
* the caller place the job off the hour boundary, which is how you stop a
|
|
450
|
+
* dozen hourly jobs from stampeding at `:00`.
|
|
451
|
+
*/
|
|
452
|
+
interface HourlySchedule {
|
|
453
|
+
/** 0–59. */
|
|
454
|
+
minuteUTC: number;
|
|
455
|
+
}
|
|
429
456
|
/** Weekly recurrence at a fixed UTC time on a given weekday. */
|
|
430
457
|
interface WeeklySchedule extends DailySchedule {
|
|
431
458
|
/** Long weekday name, case-insensitive (e.g. `"monday"`). */
|
|
@@ -463,7 +490,7 @@ interface CronJob {
|
|
|
463
490
|
workflow?: string;
|
|
464
491
|
}
|
|
465
492
|
/** The ergonomic builder methods, excluding the raw `.cron` escape hatch. */
|
|
466
|
-
type CronScheduleKind = "daily" | "interval" | "monthly" | "weekly";
|
|
493
|
+
type CronScheduleKind = "daily" | "hourly" | "interval" | "monthly" | "weekly";
|
|
467
494
|
/** The ergonomic schedule kinds as a runtime set (codegen reads this to detect cron builder methods). */
|
|
468
495
|
declare const CRON_SCHEDULE_KINDS: ReadonlySet<CronScheduleKind>;
|
|
469
496
|
/**
|
|
@@ -472,7 +499,7 @@ declare const CRON_SCHEDULE_KINDS: ReadonlySet<CronScheduleKind>;
|
|
|
472
499
|
* compilation when it statically lifts a `crons.{kind}(...)` call out of the
|
|
473
500
|
* AST — codegen imports this directly (no duplicated mirror).
|
|
474
501
|
*/
|
|
475
|
-
declare const compileCronSchedule: (kind: CronScheduleKind, schedule: DailySchedule | IntervalSchedule | MonthlySchedule | WeeklySchedule) => string;
|
|
502
|
+
declare const compileCronSchedule: (kind: CronScheduleKind, schedule: DailySchedule | HourlySchedule | IntervalSchedule | MonthlySchedule | WeeklySchedule) => string;
|
|
476
503
|
/**
|
|
477
504
|
* Builder returned by {@link cronJobs}. Each method registers one recurring
|
|
478
505
|
* job; the compiled expression is validated immediately so authoring mistakes
|
|
@@ -487,6 +514,8 @@ interface CronJobsBuilder {
|
|
|
487
514
|
cron: <T extends CronTarget>(name: string, cronExpr: string, target: T, args?: CronTargetArgs<T>) => CronJobsBuilder;
|
|
488
515
|
/** Daily at `hourUTC:minuteUTC` (UTC). The target may be a function or a durable workflow (`workflows.<name>`). */
|
|
489
516
|
daily: <T extends CronTarget>(name: string, schedule: DailySchedule, target: T, args?: CronTargetArgs<T>) => CronJobsBuilder;
|
|
517
|
+
/** Hourly at `minuteUTC` past the hour. The target may be a function or a durable workflow (`workflows.<name>`). */
|
|
518
|
+
hourly: <T extends CronTarget>(name: string, schedule: HourlySchedule, target: T, args?: CronTargetArgs<T>) => CronJobsBuilder;
|
|
490
519
|
/** Every `{ seconds | minutes | hours }`. The target may be a function or a durable workflow (`workflows.<name>`). */
|
|
491
520
|
interval: <T extends CronTarget>(name: string, schedule: IntervalSchedule, target: T, args?: CronTargetArgs<T>) => CronJobsBuilder;
|
|
492
521
|
/** Snapshot of the registered jobs, in declaration order. */
|
|
@@ -842,6 +871,33 @@ declare class SchedulerDO {
|
|
|
842
871
|
private armAlarmIfEarlier;
|
|
843
872
|
private rescheduleAlarm;
|
|
844
873
|
}
|
|
874
|
+
/** What the Cloudflare scheduler host needs from the Worker's environment. */
|
|
875
|
+
interface SchedulerHostOptions {
|
|
876
|
+
/**
|
|
877
|
+
* Named scheduler instance — one `SchedulerDO` per name, useful for tenant
|
|
878
|
+
* isolation. Defaults to `"default"`.
|
|
879
|
+
*/
|
|
880
|
+
instanceName?: string;
|
|
881
|
+
/**
|
|
882
|
+
* Data-residency jurisdiction for the `SchedulerDO`. Pass the same value as
|
|
883
|
+
* the worker's own jurisdiction so scheduled state co-resides with app data.
|
|
884
|
+
*/
|
|
885
|
+
jurisdiction?: "eu" | "fedramp" | "us";
|
|
886
|
+
/** The `SchedulerDO` namespace binding. */
|
|
887
|
+
namespace: Parameters<typeof createScheduler>[0]["namespace"];
|
|
888
|
+
/**
|
|
889
|
+
* Public origin the Worker is mounted at. `SchedulerDO` dispatches back to
|
|
890
|
+
* this base URL when an alarm fires, so a wrong value means jobs fire into
|
|
891
|
+
* nothing.
|
|
892
|
+
*/
|
|
893
|
+
originUrl: string;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Build the Cloudflare {@link SchedulerHost}.
|
|
897
|
+
*
|
|
898
|
+
* The returned host has no `cron` member — see the module docstring.
|
|
899
|
+
*/
|
|
900
|
+
declare const createSchedulerHost: (options: SchedulerHostOptions) => SchedulerHost;
|
|
845
901
|
/** Standard cron expression (5- or 6-field) or a supported `@macro`, per `cron-parser`. */
|
|
846
902
|
declare const isValidCronExpression: (schedule: string) => boolean;
|
|
847
903
|
/**
|
|
@@ -850,4 +906,4 @@ declare const isValidCronExpression: (schedule: string) => boolean;
|
|
|
850
906
|
* job (`cron job "send digest"`) vs. the bare trigger.
|
|
851
907
|
*/
|
|
852
908
|
declare const assertValidCronExpression: (schedule: string, context?: string) => void;
|
|
853
|
-
export { type ArgsOf, CRON_SCHEDULE_KINDS, type CronJob, type CronJobsBuilder, type CronScheduleKind, type CronTarget, type CronTriggerOptions, type CronTriggerSnippet, type DailySchedule, type DurableObjectIdLike, type DurableObjectJurisdiction, type DurableObjectNamespaceLike, type DurableObjectStubLike, type EnqueueOptions, type FunctionReference, type HttpDispatcherOptions, type IntervalSchedule, type LunoraSchedulerOptions, type MessageBatchLike, type MonthlySchedule, type QueueConsumerOptions, type QueueDispatch, type QueueEnqueueOptions, type QueueJob, type QueueLike, type QueueMessageLike, type QueueSendOptionsLike, type QueueSendRequestLike, type QueueWorkpool, type QueueWorkpoolOptions, type RetryPolicy, type RunOptions, type ScheduleRecord, type Scheduler, SchedulerDO, type SchedulerDOState, type SchedulerEnv, type SchedulerPoolStatus, type SchedulerStatus, type WeeklySchedule, type WorkflowReference, type Workpool, type WorkpoolOptions, assertValidCronExpression, compileCronSchedule, createCronTrigger, createQueueConsumer, createQueueWorkpool, createScheduler, createWorkpool, cronJobs, httpDispatcher, isValidCronExpression, isWorkflowReference };
|
|
909
|
+
export { type ArgsOf, CRON_SCHEDULE_KINDS, type CronJob, type CronJobsBuilder, type CronScheduleKind, type CronTarget, type CronTriggerOptions, type CronTriggerSnippet, type DailySchedule, type DurableObjectIdLike, type DurableObjectJurisdiction, type DurableObjectNamespaceLike, type DurableObjectStubLike, type EnqueueOptions, type FunctionReference, type HourlySchedule, type HttpDispatcherOptions, type IntervalSchedule, type LunoraSchedulerOptions, type MessageBatchLike, type MonthlySchedule, type QueueConsumerOptions, type QueueDispatch, type QueueEnqueueOptions, type QueueJob, type QueueLike, type QueueMessageLike, type QueueSendOptionsLike, type QueueSendRequestLike, type QueueWorkpool, type QueueWorkpoolOptions, type RetryPolicy, type RunOptions, type ScheduleRecord, type Scheduler, SchedulerDO, type SchedulerDOState, type SchedulerEnv, type SchedulerHostOptions, type SchedulerPoolStatus, type SchedulerStatus, type WeeklySchedule, type WorkflowReference, type Workpool, type WorkpoolOptions, assertValidCronExpression, compileCronSchedule, createCronTrigger, createQueueConsumer, createQueueWorkpool, createScheduler, createSchedulerHost, createWorkpool, cronJobs, httpDispatcher, isValidCronExpression, isWorkflowReference };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{default as o}from"./packem_shared/createScheduler-
|
|
1
|
+
import{default as o}from"./packem_shared/createScheduler-CsRAEtdb.mjs";import{default as p}from"./packem_shared/createWorkpool-DyVdhB6o.mjs";import{createCronTrigger as c}from"./packem_shared/createCronTrigger-CyPdVKNF.mjs";import{CRON_SCHEDULE_KINDS as f,compileCronSchedule as l,cronJobs as m}from"./packem_shared/CRON_SCHEDULE_KINDS-DgupPI9t.mjs";import{createQueueConsumer as x,createQueueWorkpool as i,httpDispatcher as n}from"./packem_shared/createQueueConsumer-B0qNXRUJ.mjs";import{SchedulerDO as C}from"./packem_shared/SchedulerDO-DGgeZ-uI.mjs";import{createSchedulerHost as S}from"./packem_shared/createSchedulerHost-C5XacwXv.mjs";import{isWorkflowReference as E}from"./packem_shared/isWorkflowReference-CT3tdefh.mjs";import{assertValidCronExpression as W,isValidCronExpression as g}from"./packem_shared/assertValidCronExpression-DHvO7Vm9.mjs";export{f as CRON_SCHEDULE_KINDS,C as SchedulerDO,W as assertValidCronExpression,l as compileCronSchedule,c as createCronTrigger,x as createQueueConsumer,i as createQueueWorkpool,o as createScheduler,S as createSchedulerHost,p as createWorkpool,m as cronJobs,n as httpDispatcher,g as isValidCronExpression,E as isWorkflowReference};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as s}from"@lunora/errors";import{isWorkflowReference as m}from"./isWorkflowReference-CT3tdefh.mjs";import{assertValidCronExpression as h}from"./assertValidCronExpression-DHvO7Vm9.mjs";const f={friday:5,monday:1,saturday:6,sunday:0,thursday:4,tuesday:2,wednesday:3},w=24,y=" For a daily or longer schedule use crons.daily(name, { hourUTC, minuteUTC }, …), crons.weekly(name, { dayOfWeek, hourUTC, minuteUTC }, …) or crons.monthly(name, { day, hourUTC, minuteUTC }, …).",l=(e,o,r,t)=>{if(!Number.isInteger(e)||e<r||e>t)throw new s("INTERNAL",`@lunora/scheduler: cronJobs ${o} must be an integer in [${r.toFixed(0)}, ${t.toFixed(0)}], got ${String(e)}`);return e.toFixed(0)},c=(e,o,r)=>{const t=l(e,o,1,r-1);if(r%e!==0)throw new s("INTERNAL",`@lunora/scheduler: ${o} must evenly divide ${r.toFixed(0)} for a fixed "every ${e.toFixed(0)}" interval — cron "*/${e.toFixed(0)}" means "at values divisible by ${e.toFixed(0)}", which wraps unevenly; pick a divisor of ${r.toFixed(0)}`);return t},T=e=>{const o=["seconds","minutes","hours"].filter(n=>e[n]!==void 0);if(o.length!==1){const n=Object.entries(e).filter(([,a])=>a!==void 0).map(([a])=>a);throw new s("INTERNAL",`@lunora/scheduler: interval schedule must specify exactly one of { seconds, minutes, hours }, got { ${n.join(", ")} }.${y}`)}const r=o[0],t=e[r];if(r==="hours"&&t>=w)throw new s("INTERNAL",`@lunora/scheduler: interval.hours is capped at 23, got ${String(t)} — an interval repeats WITHIN a day rather than spanning one.${y}`);return r==="seconds"?`*/${c(t,"interval.seconds",60)} * * * * *`:r==="minutes"?`*/${c(t,"interval.minutes",60)} * * * *`:`0 */${c(t,"interval.hours",24)} * * *`},$=e=>`${l(e.minuteUTC,"hourly.minuteUTC",0,59)} * * * *`,C=e=>{const o=l(e.minuteUTC,"daily.minuteUTC",0,59),r=l(e.hourUTC,"daily.hourUTC",0,23);return`${o} ${r} * * *`},p=e=>{const o=f[e.dayOfWeek];if(o===void 0)throw new s("INTERNAL",`@lunora/scheduler: weekly schedule has invalid dayOfWeek "${e.dayOfWeek}"`);const r=l(e.minuteUTC,"weekly.minuteUTC",0,59),t=l(e.hourUTC,"weekly.hourUTC",0,23);return`${r} ${t} * * ${o.toFixed(0)}`},v=e=>{const o=l(e.day,"monthly.day",1,31),r=l(e.minuteUTC,"monthly.minuteUTC",0,59),t=l(e.hourUTC,"monthly.hourUTC",0,23);return`${r} ${t} ${o} * *`},k=new Set(["daily","hourly","interval","monthly","weekly"]),d=(e,o)=>{switch(e){case"daily":return C(o);case"hourly":return $(o);case"interval":return T(o);case"monthly":return v(o);case"weekly":return p(o);default:throw new s("INTERNAL",`@lunora/scheduler: unknown cron schedule kind "${String(e)}"`)}},b=()=>{const e=[],o=new Set,r=(n,a,i,u)=>{if(typeof n!="string"||n.trim()==="")throw new s("INTERNAL","@lunora/scheduler: cron job name must be a non-empty string");if(o.has(n))throw new s("INTERNAL",`@lunora/scheduler: duplicate cron job name "${n}" — names must be unique within one cronJobs()`);if(m(i)){h(a,`cron expression for job "${n}"`),o.add(n),e.push({args:u??{},cron:a,name:n,workflow:typeof i.name=="string"?i.name:""});return}if(!i||typeof i.__lunoraRef!="string")throw new s("INTERNAL",`@lunora/scheduler: cron job "${n}" requires a function reference (e.g. internal.email.digest) or a workflow reference`);h(a,`cron expression for job "${n}"`),o.add(n),e.push({args:u??{},cron:a,functionPath:i.__lunoraRef,name:n})},t={cron(n,a,i,u){return r(n,a,i,u),t},daily(n,a,i,u){return r(n,d("daily",a),i,u),t},hourly(n,a,i,u){return r(n,d("hourly",a),i,u),t},interval(n,a,i,u){return r(n,d("interval",a),i,u),t},jobs:()=>[...e],monthly(n,a,i,u){return r(n,d("monthly",a),i,u),t},weekly(n,a,i,u){return r(n,d("weekly",a),i,u),t}};return t};export{k as CRON_SCHEDULE_KINDS,d as compileCronSchedule,b as cronJobs};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as i}from"@lunora/errors";import{l as s,u as a}from"./do-client-BFps7NIj.mjs";import{isWorkflowReference as g}from"./isWorkflowReference-CT3tdefh.mjs";const y=n=>{if(!n.namespace)throw new i("INTERNAL","@lunora/scheduler: `namespace` (SchedulerDO binding) is required");if(!n.originUrl)throw new i("INTERNAL","@lunora/scheduler: `originUrl` is required so the DO can dispatch back to the Worker");const c=async(e,r,o,t={})=>{const l=e instanceof Date?e.getTime():e,d={args:o,originUrl:n.originUrl,pool:t.pool,retry:t.retry,scheduledFor:l,shardKey:t.shardKey};if(g(r)){if(typeof r.binding!="string"||r.binding.length===0)throw new i("INTERNAL","@lunora/scheduler: workflow/agent schedule target is missing its `binding` — pass the generated `workflows.<name>` / `agents.<name>` reference");return a(n,"/schedule",{...d,workflow:r.binding})}const u=typeof r=="string"?r:r.__lunoraRef;return a(n,"/schedule",{...d,functionPath:u})};return{cancel:async e=>a(n,"/cancel",{id:e}),dead:async()=>{const e=await s(n,"/dead");return Array.isArray(e.records)?e.records:[]},deadRetry:async e=>{const{retried:r}=await a(n,"/dead/retry",{id:e});return r===!0},get:async e=>(await s(n,`/get?id=${encodeURIComponent(e)}`)).record??null,list:async()=>{const e=await s(n,"/list");return Array.isArray(e.records)?e.records:[]},runAfter:async(e,r,o,t={})=>{if(!Number.isFinite(e)||e<0)throw new i("INTERNAL","@lunora/scheduler: `delayMs` must be a non-negative finite number");return c(Date.now()+e,r,o,t)},runAt:c}};export{y as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import i from"./createScheduler-CsRAEtdb.mjs";const o=a=>a?.at!==void 0?typeof a.at=="number"?a.at:a.at.getTime():Date.now()+(a?.delayMs??0),u=a=>{const t=i({instanceName:a.instanceName,jurisdiction:a.jurisdiction,namespace:a.namespace,originUrl:a.originUrl}),c=e=>({attempts:e.attempts??0,functionPath:e.functionPath??e.workflow??"",id:e.id,scheduledFor:e.scheduledFor});return{cancel:async e=>{const{cancelled:r}=await t.cancel(e);return r},deadLetter:{list:async()=>(await t.dead()).map(e=>c(e)),requeue:async e=>t.deadRetry(e)},list:async()=>(await t.list()).map(e=>c(e)),schedule:async(e,r,n)=>{const s=t.runAt;return s(o(n),e,r,{retry:n?.retry,shardKey:n?.shardKey})}}};export{u as createSchedulerHost};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/scheduler",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.15",
|
|
4
4
|
"description": "Scheduling for Lunora: runAfter / runAt and Cron Triggers via SchedulerDO",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@lunora/errors": "1.0.0-alpha.9",
|
|
50
|
+
"@lunora/platform": "1.0.0-alpha.1",
|
|
50
51
|
"cron-parser": "5.6.2"
|
|
51
52
|
},
|
|
52
53
|
"engines": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as u}from"@lunora/errors";import{isWorkflowReference as m}from"./isWorkflowReference-CT3tdefh.mjs";import{assertValidCronExpression as h}from"./assertValidCronExpression-DHvO7Vm9.mjs";const y={friday:5,monday:1,saturday:6,sunday:0,thursday:4,tuesday:2,wednesday:3},l=(e,r,n,t)=>{if(!Number.isInteger(e)||e<n||e>t)throw new u("INTERNAL",`@lunora/scheduler: cronJobs ${r} must be an integer in [${n.toFixed(0)}, ${t.toFixed(0)}], got ${String(e)}`);return e.toFixed(0)},c=(e,r,n)=>{const t=l(e,r,1,n-1);if(n%e!==0)throw new u("INTERNAL",`@lunora/scheduler: ${r} must evenly divide ${n.toFixed(0)} for a fixed "every ${e.toFixed(0)}" interval — cron "*/${e.toFixed(0)}" means "at values divisible by ${e.toFixed(0)}", which wraps unevenly; pick a divisor of ${n.toFixed(0)}`);return t},f=e=>{const r=["seconds","minutes","hours"].filter(o=>e[o]!==void 0);if(r.length!==1)throw new u("INTERNAL","@lunora/scheduler: interval schedule must specify exactly one of { seconds, minutes, hours }");const n=r[0],t=e[n];return n==="seconds"?`*/${c(t,"interval.seconds",60)} * * * * *`:n==="minutes"?`*/${c(t,"interval.minutes",60)} * * * *`:`0 */${c(t,"interval.hours",24)} * * *`},w=e=>{const r=l(e.minuteUTC,"daily.minuteUTC",0,59),n=l(e.hourUTC,"daily.hourUTC",0,23);return`${r} ${n} * * *`},$=e=>{const r=y[e.dayOfWeek];if(r===void 0)throw new u("INTERNAL",`@lunora/scheduler: weekly schedule has invalid dayOfWeek "${e.dayOfWeek}"`);const n=l(e.minuteUTC,"weekly.minuteUTC",0,59),t=l(e.hourUTC,"weekly.hourUTC",0,23);return`${n} ${t} * * ${r.toFixed(0)}`},T=e=>{const r=l(e.day,"monthly.day",1,31),n=l(e.minuteUTC,"monthly.minuteUTC",0,59),t=l(e.hourUTC,"monthly.hourUTC",0,23);return`${n} ${t} ${r} * *`},C=new Set(["daily","interval","monthly","weekly"]),d=(e,r)=>{switch(e){case"daily":return w(r);case"interval":return f(r);case"monthly":return T(r);case"weekly":return $(r);default:throw new u("INTERNAL",`@lunora/scheduler: unknown cron schedule kind "${String(e)}"`)}},b=()=>{const e=[],r=new Set,n=(o,s,i,a)=>{if(typeof o!="string"||o.trim()==="")throw new u("INTERNAL","@lunora/scheduler: cron job name must be a non-empty string");if(r.has(o))throw new u("INTERNAL",`@lunora/scheduler: duplicate cron job name "${o}" — names must be unique within one cronJobs()`);if(m(i)){h(s,`cron expression for job "${o}"`),r.add(o),e.push({args:a??{},cron:s,name:o,workflow:typeof i.name=="string"?i.name:""});return}if(!i||typeof i.__lunoraRef!="string")throw new u("INTERNAL",`@lunora/scheduler: cron job "${o}" requires a function reference (e.g. internal.email.digest) or a workflow reference`);h(s,`cron expression for job "${o}"`),r.add(o),e.push({args:a??{},cron:s,functionPath:i.__lunoraRef,name:o})},t={cron(o,s,i,a){return n(o,s,i,a),t},daily(o,s,i,a){return n(o,d("daily",s),i,a),t},interval(o,s,i,a){return n(o,d("interval",s),i,a),t},jobs:()=>[...e],monthly(o,s,i,a){return n(o,d("monthly",s),i,a),t},weekly(o,s,i,a){return n(o,d("weekly",s),i,a),t}};return t};export{C as CRON_SCHEDULE_KINDS,d as compileCronSchedule,b as cronJobs};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as i}from"@lunora/errors";import{l,u as s}from"./do-client-BFps7NIj.mjs";import{isWorkflowReference as g}from"./isWorkflowReference-CT3tdefh.mjs";const m=n=>{if(!n.namespace)throw new i("INTERNAL","@lunora/scheduler: `namespace` (SchedulerDO binding) is required");if(!n.originUrl)throw new i("INTERNAL","@lunora/scheduler: `originUrl` is required so the DO can dispatch back to the Worker");const a=async(e,r,o,t={})=>{const u=e instanceof Date?e.getTime():e,c={args:o,originUrl:n.originUrl,pool:t.pool,retry:t.retry,scheduledFor:u,shardKey:t.shardKey};if(g(r)){if(typeof r.binding!="string"||r.binding.length===0)throw new i("INTERNAL","@lunora/scheduler: workflow/agent schedule target is missing its `binding` — pass the generated `workflows.<name>` / `agents.<name>` reference");return s(n,"/schedule",{...c,workflow:r.binding})}const d=typeof r=="string"?r:r.__lunoraRef;return s(n,"/schedule",{...c,functionPath:d})};return{cancel:async e=>s(n,"/cancel",{id:e}),get:async e=>(await l(n,`/get?id=${encodeURIComponent(e)}`)).record??null,list:async()=>{const e=await l(n,"/list");return Array.isArray(e.records)?e.records:[]},runAfter:async(e,r,o,t={})=>{if(!Number.isFinite(e)||e<0)throw new i("INTERNAL","@lunora/scheduler: `delayMs` must be a non-negative finite number");return a(Date.now()+e,r,o,t)},runAt:a}};export{m as default};
|