@prisma/composer-prisma-cloud 0.1.0 → 0.2.0-dev.2

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/control.d.mts +79 -36
  2. package/dist/control.d.mts.map +1 -0
  3. package/dist/control.mjs +1074 -330
  4. package/dist/control.mjs.map +1 -1
  5. package/dist/cron/index.d.mts +63 -10
  6. package/dist/cron/index.d.mts.map +1 -0
  7. package/dist/cron/index.mjs +255 -42
  8. package/dist/cron/index.mjs.map +1 -1
  9. package/dist/cron/scheduler-entrypoint.mjs +563 -289
  10. package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
  11. package/dist/cron/scheduler-service.mjs +255 -42
  12. package/dist/cron/scheduler-service.mjs.map +1 -1
  13. package/dist/index.d.mts +152 -26
  14. package/dist/index.d.mts.map +1 -0
  15. package/dist/index.mjs +108 -43
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/{prisma-next-COrwlg3N.mjs → prisma-next-DlU01kXJ-2sP5mQb6.mjs} +3 -3
  18. package/dist/prisma-next-DlU01kXJ-2sP5mQb6.mjs.map +1 -0
  19. package/dist/prisma-next.d.mts +1 -2
  20. package/dist/prisma-next.d.mts.map +1 -0
  21. package/dist/prisma-next.mjs +1 -1
  22. package/dist/provisioned-edges-B_XS1Mz--NFJgcXK7.mjs +211 -0
  23. package/dist/provisioned-edges-B_XS1Mz--NFJgcXK7.mjs.map +1 -0
  24. package/dist/serializer-Cx5slrV4-xJfH6EWS.d.mts +36 -0
  25. package/dist/serializer-Cx5slrV4-xJfH6EWS.d.mts.map +1 -0
  26. package/dist/{serializer-C2CsA7xm-29Eg2Tjl.mjs → serializer-D8_84XWO-DA2B6YbX.mjs} +91 -7
  27. package/dist/serializer-D8_84XWO-DA2B6YbX.mjs.map +1 -0
  28. package/dist/storage/index.d.mts +56 -20
  29. package/dist/storage/index.d.mts.map +1 -0
  30. package/dist/storage/index.mjs +267 -44
  31. package/dist/storage/index.mjs.map +1 -1
  32. package/dist/storage/storage-entrypoint.mjs +7395 -53
  33. package/dist/storage/storage-entrypoint.mjs.map +1 -1
  34. package/dist/storage/storage-service.mjs +267 -44
  35. package/dist/storage/storage-service.mjs.map +1 -1
  36. package/dist/storage/testing.d.mts +7 -4
  37. package/dist/storage/testing.d.mts.map +1 -0
  38. package/dist/storage/testing.mjs.map +1 -1
  39. package/dist/streams/index.d.mts +222 -0
  40. package/dist/streams/index.d.mts.map +1 -0
  41. package/dist/streams/index.mjs +4170 -0
  42. package/dist/streams/index.mjs.map +1 -0
  43. package/dist/streams/streams-entrypoint.mjs +48207 -0
  44. package/dist/streams/streams-entrypoint.mjs.map +1 -0
  45. package/dist/streams/streams-service.mjs +923 -0
  46. package/dist/streams/streams-service.mjs.map +1 -0
  47. package/dist/streams/testing.d.mts +33 -0
  48. package/dist/streams/testing.d.mts.map +1 -0
  49. package/dist/streams/testing.mjs +31335 -0
  50. package/dist/streams/testing.mjs.map +1 -0
  51. package/dist/testing.d.mts +1 -2
  52. package/dist/testing.d.mts.map +1 -0
  53. package/dist/testing.mjs +1 -1
  54. package/dist/testing.mjs.map +1 -1
  55. package/package.json +29 -23
  56. package/src/exports/control.ts +1 -0
  57. package/src/exports/cron.ts +1 -0
  58. package/src/exports/index.ts +1 -0
  59. package/src/exports/prisma-next.ts +1 -0
  60. package/src/exports/storage-testing.ts +1 -0
  61. package/src/exports/storage.ts +1 -0
  62. package/src/exports/streams-testing.ts +1 -0
  63. package/src/exports/streams.ts +1 -0
  64. package/src/exports/testing.ts +1 -0
  65. package/dist/prisma-next-COrwlg3N.mjs.map +0 -1
  66. package/dist/serializer-C2CsA7xm-29Eg2Tjl.mjs.map +0 -1
@@ -1,5 +1,56 @@
1
- import { Deps, HydratedDeps, ModuleNode, Params, RunnableServiceNode, ServiceNode } from "@prisma/composer";
2
-
1
+ import { BuildAdapter, Deps, Expose, HydratedDeps, ModuleNode, NODE, Params, RunnableServiceNode, SecretValues, Secrets, ServiceNode, Values } from "@prisma/composer";
2
+ import "@standard-schema/spec";
3
+ //#region ../../1-prisma-cloud/1-extensions/target/dist/index.d.mts
4
+ //#endregion
5
+ //#region src/compute.d.ts
6
+ declare const reservedParams: {
7
+ readonly port: import("@prisma/composer").ConfigParam<import("@standard-schema/spec").StandardSchemaV1<number, number>>;
8
+ };
9
+ type ReservedParams = typeof reservedParams;
10
+ /**
11
+ * A Prisma Compute service — declarations only (deps + params + build + the
12
+ * ports it exposes), no descriptor. `params` merges with the reserved
13
+ * `ReservedParams` (`port`); a user param whose name collides with a reserved
14
+ * one fails at authoring, the same way a colliding dependency name does.
15
+ *
16
+ * · run(address, boot) — the process controller: deserialize the platform
17
+ * environment (keyed off `address`, the extension's ONE env read) into a
18
+ * typed Config, re-emit it under address-free process-local stash keys,
19
+ * then call boot() to start the app's entry.
20
+ * · load() / config() — called from inside the app's entry: read the stash;
21
+ * load() hydrates + memoizes the deps, config() returns the typed params.
22
+ * Separate accessors so a dep and a param never share a namespace (ADR-0021).
23
+ * · origin() — this service's platform-assigned public origin, read from the
24
+ * stash `run()` populates; memoized per process.
25
+ *
26
+ * The underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
27
+ * the control-plane registry key `prisma-composer deploy` resolves through the
28
+ * app's `prisma-composer.config.ts` (ADR-0017). This module loads nothing at
29
+ * deploy time; nodes are pure data until run() or load() is called.
30
+ */
31
+ declare class ComputeService<D extends Deps, P extends Params, E extends Expose, S extends Secrets> implements RunnableServiceNode<D, P & ReservedParams, E, S> {
32
+ #private;
33
+ readonly [NODE]: true;
34
+ readonly kind: 'service';
35
+ readonly name: string;
36
+ readonly extension: string;
37
+ readonly type: string;
38
+ readonly inputs: D;
39
+ readonly params: P & ReservedParams;
40
+ readonly secretSlots: S;
41
+ readonly build: BuildAdapter;
42
+ readonly expose: E | undefined;
43
+ constructor(node: ServiceNode<D, P & ReservedParams, E, S>);
44
+ run(address: string, boot: () => Promise<unknown>): Promise<unknown>;
45
+ load(): HydratedDeps<D>;
46
+ config(): Values<P & ReservedParams>;
47
+ secrets(): SecretValues<S>;
48
+ /** This service's platform-assigned public origin — read from the stash
49
+ * run() populates and memoized per process. Throws if called before run()
50
+ * has stashed it (readOrigin's pinned message). */
51
+ origin(): string;
52
+ }
53
+ //#endregion
3
54
  //#region ../../1-prisma-cloud/2-shared-modules/cron/dist/index.d.mts
4
55
  //#region src/contract.d.ts
5
56
  declare const triggerContract: import("@prisma/composer").Contract<"rpc", {
@@ -9,7 +60,8 @@ declare const triggerContract: import("@prisma/composer").Contract<"rpc", {
9
60
  ok: boolean;
10
61
  }>;
11
62
  }>;
12
- type TriggerContract = typeof triggerContract; //#endregion
63
+ type TriggerContract = typeof triggerContract;
64
+ //#endregion
13
65
  //#region src/schedule.d.ts
14
66
  /**
15
67
  * A job-id → interval map, turned into the structured `jobs` list the
@@ -27,7 +79,8 @@ interface Schedule<Ids extends string> {
27
79
  * `{ jobs: [{ jobId: 'tick', every: '60s' }, { jobId: 'mrr', every: '24h' }] }`,
28
80
  * preserving key order.
29
81
  */
30
- declare function defineSchedule<const S extends Record<string, string>>(spec: S): Schedule<keyof S & string>; //#endregion
82
+ declare function defineSchedule<const S extends Record<string, string>>(spec: S): Schedule<keyof S & string>;
83
+ //#endregion
31
84
  //#region src/module.d.ts
32
85
  /**
33
86
  * `opts.runner` is a service exposing `{ trigger }`; the returned module
@@ -43,14 +96,15 @@ declare function cron<RD extends Deps, RP extends Params, Ids extends string>(op
43
96
  trigger: TriggerContract;
44
97
  }>;
45
98
  name?: string;
46
- }): ModuleNode<RD, Record<never, never>>; //#endregion
99
+ }): ModuleNode<RD, Record<never, never>>;
100
+ //#endregion
47
101
  //#region src/scheduler.d.ts
48
102
  /**
49
103
  * The always-on scheduler service. `schedule` sets only the `jobs` param's
50
104
  * default — the value the deploy serializes into config; the scheduler
51
105
  * itself is job-agnostic.
52
106
  */
53
- declare function cronScheduler<Ids extends string>(schedule: Schedule<Ids>): import("@prisma/composer").RunnableServiceNode<{
107
+ declare function cronScheduler<Ids extends string>(schedule: Schedule<Ids>): ComputeService<{
54
108
  trigger: import("@prisma/composer").DependencyEnd<{
55
109
  trigger: (input: {
56
110
  jobId: string;
@@ -69,8 +123,6 @@ declare function cronScheduler<Ids extends string>(schedule: Schedule<Ids>): imp
69
123
  jobId: string;
70
124
  every: string;
71
125
  }[], {}>>;
72
- } & {
73
- readonly port: import("@prisma/composer").ConfigParam<import("@standard-schema/spec").StandardSchemaV1<number, number>>;
74
126
  }, Record<never, never>, Record<never, never>>;
75
127
  /**
76
128
  * Fires `call(jobId)` on each job's `every` interval. A rejected `call` is
@@ -85,12 +137,13 @@ declare function runScheduler(opts: {
85
137
  }>;
86
138
  call: (jobId: string) => Promise<unknown>;
87
139
  setTimer?: (fn: () => void, ms: number) => void;
88
- }): void; //#endregion
140
+ }): void;
141
+ //#endregion
89
142
  //#region src/serve-schedule.d.ts
90
143
  type ScheduleHandler<D> = (deps: D) => Promise<unknown>;
91
144
  declare function serveSchedule<D extends Deps, P extends Params, Ids extends string>(service: RunnableServiceNode<D, P, {
92
145
  trigger: TriggerContract;
93
- }>, _schedule: Schedule<Ids>, handlers: { [Id in Ids]: ScheduleHandler<HydratedDeps<D>> }): (req: Request) => Promise<Response>; //#endregion
146
+ }>, _schedule: Schedule<Ids>, handlers: { [Id in Ids]: ScheduleHandler<HydratedDeps<D>>; }): (req: Request) => Promise<Response>;
94
147
  //#endregion
95
148
  export { type Schedule, type TriggerContract, cron, cronScheduler, defineSchedule, runScheduler, serveSchedule, triggerContract };
96
149
  //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../1-prisma-cloud/1-extensions/target/dist/index.d.mts","../../../../1-prisma-cloud/2-shared-modules/cron/dist/index.d.mts"],"mappings":";;;;;cA0Cc;WACH,+BAA+B,4CAA4C;;KAEjF,wBAAwB;;;;;;;;;;;;;;;;;;;;;;cAsBf,eAAe,UAAU,MAAM,UAAU,QAAQ,UAAU,QAAQ,UAAU,oBAAoB,oBAAoB,GAAG,IAAI,gBAAgB,GAAG;;YAEjJ;WACD;WACA;WACA;WACA;WACA,QAAQ;WACR,QAAQ,IAAI;WACZ,aAAa;WACb,OAAO;WACP,QAAQ;EACjB,YAAY,MAAM,YAAY,GAAG,IAAI,gBAAgB,GAAG;EACxD,IAAI,iBAAiB,YAAY,mBAAmB;EACpD,QAAQ,aAAa;EACrB,UAAU,OAAO,IAAI;EACrB,WAAW,aAAa;;;;EAIxB;;;;;cCrFY,0CAA0C;EACtD,UAAU;IACR;QACI;IACJ;;;KAGC,yBAAyB;;;;;;;;UAQpB,SAAS;WACR,MAAM;aACJ,OAAO;aACP;;;;;;;;iBAQI,qBAAqB,UAAU,wBAAwB,MAAM,IAAI,eAAe;;;;;;;;;;;iBAWhF,KAAK,WAAW,MAAM,WAAW,QAAQ,oBAAoB;EAC5E,UAAU,SAAS;EACnB,QAAQ,YAAY,IAAI;IACtB,SAAS;;EAEX;IACE,WAAW,IAAI;;;;;;;;iBAQF,cAAc,oBAAoB,UAAU,SAAS,OAmB7C;EAlBvB,kCAAkC;IAChC,UAAU;MACR;UACI;MACJ;;8BAEwB;IAC1B,UAAU;MACR;UACI;MACJ;;;;EAIJ,+BAA+B,yDAAyD;IACtF;IACA;;GAED,sBAAsB;;;;;;;iBAOR,aAAa;EAC5B,MAAM;IACJ;IACA;;EAEF,OAAO,kBAAkB;EACzB,YAAY,gBAAgB;;;;KAIzB,gBAAgB,MAAM,MAAM,MAAM;iBACtB,cAAc,UAAU,MAAM,UAAU,QAAQ,oBAAoB,SAAS,oBAAoB,GAAG;EACnH,SAAS;IACP,WAAW,SAAS,MAAM,aAAa,MAAM,MAAM,gBAAgB,aAAa,UAAU,KAAK,YAAY,QAAQ"}
@@ -1,4 +1,4 @@
1
- import { contract, rpc, serve } from "@prisma/composer/rpc";
1
+ import { RPC_PEER_KEY, contract, rpc, serve } from "@prisma/composer/service-rpc";
2
2
  import { type } from "arktype";
3
3
  import { hydrateSecrets, hydrateSync, module, number, param, service } from "@prisma/composer";
4
4
  import node from "@prisma/composer/node";
@@ -32,7 +32,7 @@ const configKey = (address, d) => {
32
32
  const segments = address.split(".").filter((s) => s.length > 0);
33
33
  const owner = d.owner === "service" ? [] : [d.owner.input];
34
34
  return [
35
- "COMPOSE",
35
+ "COMPOSER",
36
36
  ...segments,
37
37
  ...owner,
38
38
  d.name
@@ -51,12 +51,18 @@ function encode(owner, value) {
51
51
  function decode(owner, raw) {
52
52
  return owner === "service" ? JSON.parse(raw) : raw;
53
53
  }
54
+ const PARAM_POINTER_PREFIX = "@composer-param-pointer:";
55
+ /** True iff `raw` is a param pointer row (as opposed to a JSON-encoded literal). */
56
+ const isParamPointerRow = (raw) => raw.startsWith(PARAM_POINTER_PREFIX);
57
+ /** Reverses `encodeParamPointer`: the platform var NAME a pointer row points to. */
58
+ const decodeParamPointer = (raw) => raw.slice(24);
54
59
  function coerce(raw, d, key) {
55
60
  if (!(raw !== void 0 && raw !== "")) {
56
61
  if (d.param.default !== void 0) return d.param.default;
57
62
  if (d.param.optional === true) return void 0;
58
63
  throw new Error(`missing required config param "${d.name}" (env ${key})`);
59
64
  }
65
+ if (d.owner === "service" && isParamPointerRow(raw)) return coerceEnvSourcedParam(raw, d, key);
60
66
  try {
61
67
  return standardValidateSync(d.param.schema, decode(d.owner, raw));
62
68
  } catch (cause) {
@@ -65,6 +71,26 @@ function coerce(raw, d, key) {
65
71
  }
66
72
  }
67
73
  /**
74
+ * Boot resolution for an env-sourced param: double-lookup (pointer → platform
75
+ * var), then the param's own schema on the raw string — no JSON decode, and
76
+ * no redaction (it's config, not a secret). An UNSET platform var is a loud
77
+ * boot failure naming both the param and the platform var; an EMPTY string is
78
+ * not special-cased here — it reaches the schema like any other value, so it
79
+ * passes iff the schema accepts it (deliberately unlike a literal param's own
80
+ * ""-means-absent rule, and unlike a secret's non-empty requirement).
81
+ */
82
+ function coerceEnvSourcedParam(raw, d, key) {
83
+ const platformVar = decodeParamPointer(raw);
84
+ const value = process.env[platformVar];
85
+ if (value === void 0) throw new Error(`env-sourced config param "${d.name}" (env ${key} → ${platformVar}) is unset: the platform variable "${platformVar}" was not injected — the deploy did not provision it.`);
86
+ try {
87
+ return standardValidateSync(d.param.schema, value);
88
+ } catch (cause) {
89
+ const message = cause instanceof Error ? cause.message : String(cause);
90
+ throw new Error(`invalid value for env-sourced config param "${d.name}" (env ${key} → ${platformVar}): ${message}`);
91
+ }
92
+ }
93
+ /**
68
94
  * Boot: read each declared param from env by its key, reverse the param's own
69
95
  * serialization (missing/invalid fails loudly), assemble the typed Config.
70
96
  * Secrets ride a separate channel (deserializeSecrets), not this one.
@@ -104,7 +130,7 @@ const stash = (node, config) => {
104
130
  process.env[configKey("", d)] = encode(d.owner, value);
105
131
  }
106
132
  };
107
- /** The pointer-row key for a secret slot: COMPOSE_<addr>_<slot> (secrets are service-level). */
133
+ /** The pointer-row key for a secret slot: COMPOSER_<addr>_<slot> (secrets are service-level). */
108
134
  const secretKey = (address, slot) => configKey(address, {
109
135
  owner: "service",
110
136
  name: slot
@@ -139,6 +165,61 @@ const stashSecrets = (node, address) => {
139
165
  process.env[secretKey("", slot)] = name;
140
166
  }
141
167
  };
168
+ /**
169
+ * Boot: for each reserved provider param, read its address-scoped row through
170
+ * the same `coerce` a declared param uses (JSON-decode, schema-validate), and
171
+ * re-emit it address-free — `stash`'s counterpart for this separate
172
+ * declaration space. A param is declared optional here unconditionally: an
173
+ * absent row means "never provisioned" (local dev, tests, a provider with no
174
+ * registered value for this deploy), never a boot failure, so nothing is
175
+ * stashed and the runtime reader that owns this slot falls back to its own
176
+ * pass-through behavior.
177
+ */
178
+ function stashProviderParams(entries, address) {
179
+ for (const entry of entries) {
180
+ const d = {
181
+ owner: "service",
182
+ name: entry.name,
183
+ param: {
184
+ schema: entry.schema,
185
+ optional: true
186
+ }
187
+ };
188
+ const key = configKey(address, d);
189
+ const value = coerce(process.env[key], d, key);
190
+ if (value === void 0) continue;
191
+ process.env[configKey("", d)] = encode("service", value);
192
+ }
193
+ }
194
+ /** The framework-resolved origin row: COMPOSER_<addr>_ORIGIN. Written per
195
+ * compute service at serialize — the service's own provisioned endpoint URL,
196
+ * riding the reserved-provider-param machinery (`origin-key.ts`'s
197
+ * `ORIGIN_PARAM`); never a declared param, never in config(). A harness with
198
+ * no deploy behind it supplies it by setting `COMPOSER_ORIGIN` to the
199
+ * JSON-encoded origin URL — exactly how the existing entrypoint tests supply
200
+ * their other `COMPOSER_*` rows. */
201
+ const ORIGIN_KEY_NAME = "ORIGIN";
202
+ /**
203
+ * Reads this service's origin back out of the address-free stash
204
+ * `stashProviderParams` wrote for the ORIGIN entry. `COMPOSER_ORIGIN` unset is
205
+ * a loud failure — a deployed environment always writes it, so an unset row
206
+ * means either a local harness that hasn't supplied it or a boot() called
207
+ * before run().
208
+ */
209
+ function readOrigin() {
210
+ const d = {
211
+ owner: "service",
212
+ name: ORIGIN_KEY_NAME,
213
+ param: {
214
+ schema: type("string"),
215
+ optional: true
216
+ }
217
+ };
218
+ const key = configKey("", d);
219
+ const value = coerce(process.env[key], d, key);
220
+ if (value === void 0) throw new Error("this service's origin is not available (env COMPOSER_ORIGIN is unset) — a deployed environment writes it automatically; a local harness must supply it like any other config value (set COMPOSER_ORIGIN to the JSON-encoded origin URL).");
221
+ return blindCast(value);
222
+ }
142
223
  /** Synchronous Standard Schema validation — see the matching note in core's `config.ts`. */
143
224
  function standardValidateSync(schema, value) {
144
225
  const result = schema["~standard"].validate(value);
@@ -147,14 +228,130 @@ function standardValidateSync(schema, value) {
147
228
  return result.value;
148
229
  }
149
230
  //#endregion
150
- //#region ../../1-prisma-cloud/1-extensions/target/dist/index.mjs
231
+ //#region ../../1-prisma-cloud/1-extensions/target/dist/provisioned-edges-B_XS1Mz-.mjs
232
+ /**
233
+ * The service's own origin as a reserved provider param (ADR-0031): the ONE
234
+ * brand and the ONE entry — shared by control.ts (which registers the
235
+ * deploy-side value function that resolves the provisioned service's
236
+ * `endpointDomain` — see its `selfOriginValue`) and compute.ts (which
237
+ * validates and stashes the row at boot through the generic
238
+ * `stashProviderParams` loop), so writer and reader cannot drift.
239
+ *
240
+ * Unlike the key-minting brands (`service-keys.ts`, `streams-keys.ts`) this
241
+ * brand has no provisioner and no consumer edges: the value derives from the
242
+ * service's OWN provisioned attributes, so control.ts registers it as a
243
+ * service-derived provider param (`descriptors/shared.ts`'s
244
+ * `ServiceProviderParam`) and the descriptor writes it for EVERY compute
245
+ * service, exposing or not.
246
+ *
247
+ * This module is reachable from the RUNTIME/authoring side — it must never
248
+ * import `@internal/lowering` or `effect`, or those tokens leak into a user
249
+ * service's bundle (the deploy-side value function lives in control.ts, the
250
+ * control-plane-only entry).
251
+ */
252
+ /** ADR-0031's brand for the service's own origin — control.ts registers the deploy-side value function under this. */
253
+ const SELF_ORIGIN = Symbol.for("prisma:self-origin");
254
+ /**
255
+ * The reserved provider param for the origin row: the var name is `ORIGIN`,
256
+ * derived through `configKey` at both ends (`configKey(address, …)` at
257
+ * deploy, `configKey('', …)` — `COMPOSER_ORIGIN` — at boot, where
258
+ * `readOrigin` reads it back). `brand` is `SELF_ORIGIN` — control.ts looks
259
+ * its deploy-side value function up by this field.
260
+ */
261
+ const ORIGIN_PARAM = {
262
+ name: ORIGIN_KEY_NAME,
263
+ schema: type("string"),
264
+ brand: SELF_ORIGIN
265
+ };
266
+ /**
267
+ * RPC's reserved provider param (ADR-0030/ADR-0031): the declaration —
268
+ * name + schema + brand — for the accepted-keys set a provider stores, shared
269
+ * by `control.ts` (which registers the deploy-side `value(refs)` that mints
270
+ * and aggregates it — see its `rpcAcceptedKeysValue`) and `compute.ts` (which
271
+ * validates and stashes it at boot), so writer and reader cannot drift.
272
+ * Finding the edges themselves is `provisioned-edges.ts`'s generic,
273
+ * brand-blind scan — RPC is not special-cased anywhere in this target.
274
+ *
275
+ * This module is reachable from the RUNTIME/authoring side — it must never
276
+ * import `@internal/lowering` or `effect`, or those tokens leak into a user
277
+ * service's bundle (the deploy-side `value(refs)` lives in control.ts, the
278
+ * control-plane-only entry).
279
+ */
280
+ /**
281
+ * The reserved provider param for RPC's accepted-keys set: the var name is
282
+ * `RPC_ACCEPTED_KEYS`, derived through `configKey` at both ends
283
+ * (`configKey(address, …)` at deploy, `configKey('', …)` at boot — the
284
+ * address-free form is `@internal/service-rpc`'s `RPC_ACCEPTED_KEYS_ENV`). `brand` is
285
+ * `RPC_PEER_KEY`, the same brand `perBindingToken()`'s need carries — control.ts
286
+ * looks its `value(refs)` up by this field.
287
+ */
288
+ const RPC_ACCEPTED_KEYS_PARAM = {
289
+ name: "RPC_ACCEPTED_KEYS",
290
+ schema: type("string[]"),
291
+ brand: RPC_PEER_KEY
292
+ };
293
+ /** ADR-0031's need brand for the streams module's bearer key — control.ts registers the provisioner under this. */
294
+ const STREAMS_API_KEY = Symbol.for("prisma:streams/api-key");
295
+ /**
296
+ * The reserved provider param for the streams bearer key: the var name is
297
+ * `STREAMS_API_KEY`. `brand` is `STREAMS_API_KEY` itself (the same symbol
298
+ * `streamsApiKeyNeed()`'s need carries) — control.ts looks its `value(refs)`
299
+ * up by this field.
300
+ */
301
+ const STREAMS_API_KEY_PARAM = {
302
+ name: "STREAMS_API_KEY",
303
+ schema: type("string"),
304
+ brand: STREAMS_API_KEY
305
+ };
306
+ configKey("", {
307
+ owner: "service",
308
+ name: STREAMS_API_KEY_PARAM.name
309
+ });
310
+ /**
311
+ * The list of provider-side reserved params the boot path validates and
312
+ * stashes (ADR-0031): every brand's `{name, schema, brand}` declaration,
313
+ * collected from that brand's own module (`service-keys.ts`,
314
+ * `streams-keys.ts`, `origin-key.ts`) so `compute.ts` names no brand itself.
315
+ *
316
+ * This list exists separately from `control.ts`'s deploy-side registry
317
+ * (`PROVIDER_PARAMS`) because `control.ts` is deploy-only code — it imports
318
+ * `@internal/lowering` and `effect` to mint values — and a booted service
319
+ * must never import it. This module is reachable from a user service's
320
+ * bundle through `compute.ts`, so it must never import `@internal/lowering`,
321
+ * `effect`, `alchemy`, or `control.ts`.
322
+ *
323
+ * This is the single source of which reserved provider params exist:
324
+ * control.ts builds `PROVIDER_PARAMS` by mapping over this list and looking
325
+ * up each entry's deploy-side value function (edge-derived `value(refs)` or
326
+ * service-derived `valueForService(provisioned, address)`) by its `brand`,
327
+ * throwing at module load if one is missing. Adding a brand means adding its
328
+ * entry here, plus its deploy-side value function in control.ts — a brand
329
+ * registered for deploy but absent here is no longer expressible, because
330
+ * deploy no longer names its own param set independently.
331
+ */
332
+ const RESERVED_PROVIDER_PARAMS = [
333
+ RPC_ACCEPTED_KEYS_PARAM,
334
+ STREAMS_API_KEY_PARAM,
335
+ ORIGIN_PARAM
336
+ ];
337
+ blindCast(Symbol.for("prisma:prisma-cloud-param-source"));
338
+ Object.freeze({
339
+ kind: "s3",
340
+ __cmp: {
341
+ url: "",
342
+ bucket: "",
343
+ accessKeyId: "",
344
+ secretAccessKey: ""
345
+ },
346
+ satisfies: (required) => required.kind === "s3"
347
+ });
151
348
  const reservedParams = { port: number({ default: 3e3 }) };
152
349
  /**
153
350
  * A Prisma Compute service — declarations only (deps + params + build + the
154
351
  * ports it exposes), no descriptor. `params` merges with the reserved
155
352
  * `ReservedParams` (`port`); a user param whose name collides with a reserved
156
353
  * one fails at authoring, the same way a colliding dependency name does.
157
- * Returns the extension's runnable/loadable node:
354
+ *
158
355
  * · run(address, boot) — the process controller: deserialize the platform
159
356
  * environment (keyed off `address`, the extension's ONE env read) into a
160
357
  * typed Config, re-emit it under address-free process-local stash keys,
@@ -162,23 +359,69 @@ const reservedParams = { port: number({ default: 3e3 }) };
162
359
  * · load() / config() — called from inside the app's entry: read the stash;
163
360
  * load() hydrates + memoizes the deps, config() returns the typed params.
164
361
  * Separate accessors so a dep and a param never share a namespace (ADR-0021).
362
+ * · origin() — this service's platform-assigned public origin, read from the
363
+ * stash `run()` populates; memoized per process.
165
364
  *
166
- * `service()`'s underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
365
+ * The underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
167
366
  * the control-plane registry key `prisma-composer deploy` resolves through the
168
367
  * app's `prisma-composer.config.ts` (ADR-0017). This module loads nothing at
169
- * deploy time; nodes are pure data.
368
+ * deploy time; nodes are pure data until run() or load() is called.
170
369
  */
370
+ var ComputeService = class {
371
+ #resolved;
372
+ #loadedDeps;
373
+ #loadedParams;
374
+ #loadedSecrets;
375
+ #origin;
376
+ constructor(node) {
377
+ Object.assign(this, node);
378
+ }
379
+ #processConfig() {
380
+ if (this.#resolved === void 0) this.#resolved = deserialize(this, "");
381
+ return this.#resolved;
382
+ }
383
+ async run(address, boot) {
384
+ const config = deserialize(this, address);
385
+ stash(this, config);
386
+ stashProviderParams(RESERVED_PROVIDER_PARAMS, address);
387
+ stashSecrets(this, address);
388
+ const port = config.service["port"];
389
+ if (typeof port === "number") process.env["PORT"] = String(port);
390
+ return boot();
391
+ }
392
+ load() {
393
+ if (this.#loadedDeps === void 0) this.#loadedDeps = blindCast(hydrateSync(this, this.#processConfig()));
394
+ return this.#loadedDeps;
395
+ }
396
+ config() {
397
+ if (this.#loadedParams === void 0) this.#loadedParams = blindCast(this.#processConfig().service);
398
+ return this.#loadedParams;
399
+ }
400
+ secrets() {
401
+ if (this.#loadedSecrets === void 0) this.#loadedSecrets = blindCast(hydrateSecrets(this, deserializeSecrets(this, "")));
402
+ return this.#loadedSecrets;
403
+ }
404
+ /** This service's platform-assigned public origin — read from the stash
405
+ * run() populates and memoized per process. Throws if called before run()
406
+ * has stashed it (readOrigin's pinned message). */
407
+ origin() {
408
+ this.#origin ??= readOrigin();
409
+ return this.#origin;
410
+ }
411
+ };
171
412
  const compute = (def) => {
172
413
  const userParams = def.params ?? blindCast({});
173
414
  for (const reserved of Object.keys(reservedParams)) {
174
415
  if (reserved in def.deps) throw new Error(`compute(): dependency "${reserved}" collides with the reserved service param of the same name — rename the dependency.`);
175
416
  if (reserved in userParams) throw new Error(`compute(): param "${reserved}" collides with the reserved service param of the same name — rename the param.`);
176
417
  }
418
+ 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.`);
419
+ 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.`);
177
420
  const params = blindCast({
178
421
  ...userParams,
179
422
  ...reservedParams
180
423
  });
181
- const node = service({
424
+ const instance = new ComputeService(service({
182
425
  name: def.name,
183
426
  extension: "@prisma/composer-prisma-cloud",
184
427
  type: "compute",
@@ -187,39 +430,9 @@ const compute = (def) => {
187
430
  ...def.secrets !== void 0 ? { secrets: def.secrets } : {},
188
431
  build: def.build,
189
432
  ...def.expose !== void 0 ? { expose: def.expose } : {}
190
- });
191
- let resolved;
192
- let loadedDeps;
193
- let loadedParams;
194
- let loadedSecrets;
195
- function processConfig() {
196
- if (resolved === void 0) resolved = deserialize(node, "");
197
- return resolved;
198
- }
199
- const runnable = {
200
- ...node,
201
- async run(address, boot) {
202
- const config = deserialize(node, address);
203
- stash(node, config);
204
- stashSecrets(node, address);
205
- const port = config.service["port"];
206
- if (typeof port === "number") process.env["PORT"] = String(port);
207
- return boot();
208
- },
209
- load() {
210
- if (loadedDeps === void 0) loadedDeps = blindCast(hydrateSync(node, processConfig()));
211
- return loadedDeps;
212
- },
213
- config() {
214
- if (loadedParams === void 0) loadedParams = blindCast(processConfig().service);
215
- return loadedParams;
216
- },
217
- secrets() {
218
- if (loadedSecrets === void 0) loadedSecrets = blindCast(hydrateSecrets(node, deserializeSecrets(node, "")));
219
- return loadedSecrets;
220
- }
221
- };
222
- return Object.freeze(blindCast(runnable));
433
+ }));
434
+ Object.freeze(instance);
435
+ return instance;
223
436
  };
224
437
  Object.freeze({
225
438
  kind: "postgres",
@@ -235,7 +448,7 @@ Object.freeze({
235
448
  satisfies: (required) => required.kind === "credentials"
236
449
  });
237
450
  //#endregion
238
- //#region ../../1-prisma-cloud/2-shared-modules/cron/dist/scheduler-iL9rl3YY.mjs
451
+ //#region ../../1-prisma-cloud/2-shared-modules/cron/dist/scheduler-DhziPSWE.mjs
239
452
  /**
240
453
  * The one call edge between the scheduler and the app's runner: `trigger(jobId)`.
241
454
  * The scheduler depends on it (`rpc(triggerContract)`); the runner exposes it