@prisma/composer-prisma-cloud 0.1.0-dev.1 → 0.1.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 (35) hide show
  1. package/dist/control.d.mts +41 -1
  2. package/dist/control.mjs +137 -17
  3. package/dist/control.mjs.map +1 -1
  4. package/dist/cron/index.mjs +72 -7
  5. package/dist/cron/index.mjs.map +1 -1
  6. package/dist/cron/scheduler-entrypoint.mjs +158 -93
  7. package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
  8. package/dist/cron/scheduler-service.mjs +72 -7
  9. package/dist/cron/scheduler-service.mjs.map +1 -1
  10. package/dist/index.d.mts +34 -15
  11. package/dist/index.mjs +4 -5
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/{param-DB0B8m15-IvzNq9BM.mjs → provisioned-edges-Bb7WiV49-DeSPi3Ax.mjs} +86 -27
  14. package/dist/provisioned-edges-Bb7WiV49-DeSPi3Ax.mjs.map +1 -0
  15. package/dist/{serializer-DAEWRfnm-D3GW9dOZ.mjs → serializer-CX4VYdf_-KKGoAxfx.mjs} +29 -3
  16. package/dist/{serializer-DAEWRfnm-D3GW9dOZ.mjs.map → serializer-CX4VYdf_-KKGoAxfx.mjs.map} +1 -1
  17. package/dist/serializer-Cx5slrV4-xJfH6EWS.d.mts +36 -0
  18. package/dist/storage/index.d.mts +1 -0
  19. package/dist/storage/index.mjs +73 -7
  20. package/dist/storage/index.mjs.map +1 -1
  21. package/dist/storage/storage-entrypoint.mjs +7197 -12
  22. package/dist/storage/storage-entrypoint.mjs.map +1 -1
  23. package/dist/storage/storage-service.mjs +73 -7
  24. package/dist/storage/storage-service.mjs.map +1 -1
  25. package/dist/streams/index.d.mts +219 -16
  26. package/dist/streams/index.mjs +3354 -30
  27. package/dist/streams/index.mjs.map +1 -1
  28. package/dist/streams/streams-entrypoint.mjs +7731 -221
  29. package/dist/streams/streams-entrypoint.mjs.map +1 -1
  30. package/dist/streams/streams-service.mjs +399 -20
  31. package/dist/streams/streams-service.mjs.map +1 -1
  32. package/dist/testing.mjs +1 -1
  33. package/dist/testing.mjs.map +1 -1
  34. package/package.json +13 -13
  35. package/dist/param-DB0B8m15-IvzNq9BM.mjs.map +0 -1
@@ -1,3 +1,4 @@
1
+ import { t as ProviderParamEntry } from "./serializer-Cx5slrV4-xJfH6EWS.mjs";
1
2
  import * as Layer from "effect/Layer";
2
3
  import { createManagementApiClient } from "@prisma/management-api-sdk";
3
4
  import "effect/Context";
@@ -9,6 +10,7 @@ import { Resource, StackServices } from "alchemy";
9
10
  import "effect/Schedule";
10
11
  import postgres from "postgres";
11
12
  import { State, StateStoreError } from "alchemy/State";
13
+ import * as Output from "alchemy/Output";
12
14
  import { ExtensionDescriptor } from "@prisma/composer/config";
13
15
  //#region ../../1-prisma-cloud/0-lowering/lowering/dist/compute/index.d.mts
14
16
  /** Every region Prisma Compute serves — the runtime source of truth; `ComputeRegion` is derived from it so the two can never drift. */
@@ -39,6 +41,33 @@ type ComputeRegion = (typeof COMPUTE_REGIONS)[number];
39
41
  declare const prismaState: () => Layer.Layer<State, never, StackServices>;
40
42
  //#endregion
41
43
  //#region ../../1-prisma-cloud/1-extensions/target/dist/control.d.mts
44
+ //#region src/descriptors/shared.d.ts
45
+ /**
46
+ * The provider-side reserved param for one brand's minted values (ADR-0031:
47
+ * "the provisioner owns mint, size, **aggregation**, stability, and
48
+ * rotation", and ADR-0019: the physical encoding is the target's). `value`
49
+ * is deploy-side: given every inbound edge's minted ref for one provider
50
+ * (possibly empty), it returns the typed value to store, or `undefined` to
51
+ * write no row. The returned value is encoded through the serializer's
52
+ * normal service-own literal path (JSON) — the same path any declared param
53
+ * takes — never a brand-invented wire format.
54
+ *
55
+ * This is the seam that keeps `descriptors/compute.ts` brand-blind: a
56
+ * `ProviderParam` is registered beside its brand's provisioner in
57
+ * `control.ts`; the descriptor asks every registered entry about every
58
+ * exposing service and writes whatever comes back.
59
+ */
60
+ interface ProviderParam extends ProviderParamEntry {
61
+ /**
62
+ * Every inbound edge's minted ref for this provider — POSSIBLY EMPTY. A
63
+ * provider with no wired consumers is still asked, because "no edges" and
64
+ * "no var" mean different things at boot: an absent var reads as "never
65
+ * provisioned" (local dev, tests). What an empty set means is this param's
66
+ * own call — deny everything, or emit nothing and let its reader fail closed.
67
+ */
68
+ readonly value: (refs: readonly unknown[]) => Output.Output<unknown> | unknown | undefined;
69
+ }
70
+ //#endregion
42
71
  //#region src/control.d.ts
43
72
  interface PrismaCloudOptions {
44
73
  /** Defaults to the PRISMA_WORKSPACE_ID environment variable. */
@@ -46,8 +75,19 @@ interface PrismaCloudOptions {
46
75
  /** Defaults to the PRISMA_REGION environment variable when set. */
47
76
  region?: ComputeRegion;
48
77
  }
78
+ /**
79
+ * Builds the deploy-side registry from the boot-side list, keyed by brand —
80
+ * throws if a boot-side entry has no registered deploy-side `value(refs)`, so
81
+ * `RESERVED_PROVIDER_PARAMS` stays the single source of which reserved
82
+ * provider params exist: deploy can no longer write a row boot never
83
+ * stashes. Exported (rather than inlined into `PROVIDER_PARAMS` below) so
84
+ * `__tests__/provider-params.test.ts` can drive it directly with a
85
+ * deliberately incomplete value map and watch it throw.
86
+ */
87
+ declare function buildProviderParams(entries: readonly ProviderParamEntry[], values: ReadonlyMap<symbol, ProviderParam['value']>): ReadonlyMap<symbol, ProviderParam>;
88
+ declare const PROVIDER_PARAMS: ReadonlyMap<symbol, ProviderParam>;
49
89
  /** The Prisma Cloud extension descriptor — `prisma-composer.config.ts` lists it under `extensions`. */
50
90
  declare const prismaCloud: (opts?: PrismaCloudOptions) => ExtensionDescriptor;
51
91
  //#endregion
52
- export { PrismaCloudOptions, prismaCloud, prismaState };
92
+ export { PROVIDER_PARAMS, PrismaCloudOptions, buildProviderParams, prismaCloud, prismaState };
53
93
  //# sourceMappingURL=control.d.mts.map
package/dist/control.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { a as encodeParamPointer, c as secretName, i as encode, l as secretPointerRows, s as paramEntries, t as configKey } from "./serializer-DAEWRfnm-D3GW9dOZ.mjs";
2
- import { a as serviceKeyEdges, i as paramName, n as isEnvParamSource, o as serviceKeyEnvName, r as paramBindingFor } from "./param-DB0B8m15-IvzNq9BM.mjs";
1
+ import { a as encodeParamPointer, c as secretName, i as encode, l as secretPointerRows, s as paramEntries, t as configKey } from "./serializer-CX4VYdf_-KKGoAxfx.mjs";
2
+ import { a as isEnvParamSource, c as provisionedEdges, n as STREAMS_API_KEY, o as paramBindingFor, s as paramName, t as RESERVED_PROVIDER_PARAMS } from "./provisioned-edges-Bb7WiV49-DeSPi3Ax.mjs";
3
3
  import { a as normalizeSslMode, n as isPnPostgresResourceNode, o as withConnectionRetry } from "./prisma-next-COrwlg3N.mjs";
4
4
  import { isParamSource, paramManifest, provisionManifest } from "@prisma/composer";
5
5
  import { blindCast } from "@prisma/composer/casts";
@@ -1293,16 +1293,31 @@ function computeDescriptor(o) {
1293
1293
  ...branch
1294
1294
  }));
1295
1295
  if (svc.expose !== void 0 && Object.keys(svc.expose).length > 0) {
1296
- const keyOuts = serviceKeyEdges(graph).filter((e) => e.providerAddress === address).map((e) => ctx.provisioned.get(e.edgeId)).filter((value) => value !== void 0).map((value) => blindCast(value));
1297
- const acceptedJson = keyOuts.length > 0 ? Output.map(Output.all(...keyOuts), (vals) => JSON.stringify(vals)) : JSON.stringify([]);
1298
- const key = serviceKeyEnvName(address);
1299
- records.push(yield* EnvironmentVariable(`${key}-var`, {
1300
- projectId,
1301
- key,
1302
- value: acceptedJson,
1303
- class: cls,
1304
- ...branch
1305
- }));
1296
+ const refsByBrand = /* @__PURE__ */ new Map();
1297
+ for (const edge of provisionedEdges(graph)) {
1298
+ if (edge.providerAddress !== address) continue;
1299
+ const ref = ctx.provisioned.get(edge.edgeId);
1300
+ if (ref === void 0) continue;
1301
+ const refs = refsByBrand.get(edge.brand) ?? [];
1302
+ refs.push(ref);
1303
+ refsByBrand.set(edge.brand, refs);
1304
+ }
1305
+ for (const [brand, entry] of o.providerParams) {
1306
+ const raw = entry.value(refsByBrand.get(brand) ?? []);
1307
+ if (raw === void 0) continue;
1308
+ const key = configKey(address, {
1309
+ owner: "service",
1310
+ name: entry.name
1311
+ });
1312
+ const value = Output.isOutput(raw) ? Output.map(raw, (v) => encode("service", v)) : encode("service", raw);
1313
+ records.push(yield* EnvironmentVariable(`${key}-var`, {
1314
+ projectId,
1315
+ key,
1316
+ value,
1317
+ class: cls,
1318
+ ...branch
1319
+ }));
1320
+ }
1306
1321
  }
1307
1322
  return {
1308
1323
  environment: records,
@@ -1957,6 +1972,63 @@ async function runTeardown(input, deps) {
1957
1972
  const serviceKeyProvisioner = { provision: (edge) => Effect.gen(function* () {
1958
1973
  return (yield* ServiceKey(`servicekey-${edge.edgeId}`, {})).value;
1959
1974
  }) };
1975
+ /**
1976
+ * `ctx.provisioned`'s refs are typed `unknown` — core forwards a provisioner's
1977
+ * ref without inspecting it. Each provider param below is the sole reader of
1978
+ * its own provisioner's output, so the shape is asserted here, once, rather
1979
+ * than checked.
1980
+ */
1981
+ const asKeyOutputs = (refs) => refs.map((ref) => blindCast(ref));
1982
+ /**
1983
+ * RPC's deploy-side `value(refs)` (ADR-0030): the provider stores a SET — one
1984
+ * key per inbound edge — into the accepted-keys var `serve()` reads. Paired
1985
+ * with the provisioner above: mint per edge, aggregate every edge.
1986
+ *
1987
+ * Zero consumers still emits, and that is the whole point of #100: an ABSENT
1988
+ * var means "never provisioned" and passes every caller through, so a deployed
1989
+ * provider nobody wired must say "[]" — deny everything — rather than say
1990
+ * nothing. Written as a literal because `Output.all()` with no arguments has
1991
+ * nothing to resolve.
1992
+ */
1993
+ const rpcAcceptedKeysValue = (refs) => refs.length > 0 ? Output.all(...asKeyOutputs(refs)) : [];
1994
+ /**
1995
+ * ADR-0031's registered provisioner for STREAMS_API_KEY — the same `ServiceKey`
1996
+ * mint, keyed PER PROVIDER instead of per edge: the resource id is the
1997
+ * provider's address, so every consumer edge of one streams module resolves to
1998
+ * the same resource and therefore the same stable value. That is what
1999
+ * `@prisma/streams-server` requires (it authenticates a single `API_KEY`), and
2000
+ * cardinality is exactly what ADR-0031 leaves to the provisioner. Making it
2001
+ * per-edge later is this id's shape plus an accepted-set provider param — no
2002
+ * new resource, no core change.
2003
+ */
2004
+ const streamsApiKeyProvisioner = { provision: (edge) => Effect.gen(function* () {
2005
+ return (yield* ServiceKey(`streamskey-${edge.providerAddress}`, {})).value;
2006
+ }) };
2007
+ /**
2008
+ * Streams' deploy-side `value(refs)`: ONE value, not a set —
2009
+ * `@prisma/streams-server` authenticates a single `API_KEY`, which is why the
2010
+ * provisioner above mints per provider. That pairing is the invariant this
2011
+ * param depends on, so it asserts rather than trusts it: a future per-edge
2012
+ * flip without a paired accepted-set param here would otherwise ship
2013
+ * whichever key came first and leave every other consumer 401ing, silently.
2014
+ * The refs are lazy Outputs (not comparable at serialize time); inside
2015
+ * `Output.map` they are resolved strings, the same seam RPC's set aggregates
2016
+ * on.
2017
+ *
2018
+ * Zero consumers emits NOTHING — the streams counterpart to RPC's "[]".
2019
+ * `@prisma/streams-server` has no deny-all mode: it either authenticates a key
2020
+ * or runs --no-auth, so there is no value here that means "refuse everyone".
2021
+ * Writing no key is what fails closed — the entrypoint refuses to boot with
2022
+ * a named error rather than serve unauthenticated.
2023
+ */
2024
+ const streamsApiKeyValue = (refs) => {
2025
+ if (refs.length === 0) return void 0;
2026
+ return Output.map(Output.all(...asKeyOutputs(refs)), (vals) => {
2027
+ const distinct = [...new Set(vals)];
2028
+ if (distinct.length > 1) throw new Error(`a streams provider was provisioned ${distinct.length} distinct keys across its ${refs.length} inbound bindings, but it can only be given one (@prisma/streams-server authenticates a single API_KEY). Its provisioner must mint per provider, not per edge — or this param must store an accepted-key set, once the server accepts one.`);
2029
+ return distinct[0] ?? "";
2030
+ });
2031
+ };
1960
2032
  const KNOWN_REGION_SET = new Set(COMPUTE_REGIONS);
1961
2033
  function isComputeRegion(value) {
1962
2034
  return KNOWN_REGION_SET.has(value);
@@ -1966,6 +2038,51 @@ function asProvidersLayer(layer) {
1966
2038
  return layer;
1967
2039
  }
1968
2040
  /**
2041
+ * This extension's brands, each with the two halves ADR-0031 splits: the
2042
+ * PROVISIONER core resolves a mint through, and the reserved PROVIDER PARAM
2043
+ * that stores the minted values on the provider. So this file stays the only
2044
+ * place a brand is named — `descriptors/compute.ts` just looks a provider
2045
+ * param up by brand.
2046
+ *
2047
+ * `__tests__/provider-params.test.ts` asserts this map's brands are exactly
2048
+ * `PROVIDER_PARAMS`'s brands: a brand minted here with no provider param
2049
+ * below would leave the value it mints written to consumers while no
2050
+ * provider ever stores an accepted-keys row for it — `serve()` (or the
2051
+ * equivalent runtime reader) then sees an absent var and passes every caller
2052
+ * through.
2053
+ */
2054
+ const PROVISIONERS = /* @__PURE__ */ new Map([[RPC_PEER_KEY, serviceKeyProvisioner], [STREAMS_API_KEY, streamsApiKeyProvisioner]]);
2055
+ /**
2056
+ * Every brand's deploy-side `value(refs)` — the only per-brand thing this
2057
+ * file still holds directly. `PROVIDER_PARAMS` below is built by mapping
2058
+ * `RESERVED_PROVIDER_PARAMS` (`provider-params.ts`, the boot-side list) onto
2059
+ * this map, so a param can exist on the deploy side only if it already
2060
+ * exists on the boot side: `RESERVED_PROVIDER_PARAMS` is the single source of
2061
+ * which reserved provider params exist at all, closing the drift the old
2062
+ * name-comparison test only detected after the fact.
2063
+ */
2064
+ const PROVIDER_PARAM_VALUES = /* @__PURE__ */ new Map([[RPC_PEER_KEY, rpcAcceptedKeysValue], [STREAMS_API_KEY, streamsApiKeyValue]]);
2065
+ /**
2066
+ * Builds the deploy-side registry from the boot-side list, keyed by brand —
2067
+ * throws if a boot-side entry has no registered deploy-side `value(refs)`, so
2068
+ * `RESERVED_PROVIDER_PARAMS` stays the single source of which reserved
2069
+ * provider params exist: deploy can no longer write a row boot never
2070
+ * stashes. Exported (rather than inlined into `PROVIDER_PARAMS` below) so
2071
+ * `__tests__/provider-params.test.ts` can drive it directly with a
2072
+ * deliberately incomplete value map and watch it throw.
2073
+ */
2074
+ function buildProviderParams(entries, values) {
2075
+ return new Map(entries.map((entry) => {
2076
+ const value = values.get(entry.brand);
2077
+ if (value === void 0) throw new Error(`prisma-cloud: reserved provider param "${entry.name}" (provider-params.ts) has no registered deploy-side value() in control.ts's PROVIDER_PARAM_VALUES — every param in RESERVED_PROVIDER_PARAMS must have one.`);
2078
+ return [entry.brand, {
2079
+ ...entry,
2080
+ value
2081
+ }];
2082
+ }));
2083
+ }
2084
+ const PROVIDER_PARAMS = buildProviderParams(RESERVED_PROVIDER_PARAMS, PROVIDER_PARAM_VALUES);
2085
+ /**
1969
2086
  * Resolves the factory's env-or-option inputs, failing fast with the exact
1970
2087
  * variable name. `projectId`/`branchId` aren't required here — `prismaCloud()`
1971
2088
  * also runs in the CLI parent, before they're set; the required check lives in `application.provision`.
@@ -1979,20 +2096,23 @@ function resolveOptions(opts) {
1979
2096
  workspaceId,
1980
2097
  region: opts.region,
1981
2098
  projectId,
1982
- branchId
2099
+ branchId,
2100
+ providerParams: PROVIDER_PARAMS
1983
2101
  };
1984
2102
  const region = process.env["PRISMA_REGION"];
1985
2103
  if (region === void 0 || region.length === 0) return {
1986
2104
  workspaceId,
1987
2105
  projectId,
1988
- branchId
2106
+ branchId,
2107
+ providerParams: PROVIDER_PARAMS
1989
2108
  };
1990
2109
  if (!isComputeRegion(region)) throw new Error(`prismaCloud(): environment variable PRISMA_REGION="${region}" is not a known region (expected one of: ${COMPUTE_REGIONS.join(", ")}).`);
1991
2110
  return {
1992
2111
  workspaceId,
1993
2112
  region,
1994
2113
  projectId,
1995
- branchId
2114
+ branchId,
2115
+ providerParams: PROVIDER_PARAMS
1996
2116
  };
1997
2117
  }
1998
2118
  /** The Prisma Cloud extension descriptor — `prisma-composer.config.ts` lists it under `extensions`. */
@@ -2015,7 +2135,7 @@ const prismaCloud = (opts = {}) => {
2015
2135
  });
2016
2136
  return { projectId };
2017
2137
  }) },
2018
- provisions: /* @__PURE__ */ new Map([[RPC_PEER_KEY, serviceKeyProvisioner]]),
2138
+ provisions: PROVISIONERS,
2019
2139
  nodes: {
2020
2140
  postgres: postgresDescriptor(o),
2021
2141
  "prisma-next": prismaNextDescriptor(o),
@@ -2026,6 +2146,6 @@ const prismaCloud = (opts = {}) => {
2026
2146
  };
2027
2147
  };
2028
2148
  //#endregion
2029
- export { prismaCloud, prismaState };
2149
+ export { PROVIDER_PARAMS, buildProviderParams, prismaCloud, prismaState };
2030
2150
 
2031
2151
  //# sourceMappingURL=control.mjs.map