@alzulejos/laranja-core 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +274 -0
- package/dist/api.js +45 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +37 -0
- package/dist/auth.js +78 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +104 -0
- package/dist/client.js +240 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +151 -0
- package/dist/config.js +89 -0
- package/dist/config.js.map +1 -0
- package/dist/env.d.ts +55 -0
- package/dist/env.js +66 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/ir.d.ts +204 -0
- package/dist/ir.js +21 -0
- package/dist/ir.js.map +1 -0
- package/dist/nest-schedule.d.ts +127 -0
- package/dist/nest-schedule.js +222 -0
- package/dist/nest-schedule.js.map +1 -0
- package/dist/schedule.d.ts +62 -0
- package/dist/schedule.js +140 -0
- package/dist/schedule.js.map +1 -0
- package/package.json +23 -0
package/dist/ir.d.ts
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Infra IR is the serializable boundary between the front half of the tool
|
|
3
|
+
* (scanning user source) and the back half (generating + deploying CDK).
|
|
4
|
+
*
|
|
5
|
+
* Everything downstream depends only on this shape — never on ts-morph nodes or
|
|
6
|
+
* the user's source tree. This is what lets us later move CDK synth server-side
|
|
7
|
+
* (free tier) vs. local eject (paid) without touching the scanner.
|
|
8
|
+
*/
|
|
9
|
+
import type { Schedule } from "./schedule.js";
|
|
10
|
+
export type Framework = "express" | "nest";
|
|
11
|
+
/**
|
|
12
|
+
* Target cloud. Only "aws" is implemented today; the rest are planned. The field
|
|
13
|
+
* lives in the IR so server-side synth can dispatch to the right back-half and
|
|
14
|
+
* configs written today stay forward-compatible.
|
|
15
|
+
*/
|
|
16
|
+
export type CloudProvider = "aws" | "azure" | "gcp" | "cloudflare";
|
|
17
|
+
/**
|
|
18
|
+
* Runtime config shared by every function-backed resource — the HTTP proxy and
|
|
19
|
+
* each cron/queue consumer all become a function, so they all carry this.
|
|
20
|
+
*
|
|
21
|
+
* Sourced from the config's global `compute` defaults, overridden per-resource by
|
|
22
|
+
* `resources[id]`; the scanner merges the two and attaches the result here. Each
|
|
23
|
+
* field maps to a real knob on AWS Lambda, GCP Cloud Functions, and Azure
|
|
24
|
+
* Functions — except the two flagged AWS-honest, which a future provider union
|
|
25
|
+
* rejects on non-AWS targets rather than fake-abstracting.
|
|
26
|
+
*/
|
|
27
|
+
export interface ComputeConfig {
|
|
28
|
+
/** Memory in MB. */
|
|
29
|
+
memory?: number;
|
|
30
|
+
/** Max wall-clock seconds per invocation. */
|
|
31
|
+
timeout?: number;
|
|
32
|
+
/** Cap on simultaneous executions (AWS reserved concurrency / GCP maxInstances). */
|
|
33
|
+
maxConcurrency?: number;
|
|
34
|
+
/** CPU architecture. AWS-honest. */
|
|
35
|
+
architecture?: "x86_64" | "arm64";
|
|
36
|
+
/** Log retention in days. AWS-honest (CloudWatch log group). */
|
|
37
|
+
logRetention?: number;
|
|
38
|
+
}
|
|
39
|
+
/** A point in the user's source, for diagnostics / visibility. e.g. "src/jobs.ts:12" */
|
|
40
|
+
export type SourceLocation = string;
|
|
41
|
+
/** A decorated method on a class: `class Jobs { @Cron() method() {} }`. */
|
|
42
|
+
export interface MethodTarget {
|
|
43
|
+
style: "method";
|
|
44
|
+
/** Project-relative path to the file declaring the class. */
|
|
45
|
+
file: string;
|
|
46
|
+
/** Class the method lives on. */
|
|
47
|
+
className: string;
|
|
48
|
+
/** Method name to invoke. */
|
|
49
|
+
method: string;
|
|
50
|
+
/** Source location for diagnostics. */
|
|
51
|
+
source: SourceLocation;
|
|
52
|
+
}
|
|
53
|
+
/** An exported function registered via `cron(...)` / `queue(...)`. */
|
|
54
|
+
export interface FunctionTarget {
|
|
55
|
+
style: "function";
|
|
56
|
+
/** Project-relative path to the file declaring the function. */
|
|
57
|
+
file: string;
|
|
58
|
+
/** Exported name of the handler function to import. */
|
|
59
|
+
exportName: string;
|
|
60
|
+
/** Source location for diagnostics. */
|
|
61
|
+
source: SourceLocation;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Reference to the user code that becomes an isolated Lambda. Either a method on
|
|
65
|
+
* a class (decorator style) or a standalone exported function (marker style).
|
|
66
|
+
*/
|
|
67
|
+
export type HandlerRef = MethodTarget | FunctionTarget;
|
|
68
|
+
/** The natural handler name: method name (class style) or export name (function style). */
|
|
69
|
+
export declare function handlerName(ref: HandlerRef): string;
|
|
70
|
+
/** The id a handler gets when the user doesn't set an explicit one. */
|
|
71
|
+
export declare function defaultHandlerId(ref: HandlerRef): string;
|
|
72
|
+
/** Lambda label: the natural handler name, unless the user set a custom id. */
|
|
73
|
+
export declare function handlerLabel(item: HandlerRef & {
|
|
74
|
+
id: string;
|
|
75
|
+
}): string;
|
|
76
|
+
/** A discovered HTTP route. In v1 all routes are served by ONE proxy Lambda; */
|
|
77
|
+
/** routes are captured for visibility / validation / future per-route IAM. */
|
|
78
|
+
export interface HttpRoute {
|
|
79
|
+
method: string;
|
|
80
|
+
path: string;
|
|
81
|
+
source: SourceLocation;
|
|
82
|
+
}
|
|
83
|
+
export interface HttpIR {
|
|
84
|
+
/** Project-relative module that exports the framework app (the proxy target). */
|
|
85
|
+
handlerEntry: string;
|
|
86
|
+
/** Named export of the app within `handlerEntry` (e.g. "app" or "default"). */
|
|
87
|
+
appExport: string;
|
|
88
|
+
routes: HttpRoute[];
|
|
89
|
+
/** Resolved compute config for the proxy function (keyed as "http" in `resources`). */
|
|
90
|
+
compute?: ComputeConfig;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* A `workers(SomeModule)` marker — and, post‑consolidation, the ONE worker Lambda
|
|
94
|
+
* for that module. All of a module's method‑style `@Cron`/`@Queue` handlers run in
|
|
95
|
+
* this single function: it boots a standalone DI context
|
|
96
|
+
* (`NestFactory.createApplicationContext(module)`) once, and its generated shim
|
|
97
|
+
* routes each invocation (EventBridge → cron by id, SQS → queue by ARN) to the
|
|
98
|
+
* right provider method. Absent for Express (no DI) and workers‑free projects.
|
|
99
|
+
*
|
|
100
|
+
* A project may declare several — one per disjoint DI root (e.g. a queues module
|
|
101
|
+
* and a crons module) — so each worker Lambda boots only the graph it needs and
|
|
102
|
+
* pays a smaller cold start. Each method‑style cron/queue names its module via
|
|
103
|
+
* `workersId`; that is the function it belongs to.
|
|
104
|
+
*/
|
|
105
|
+
export interface WorkersIR {
|
|
106
|
+
/** Stable id — the module's class name; what handlers point `workersId` at, and
|
|
107
|
+
* the asset/function key for this worker Lambda. */
|
|
108
|
+
id: string;
|
|
109
|
+
/** Project-relative module that exports `workers(SomeModule)`. */
|
|
110
|
+
handlerEntry: string;
|
|
111
|
+
/** Named export within that module (e.g. "default" or "jobs"). */
|
|
112
|
+
appExport: string;
|
|
113
|
+
/** Compute for this shared worker function — resolved from `resources[<module>]`
|
|
114
|
+
* merged over the global `compute` default. Shared by every hosted handler. */
|
|
115
|
+
compute?: ComputeConfig;
|
|
116
|
+
}
|
|
117
|
+
/** @Cron(...) / cron(...) -> scheduled trigger -> its own Lambda. */
|
|
118
|
+
export type CronIR = HandlerRef & {
|
|
119
|
+
/** Stable logical id, used for the CDK construct + function name. */
|
|
120
|
+
id: string;
|
|
121
|
+
/** Provider-neutral schedule; the back half lowers it to the target's syntax. */
|
|
122
|
+
schedule: Schedule;
|
|
123
|
+
/** IANA timezone for the schedule (needs EventBridge Scheduler, not Rules). */
|
|
124
|
+
timezone?: string;
|
|
125
|
+
/** Async-invoke retry attempts (AWS allows 0–2). */
|
|
126
|
+
retryAttempts?: number;
|
|
127
|
+
/** Max age (seconds) of an event before async retries are abandoned. */
|
|
128
|
+
maxEventAge?: number;
|
|
129
|
+
/** Dead-letter failed async invokes to another declared queue, referenced by id. */
|
|
130
|
+
dlq?: {
|
|
131
|
+
queue: string;
|
|
132
|
+
};
|
|
133
|
+
/** Resolved compute config for this cron's function. */
|
|
134
|
+
compute?: ComputeConfig;
|
|
135
|
+
/** Method-style Nest crons only: id of the WorkersIR DI root that owns this provider. */
|
|
136
|
+
workersId?: string;
|
|
137
|
+
};
|
|
138
|
+
/** @Queue({ name }) / queue(...) -> SQS queue -> its own consumer Lambda. */
|
|
139
|
+
export type QueueIR = HandlerRef & {
|
|
140
|
+
id: string;
|
|
141
|
+
/** Queue name. A ".fifo" suffix or fifo:true marks a FIFO queue. */
|
|
142
|
+
name: string;
|
|
143
|
+
batchSize?: number;
|
|
144
|
+
fifo?: boolean;
|
|
145
|
+
/** FIFO content-based dedup (FIFO-only). Defaults to true for FIFO when unset. */
|
|
146
|
+
contentBasedDedup?: boolean;
|
|
147
|
+
/** Seconds a message stays hidden while being processed (AWS requires >= timeout). */
|
|
148
|
+
visibilityTimeout?: number;
|
|
149
|
+
/** Seconds to wait gathering a fuller batch before invoking the consumer. */
|
|
150
|
+
maxBatchingWindow?: number;
|
|
151
|
+
/** Report per-message failures so only failed items are retried, not the batch. */
|
|
152
|
+
reportBatchItemFailures?: boolean;
|
|
153
|
+
/** Seconds an undelivered message is retained on the source queue. */
|
|
154
|
+
messageRetention?: number;
|
|
155
|
+
/** Dead-letter after N failed receives to another declared queue, referenced by id. */
|
|
156
|
+
dlq?: {
|
|
157
|
+
maxReceiveCount: number;
|
|
158
|
+
queue: string;
|
|
159
|
+
};
|
|
160
|
+
/** Resolved compute config for this queue's consumer function. */
|
|
161
|
+
compute?: ComputeConfig;
|
|
162
|
+
/** Method-style Nest queues only: id of the WorkersIR DI root that owns this provider. */
|
|
163
|
+
workersId?: string;
|
|
164
|
+
};
|
|
165
|
+
export interface InfraIR {
|
|
166
|
+
app: {
|
|
167
|
+
name: string;
|
|
168
|
+
framework: Framework;
|
|
169
|
+
/** Target cloud. Defaults to "aws". */
|
|
170
|
+
provider: CloudProvider;
|
|
171
|
+
/** Deployment stage; part of resource names. */
|
|
172
|
+
stage: string;
|
|
173
|
+
/**
|
|
174
|
+
* Emit a per-app-stage monitoring dashboard. Provider-neutral; the back half
|
|
175
|
+
* maps it to its own primitives (CloudWatch dashboard on AWS). Defaults to true.
|
|
176
|
+
*/
|
|
177
|
+
monitoring: boolean;
|
|
178
|
+
/** Project-relative app entry (same as http.handlerEntry). Absent for workers-only apps. */
|
|
179
|
+
entry?: string;
|
|
180
|
+
};
|
|
181
|
+
/** Absent when there's no `http()` marker — a workers-only deployment. */
|
|
182
|
+
http?: HttpIR;
|
|
183
|
+
/**
|
|
184
|
+
* Nest DI roots for class-based workers; absent for Express / function-only apps.
|
|
185
|
+
* One entry per `workers()` marker — a project can run disjoint DI graphs so each
|
|
186
|
+
* worker Lambda boots only its own module (smaller cold starts). Method-style
|
|
187
|
+
* crons/queues bind to a root via `workersId`.
|
|
188
|
+
*/
|
|
189
|
+
workers?: WorkersIR[];
|
|
190
|
+
crons: CronIR[];
|
|
191
|
+
queues: QueueIR[];
|
|
192
|
+
/**
|
|
193
|
+
* Static env from config, injected into every Lambda as literal name->value.
|
|
194
|
+
* Crosses the wire to the server as-is. Secrets handling comes later.
|
|
195
|
+
*/
|
|
196
|
+
env: Record<string, string>;
|
|
197
|
+
/**
|
|
198
|
+
* Env var NAMES discovered from `env("NAME")` calls in user code (names only,
|
|
199
|
+
* never values). The client resolves each from `process.env` at deploy time
|
|
200
|
+
* and injects it into every Lambda — so values stay on the developer's machine
|
|
201
|
+
* (and out of the IR, the wire, and the server). Sorted + de-duplicated.
|
|
202
|
+
*/
|
|
203
|
+
envKeys: string[];
|
|
204
|
+
}
|
package/dist/ir.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Infra IR is the serializable boundary between the front half of the tool
|
|
3
|
+
* (scanning user source) and the back half (generating + deploying CDK).
|
|
4
|
+
*
|
|
5
|
+
* Everything downstream depends only on this shape — never on ts-morph nodes or
|
|
6
|
+
* the user's source tree. This is what lets us later move CDK synth server-side
|
|
7
|
+
* (free tier) vs. local eject (paid) without touching the scanner.
|
|
8
|
+
*/
|
|
9
|
+
/** The natural handler name: method name (class style) or export name (function style). */
|
|
10
|
+
export function handlerName(ref) {
|
|
11
|
+
return ref.style === "function" ? ref.exportName : ref.method;
|
|
12
|
+
}
|
|
13
|
+
/** The id a handler gets when the user doesn't set an explicit one. */
|
|
14
|
+
export function defaultHandlerId(ref) {
|
|
15
|
+
return ref.style === "function" ? ref.exportName : `${ref.className}-${ref.method}`;
|
|
16
|
+
}
|
|
17
|
+
/** Lambda label: the natural handler name, unless the user set a custom id. */
|
|
18
|
+
export function handlerLabel(item) {
|
|
19
|
+
return item.id === defaultHandlerId(item) ? handlerName(item) : item.id;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=ir.js.map
|
package/dist/ir.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ir.js","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAqEH,2FAA2F;AAC3F,MAAM,UAAU,WAAW,CAAC,GAAe;IACzC,OAAO,GAAG,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAChE,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,gBAAgB,CAAC,GAAe;IAC9C,OAAO,GAAG,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;AACtF,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,YAAY,CAAC,IAAiC;IAC5D,OAAO,IAAI,CAAC,EAAE,KAAK,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nestjs/schedule` compatibility. A Nest user should be able to swap the
|
|
3
|
+
* `@Cron` import from `@nestjs/schedule` to laranja and keep their existing
|
|
4
|
+
* schedules — so we accept node-cron expressions (and the `CronExpression` enum)
|
|
5
|
+
* and translate them into laranja's neutral `Schedule` here, in the front half.
|
|
6
|
+
*
|
|
7
|
+
* We lower to an AWS EventBridge `cron(...)` expression (the only dialect the back
|
|
8
|
+
* half understands today). node-cron and EventBridge cron differ in real ways —
|
|
9
|
+
* sub-minute granularity, day-of-week numbering, and the mutually-exclusive
|
|
10
|
+
* day-of-month/day-of-week rule (EventBridge requires exactly one of them to be
|
|
11
|
+
* `?`). So this both TRANSLATES what maps and REJECTS, loudly and with a source
|
|
12
|
+
* location, what EventBridge physically cannot honor. We never silently round a
|
|
13
|
+
* schedule to a different cadence — a job the user thinks runs every 30s must not
|
|
14
|
+
* quietly become every minute.
|
|
15
|
+
*/
|
|
16
|
+
import { type Schedule } from "./schedule.js";
|
|
17
|
+
/**
|
|
18
|
+
* Mirror of `@nestjs/schedule`'s `CronExpression` enum (values copied verbatim),
|
|
19
|
+
* re-exported so users who `import { CronExpression }` can point it at laranja and
|
|
20
|
+
* keep compiling. The scanner resolves `CronExpression.MEMBER` to its string value
|
|
21
|
+
* through this same object, so the two stay in lockstep by construction.
|
|
22
|
+
*/
|
|
23
|
+
export declare enum CronExpression {
|
|
24
|
+
EVERY_SECOND = "* * * * * *",
|
|
25
|
+
EVERY_5_SECONDS = "*/5 * * * * *",
|
|
26
|
+
EVERY_10_SECONDS = "*/10 * * * * *",
|
|
27
|
+
EVERY_30_SECONDS = "*/30 * * * * *",
|
|
28
|
+
EVERY_MINUTE = "*/1 * * * *",
|
|
29
|
+
EVERY_5_MINUTES = "0 */5 * * * *",
|
|
30
|
+
EVERY_10_MINUTES = "0 */10 * * * *",
|
|
31
|
+
EVERY_30_MINUTES = "0 */30 * * * *",
|
|
32
|
+
EVERY_HOUR = "0 0-23/1 * * *",
|
|
33
|
+
EVERY_2_HOURS = "0 0-23/2 * * *",
|
|
34
|
+
EVERY_3_HOURS = "0 0-23/3 * * *",
|
|
35
|
+
EVERY_4_HOURS = "0 0-23/4 * * *",
|
|
36
|
+
EVERY_5_HOURS = "0 0-23/5 * * *",
|
|
37
|
+
EVERY_6_HOURS = "0 0-23/6 * * *",
|
|
38
|
+
EVERY_7_HOURS = "0 0-23/7 * * *",
|
|
39
|
+
EVERY_8_HOURS = "0 0-23/8 * * *",
|
|
40
|
+
EVERY_9_HOURS = "0 0-23/9 * * *",
|
|
41
|
+
EVERY_10_HOURS = "0 0-23/10 * * *",
|
|
42
|
+
EVERY_11_HOURS = "0 0-23/11 * * *",
|
|
43
|
+
EVERY_12_HOURS = "0 0-23/12 * * *",
|
|
44
|
+
EVERY_DAY_AT_1AM = "0 01 * * *",
|
|
45
|
+
EVERY_DAY_AT_2AM = "0 02 * * *",
|
|
46
|
+
EVERY_DAY_AT_3AM = "0 03 * * *",
|
|
47
|
+
EVERY_DAY_AT_4AM = "0 04 * * *",
|
|
48
|
+
EVERY_DAY_AT_5AM = "0 05 * * *",
|
|
49
|
+
EVERY_DAY_AT_6AM = "0 06 * * *",
|
|
50
|
+
EVERY_DAY_AT_7AM = "0 07 * * *",
|
|
51
|
+
EVERY_DAY_AT_8AM = "0 08 * * *",
|
|
52
|
+
EVERY_DAY_AT_9AM = "0 09 * * *",
|
|
53
|
+
EVERY_DAY_AT_10AM = "0 10 * * *",
|
|
54
|
+
EVERY_DAY_AT_11AM = "0 11 * * *",
|
|
55
|
+
EVERY_DAY_AT_NOON = "0 12 * * *",
|
|
56
|
+
EVERY_DAY_AT_1PM = "0 13 * * *",
|
|
57
|
+
EVERY_DAY_AT_2PM = "0 14 * * *",
|
|
58
|
+
EVERY_DAY_AT_3PM = "0 15 * * *",
|
|
59
|
+
EVERY_DAY_AT_4PM = "0 16 * * *",
|
|
60
|
+
EVERY_DAY_AT_5PM = "0 17 * * *",
|
|
61
|
+
EVERY_DAY_AT_6PM = "0 18 * * *",
|
|
62
|
+
EVERY_DAY_AT_7PM = "0 19 * * *",
|
|
63
|
+
EVERY_DAY_AT_8PM = "0 20 * * *",
|
|
64
|
+
EVERY_DAY_AT_9PM = "0 21 * * *",
|
|
65
|
+
EVERY_DAY_AT_10PM = "0 22 * * *",
|
|
66
|
+
EVERY_DAY_AT_11PM = "0 23 * * *",
|
|
67
|
+
EVERY_DAY_AT_MIDNIGHT = "0 0 * * *",
|
|
68
|
+
EVERY_WEEK = "0 0 * * 0",
|
|
69
|
+
EVERY_WEEKDAY = "0 0 * * 1-5",
|
|
70
|
+
EVERY_WEEKEND = "0 0 * * 6,0",
|
|
71
|
+
EVERY_1ST_DAY_OF_MONTH_AT_MIDNIGHT = "0 0 1 * *",
|
|
72
|
+
EVERY_1ST_DAY_OF_MONTH_AT_NOON = "0 12 1 * *",
|
|
73
|
+
EVERY_2ND_HOUR = "0 */2 * * *",
|
|
74
|
+
EVERY_2ND_HOUR_FROM_1AM_THROUGH_11PM = "0 1-23/2 * * *",
|
|
75
|
+
EVERY_2ND_MONTH = "0 0 1 */2 *",
|
|
76
|
+
EVERY_QUARTER = "0 0 1 */3 *",
|
|
77
|
+
EVERY_6_MONTHS = "0 0 1 */6 *",
|
|
78
|
+
EVERY_YEAR = "0 0 1 1 *",
|
|
79
|
+
EVERY_30_MINUTES_BETWEEN_9AM_AND_5PM = "0 */30 9-17 * * *",
|
|
80
|
+
EVERY_30_MINUTES_BETWEEN_9AM_AND_6PM = "0 */30 9-18 * * *",
|
|
81
|
+
EVERY_30_MINUTES_BETWEEN_10AM_AND_7PM = "0 */30 10-19 * * *",
|
|
82
|
+
MONDAY_TO_FRIDAY_AT_1AM = "0 0 01 * * 1-5",
|
|
83
|
+
MONDAY_TO_FRIDAY_AT_2AM = "0 0 02 * * 1-5",
|
|
84
|
+
MONDAY_TO_FRIDAY_AT_3AM = "0 0 03 * * 1-5",
|
|
85
|
+
MONDAY_TO_FRIDAY_AT_4AM = "0 0 04 * * 1-5",
|
|
86
|
+
MONDAY_TO_FRIDAY_AT_5AM = "0 0 05 * * 1-5",
|
|
87
|
+
MONDAY_TO_FRIDAY_AT_6AM = "0 0 06 * * 1-5",
|
|
88
|
+
MONDAY_TO_FRIDAY_AT_7AM = "0 0 07 * * 1-5",
|
|
89
|
+
MONDAY_TO_FRIDAY_AT_8AM = "0 0 08 * * 1-5",
|
|
90
|
+
MONDAY_TO_FRIDAY_AT_9AM = "0 0 09 * * 1-5",
|
|
91
|
+
MONDAY_TO_FRIDAY_AT_09_30AM = "0 30 09 * * 1-5",
|
|
92
|
+
MONDAY_TO_FRIDAY_AT_10AM = "0 0 10 * * 1-5",
|
|
93
|
+
MONDAY_TO_FRIDAY_AT_11AM = "0 0 11 * * 1-5",
|
|
94
|
+
MONDAY_TO_FRIDAY_AT_11_30AM = "0 30 11 * * 1-5",
|
|
95
|
+
MONDAY_TO_FRIDAY_AT_12PM = "0 0 12 * * 1-5",
|
|
96
|
+
MONDAY_TO_FRIDAY_AT_1PM = "0 0 13 * * 1-5",
|
|
97
|
+
MONDAY_TO_FRIDAY_AT_2PM = "0 0 14 * * 1-5",
|
|
98
|
+
MONDAY_TO_FRIDAY_AT_3PM = "0 0 15 * * 1-5",
|
|
99
|
+
MONDAY_TO_FRIDAY_AT_4PM = "0 0 16 * * 1-5",
|
|
100
|
+
MONDAY_TO_FRIDAY_AT_5PM = "0 0 17 * * 1-5",
|
|
101
|
+
MONDAY_TO_FRIDAY_AT_6PM = "0 0 18 * * 1-5",
|
|
102
|
+
MONDAY_TO_FRIDAY_AT_7PM = "0 0 19 * * 1-5",
|
|
103
|
+
MONDAY_TO_FRIDAY_AT_8PM = "0 0 20 * * 1-5",
|
|
104
|
+
MONDAY_TO_FRIDAY_AT_9PM = "0 0 21 * * 1-5",
|
|
105
|
+
MONDAY_TO_FRIDAY_AT_10PM = "0 0 22 * * 1-5",
|
|
106
|
+
MONDAY_TO_FRIDAY_AT_11PM = "0 0 23 * * 1-5"
|
|
107
|
+
}
|
|
108
|
+
/** Every enum string keyed by member name — used by the scanner to fold `CronExpression.X`. */
|
|
109
|
+
export declare const CRON_EXPRESSION_VALUES: Record<string, string>;
|
|
110
|
+
/**
|
|
111
|
+
* Translate a node-cron expression (5-field `min hour dom month dow`, or 6-field
|
|
112
|
+
* with a leading seconds column) into a neutral AWS-dialect cron `Schedule`.
|
|
113
|
+
* Throws a clear, located error for anything EventBridge can't express.
|
|
114
|
+
*
|
|
115
|
+
* NOTE on the seconds column: EventBridge has a 1-minute floor, so the only
|
|
116
|
+
* seconds value we accept is `0` ("at the top of the minute"), which we drop.
|
|
117
|
+
* Any other seconds value is a sub-minute or second-offset schedule and is
|
|
118
|
+
* rejected rather than approximated.
|
|
119
|
+
*/
|
|
120
|
+
export declare function nestCronToSchedule(expr: string, where: string): Schedule;
|
|
121
|
+
/**
|
|
122
|
+
* Translate `@Interval(ms)` into a neutral rate `Schedule`. Unlike `@Cron`,
|
|
123
|
+
* `@Interval` genuinely means "every N milliseconds", which maps to EventBridge's
|
|
124
|
+
* clock-independent `rate(...)`. EventBridge's floor is one minute, so the
|
|
125
|
+
* interval must be a whole number of minutes.
|
|
126
|
+
*/
|
|
127
|
+
export declare function intervalToSchedule(ms: number, where: string): Schedule;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nestjs/schedule` compatibility. A Nest user should be able to swap the
|
|
3
|
+
* `@Cron` import from `@nestjs/schedule` to laranja and keep their existing
|
|
4
|
+
* schedules — so we accept node-cron expressions (and the `CronExpression` enum)
|
|
5
|
+
* and translate them into laranja's neutral `Schedule` here, in the front half.
|
|
6
|
+
*
|
|
7
|
+
* We lower to an AWS EventBridge `cron(...)` expression (the only dialect the back
|
|
8
|
+
* half understands today). node-cron and EventBridge cron differ in real ways —
|
|
9
|
+
* sub-minute granularity, day-of-week numbering, and the mutually-exclusive
|
|
10
|
+
* day-of-month/day-of-week rule (EventBridge requires exactly one of them to be
|
|
11
|
+
* `?`). So this both TRANSLATES what maps and REJECTS, loudly and with a source
|
|
12
|
+
* location, what EventBridge physically cannot honor. We never silently round a
|
|
13
|
+
* schedule to a different cadence — a job the user thinks runs every 30s must not
|
|
14
|
+
* quietly become every minute.
|
|
15
|
+
*/
|
|
16
|
+
import { rate } from "./schedule.js";
|
|
17
|
+
/**
|
|
18
|
+
* Mirror of `@nestjs/schedule`'s `CronExpression` enum (values copied verbatim),
|
|
19
|
+
* re-exported so users who `import { CronExpression }` can point it at laranja and
|
|
20
|
+
* keep compiling. The scanner resolves `CronExpression.MEMBER` to its string value
|
|
21
|
+
* through this same object, so the two stay in lockstep by construction.
|
|
22
|
+
*/
|
|
23
|
+
export var CronExpression;
|
|
24
|
+
(function (CronExpression) {
|
|
25
|
+
CronExpression["EVERY_SECOND"] = "* * * * * *";
|
|
26
|
+
CronExpression["EVERY_5_SECONDS"] = "*/5 * * * * *";
|
|
27
|
+
CronExpression["EVERY_10_SECONDS"] = "*/10 * * * * *";
|
|
28
|
+
CronExpression["EVERY_30_SECONDS"] = "*/30 * * * * *";
|
|
29
|
+
CronExpression["EVERY_MINUTE"] = "*/1 * * * *";
|
|
30
|
+
CronExpression["EVERY_5_MINUTES"] = "0 */5 * * * *";
|
|
31
|
+
CronExpression["EVERY_10_MINUTES"] = "0 */10 * * * *";
|
|
32
|
+
CronExpression["EVERY_30_MINUTES"] = "0 */30 * * * *";
|
|
33
|
+
CronExpression["EVERY_HOUR"] = "0 0-23/1 * * *";
|
|
34
|
+
CronExpression["EVERY_2_HOURS"] = "0 0-23/2 * * *";
|
|
35
|
+
CronExpression["EVERY_3_HOURS"] = "0 0-23/3 * * *";
|
|
36
|
+
CronExpression["EVERY_4_HOURS"] = "0 0-23/4 * * *";
|
|
37
|
+
CronExpression["EVERY_5_HOURS"] = "0 0-23/5 * * *";
|
|
38
|
+
CronExpression["EVERY_6_HOURS"] = "0 0-23/6 * * *";
|
|
39
|
+
CronExpression["EVERY_7_HOURS"] = "0 0-23/7 * * *";
|
|
40
|
+
CronExpression["EVERY_8_HOURS"] = "0 0-23/8 * * *";
|
|
41
|
+
CronExpression["EVERY_9_HOURS"] = "0 0-23/9 * * *";
|
|
42
|
+
CronExpression["EVERY_10_HOURS"] = "0 0-23/10 * * *";
|
|
43
|
+
CronExpression["EVERY_11_HOURS"] = "0 0-23/11 * * *";
|
|
44
|
+
CronExpression["EVERY_12_HOURS"] = "0 0-23/12 * * *";
|
|
45
|
+
CronExpression["EVERY_DAY_AT_1AM"] = "0 01 * * *";
|
|
46
|
+
CronExpression["EVERY_DAY_AT_2AM"] = "0 02 * * *";
|
|
47
|
+
CronExpression["EVERY_DAY_AT_3AM"] = "0 03 * * *";
|
|
48
|
+
CronExpression["EVERY_DAY_AT_4AM"] = "0 04 * * *";
|
|
49
|
+
CronExpression["EVERY_DAY_AT_5AM"] = "0 05 * * *";
|
|
50
|
+
CronExpression["EVERY_DAY_AT_6AM"] = "0 06 * * *";
|
|
51
|
+
CronExpression["EVERY_DAY_AT_7AM"] = "0 07 * * *";
|
|
52
|
+
CronExpression["EVERY_DAY_AT_8AM"] = "0 08 * * *";
|
|
53
|
+
CronExpression["EVERY_DAY_AT_9AM"] = "0 09 * * *";
|
|
54
|
+
CronExpression["EVERY_DAY_AT_10AM"] = "0 10 * * *";
|
|
55
|
+
CronExpression["EVERY_DAY_AT_11AM"] = "0 11 * * *";
|
|
56
|
+
CronExpression["EVERY_DAY_AT_NOON"] = "0 12 * * *";
|
|
57
|
+
CronExpression["EVERY_DAY_AT_1PM"] = "0 13 * * *";
|
|
58
|
+
CronExpression["EVERY_DAY_AT_2PM"] = "0 14 * * *";
|
|
59
|
+
CronExpression["EVERY_DAY_AT_3PM"] = "0 15 * * *";
|
|
60
|
+
CronExpression["EVERY_DAY_AT_4PM"] = "0 16 * * *";
|
|
61
|
+
CronExpression["EVERY_DAY_AT_5PM"] = "0 17 * * *";
|
|
62
|
+
CronExpression["EVERY_DAY_AT_6PM"] = "0 18 * * *";
|
|
63
|
+
CronExpression["EVERY_DAY_AT_7PM"] = "0 19 * * *";
|
|
64
|
+
CronExpression["EVERY_DAY_AT_8PM"] = "0 20 * * *";
|
|
65
|
+
CronExpression["EVERY_DAY_AT_9PM"] = "0 21 * * *";
|
|
66
|
+
CronExpression["EVERY_DAY_AT_10PM"] = "0 22 * * *";
|
|
67
|
+
CronExpression["EVERY_DAY_AT_11PM"] = "0 23 * * *";
|
|
68
|
+
CronExpression["EVERY_DAY_AT_MIDNIGHT"] = "0 0 * * *";
|
|
69
|
+
CronExpression["EVERY_WEEK"] = "0 0 * * 0";
|
|
70
|
+
CronExpression["EVERY_WEEKDAY"] = "0 0 * * 1-5";
|
|
71
|
+
CronExpression["EVERY_WEEKEND"] = "0 0 * * 6,0";
|
|
72
|
+
CronExpression["EVERY_1ST_DAY_OF_MONTH_AT_MIDNIGHT"] = "0 0 1 * *";
|
|
73
|
+
CronExpression["EVERY_1ST_DAY_OF_MONTH_AT_NOON"] = "0 12 1 * *";
|
|
74
|
+
CronExpression["EVERY_2ND_HOUR"] = "0 */2 * * *";
|
|
75
|
+
CronExpression["EVERY_2ND_HOUR_FROM_1AM_THROUGH_11PM"] = "0 1-23/2 * * *";
|
|
76
|
+
CronExpression["EVERY_2ND_MONTH"] = "0 0 1 */2 *";
|
|
77
|
+
CronExpression["EVERY_QUARTER"] = "0 0 1 */3 *";
|
|
78
|
+
CronExpression["EVERY_6_MONTHS"] = "0 0 1 */6 *";
|
|
79
|
+
CronExpression["EVERY_YEAR"] = "0 0 1 1 *";
|
|
80
|
+
CronExpression["EVERY_30_MINUTES_BETWEEN_9AM_AND_5PM"] = "0 */30 9-17 * * *";
|
|
81
|
+
CronExpression["EVERY_30_MINUTES_BETWEEN_9AM_AND_6PM"] = "0 */30 9-18 * * *";
|
|
82
|
+
CronExpression["EVERY_30_MINUTES_BETWEEN_10AM_AND_7PM"] = "0 */30 10-19 * * *";
|
|
83
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_1AM"] = "0 0 01 * * 1-5";
|
|
84
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_2AM"] = "0 0 02 * * 1-5";
|
|
85
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_3AM"] = "0 0 03 * * 1-5";
|
|
86
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_4AM"] = "0 0 04 * * 1-5";
|
|
87
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_5AM"] = "0 0 05 * * 1-5";
|
|
88
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_6AM"] = "0 0 06 * * 1-5";
|
|
89
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_7AM"] = "0 0 07 * * 1-5";
|
|
90
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_8AM"] = "0 0 08 * * 1-5";
|
|
91
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_9AM"] = "0 0 09 * * 1-5";
|
|
92
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_09_30AM"] = "0 30 09 * * 1-5";
|
|
93
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_10AM"] = "0 0 10 * * 1-5";
|
|
94
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_11AM"] = "0 0 11 * * 1-5";
|
|
95
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_11_30AM"] = "0 30 11 * * 1-5";
|
|
96
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_12PM"] = "0 0 12 * * 1-5";
|
|
97
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_1PM"] = "0 0 13 * * 1-5";
|
|
98
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_2PM"] = "0 0 14 * * 1-5";
|
|
99
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_3PM"] = "0 0 15 * * 1-5";
|
|
100
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_4PM"] = "0 0 16 * * 1-5";
|
|
101
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_5PM"] = "0 0 17 * * 1-5";
|
|
102
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_6PM"] = "0 0 18 * * 1-5";
|
|
103
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_7PM"] = "0 0 19 * * 1-5";
|
|
104
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_8PM"] = "0 0 20 * * 1-5";
|
|
105
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_9PM"] = "0 0 21 * * 1-5";
|
|
106
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_10PM"] = "0 0 22 * * 1-5";
|
|
107
|
+
CronExpression["MONDAY_TO_FRIDAY_AT_11PM"] = "0 0 23 * * 1-5";
|
|
108
|
+
})(CronExpression || (CronExpression = {}));
|
|
109
|
+
/** Every enum string keyed by member name — used by the scanner to fold `CronExpression.X`. */
|
|
110
|
+
export const CRON_EXPRESSION_VALUES = Object.fromEntries(Object.entries(CronExpression).filter(([, v]) => typeof v === "string"));
|
|
111
|
+
/**
|
|
112
|
+
* Strip leading zeros from every numeric token in a field (`09` -> `9`, `01-05`
|
|
113
|
+
* -> `1-5`). The Nest enum zero-pads hours and days, which EventBridge's parser
|
|
114
|
+
* rejects. Non-numeric tokens (`*`, `?`, `,`, `-`, `/`, names) are left intact.
|
|
115
|
+
*/
|
|
116
|
+
function stripZeros(field) {
|
|
117
|
+
return field.replace(/\d+/g, (d) => String(parseInt(d, 10)));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Collapse a full-domain range-step (`0-23/2`) or full range (`0-59`) to the `*`
|
|
121
|
+
* form EventBridge prefers, and drop a redundant `/1` step. Leaves anything else
|
|
122
|
+
* (explicit values, lists, partial ranges) untouched. Assumes zeros already stripped.
|
|
123
|
+
*/
|
|
124
|
+
function normalizeField(field, min, max) {
|
|
125
|
+
const full = new RegExp(`^${min}-${max}(?:/(\\d+))?$`);
|
|
126
|
+
const m = full.exec(field);
|
|
127
|
+
if (m)
|
|
128
|
+
return m[1] && m[1] !== "1" ? `*/${m[1]}` : "*";
|
|
129
|
+
const starStep = /^\*\/1$/.exec(field);
|
|
130
|
+
if (starStep)
|
|
131
|
+
return "*";
|
|
132
|
+
return field;
|
|
133
|
+
}
|
|
134
|
+
/** Translate one numeric day-of-week token from Unix (0-7, 0/7=Sun) to AWS (1-7, 1=Sun). */
|
|
135
|
+
function translateDowNumber(token) {
|
|
136
|
+
if (!/^\d+$/.test(token))
|
|
137
|
+
return token; // names (MON..SUN) pass through — AWS accepts them
|
|
138
|
+
const n = Number(token);
|
|
139
|
+
if (n < 0 || n > 7)
|
|
140
|
+
return token; // out of range: let AWS reject it with its own message
|
|
141
|
+
return String((n % 7) + 1);
|
|
142
|
+
}
|
|
143
|
+
/** Apply the Unix→AWS day-of-week remap across ranges (`1-5`) and lists (`6,0`). */
|
|
144
|
+
function translateDow(field) {
|
|
145
|
+
if (field === "*" || field === "?")
|
|
146
|
+
return field;
|
|
147
|
+
return field
|
|
148
|
+
.split(",")
|
|
149
|
+
.map((part) => part
|
|
150
|
+
.split("/")
|
|
151
|
+
.map((seg, i) =>
|
|
152
|
+
// Only the value/range segment is remapped; a trailing `/step` is numeric, left as-is.
|
|
153
|
+
i === 0 ? seg.split("-").map(translateDowNumber).join("-") : seg)
|
|
154
|
+
.join("/"))
|
|
155
|
+
.join(",");
|
|
156
|
+
}
|
|
157
|
+
const SPECIFIED = (v) => v !== "*" && v !== "?";
|
|
158
|
+
/**
|
|
159
|
+
* Translate a node-cron expression (5-field `min hour dom month dow`, or 6-field
|
|
160
|
+
* with a leading seconds column) into a neutral AWS-dialect cron `Schedule`.
|
|
161
|
+
* Throws a clear, located error for anything EventBridge can't express.
|
|
162
|
+
*
|
|
163
|
+
* NOTE on the seconds column: EventBridge has a 1-minute floor, so the only
|
|
164
|
+
* seconds value we accept is `0` ("at the top of the minute"), which we drop.
|
|
165
|
+
* Any other seconds value is a sub-minute or second-offset schedule and is
|
|
166
|
+
* rejected rather than approximated.
|
|
167
|
+
*/
|
|
168
|
+
export function nestCronToSchedule(expr, where) {
|
|
169
|
+
const parts = expr.trim().split(/\s+/);
|
|
170
|
+
if (parts.length !== 5 && parts.length !== 6) {
|
|
171
|
+
throw new Error(`schedule at ${where}: "${expr}" is not a 5- or 6-field cron expression.`);
|
|
172
|
+
}
|
|
173
|
+
let fields = parts;
|
|
174
|
+
if (parts.length === 6) {
|
|
175
|
+
const seconds = parts[0];
|
|
176
|
+
if (seconds !== "0") {
|
|
177
|
+
throw new Error(`schedule at ${where}: "${expr}" uses a sub-minute seconds field ("${seconds}"). ` +
|
|
178
|
+
`EventBridge has a 1-minute minimum granularity, so only a seconds value of "0" is supported.`);
|
|
179
|
+
}
|
|
180
|
+
fields = parts.slice(1);
|
|
181
|
+
}
|
|
182
|
+
let dayOfMonth = stripZeros(fields[2]);
|
|
183
|
+
const month = stripZeros(fields[3]);
|
|
184
|
+
let dayOfWeek = translateDow(fields[4]);
|
|
185
|
+
const minute = normalizeField(stripZeros(fields[0]), 0, 59);
|
|
186
|
+
const hour = normalizeField(stripZeros(fields[1]), 0, 23);
|
|
187
|
+
// EventBridge forbids specifying BOTH day-of-month and day-of-week; exactly one
|
|
188
|
+
// must be `?`. Unix cron allows `* * `, so we pick the `?` for whichever side the
|
|
189
|
+
// user didn't constrain — and reject the genuinely-ambiguous "both constrained".
|
|
190
|
+
const domSpec = SPECIFIED(dayOfMonth);
|
|
191
|
+
const dowSpec = SPECIFIED(dayOfWeek);
|
|
192
|
+
if (domSpec && dowSpec) {
|
|
193
|
+
throw new Error(`schedule at ${where}: "${expr}" constrains both day-of-month and day-of-week. ` +
|
|
194
|
+
`EventBridge cron can't AND them — set one of the two to "*".`);
|
|
195
|
+
}
|
|
196
|
+
if (dowSpec)
|
|
197
|
+
dayOfMonth = "?";
|
|
198
|
+
else
|
|
199
|
+
dayOfWeek = "?";
|
|
200
|
+
return {
|
|
201
|
+
kind: "cron",
|
|
202
|
+
expression: `${minute} ${hour} ${dayOfMonth} ${month} ${dayOfWeek} *`,
|
|
203
|
+
dialect: "aws",
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Translate `@Interval(ms)` into a neutral rate `Schedule`. Unlike `@Cron`,
|
|
208
|
+
* `@Interval` genuinely means "every N milliseconds", which maps to EventBridge's
|
|
209
|
+
* clock-independent `rate(...)`. EventBridge's floor is one minute, so the
|
|
210
|
+
* interval must be a whole number of minutes.
|
|
211
|
+
*/
|
|
212
|
+
export function intervalToSchedule(ms, where) {
|
|
213
|
+
if (!Number.isInteger(ms) || ms <= 0) {
|
|
214
|
+
throw new Error(`@Interval at ${where}: interval must be a positive integer of milliseconds, got ${ms}.`);
|
|
215
|
+
}
|
|
216
|
+
if (ms % 60000 !== 0) {
|
|
217
|
+
throw new Error(`@Interval at ${where}: ${ms}ms is not a whole number of minutes. ` +
|
|
218
|
+
`EventBridge has a 1-minute minimum granularity, so intervals must be multiples of 60000ms.`);
|
|
219
|
+
}
|
|
220
|
+
return rate(ms / 60000, "minutes");
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=nest-schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nest-schedule.js","sourceRoot":"","sources":["../src/nest-schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAiB,MAAM,eAAe,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,CAAN,IAAY,cAoFX;AApFD,WAAY,cAAc;IACxB,8CAA4B,CAAA;IAC5B,mDAAiC,CAAA;IACjC,qDAAmC,CAAA;IACnC,qDAAmC,CAAA;IACnC,8CAA4B,CAAA;IAC5B,mDAAiC,CAAA;IACjC,qDAAmC,CAAA;IACnC,qDAAmC,CAAA;IACnC,+CAA6B,CAAA;IAC7B,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,oDAAkC,CAAA;IAClC,oDAAkC,CAAA;IAClC,oDAAkC,CAAA;IAClC,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,iDAA+B,CAAA;IAC/B,kDAAgC,CAAA;IAChC,kDAAgC,CAAA;IAChC,qDAAmC,CAAA;IACnC,0CAAwB,CAAA;IACxB,+CAA6B,CAAA;IAC7B,+CAA6B,CAAA;IAC7B,kEAAgD,CAAA;IAChD,+DAA6C,CAAA;IAC7C,gDAA8B,CAAA;IAC9B,yEAAuD,CAAA;IACvD,iDAA+B,CAAA;IAC/B,+CAA6B,CAAA;IAC7B,gDAA8B,CAAA;IAC9B,0CAAwB,CAAA;IACxB,4EAA0D,CAAA;IAC1D,4EAA0D,CAAA;IAC1D,8EAA4D,CAAA;IAC5D,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,iEAA+C,CAAA;IAC/C,6DAA2C,CAAA;IAC3C,6DAA2C,CAAA;IAC3C,iEAA+C,CAAA;IAC/C,6DAA2C,CAAA;IAC3C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,4DAA0C,CAAA;IAC1C,6DAA2C,CAAA;IAC3C,6DAA2C,CAAA;AAC7C,CAAC,EApFW,cAAc,KAAd,cAAc,QAoFzB;AAED,+FAA+F;AAC/F,MAAM,CAAC,MAAM,sBAAsB,GAA2B,MAAM,CAAC,WAAW,CAC9E,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAC9C,CAAC;AAE5B;;;;GAIG;AACH,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IAC7D,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,eAAe,CAAC,CAAC;IACvD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IACvD,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,QAAQ;QAAE,OAAO,GAAG,CAAC;IACzB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,4FAA4F;AAC5F,SAAS,kBAAkB,CAAC,KAAa;IACvC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,mDAAmD;IAC3F,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,uDAAuD;IACzF,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,oFAAoF;AACpF,SAAS,YAAY,CAAC,KAAa;IACjC,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IACjD,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACZ,IAAI;SACD,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;IACd,uFAAuF;IACvF,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CACjE;SACA,IAAI,CAAC,GAAG,CAAC,CACb;SACA,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC;AAEjE;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,KAAa;IAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CACb,eAAe,KAAK,MAAM,IAAI,2CAA2C,CAC1E,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,eAAe,KAAK,MAAM,IAAI,uCAAuC,OAAO,MAAM;gBAChF,8FAA8F,CACjG,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAE1D,gFAAgF;IAChF,kFAAkF;IAClF,iFAAiF;IACjF,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,eAAe,KAAK,MAAM,IAAI,kDAAkD;YAC9E,8DAA8D,CACjE,CAAC;IACJ,CAAC;IACD,IAAI,OAAO;QAAE,UAAU,GAAG,GAAG,CAAC;;QACzB,SAAS,GAAG,GAAG,CAAC;IAErB,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE,GAAG,MAAM,IAAI,IAAI,IAAI,UAAU,IAAI,KAAK,IAAI,SAAS,IAAI;QACrE,OAAO,EAAE,KAAK;KACf,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAU,EAAE,KAAa;IAC1D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,gBAAgB,KAAK,8DAA8D,EAAE,GAAG,CAAC,CAAC;IAC5G,CAAC;IACD,IAAI,EAAE,GAAG,KAAK,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,gBAAgB,KAAK,KAAK,EAAE,uCAAuC;YACjE,4FAA4F,CAC/F,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schedule representation. laranja stores schedules in a PROVIDER-NEUTRAL
|
|
3
|
+
* structured form so the back half can lower them to whatever the target cloud
|
|
4
|
+
* expects (AWS EventBridge `rate(...)`/`cron(...)`, GCP/Cloudflare Unix cron,
|
|
5
|
+
* Azure NCRONTAB, …). The front half never bakes in a provider string.
|
|
6
|
+
*
|
|
7
|
+
* `rate` ("every N units") is portable across every provider. `cron` carries a
|
|
8
|
+
* raw expression tagged with its dialect — an explicit escape hatch (only "aws"
|
|
9
|
+
* exists today; new dialects land with their providers).
|
|
10
|
+
*
|
|
11
|
+
* The builders are pure, which lets the static scanner constant-fold calls like
|
|
12
|
+
* `@Cron(rate(5, "minutes"))` at scan time without executing user code.
|
|
13
|
+
*/
|
|
14
|
+
/** Units accepted by the `rate()` builder (singular or plural, for ergonomics). */
|
|
15
|
+
export type RateUnit = "minute" | "minutes" | "hour" | "hours" | "day" | "days";
|
|
16
|
+
/** Canonical singular unit stored in the IR. */
|
|
17
|
+
export type ScheduleUnit = "minute" | "hour" | "day";
|
|
18
|
+
/** Provider-neutral schedule stored in the IR. */
|
|
19
|
+
export type Schedule = {
|
|
20
|
+
kind: "rate";
|
|
21
|
+
value: number;
|
|
22
|
+
unit: ScheduleUnit;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "cron";
|
|
25
|
+
expression: string;
|
|
26
|
+
dialect: "aws";
|
|
27
|
+
};
|
|
28
|
+
/** Anything accepted where a schedule is expected: structured, or a raw string. */
|
|
29
|
+
export type ScheduleInput = Schedule | string;
|
|
30
|
+
/**
|
|
31
|
+
* Builds a neutral "every N units" schedule.
|
|
32
|
+
*
|
|
33
|
+
* @example rate(5, "minutes") // { kind: "rate", value: 5, unit: "minute" }
|
|
34
|
+
* @example rate(1, "hour") // { kind: "rate", value: 1, unit: "hour" }
|
|
35
|
+
*/
|
|
36
|
+
export declare function rate(value: number, unit: RateUnit): Schedule;
|
|
37
|
+
/**
|
|
38
|
+
* Shorthand for `rate(1, unit)`.
|
|
39
|
+
* @example every("day") // { kind: "rate", value: 1, unit: "day" }
|
|
40
|
+
*/
|
|
41
|
+
export declare function every(unit: ScheduleUnit): Schedule;
|
|
42
|
+
/**
|
|
43
|
+
* Parse a raw AWS schedule STRING (`"rate(5 minutes)"` / `"cron(0 12 * * ? *)"`)
|
|
44
|
+
* into the neutral structured form. Returns undefined for anything that isn't a
|
|
45
|
+
* valid AWS expression (e.g. a 5-field Unix cron string), so callers can raise a
|
|
46
|
+
* clear error. (Other dialects' string parsing arrives with their providers.)
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseScheduleString(s: string): Schedule | undefined;
|
|
49
|
+
/** Throws a clear, located error if `s` isn't a valid schedule. */
|
|
50
|
+
export declare function assertSchedule(s: Schedule, where: string): void;
|
|
51
|
+
/**
|
|
52
|
+
* Human-readable description of a Schedule — the single source of truth for how a
|
|
53
|
+
* schedule is shown to a user (the CLI `plan` table and the dashboard both call
|
|
54
|
+
* this, so the wording never drifts). `rate` renders structurally; `cron` is
|
|
55
|
+
* normalized from our AWS dialect to standard Unix cron and handed to cronstrue.
|
|
56
|
+
* Anything cronstrue can't parse falls back to the raw expression, so we never
|
|
57
|
+
* show a misleading label.
|
|
58
|
+
*
|
|
59
|
+
* @example describeSchedule({ kind: "rate", value: 5, unit: "minute" }) // "Every 5 minutes"
|
|
60
|
+
* @example describeSchedule({ kind: "cron", expression: "* * * * ? *", dialect: "aws" }) // "Every minute"
|
|
61
|
+
*/
|
|
62
|
+
export declare function describeSchedule(schedule: Schedule): string;
|