@prisma/composer-prisma-cloud 0.1.0-dev.9 → 0.2.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/control.d.mts +6 -29
- package/dist/control.mjs +452 -65
- package/dist/control.mjs.map +1 -1
- package/dist/cron/index.mjs +10 -2
- package/dist/cron/index.mjs.map +1 -1
- package/dist/cron/scheduler-entrypoint.mjs +69 -20
- package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
- package/dist/cron/scheduler-service.mjs +10 -2
- package/dist/cron/scheduler-service.mjs.map +1 -1
- package/dist/index.d.mts +40 -1
- package/dist/index.mjs +41 -1
- package/dist/index.mjs.map +1 -1
- package/dist/{prisma-next-qPB8_Az6.mjs → prisma-next-DlU01kXJ-2sP5mQb6.mjs} +3 -3
- package/dist/prisma-next-DlU01kXJ-2sP5mQb6.mjs.map +1 -0
- package/dist/prisma-next.d.mts +1 -1
- package/dist/prisma-next.mjs +1 -1
- package/dist/storage/index.d.mts +11 -10
- package/dist/storage/index.mjs +11 -3
- package/dist/storage/index.mjs.map +1 -1
- package/dist/storage/storage-entrypoint.mjs +10 -0
- package/dist/storage/storage-entrypoint.mjs.map +1 -1
- package/dist/storage/storage-service.mjs +11 -3
- package/dist/storage/storage-service.mjs.map +1 -1
- package/dist/storage/testing.mjs.map +1 -1
- package/dist/streams/index.d.mts +13 -12
- package/dist/streams/index.mjs +12 -4
- package/dist/streams/index.mjs.map +1 -1
- package/dist/streams/streams-entrypoint.mjs +10 -0
- package/dist/streams/streams-entrypoint.mjs.map +1 -1
- package/dist/streams/streams-service.mjs +11 -3
- package/dist/streams/streams-service.mjs.map +1 -1
- package/dist/streams/testing.d.mts +1 -1
- package/dist/streams/testing.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.mjs.map +1 -1
- package/package.json +14 -14
- package/dist/prisma-next-qPB8_Az6.mjs.map +0 -1
package/dist/control.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
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
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-DIQAR4q4-Bn9op-JG.mjs";
|
|
3
|
-
import { a as normalizeSslMode, n as isPnPostgresResourceNode, o as withConnectionRetry } from "./prisma-next-
|
|
3
|
+
import { a as normalizeSslMode, n as isPnPostgresResourceNode, o as withConnectionRetry } from "./prisma-next-DlU01kXJ-2sP5mQb6.mjs";
|
|
4
4
|
import { isParamSource, paramManifest, provisionManifest } from "@prisma/composer";
|
|
5
5
|
import { blindCast } from "@prisma/composer/casts";
|
|
6
6
|
import { RPC_PEER_KEY } from "@prisma/composer/service-rpc";
|
|
7
7
|
import pg from "pg";
|
|
8
|
-
import * as Layer from "effect/Layer";
|
|
9
8
|
import { createManagementApiClient } from "@prisma/management-api-sdk";
|
|
10
9
|
import * as Context from "effect/Context";
|
|
11
10
|
import * as Effect from "effect/Effect";
|
|
11
|
+
import * as Layer from "effect/Layer";
|
|
12
12
|
import * as Redacted from "effect/Redacted";
|
|
13
13
|
import * as Config$1 from "effect/Config";
|
|
14
14
|
import * as Data from "effect/Data";
|
|
@@ -28,7 +28,7 @@ import { resolve } from "pathe";
|
|
|
28
28
|
import { readRef } from "@prisma-next/migration-tools/refs";
|
|
29
29
|
import { APP_SPACE_ID, readContractSpaceHeadRef, spaceMigrationDirectory, spaceRefsDirectory } from "@prisma-next/migration-tools/spaces";
|
|
30
30
|
import { createPostgresControlClient } from "@prisma-next/postgres/control";
|
|
31
|
-
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/http-
|
|
31
|
+
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/http-CJM0E6rj.mjs
|
|
32
32
|
/**
|
|
33
33
|
* The Prisma service token used to authenticate Management API calls. Kept
|
|
34
34
|
* as a Redacted value so it never lands in logs or error output.
|
|
@@ -68,6 +68,84 @@ const callOptional = (f) => attempt$1(f).pipe(Effect.flatMap((r) => r.response.s
|
|
|
68
68
|
/** Fire-and-forget a call, tolerating a 404 (already deleted). */
|
|
69
69
|
const callVoid = (f) => attempt$1(f).pipe(Effect.flatMap((r) => r.response.status === 404 || r.error === void 0 ? Effect.void : fail(r)));
|
|
70
70
|
//#endregion
|
|
71
|
+
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/buckets.mjs
|
|
72
|
+
/** A Prisma **Object Store bucket** inside a project. */
|
|
73
|
+
const Bucket = Resource("Prisma.Bucket");
|
|
74
|
+
const BucketProvider = () => Provider.effect(Bucket, Effect.gen(function* () {
|
|
75
|
+
const client = yield* ManagementClient;
|
|
76
|
+
return {
|
|
77
|
+
stables: ["id"],
|
|
78
|
+
list: () => Effect.succeed([]),
|
|
79
|
+
reconcile: Effect.fn(function* ({ news, output }) {
|
|
80
|
+
const observed = output?.id ? yield* callOptional(() => client.GET("/v1/buckets/{bucketId}", { params: { path: { bucketId: output.id } } })) : void 0;
|
|
81
|
+
if (observed) return {
|
|
82
|
+
id: observed.data.id,
|
|
83
|
+
name: observed.data.name
|
|
84
|
+
};
|
|
85
|
+
const created = yield* call(() => client.POST("/v1/buckets", { body: {
|
|
86
|
+
projectId: news.projectId,
|
|
87
|
+
name: news.name,
|
|
88
|
+
...news.branchId !== void 0 ? { branchId: news.branchId } : {}
|
|
89
|
+
} }));
|
|
90
|
+
return {
|
|
91
|
+
id: created.data.id,
|
|
92
|
+
name: created.data.name
|
|
93
|
+
};
|
|
94
|
+
}),
|
|
95
|
+
delete: Effect.fn(function* ({ output }) {
|
|
96
|
+
yield* callVoid(() => client.DELETE("/v1/buckets/{bucketId}", { params: { path: { bucketId: output.id } } }));
|
|
97
|
+
}),
|
|
98
|
+
read: Effect.fn(function* ({ output }) {
|
|
99
|
+
if (!output?.id) return void 0;
|
|
100
|
+
const b = yield* callOptional(() => client.GET("/v1/buckets/{bucketId}", { params: { path: { bucketId: output.id } } }));
|
|
101
|
+
return b ? {
|
|
102
|
+
id: b.data.id,
|
|
103
|
+
name: b.data.name
|
|
104
|
+
} : void 0;
|
|
105
|
+
})
|
|
106
|
+
};
|
|
107
|
+
}));
|
|
108
|
+
/** A **bucket access key** for a Prisma Object Store bucket — yields the S3 credentials. */
|
|
109
|
+
const BucketKey = Resource("Prisma.BucketKey");
|
|
110
|
+
const BucketKeyProvider = () => Provider.effect(BucketKey, Effect.gen(function* () {
|
|
111
|
+
const client = yield* ManagementClient;
|
|
112
|
+
return {
|
|
113
|
+
stables: [
|
|
114
|
+
"id",
|
|
115
|
+
"bucketId",
|
|
116
|
+
"secretAccessKey",
|
|
117
|
+
"accessKeyId",
|
|
118
|
+
"endpoint",
|
|
119
|
+
"bucketName"
|
|
120
|
+
],
|
|
121
|
+
list: () => Effect.succeed([]),
|
|
122
|
+
reconcile: Effect.fn(function* ({ news, output }) {
|
|
123
|
+
if (output?.id) return output;
|
|
124
|
+
const created = yield* call(() => client.POST("/v1/buckets/{bucketId}/keys", {
|
|
125
|
+
params: { path: { bucketId: news.bucketId } },
|
|
126
|
+
body: {
|
|
127
|
+
name: news.name,
|
|
128
|
+
role: news.role
|
|
129
|
+
}
|
|
130
|
+
}));
|
|
131
|
+
return {
|
|
132
|
+
id: created.data.id,
|
|
133
|
+
bucketId: news.bucketId,
|
|
134
|
+
accessKeyId: created.data.accessKeyId,
|
|
135
|
+
secretAccessKey: Redacted.make(created.data.secretAccessKey),
|
|
136
|
+
endpoint: created.data.endpoint,
|
|
137
|
+
bucketName: created.data.bucketName
|
|
138
|
+
};
|
|
139
|
+
}),
|
|
140
|
+
delete: Effect.fn(function* ({ output }) {
|
|
141
|
+
yield* callVoid(() => client.DELETE("/v1/buckets/{bucketId}/keys/{keyId}", { params: { path: {
|
|
142
|
+
bucketId: output.bucketId,
|
|
143
|
+
keyId: output.id
|
|
144
|
+
} } }));
|
|
145
|
+
})
|
|
146
|
+
};
|
|
147
|
+
}));
|
|
148
|
+
//#endregion
|
|
71
149
|
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/compute.mjs
|
|
72
150
|
/**
|
|
73
151
|
* Stopping a deployment before the app that owns it can be
|
|
@@ -470,25 +548,23 @@ const DatabaseProvider = () => Provider.effect(Database, Effect.gen(function* ()
|
|
|
470
548
|
list: () => Effect.succeed([]),
|
|
471
549
|
reconcile: Effect.fn(function* ({ news, output }) {
|
|
472
550
|
const observed = output?.id ? yield* callOptional(() => client.GET("/v1/databases/{databaseId}", { params: { path: { databaseId: output.id } } })) : void 0;
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
name: news.name,
|
|
483
|
-
region: news.region,
|
|
484
|
-
...news.isDefault !== void 0 && { isDefault: news.isDefault }
|
|
485
|
-
}
|
|
486
|
-
}));
|
|
487
|
-
result = {
|
|
551
|
+
if (!observed) {
|
|
552
|
+
const created = yield* call(() => client.POST("/v1/databases", { body: {
|
|
553
|
+
projectId: news.projectId,
|
|
554
|
+
name: news.name,
|
|
555
|
+
region: news.region,
|
|
556
|
+
...news.isDefault !== void 0 && { isDefault: news.isDefault },
|
|
557
|
+
...news.branchId !== void 0 && { branchId: news.branchId }
|
|
558
|
+
} }));
|
|
559
|
+
return {
|
|
488
560
|
id: created.data.id,
|
|
489
561
|
name: created.data.name
|
|
490
562
|
};
|
|
491
563
|
}
|
|
564
|
+
const result = {
|
|
565
|
+
id: observed.data.id,
|
|
566
|
+
name: observed.data.name
|
|
567
|
+
};
|
|
492
568
|
if (news.branchId !== void 0) {
|
|
493
569
|
const branchId = news.branchId;
|
|
494
570
|
yield* call(() => client.PATCH("/v1/databases/{databaseId}", {
|
|
@@ -546,7 +622,107 @@ const ProjectProvider = () => Provider.effect(Project, Effect.gen(function* () {
|
|
|
546
622
|
})
|
|
547
623
|
};
|
|
548
624
|
}));
|
|
549
|
-
|
|
625
|
+
//#endregion
|
|
626
|
+
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/index.mjs
|
|
627
|
+
/** Raised with `ensure: false` when the app's Project (or a named stage's Branch) doesn't exist. */
|
|
628
|
+
var ContainerNotFoundError = class extends Data.TaggedError("ContainerNotFoundError") {};
|
|
629
|
+
const listAllProjects = (client) => Effect.gen(function* () {
|
|
630
|
+
const projects = [];
|
|
631
|
+
let cursor;
|
|
632
|
+
for (;;) {
|
|
633
|
+
const query = cursor === void 0 ? {} : { cursor };
|
|
634
|
+
const page = yield* call(() => client.GET("/v1/projects", { params: { query } }));
|
|
635
|
+
projects.push(...page.data);
|
|
636
|
+
if (!page.pagination.hasMore || page.pagination.nextCursor === null) break;
|
|
637
|
+
cursor = page.pagination.nextCursor;
|
|
638
|
+
}
|
|
639
|
+
return projects;
|
|
640
|
+
});
|
|
641
|
+
/**
|
|
642
|
+
* Workspace ids circulate in two shapes: `wksp_`-prefixed and bare. Compare
|
|
643
|
+
* bare-to-bare so a `wksp_`-prefixed API id still matches a bare configured
|
|
644
|
+
* one (the same normalization `state/bootstrap.ts` applies to the same
|
|
645
|
+
* `/v1/projects` listing).
|
|
646
|
+
*/
|
|
647
|
+
const bareWorkspaceId = (id) => id.startsWith("wksp_") ? id.slice(5) : id;
|
|
648
|
+
/**
|
|
649
|
+
* Finds the app's Project by name in the workspace — PDP allows duplicate
|
|
650
|
+
* project names, so more than one can match; the oldest wins. Creates one
|
|
651
|
+
* if none match, unless `ensure` is `false` (find-only — `destroy`), in
|
|
652
|
+
* which case an absent Project fails with `ContainerNotFoundError`. No
|
|
653
|
+
* ownership marker and no `--project` override (both deferred — see
|
|
654
|
+
* ADR-0019).
|
|
655
|
+
*/
|
|
656
|
+
const resolveProject = (client, workspaceId, appName, ensure) => Effect.gen(function* () {
|
|
657
|
+
const oldest = (yield* listAllProjects(client)).filter((p) => bareWorkspaceId(p.workspace.id) === bareWorkspaceId(workspaceId) && p.name === appName).sort((a, b) => a.createdAt.localeCompare(b.createdAt))[0];
|
|
658
|
+
if (oldest !== void 0) return oldest.id;
|
|
659
|
+
if (!ensure) return yield* Effect.fail(new ContainerNotFoundError({ appName }));
|
|
660
|
+
return (yield* call(() => client.POST("/v1/projects", { body: {
|
|
661
|
+
name: appName,
|
|
662
|
+
workspaceId
|
|
663
|
+
} }))).data.id;
|
|
664
|
+
});
|
|
665
|
+
const findBranchId = (client, projectId, gitName) => call(() => client.GET("/v1/projects/{projectId}/branches", { params: {
|
|
666
|
+
path: { projectId },
|
|
667
|
+
query: { gitName }
|
|
668
|
+
} })).pipe(Effect.map((page) => page.data[0]?.id));
|
|
669
|
+
/**
|
|
670
|
+
* Finds the stage's Branch by its exact `gitName`, creating it if absent
|
|
671
|
+
* unless `ensure` is `false` (find-only — `destroy`), in which case an
|
|
672
|
+
* absent Branch fails with `ContainerNotFoundError`. The Management API has
|
|
673
|
+
* no server-side "create-or-return" idempotency (`POST
|
|
674
|
+
* /v1/projects/:id/branches` 409s on a duplicate `gitName`, with no request
|
|
675
|
+
* field to make that a no-op), so idempotency is client-side: observe
|
|
676
|
+
* first, and on a racing 409 from create, re-observe rather than fail.
|
|
677
|
+
*/
|
|
678
|
+
const resolveBranch = (client, projectId, gitName, appName, ensure) => Effect.gen(function* () {
|
|
679
|
+
const existing = yield* findBranchId(client, projectId, gitName);
|
|
680
|
+
if (existing !== void 0) return existing;
|
|
681
|
+
if (!ensure) return yield* Effect.fail(new ContainerNotFoundError({
|
|
682
|
+
appName,
|
|
683
|
+
stage: gitName
|
|
684
|
+
}));
|
|
685
|
+
return yield* call(() => client.POST("/v1/projects/{projectId}/branches", {
|
|
686
|
+
params: { path: { projectId } },
|
|
687
|
+
body: { gitName }
|
|
688
|
+
})).pipe(Effect.map((r) => r.data.id), Effect.catch((err) => err.status === 409 ? findBranchId(client, projectId, gitName).pipe(Effect.flatMap((id) => id === void 0 ? Effect.fail(err) : Effect.succeed(id))) : Effect.fail(err)));
|
|
689
|
+
});
|
|
690
|
+
/**
|
|
691
|
+
* Resolves the two containers a stage's deploy runs into (ADR-0019): the
|
|
692
|
+
* app's **Project**, found-or-created by name, and — for a named stage
|
|
693
|
+
* only — its **Branch**, found-or-created by `gitName`. The default stage
|
|
694
|
+
* (no `stage`) creates no Branch; `branchId` is omitted. With `ensure:
|
|
695
|
+
* false` (`destroy`), nothing is created — an absent Project or Branch
|
|
696
|
+
* fails with `ContainerNotFoundError` instead.
|
|
697
|
+
*/
|
|
698
|
+
const resolveContainer = (opts) => Effect.gen(function* () {
|
|
699
|
+
const client = yield* ManagementClient;
|
|
700
|
+
const ensure = opts.ensure ?? true;
|
|
701
|
+
const projectId = yield* resolveProject(client, opts.workspaceId, opts.appName, ensure);
|
|
702
|
+
if (opts.stage === void 0) return { projectId };
|
|
703
|
+
return {
|
|
704
|
+
projectId,
|
|
705
|
+
branchId: yield* resolveBranch(client, projectId, opts.stage, opts.appName, ensure)
|
|
706
|
+
};
|
|
707
|
+
});
|
|
708
|
+
/**
|
|
709
|
+
* Soft-deletes a Branch. Tolerates a 404 (already gone). The API refuses if
|
|
710
|
+
* the Branch still has live members or is the production/default Branch —
|
|
711
|
+
* that surfaces as a `PrismaApiError`.
|
|
712
|
+
*/
|
|
713
|
+
const deleteBranch = (branchId) => Effect.gen(function* () {
|
|
714
|
+
const client = yield* ManagementClient;
|
|
715
|
+
yield* callVoid(() => client.DELETE("/v1/branches/{branchId}", { params: { path: { branchId } } }));
|
|
716
|
+
});
|
|
717
|
+
/**
|
|
718
|
+
* Deletes a Project. Tolerates a 404 (already gone). The API refuses with a
|
|
719
|
+
* 400 if the Project still has live dependencies (e.g. another stage's
|
|
720
|
+
* Branch/resources) — that surfaces as a `PrismaApiError`.
|
|
721
|
+
*/
|
|
722
|
+
const deleteProject = (projectId) => Effect.gen(function* () {
|
|
723
|
+
const client = yield* ManagementClient;
|
|
724
|
+
yield* callVoid(() => client.DELETE("/v1/projects/{id}", { params: { path: { id: projectId } } }));
|
|
725
|
+
});
|
|
550
726
|
/** The collection of Prisma resource providers. */
|
|
551
727
|
var Providers = class extends Provider.ProviderCollection()("Prisma") {};
|
|
552
728
|
/**
|
|
@@ -560,8 +736,10 @@ const providers = () => Layer.effect(Providers, Provider.collection([
|
|
|
560
736
|
Connection,
|
|
561
737
|
ComputeService,
|
|
562
738
|
Deployment,
|
|
563
|
-
EnvironmentVariable
|
|
564
|
-
|
|
739
|
+
EnvironmentVariable,
|
|
740
|
+
Bucket,
|
|
741
|
+
BucketKey
|
|
742
|
+
])).pipe(Layer.provide(Layer.mergeAll(ProjectProvider(), DatabaseProvider(), ConnectionProvider(), ComputeServiceProvider(), DeploymentProvider(), EnvironmentVariableProvider(), BucketProvider(), BucketKeyProvider())), Layer.provideMerge(layer()), Layer.provideMerge(fromEnv()), Layer.orDie);
|
|
565
743
|
//#endregion
|
|
566
744
|
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/state.mjs
|
|
567
745
|
/** The framework-owned database a stage's deploy state lives in — a child of that stage's Branch (ADR-0034). */
|
|
@@ -1202,11 +1380,8 @@ const guardStateService = (service, checkLive, now = Date.now) => {
|
|
|
1202
1380
|
* StackServices>` contract and alchemy's own convention (e.g. a missing
|
|
1203
1381
|
* state store is `Effect.die` in `Stack.make`).
|
|
1204
1382
|
*/
|
|
1205
|
-
const
|
|
1206
|
-
const projectId =
|
|
1207
|
-
if (projectId === void 0 || projectId.length === 0) throw new Error("prismaState(): environment variable PRISMA_PROJECT_ID is required (the CLI sets it — deploy via `prisma-composer deploy`).");
|
|
1208
|
-
const branchIdEnv = process.env["PRISMA_BRANCH_ID"];
|
|
1209
|
-
const branchId = branchIdEnv === void 0 || branchIdEnv.length === 0 ? void 0 : branchIdEnv;
|
|
1383
|
+
const prismaStateLayer = (ids) => {
|
|
1384
|
+
const { projectId, branchId } = ids;
|
|
1210
1385
|
return Layer.effect(State, Effect.gen(function* () {
|
|
1211
1386
|
const stack = yield* Stack;
|
|
1212
1387
|
const container = branchId === void 0 ? projectId : `${projectId}/${branchId}`;
|
|
@@ -1229,18 +1404,218 @@ const prismaState = () => {
|
|
|
1229
1404
|
};
|
|
1230
1405
|
//#endregion
|
|
1231
1406
|
//#region ../../1-prisma-cloud/1-extensions/target/dist/control.mjs
|
|
1407
|
+
const PRISMA_CLOUD_EXTENSION_ID = "@prisma/composer-prisma-cloud";
|
|
1408
|
+
var PrismaCloudContainer = class {
|
|
1409
|
+
input;
|
|
1410
|
+
projectId;
|
|
1411
|
+
branchId;
|
|
1412
|
+
constructor(input, projectId, branchId) {
|
|
1413
|
+
this.input = input;
|
|
1414
|
+
this.projectId = projectId;
|
|
1415
|
+
this.branchId = branchId;
|
|
1416
|
+
}
|
|
1417
|
+
serialize() {
|
|
1418
|
+
return JSON.stringify({
|
|
1419
|
+
input: this.input,
|
|
1420
|
+
projectId: this.projectId,
|
|
1421
|
+
...this.branchId !== void 0 ? { branchId: this.branchId } : {}
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
/** `instanceof` — parent-side instances and child-side deserialized instances are both constructed by this module. */
|
|
1426
|
+
function isPrismaCloudContainer(value) {
|
|
1427
|
+
return value instanceof PrismaCloudContainer;
|
|
1428
|
+
}
|
|
1429
|
+
/** Narrow-or-throw for hook inputs. */
|
|
1430
|
+
function prismaCloudContainerOf(value) {
|
|
1431
|
+
if (!isPrismaCloudContainer(value)) throw new Error("the Prisma Cloud container was not resolved — the extension's container descriptor did not run.");
|
|
1432
|
+
return value;
|
|
1433
|
+
}
|
|
1434
|
+
function isRecord(value) {
|
|
1435
|
+
return typeof value === "object" && value !== null;
|
|
1436
|
+
}
|
|
1437
|
+
function invalidPayloadError(reason) {
|
|
1438
|
+
return /* @__PURE__ */ new Error(`${PRISMA_CLOUD_EXTENSION_ID}: invalid container transport payload — ${reason}.`);
|
|
1439
|
+
}
|
|
1440
|
+
/** Reconstructs a `PrismaCloudContainer` from `serialize()`'s JSON output — real narrowing, no casts. */
|
|
1441
|
+
function deserialize(serialized) {
|
|
1442
|
+
let parsed;
|
|
1443
|
+
try {
|
|
1444
|
+
parsed = JSON.parse(serialized);
|
|
1445
|
+
} catch (error) {
|
|
1446
|
+
throw invalidPayloadError(`not valid JSON (${error instanceof Error ? error.message : String(error)})`);
|
|
1447
|
+
}
|
|
1448
|
+
if (!isRecord(parsed)) throw invalidPayloadError("not an object");
|
|
1449
|
+
const input = parsed["input"];
|
|
1450
|
+
if (!isRecord(input)) throw invalidPayloadError("\"input\" is not an object");
|
|
1451
|
+
const appName = input["appName"];
|
|
1452
|
+
if (typeof appName !== "string") throw invalidPayloadError("\"input.appName\" is not a string");
|
|
1453
|
+
const stage = input["stage"];
|
|
1454
|
+
if (stage !== void 0 && typeof stage !== "string") throw invalidPayloadError("\"input.stage\" is not a string or absent");
|
|
1455
|
+
const projectId = parsed["projectId"];
|
|
1456
|
+
if (typeof projectId !== "string") throw invalidPayloadError("\"projectId\" is not a string");
|
|
1457
|
+
const branchId = parsed["branchId"];
|
|
1458
|
+
if (branchId !== void 0 && typeof branchId !== "string") throw invalidPayloadError("\"branchId\" is not a string or absent");
|
|
1459
|
+
return new PrismaCloudContainer({
|
|
1460
|
+
appName,
|
|
1461
|
+
stage
|
|
1462
|
+
}, projectId, branchId);
|
|
1463
|
+
}
|
|
1464
|
+
const workspaceRequiredError = () => /* @__PURE__ */ new Error("environment variable PRISMA_WORKSPACE_ID is required.");
|
|
1465
|
+
const tokenRequiredError$2 = () => /* @__PURE__ */ new Error("environment variable PRISMA_SERVICE_TOKEN is required.");
|
|
1466
|
+
function requireWorkspaceId() {
|
|
1467
|
+
const workspaceId = process.env["PRISMA_WORKSPACE_ID"];
|
|
1468
|
+
if (workspaceId === void 0 || workspaceId.length === 0) throw workspaceRequiredError();
|
|
1469
|
+
return workspaceId;
|
|
1470
|
+
}
|
|
1471
|
+
function requireTokenUnlessInjected(deps) {
|
|
1472
|
+
if (deps?.client === void 0 && (process.env["PRISMA_SERVICE_TOKEN"] ?? "").length === 0) throw tokenRequiredError$2();
|
|
1473
|
+
}
|
|
1474
|
+
async function ensureContainer(input, deps) {
|
|
1475
|
+
const workspaceId = requireWorkspaceId();
|
|
1476
|
+
requireTokenUnlessInjected(deps);
|
|
1477
|
+
const program = resolveContainer({
|
|
1478
|
+
workspaceId,
|
|
1479
|
+
appName: input.appName,
|
|
1480
|
+
...input.stage !== void 0 ? { stage: input.stage } : {},
|
|
1481
|
+
ensure: true
|
|
1482
|
+
}).pipe(Effect.map((c) => ({
|
|
1483
|
+
ok: true,
|
|
1484
|
+
container: c
|
|
1485
|
+
})), Effect.catchTag("PrismaApiError", (e) => Effect.succeed({
|
|
1486
|
+
ok: false,
|
|
1487
|
+
message: `Prisma Management API error resolving containers: ${e.message}.`
|
|
1488
|
+
})));
|
|
1489
|
+
const provided = deps?.client !== void 0 ? program.pipe(Effect.provideService(ManagementClient, deps.client)) : program.pipe(Effect.provide(layer().pipe(Layer.provide(fromEnv()))));
|
|
1490
|
+
const outcome = await Effect.runPromise(provided);
|
|
1491
|
+
if (!outcome.ok) throw new Error(outcome.message);
|
|
1492
|
+
return new PrismaCloudContainer(input, outcome.container.projectId, outcome.container.branchId);
|
|
1493
|
+
}
|
|
1494
|
+
async function locateContainer(input, deps) {
|
|
1495
|
+
const workspaceId = requireWorkspaceId();
|
|
1496
|
+
requireTokenUnlessInjected(deps);
|
|
1497
|
+
const program = resolveContainer({
|
|
1498
|
+
workspaceId,
|
|
1499
|
+
appName: input.appName,
|
|
1500
|
+
...input.stage !== void 0 ? { stage: input.stage } : {},
|
|
1501
|
+
ensure: false
|
|
1502
|
+
}).pipe(Effect.map((c) => ({
|
|
1503
|
+
ok: true,
|
|
1504
|
+
container: c
|
|
1505
|
+
})), Effect.catchTag("ContainerNotFoundError", () => Effect.succeed({ ok: false })), Effect.catchTag("PrismaApiError", (e) => Effect.fail(/* @__PURE__ */ new Error(`Prisma Management API error resolving containers: ${e.message}.`))));
|
|
1506
|
+
const provided = deps?.client !== void 0 ? program.pipe(Effect.provideService(ManagementClient, deps.client)) : program.pipe(Effect.provide(layer().pipe(Layer.provide(fromEnv()))));
|
|
1507
|
+
const outcome = await Effect.runPromise(provided);
|
|
1508
|
+
if (!outcome.ok) return void 0;
|
|
1509
|
+
return new PrismaCloudContainer(input, outcome.container.projectId, outcome.container.branchId);
|
|
1510
|
+
}
|
|
1511
|
+
/**
|
|
1512
|
+
* Soft-deletes a named stage's Branch after a successful `alchemy destroy`
|
|
1513
|
+
* has removed its members — the Management API refuses to delete a Branch
|
|
1514
|
+
* that still has live members.
|
|
1515
|
+
*/
|
|
1516
|
+
async function removeStageBranch(branchId, deps) {
|
|
1517
|
+
requireTokenUnlessInjected(deps);
|
|
1518
|
+
const program = deleteBranch(branchId).pipe(Effect.map(() => ({ ok: true })), Effect.catchTag("PrismaApiError", (e) => Effect.succeed({
|
|
1519
|
+
ok: false,
|
|
1520
|
+
message: `Failed to delete the stage Branch: ${e.message}.`
|
|
1521
|
+
})));
|
|
1522
|
+
const provided = deps?.client !== void 0 ? program.pipe(Effect.provideService(ManagementClient, deps.client)) : program.pipe(Effect.provide(layer().pipe(Layer.provide(fromEnv()))));
|
|
1523
|
+
const outcome = await Effect.runPromise(provided);
|
|
1524
|
+
if (!outcome.ok) throw new Error(outcome.message);
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Best-effort cleanup after a successful `--production` destroy: removes
|
|
1528
|
+
* the app's Project so hand-run stacks don't accumulate as empty Projects
|
|
1529
|
+
* (they eventually hit the workspace's plan limit). Unlike `removeStageBranch`,
|
|
1530
|
+
* this never throws: the destroy itself already succeeded, and the API's own
|
|
1531
|
+
* 400 ("still has dependencies") is the only check that matters — failing
|
|
1532
|
+
* the command over a cleanup step would be worse than leaving a Project shell.
|
|
1533
|
+
*/
|
|
1534
|
+
async function removeAppProject(projectId, deps) {
|
|
1535
|
+
if (deps?.client === void 0 && (process.env["PRISMA_SERVICE_TOKEN"] ?? "").length === 0) {
|
|
1536
|
+
console.warn(`Skipped removing the Project (${projectId}): PRISMA_SERVICE_TOKEN is not set.`);
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
const program = deleteProject(projectId).pipe(Effect.map(() => ({ ok: true })), Effect.catchTag("PrismaApiError", (e) => Effect.succeed({
|
|
1540
|
+
ok: false,
|
|
1541
|
+
error: e
|
|
1542
|
+
})));
|
|
1543
|
+
const provided = deps?.client !== void 0 ? program.pipe(Effect.provideService(ManagementClient, deps.client)) : program.pipe(Effect.provide(layer().pipe(Layer.provide(fromEnv()))));
|
|
1544
|
+
const outcome = await Effect.runPromise(provided);
|
|
1545
|
+
if (outcome.ok) {
|
|
1546
|
+
console.log(`Removed the Project (${projectId}) — nothing was left in it.`);
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
if (outcome.error.status === 400) {
|
|
1550
|
+
console.log(`Kept the Project (${projectId}) — it still has another stage's resources.`);
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
console.warn(`Could not remove the Project (${projectId}) after destroy: ${outcome.error.message}.`);
|
|
1554
|
+
}
|
|
1555
|
+
function containerDescriptor(deps) {
|
|
1556
|
+
return {
|
|
1557
|
+
ensure: (input) => ensureContainer(input, deps),
|
|
1558
|
+
locate: (input) => locateContainer(input, deps),
|
|
1559
|
+
remove: (instance) => instance.input.stage !== void 0 ? removeStageBranch(instance.branchId ?? missingBranchId(instance), deps) : removeAppProject(instance.projectId, deps),
|
|
1560
|
+
deserialize
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
/** Defensive: a named-stage container always resolves a Branch together with its stage — `ensure`/`locate`/`deserialize` never produce one without the other. */
|
|
1564
|
+
function missingBranchId(instance) {
|
|
1565
|
+
throw new Error(`${PRISMA_CLOUD_EXTENSION_ID}: a named-stage ("${instance.input.stage}") container instance is missing its branchId — this is a bug in ensure/locate/deserialize.`);
|
|
1566
|
+
}
|
|
1232
1567
|
const PRISMA_NAME_MIN = 3;
|
|
1233
1568
|
const PRISMA_NAME_MAX = 65;
|
|
1234
1569
|
function validateName(value, source) {
|
|
1235
1570
|
if (value.length < PRISMA_NAME_MIN || value.length > PRISMA_NAME_MAX) throw new Error(`prisma-cloud: ${source} "${value}" (${value.length} characters) is not a valid Prisma resource name — Prisma requires ${PRISMA_NAME_MIN}–${PRISMA_NAME_MAX} characters. Rename the provision id (or the deploy --name) to fit.`);
|
|
1236
1571
|
}
|
|
1237
1572
|
function isCloudApplication(value) {
|
|
1238
|
-
return typeof value === "object" && value !== null && "projectId" in value && typeof value.projectId === "string";
|
|
1573
|
+
return typeof value === "object" && value !== null && "projectId" in value && typeof value.projectId === "string" && "branchId" in value && (value.branchId === void 0 || typeof value.branchId === "string");
|
|
1239
1574
|
}
|
|
1240
1575
|
/** Narrows `ctx.application`, which core hands over as `unknown`, to this extension's own product; throws naming the hook when it hasn't run. */
|
|
1241
|
-
function
|
|
1576
|
+
function cloudApplicationOf(application) {
|
|
1242
1577
|
if (!isCloudApplication(application)) throw new Error("prisma-cloud: ctx.application is not this extension's application product — the prismaCloud() application hook must run before any node lowers.");
|
|
1243
|
-
return application
|
|
1578
|
+
return application;
|
|
1579
|
+
}
|
|
1580
|
+
function projectIdOf(application) {
|
|
1581
|
+
return cloudApplicationOf(application).projectId;
|
|
1582
|
+
}
|
|
1583
|
+
/**
|
|
1584
|
+
* One Bucket per module-provisioned bucket resource — `id` is the module
|
|
1585
|
+
* provision id, so a resource shared by several consumers is created exactly
|
|
1586
|
+
* once. A BucketKey is minted for the bucket: it is the reveal-once credential
|
|
1587
|
+
* carrier, and its attributes (endpoint, bucketName, accessKeyId,
|
|
1588
|
+
* secretAccessKey) become the four S3Config outputs consumers resolve by name.
|
|
1589
|
+
*/
|
|
1590
|
+
function bucketDescriptor(_o) {
|
|
1591
|
+
const lowering = ({ id, application }) => Effect.gen(function* () {
|
|
1592
|
+
validateName(id, "resource name (from provision id)");
|
|
1593
|
+
const branchId = cloudApplicationOf(application).branchId;
|
|
1594
|
+
const bkt = yield* Bucket(`${id}-bucket`, {
|
|
1595
|
+
projectId: projectIdOf(application),
|
|
1596
|
+
name: id,
|
|
1597
|
+
...branchId !== void 0 ? { branchId } : {}
|
|
1598
|
+
});
|
|
1599
|
+
const key = yield* BucketKey(`${id}-key`, {
|
|
1600
|
+
bucketId: bkt.id,
|
|
1601
|
+
name: id,
|
|
1602
|
+
role: "read_write"
|
|
1603
|
+
});
|
|
1604
|
+
const secretAccessKey = Output.map(key.secretAccessKey, (v) => Redacted.value(v));
|
|
1605
|
+
return {
|
|
1606
|
+
outputs: {
|
|
1607
|
+
url: key.endpoint,
|
|
1608
|
+
bucket: key.bucketName,
|
|
1609
|
+
accessKeyId: key.accessKeyId,
|
|
1610
|
+
secretAccessKey
|
|
1611
|
+
},
|
|
1612
|
+
entities: [{
|
|
1613
|
+
kind: "bucket",
|
|
1614
|
+
id: bkt.id
|
|
1615
|
+
}]
|
|
1616
|
+
};
|
|
1617
|
+
});
|
|
1618
|
+
return Object.assign(lowering, { kind: "resource" });
|
|
1244
1619
|
}
|
|
1245
1620
|
/** The `compute` node kind's descriptor: the four service hooks — provision, serialize, package, deploy. */
|
|
1246
1621
|
/**
|
|
@@ -1255,20 +1630,22 @@ function computeDescriptor(o) {
|
|
|
1255
1630
|
provision: ({ id, application }) => Effect.gen(function* () {
|
|
1256
1631
|
validateName(id, "service name (from provision id)");
|
|
1257
1632
|
const projectId = projectIdOf(application);
|
|
1633
|
+
const branchId = cloudApplicationOf(application).branchId;
|
|
1258
1634
|
return {
|
|
1259
1635
|
serviceId: (yield* ComputeService(`${id}-svc`, {
|
|
1260
1636
|
projectId,
|
|
1261
1637
|
name: id,
|
|
1262
1638
|
region: o.region ?? "us-east-1",
|
|
1263
|
-
...
|
|
1639
|
+
...branchId !== void 0 ? { branchId } : {}
|
|
1264
1640
|
})).id,
|
|
1265
1641
|
projectId
|
|
1266
1642
|
};
|
|
1267
1643
|
}),
|
|
1268
1644
|
serialize: (ctx, provisioned, config) => Effect.gen(function* () {
|
|
1269
1645
|
const { address, node, graph } = ctx;
|
|
1270
|
-
const
|
|
1271
|
-
const
|
|
1646
|
+
const branchId = cloudApplicationOf(ctx.application).branchId;
|
|
1647
|
+
const cls = branchId ? "preview" : "production";
|
|
1648
|
+
const branch = branchId !== void 0 ? { branchId } : {};
|
|
1272
1649
|
const projectId = provisioned.projectId;
|
|
1273
1650
|
const svc = node;
|
|
1274
1651
|
const records = [];
|
|
@@ -1408,11 +1785,12 @@ const PgWarmProvider = () => Provider.effect(PgWarm, Effect.succeed(pgWarmProvid
|
|
|
1408
1785
|
function postgresDescriptor(o) {
|
|
1409
1786
|
const lowering = ({ id, application }) => Effect.gen(function* () {
|
|
1410
1787
|
validateName(id, "resource name (from provision id)");
|
|
1788
|
+
const branchId = cloudApplicationOf(application).branchId;
|
|
1411
1789
|
const db = yield* Database(`${id}-db`, {
|
|
1412
1790
|
projectId: projectIdOf(application),
|
|
1413
1791
|
name: id,
|
|
1414
1792
|
region: o.region ?? "us-east-1",
|
|
1415
|
-
...
|
|
1793
|
+
...branchId !== void 0 ? { branchId } : {}
|
|
1416
1794
|
});
|
|
1417
1795
|
const conn = yield* Connection(`${id}-conn`, {
|
|
1418
1796
|
databaseId: db.id,
|
|
@@ -1676,11 +2054,12 @@ const PnMigrationProvider = () => Provider.effect(PnMigration, Effect.succeed(pn
|
|
|
1676
2054
|
function prismaNextDescriptor(o) {
|
|
1677
2055
|
const lowering = ({ id, node, application }) => Effect.gen(function* () {
|
|
1678
2056
|
validateName(id, "resource name (from provision id)");
|
|
2057
|
+
const branchId = cloudApplicationOf(application).branchId;
|
|
1679
2058
|
const db = yield* Database(`${id}-db`, {
|
|
1680
2059
|
projectId: projectIdOf(application),
|
|
1681
2060
|
name: id,
|
|
1682
2061
|
region: o.region ?? "us-east-1",
|
|
1683
|
-
...
|
|
2062
|
+
...branchId !== void 0 ? { branchId } : {}
|
|
1684
2063
|
});
|
|
1685
2064
|
const conn = yield* Connection(`${id}-conn`, {
|
|
1686
2065
|
databaseId: db.id,
|
|
@@ -1817,7 +2196,7 @@ function s3StoreDescriptor(o) {
|
|
|
1817
2196
|
*
|
|
1818
2197
|
* Control-plane only (imported by control.ts → prisma-composer.config.ts); runs
|
|
1819
2198
|
* in the CLI parent, so it builds its own Management API client from env — the
|
|
1820
|
-
* same credential path `
|
|
2199
|
+
* same credential path `container.ts`'s `ensure`/`locate` use.
|
|
1821
2200
|
*/
|
|
1822
2201
|
/** production for the default stage; preview for a named stage — matching how the pack writes config rows. */
|
|
1823
2202
|
const classFor = (branchId) => branchId === void 0 ? "production" : "preview";
|
|
@@ -1860,21 +2239,21 @@ async function existsOnPlatform(client, projectId, branchId, key) {
|
|
|
1860
2239
|
* EnvironmentVariable.ts). A 409 means a concurrent deploy already provisioned
|
|
1861
2240
|
* it — tolerated. The value is never logged.
|
|
1862
2241
|
*/
|
|
1863
|
-
async function fillMissing(client,
|
|
2242
|
+
async function fillMissing(client, projectId, branchId, key, value) {
|
|
1864
2243
|
const res = await client.POST("/v1/environment-variables", { body: {
|
|
1865
|
-
projectId
|
|
1866
|
-
class: classFor(
|
|
2244
|
+
projectId,
|
|
2245
|
+
class: classFor(branchId),
|
|
1867
2246
|
key,
|
|
1868
2247
|
value,
|
|
1869
|
-
...
|
|
2248
|
+
...branchId !== void 0 ? { branchId } : {}
|
|
1870
2249
|
} });
|
|
1871
2250
|
if (res.error !== void 0 && res.response.status !== 409) throw fillFailedError(key, res.error);
|
|
1872
2251
|
}
|
|
1873
2252
|
const tokenRequiredError$1 = () => /* @__PURE__ */ new Error("environment variable PRISMA_SERVICE_TOKEN is required for deploy preflight.");
|
|
1874
2253
|
const listFailedError = (key, error) => /* @__PURE__ */ new Error(`deploy preflight: Prisma Management API error listing "${key}": ${JSON.stringify(error)}.`);
|
|
1875
2254
|
const fillFailedError = (key, error) => /* @__PURE__ */ new Error(`deploy preflight: failed to provision "${key}" from the deploy shell: ${JSON.stringify(error)}.`);
|
|
1876
|
-
function missingError(missing,
|
|
1877
|
-
const scope =
|
|
2255
|
+
function missingError(missing, branchId, stage) {
|
|
2256
|
+
const scope = branchId === void 0 ? "the production class (project-level template)" : `the preview class of stage "${stage ?? branchId}" (branch override or template)`;
|
|
1878
2257
|
const lines = missing.map((m) => ` - ${m.name} (required by service "${m.serviceAddress}")`);
|
|
1879
2258
|
return /* @__PURE__ */ new Error(`Deploy preflight failed — ${missing.length} env var(s) (secret or env-sourced param) are not provisioned on Prisma Cloud for ${scope}, and are absent from the deploy shell:\n${lines.join("\n")}\n\nSet each in the deploy shell environment (the CLI will provision it on deploy), or create it on the platform (Prisma Console or the Management API) in ${scope}.`);
|
|
1880
2259
|
}
|
|
@@ -1893,6 +2272,7 @@ async function managementClient$1() {
|
|
|
1893
2272
|
* from env.
|
|
1894
2273
|
*/
|
|
1895
2274
|
async function runPreflight(input, deps) {
|
|
2275
|
+
const { projectId, branchId } = prismaCloudContainerOf(input.container);
|
|
1896
2276
|
const names = /* @__PURE__ */ new Map();
|
|
1897
2277
|
for (const binding of provisionManifest(input.graph)) {
|
|
1898
2278
|
const name = secretName(binding);
|
|
@@ -1913,15 +2293,15 @@ async function runPreflight(input, deps) {
|
|
|
1913
2293
|
const client = deps?.client ?? await managementClient$1();
|
|
1914
2294
|
const missing = [];
|
|
1915
2295
|
for (const meta of names.values()) {
|
|
1916
|
-
if (await existsOnPlatform(client,
|
|
2296
|
+
if (await existsOnPlatform(client, projectId, branchId, meta.name)) continue;
|
|
1917
2297
|
const shellValue = process.env[meta.name];
|
|
1918
2298
|
if (shellValue !== void 0 && shellValue.length > 0) {
|
|
1919
|
-
await fillMissing(client,
|
|
2299
|
+
await fillMissing(client, projectId, branchId, meta.name, shellValue);
|
|
1920
2300
|
continue;
|
|
1921
2301
|
}
|
|
1922
2302
|
missing.push(meta);
|
|
1923
2303
|
}
|
|
1924
|
-
if (missing.length > 0) throw missingError(missing, input);
|
|
2304
|
+
if (missing.length > 0) throw missingError(missing, branchId, input.stage);
|
|
1925
2305
|
}
|
|
1926
2306
|
const tokenRequiredError = () => /* @__PURE__ */ new Error("environment variable PRISMA_SERVICE_TOKEN is required for destroy teardown.");
|
|
1927
2307
|
async function managementClient() {
|
|
@@ -1946,12 +2326,13 @@ async function managementClient() {
|
|
|
1946
2326
|
* builds a client from env and verifies against the real database.
|
|
1947
2327
|
*/
|
|
1948
2328
|
async function runTeardown(input, deps) {
|
|
1949
|
-
const
|
|
2329
|
+
const { projectId, branchId } = prismaCloudContainerOf(input.container);
|
|
2330
|
+
const isNamedStage = branchId !== void 0;
|
|
1950
2331
|
try {
|
|
1951
2332
|
const client = deps?.client ?? await managementClient();
|
|
1952
2333
|
await Effect.runPromise(deleteStateDatabaseWith({
|
|
1953
|
-
projectId
|
|
1954
|
-
...
|
|
2334
|
+
projectId,
|
|
2335
|
+
...branchId !== void 0 ? { branchId } : {}
|
|
1955
2336
|
}, deps?.verify ?? verifyOwnership).pipe(Effect.provideService(ManagementClient, client)));
|
|
1956
2337
|
} catch (error) {
|
|
1957
2338
|
const reason = error instanceof Error ? error.message : String(error);
|
|
@@ -2029,6 +2410,17 @@ const streamsApiKeyValue = (refs) => {
|
|
|
2029
2410
|
return distinct[0] ?? "";
|
|
2030
2411
|
});
|
|
2031
2412
|
};
|
|
2413
|
+
/** The user-facing state descriptor: `state: prismaState()` in `prisma-composer.config.ts` (ADR-0017). */
|
|
2414
|
+
const prismaState = () => ({
|
|
2415
|
+
extension: PRISMA_CLOUD_EXTENSION_ID,
|
|
2416
|
+
create: (container) => {
|
|
2417
|
+
const { projectId, branchId } = prismaCloudContainerOf(container);
|
|
2418
|
+
return prismaStateLayer(branchId !== void 0 ? {
|
|
2419
|
+
projectId,
|
|
2420
|
+
branchId
|
|
2421
|
+
} : { projectId });
|
|
2422
|
+
}
|
|
2423
|
+
});
|
|
2032
2424
|
const KNOWN_REGION_SET = new Set(COMPUTE_REGIONS);
|
|
2033
2425
|
function isComputeRegion(value) {
|
|
2034
2426
|
return KNOWN_REGION_SET.has(value);
|
|
@@ -2084,34 +2476,25 @@ function buildProviderParams(entries, values) {
|
|
|
2084
2476
|
const PROVIDER_PARAMS = buildProviderParams(RESERVED_PROVIDER_PARAMS, PROVIDER_PARAM_VALUES);
|
|
2085
2477
|
/**
|
|
2086
2478
|
* Resolves the factory's env-or-option inputs, failing fast with the exact
|
|
2087
|
-
* variable name.
|
|
2088
|
-
* also runs in the CLI parent, before they're set; the required check lives in `application.provision`.
|
|
2479
|
+
* variable name.
|
|
2089
2480
|
*/
|
|
2090
2481
|
function resolveOptions(opts) {
|
|
2091
2482
|
const workspaceId = opts.workspaceId ?? process.env["PRISMA_WORKSPACE_ID"];
|
|
2092
2483
|
if (workspaceId === void 0 || workspaceId.length === 0) throw new Error("prismaCloud(): environment variable PRISMA_WORKSPACE_ID is required.");
|
|
2093
|
-
const projectId = process.env["PRISMA_PROJECT_ID"] || void 0;
|
|
2094
|
-
const branchId = process.env["PRISMA_BRANCH_ID"] || void 0;
|
|
2095
2484
|
if (opts.region !== void 0) return {
|
|
2096
2485
|
workspaceId,
|
|
2097
2486
|
region: opts.region,
|
|
2098
|
-
projectId,
|
|
2099
|
-
branchId,
|
|
2100
2487
|
providerParams: PROVIDER_PARAMS
|
|
2101
2488
|
};
|
|
2102
2489
|
const region = process.env["PRISMA_REGION"];
|
|
2103
2490
|
if (region === void 0 || region.length === 0) return {
|
|
2104
2491
|
workspaceId,
|
|
2105
|
-
projectId,
|
|
2106
|
-
branchId,
|
|
2107
2492
|
providerParams: PROVIDER_PARAMS
|
|
2108
2493
|
};
|
|
2109
2494
|
if (!isComputeRegion(region)) throw new Error(`prismaCloud(): environment variable PRISMA_REGION="${region}" is not a known region (expected one of: ${COMPUTE_REGIONS.join(", ")}).`);
|
|
2110
2495
|
return {
|
|
2111
2496
|
workspaceId,
|
|
2112
2497
|
region,
|
|
2113
|
-
projectId,
|
|
2114
|
-
branchId,
|
|
2115
2498
|
providerParams: PROVIDER_PARAMS
|
|
2116
2499
|
};
|
|
2117
2500
|
}
|
|
@@ -2119,21 +2502,24 @@ function resolveOptions(opts) {
|
|
|
2119
2502
|
const prismaCloud = (opts = {}) => {
|
|
2120
2503
|
const o = resolveOptions(opts);
|
|
2121
2504
|
return {
|
|
2122
|
-
id:
|
|
2505
|
+
id: PRISMA_CLOUD_EXTENSION_ID,
|
|
2506
|
+
container: containerDescriptor(),
|
|
2123
2507
|
providers: () => asProvidersLayer(Layer.mergeAll(providers(), PgWarmProvider(), PnMigrationProvider(), S3CredentialsProvider(), ServiceKeyProvider())),
|
|
2124
2508
|
preflight: (input) => runPreflight(input),
|
|
2125
2509
|
teardown: (input) => runTeardown(input),
|
|
2126
|
-
application: { provision: () => Effect.gen(function* () {
|
|
2127
|
-
const projectId =
|
|
2128
|
-
if (projectId === void 0 || projectId.length === 0) throw new Error("prismaCloud(): environment variable PRISMA_PROJECT_ID is required (the CLI sets it — deploy via `prisma-composer deploy`).");
|
|
2510
|
+
application: { provision: (ctx) => Effect.gen(function* () {
|
|
2511
|
+
const { projectId, branchId } = prismaCloudContainerOf(ctx.container);
|
|
2129
2512
|
for (const key of ["DATABASE_URL", "DATABASE_URL_POOLED"]) yield* EnvironmentVariable(`${key}-poison`, {
|
|
2130
2513
|
projectId,
|
|
2131
2514
|
key,
|
|
2132
2515
|
value: "-",
|
|
2133
|
-
class:
|
|
2134
|
-
...
|
|
2516
|
+
class: branchId ? "preview" : "production",
|
|
2517
|
+
...branchId !== void 0 ? { branchId } : {}
|
|
2135
2518
|
});
|
|
2136
|
-
return {
|
|
2519
|
+
return {
|
|
2520
|
+
projectId,
|
|
2521
|
+
branchId
|
|
2522
|
+
};
|
|
2137
2523
|
}) },
|
|
2138
2524
|
provisions: PROVISIONERS,
|
|
2139
2525
|
nodes: {
|
|
@@ -2141,7 +2527,8 @@ const prismaCloud = (opts = {}) => {
|
|
|
2141
2527
|
"prisma-next": prismaNextDescriptor(o),
|
|
2142
2528
|
compute: computeDescriptor(o),
|
|
2143
2529
|
credentials: s3CredentialsDescriptor(o),
|
|
2144
|
-
"s3-store": s3StoreDescriptor(o)
|
|
2530
|
+
"s3-store": s3StoreDescriptor(o),
|
|
2531
|
+
s3: bucketDescriptor(o)
|
|
2145
2532
|
}
|
|
2146
2533
|
};
|
|
2147
2534
|
};
|