@cronvello/sdk 0.2.1 → 0.4.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.
- package/CHANGELOG.md +56 -0
- package/README.md +102 -15
- package/dist/cli.cjs +990 -216
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +990 -216
- package/dist/cli.js.map +1 -1
- package/dist/dev.cjs +1001 -217
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.d.cts +5 -0
- package/dist/dev.d.ts +5 -0
- package/dist/dev.js +1001 -217
- package/dist/dev.js.map +1 -1
- package/dist/{dispatch-handler-BoadpsL9.d.cts → dispatch-handler-yHIFEnNG.d.cts} +17 -5
- package/dist/{dispatch-handler-BoadpsL9.d.ts → dispatch-handler-yHIFEnNG.d.ts} +17 -5
- package/dist/express.d.cts +1 -1
- package/dist/express.d.ts +1 -1
- package/dist/index.cjs +191 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +280 -10
- package/dist/index.d.ts +280 -10
- package/dist/index.js +191 -26
- package/dist/index.js.map +1 -1
- package/dist/next.d.cts +1 -1
- package/dist/next.d.ts +1 -1
- package/docs/dashboard.png +0 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -543,8 +543,13 @@ function createDispatcher(state) {
|
|
|
543
543
|
if (req.method.toUpperCase() !== "POST") {
|
|
544
544
|
return resp(405, { ok: false, error: "Method not allowed" });
|
|
545
545
|
}
|
|
546
|
+
const secret = state.dispatchSecret;
|
|
547
|
+
if (!secret) {
|
|
548
|
+
log.error?.("[cronvello] dispatch refused: no `dispatchSecret` configured on this app");
|
|
549
|
+
return resp(500, { ok: false, error: "Dispatch is not configured" });
|
|
550
|
+
}
|
|
546
551
|
const token = parseBearer(req.authorization);
|
|
547
|
-
if (!token || !timingSafeEqual(token,
|
|
552
|
+
if (!token || !timingSafeEqual(token, secret)) {
|
|
548
553
|
log.warn?.("[cronvello] dispatch rejected: bad or missing bearer token");
|
|
549
554
|
return resp(401, { ok: false, error: "Unauthorized" });
|
|
550
555
|
}
|
|
@@ -575,7 +580,7 @@ function createDispatcher(state) {
|
|
|
575
580
|
const isAsync = callback !== null;
|
|
576
581
|
const ctx = buildContext(key, job, req, body, isAsync, "dispatch");
|
|
577
582
|
if (callback) {
|
|
578
|
-
const work = runAndReportCallback(job, ctx, callback,
|
|
583
|
+
const work = runAndReportCallback(job, ctx, callback, secret, log, invokeHandler);
|
|
579
584
|
if (req.waitUntil) req.waitUntil(work);
|
|
580
585
|
return resp(202, { ok: true, job: key, accepted: true });
|
|
581
586
|
}
|
|
@@ -1187,6 +1192,7 @@ var LocalEngine = class {
|
|
|
1187
1192
|
started = false;
|
|
1188
1193
|
stopped = false;
|
|
1189
1194
|
signalCleanup = null;
|
|
1195
|
+
startedAtMs = null;
|
|
1190
1196
|
constructor(jobs, runner, options = {}) {
|
|
1191
1197
|
this.clock = options.clock ?? realClock;
|
|
1192
1198
|
if (options.onEvent) this.listeners.add(options.onEvent);
|
|
@@ -1235,7 +1241,8 @@ var LocalEngine = class {
|
|
|
1235
1241
|
if (this.started) return this;
|
|
1236
1242
|
this.started = true;
|
|
1237
1243
|
this.stopped = false;
|
|
1238
|
-
this.
|
|
1244
|
+
this.startedAtMs = this.clock.now();
|
|
1245
|
+
this.emit({ type: "engine-start", jobs: this.states.length, at: this.startedAtMs });
|
|
1239
1246
|
for (const state of this.states) {
|
|
1240
1247
|
if (state.isReboot) {
|
|
1241
1248
|
this.launch(state);
|
|
@@ -1299,6 +1306,14 @@ var LocalEngine = class {
|
|
|
1299
1306
|
get activeRuns() {
|
|
1300
1307
|
return this.inFlight.size;
|
|
1301
1308
|
}
|
|
1309
|
+
/** Epoch ms of the `start()` call, or null while the engine has never been started. */
|
|
1310
|
+
get startedAt() {
|
|
1311
|
+
return this.startedAtMs;
|
|
1312
|
+
}
|
|
1313
|
+
/** True between `start()` and `stop()`. */
|
|
1314
|
+
get running() {
|
|
1315
|
+
return this.started && !this.stopped;
|
|
1316
|
+
}
|
|
1302
1317
|
// ── Scheduling ─────────────────────────────────────────────────────────────
|
|
1303
1318
|
scheduleNext(state) {
|
|
1304
1319
|
if (this.stopped) return;
|
|
@@ -1493,14 +1508,20 @@ function defineCronvello(config) {
|
|
|
1493
1508
|
}
|
|
1494
1509
|
const jobs = normalizeJobs(config.jobs, validate);
|
|
1495
1510
|
const dispatchPath = normalizePath(config.dispatchPath ?? DEFAULT_DISPATCH_PATH);
|
|
1496
|
-
|
|
1497
|
-
const
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1511
|
+
let clientInstance;
|
|
1512
|
+
const getClient = () => {
|
|
1513
|
+
if (!clientInstance) {
|
|
1514
|
+
requireCloud(config, ["apiKey"], "Talking to the Cronvello API");
|
|
1515
|
+
clientInstance = new CronvelloClient({
|
|
1516
|
+
apiKey: config.apiKey,
|
|
1517
|
+
baseUrl: config.baseUrl ?? CRONVELLO_DEFAULT_BASE_URL,
|
|
1518
|
+
...config.timeoutMs !== void 0 ? { timeoutMs: config.timeoutMs } : {},
|
|
1519
|
+
...config.maxRetries !== void 0 ? { maxRetries: config.maxRetries } : {},
|
|
1520
|
+
...config.fetch ? { fetch: config.fetch } : {}
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
return clientInstance;
|
|
1524
|
+
};
|
|
1504
1525
|
const dispatcher = createDispatcher({
|
|
1505
1526
|
jobs,
|
|
1506
1527
|
dispatchSecret: config.dispatchSecret,
|
|
@@ -1509,17 +1530,29 @@ function defineCronvello(config) {
|
|
|
1509
1530
|
...config.maxBodyBytes !== void 0 ? { maxBodyBytes: config.maxBodyBytes } : {}
|
|
1510
1531
|
});
|
|
1511
1532
|
const app = {
|
|
1512
|
-
client
|
|
1533
|
+
get client() {
|
|
1534
|
+
return getClient();
|
|
1535
|
+
},
|
|
1513
1536
|
jobs,
|
|
1514
1537
|
appName: config.appName,
|
|
1515
1538
|
dispatchPath,
|
|
1516
|
-
dispatchUrl
|
|
1539
|
+
get dispatchUrl() {
|
|
1540
|
+
requireCloud(config, ["appUrl"], "Building the dispatch URL");
|
|
1541
|
+
return joinUrl(config.appUrl, dispatchPath);
|
|
1542
|
+
},
|
|
1543
|
+
get isCloudConfigured() {
|
|
1544
|
+
return missingCloudFields(config, CLOUD_FIELDS).length === 0;
|
|
1545
|
+
},
|
|
1517
1546
|
async sync(options) {
|
|
1547
|
+
requireCloud(config, CLOUD_FIELDS, "Syncing your jobs to Cronvello");
|
|
1548
|
+
const client = getClient();
|
|
1549
|
+
const dispatchUrl = joinUrl(config.appUrl, dispatchPath);
|
|
1550
|
+
const dispatchSecret = config.dispatchSecret;
|
|
1518
1551
|
const opts = options ?? {};
|
|
1519
1552
|
if (!opts.dryRun) {
|
|
1520
1553
|
try {
|
|
1521
1554
|
const res = await client.reconcileRegistry(
|
|
1522
|
-
buildRegistryRequest(config, dispatchUrl, defaultTimeZone, [...jobs.values()], opts)
|
|
1555
|
+
buildRegistryRequest(config, dispatchSecret, dispatchUrl, defaultTimeZone, [...jobs.values()], opts)
|
|
1523
1556
|
);
|
|
1524
1557
|
return {
|
|
1525
1558
|
jobId: res.job.id,
|
|
@@ -1547,7 +1580,7 @@ function defineCronvello(config) {
|
|
|
1547
1580
|
client,
|
|
1548
1581
|
appName: config.appName,
|
|
1549
1582
|
dispatchUrl,
|
|
1550
|
-
dispatchSecret
|
|
1583
|
+
dispatchSecret,
|
|
1551
1584
|
defaultTimeZone,
|
|
1552
1585
|
jobs: [...jobs.values()]
|
|
1553
1586
|
},
|
|
@@ -1558,6 +1591,7 @@ function defineCronvello(config) {
|
|
|
1558
1591
|
if (!jobs.has(key)) {
|
|
1559
1592
|
throw new CronvelloConfigError(`Unknown job '${key}'. Known: ${[...jobs.keys()].join(", ") || "(none)"}`);
|
|
1560
1593
|
}
|
|
1594
|
+
const client = getClient();
|
|
1561
1595
|
const containers = await client.jobs.list();
|
|
1562
1596
|
const container = containers.find((j) => j.name === config.appName);
|
|
1563
1597
|
if (!container) {
|
|
@@ -1572,8 +1606,16 @@ function defineCronvello(config) {
|
|
|
1572
1606
|
},
|
|
1573
1607
|
trigger: (key, payload) => dispatcher.runLocal(key, payload),
|
|
1574
1608
|
handle: dispatcher.handle,
|
|
1575
|
-
|
|
1576
|
-
|
|
1609
|
+
// Mounting a dispatch route that could only ever answer "not configured" hides the real
|
|
1610
|
+
// mistake behind a runtime 500, so both adapters fail at mount time instead.
|
|
1611
|
+
expressHandler: () => {
|
|
1612
|
+
requireCloud(config, ["dispatchSecret"], "Mounting the dispatch handler");
|
|
1613
|
+
return expressHandler(app);
|
|
1614
|
+
},
|
|
1615
|
+
nextHandler: () => {
|
|
1616
|
+
requireCloud(config, ["dispatchSecret"], "Mounting the dispatch handler");
|
|
1617
|
+
return nextHandler(app);
|
|
1618
|
+
},
|
|
1577
1619
|
dev(options) {
|
|
1578
1620
|
const { autoStart = true, dashboard, ...engineOptions } = options ?? {};
|
|
1579
1621
|
const engineJobs = buildEngineJobs([...jobs.values()], defaultTimeZone);
|
|
@@ -1623,7 +1665,9 @@ function buildEngineJobs(jobs, defaultTimeZone) {
|
|
|
1623
1665
|
!appUrl && "CRONVELLO_APP_URL (or PUBLIC_URL)"
|
|
1624
1666
|
].filter(Boolean);
|
|
1625
1667
|
if (missing.length) {
|
|
1626
|
-
throw new CronvelloConfigError(
|
|
1668
|
+
throw new CronvelloConfigError(
|
|
1669
|
+
`defineCronvello.fromEnv() is missing required env: ${missing.join(", ")}. To run locally with no account, use defineCronvello({ appName, jobs }) instead \u2014 it needs none of these.`
|
|
1670
|
+
);
|
|
1627
1671
|
}
|
|
1628
1672
|
return defineCronvello2({
|
|
1629
1673
|
...config,
|
|
@@ -1635,17 +1679,32 @@ function buildEngineJobs(jobs, defaultTimeZone) {
|
|
|
1635
1679
|
}
|
|
1636
1680
|
defineCronvello2.fromEnv = fromEnv;
|
|
1637
1681
|
})(defineCronvello || (defineCronvello = {}));
|
|
1682
|
+
var CLOUD_FIELDS = ["apiKey", "appUrl", "dispatchSecret"];
|
|
1683
|
+
var CLOUD_FIELD_HINT = {
|
|
1684
|
+
apiKey: "`apiKey` (crn_live_\u2026, from your Cronvello account)",
|
|
1685
|
+
appUrl: "`appUrl` (the public https URL of THIS app, where Cronvello delivers callbacks)",
|
|
1686
|
+
dispatchSecret: "`dispatchSecret` (a random 32-byte value: run `npx cronvello secret`)"
|
|
1687
|
+
};
|
|
1688
|
+
function missingCloudFields(config, fields) {
|
|
1689
|
+
return fields.filter((f) => !config[f]);
|
|
1690
|
+
}
|
|
1691
|
+
function requireCloud(config, fields, purpose) {
|
|
1692
|
+
const missing = missingCloudFields(config, fields);
|
|
1693
|
+
if (!missing.length) return;
|
|
1694
|
+
throw new CronvelloConfigError(
|
|
1695
|
+
`${purpose} needs config this app doesn't have: ${missing.map((f) => CLOUD_FIELD_HINT[f]).join(", ")}. Local runs (\`cronvello dev\`, \`trigger()\`) work without any of it.`
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1638
1698
|
function validateConfig(config) {
|
|
1639
1699
|
if (!config) throw new CronvelloConfigError("defineCronvello requires a config object.");
|
|
1640
1700
|
if (!config.appName || !config.appName.trim()) throw new CronvelloConfigError("`appName` is required.");
|
|
1641
|
-
if (!config.
|
|
1701
|
+
if (!config.jobs) throw new CronvelloConfigError("`jobs` is required.");
|
|
1702
|
+
if (config.appUrl !== void 0 && !/^https?:\/\//i.test(config.appUrl)) {
|
|
1642
1703
|
throw new CronvelloConfigError("`appUrl` must be an absolute http(s) URL (the public URL of THIS app).");
|
|
1643
1704
|
}
|
|
1644
|
-
if (
|
|
1645
|
-
|
|
1646
|
-
throw new CronvelloConfigError("`dispatchSecret` is required and must be at least 16 chars (use a random 32-byte value).");
|
|
1705
|
+
if (config.dispatchSecret !== void 0 && config.dispatchSecret.length < 16) {
|
|
1706
|
+
throw new CronvelloConfigError("`dispatchSecret` must be at least 16 chars (use a random 32-byte value).");
|
|
1647
1707
|
}
|
|
1648
|
-
if (!config.jobs) throw new CronvelloConfigError("`jobs` is required.");
|
|
1649
1708
|
}
|
|
1650
1709
|
function normalizeJobs(input, validate) {
|
|
1651
1710
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -1682,14 +1741,14 @@ function normalizePath(path) {
|
|
|
1682
1741
|
function joinUrl(base, path) {
|
|
1683
1742
|
return `${base.replace(/\/+$/, "")}${path}`;
|
|
1684
1743
|
}
|
|
1685
|
-
function buildRegistryRequest(config, dispatchUrl, defaultTimeZone, jobs, opts) {
|
|
1744
|
+
function buildRegistryRequest(config, dispatchSecret, dispatchUrl, defaultTimeZone, jobs, opts) {
|
|
1686
1745
|
const tasks = jobs.map((j) => {
|
|
1687
1746
|
const cfg = j.config;
|
|
1688
1747
|
const task = {
|
|
1689
1748
|
key: j.key,
|
|
1690
1749
|
schedule: cfg.schedule,
|
|
1691
1750
|
targetUrl: dispatchUrl,
|
|
1692
|
-
targetToken:
|
|
1751
|
+
targetToken: dispatchSecret,
|
|
1693
1752
|
method: "POST",
|
|
1694
1753
|
timeZone: cfg.timeZone ?? defaultTimeZone,
|
|
1695
1754
|
requestBody: JSON.stringify({ job: j.key, ...cfg.payload ?? {} })
|
|
@@ -1855,6 +1914,112 @@ function field(value, min, max, label) {
|
|
|
1855
1914
|
return value;
|
|
1856
1915
|
}
|
|
1857
1916
|
|
|
1917
|
+
// src/client/admin-client.ts
|
|
1918
|
+
var CronvelloAdminClient = class {
|
|
1919
|
+
transport;
|
|
1920
|
+
/** The resolved base URL in use. */
|
|
1921
|
+
baseUrl;
|
|
1922
|
+
/** Registration, status, key rotation and removal of external apps. */
|
|
1923
|
+
externalApps;
|
|
1924
|
+
constructor(options) {
|
|
1925
|
+
if (!options || !options.serviceKey) {
|
|
1926
|
+
throw new CronvelloConfigError(
|
|
1927
|
+
"CronvelloAdminClient requires a `serviceKey` (Cronvello's backend-to-backend key, not an account apiKey)."
|
|
1928
|
+
);
|
|
1929
|
+
}
|
|
1930
|
+
this.baseUrl = (options.baseUrl ?? CRONVELLO_DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
1931
|
+
this.transport = new Transport({
|
|
1932
|
+
baseUrl: this.baseUrl,
|
|
1933
|
+
apiKey: options.serviceKey,
|
|
1934
|
+
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
|
|
1935
|
+
...options.maxRetries !== void 0 ? { maxRetries: options.maxRetries } : {},
|
|
1936
|
+
...options.fetch ? { fetch: options.fetch } : {},
|
|
1937
|
+
...options.onRequest ? { onRequest: options.onRequest } : {}
|
|
1938
|
+
});
|
|
1939
|
+
this.externalApps = new ExternalAppsResource(this.transport);
|
|
1940
|
+
}
|
|
1941
|
+
};
|
|
1942
|
+
var ExternalAppsResource = class {
|
|
1943
|
+
constructor(t) {
|
|
1944
|
+
this.t = t;
|
|
1945
|
+
}
|
|
1946
|
+
t;
|
|
1947
|
+
/**
|
|
1948
|
+
* Idempotent upsert, keyed on the string `appId`: creates when unknown, updates credentials
|
|
1949
|
+
* and URL when it already exists. Safe to retry and to re-run on every provisioning pass.
|
|
1950
|
+
*
|
|
1951
|
+
* When the server mints the token (`generateApiKey: true` on a *new* app) it comes back as
|
|
1952
|
+
* `generatedApiKey` — plaintext, exactly once. On an update it is `null`.
|
|
1953
|
+
*/
|
|
1954
|
+
register(input) {
|
|
1955
|
+
assertRegisterInput(input);
|
|
1956
|
+
return this.t.request({ method: "POST", path: "/external-apps/service/register", body: input });
|
|
1957
|
+
}
|
|
1958
|
+
/** Registration status, last-sync info and job count for one app, by its string `appId`. */
|
|
1959
|
+
status(appId) {
|
|
1960
|
+
assertAppId(appId, "status");
|
|
1961
|
+
return this.t.request({ method: "GET", path: `/external-apps/service/status/${enc2(appId)}` });
|
|
1962
|
+
}
|
|
1963
|
+
/**
|
|
1964
|
+
* Mint a fresh per-app token, by string `appId`. The new token is returned once as `newApiKey`
|
|
1965
|
+
* and must be written into the app's environment — the previous one stops working.
|
|
1966
|
+
*
|
|
1967
|
+
* Use this for drift recovery when the current token is no longer known.
|
|
1968
|
+
*/
|
|
1969
|
+
rotateKey(appId) {
|
|
1970
|
+
assertAppId(appId, "rotateKey");
|
|
1971
|
+
return this.t.request({ method: "POST", path: `/external-apps/service/rotate-key/${enc2(appId)}` });
|
|
1972
|
+
}
|
|
1973
|
+
/**
|
|
1974
|
+
* Delete a registration, cascading its jobs and tasks.
|
|
1975
|
+
*
|
|
1976
|
+
* ⚠ This one takes the **numeric** {@link ExternalApp.id}, not the string `appId` the other
|
|
1977
|
+
* three methods take — an asymmetry in the server's route contract. Read the id off a
|
|
1978
|
+
* `register()` result (or a prior lookup); passing a string `appId` here is rejected locally.
|
|
1979
|
+
*/
|
|
1980
|
+
delete(id) {
|
|
1981
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
1982
|
+
throw new CronvelloConfigError(
|
|
1983
|
+
`externalApps.delete() takes the numeric app id (ExternalApp.id), not the string appId \u2014 received ${JSON.stringify(id)}.`
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
return this.t.request({ method: "DELETE", path: `/external-apps/service/delete/${id}` });
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
function assertRegisterInput(input) {
|
|
1990
|
+
if (!input || typeof input !== "object") {
|
|
1991
|
+
throw new CronvelloConfigError("externalApps.register() requires an input object.");
|
|
1992
|
+
}
|
|
1993
|
+
if (!input.appId || !input.appId.trim()) {
|
|
1994
|
+
throw new CronvelloConfigError("externalApps.register() requires a non-empty `appId`.");
|
|
1995
|
+
}
|
|
1996
|
+
if (!input.name || !input.name.trim()) {
|
|
1997
|
+
throw new CronvelloConfigError("externalApps.register() requires a non-empty `name`.");
|
|
1998
|
+
}
|
|
1999
|
+
if (!input.base_url && input.targetUrl === void 0) {
|
|
2000
|
+
throw new CronvelloConfigError("externalApps.register() requires either `base_url` or `targetUrl`.");
|
|
2001
|
+
}
|
|
2002
|
+
const authMethod = input.authMethod ?? (input.oauthClientId || input.oauthClientSecret ? "oauth" : "api_key");
|
|
2003
|
+
if (authMethod === "api_key" && !input.apiKey && !input.generateApiKey) {
|
|
2004
|
+
throw new CronvelloConfigError(
|
|
2005
|
+
"externalApps.register() with api_key auth requires either `apiKey` or `generateApiKey: true`."
|
|
2006
|
+
);
|
|
2007
|
+
}
|
|
2008
|
+
if (authMethod === "oauth" && (!input.oauthClientId || !input.oauthClientSecret)) {
|
|
2009
|
+
throw new CronvelloConfigError(
|
|
2010
|
+
"externalApps.register() with oauth auth requires both `oauthClientId` and `oauthClientSecret`."
|
|
2011
|
+
);
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
function assertAppId(appId, method) {
|
|
2015
|
+
if (typeof appId !== "string" || !appId.trim()) {
|
|
2016
|
+
throw new CronvelloConfigError(`externalApps.${method}() requires a non-empty string appId.`);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
function enc2(segment) {
|
|
2020
|
+
return encodeURIComponent(segment);
|
|
2021
|
+
}
|
|
2022
|
+
|
|
1858
2023
|
// src/index.ts
|
|
1859
2024
|
function generateDispatchSecret(bytes = 32) {
|
|
1860
2025
|
const buf = new Uint8Array(bytes);
|
|
@@ -1862,6 +2027,6 @@ function generateDispatchSecret(bytes = 32) {
|
|
|
1862
2027
|
return Array.from(buf).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1863
2028
|
}
|
|
1864
2029
|
|
|
1865
|
-
export { CRONVELLO_DEFAULT_BASE_URL, CronvelloApiError, CronvelloClient, CronvelloConfigError, CronvelloError, CronvelloNetworkError, cron, daily, defineCronvello, every, everyHours, everyMinutes, formatSyncResult, generateDispatchSecret, hourly, isValidTimeZone, monthly, nextOccurrence, previewSchedule, schedule, validateCron, weekdays, weekends, weekly };
|
|
2030
|
+
export { CRONVELLO_DEFAULT_BASE_URL, CronvelloAdminClient, CronvelloApiError, CronvelloClient, CronvelloConfigError, CronvelloError, CronvelloNetworkError, cron, daily, defineCronvello, every, everyHours, everyMinutes, formatSyncResult, generateDispatchSecret, hourly, isValidTimeZone, monthly, nextOccurrence, previewSchedule, schedule, validateCron, weekdays, weekends, weekly };
|
|
1866
2031
|
//# sourceMappingURL=index.js.map
|
|
1867
2032
|
//# sourceMappingURL=index.js.map
|