@gaganref/confect-alchemy 0.0.0-stage → 10.3.1-fork.10
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/LICENSE +7 -0
- package/README.md +22 -2
- package/dist/Backend.d.ts +45 -0
- package/dist/Backend.d.ts.map +1 -0
- package/dist/Backend.js +38 -0
- package/dist/Backend.js.map +1 -0
- package/dist/Code.d.ts +80 -0
- package/dist/Code.d.ts.map +1 -0
- package/dist/Code.js +29 -0
- package/dist/Code.js.map +1 -0
- package/dist/Confect.d.ts +2 -0
- package/dist/Confect.d.ts.map +1 -0
- package/dist/Confect.js +8 -0
- package/dist/Confect.js.map +1 -0
- package/dist/Convex.d.ts +7 -0
- package/dist/Convex.d.ts.map +1 -0
- package/dist/Convex.js +21 -0
- package/dist/Convex.js.map +1 -0
- package/dist/ConvexClient.d.ts +215 -0
- package/dist/ConvexClient.d.ts.map +1 -0
- package/dist/ConvexClient.js +224 -0
- package/dist/ConvexClient.js.map +1 -0
- package/dist/DeployKey.d.ts +120 -0
- package/dist/DeployKey.d.ts.map +1 -0
- package/dist/DeployKey.js +151 -0
- package/dist/DeployKey.js.map +1 -0
- package/dist/Deployment.d.ts +113 -0
- package/dist/Deployment.d.ts.map +1 -0
- package/dist/Deployment.js +160 -0
- package/dist/Deployment.js.map +1 -0
- package/dist/EnvironmentVariables.d.ts +155 -0
- package/dist/EnvironmentVariables.d.ts.map +1 -0
- package/dist/EnvironmentVariables.js +135 -0
- package/dist/EnvironmentVariables.js.map +1 -0
- package/dist/Project.d.ts +100 -0
- package/dist/Project.d.ts.map +1 -0
- package/dist/Project.js +123 -0
- package/dist/Project.js.map +1 -0
- package/dist/Providers.d.ts +17 -0
- package/dist/Providers.d.ts.map +1 -0
- package/dist/Providers.js +46 -0
- package/dist/Providers.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/internal/CodeDeployment.d.ts +17 -0
- package/dist/internal/CodeDeployment.d.ts.map +1 -0
- package/dist/internal/CodeDeployment.js +53 -0
- package/dist/internal/CodeDeployment.js.map +1 -0
- package/dist/internal/CommandRunner.d.ts +55 -0
- package/dist/internal/CommandRunner.d.ts.map +1 -0
- package/dist/internal/CommandRunner.js +126 -0
- package/dist/internal/CommandRunner.js.map +1 -0
- package/dist/internal/FileLock.d.ts +30 -0
- package/dist/internal/FileLock.d.ts.map +1 -0
- package/dist/internal/FileLock.js +83 -0
- package/dist/internal/FileLock.js.map +1 -0
- package/dist/internal/Lifecycle.d.ts +11 -0
- package/dist/internal/Lifecycle.d.ts.map +1 -0
- package/dist/internal/Lifecycle.js +45 -0
- package/dist/internal/Lifecycle.js.map +1 -0
- package/dist/internal/LocalBackend.d.ts +63 -0
- package/dist/internal/LocalBackend.d.ts.map +1 -0
- package/dist/internal/LocalBackend.js +333 -0
- package/dist/internal/LocalBackend.js.map +1 -0
- package/dist/internal/LocalSidecar.d.ts +3 -0
- package/dist/internal/LocalSidecar.d.ts.map +1 -0
- package/dist/internal/LocalSidecar.js +7 -0
- package/dist/internal/LocalSidecar.js.map +1 -0
- package/dist/internal/Loopback.d.ts +18 -0
- package/dist/internal/Loopback.d.ts.map +1 -0
- package/dist/internal/Loopback.js +31 -0
- package/dist/internal/Loopback.js.map +1 -0
- package/dist/internal/PushLock.d.ts +36 -0
- package/dist/internal/PushLock.d.ts.map +1 -0
- package/dist/internal/PushLock.js +61 -0
- package/dist/internal/PushLock.js.map +1 -0
- package/dist/internal/ResourceIdentity.d.ts +3 -0
- package/dist/internal/ResourceIdentity.d.ts.map +1 -0
- package/dist/internal/ResourceIdentity.js +10 -0
- package/dist/internal/ResourceIdentity.js.map +1 -0
- package/dist/internal/UserCache.d.ts +12 -0
- package/dist/internal/UserCache.d.ts.map +1 -0
- package/dist/internal/UserCache.js +25 -0
- package/dist/internal/UserCache.js.map +1 -0
- package/dist/internal/Zip.d.ts +15 -0
- package/dist/internal/Zip.d.ts.map +1 -0
- package/dist/internal/Zip.js +65 -0
- package/dist/internal/Zip.js.map +1 -0
- package/package.json +65 -3
- package/src/Backend.ts +101 -0
- package/src/Code.ts +58 -0
- package/src/Confect.ts +1 -0
- package/src/Convex.ts +22 -0
- package/src/ConvexClient.ts +544 -0
- package/src/DeployKey.ts +256 -0
- package/src/Deployment.ts +277 -0
- package/src/EnvironmentVariables.ts +254 -0
- package/src/Project.ts +205 -0
- package/src/Providers.ts +67 -0
- package/src/index.ts +2 -0
- package/src/internal/CodeDeployment.ts +81 -0
- package/src/internal/CommandRunner.ts +251 -0
- package/src/internal/FileLock.ts +136 -0
- package/src/internal/Lifecycle.ts +49 -0
- package/src/internal/LocalBackend.ts +492 -0
- package/src/internal/LocalSidecar.ts +9 -0
- package/src/internal/Loopback.ts +34 -0
- package/src/internal/PushLock.ts +99 -0
- package/src/internal/ResourceIdentity.ts +20 -0
- package/src/internal/UserCache.ts +25 -0
- package/src/internal/Zip.ts +108 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { CreateDeploymentType, RegionName } from "@convex-dev/platform/managementApi";
|
|
2
|
+
import { OwnedBySomeoneElse } from "alchemy/AdoptPolicy";
|
|
3
|
+
import * as Provider from "alchemy/Provider";
|
|
4
|
+
import { Resource } from "alchemy/Resource";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as FileSystem from "effect/FileSystem";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
import { ConvexClient } from "./ConvexClient.js";
|
|
9
|
+
import type { Providers } from "./Providers.js";
|
|
10
|
+
export interface DeploymentProps {
|
|
11
|
+
readonly projectId: number;
|
|
12
|
+
readonly type: CreateDeploymentType;
|
|
13
|
+
readonly reference?: string;
|
|
14
|
+
readonly region?: RegionName;
|
|
15
|
+
}
|
|
16
|
+
export interface DeploymentAttributes {
|
|
17
|
+
readonly projectId: number;
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly reference: string;
|
|
20
|
+
readonly type: CreateDeploymentType;
|
|
21
|
+
readonly url: string;
|
|
22
|
+
/**
|
|
23
|
+
* Always set in the cloud; a local deployment echoes the requested region.
|
|
24
|
+
*/
|
|
25
|
+
readonly region?: RegionName;
|
|
26
|
+
}
|
|
27
|
+
export type Deployment = Resource<"Convex.Deployment", DeploymentProps, DeploymentAttributes, never, Providers>;
|
|
28
|
+
export declare const Deployment: import("alchemy/Resource").ResourceClass<Deployment>;
|
|
29
|
+
declare const DeploymentIdentityChange_base: Schema.Class<DeploymentIdentityChange, Schema.TaggedStruct<"DeploymentIdentityChange", {
|
|
30
|
+
readonly deploymentName: Schema.String;
|
|
31
|
+
readonly field: Schema.String;
|
|
32
|
+
readonly current: Schema.String;
|
|
33
|
+
readonly requested: Schema.String;
|
|
34
|
+
}>, import("effect/Cause").YieldableError>;
|
|
35
|
+
export declare class DeploymentIdentityChange extends DeploymentIdentityChange_base {
|
|
36
|
+
}
|
|
37
|
+
declare const UnsupportedLocalDeployment_base: Schema.Class<UnsupportedLocalDeployment, Schema.TaggedStruct<"UnsupportedLocalDeployment", {
|
|
38
|
+
readonly deploymentName: Schema.String;
|
|
39
|
+
}>, import("effect/Cause").YieldableError>;
|
|
40
|
+
export declare class UnsupportedLocalDeployment extends UnsupportedLocalDeployment_base {
|
|
41
|
+
}
|
|
42
|
+
declare const AmbiguousDeployment_base: Schema.Class<AmbiguousDeployment, Schema.TaggedStruct<"AmbiguousDeployment", {
|
|
43
|
+
readonly projectId: Schema.Finite;
|
|
44
|
+
readonly reference: Schema.String;
|
|
45
|
+
}>, import("effect/Cause").YieldableError>;
|
|
46
|
+
export declare class AmbiguousDeployment extends AmbiguousDeployment_base {
|
|
47
|
+
}
|
|
48
|
+
export declare const provider: Effect.Effect<{
|
|
49
|
+
diff: (args_0: {
|
|
50
|
+
id: string;
|
|
51
|
+
fqn: string;
|
|
52
|
+
instanceId: string;
|
|
53
|
+
olds: DeploymentProps;
|
|
54
|
+
news: import("alchemy/Input").Input<DeploymentProps>;
|
|
55
|
+
oldBindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
56
|
+
newBindings: import("alchemy/Input").Input<import("alchemy/Resource").ResourceBinding<never>[]>;
|
|
57
|
+
output: DeploymentAttributes | undefined;
|
|
58
|
+
}) => Effect.Effect<{
|
|
59
|
+
action: "update";
|
|
60
|
+
} | undefined, import("./ConvexClient.js").ConvexApiError | import("./ConvexClient.js").ConvexConflict | DeploymentIdentityChange | UnsupportedLocalDeployment, never>;
|
|
61
|
+
read: (args_0: {
|
|
62
|
+
id: string;
|
|
63
|
+
fqn: string;
|
|
64
|
+
instanceId: string;
|
|
65
|
+
olds: DeploymentProps;
|
|
66
|
+
output: DeploymentAttributes | undefined;
|
|
67
|
+
}) => Effect.Effect<{
|
|
68
|
+
projectId: number;
|
|
69
|
+
name: string;
|
|
70
|
+
reference: string;
|
|
71
|
+
type: "custom" | "dev" | "preview" | "prod";
|
|
72
|
+
url: string;
|
|
73
|
+
region: "aws-ap-southeast-2" | "aws-ca-central-1" | "aws-eu-west-1" | "aws-us-east-1";
|
|
74
|
+
} | undefined, AmbiguousDeployment | import("./ConvexClient.js").ConvexApiError | import("./ConvexClient.js").ConvexConflict | import("./ConvexClient.js").ConvexNotFound | UnsupportedLocalDeployment, never>;
|
|
75
|
+
reconcile: (args_0: {
|
|
76
|
+
id: string;
|
|
77
|
+
fqn: string;
|
|
78
|
+
instanceId: string;
|
|
79
|
+
news: DeploymentProps;
|
|
80
|
+
olds: DeploymentProps | undefined;
|
|
81
|
+
output: DeploymentAttributes | undefined;
|
|
82
|
+
session: import("alchemy/Report").ScopedPlanStatusSession;
|
|
83
|
+
bindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
84
|
+
}) => Effect.Effect<{
|
|
85
|
+
projectId: number;
|
|
86
|
+
name: string;
|
|
87
|
+
reference: string;
|
|
88
|
+
type: "custom" | "dev" | "preview" | "prod";
|
|
89
|
+
url: string;
|
|
90
|
+
region: "aws-ap-southeast-2" | "aws-ca-central-1" | "aws-eu-west-1" | "aws-us-east-1";
|
|
91
|
+
}, AmbiguousDeployment | import("./ConvexClient.js").ConvexApiError | import("./ConvexClient.js").ConvexConflict | import("./ConvexClient.js").ConvexNotFound | DeploymentIdentityChange | import("./internal/Lifecycle.js").LifecycleStateError | OwnedBySomeoneElse | import("alchemy/State/State").StateStoreError | UnsupportedLocalDeployment, never>;
|
|
92
|
+
delete: (args_0: {
|
|
93
|
+
id: string;
|
|
94
|
+
fqn: string;
|
|
95
|
+
instanceId: string;
|
|
96
|
+
olds: DeploymentProps;
|
|
97
|
+
output: DeploymentAttributes;
|
|
98
|
+
session: import("alchemy/Report").ScopedPlanStatusSession;
|
|
99
|
+
bindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
100
|
+
force?: boolean;
|
|
101
|
+
}) => Effect.Effect<void, import("./ConvexClient.js").ConvexApiError | import("./ConvexClient.js").ConvexConflict, never>;
|
|
102
|
+
}, never, ConvexClient>;
|
|
103
|
+
/**
|
|
104
|
+
* Under `alchemy dev` a deployment is a local Convex backend this provider
|
|
105
|
+
* owns. Alchemy's dev sidecar hosts it, so the backend keeps running across
|
|
106
|
+
* reloads of the stack and stops when the dev session ends. Its data lives in
|
|
107
|
+
* `.alchemy/convex/<stack>/<stage>/<name>` and is removed only when the
|
|
108
|
+
* deployment is destroyed.
|
|
109
|
+
*/
|
|
110
|
+
export declare const localLayer: import("effect/Layer").Layer<Provider.Provider<Deployment>, never, import("alchemy/AlchemyContext").AlchemyContext | import("alchemy/Artifacts").ArtifactStore | import("effect/process/ChildProcessSpawner").ChildProcessSpawner | import("effect/Crypto").Crypto | FileSystem.FileSystem | import("effect/http/HttpClient").HttpClient | import("effect/Path").Path | import("alchemy/Stack").Stack>;
|
|
111
|
+
export declare const layer: import("effect/Layer").Layer<Provider.Provider<Deployment>, never, ConvexClient>;
|
|
112
|
+
export {};
|
|
113
|
+
//# sourceMappingURL=Deployment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Deployment.d.ts","sourceRoot":"","sources":["../src/Deployment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EAEpB,UAAU,EACX,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAW,MAAM,qBAAqB,CAAC;AAGlE,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKhD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;CAC9B;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,CAC/B,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,KAAK,EACL,SAAS,CACV,CAAC;AACF,eAAO,MAAM,UAAU,sDAErB,CAAC;;;;;;;AAEH,qBAAa,wBAAyB,SAAQ,6BAQ7C;CAAG;;;;AAEJ,qBAAa,0BAA2B,SAAQ,+BAG/C;CAAG;;;;;AAEJ,qBAAa,mBAAoB,SAAQ,wBAGxC;CAAG;AAEJ,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAyInB,CAAC;AAOH;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,wYAoDtB,CAAC;AAEF,eAAO,MAAM,KAAK,kFAAwC,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { ConvexClient } from "./ConvexClient.js";
|
|
2
|
+
import { checkpointCreate, shouldAdopt } from "./internal/Lifecycle.js";
|
|
3
|
+
import { resourceName } from "./internal/ResourceIdentity.js";
|
|
4
|
+
import { boot, dataDirectories, remove } from "./internal/LocalBackend.js";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Provider from "alchemy/Provider";
|
|
7
|
+
import { Resource } from "alchemy/Resource";
|
|
8
|
+
import * as Schema from "effect/Schema";
|
|
9
|
+
import * as FileSystem from "effect/FileSystem";
|
|
10
|
+
import { OwnedBySomeoneElse, Unowned } from "alchemy/AdoptPolicy";
|
|
11
|
+
import { isResolved } from "alchemy/Diff";
|
|
12
|
+
import * as LocalProvider from "alchemy/Local/LocalProvider";
|
|
13
|
+
import { moduleExtension } from "alchemy/Util/Node";
|
|
14
|
+
//#region src/Deployment.ts
|
|
15
|
+
const Deployment = Resource("Convex.Deployment", { defaultRemovalPolicy: "retain" });
|
|
16
|
+
var DeploymentIdentityChange = class extends Schema.TaggedError()("DeploymentIdentityChange", {
|
|
17
|
+
deploymentName: Schema.String,
|
|
18
|
+
field: Schema.String,
|
|
19
|
+
current: Schema.String,
|
|
20
|
+
requested: Schema.String
|
|
21
|
+
}) {};
|
|
22
|
+
var UnsupportedLocalDeployment = class extends Schema.TaggedError()("UnsupportedLocalDeployment", { deploymentName: Schema.String }) {};
|
|
23
|
+
var AmbiguousDeployment = class extends Schema.TaggedError()("AmbiguousDeployment", {
|
|
24
|
+
projectId: Schema.Finite,
|
|
25
|
+
reference: Schema.String
|
|
26
|
+
}) {};
|
|
27
|
+
const provider = Effect.gen(function* () {
|
|
28
|
+
const client = yield* ConvexClient;
|
|
29
|
+
const attributes = Effect.fn("Deployment.attributes")(function* (deployment) {
|
|
30
|
+
if (deployment.kind !== "cloud") return yield* new UnsupportedLocalDeployment({ deploymentName: deployment.name });
|
|
31
|
+
return {
|
|
32
|
+
projectId: deployment.projectId,
|
|
33
|
+
name: deployment.name,
|
|
34
|
+
reference: deployment.reference,
|
|
35
|
+
type: deployment.deploymentType,
|
|
36
|
+
url: deployment.deploymentUrl,
|
|
37
|
+
region: deployment.region
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
const find = Effect.fn("Deployment.find")(function* (projectId, reference) {
|
|
41
|
+
const matches = (yield* client.listDeployments(projectId)).filter((deployment) => deployment.kind === "cloud" && deployment.reference === reference);
|
|
42
|
+
if (matches.length > 1) return yield* new AmbiguousDeployment({
|
|
43
|
+
projectId,
|
|
44
|
+
reference
|
|
45
|
+
});
|
|
46
|
+
return matches[0];
|
|
47
|
+
});
|
|
48
|
+
const validate = Effect.fn("Deployment.validate")(function* (current, news) {
|
|
49
|
+
for (const field of [
|
|
50
|
+
"projectId",
|
|
51
|
+
"type",
|
|
52
|
+
"region"
|
|
53
|
+
]) if (news[field] !== void 0 && current[field] !== news[field]) return yield* new DeploymentIdentityChange({
|
|
54
|
+
deploymentName: current.name,
|
|
55
|
+
field,
|
|
56
|
+
current: String(current[field]),
|
|
57
|
+
requested: String(news[field])
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
diff: Effect.fn("Deployment.diff")(function* ({ news, output }) {
|
|
62
|
+
if (!isResolved(news) || !output) return;
|
|
63
|
+
yield* validate(output, news);
|
|
64
|
+
const deployment = yield* client.getDeployment(output.name).pipe(Effect.catchTag("ConvexNotFound", () => Effect.void));
|
|
65
|
+
if (!deployment) return { action: "update" };
|
|
66
|
+
const current = yield* attributes(deployment);
|
|
67
|
+
yield* validate(current, news);
|
|
68
|
+
if ((news.reference ?? output.reference) !== current.reference) return { action: "update" };
|
|
69
|
+
}),
|
|
70
|
+
read: Effect.fn("Deployment.read")(function* ({ fqn, instanceId, olds, output }) {
|
|
71
|
+
if (output) {
|
|
72
|
+
const deployment = yield* client.getDeployment(output.name).pipe(Effect.catchTag("ConvexNotFound", () => Effect.void));
|
|
73
|
+
return deployment ? yield* attributes(deployment) : void 0;
|
|
74
|
+
}
|
|
75
|
+
if (olds.projectId === void 0) return;
|
|
76
|
+
const deployment = yield* find(olds.projectId, olds.reference ?? (yield* resourceName("deployment", fqn, instanceId)));
|
|
77
|
+
return deployment ? Unowned(yield* attributes(deployment)) : void 0;
|
|
78
|
+
}),
|
|
79
|
+
reconcile: Effect.fn("Deployment.reconcile")(function* ({ fqn, instanceId, news, output }) {
|
|
80
|
+
if (!output) yield* checkpointCreate(fqn, instanceId, news);
|
|
81
|
+
if (output) yield* validate(output, news);
|
|
82
|
+
let deployment = output ? yield* client.getDeployment(output.name).pipe(Effect.catchTag("ConvexNotFound", () => Effect.void)) : void 0;
|
|
83
|
+
const reference = news.reference ?? output?.reference ?? (yield* resourceName("deployment", fqn, instanceId));
|
|
84
|
+
if (!deployment) {
|
|
85
|
+
const existing = yield* find(news.projectId, reference);
|
|
86
|
+
if (existing && !(yield* shouldAdopt(fqn))) return yield* new OwnedBySomeoneElse({
|
|
87
|
+
message: "An existing deployment requires explicit adoption.",
|
|
88
|
+
resourceType: Deployment.Type,
|
|
89
|
+
physicalName: reference
|
|
90
|
+
});
|
|
91
|
+
if (existing) {
|
|
92
|
+
const adopted = yield* attributes(existing);
|
|
93
|
+
yield* validate(adopted, news);
|
|
94
|
+
yield* checkpointCreate(fqn, instanceId, news, adopted);
|
|
95
|
+
deployment = existing;
|
|
96
|
+
} else deployment = yield* client.createDeployment(news.projectId, {
|
|
97
|
+
type: news.type,
|
|
98
|
+
reference,
|
|
99
|
+
...news.region === void 0 ? {} : { region: news.region }
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const current = yield* attributes(deployment);
|
|
103
|
+
yield* validate(current, news);
|
|
104
|
+
if (current.reference !== reference) {
|
|
105
|
+
const existing = yield* find(news.projectId, reference);
|
|
106
|
+
if (existing && existing.name !== current.name) return yield* new OwnedBySomeoneElse({
|
|
107
|
+
message: "The requested deployment reference is already in use.",
|
|
108
|
+
resourceType: Deployment.Type,
|
|
109
|
+
physicalName: reference
|
|
110
|
+
});
|
|
111
|
+
yield* client.updateDeployment(current.name, { reference });
|
|
112
|
+
deployment = yield* client.getDeployment(current.name);
|
|
113
|
+
}
|
|
114
|
+
return yield* attributes(deployment);
|
|
115
|
+
}),
|
|
116
|
+
delete: Effect.fn("Deployment.delete")(function* ({ output }) {
|
|
117
|
+
yield* client.deleteDeployment(output.name).pipe(Effect.catchTag("ConvexNotFound", () => Effect.void));
|
|
118
|
+
})
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
/**
|
|
122
|
+
* Under `alchemy dev` a deployment is a local Convex backend this provider
|
|
123
|
+
* owns. Alchemy's dev sidecar hosts it, so the backend keeps running across
|
|
124
|
+
* reloads of the stack and stops when the dev session ends. Its data lives in
|
|
125
|
+
* `.alchemy/convex/<stack>/<stage>/<name>` and is removed only when the
|
|
126
|
+
* deployment is destroyed.
|
|
127
|
+
*/
|
|
128
|
+
const localLayer = LocalProvider.make(Deployment, new URL(`./internal/LocalSidecar${moduleExtension(import.meta.url)}`, import.meta.url).href, Effect.gen(function* () {
|
|
129
|
+
const fs = yield* FileSystem.FileSystem;
|
|
130
|
+
const directory = yield* dataDirectories;
|
|
131
|
+
return {
|
|
132
|
+
resolveConfig: Effect.fn("Deployment.localConfig")(function* ({ fqn, instanceId, news }) {
|
|
133
|
+
return {
|
|
134
|
+
name: yield* resourceName("deployment", fqn, instanceId),
|
|
135
|
+
props: news
|
|
136
|
+
};
|
|
137
|
+
}),
|
|
138
|
+
start: Effect.fn("Deployment.localStart")(function* ({ config, invalidate }) {
|
|
139
|
+
const backend = yield* boot(config.name, directory(config.name));
|
|
140
|
+
yield* backend.exited.pipe(Effect.andThen(invalidate), Effect.forkScoped);
|
|
141
|
+
return {
|
|
142
|
+
projectId: config.props.projectId,
|
|
143
|
+
name: config.name,
|
|
144
|
+
reference: config.props.reference ?? config.name,
|
|
145
|
+
type: config.props.type,
|
|
146
|
+
url: backend.url,
|
|
147
|
+
...config.props.region === void 0 ? {} : { region: config.props.region }
|
|
148
|
+
};
|
|
149
|
+
}),
|
|
150
|
+
stop: Effect.fn("Deployment.localStop")(function* ({ fqn, instanceId }) {
|
|
151
|
+
const name = yield* resourceName("deployment", fqn, instanceId);
|
|
152
|
+
yield* remove(name, directory(name)).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
153
|
+
})
|
|
154
|
+
};
|
|
155
|
+
}));
|
|
156
|
+
const layer = Provider.effect(Deployment, provider);
|
|
157
|
+
//#endregion
|
|
158
|
+
export { AmbiguousDeployment, Deployment, DeploymentIdentityChange, UnsupportedLocalDeployment, layer, localLayer, provider };
|
|
159
|
+
|
|
160
|
+
//# sourceMappingURL=Deployment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Deployment.js","names":[],"sources":["../src/Deployment.ts"],"sourcesContent":["import type {\n CreateDeploymentType,\n PlatformDeploymentResponse,\n RegionName,\n} from \"@convex-dev/platform/managementApi\";\nimport { OwnedBySomeoneElse, Unowned } from \"alchemy/AdoptPolicy\";\nimport { isResolved } from \"alchemy/Diff\";\nimport * as LocalProvider from \"alchemy/Local/LocalProvider\";\nimport * as Provider from \"alchemy/Provider\";\nimport { Resource } from \"alchemy/Resource\";\nimport { moduleExtension } from \"alchemy/Util/Node\";\nimport * as Effect from \"effect/Effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Schema from \"effect/Schema\";\n\nimport { ConvexClient } from \"./ConvexClient.js\";\nimport type { Providers } from \"./Providers.js\";\nimport { resourceName } from \"./internal/ResourceIdentity.js\";\nimport { checkpointCreate, shouldAdopt } from \"./internal/Lifecycle.js\";\nimport { boot, dataDirectories, remove } from \"./internal/LocalBackend.js\";\n\nexport interface DeploymentProps {\n readonly projectId: number;\n readonly type: CreateDeploymentType;\n readonly reference?: string;\n readonly region?: RegionName;\n}\n\nexport interface DeploymentAttributes {\n readonly projectId: number;\n readonly name: string;\n readonly reference: string;\n readonly type: CreateDeploymentType;\n readonly url: string;\n /**\n * Always set in the cloud; a local deployment echoes the requested region.\n */\n readonly region?: RegionName;\n}\n\nexport type Deployment = Resource<\n \"Convex.Deployment\",\n DeploymentProps,\n DeploymentAttributes,\n never,\n Providers\n>;\nexport const Deployment = Resource<Deployment>(\"Convex.Deployment\", {\n defaultRemovalPolicy: \"retain\",\n});\n\nexport class DeploymentIdentityChange extends Schema.TaggedError<DeploymentIdentityChange>()(\n \"DeploymentIdentityChange\",\n {\n deploymentName: Schema.String,\n field: Schema.String,\n current: Schema.String,\n requested: Schema.String,\n },\n) {}\n\nexport class UnsupportedLocalDeployment extends Schema.TaggedError<UnsupportedLocalDeployment>()(\n \"UnsupportedLocalDeployment\",\n { deploymentName: Schema.String },\n) {}\n\nexport class AmbiguousDeployment extends Schema.TaggedError<AmbiguousDeployment>()(\n \"AmbiguousDeployment\",\n { projectId: Schema.Finite, reference: Schema.String },\n) {}\n\nexport const provider = Effect.gen(function* () {\n const client = yield* ConvexClient;\n const attributes = Effect.fn(\"Deployment.attributes\")(function* (\n deployment: PlatformDeploymentResponse,\n ) {\n if (deployment.kind !== \"cloud\")\n return yield* new UnsupportedLocalDeployment({\n deploymentName: deployment.name,\n });\n return {\n projectId: deployment.projectId,\n name: deployment.name,\n reference: deployment.reference,\n type: deployment.deploymentType,\n url: deployment.deploymentUrl,\n region: deployment.region,\n } satisfies DeploymentAttributes;\n });\n const find = Effect.fn(\"Deployment.find\")(function* (\n projectId: number,\n reference: string,\n ) {\n const matches = (yield* client.listDeployments(projectId)).filter(\n (deployment) =>\n deployment.kind === \"cloud\" && deployment.reference === reference,\n );\n if (matches.length > 1)\n return yield* new AmbiguousDeployment({ projectId, reference });\n return matches[0];\n });\n const validate = Effect.fn(\"Deployment.validate\")(function* (\n current: DeploymentAttributes,\n news: DeploymentProps,\n ) {\n for (const field of [\"projectId\", \"type\", \"region\"] as const) {\n if (news[field] !== undefined && current[field] !== news[field])\n return yield* new DeploymentIdentityChange({\n deploymentName: current.name,\n field,\n current: String(current[field]),\n requested: String(news[field]),\n });\n }\n });\n return {\n diff: Effect.fn(\"Deployment.diff\")(function* ({ news, output }) {\n if (!isResolved(news) || !output) return;\n yield* validate(output, news);\n const deployment = yield* client\n .getDeployment(output.name)\n .pipe(Effect.catchTag(\"ConvexNotFound\", () => Effect.void));\n if (!deployment) return { action: \"update\" };\n const current = yield* attributes(deployment);\n yield* validate(current, news);\n if ((news.reference ?? output.reference) !== current.reference)\n return { action: \"update\" };\n }),\n read: Effect.fn(\"Deployment.read\")(function* ({\n fqn,\n instanceId,\n olds,\n output,\n }) {\n if (output) {\n const deployment = yield* client\n .getDeployment(output.name)\n .pipe(Effect.catchTag(\"ConvexNotFound\", () => Effect.void));\n return deployment ? yield* attributes(deployment) : undefined;\n }\n if (olds.projectId === undefined) return;\n const deployment = yield* find(\n olds.projectId,\n olds.reference ?? (yield* resourceName(\"deployment\", fqn, instanceId)),\n );\n return deployment ? Unowned(yield* attributes(deployment)) : undefined;\n }),\n reconcile: Effect.fn(\"Deployment.reconcile\")(function* ({\n fqn,\n instanceId,\n news,\n output,\n }) {\n if (!output) yield* checkpointCreate(fqn, instanceId, news);\n if (output) yield* validate(output, news);\n let deployment = output\n ? yield* client\n .getDeployment(output.name)\n .pipe(Effect.catchTag(\"ConvexNotFound\", () => Effect.void))\n : undefined;\n const reference =\n news.reference ??\n output?.reference ??\n (yield* resourceName(\"deployment\", fqn, instanceId));\n if (!deployment) {\n const existing = yield* find(news.projectId, reference);\n if (existing && !(yield* shouldAdopt(fqn)))\n return yield* new OwnedBySomeoneElse({\n message: \"An existing deployment requires explicit adoption.\",\n resourceType: Deployment.Type,\n physicalName: reference,\n });\n if (existing) {\n const adopted = yield* attributes(existing);\n yield* validate(adopted, news);\n yield* checkpointCreate(fqn, instanceId, news, adopted);\n deployment = existing;\n } else {\n deployment = yield* client.createDeployment(news.projectId, {\n type: news.type,\n reference,\n ...(news.region === undefined ? {} : { region: news.region }),\n });\n }\n }\n const current = yield* attributes(deployment);\n yield* validate(current, news);\n if (current.reference !== reference) {\n const existing = yield* find(news.projectId, reference);\n if (existing && existing.name !== current.name)\n return yield* new OwnedBySomeoneElse({\n message: \"The requested deployment reference is already in use.\",\n resourceType: Deployment.Type,\n physicalName: reference,\n });\n yield* client.updateDeployment(current.name, {\n reference,\n });\n deployment = yield* client.getDeployment(current.name);\n }\n return yield* attributes(deployment);\n }),\n delete: Effect.fn(\"Deployment.delete\")(function* ({ output }) {\n yield* client\n .deleteDeployment(output.name)\n .pipe(Effect.catchTag(\"ConvexNotFound\", () => Effect.void));\n }),\n } satisfies Provider.ProviderServiceInput<Deployment>;\n});\n\ninterface LocalConfig {\n readonly name: string;\n readonly props: DeploymentProps;\n}\n\n/**\n * Under `alchemy dev` a deployment is a local Convex backend this provider\n * owns. Alchemy's dev sidecar hosts it, so the backend keeps running across\n * reloads of the stack and stops when the dev session ends. Its data lives in\n * `.alchemy/convex/<stack>/<stage>/<name>` and is removed only when the\n * deployment is destroyed.\n */\nexport const localLayer = LocalProvider.make(\n Deployment,\n new URL(\n `./internal/LocalSidecar${moduleExtension(import.meta.url)}`,\n import.meta.url,\n ).href,\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const directory = yield* dataDirectories;\n return {\n resolveConfig: Effect.fn(\"Deployment.localConfig\")(function* ({\n fqn,\n instanceId,\n news,\n }) {\n return {\n name: yield* resourceName(\"deployment\", fqn, instanceId),\n props: news,\n } satisfies LocalConfig;\n }),\n start: Effect.fn(\"Deployment.localStart\")(function* ({\n config,\n invalidate,\n }) {\n const backend = yield* boot(config.name, directory(config.name));\n yield* backend.exited.pipe(\n Effect.andThen(invalidate),\n Effect.forkScoped,\n );\n return {\n projectId: config.props.projectId,\n name: config.name,\n reference: config.props.reference ?? config.name,\n type: config.props.type,\n url: backend.url,\n ...(config.props.region === undefined\n ? {}\n : { region: config.props.region }),\n } satisfies DeploymentAttributes;\n }),\n stop: Effect.fn(\"Deployment.localStop\")(function* ({ fqn, instanceId }) {\n const name = yield* resourceName(\"deployment\", fqn, instanceId);\n yield* remove(name, directory(name)).pipe(\n Effect.provideService(FileSystem.FileSystem, fs),\n );\n }),\n } satisfies LocalProvider.LocalProviderSpec<\n Deployment,\n LocalConfig,\n Effect.Services<ReturnType<typeof boot>>\n >;\n }),\n);\n\nexport const layer = Provider.effect(Deployment, provider);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { OwnedBySomeoneElse } from "alchemy/AdoptPolicy";
|
|
2
|
+
import * as Provider from "alchemy/Provider";
|
|
3
|
+
import { Resource } from "alchemy/Resource";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Layer from "effect/Layer";
|
|
6
|
+
import * as Redacted from "effect/Redacted";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
import * as ConvexClient from "./ConvexClient.js";
|
|
9
|
+
import type { Providers } from "./Providers.js";
|
|
10
|
+
export interface EnvironmentVariablesProps {
|
|
11
|
+
readonly url: string;
|
|
12
|
+
readonly deployKey: Redacted.Redacted<string>;
|
|
13
|
+
readonly variables: Readonly<Record<string, string | Redacted.Redacted<string>>>;
|
|
14
|
+
}
|
|
15
|
+
export interface EnvironmentVariablesAttributes {
|
|
16
|
+
readonly url: string;
|
|
17
|
+
readonly deployKey: Redacted.Redacted<string>;
|
|
18
|
+
readonly ownedNames: ReadonlyArray<string>;
|
|
19
|
+
readonly variables: Readonly<Record<string, Redacted.Redacted<string>>>;
|
|
20
|
+
readonly originals: Readonly<Record<string, Redacted.Redacted<string>>>;
|
|
21
|
+
}
|
|
22
|
+
export type EnvironmentVariables = Resource<"Convex.EnvironmentVariables", EnvironmentVariablesProps, EnvironmentVariablesAttributes, never, Providers>;
|
|
23
|
+
export declare const EnvironmentVariables: import("alchemy/Resource").ResourceClass<EnvironmentVariables>;
|
|
24
|
+
declare const EnvironmentTargetChange_base: Schema.Class<EnvironmentTargetChange, Schema.TaggedStruct<"EnvironmentTargetChange", {
|
|
25
|
+
readonly url: Schema.String;
|
|
26
|
+
}>, import("effect/Cause").YieldableError>;
|
|
27
|
+
export declare class EnvironmentTargetChange extends EnvironmentTargetChange_base {
|
|
28
|
+
}
|
|
29
|
+
export declare const provider: Effect.Effect<{
|
|
30
|
+
diff: (args_0: {
|
|
31
|
+
id: string;
|
|
32
|
+
fqn: string;
|
|
33
|
+
instanceId: string;
|
|
34
|
+
olds: EnvironmentVariablesProps;
|
|
35
|
+
news: import("alchemy/Input").Input<EnvironmentVariablesProps>;
|
|
36
|
+
oldBindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
37
|
+
newBindings: import("alchemy/Input").Input<import("alchemy/Resource").ResourceBinding<never>[]>;
|
|
38
|
+
output: EnvironmentVariablesAttributes | undefined;
|
|
39
|
+
}) => Effect.Effect<{
|
|
40
|
+
action: "update";
|
|
41
|
+
} | undefined, EnvironmentTargetChange | ConvexClient.ConvexClientError, never>;
|
|
42
|
+
read: (args_0: {
|
|
43
|
+
id: string;
|
|
44
|
+
fqn: string;
|
|
45
|
+
instanceId: string;
|
|
46
|
+
olds: EnvironmentVariablesProps;
|
|
47
|
+
output: EnvironmentVariablesAttributes | undefined;
|
|
48
|
+
}) => Effect.Effect<{
|
|
49
|
+
url: string;
|
|
50
|
+
ownedNames: ReadonlyArray<string>;
|
|
51
|
+
originals: Readonly<Record<string, Redacted.Redacted<string>>>;
|
|
52
|
+
deployKey: Redacted.Redacted<string>;
|
|
53
|
+
variables: {
|
|
54
|
+
[k: string]: Redacted.Redacted<string>;
|
|
55
|
+
};
|
|
56
|
+
} | undefined, ConvexClient.ConvexClientError, never>;
|
|
57
|
+
reconcile: (args_0: {
|
|
58
|
+
id: string;
|
|
59
|
+
fqn: string;
|
|
60
|
+
instanceId: string;
|
|
61
|
+
news: EnvironmentVariablesProps;
|
|
62
|
+
olds: EnvironmentVariablesProps | undefined;
|
|
63
|
+
output: EnvironmentVariablesAttributes | undefined;
|
|
64
|
+
session: import("alchemy/Report").ScopedPlanStatusSession;
|
|
65
|
+
bindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
66
|
+
}) => Effect.Effect<{
|
|
67
|
+
url: string;
|
|
68
|
+
deployKey: Redacted.Redacted<string>;
|
|
69
|
+
ownedNames: string[];
|
|
70
|
+
variables: {
|
|
71
|
+
[k: string]: Redacted.Redacted<string>;
|
|
72
|
+
};
|
|
73
|
+
originals: {
|
|
74
|
+
[k: string]: Redacted.Redacted<string>;
|
|
75
|
+
};
|
|
76
|
+
}, ConvexClient.ConvexApiError | ConvexClient.ConvexConflict | ConvexClient.ConvexNotFound | EnvironmentTargetChange | import("./internal/Lifecycle.js").LifecycleStateError | OwnedBySomeoneElse | import("alchemy/State/State").StateStoreError, never>;
|
|
77
|
+
delete: (args_0: {
|
|
78
|
+
id: string;
|
|
79
|
+
fqn: string;
|
|
80
|
+
instanceId: string;
|
|
81
|
+
olds: EnvironmentVariablesProps;
|
|
82
|
+
output: EnvironmentVariablesAttributes;
|
|
83
|
+
session: import("alchemy/Report").ScopedPlanStatusSession;
|
|
84
|
+
bindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
85
|
+
force?: boolean;
|
|
86
|
+
}) => Effect.Effect<void, ConvexClient.ConvexApiError | ConvexClient.ConvexConflict, never>;
|
|
87
|
+
}, never, ConvexClient.ConvexClient>;
|
|
88
|
+
/**
|
|
89
|
+
* Under `alchemy dev` variables are managed on the local backend. A backend
|
|
90
|
+
* that is not running keeps its variables in its retained data, so removing
|
|
91
|
+
* them is skipped rather than failing the apply.
|
|
92
|
+
*/
|
|
93
|
+
export declare const localProvider: Effect.Effect<{
|
|
94
|
+
diff: (args_0: {
|
|
95
|
+
id: string;
|
|
96
|
+
fqn: string;
|
|
97
|
+
instanceId: string;
|
|
98
|
+
olds: EnvironmentVariablesProps;
|
|
99
|
+
news: import("alchemy/Input").Input<EnvironmentVariablesProps>;
|
|
100
|
+
oldBindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
101
|
+
newBindings: import("alchemy/Input").Input<import("alchemy/Resource").ResourceBinding<never>[]>;
|
|
102
|
+
output: EnvironmentVariablesAttributes | undefined;
|
|
103
|
+
}) => Effect.Effect<{
|
|
104
|
+
action: "update";
|
|
105
|
+
} | undefined, EnvironmentTargetChange | ConvexClient.ConvexClientError, never>;
|
|
106
|
+
read: (args_0: {
|
|
107
|
+
id: string;
|
|
108
|
+
fqn: string;
|
|
109
|
+
instanceId: string;
|
|
110
|
+
olds: EnvironmentVariablesProps;
|
|
111
|
+
output: EnvironmentVariablesAttributes | undefined;
|
|
112
|
+
}) => Effect.Effect<{
|
|
113
|
+
url: string;
|
|
114
|
+
ownedNames: ReadonlyArray<string>;
|
|
115
|
+
originals: Readonly<Record<string, Redacted.Redacted<string>>>;
|
|
116
|
+
deployKey: Redacted.Redacted<string>;
|
|
117
|
+
variables: {
|
|
118
|
+
[k: string]: Redacted.Redacted<string>;
|
|
119
|
+
};
|
|
120
|
+
} | undefined, ConvexClient.ConvexClientError, never>;
|
|
121
|
+
reconcile: (args_0: {
|
|
122
|
+
id: string;
|
|
123
|
+
fqn: string;
|
|
124
|
+
instanceId: string;
|
|
125
|
+
news: EnvironmentVariablesProps;
|
|
126
|
+
olds: EnvironmentVariablesProps | undefined;
|
|
127
|
+
output: EnvironmentVariablesAttributes | undefined;
|
|
128
|
+
session: import("alchemy/Report").ScopedPlanStatusSession;
|
|
129
|
+
bindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
130
|
+
}) => Effect.Effect<{
|
|
131
|
+
url: string;
|
|
132
|
+
deployKey: Redacted.Redacted<string>;
|
|
133
|
+
ownedNames: string[];
|
|
134
|
+
variables: {
|
|
135
|
+
[k: string]: Redacted.Redacted<string>;
|
|
136
|
+
};
|
|
137
|
+
originals: {
|
|
138
|
+
[k: string]: Redacted.Redacted<string>;
|
|
139
|
+
};
|
|
140
|
+
}, ConvexClient.ConvexApiError | ConvexClient.ConvexConflict | ConvexClient.ConvexNotFound | EnvironmentTargetChange | import("./internal/Lifecycle.js").LifecycleStateError | OwnedBySomeoneElse | import("alchemy/State/State").StateStoreError, never>;
|
|
141
|
+
delete: (input: {
|
|
142
|
+
id: string;
|
|
143
|
+
fqn: string;
|
|
144
|
+
instanceId: string;
|
|
145
|
+
olds: EnvironmentVariablesProps;
|
|
146
|
+
output: EnvironmentVariablesAttributes;
|
|
147
|
+
session: import("alchemy/Report").ScopedPlanStatusSession;
|
|
148
|
+
bindings: import("alchemy/Resource").ResourceBinding<never>[];
|
|
149
|
+
force?: boolean;
|
|
150
|
+
}) => Effect.Effect<void, any, never>;
|
|
151
|
+
}, never, ConvexClient.ConvexClient>;
|
|
152
|
+
export declare const layer: Layer.Layer<Provider.Provider<EnvironmentVariables>, never, ConvexClient.ConvexClient>;
|
|
153
|
+
export declare const localLayer: Layer.Layer<Provider.Provider<EnvironmentVariables>, never, never>;
|
|
154
|
+
export {};
|
|
155
|
+
//# sourceMappingURL=EnvironmentVariables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnvironmentVariables.d.ts","sourceRoot":"","sources":["../src/EnvironmentVariables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAW,MAAM,qBAAqB,CAAC;AAElE,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAC1B,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CACnD,CAAC;CACH;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACxE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;CACzE;AAED,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CACzC,6BAA6B,EAC7B,yBAAyB,EACzB,8BAA8B,EAC9B,KAAK,EACL,SAAS,CACV,CAAC;AACF,eAAO,MAAM,oBAAoB,gEAEhC,CAAC;;;;AAEF,qBAAa,uBAAwB,SAAQ,4BAG5C;CAAG;AAEJ,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;aAvBL,MAAM;oBAEC,aAAa,CAAC,MAAM,CAAC;mBAEtB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCA+LvE,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;aA1MV,MAAM;oBAEC,aAAa,CAAC,MAAM,CAAC;mBAEtB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAsNxE,CAAC;AAEF,eAAO,MAAM,KAAK,wFAAkD,CAAC;AACrE,eAAO,MAAM,UAAU,oEAStB,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { ConvexClient, layer as layer$1 } from "./ConvexClient.js";
|
|
2
|
+
import { checkpointCreate, shouldAdopt } from "./internal/Lifecycle.js";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Provider from "alchemy/Provider";
|
|
5
|
+
import { Resource } from "alchemy/Resource";
|
|
6
|
+
import * as Redacted from "effect/Redacted";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
import * as Layer from "effect/Layer";
|
|
9
|
+
import { OwnedBySomeoneElse, Unowned } from "alchemy/AdoptPolicy";
|
|
10
|
+
import { isResolved } from "alchemy/Diff";
|
|
11
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
12
|
+
//#region src/EnvironmentVariables.ts
|
|
13
|
+
const EnvironmentVariables = Resource("Convex.EnvironmentVariables");
|
|
14
|
+
var EnvironmentTargetChange = class extends Schema.TaggedError()("EnvironmentTargetChange", { url: Schema.String }) {};
|
|
15
|
+
const provider = Effect.gen(function* () {
|
|
16
|
+
const client = yield* ConvexClient;
|
|
17
|
+
const redacted = (value) => typeof value === "string" ? Redacted.make(value) : value;
|
|
18
|
+
const valueAt = (variables, name) => Object.hasOwn(variables, name) ? variables[name] : void 0;
|
|
19
|
+
const select = (variables, names) => Object.fromEntries(names.flatMap((name) => !Object.hasOwn(variables, name) ? [] : [[name, variables[name]]]));
|
|
20
|
+
return {
|
|
21
|
+
diff: Effect.fn("EnvironmentVariables.diff")(function* ({ news, output }) {
|
|
22
|
+
if (!isResolved(news) || !output) return;
|
|
23
|
+
if (news.url !== output.url) return yield* new EnvironmentTargetChange({ url: output.url });
|
|
24
|
+
const names = Object.keys(news.variables);
|
|
25
|
+
if (names.length !== output.ownedNames.length || names.some((name) => !output.ownedNames.includes(name))) return { action: "update" };
|
|
26
|
+
const variables = yield* client.listEnvironmentVariables(news.url, news.deployKey);
|
|
27
|
+
for (const [name, value] of Object.entries(news.variables)) {
|
|
28
|
+
const observed = valueAt(variables, name);
|
|
29
|
+
if (observed === void 0 || Redacted.value(observed) !== Redacted.value(redacted(value))) return { action: "update" };
|
|
30
|
+
}
|
|
31
|
+
}),
|
|
32
|
+
read: Effect.fn("EnvironmentVariables.read")(function* ({ olds, output }) {
|
|
33
|
+
const url = output?.url ?? olds.url;
|
|
34
|
+
if (url === void 0 || olds.deployKey === void 0) return;
|
|
35
|
+
const observed = yield* client.listEnvironmentVariables(url, olds.deployKey);
|
|
36
|
+
const ownedNames = output?.ownedNames ?? Object.keys(olds.variables);
|
|
37
|
+
const variables = select(observed, ownedNames);
|
|
38
|
+
if (output) return {
|
|
39
|
+
...output,
|
|
40
|
+
deployKey: olds.deployKey,
|
|
41
|
+
variables
|
|
42
|
+
};
|
|
43
|
+
if (Object.keys(variables).length === 0) return void 0;
|
|
44
|
+
return Unowned({
|
|
45
|
+
url,
|
|
46
|
+
deployKey: olds.deployKey,
|
|
47
|
+
ownedNames,
|
|
48
|
+
variables,
|
|
49
|
+
originals: variables
|
|
50
|
+
});
|
|
51
|
+
}),
|
|
52
|
+
reconcile: Effect.fn("EnvironmentVariables.reconcile")(function* ({ fqn, instanceId, news, output }) {
|
|
53
|
+
if (!output) yield* checkpointCreate(fqn, instanceId, news);
|
|
54
|
+
if (output && output.url !== news.url) return yield* new EnvironmentTargetChange({ url: output.url });
|
|
55
|
+
const observed = yield* client.listEnvironmentVariables(news.url, news.deployKey);
|
|
56
|
+
const ownedNames = Object.keys(news.variables);
|
|
57
|
+
if (!output && (yield* shouldAdopt(fqn))) {
|
|
58
|
+
const variables = select(observed, ownedNames);
|
|
59
|
+
output = {
|
|
60
|
+
url: news.url,
|
|
61
|
+
deployKey: news.deployKey,
|
|
62
|
+
ownedNames,
|
|
63
|
+
variables,
|
|
64
|
+
originals: variables
|
|
65
|
+
};
|
|
66
|
+
yield* checkpointCreate(fqn, instanceId, news, output);
|
|
67
|
+
}
|
|
68
|
+
const previousNames = output?.ownedNames ?? [];
|
|
69
|
+
for (const name of ownedNames) if (!previousNames.includes(name) && valueAt(observed, name) !== void 0) return yield* new OwnedBySomeoneElse({
|
|
70
|
+
message: "An existing environment variable requires explicit adoption in a separate resource.",
|
|
71
|
+
resourceType: EnvironmentVariables.Type,
|
|
72
|
+
physicalName: name
|
|
73
|
+
});
|
|
74
|
+
const desired = Object.fromEntries(Object.entries(news.variables).map(([name, value]) => [name, redacted(value)]));
|
|
75
|
+
const changes = [];
|
|
76
|
+
for (const [name, value] of Object.entries(desired)) {
|
|
77
|
+
const current = valueAt(observed, name);
|
|
78
|
+
if (current === void 0 || Redacted.value(current) !== Redacted.value(value)) changes.push({
|
|
79
|
+
name,
|
|
80
|
+
value
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
for (const name of previousNames) {
|
|
84
|
+
if (Object.hasOwn(desired, name)) continue;
|
|
85
|
+
const original = output ? valueAt(output.originals, name) : void 0;
|
|
86
|
+
const current = valueAt(observed, name);
|
|
87
|
+
if (original !== void 0) {
|
|
88
|
+
if (current === void 0 || Redacted.value(current) !== Redacted.value(original)) changes.push({
|
|
89
|
+
name,
|
|
90
|
+
value: original
|
|
91
|
+
});
|
|
92
|
+
} else if (current !== void 0) changes.push({ name });
|
|
93
|
+
}
|
|
94
|
+
if (changes.length > 0) yield* client.updateEnvironmentVariables(news.url, news.deployKey, changes);
|
|
95
|
+
return {
|
|
96
|
+
url: news.url,
|
|
97
|
+
deployKey: news.deployKey,
|
|
98
|
+
ownedNames,
|
|
99
|
+
variables: desired,
|
|
100
|
+
originals: select(output?.originals ?? {}, ownedNames)
|
|
101
|
+
};
|
|
102
|
+
}),
|
|
103
|
+
delete: Effect.fn("EnvironmentVariables.delete")(function* ({ output }) {
|
|
104
|
+
const observed = yield* client.listEnvironmentVariables(output.url, output.deployKey).pipe(Effect.catchTag("ConvexNotFound", () => Effect.void));
|
|
105
|
+
if (observed === void 0) return;
|
|
106
|
+
const changes = [];
|
|
107
|
+
for (const name of output.ownedNames) {
|
|
108
|
+
const original = valueAt(output.originals, name);
|
|
109
|
+
const current = valueAt(observed, name);
|
|
110
|
+
if (original !== void 0) {
|
|
111
|
+
if (current === void 0 || Redacted.value(current) !== Redacted.value(original)) changes.push({
|
|
112
|
+
name,
|
|
113
|
+
value: original
|
|
114
|
+
});
|
|
115
|
+
} else if (current !== void 0) changes.push({ name });
|
|
116
|
+
}
|
|
117
|
+
if (changes.length > 0) yield* client.updateEnvironmentVariables(output.url, output.deployKey, changes).pipe(Effect.catchTag("ConvexNotFound", () => Effect.void));
|
|
118
|
+
})
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
/**
|
|
122
|
+
* Under `alchemy dev` variables are managed on the local backend. A backend
|
|
123
|
+
* that is not running keeps its variables in its retained data, so removing
|
|
124
|
+
* them is skipped rather than failing the apply.
|
|
125
|
+
*/
|
|
126
|
+
const localProvider = Effect.map(provider, (service) => ({
|
|
127
|
+
...service,
|
|
128
|
+
delete: (input) => service.delete(input).pipe(Effect.catchIf((error) => error._tag === "ConvexApiError" && error.code === "TransportError", () => Effect.void))
|
|
129
|
+
}));
|
|
130
|
+
const layer = Provider.effect(EnvironmentVariables, provider);
|
|
131
|
+
const localLayer = Provider.effect(EnvironmentVariables, localProvider).pipe(Layer.provide(layer$1({ mode: "local" }).pipe(Layer.provide(FetchHttpClient.layer))));
|
|
132
|
+
//#endregion
|
|
133
|
+
export { EnvironmentTargetChange, EnvironmentVariables, layer, localLayer, localProvider, provider };
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=EnvironmentVariables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnvironmentVariables.js","names":["ConvexClient.ConvexClient","ConvexClient.layer"],"sources":["../src/EnvironmentVariables.ts"],"sourcesContent":["import { OwnedBySomeoneElse, Unowned } from \"alchemy/AdoptPolicy\";\nimport { isResolved } from \"alchemy/Diff\";\nimport * as Provider from \"alchemy/Provider\";\nimport { Resource } from \"alchemy/Resource\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as FetchHttpClient from \"effect/http/FetchHttpClient\";\nimport * as Redacted from \"effect/Redacted\";\nimport * as Schema from \"effect/Schema\";\n\nimport * as ConvexClient from \"./ConvexClient.js\";\nimport type { Providers } from \"./Providers.js\";\nimport { checkpointCreate, shouldAdopt } from \"./internal/Lifecycle.js\";\n\nexport interface EnvironmentVariablesProps {\n readonly url: string;\n readonly deployKey: Redacted.Redacted<string>;\n readonly variables: Readonly<\n Record<string, string | Redacted.Redacted<string>>\n >;\n}\n\nexport interface EnvironmentVariablesAttributes {\n readonly url: string;\n readonly deployKey: Redacted.Redacted<string>;\n readonly ownedNames: ReadonlyArray<string>;\n readonly variables: Readonly<Record<string, Redacted.Redacted<string>>>;\n readonly originals: Readonly<Record<string, Redacted.Redacted<string>>>;\n}\n\nexport type EnvironmentVariables = Resource<\n \"Convex.EnvironmentVariables\",\n EnvironmentVariablesProps,\n EnvironmentVariablesAttributes,\n never,\n Providers\n>;\nexport const EnvironmentVariables = Resource<EnvironmentVariables>(\n \"Convex.EnvironmentVariables\",\n);\n\nexport class EnvironmentTargetChange extends Schema.TaggedError<EnvironmentTargetChange>()(\n \"EnvironmentTargetChange\",\n { url: Schema.String },\n) {}\n\nexport const provider = Effect.gen(function* () {\n const client = yield* ConvexClient.ConvexClient;\n const redacted = (value: string | Redacted.Redacted<string>) =>\n typeof value === \"string\" ? Redacted.make(value) : value;\n const valueAt = (\n variables: Readonly<Record<string, Redacted.Redacted<string>>>,\n name: string,\n ) => (Object.hasOwn(variables, name) ? variables[name] : undefined);\n const select = (\n variables: Readonly<Record<string, Redacted.Redacted<string>>>,\n names: ReadonlyArray<string>,\n ) =>\n Object.fromEntries(\n names.flatMap((name) =>\n !Object.hasOwn(variables, name) ? [] : [[name, variables[name]]],\n ),\n );\n return {\n diff: Effect.fn(\"EnvironmentVariables.diff\")(function* ({ news, output }) {\n if (!isResolved(news) || !output) return;\n if (news.url !== output.url)\n return yield* new EnvironmentTargetChange({\n url: output.url,\n });\n const names = Object.keys(news.variables);\n if (\n names.length !== output.ownedNames.length ||\n names.some((name) => !output.ownedNames.includes(name))\n )\n return { action: \"update\" };\n const variables = yield* client.listEnvironmentVariables(\n news.url,\n news.deployKey,\n );\n for (const [name, value] of Object.entries(news.variables)) {\n const observed = valueAt(variables, name);\n if (\n observed === undefined ||\n Redacted.value(observed) !== Redacted.value(redacted(value))\n )\n return { action: \"update\" };\n }\n }),\n read: Effect.fn(\"EnvironmentVariables.read\")(function* ({ olds, output }) {\n const url = output?.url ?? olds.url;\n if (url === undefined || olds.deployKey === undefined) return;\n const observed = yield* client.listEnvironmentVariables(\n url,\n olds.deployKey,\n );\n const ownedNames = output?.ownedNames ?? Object.keys(olds.variables);\n const variables = select(observed, ownedNames);\n if (output) return { ...output, deployKey: olds.deployKey, variables };\n if (Object.keys(variables).length === 0) return undefined;\n return Unowned({\n url,\n deployKey: olds.deployKey,\n ownedNames,\n variables,\n originals: variables,\n });\n }),\n reconcile: Effect.fn(\"EnvironmentVariables.reconcile\")(function* ({\n fqn,\n instanceId,\n news,\n output,\n }) {\n if (!output) yield* checkpointCreate(fqn, instanceId, news);\n if (output && output.url !== news.url)\n return yield* new EnvironmentTargetChange({\n url: output.url,\n });\n const observed = yield* client.listEnvironmentVariables(\n news.url,\n news.deployKey,\n );\n const ownedNames = Object.keys(news.variables);\n if (!output && (yield* shouldAdopt(fqn))) {\n const variables = select(observed, ownedNames);\n output = {\n url: news.url,\n deployKey: news.deployKey,\n ownedNames,\n variables,\n originals: variables,\n };\n yield* checkpointCreate(fqn, instanceId, news, output);\n }\n const previousNames = output?.ownedNames ?? [];\n for (const name of ownedNames) {\n if (\n !previousNames.includes(name) &&\n valueAt(observed, name) !== undefined\n )\n return yield* new OwnedBySomeoneElse({\n message:\n \"An existing environment variable requires explicit adoption in a separate resource.\",\n resourceType: EnvironmentVariables.Type,\n physicalName: name,\n });\n }\n const desired = Object.fromEntries(\n Object.entries(news.variables).map(([name, value]) => [\n name,\n redacted(value),\n ]),\n );\n const changes: Array<{\n name: string;\n value?: Redacted.Redacted<string>;\n }> = [];\n for (const [name, value] of Object.entries(desired)) {\n const current = valueAt(observed, name);\n if (\n current === undefined ||\n Redacted.value(current) !== Redacted.value(value)\n )\n changes.push({ name, value });\n }\n for (const name of previousNames) {\n if (Object.hasOwn(desired, name)) continue;\n const original = output ? valueAt(output.originals, name) : undefined;\n const current = valueAt(observed, name);\n if (original !== undefined) {\n if (\n current === undefined ||\n Redacted.value(current) !== Redacted.value(original)\n )\n changes.push({ name, value: original });\n } else if (current !== undefined) changes.push({ name });\n }\n if (changes.length > 0)\n yield* client.updateEnvironmentVariables(\n news.url,\n news.deployKey,\n changes,\n );\n return {\n url: news.url,\n deployKey: news.deployKey,\n ownedNames,\n variables: desired,\n originals: select(output?.originals ?? {}, ownedNames),\n };\n }),\n delete: Effect.fn(\"EnvironmentVariables.delete\")(function* ({ output }) {\n const observed = yield* client\n .listEnvironmentVariables(output.url, output.deployKey)\n .pipe(Effect.catchTag(\"ConvexNotFound\", () => Effect.void));\n if (observed === undefined) return;\n const changes: Array<{\n name: string;\n value?: Redacted.Redacted<string>;\n }> = [];\n for (const name of output.ownedNames) {\n const original = valueAt(output.originals, name);\n const current = valueAt(observed, name);\n if (original !== undefined) {\n if (\n current === undefined ||\n Redacted.value(current) !== Redacted.value(original)\n )\n changes.push({ name, value: original });\n } else if (current !== undefined) changes.push({ name });\n }\n if (changes.length > 0)\n yield* client\n .updateEnvironmentVariables(output.url, output.deployKey, changes)\n .pipe(Effect.catchTag(\"ConvexNotFound\", () => Effect.void));\n }),\n } satisfies Provider.ProviderServiceInput<EnvironmentVariables>;\n});\n\n/**\n * Under `alchemy dev` variables are managed on the local backend. A backend\n * that is not running keeps its variables in its retained data, so removing\n * them is skipped rather than failing the apply.\n */\nexport const localProvider = Effect.map(\n provider,\n (service) =>\n ({\n ...service,\n delete: (input) =>\n // oxlint-disable-next-line effecttsgo/any-unknown-in-error-context -- Alchemy's provider input type erases the delete error channel.\n service.delete(input).pipe(\n Effect.catchIf(\n (error) =>\n error._tag === \"ConvexApiError\" &&\n error.code === \"TransportError\",\n () => Effect.void,\n ),\n ),\n }) satisfies Provider.ProviderServiceInput<EnvironmentVariables>,\n);\n\nexport const layer = Provider.effect(EnvironmentVariables, provider);\nexport const localLayer = Provider.effect(\n EnvironmentVariables,\n localProvider,\n).pipe(\n Layer.provide(\n ConvexClient.layer({ mode: \"local\" }).pipe(\n Layer.provide(FetchHttpClient.layer),\n ),\n ),\n);\n"],"mappings":"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"}
|