@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.
- package/dist/compute-main.mjs +4 -20
- package/dist/compute-main.mjs.map +1 -1
- package/dist/control.d.mts +1 -1
- package/dist/control.mjs +17 -28
- package/dist/control.mjs.map +1 -1
- package/dist/cron/index.d.mts +26 -33
- package/dist/cron/index.d.mts.map +1 -1
- package/dist/cron/index.mjs +77 -202
- package/dist/cron/index.mjs.map +1 -1
- package/dist/cron/scheduler-entrypoint.mjs +114 -133
- package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
- package/dist/cron/scheduler-service.mjs +76 -200
- package/dist/cron/scheduler-service.mjs.map +1 -1
- package/dist/email/email-entrypoint.mjs +126 -162
- package/dist/email/email-entrypoint.mjs.map +1 -1
- package/dist/email/email-service.mjs +79 -230
- package/dist/email/email-service.mjs.map +1 -1
- package/dist/email/index.d.mts +29 -33
- package/dist/email/index.d.mts.map +1 -1
- package/dist/email/index.mjs +84 -236
- package/dist/email/index.mjs.map +1 -1
- package/dist/email/testing.mjs +89 -112
- package/dist/email/testing.mjs.map +1 -1
- package/dist/index.d.mts +43 -51
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +51 -47
- package/dist/index.mjs.map +1 -1
- package/dist/local-target.mjs +1 -1
- package/dist/local-target.mjs.map +1 -1
- package/dist/{secret-BVGxqHxY-DYDfiULl.mjs → param-BTzY0ne5-CW6ojZ3E.mjs} +4 -45
- package/dist/param-BTzY0ne5-CW6ojZ3E.mjs.map +1 -0
- package/dist/{preflight-names-CpJUd9ZA-BCU-W3cT.mjs → preflight-names-BPL-qsZF-BfoRgbgb.mjs} +14 -30
- package/dist/{preflight-names-CpJUd9ZA-BCU-W3cT.mjs.map → preflight-names-BPL-qsZF-BfoRgbgb.mjs.map} +1 -1
- package/dist/{provisioned-edges-Cxy18aoh-CUnaY96r.mjs → provisioned-edges-C1wSO3cx-YC5C19f9.mjs} +3 -3
- package/dist/{provisioned-edges-Cxy18aoh-CUnaY96r.mjs.map → provisioned-edges-C1wSO3cx-YC5C19f9.mjs.map} +1 -1
- package/dist/secret-rz_ZqNeq-_xd97Jd9.mjs +47 -0
- package/dist/secret-rz_ZqNeq-_xd97Jd9.mjs.map +1 -0
- package/dist/serializer-CJiOhF2d-DJUjQj1i.mjs +251 -0
- package/dist/serializer-CJiOhF2d-DJUjQj1i.mjs.map +1 -0
- package/dist/{serializer-BD_6nkr4-DWn5NNTC.d.mts → serializer-Cx5slrV4-xJfH6EWS.d.mts} +2 -2
- package/dist/serializer-Cx5slrV4-xJfH6EWS.d.mts.map +1 -0
- package/dist/storage/index.d.mts +26 -31
- package/dist/storage/index.d.mts.map +1 -1
- package/dist/storage/index.mjs +89 -215
- package/dist/storage/index.mjs.map +1 -1
- package/dist/storage/storage-entrypoint.mjs +122 -147
- package/dist/storage/storage-entrypoint.mjs.map +1 -1
- package/dist/storage/storage-service.mjs +87 -212
- package/dist/storage/storage-service.mjs.map +1 -1
- package/dist/streams/index.d.mts +22 -29
- package/dist/streams/index.d.mts.map +1 -1
- package/dist/streams/index.mjs +88 -213
- package/dist/streams/index.mjs.map +1 -1
- package/dist/streams/streams-entrypoint.mjs +118 -139
- package/dist/streams/streams-entrypoint.mjs.map +1 -1
- package/dist/streams/streams-service.mjs +87 -212
- package/dist/streams/streams-service.mjs.map +1 -1
- package/dist/testing.d.mts +5 -19
- package/dist/testing.d.mts.map +1 -1
- package/dist/testing.mjs +3 -11
- package/dist/testing.mjs.map +1 -1
- package/package.json +18 -18
- package/dist/secret-BVGxqHxY-DYDfiULl.mjs.map +0 -1
- package/dist/serializer-BD_6nkr4-DWn5NNTC.d.mts.map +0 -1
- package/dist/serializer-sVE4UAmg-CikRngbR.mjs +0 -475
- package/dist/serializer-sVE4UAmg-CikRngbR.mjs.map +0 -1
|
@@ -66,6 +66,14 @@ function blindCast(input) {
|
|
|
66
66
|
* data objects. A node's `extension` + `type` form its deploy-time registry key (ADR-0017).
|
|
67
67
|
*/
|
|
68
68
|
const NODE = Symbol.for("prisma:node");
|
|
69
|
+
const SECRET_NEED = blindCast(Symbol.for("prisma:secret-need"));
|
|
70
|
+
/** Declares a secret NEED. Nameless — the platform name is bound at the root via `envSecret`. */
|
|
71
|
+
function secret() {
|
|
72
|
+
return Object.freeze({
|
|
73
|
+
[SECRET_NEED]: true,
|
|
74
|
+
kind: "secret"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
69
77
|
const PROVISION_NEED = blindCast(Symbol.for("prisma:provision-need"));
|
|
70
78
|
/** Builds an opaque provisioning need — the declaring package's own brand plus whatever payload its provisioner reads back. */
|
|
71
79
|
function provisionNeed(brand, payload) {
|
|
@@ -104,6 +112,11 @@ function freezeParams(params) {
|
|
|
104
112
|
for (const [name, param] of Object.entries(params)) frozen[name] = Object.freeze({ ...param });
|
|
105
113
|
return Object.freeze(frozen);
|
|
106
114
|
}
|
|
115
|
+
function freezeSecrets(secrets) {
|
|
116
|
+
const frozen = {};
|
|
117
|
+
for (const [name, need] of Object.entries(secrets)) frozen[name] = Object.freeze({ ...need });
|
|
118
|
+
return blindCast(Object.freeze(frozen));
|
|
119
|
+
}
|
|
107
120
|
/** A frozen shallow copy that keeps the caller's declared type. */
|
|
108
121
|
function frozenShallowCopy(obj) {
|
|
109
122
|
return blindCast(Object.freeze({ ...obj }));
|
|
@@ -157,8 +170,7 @@ function resource(def) {
|
|
|
157
170
|
}
|
|
158
171
|
/**
|
|
159
172
|
* Constructs a branded, frozen Service node — declarations only (inputs,
|
|
160
|
-
* params,
|
|
161
|
-
* carries no runtime behavior.
|
|
173
|
+
* params, build adapter, and the ports it exposes). Pure; carries no runtime behavior.
|
|
162
174
|
*/
|
|
163
175
|
function service$1(def) {
|
|
164
176
|
requireName(def.name, "service");
|
|
@@ -166,7 +178,8 @@ function service$1(def) {
|
|
|
166
178
|
requireType(def.type, "service");
|
|
167
179
|
requireConfigKeySegmentNames(Object.keys(def.inputs), "input", "service");
|
|
168
180
|
requireConfigKeySegmentNames(Object.keys(def.params), "param", "service");
|
|
169
|
-
|
|
181
|
+
requireConfigKeySegmentNames(Object.keys(def.secrets ?? {}), "secret", "service");
|
|
182
|
+
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.`);
|
|
170
183
|
return Object.freeze({
|
|
171
184
|
[NODE]: true,
|
|
172
185
|
kind: "service",
|
|
@@ -175,7 +188,7 @@ function service$1(def) {
|
|
|
175
188
|
type: def.type,
|
|
176
189
|
inputs: frozenShallowCopy(def.inputs),
|
|
177
190
|
params: freezeParams(def.params),
|
|
178
|
-
|
|
191
|
+
secretSlots: freezeSecrets(def.secrets ?? blindCast({})),
|
|
179
192
|
build: Object.freeze({ ...def.build }),
|
|
180
193
|
expose: def.expose !== void 0 ? frozenShallowCopy(def.expose) : void 0
|
|
181
194
|
});
|
|
@@ -208,16 +221,11 @@ function dependency(def) {
|
|
|
208
221
|
* `JSON.stringify`, and `console.log`/`util.inspect` all print `[REDACTED]`, so
|
|
209
222
|
* a secret can't leak through an accidental log or serialization.
|
|
210
223
|
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* symbol key is invisible to `JSON.stringify` and `Object.keys`, so the box's
|
|
214
|
-
* public shape still matches the platform's own `secrecy` type
|
|
215
|
-
* (pdp-control-plane).
|
|
224
|
+
* Shape matches the platform's own `secrecy` type (pdp-control-plane). The class
|
|
225
|
+
* is nominal enough on its own — no phantom brand.
|
|
216
226
|
*/
|
|
217
227
|
const REDACTED = "[REDACTED]";
|
|
218
|
-
const SECRET_BOX = blindCast(Symbol.for("prisma:secret-box"));
|
|
219
228
|
var SecretBox = class {
|
|
220
|
-
[SECRET_BOX] = true;
|
|
221
229
|
#value;
|
|
222
230
|
constructor(value) {
|
|
223
231
|
this.#value = value;
|
|
@@ -242,14 +250,6 @@ var SecretBox = class {
|
|
|
242
250
|
return REDACTED;
|
|
243
251
|
}
|
|
244
252
|
};
|
|
245
|
-
/**
|
|
246
|
-
* True for a redacting secret box — what a schema's secret leaf checks
|
|
247
|
-
* (ADR-0042). Reads the brand rather than `instanceof`, so a box from a
|
|
248
|
-
* duplicated module copy in a bundle counts and a look-alike does not.
|
|
249
|
-
*/
|
|
250
|
-
function isSecretString(value) {
|
|
251
|
-
return typeof value === "object" && value !== null && blindCast(value)[SECRET_BOX] === true;
|
|
252
|
-
}
|
|
253
253
|
function scalarSchema(name, check) {
|
|
254
254
|
return { "~standard": {
|
|
255
255
|
version: 1,
|
|
@@ -275,6 +275,10 @@ function string$1(opts = {}) {
|
|
|
275
275
|
function number$1(opts = {}) {
|
|
276
276
|
return withFacets(numberSchema, opts);
|
|
277
277
|
}
|
|
278
|
+
/** A param over any caller-supplied Standard Schema — a structured `jobs`, say. */
|
|
279
|
+
function param(schema, opts = {}) {
|
|
280
|
+
return withFacets(schema, opts);
|
|
281
|
+
}
|
|
278
282
|
/**
|
|
279
283
|
* Synchronous hydrate — what the node's `load()` uses so
|
|
280
284
|
* `const { db } = service.load()` reads without `await`. Requires every
|
|
@@ -291,6 +295,24 @@ function hydrateSync(root, config) {
|
|
|
291
295
|
}
|
|
292
296
|
return deps;
|
|
293
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* Wraps each of a service's resolved secret values in a redacting `SecretBox`
|
|
300
|
+
* — what the node's `secrets()` accessor returns (ADR-0021, sibling to
|
|
301
|
+
* `load()`/`config()`). The RESOLUTION of a secret's value (the boot
|
|
302
|
+
* double-lookup that reads the platform var the pointer names) is the target
|
|
303
|
+
* pack's job; core is handed the already-resolved strings and only boxes them,
|
|
304
|
+
* so a secret is redacted by TYPE from here on. A declared slot missing from
|
|
305
|
+
* `values` is a target contract violation, named loudly.
|
|
306
|
+
*/
|
|
307
|
+
function hydrateSecrets(root, values) {
|
|
308
|
+
const boxed = {};
|
|
309
|
+
for (const slot of Object.keys(root.secretSlots)) {
|
|
310
|
+
const value = values[slot];
|
|
311
|
+
if (value === void 0) throw new Error(`secret slot "${slot}" has no resolved value — the target must resolve every declared secret before hydrateSecrets().`);
|
|
312
|
+
boxed[slot] = new SecretBox(value);
|
|
313
|
+
}
|
|
314
|
+
return blindCast(boxed);
|
|
315
|
+
}
|
|
294
316
|
/** Bounded jittered backoff for retrying a dropped call. `maxRetries` is retries after the first attempt. */
|
|
295
317
|
const RETRY = {
|
|
296
318
|
initialDelayMs: 250,
|
|
@@ -11670,6 +11692,13 @@ function smtpAttempt(deliveryUrl, credential) {
|
|
|
11670
11692
|
function createSmtpDelivery(opts) {
|
|
11671
11693
|
return withRetryPolicy(smtpAttempt(opts.deliveryUrl, opts.credential), opts.retryPolicy);
|
|
11672
11694
|
}
|
|
11695
|
+
const nodeBuild = (opts) => ({
|
|
11696
|
+
extension: "@prisma/composer/node",
|
|
11697
|
+
type: "node",
|
|
11698
|
+
module: opts.module,
|
|
11699
|
+
entry: opts.entry,
|
|
11700
|
+
...opts.dir === void 0 ? {} : { dir: opts.dir }
|
|
11701
|
+
});
|
|
11673
11702
|
const liftArray = (data) => Array.isArray(data) ? data : [data];
|
|
11674
11703
|
/**
|
|
11675
11704
|
* Splits an array into two arrays based on the result of a predicate
|
|
@@ -18789,28 +18818,6 @@ ark.schema;
|
|
|
18789
18818
|
ark.define;
|
|
18790
18819
|
ark.declare;
|
|
18791
18820
|
/**
|
|
18792
|
-
* ArkType spellings of the framework's schema leaves. Opt-in: the framework
|
|
18793
|
-
* accepts any Standard Schema library (ADR-0042) and nothing outside this
|
|
18794
|
-
* module imports arktype, so an app that uses Zod never loads it.
|
|
18795
|
-
*/
|
|
18796
|
-
/**
|
|
18797
|
-
* A schema leaf that accepts only a redacting `SecretString` box, so
|
|
18798
|
-
* `input().<field>.expose()` type-checks and binding a plain literal there
|
|
18799
|
-
* fails the deploy (ADR-0042).
|
|
18800
|
-
*
|
|
18801
|
-
* ```ts
|
|
18802
|
-
* input: type({ signingKey: secretString() })
|
|
18803
|
-
* ```
|
|
18804
|
-
*/
|
|
18805
|
-
const secretString = () => type("unknown").narrow((value, ctx) => isSecretString(value) || ctx.mustBe("a SecretString box — bind this field to a secret"));
|
|
18806
|
-
const nodeBuild = (opts) => ({
|
|
18807
|
-
extension: "@prisma/composer/node",
|
|
18808
|
-
type: "node",
|
|
18809
|
-
module: opts.module,
|
|
18810
|
-
entry: opts.entry,
|
|
18811
|
-
...opts.dir === void 0 ? {} : { dir: opts.dir }
|
|
18812
|
-
});
|
|
18813
|
-
/**
|
|
18814
18821
|
* Walks a node's own params, then each dependency input's connection params —
|
|
18815
18822
|
* the same enumeration order `configOf` uses, but carrying the raw
|
|
18816
18823
|
* `ConfigParam` (with its `serialize`/`deserialize`) instead of a pure-data
|
|
@@ -18899,7 +18906,7 @@ function coerceEnvSourcedParam(raw, d, key) {
|
|
|
18899
18906
|
/**
|
|
18900
18907
|
* Boot: read each declared param from env by its key, reverse the param's own
|
|
18901
18908
|
* serialization (missing/invalid fails loudly), assemble the typed Config.
|
|
18902
|
-
*
|
|
18909
|
+
* Secrets ride a separate channel (deserializeSecrets), not this one.
|
|
18903
18910
|
*/
|
|
18904
18911
|
const deserialize = (node, address) => {
|
|
18905
18912
|
const service = {};
|
|
@@ -18936,84 +18943,40 @@ const stash = (node, config) => {
|
|
|
18936
18943
|
process.env[configKey("", d)] = encode(d.owner, value);
|
|
18937
18944
|
}
|
|
18938
18945
|
};
|
|
18939
|
-
/** The
|
|
18940
|
-
const
|
|
18941
|
-
/** The input document row's key for a service address. */
|
|
18942
|
-
const inputKey = (address) => configKey(address, {
|
|
18946
|
+
/** The pointer-row key for a secret slot: COMPOSER_<addr>_<slot> (secrets are service-level). */
|
|
18947
|
+
const secretKey = (address, slot) => configKey(address, {
|
|
18943
18948
|
owner: "service",
|
|
18944
|
-
name:
|
|
18949
|
+
name: slot
|
|
18945
18950
|
});
|
|
18946
|
-
const SECRET_MARKER = "$secret";
|
|
18947
|
-
const ESCAPED_KEY = /^\$\$+secret$/;
|
|
18948
|
-
/** True for the framework's secret pointer: `{ "$secret": "<PLATFORM_VAR>" }` and nothing else. */
|
|
18949
|
-
function isSecretPointer(value) {
|
|
18950
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 1 && SECRET_MARKER in value && typeof value[SECRET_MARKER] === "string";
|
|
18951
|
-
}
|
|
18952
|
-
/** A plain data object (not an array, not a class instance) — the only object shape a binding/document may nest. */
|
|
18953
|
-
function isPlainObject(value) {
|
|
18954
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
18955
|
-
const proto = Object.getPrototypeOf(value);
|
|
18956
|
-
return proto === Object.prototype || proto === null;
|
|
18957
|
-
}
|
|
18958
18951
|
/**
|
|
18959
|
-
* Boot:
|
|
18960
|
-
*
|
|
18961
|
-
* platform
|
|
18962
|
-
*
|
|
18963
|
-
* the env var — a deployed environment always writes it; a local harness must
|
|
18964
|
-
* supply it (set the row to the serialized input document).
|
|
18952
|
+
* Boot: resolve every secret slot to its value by double-lookup — read the
|
|
18953
|
+
* pointer key (the platform NAME), then read that platform var. A missing
|
|
18954
|
+
* pointer or a missing/empty platform value is a loud failure naming both keys.
|
|
18955
|
+
* Returns a plain Record for core's `hydrateSecrets` to box.
|
|
18965
18956
|
*/
|
|
18966
|
-
|
|
18967
|
-
const
|
|
18968
|
-
|
|
18969
|
-
|
|
18970
|
-
|
|
18971
|
-
|
|
18972
|
-
|
|
18973
|
-
|
|
18974
|
-
|
|
18975
|
-
}
|
|
18976
|
-
|
|
18977
|
-
|
|
18978
|
-
}
|
|
18979
|
-
const hydrated = hydrateInputDocument(parsed, key);
|
|
18980
|
-
try {
|
|
18981
|
-
return standardValidateSync(schema, hydrated);
|
|
18982
|
-
} catch (cause) {
|
|
18983
|
-
const message = cause instanceof Error ? cause.message : String(cause);
|
|
18984
|
-
throw new Error(`invalid input document (env ${key}): ${message}`);
|
|
18985
|
-
}
|
|
18986
|
-
}
|
|
18987
|
-
/** Reverses the document encoding: `$secret` pointers become redacting boxes over the named platform vars; escaped reserved keys drop one "$". */
|
|
18988
|
-
function hydrateInputDocument(value, key) {
|
|
18989
|
-
if (isSecretPointer(value)) {
|
|
18990
|
-
const name = value[SECRET_MARKER];
|
|
18991
|
-
const secret = process.env[name];
|
|
18992
|
-
if (secret === void 0 || secret === "") throw new Error(`secret input is not provisioned (env ${key} → ${name}): the platform var "${name}" is unset or empty.`);
|
|
18993
|
-
return new SecretBox(secret);
|
|
18994
|
-
}
|
|
18995
|
-
if (Array.isArray(value)) return value.map((member) => hydrateInputDocument(member, key));
|
|
18996
|
-
if (isPlainObject(value)) {
|
|
18997
|
-
const out = {};
|
|
18998
|
-
for (const [k, member] of Object.entries(value)) {
|
|
18999
|
-
const read = ESCAPED_KEY.test(k) ? k.slice(1) : k;
|
|
19000
|
-
out[read] = hydrateInputDocument(member, key);
|
|
19001
|
-
}
|
|
19002
|
-
return out;
|
|
19003
|
-
}
|
|
19004
|
-
return value;
|
|
19005
|
-
}
|
|
18957
|
+
const deserializeSecrets = (node, address) => {
|
|
18958
|
+
const values = {};
|
|
18959
|
+
for (const slot of Object.keys(node.secretSlots)) {
|
|
18960
|
+
const key = secretKey(address, slot);
|
|
18961
|
+
const name = process.env[key];
|
|
18962
|
+
if (name === void 0 || name === "") throw new Error(`missing secret pointer for slot "${slot}" (env ${key}) — the deploy did not write it.`);
|
|
18963
|
+
const value = process.env[name];
|
|
18964
|
+
if (value === void 0 || value === "") throw new Error(`secret "${slot}" is not provisioned (env ${key} → ${name}): the platform var "${name}" is unset or empty.`);
|
|
18965
|
+
values[slot] = value;
|
|
18966
|
+
}
|
|
18967
|
+
return values;
|
|
18968
|
+
};
|
|
19006
18969
|
/**
|
|
19007
|
-
* run()'s setup step for
|
|
19008
|
-
* address-free key, so the address-free `
|
|
19009
|
-
*
|
|
19010
|
-
* platform vars.
|
|
18970
|
+
* run()'s setup step for secrets: re-emit each slot's pointer NAME under its
|
|
18971
|
+
* address-free key, so the address-free `deserializeSecrets` double-looks-up
|
|
18972
|
+
* identically. Never the value — the value stays only in the platform var.
|
|
19011
18973
|
*/
|
|
19012
|
-
const
|
|
19013
|
-
|
|
19014
|
-
|
|
19015
|
-
|
|
19016
|
-
|
|
18974
|
+
const stashSecrets = (node, address) => {
|
|
18975
|
+
for (const slot of Object.keys(node.secretSlots)) {
|
|
18976
|
+
const name = process.env[secretKey(address, slot)];
|
|
18977
|
+
if (name === void 0) continue;
|
|
18978
|
+
process.env[secretKey("", slot)] = name;
|
|
18979
|
+
}
|
|
19017
18980
|
};
|
|
19018
18981
|
/**
|
|
19019
18982
|
* Boot: for each reserved provider param, read its address-scoped row through
|
|
@@ -19194,24 +19157,20 @@ Object.freeze({
|
|
|
19194
19157
|
});
|
|
19195
19158
|
const reservedParams = { port: number$1({ default: 3e3 }) };
|
|
19196
19159
|
/**
|
|
19197
|
-
* A Prisma Compute service — declarations only (deps +
|
|
19198
|
-
*
|
|
19199
|
-
*
|
|
19200
|
-
*
|
|
19160
|
+
* A Prisma Compute service — declarations only (deps + params + build + the
|
|
19161
|
+
* ports it exposes), no descriptor. `params` merges with the reserved
|
|
19162
|
+
* `ReservedParams` (`port`); a user param whose name collides with a reserved
|
|
19163
|
+
* one fails at authoring, the same way a colliding dependency name does.
|
|
19201
19164
|
*
|
|
19202
19165
|
* · run(address, boot) — the process controller: deserialize the platform
|
|
19203
19166
|
* environment (keyed off `address`, the extension's ONE env read) into a
|
|
19204
|
-
* typed Config, re-emit it
|
|
19205
|
-
*
|
|
19206
|
-
* · load() /
|
|
19207
|
-
* load() hydrates + memoizes the deps,
|
|
19208
|
-
*
|
|
19209
|
-
* platform var, validates with the declared schema, and memoizes (ADR-0042).
|
|
19167
|
+
* typed Config, re-emit it under address-free process-local stash keys,
|
|
19168
|
+
* then call boot() to start the app's entry.
|
|
19169
|
+
* · load() / config() — called from inside the app's entry: read the stash;
|
|
19170
|
+
* load() hydrates + memoizes the deps, config() returns the typed params.
|
|
19171
|
+
* Separate accessors so a dep and a param never share a namespace (ADR-0021).
|
|
19210
19172
|
* · origin() — this service's platform-assigned public origin, read from the
|
|
19211
19173
|
* stash `run()` populates; memoized per process.
|
|
19212
|
-
* · port() — this service's resolved reserved port (the value `run()` routes
|
|
19213
|
-
* to and exports as PORT), read from that same stash via #processConfig();
|
|
19214
|
-
* defaults to 3000 when the platform binds none.
|
|
19215
19174
|
*
|
|
19216
19175
|
* The underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
|
|
19217
19176
|
* the control-plane registry key `prisma-composer deploy` resolves through the
|
|
@@ -19221,7 +19180,8 @@ const reservedParams = { port: number$1({ default: 3e3 }) };
|
|
|
19221
19180
|
var ComputeService = class {
|
|
19222
19181
|
#resolved;
|
|
19223
19182
|
#loadedDeps;
|
|
19224
|
-
#
|
|
19183
|
+
#loadedParams;
|
|
19184
|
+
#loadedSecrets;
|
|
19225
19185
|
#origin;
|
|
19226
19186
|
constructor(node) {
|
|
19227
19187
|
Object.assign(this, node);
|
|
@@ -19234,7 +19194,7 @@ var ComputeService = class {
|
|
|
19234
19194
|
const config = deserialize(this, address);
|
|
19235
19195
|
stash(this, config);
|
|
19236
19196
|
stashProviderParams(RESERVED_PROVIDER_PARAMS, address);
|
|
19237
|
-
|
|
19197
|
+
stashSecrets(this, address);
|
|
19238
19198
|
const port = config.service["port"];
|
|
19239
19199
|
if (typeof port === "number") process.env["PORT"] = String(port);
|
|
19240
19200
|
return boot();
|
|
@@ -19243,9 +19203,13 @@ var ComputeService = class {
|
|
|
19243
19203
|
if (this.#loadedDeps === void 0) this.#loadedDeps = blindCast(hydrateSync(this, this.#processConfig()));
|
|
19244
19204
|
return this.#loadedDeps;
|
|
19245
19205
|
}
|
|
19246
|
-
|
|
19247
|
-
if (this.#
|
|
19248
|
-
return this.#
|
|
19206
|
+
config() {
|
|
19207
|
+
if (this.#loadedParams === void 0) this.#loadedParams = blindCast(this.#processConfig().service);
|
|
19208
|
+
return this.#loadedParams;
|
|
19209
|
+
}
|
|
19210
|
+
secrets() {
|
|
19211
|
+
if (this.#loadedSecrets === void 0) this.#loadedSecrets = blindCast(hydrateSecrets(this, deserializeSecrets(this, "")));
|
|
19212
|
+
return this.#loadedSecrets;
|
|
19249
19213
|
}
|
|
19250
19214
|
/** This service's platform-assigned public origin — read from the stash
|
|
19251
19215
|
* run() populates and memoized per process. Throws if called before run()
|
|
@@ -19254,24 +19218,26 @@ var ComputeService = class {
|
|
|
19254
19218
|
this.#origin ??= readOrigin();
|
|
19255
19219
|
return this.#origin;
|
|
19256
19220
|
}
|
|
19257
|
-
/** This service's resolved reserved port — the value run() routes to and
|
|
19258
|
-
* exports as PORT — read the same way load() reads the stash. Defaults to
|
|
19259
|
-
* 3000 when the platform binds none. */
|
|
19260
|
-
port() {
|
|
19261
|
-
const port = this.#processConfig().service["port"];
|
|
19262
|
-
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.`);
|
|
19263
|
-
return port;
|
|
19264
|
-
}
|
|
19265
19221
|
};
|
|
19266
19222
|
const compute = (def) => {
|
|
19267
|
-
|
|
19223
|
+
const userParams = def.params ?? blindCast({});
|
|
19224
|
+
for (const reserved of Object.keys(reservedParams)) {
|
|
19225
|
+
if (reserved in def.deps) throw new Error(`compute(): dependency "${reserved}" collides with the reserved service param of the same name — rename the dependency.`);
|
|
19226
|
+
if (reserved in userParams) throw new Error(`compute(): param "${reserved}" collides with the reserved service param of the same name — rename the param.`);
|
|
19227
|
+
}
|
|
19228
|
+
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.`);
|
|
19229
|
+
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.`);
|
|
19230
|
+
const params = blindCast({
|
|
19231
|
+
...userParams,
|
|
19232
|
+
...reservedParams
|
|
19233
|
+
});
|
|
19268
19234
|
const instance = new ComputeService(service$1({
|
|
19269
19235
|
name: def.name,
|
|
19270
19236
|
extension: "@prisma/composer-prisma-cloud",
|
|
19271
19237
|
type: "compute",
|
|
19272
19238
|
inputs: def.deps,
|
|
19273
|
-
params
|
|
19274
|
-
...def.
|
|
19239
|
+
params,
|
|
19240
|
+
...def.secrets !== void 0 ? { secrets: def.secrets } : {},
|
|
19275
19241
|
build: def.build,
|
|
19276
19242
|
...def.expose !== void 0 ? { expose: def.expose } : {}
|
|
19277
19243
|
}));
|
|
@@ -19371,27 +19337,25 @@ const emailOutboxContract = contract({
|
|
|
19371
19337
|
});
|
|
19372
19338
|
/**
|
|
19373
19339
|
* The email compute service (spec §"Service definition"): a Postgres `db`
|
|
19374
|
-
* dependency,
|
|
19375
|
-
* `deliveryCredential` secret
|
|
19376
|
-
*
|
|
19377
|
-
*
|
|
19378
|
-
*
|
|
19379
|
-
*
|
|
19380
|
-
*
|
|
19381
|
-
* bootstrap can re-import it as `main` and call `main.run(address, boot)`;
|
|
19382
|
-
* `entry` resolves the sibling entrypoint pass in the same dist directory.
|
|
19340
|
+
* dependency, the `deliveryMode`/`deliveryUrl`/`from` params, the
|
|
19341
|
+
* `deliveryCredential` secret, and the two exposed ports (`send`, `outbox`).
|
|
19342
|
+
* Build/entry mechanics copied from storage's service file
|
|
19343
|
+
* (`storage/src/storage-service.ts`), not re-derived: `build.module` points
|
|
19344
|
+
* at this file's own built output so the deploy bootstrap can re-import it
|
|
19345
|
+
* as `main` and call `main.run(address, boot)`; `entry` resolves the
|
|
19346
|
+
* sibling entrypoint pass in the same dist directory.
|
|
19383
19347
|
*/
|
|
19384
|
-
const
|
|
19385
|
-
|
|
19386
|
-
deliveryUrl: "string",
|
|
19387
|
-
from: "string",
|
|
19388
|
-
deliveryCredential: secretString()
|
|
19389
|
-
});
|
|
19390
|
-
function emailService() {
|
|
19348
|
+
const deliveryModeSchema = type("'resend'|'smtp'|'none'");
|
|
19349
|
+
function emailService(opts) {
|
|
19391
19350
|
return compute({
|
|
19392
19351
|
name: "email",
|
|
19393
19352
|
deps: { db: postgres() },
|
|
19394
|
-
|
|
19353
|
+
params: {
|
|
19354
|
+
deliveryMode: param(deliveryModeSchema),
|
|
19355
|
+
deliveryUrl: string$1({ default: opts?.deliveryUrl ?? "https://api.resend.com" }),
|
|
19356
|
+
from: string$1()
|
|
19357
|
+
},
|
|
19358
|
+
secrets: { deliveryCredential: secret() },
|
|
19395
19359
|
expose: {
|
|
19396
19360
|
send: emailSendContract,
|
|
19397
19361
|
outbox: emailOutboxContract
|
|
@@ -19740,8 +19704,8 @@ function checkDeliveryUrl(deliveryMode, deliveryUrl) {
|
|
|
19740
19704
|
}
|
|
19741
19705
|
const service = emailService();
|
|
19742
19706
|
const { db } = service.load();
|
|
19743
|
-
const { deliveryMode, deliveryUrl, from,
|
|
19744
|
-
const
|
|
19707
|
+
const { deliveryMode, deliveryUrl, from, port } = service.config();
|
|
19708
|
+
const { deliveryCredential } = service.secrets();
|
|
19745
19709
|
const deliveryUrlError = checkDeliveryUrl(deliveryMode, deliveryUrl);
|
|
19746
19710
|
if (deliveryUrlError !== null) throw new Error(deliveryUrlError);
|
|
19747
19711
|
const handlers = createHandlers({
|