@prisma/composer-prisma-cloud 0.3.0-dev.5 → 0.3.0-dev.7

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 (64) hide show
  1. package/dist/control.d.mts +1 -1
  2. package/dist/control.mjs +28 -17
  3. package/dist/control.mjs.map +1 -1
  4. package/dist/cron/index.d.mts +33 -26
  5. package/dist/cron/index.d.mts.map +1 -1
  6. package/dist/cron/index.mjs +202 -77
  7. package/dist/cron/index.mjs.map +1 -1
  8. package/dist/cron/scheduler-entrypoint.mjs +133 -114
  9. package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
  10. package/dist/cron/scheduler-service.mjs +200 -76
  11. package/dist/cron/scheduler-service.mjs.map +1 -1
  12. package/dist/email/email-entrypoint.mjs +162 -126
  13. package/dist/email/email-entrypoint.mjs.map +1 -1
  14. package/dist/email/email-service.mjs +230 -79
  15. package/dist/email/email-service.mjs.map +1 -1
  16. package/dist/email/index.d.mts +33 -29
  17. package/dist/email/index.d.mts.map +1 -1
  18. package/dist/email/index.mjs +236 -84
  19. package/dist/email/index.mjs.map +1 -1
  20. package/dist/email/testing.mjs +112 -89
  21. package/dist/email/testing.mjs.map +1 -1
  22. package/dist/index.d.mts +51 -43
  23. package/dist/index.d.mts.map +1 -1
  24. package/dist/index.mjs +47 -51
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/local-target.mjs +1 -1
  27. package/dist/local-target.mjs.map +1 -1
  28. package/dist/{preflight-names-BPL-qsZF-BfoRgbgb.mjs → preflight-names-CpJUd9ZA-BCU-W3cT.mjs} +30 -14
  29. package/dist/{preflight-names-BPL-qsZF-BfoRgbgb.mjs.map → preflight-names-CpJUd9ZA-BCU-W3cT.mjs.map} +1 -1
  30. package/dist/{provisioned-edges-C1wSO3cx-YC5C19f9.mjs → provisioned-edges-Cxy18aoh-CUnaY96r.mjs} +3 -3
  31. package/dist/{provisioned-edges-C1wSO3cx-YC5C19f9.mjs.map → provisioned-edges-Cxy18aoh-CUnaY96r.mjs.map} +1 -1
  32. package/dist/{param-BTzY0ne5-CW6ojZ3E.mjs → secret-BVGxqHxY-DYDfiULl.mjs} +45 -4
  33. package/dist/secret-BVGxqHxY-DYDfiULl.mjs.map +1 -0
  34. package/dist/{serializer-Cx5slrV4-xJfH6EWS.d.mts → serializer-BD_6nkr4-DWn5NNTC.d.mts} +2 -2
  35. package/dist/serializer-BD_6nkr4-DWn5NNTC.d.mts.map +1 -0
  36. package/dist/serializer-sVE4UAmg-CikRngbR.mjs +475 -0
  37. package/dist/serializer-sVE4UAmg-CikRngbR.mjs.map +1 -0
  38. package/dist/storage/index.d.mts +31 -26
  39. package/dist/storage/index.d.mts.map +1 -1
  40. package/dist/storage/index.mjs +215 -89
  41. package/dist/storage/index.mjs.map +1 -1
  42. package/dist/storage/storage-entrypoint.mjs +147 -122
  43. package/dist/storage/storage-entrypoint.mjs.map +1 -1
  44. package/dist/storage/storage-service.mjs +212 -87
  45. package/dist/storage/storage-service.mjs.map +1 -1
  46. package/dist/streams/index.d.mts +29 -22
  47. package/dist/streams/index.d.mts.map +1 -1
  48. package/dist/streams/index.mjs +213 -88
  49. package/dist/streams/index.mjs.map +1 -1
  50. package/dist/streams/streams-entrypoint.mjs +139 -118
  51. package/dist/streams/streams-entrypoint.mjs.map +1 -1
  52. package/dist/streams/streams-service.mjs +212 -87
  53. package/dist/streams/streams-service.mjs.map +1 -1
  54. package/dist/testing.d.mts +19 -5
  55. package/dist/testing.d.mts.map +1 -1
  56. package/dist/testing.mjs +11 -3
  57. package/dist/testing.mjs.map +1 -1
  58. package/package.json +18 -18
  59. package/dist/param-BTzY0ne5-CW6ojZ3E.mjs.map +0 -1
  60. package/dist/secret-rz_ZqNeq-_xd97Jd9.mjs +0 -47
  61. package/dist/secret-rz_ZqNeq-_xd97Jd9.mjs.map +0 -1
  62. package/dist/serializer-CJiOhF2d-DJUjQj1i.mjs +0 -251
  63. package/dist/serializer-CJiOhF2d-DJUjQj1i.mjs.map +0 -1
  64. package/dist/serializer-Cx5slrV4-xJfH6EWS.d.mts.map +0 -1
@@ -130,11 +130,6 @@ function freezeParams(params) {
130
130
  for (const [name, param] of Object.entries(params)) frozen[name] = Object.freeze({ ...param });
131
131
  return Object.freeze(frozen);
132
132
  }
133
- function freezeSecrets(secrets) {
134
- const frozen = {};
135
- for (const [name, need] of Object.entries(secrets)) frozen[name] = Object.freeze({ ...need });
136
- return blindCast(Object.freeze(frozen));
137
- }
138
133
  /** A frozen shallow copy that keeps the caller's declared type. */
139
134
  function frozenShallowCopy(obj) {
140
135
  return blindCast(Object.freeze({ ...obj }));
@@ -188,16 +183,16 @@ function resource(def) {
188
183
  }
189
184
  /**
190
185
  * Constructs a branded, frozen Service node — declarations only (inputs,
191
- * params, build adapter, and the ports it exposes). Pure; carries no runtime behavior.
186
+ * params, the input schema, build adapter, and the ports it exposes). Pure;
187
+ * carries no runtime behavior.
192
188
  */
193
- function service$1(def) {
189
+ function service(def) {
194
190
  requireName(def.name, "service");
195
191
  requireExtension(def.extension, "service");
196
192
  requireType(def.type, "service");
197
193
  requireConfigKeySegmentNames(Object.keys(def.inputs), "input", "service");
198
194
  requireConfigKeySegmentNames(Object.keys(def.params), "param", "service");
199
- requireConfigKeySegmentNames(Object.keys(def.secrets ?? {}), "secret", "service");
200
- 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.`);
195
+ 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).");
201
196
  return Object.freeze({
202
197
  [NODE]: true,
203
198
  kind: "service",
@@ -206,7 +201,7 @@ function service$1(def) {
206
201
  type: def.type,
207
202
  inputs: frozenShallowCopy(def.inputs),
208
203
  params: freezeParams(def.params),
209
- secretSlots: freezeSecrets(def.secrets ?? blindCast({})),
204
+ inputSchema: blindCast(def.input),
210
205
  build: Object.freeze({ ...def.build }),
211
206
  expose: def.expose !== void 0 ? frozenShallowCopy(def.expose) : void 0
212
207
  });
@@ -239,11 +234,16 @@ function dependency(def) {
239
234
  * `JSON.stringify`, and `console.log`/`util.inspect` all print `[REDACTED]`, so
240
235
  * a secret can't leak through an accidental log or serialization.
241
236
  *
242
- * Shape matches the platform's own `secrecy` type (pdp-control-plane). The class
243
- * is nominal enough on its own — no phantom brand.
237
+ * Every box carries a brand property keyed by the registered symbol
238
+ * `Symbol.for('prisma:secret-box')`, which is what `isSecretString` checks. A
239
+ * symbol key is invisible to `JSON.stringify` and `Object.keys`, so the box's
240
+ * public shape still matches the platform's own `secrecy` type
241
+ * (pdp-control-plane).
244
242
  */
245
243
  const REDACTED = "[REDACTED]";
244
+ const SECRET_BOX = blindCast(Symbol.for("prisma:secret-box"));
246
245
  var SecretBox = class {
246
+ [SECRET_BOX] = true;
247
247
  #value;
248
248
  constructor(value) {
249
249
  this.#value = value;
@@ -309,24 +309,6 @@ function hydrateSync(root, config) {
309
309
  }
310
310
  return deps;
311
311
  }
312
- /**
313
- * Wraps each of a service's resolved secret values in a redacting `SecretBox`
314
- * — what the node's `secrets()` accessor returns (ADR-0021, sibling to
315
- * `load()`/`config()`). The RESOLUTION of a secret's value (the boot
316
- * double-lookup that reads the platform var the pointer names) is the target
317
- * pack's job; core is handed the already-resolved strings and only boxes them,
318
- * so a secret is redacted by TYPE from here on. A declared slot missing from
319
- * `values` is a target contract violation, named loudly.
320
- */
321
- function hydrateSecrets(root, values) {
322
- const boxed = {};
323
- for (const slot of Object.keys(root.secretSlots)) {
324
- const value = values[slot];
325
- if (value === void 0) throw new Error(`secret slot "${slot}" has no resolved value — the target must resolve every declared secret before hydrateSecrets().`);
326
- boxed[slot] = new SecretBox(value);
327
- }
328
- return blindCast(boxed);
329
- }
330
312
  const liftArray = (data) => Array.isArray(data) ? data : [data];
331
313
  /**
332
314
  * Splits an array into two arrays based on the result of a predicate
@@ -7534,7 +7516,7 @@ function coerceEnvSourcedParam(raw, d, key) {
7534
7516
  /**
7535
7517
  * Boot: read each declared param from env by its key, reverse the param's own
7536
7518
  * serialization (missing/invalid fails loudly), assemble the typed Config.
7537
- * Secrets ride a separate channel (deserializeSecrets), not this one.
7519
+ * The input document rides its own channel (readInput), not this one.
7538
7520
  */
7539
7521
  const deserialize = (node, address) => {
7540
7522
  const service = {};
@@ -7571,40 +7553,84 @@ const stash = (node, config) => {
7571
7553
  process.env[configKey("", d)] = encode(d.owner, value);
7572
7554
  }
7573
7555
  };
7574
- /** The pointer-row key for a secret slot: COMPOSER_<addr>_<slot> (secrets are service-level). */
7575
- const secretKey = (address, slot) => configKey(address, {
7556
+ /** The input document's own row name; its full key is COMPOSER_<addr>_INPUT. */
7557
+ const INPUT_KEY_NAME = "INPUT";
7558
+ /** The input document row's key for a service address. */
7559
+ const inputKey = (address) => configKey(address, {
7576
7560
  owner: "service",
7577
- name: slot
7561
+ name: INPUT_KEY_NAME
7578
7562
  });
7563
+ const SECRET_MARKER = "$secret";
7564
+ const ESCAPED_KEY = /^\$\$+secret$/;
7565
+ /** True for the framework's secret pointer: `{ "$secret": "<PLATFORM_VAR>" }` and nothing else. */
7566
+ function isSecretPointer(value) {
7567
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 1 && SECRET_MARKER in value && typeof value[SECRET_MARKER] === "string";
7568
+ }
7569
+ /** A plain data object (not an array, not a class instance) — the only object shape a binding/document may nest. */
7570
+ function isPlainObject$7(value) {
7571
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
7572
+ const proto = Object.getPrototypeOf(value);
7573
+ return proto === Object.prototype || proto === null;
7574
+ }
7579
7575
  /**
7580
- * Boot: resolve every secret slot to its value by double-lookup read the
7581
- * pointer key (the platform NAME), then read that platform var. A missing
7582
- * pointer or a missing/empty platform value is a loud failure naming both keys.
7583
- * Returns a plain Record for core's `hydrateSecrets` to box.
7576
+ * Boot: read the one input document row (address-free after run()'s
7577
+ * re-stash), swap each `$secret` pointer for a redacting box over the named
7578
+ * platform var, unescape reserved keys, validate with the service's own
7579
+ * schema, and return the typed object. A missing row is a loud failure naming
7580
+ * the env var — a deployed environment always writes it; a local harness must
7581
+ * supply it (set the row to the serialized input document).
7584
7582
  */
7585
- const deserializeSecrets = (node, address) => {
7586
- const values = {};
7587
- for (const slot of Object.keys(node.secretSlots)) {
7588
- const key = secretKey(address, slot);
7589
- const name = process.env[key];
7590
- if (name === void 0 || name === "") throw new Error(`missing secret pointer for slot "${slot}" (env ${key}) — the deploy did not write it.`);
7591
- const value = process.env[name];
7592
- if (value === void 0 || value === "") throw new Error(`secret "${slot}" is not provisioned (env ${key} → ${name}): the platform var "${name}" is unset or empty.`);
7593
- values[slot] = value;
7583
+ function readInput(node, address) {
7584
+ const schema = node.inputSchema;
7585
+ 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).`);
7586
+ const key = inputKey(address);
7587
+ const raw = process.env[key];
7588
+ 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).`);
7589
+ let parsed;
7590
+ try {
7591
+ parsed = JSON.parse(raw);
7592
+ } catch (cause) {
7593
+ const message = cause instanceof Error ? cause.message : String(cause);
7594
+ 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).`);
7594
7595
  }
7595
- return values;
7596
- };
7596
+ const hydrated = hydrateInputDocument(parsed, key);
7597
+ try {
7598
+ return standardValidateSync(schema, hydrated);
7599
+ } catch (cause) {
7600
+ const message = cause instanceof Error ? cause.message : String(cause);
7601
+ throw new Error(`invalid input document (env ${key}): ${message}`);
7602
+ }
7603
+ }
7604
+ /** Reverses the document encoding: `$secret` pointers become redacting boxes over the named platform vars; escaped reserved keys drop one "$". */
7605
+ function hydrateInputDocument(value, key) {
7606
+ if (isSecretPointer(value)) {
7607
+ const name = value[SECRET_MARKER];
7608
+ const secret = process.env[name];
7609
+ if (secret === void 0 || secret === "") throw new Error(`secret input is not provisioned (env ${key} → ${name}): the platform var "${name}" is unset or empty.`);
7610
+ return new SecretBox(secret);
7611
+ }
7612
+ if (Array.isArray(value)) return value.map((member) => hydrateInputDocument(member, key));
7613
+ if (isPlainObject$7(value)) {
7614
+ const out = {};
7615
+ for (const [k, member] of Object.entries(value)) {
7616
+ const read = ESCAPED_KEY.test(k) ? k.slice(1) : k;
7617
+ out[read] = hydrateInputDocument(member, key);
7618
+ }
7619
+ return out;
7620
+ }
7621
+ return value;
7622
+ }
7597
7623
  /**
7598
- * run()'s setup step for secrets: re-emit each slot's pointer NAME under its
7599
- * address-free key, so the address-free `deserializeSecrets` double-looks-up
7600
- * identically. Never the value — the value stays only in the platform var.
7624
+ * run()'s setup step for the input document: re-emit the row under its
7625
+ * address-free key, so the address-free `readInput` reads identically. The
7626
+ * document carries pointers, never values — the values stay only in their
7627
+ * platform vars.
7601
7628
  */
7602
- const stashSecrets = (node, address) => {
7603
- for (const slot of Object.keys(node.secretSlots)) {
7604
- const name = process.env[secretKey(address, slot)];
7605
- if (name === void 0) continue;
7606
- process.env[secretKey("", slot)] = name;
7607
- }
7629
+ const stashInput = (node, address) => {
7630
+ if (node.inputSchema === void 0) return;
7631
+ const raw = process.env[inputKey(address)];
7632
+ if (raw === void 0) return;
7633
+ process.env[inputKey("")] = raw;
7608
7634
  };
7609
7635
  /**
7610
7636
  * Boot: for each reserved provider param, read its address-scoped row through
@@ -7796,20 +7822,24 @@ Object.freeze({
7796
7822
  });
7797
7823
  const reservedParams = { port: number$1({ default: 3e3 }) };
7798
7824
  /**
7799
- * A Prisma Compute service — declarations only (deps + params + build + the
7800
- * ports it exposes), no descriptor. `params` merges with the reserved
7801
- * `ReservedParams` (`port`); a user param whose name collides with a reserved
7802
- * one fails at authoring, the same way a colliding dependency name does.
7825
+ * A Prisma Compute service — declarations only (deps + one input schema +
7826
+ * build + the ports it exposes), no descriptor. The reserved `port` param
7827
+ * rides its own channel (ADR-0042 leaves it untouched); a dependency named
7828
+ * like it fails at authoring.
7803
7829
  *
7804
7830
  * · run(address, boot) — the process controller: deserialize the platform
7805
7831
  * environment (keyed off `address`, the extension's ONE env read) into a
7806
- * typed Config, re-emit it under address-free process-local stash keys,
7807
- * then call boot() to start the app's entry.
7808
- * · load() / config() — called from inside the app's entry: read the stash;
7809
- * load() hydrates + memoizes the deps, config() returns the typed params.
7810
- * Separate accessors so a dep and a param never share a namespace (ADR-0021).
7832
+ * typed Config, re-emit it (and the input document row) under address-free
7833
+ * process-local stash keys, then call boot() to start the app's entry.
7834
+ * · load() / input() — called from inside the app's entry: read the stash;
7835
+ * load() hydrates + memoizes the deps, input() parses the input document,
7836
+ * replaces each `$secret` pointer with a redacting box over the named
7837
+ * platform var, validates with the declared schema, and memoizes (ADR-0042).
7811
7838
  * · origin() — this service's platform-assigned public origin, read from the
7812
7839
  * stash `run()` populates; memoized per process.
7840
+ * · port() — this service's resolved reserved port (the value `run()` routes
7841
+ * to and exports as PORT), read from that same stash via #processConfig();
7842
+ * defaults to 3000 when the platform binds none.
7813
7843
  *
7814
7844
  * The underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
7815
7845
  * the control-plane registry key `prisma-composer deploy` resolves through the
@@ -7819,8 +7849,7 @@ const reservedParams = { port: number$1({ default: 3e3 }) };
7819
7849
  var ComputeService = class {
7820
7850
  #resolved;
7821
7851
  #loadedDeps;
7822
- #loadedParams;
7823
- #loadedSecrets;
7852
+ #loadedInput;
7824
7853
  #origin;
7825
7854
  constructor(node) {
7826
7855
  Object.assign(this, node);
@@ -7833,7 +7862,7 @@ var ComputeService = class {
7833
7862
  const config = deserialize(this, address);
7834
7863
  stash(this, config);
7835
7864
  stashProviderParams(RESERVED_PROVIDER_PARAMS, address);
7836
- stashSecrets(this, address);
7865
+ stashInput(this, address);
7837
7866
  const port = config.service["port"];
7838
7867
  if (typeof port === "number") process.env["PORT"] = String(port);
7839
7868
  return boot();
@@ -7842,13 +7871,9 @@ var ComputeService = class {
7842
7871
  if (this.#loadedDeps === void 0) this.#loadedDeps = blindCast(hydrateSync(this, this.#processConfig()));
7843
7872
  return this.#loadedDeps;
7844
7873
  }
7845
- config() {
7846
- if (this.#loadedParams === void 0) this.#loadedParams = blindCast(this.#processConfig().service);
7847
- return this.#loadedParams;
7848
- }
7849
- secrets() {
7850
- if (this.#loadedSecrets === void 0) this.#loadedSecrets = blindCast(hydrateSecrets(this, deserializeSecrets(this, "")));
7851
- return this.#loadedSecrets;
7874
+ input() {
7875
+ if (this.#loadedInput === void 0) this.#loadedInput = blindCast(readInput(this, ""));
7876
+ return this.#loadedInput;
7852
7877
  }
7853
7878
  /** This service's platform-assigned public origin — read from the stash
7854
7879
  * run() populates and memoized per process. Throws if called before run()
@@ -7857,26 +7882,24 @@ var ComputeService = class {
7857
7882
  this.#origin ??= readOrigin();
7858
7883
  return this.#origin;
7859
7884
  }
7885
+ /** This service's resolved reserved port — the value run() routes to and
7886
+ * exports as PORT — read the same way load() reads the stash. Defaults to
7887
+ * 3000 when the platform binds none. */
7888
+ port() {
7889
+ const port = this.#processConfig().service["port"];
7890
+ 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.`);
7891
+ return port;
7892
+ }
7860
7893
  };
7861
7894
  const compute = (def) => {
7862
- const userParams = def.params ?? blindCast({});
7863
- for (const reserved of Object.keys(reservedParams)) {
7864
- if (reserved in def.deps) throw new Error(`compute(): dependency "${reserved}" collides with the reserved service param of the same name — rename the dependency.`);
7865
- if (reserved in userParams) throw new Error(`compute(): param "${reserved}" collides with the reserved service param of the same name — rename the param.`);
7866
- }
7867
- 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.`);
7868
- 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.`);
7869
- const params = blindCast({
7870
- ...userParams,
7871
- ...reservedParams
7872
- });
7873
- const instance = new ComputeService(service$1({
7895
+ 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.`);
7896
+ const instance = new ComputeService(service({
7874
7897
  name: def.name,
7875
7898
  extension: "@prisma/composer-prisma-cloud",
7876
7899
  type: "compute",
7877
7900
  inputs: def.deps,
7878
- params,
7879
- ...def.secrets !== void 0 ? { secrets: def.secrets } : {},
7901
+ params: reservedParams,
7902
+ ...def.input !== void 0 ? { input: def.input } : {},
7880
7903
  build: def.build,
7881
7904
  ...def.expose !== void 0 ? { expose: def.expose } : {}
7882
7905
  }));
@@ -7944,21 +7967,21 @@ function s3Credentials(opts) {
7944
7967
  /**
7945
7968
  * The storage service authoring factory — a `compute` service routed to the
7946
7969
  * `s3-store` lowering instead of `compute`'s. It is exactly `compute`'s
7947
- * runnable (run/load/config, deps, params, build, expose) with the routing
7948
- * `type` overridden to `'s3-store'`: nothing at runtime keys off `type` (the
7949
- * serializer keys off the deployment address and each param's owner/name, and
7950
- * `load`/`config` off deps/params), so only the deploy-time descriptor lookup
7951
- * sees the override and routes to the extended-output lowering (§ 5). The
7952
- * return type is compute's exactly (including the reserved `port` param). The
7953
- * storage module (D4b) calls this with its `db`/`credentials` deps, a `bucket`
7954
- * param, and `expose: { store: s3Contract }`.
7970
+ * runnable (run/load/input, deps, input schema, build, expose) with the
7971
+ * routing `type` overridden to `'s3-store'`: nothing at runtime keys off
7972
+ * `type` (the serializer keys off the deployment address and each param's
7973
+ * owner/name, and `load`/`input` off deps/the input schema), so only the
7974
+ * deploy-time descriptor lookup sees the override and routes to the
7975
+ * extended-output lowering (§ 5). The return type is compute's exactly
7976
+ * (including the reserved `port` param). The storage module (D4b) calls this
7977
+ * with its `db`/`credentials` deps and `expose: { store: s3Contract }`.
7955
7978
  *
7956
- * `compute()`'s result is a `ComputeService` instance — its run/load/config/
7957
- * secrets/origin methods live on the class prototype, not as the instance's
7958
- * own properties, so a plain object spread (`{ ...node }`) would silently
7959
- * drop them. Building a fresh `ComputeService` from the same data fields
7960
- * (which `{ ...node }` DOES copy — they're the node's own enumerable
7961
- * properties) with `type` overridden keeps every method intact.
7979
+ * `compute()`'s result is a `ComputeService` instance — its run/load/input/
7980
+ * origin methods live on the class prototype, not as the instance's own
7981
+ * properties, so a plain object spread (`{ ...node }`) would silently drop
7982
+ * them. Building a fresh `ComputeService` from the same data fields (which
7983
+ * `{ ...node }` DOES copy — they're the node's own enumerable properties)
7984
+ * with `type` overridden keeps every method intact.
7962
7985
  */
7963
7986
  function s3StoreService(def) {
7964
7987
  const instance = new ComputeService({
@@ -8007,21 +8030,22 @@ function s3() {
8007
8030
  /**
8008
8031
  * The storage service node (like cron's `scheduler.ts` + `scheduler-service.ts`
8009
8032
  * combined): `storageService` builds the `s3-store` service — a Postgres `db`
8010
- * dependency, a minted `credentials` dependency, a `bucket` param, and the
8011
- * `store` port exposing `s3Contract`. The deploy bootstrap runs the
8012
- * default-exported bare node (`main.run(address, boot)`); the real bucket comes
8013
- * from serialized config at runtime, so the default's `bucket` is only a
8014
- * placeholder — exactly like `scheduler-service.ts` default-exports
8015
- * `cronScheduler({ jobs: [] })`.
8033
+ * dependency, a minted `credentials` dependency, a `bucket` input key
8034
+ * (bound at provision by `storage()`, ADR-0042), and the `store` port exposing
8035
+ * `s3Contract`. The deploy bootstrap runs the default-exported bare node
8036
+ * (`main.run(address, boot)`); the real bucket comes from the stashed input
8037
+ * document at runtime — exactly like `scheduler-service.ts` default-exports a
8038
+ * schedule-free `cronScheduler()`.
8016
8039
  */
8017
- function storageService(opts) {
8040
+ const storageInputSchema = type({ bucket: "string" });
8041
+ function storageService() {
8018
8042
  return s3StoreService({
8019
8043
  name: "storage",
8020
8044
  deps: {
8021
8045
  db: postgres(),
8022
8046
  credentials: s3Credentials()
8023
8047
  },
8024
- params: { bucket: string$1({ default: opts.bucket }) },
8048
+ input: storageInputSchema,
8025
8049
  build: nodeBuild({
8026
8050
  module: new URL("./storage-service.mjs", import.meta.url).href,
8027
8051
  entry: "./storage-entrypoint.mjs"
@@ -8029,7 +8053,7 @@ function storageService(opts) {
8029
8053
  expose: { store: s3Contract }
8030
8054
  });
8031
8055
  }
8032
- storageService({ bucket: "storage" });
8056
+ storageService();
8033
8057
  var require_reusify = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8034
8058
  function reusify(Constructor) {
8035
8059
  var head = new Constructor();
@@ -48173,9 +48197,7 @@ var init_package_entry = __esmMin((async () => {
48173
48197
  process.argv = ensureComputeArgv(process.argv);
48174
48198
  await init_server().then(() => server_exports);
48175
48199
  }));
48176
- const service = streamsService();
48177
- const { store } = service.load();
48178
- const { port } = service.config();
48200
+ const { store } = streamsService().load();
48179
48201
  const raw = process.env[STREAMS_API_KEY_ENV];
48180
48202
  if (raw === void 0 || raw === "") throw new Error("streams: no bearer key was provisioned for this module — nothing declares a durableStreams() dependency on it, so the key that authenticates its API was never minted. Wire a consumer to the module's `streams` port, or remove the module.");
48181
48203
  let parsed;
@@ -48187,7 +48209,6 @@ try {
48187
48209
  if (typeof parsed !== "string" || parsed.length === 0) throw new Error("streams: the provisioned bearer key is not a valid JSON-encoded string — the deploy wrote something this entrypoint cannot read back. Redeploy to re-mint the key.");
48188
48210
  const apiKey = parsed;
48189
48211
  process.env["API_KEY"] = apiKey;
48190
- process.env["PORT"] = String(port);
48191
48212
  process.env["DS_HOST"] ??= "0.0.0.0";
48192
48213
  process.env["DS_ROOT"] ??= "/tmp/ds-data";
48193
48214
  process.env["DS_SEGMENT_MAX_INTERVAL_MS"] ??= "5000";