@prisma/composer-prisma-cloud 0.3.0-dev.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/compute-main.mjs +4 -20
  2. package/dist/compute-main.mjs.map +1 -1
  3. package/dist/control.d.mts +1 -1
  4. package/dist/control.mjs +17 -28
  5. package/dist/control.mjs.map +1 -1
  6. package/dist/cron/index.d.mts +26 -33
  7. package/dist/cron/index.d.mts.map +1 -1
  8. package/dist/cron/index.mjs +77 -202
  9. package/dist/cron/index.mjs.map +1 -1
  10. package/dist/cron/scheduler-entrypoint.mjs +114 -133
  11. package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
  12. package/dist/cron/scheduler-service.mjs +76 -200
  13. package/dist/cron/scheduler-service.mjs.map +1 -1
  14. package/dist/email/email-entrypoint.mjs +126 -162
  15. package/dist/email/email-entrypoint.mjs.map +1 -1
  16. package/dist/email/email-service.mjs +79 -230
  17. package/dist/email/email-service.mjs.map +1 -1
  18. package/dist/email/index.d.mts +29 -33
  19. package/dist/email/index.d.mts.map +1 -1
  20. package/dist/email/index.mjs +84 -236
  21. package/dist/email/index.mjs.map +1 -1
  22. package/dist/email/testing.mjs +89 -112
  23. package/dist/email/testing.mjs.map +1 -1
  24. package/dist/index.d.mts +43 -51
  25. package/dist/index.d.mts.map +1 -1
  26. package/dist/index.mjs +51 -47
  27. package/dist/index.mjs.map +1 -1
  28. package/dist/local-target.mjs +1 -1
  29. package/dist/local-target.mjs.map +1 -1
  30. package/dist/{secret-BVGxqHxY-DYDfiULl.mjs → param-BTzY0ne5-CW6ojZ3E.mjs} +4 -45
  31. package/dist/param-BTzY0ne5-CW6ojZ3E.mjs.map +1 -0
  32. package/dist/{preflight-names-CpJUd9ZA-BCU-W3cT.mjs → preflight-names-BPL-qsZF-BfoRgbgb.mjs} +14 -30
  33. package/dist/{preflight-names-CpJUd9ZA-BCU-W3cT.mjs.map → preflight-names-BPL-qsZF-BfoRgbgb.mjs.map} +1 -1
  34. package/dist/{provisioned-edges-Cxy18aoh-CUnaY96r.mjs → provisioned-edges-C1wSO3cx-YC5C19f9.mjs} +3 -3
  35. package/dist/{provisioned-edges-Cxy18aoh-CUnaY96r.mjs.map → provisioned-edges-C1wSO3cx-YC5C19f9.mjs.map} +1 -1
  36. package/dist/secret-rz_ZqNeq-_xd97Jd9.mjs +47 -0
  37. package/dist/secret-rz_ZqNeq-_xd97Jd9.mjs.map +1 -0
  38. package/dist/serializer-CJiOhF2d-DJUjQj1i.mjs +251 -0
  39. package/dist/serializer-CJiOhF2d-DJUjQj1i.mjs.map +1 -0
  40. package/dist/{serializer-BD_6nkr4-DWn5NNTC.d.mts → serializer-Cx5slrV4-xJfH6EWS.d.mts} +2 -2
  41. package/dist/serializer-Cx5slrV4-xJfH6EWS.d.mts.map +1 -0
  42. package/dist/storage/index.d.mts +26 -31
  43. package/dist/storage/index.d.mts.map +1 -1
  44. package/dist/storage/index.mjs +89 -215
  45. package/dist/storage/index.mjs.map +1 -1
  46. package/dist/storage/storage-entrypoint.mjs +122 -147
  47. package/dist/storage/storage-entrypoint.mjs.map +1 -1
  48. package/dist/storage/storage-service.mjs +87 -212
  49. package/dist/storage/storage-service.mjs.map +1 -1
  50. package/dist/streams/index.d.mts +22 -29
  51. package/dist/streams/index.d.mts.map +1 -1
  52. package/dist/streams/index.mjs +88 -213
  53. package/dist/streams/index.mjs.map +1 -1
  54. package/dist/streams/streams-entrypoint.mjs +118 -139
  55. package/dist/streams/streams-entrypoint.mjs.map +1 -1
  56. package/dist/streams/streams-service.mjs +87 -212
  57. package/dist/streams/streams-service.mjs.map +1 -1
  58. package/dist/testing.d.mts +5 -19
  59. package/dist/testing.d.mts.map +1 -1
  60. package/dist/testing.mjs +3 -11
  61. package/dist/testing.mjs.map +1 -1
  62. package/package.json +18 -18
  63. package/dist/secret-BVGxqHxY-DYDfiULl.mjs.map +0 -1
  64. package/dist/serializer-BD_6nkr4-DWn5NNTC.d.mts.map +0 -1
  65. package/dist/serializer-sVE4UAmg-CikRngbR.mjs +0 -475
  66. package/dist/serializer-sVE4UAmg-CikRngbR.mjs.map +0 -1
@@ -1,11 +1,4 @@
1
1
  //#region ../../1-prisma-cloud/2-shared-modules/cron/dist/scheduler-entrypoint.mjs
2
- const nodeBuild = (opts) => ({
3
- extension: "@prisma/composer/node",
4
- type: "node",
5
- module: opts.module,
6
- entry: opts.entry,
7
- ...opts.dir === void 0 ? {} : { dir: opts.dir }
8
- });
9
2
  /**
10
3
  * **Last-resort escape hatch for unsafe type assertions. Not a sanctioned tool to reach for.**
11
4
  *
@@ -87,14 +80,18 @@ function freezeParams(params) {
87
80
  for (const [name, param] of Object.entries(params)) frozen[name] = Object.freeze({ ...param });
88
81
  return Object.freeze(frozen);
89
82
  }
83
+ function freezeSecrets(secrets) {
84
+ const frozen = {};
85
+ for (const [name, need] of Object.entries(secrets)) frozen[name] = Object.freeze({ ...need });
86
+ return blindCast(Object.freeze(frozen));
87
+ }
90
88
  /** A frozen shallow copy that keeps the caller's declared type. */
91
89
  function frozenShallowCopy(obj) {
92
90
  return blindCast(Object.freeze({ ...obj }));
93
91
  }
94
92
  /**
95
93
  * Constructs a branded, frozen Service node — declarations only (inputs,
96
- * params, the input schema, build adapter, and the ports it exposes). Pure;
97
- * carries no runtime behavior.
94
+ * params, build adapter, and the ports it exposes). Pure; carries no runtime behavior.
98
95
  */
99
96
  function service$1(def) {
100
97
  requireName(def.name, "service");
@@ -102,7 +99,8 @@ function service$1(def) {
102
99
  requireType(def.type, "service");
103
100
  requireConfigKeySegmentNames(Object.keys(def.inputs), "input", "service");
104
101
  requireConfigKeySegmentNames(Object.keys(def.params), "param", "service");
105
- if (def.input !== void 0 && typeof def.input["~standard"]?.validate !== "function") throw new Error("service() `input` must be a Standard Schema (an object with a \"~standard\".validate function) — see https://standardschema.dev (ADR-0042).");
102
+ requireConfigKeySegmentNames(Object.keys(def.secrets ?? {}), "secret", "service");
103
+ for (const slot of Object.keys(def.secrets ?? {})) if (Object.hasOwn(def.params, slot)) throw new Error(`service() secret slot "${slot}" collides with a param of the same name — a secret slot and a service param derive the same config key (COMPOSER_<addr>_${slot.toUpperCase()}); rename one.`);
106
104
  return Object.freeze({
107
105
  [NODE]: true,
108
106
  kind: "service",
@@ -111,7 +109,7 @@ function service$1(def) {
111
109
  type: def.type,
112
110
  inputs: frozenShallowCopy(def.inputs),
113
111
  params: freezeParams(def.params),
114
- inputSchema: blindCast(def.input),
112
+ secretSlots: freezeSecrets(def.secrets ?? blindCast({})),
115
113
  build: Object.freeze({ ...def.build }),
116
114
  expose: def.expose !== void 0 ? frozenShallowCopy(def.expose) : void 0
117
115
  });
@@ -144,16 +142,11 @@ function dependency(def) {
144
142
  * `JSON.stringify`, and `console.log`/`util.inspect` all print `[REDACTED]`, so
145
143
  * a secret can't leak through an accidental log or serialization.
146
144
  *
147
- * Every box carries a brand property keyed by the registered symbol
148
- * `Symbol.for('prisma:secret-box')`, which is what `isSecretString` checks. A
149
- * symbol key is invisible to `JSON.stringify` and `Object.keys`, so the box's
150
- * public shape still matches the platform's own `secrecy` type
151
- * (pdp-control-plane).
145
+ * Shape matches the platform's own `secrecy` type (pdp-control-plane). The class
146
+ * is nominal enough on its own — no phantom brand.
152
147
  */
153
148
  const REDACTED = "[REDACTED]";
154
- const SECRET_BOX = blindCast(Symbol.for("prisma:secret-box"));
155
149
  var SecretBox = class {
156
- [SECRET_BOX] = true;
157
150
  #value;
158
151
  constructor(value) {
159
152
  this.#value = value;
@@ -203,6 +196,10 @@ function string$1(opts = {}) {
203
196
  function number$1(opts = {}) {
204
197
  return withFacets(numberSchema, opts);
205
198
  }
199
+ /** A param over any caller-supplied Standard Schema — a structured `jobs`, say. */
200
+ function param(schema, opts = {}) {
201
+ return withFacets(schema, opts);
202
+ }
206
203
  /**
207
204
  * Synchronous hydrate — what the node's `load()` uses so
208
205
  * `const { db } = service.load()` reads without `await`. Requires every
@@ -219,6 +216,31 @@ function hydrateSync(root, config) {
219
216
  }
220
217
  return deps;
221
218
  }
219
+ /**
220
+ * Wraps each of a service's resolved secret values in a redacting `SecretBox`
221
+ * — what the node's `secrets()` accessor returns (ADR-0021, sibling to
222
+ * `load()`/`config()`). The RESOLUTION of a secret's value (the boot
223
+ * double-lookup that reads the platform var the pointer names) is the target
224
+ * pack's job; core is handed the already-resolved strings and only boxes them,
225
+ * so a secret is redacted by TYPE from here on. A declared slot missing from
226
+ * `values` is a target contract violation, named loudly.
227
+ */
228
+ function hydrateSecrets(root, values) {
229
+ const boxed = {};
230
+ for (const slot of Object.keys(root.secretSlots)) {
231
+ const value = values[slot];
232
+ if (value === void 0) throw new Error(`secret slot "${slot}" has no resolved value — the target must resolve every declared secret before hydrateSecrets().`);
233
+ boxed[slot] = new SecretBox(value);
234
+ }
235
+ return blindCast(boxed);
236
+ }
237
+ const nodeBuild = (opts) => ({
238
+ extension: "@prisma/composer/node",
239
+ type: "node",
240
+ module: opts.module,
241
+ entry: opts.entry,
242
+ ...opts.dir === void 0 ? {} : { dir: opts.dir }
243
+ });
222
244
  const liftArray = (data) => Array.isArray(data) ? data : [data];
223
245
  /**
224
246
  * Splits an array into two arrays based on the result of a predicate
@@ -7426,7 +7448,7 @@ function coerceEnvSourcedParam(raw, d, key) {
7426
7448
  /**
7427
7449
  * Boot: read each declared param from env by its key, reverse the param's own
7428
7450
  * serialization (missing/invalid fails loudly), assemble the typed Config.
7429
- * The input document rides its own channel (readInput), not this one.
7451
+ * Secrets ride a separate channel (deserializeSecrets), not this one.
7430
7452
  */
7431
7453
  const deserialize = (node, address) => {
7432
7454
  const service = {};
@@ -7463,84 +7485,40 @@ const stash = (node, config) => {
7463
7485
  process.env[configKey("", d)] = encode(d.owner, value);
7464
7486
  }
7465
7487
  };
7466
- /** The input document's own row name; its full key is COMPOSER_<addr>_INPUT. */
7467
- const INPUT_KEY_NAME = "INPUT";
7468
- /** The input document row's key for a service address. */
7469
- const inputKey = (address) => configKey(address, {
7488
+ /** The pointer-row key for a secret slot: COMPOSER_<addr>_<slot> (secrets are service-level). */
7489
+ const secretKey = (address, slot) => configKey(address, {
7470
7490
  owner: "service",
7471
- name: INPUT_KEY_NAME
7491
+ name: slot
7472
7492
  });
7473
- const SECRET_MARKER = "$secret";
7474
- const ESCAPED_KEY = /^\$\$+secret$/;
7475
- /** True for the framework's secret pointer: `{ "$secret": "<PLATFORM_VAR>" }` and nothing else. */
7476
- function isSecretPointer(value) {
7477
- return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 1 && SECRET_MARKER in value && typeof value[SECRET_MARKER] === "string";
7478
- }
7479
- /** A plain data object (not an array, not a class instance) — the only object shape a binding/document may nest. */
7480
- function isPlainObject(value) {
7481
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
7482
- const proto = Object.getPrototypeOf(value);
7483
- return proto === Object.prototype || proto === null;
7484
- }
7485
7493
  /**
7486
- * Boot: read the one input document row (address-free after run()'s
7487
- * re-stash), swap each `$secret` pointer for a redacting box over the named
7488
- * platform var, unescape reserved keys, validate with the service's own
7489
- * schema, and return the typed object. A missing row is a loud failure naming
7490
- * the env var — a deployed environment always writes it; a local harness must
7491
- * supply it (set the row to the serialized input document).
7494
+ * Boot: resolve every secret slot to its value by double-lookup read the
7495
+ * pointer key (the platform NAME), then read that platform var. A missing
7496
+ * pointer or a missing/empty platform value is a loud failure naming both keys.
7497
+ * Returns a plain Record for core's `hydrateSecrets` to box.
7492
7498
  */
7493
- function readInput(node, address) {
7494
- const schema = node.inputSchema;
7495
- if (schema === void 0) throw new Error(`input() called on service "${node.name}", which declares no input schema — declare \`input: <schema>\` on compute() to use it (ADR-0042).`);
7496
- const key = inputKey(address);
7497
- const raw = process.env[key];
7498
- if (raw === void 0 || raw === "") throw new Error(`this service's input is not available (env ${key} is unset) — a deployed environment writes it automatically; a local harness must supply it like any other config value (set ${key} to the serialized input document).`);
7499
- let parsed;
7500
- try {
7501
- parsed = JSON.parse(raw);
7502
- } catch (cause) {
7503
- const message = cause instanceof Error ? cause.message : String(cause);
7504
- throw new Error(`this service's input document is not valid JSON (env ${key}): ${message} — a deployed environment writes it automatically; a local harness must supply the serialized input document (set ${key} to it).`);
7505
- }
7506
- const hydrated = hydrateInputDocument(parsed, key);
7507
- try {
7508
- return standardValidateSync(schema, hydrated);
7509
- } catch (cause) {
7510
- const message = cause instanceof Error ? cause.message : String(cause);
7511
- throw new Error(`invalid input document (env ${key}): ${message}`);
7512
- }
7513
- }
7514
- /** Reverses the document encoding: `$secret` pointers become redacting boxes over the named platform vars; escaped reserved keys drop one "$". */
7515
- function hydrateInputDocument(value, key) {
7516
- if (isSecretPointer(value)) {
7517
- const name = value[SECRET_MARKER];
7518
- const secret = process.env[name];
7519
- if (secret === void 0 || secret === "") throw new Error(`secret input is not provisioned (env ${key} → ${name}): the platform var "${name}" is unset or empty.`);
7520
- return new SecretBox(secret);
7521
- }
7522
- if (Array.isArray(value)) return value.map((member) => hydrateInputDocument(member, key));
7523
- if (isPlainObject(value)) {
7524
- const out = {};
7525
- for (const [k, member] of Object.entries(value)) {
7526
- const read = ESCAPED_KEY.test(k) ? k.slice(1) : k;
7527
- out[read] = hydrateInputDocument(member, key);
7528
- }
7529
- return out;
7530
- }
7531
- return value;
7532
- }
7499
+ const deserializeSecrets = (node, address) => {
7500
+ const values = {};
7501
+ for (const slot of Object.keys(node.secretSlots)) {
7502
+ const key = secretKey(address, slot);
7503
+ const name = process.env[key];
7504
+ if (name === void 0 || name === "") throw new Error(`missing secret pointer for slot "${slot}" (env ${key}) — the deploy did not write it.`);
7505
+ const value = process.env[name];
7506
+ if (value === void 0 || value === "") throw new Error(`secret "${slot}" is not provisioned (env ${key} → ${name}): the platform var "${name}" is unset or empty.`);
7507
+ values[slot] = value;
7508
+ }
7509
+ return values;
7510
+ };
7533
7511
  /**
7534
- * run()'s setup step for the input document: re-emit the row under its
7535
- * address-free key, so the address-free `readInput` reads identically. The
7536
- * document carries pointers, never values — the values stay only in their
7537
- * platform vars.
7512
+ * run()'s setup step for secrets: re-emit each slot's pointer NAME under its
7513
+ * address-free key, so the address-free `deserializeSecrets` double-looks-up
7514
+ * identically. Never the value — the value stays only in the platform var.
7538
7515
  */
7539
- const stashInput = (node, address) => {
7540
- if (node.inputSchema === void 0) return;
7541
- const raw = process.env[inputKey(address)];
7542
- if (raw === void 0) return;
7543
- process.env[inputKey("")] = raw;
7516
+ const stashSecrets = (node, address) => {
7517
+ for (const slot of Object.keys(node.secretSlots)) {
7518
+ const name = process.env[secretKey(address, slot)];
7519
+ if (name === void 0) continue;
7520
+ process.env[secretKey("", slot)] = name;
7521
+ }
7544
7522
  };
7545
7523
  /**
7546
7524
  * Boot: for each reserved provider param, read its address-scoped row through
@@ -7830,24 +7808,20 @@ Object.freeze({
7830
7808
  });
7831
7809
  const reservedParams = { port: number$1({ default: 3e3 }) };
7832
7810
  /**
7833
- * A Prisma Compute service — declarations only (deps + one input schema +
7834
- * build + the ports it exposes), no descriptor. The reserved `port` param
7835
- * rides its own channel (ADR-0042 leaves it untouched); a dependency named
7836
- * like it fails at authoring.
7811
+ * A Prisma Compute service — declarations only (deps + params + build + the
7812
+ * ports it exposes), no descriptor. `params` merges with the reserved
7813
+ * `ReservedParams` (`port`); a user param whose name collides with a reserved
7814
+ * one fails at authoring, the same way a colliding dependency name does.
7837
7815
  *
7838
7816
  * · run(address, boot) — the process controller: deserialize the platform
7839
7817
  * environment (keyed off `address`, the extension's ONE env read) into a
7840
- * typed Config, re-emit it (and the input document row) under address-free
7841
- * process-local stash keys, then call boot() to start the app's entry.
7842
- * · load() / input() — called from inside the app's entry: read the stash;
7843
- * load() hydrates + memoizes the deps, input() parses the input document,
7844
- * replaces each `$secret` pointer with a redacting box over the named
7845
- * platform var, validates with the declared schema, and memoizes (ADR-0042).
7818
+ * typed Config, re-emit it under address-free process-local stash keys,
7819
+ * then call boot() to start the app's entry.
7820
+ * · load() / config() — called from inside the app's entry: read the stash;
7821
+ * load() hydrates + memoizes the deps, config() returns the typed params.
7822
+ * Separate accessors so a dep and a param never share a namespace (ADR-0021).
7846
7823
  * · origin() — this service's platform-assigned public origin, read from the
7847
7824
  * stash `run()` populates; memoized per process.
7848
- * · port() — this service's resolved reserved port (the value `run()` routes
7849
- * to and exports as PORT), read from that same stash via #processConfig();
7850
- * defaults to 3000 when the platform binds none.
7851
7825
  *
7852
7826
  * The underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
7853
7827
  * the control-plane registry key `prisma-composer deploy` resolves through the
@@ -7857,7 +7831,8 @@ const reservedParams = { port: number$1({ default: 3e3 }) };
7857
7831
  var ComputeService = class {
7858
7832
  #resolved;
7859
7833
  #loadedDeps;
7860
- #loadedInput;
7834
+ #loadedParams;
7835
+ #loadedSecrets;
7861
7836
  #origin;
7862
7837
  constructor(node) {
7863
7838
  Object.assign(this, node);
@@ -7870,7 +7845,7 @@ var ComputeService = class {
7870
7845
  const config = deserialize(this, address);
7871
7846
  stash(this, config);
7872
7847
  stashProviderParams(RESERVED_PROVIDER_PARAMS, address);
7873
- stashInput(this, address);
7848
+ stashSecrets(this, address);
7874
7849
  const port = config.service["port"];
7875
7850
  if (typeof port === "number") process.env["PORT"] = String(port);
7876
7851
  return boot();
@@ -7879,9 +7854,13 @@ var ComputeService = class {
7879
7854
  if (this.#loadedDeps === void 0) this.#loadedDeps = blindCast(hydrateSync(this, this.#processConfig()));
7880
7855
  return this.#loadedDeps;
7881
7856
  }
7882
- input() {
7883
- if (this.#loadedInput === void 0) this.#loadedInput = blindCast(readInput(this, ""));
7884
- return this.#loadedInput;
7857
+ config() {
7858
+ if (this.#loadedParams === void 0) this.#loadedParams = blindCast(this.#processConfig().service);
7859
+ return this.#loadedParams;
7860
+ }
7861
+ secrets() {
7862
+ if (this.#loadedSecrets === void 0) this.#loadedSecrets = blindCast(hydrateSecrets(this, deserializeSecrets(this, "")));
7863
+ return this.#loadedSecrets;
7885
7864
  }
7886
7865
  /** This service's platform-assigned public origin — read from the stash
7887
7866
  * run() populates and memoized per process. Throws if called before run()
@@ -7890,24 +7869,26 @@ var ComputeService = class {
7890
7869
  this.#origin ??= readOrigin();
7891
7870
  return this.#origin;
7892
7871
  }
7893
- /** This service's resolved reserved port — the value run() routes to and
7894
- * exports as PORT — read the same way load() reads the stash. Defaults to
7895
- * 3000 when the platform binds none. */
7896
- port() {
7897
- const port = this.#processConfig().service["port"];
7898
- if (typeof port !== "number") throw new Error(`service "${this.name}" resolved a non-numeric port — the reserved port param is number({ default: 3000 }), so a stashed config always carries a number here.`);
7899
- return port;
7900
- }
7901
7872
  };
7902
7873
  const compute = (def) => {
7903
- for (const reserved of Object.keys(reservedParams)) if (reserved in def.deps) throw new Error(`compute(): dependency "${reserved}" collides with the reserved service param of the same name — rename the dependency.`);
7874
+ const userParams = def.params ?? blindCast({});
7875
+ for (const reserved of Object.keys(reservedParams)) {
7876
+ if (reserved in def.deps) throw new Error(`compute(): dependency "${reserved}" collides with the reserved service param of the same name — rename the dependency.`);
7877
+ if (reserved in userParams) throw new Error(`compute(): param "${reserved}" collides with the reserved service param of the same name — rename the param.`);
7878
+ }
7879
+ for (const name of Object.keys(userParams)) if (name.toUpperCase() === "ORIGIN") throw new Error(`compute(): param "${name}" collides with the framework-written origin row — rename the param.`);
7880
+ for (const name of Object.keys(def.secrets ?? {})) if (name.toUpperCase() === "ORIGIN") throw new Error(`compute(): secret "${name}" collides with the framework-written origin row — rename the secret.`);
7881
+ const params = blindCast({
7882
+ ...userParams,
7883
+ ...reservedParams
7884
+ });
7904
7885
  const instance = new ComputeService(service$1({
7905
7886
  name: def.name,
7906
7887
  extension: "@prisma/composer-prisma-cloud",
7907
7888
  type: "compute",
7908
7889
  inputs: def.deps,
7909
- params: reservedParams,
7910
- ...def.input !== void 0 ? { input: def.input } : {},
7890
+ params,
7891
+ ...def.secrets !== void 0 ? { secrets: def.secrets } : {},
7911
7892
  build: def.build,
7912
7893
  ...def.expose !== void 0 ? { expose: def.expose } : {}
7913
7894
  }));
@@ -7958,25 +7939,25 @@ function parseEvery(s) {
7958
7939
  }
7959
7940
  /**
7960
7941
  * The reusable scheduler node and its firing logic. `cronScheduler` builds a
7961
- * `compute()` whose one input is the `jobs` schedule (bound at provision by
7962
- * `cron()`, ADR-0042) and whose only dependency is `trigger(jobId)`; nothing
7963
- * else about it varies per app. `runScheduler` is the pure, injectable firing
7964
- * loop the entrypoint (and its tests) drive.
7942
+ * `compute()` whose `jobs` param default is the app's schedule and whose only
7943
+ * dependency is `trigger(jobId)`; nothing else about it varies per app.
7944
+ * `runScheduler` is the pure, injectable firing loop the entrypoint (and its
7945
+ * tests) drive.
7965
7946
  */
7966
- const cronInputSchema = type({ jobs: type({
7947
+ const scheduleSchema = type({
7967
7948
  jobId: "string",
7968
7949
  every: "string"
7969
- }).array() });
7950
+ }).array();
7970
7951
  /**
7971
- * The always-on scheduler service. Job-agnostic: the schedule arrives as the
7972
- * `jobs` key of the input binding `cron()` supplies at provision, and the
7973
- * entrypoint reads it back through `input()`.
7952
+ * The always-on scheduler service. `schedule` sets only the `jobs` param's
7953
+ * default the value the deploy serializes into config; the scheduler
7954
+ * itself is job-agnostic.
7974
7955
  */
7975
- function cronScheduler() {
7956
+ function cronScheduler(schedule) {
7976
7957
  return compute({
7977
7958
  name: "scheduler",
7978
7959
  deps: { trigger: rpc(triggerContract) },
7979
- input: cronInputSchema,
7960
+ params: { jobs: param(scheduleSchema, { default: [...schedule.jobs] }) },
7980
7961
  build: nodeBuild({
7981
7962
  module: new URL("./scheduler-service.mjs", import.meta.url).href,
7982
7963
  entry: "./scheduler-entrypoint.mjs"
@@ -7997,9 +7978,9 @@ function runScheduler(opts) {
7997
7978
  });
7998
7979
  }, parseEvery(job.every));
7999
7980
  }
8000
- const service = cronScheduler();
7981
+ const service = cronScheduler({ jobs: [] });
8001
7982
  const { trigger } = service.load();
8002
- const { jobs } = service.input();
7983
+ const { jobs } = service.config();
8003
7984
  runScheduler({
8004
7985
  jobs,
8005
7986
  call: (jobId) => trigger.trigger({ jobId })