@gaganref/confect-alchemy 0.0.0-stage → 10.3.1-fork.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +22 -2
  3. package/dist/Backend.d.ts +45 -0
  4. package/dist/Backend.d.ts.map +1 -0
  5. package/dist/Backend.js +38 -0
  6. package/dist/Backend.js.map +1 -0
  7. package/dist/Code.d.ts +80 -0
  8. package/dist/Code.d.ts.map +1 -0
  9. package/dist/Code.js +29 -0
  10. package/dist/Code.js.map +1 -0
  11. package/dist/Confect.d.ts +2 -0
  12. package/dist/Confect.d.ts.map +1 -0
  13. package/dist/Confect.js +8 -0
  14. package/dist/Confect.js.map +1 -0
  15. package/dist/Convex.d.ts +7 -0
  16. package/dist/Convex.d.ts.map +1 -0
  17. package/dist/Convex.js +21 -0
  18. package/dist/Convex.js.map +1 -0
  19. package/dist/ConvexClient.d.ts +215 -0
  20. package/dist/ConvexClient.d.ts.map +1 -0
  21. package/dist/ConvexClient.js +224 -0
  22. package/dist/ConvexClient.js.map +1 -0
  23. package/dist/DeployKey.d.ts +120 -0
  24. package/dist/DeployKey.d.ts.map +1 -0
  25. package/dist/DeployKey.js +151 -0
  26. package/dist/DeployKey.js.map +1 -0
  27. package/dist/Deployment.d.ts +113 -0
  28. package/dist/Deployment.d.ts.map +1 -0
  29. package/dist/Deployment.js +160 -0
  30. package/dist/Deployment.js.map +1 -0
  31. package/dist/EnvironmentVariables.d.ts +155 -0
  32. package/dist/EnvironmentVariables.d.ts.map +1 -0
  33. package/dist/EnvironmentVariables.js +135 -0
  34. package/dist/EnvironmentVariables.js.map +1 -0
  35. package/dist/Project.d.ts +100 -0
  36. package/dist/Project.d.ts.map +1 -0
  37. package/dist/Project.js +123 -0
  38. package/dist/Project.js.map +1 -0
  39. package/dist/Providers.d.ts +17 -0
  40. package/dist/Providers.d.ts.map +1 -0
  41. package/dist/Providers.js +46 -0
  42. package/dist/Providers.js.map +1 -0
  43. package/dist/_virtual/_rolldown/runtime.js +13 -0
  44. package/dist/index.d.ts +3 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +3 -0
  47. package/dist/internal/CodeDeployment.d.ts +17 -0
  48. package/dist/internal/CodeDeployment.d.ts.map +1 -0
  49. package/dist/internal/CodeDeployment.js +53 -0
  50. package/dist/internal/CodeDeployment.js.map +1 -0
  51. package/dist/internal/CommandRunner.d.ts +55 -0
  52. package/dist/internal/CommandRunner.d.ts.map +1 -0
  53. package/dist/internal/CommandRunner.js +126 -0
  54. package/dist/internal/CommandRunner.js.map +1 -0
  55. package/dist/internal/FileLock.d.ts +30 -0
  56. package/dist/internal/FileLock.d.ts.map +1 -0
  57. package/dist/internal/FileLock.js +83 -0
  58. package/dist/internal/FileLock.js.map +1 -0
  59. package/dist/internal/Lifecycle.d.ts +11 -0
  60. package/dist/internal/Lifecycle.d.ts.map +1 -0
  61. package/dist/internal/Lifecycle.js +45 -0
  62. package/dist/internal/Lifecycle.js.map +1 -0
  63. package/dist/internal/LocalBackend.d.ts +63 -0
  64. package/dist/internal/LocalBackend.d.ts.map +1 -0
  65. package/dist/internal/LocalBackend.js +333 -0
  66. package/dist/internal/LocalBackend.js.map +1 -0
  67. package/dist/internal/LocalSidecar.d.ts +3 -0
  68. package/dist/internal/LocalSidecar.d.ts.map +1 -0
  69. package/dist/internal/LocalSidecar.js +7 -0
  70. package/dist/internal/LocalSidecar.js.map +1 -0
  71. package/dist/internal/Loopback.d.ts +18 -0
  72. package/dist/internal/Loopback.d.ts.map +1 -0
  73. package/dist/internal/Loopback.js +31 -0
  74. package/dist/internal/Loopback.js.map +1 -0
  75. package/dist/internal/PushLock.d.ts +36 -0
  76. package/dist/internal/PushLock.d.ts.map +1 -0
  77. package/dist/internal/PushLock.js +61 -0
  78. package/dist/internal/PushLock.js.map +1 -0
  79. package/dist/internal/ResourceIdentity.d.ts +3 -0
  80. package/dist/internal/ResourceIdentity.d.ts.map +1 -0
  81. package/dist/internal/ResourceIdentity.js +10 -0
  82. package/dist/internal/ResourceIdentity.js.map +1 -0
  83. package/dist/internal/UserCache.d.ts +12 -0
  84. package/dist/internal/UserCache.d.ts.map +1 -0
  85. package/dist/internal/UserCache.js +25 -0
  86. package/dist/internal/UserCache.js.map +1 -0
  87. package/dist/internal/Zip.d.ts +15 -0
  88. package/dist/internal/Zip.d.ts.map +1 -0
  89. package/dist/internal/Zip.js +65 -0
  90. package/dist/internal/Zip.js.map +1 -0
  91. package/package.json +65 -3
  92. package/src/Backend.ts +101 -0
  93. package/src/Code.ts +55 -0
  94. package/src/Confect.ts +1 -0
  95. package/src/Convex.ts +18 -0
  96. package/src/ConvexClient.ts +544 -0
  97. package/src/DeployKey.ts +256 -0
  98. package/src/Deployment.ts +277 -0
  99. package/src/EnvironmentVariables.ts +254 -0
  100. package/src/Project.ts +205 -0
  101. package/src/Providers.ts +67 -0
  102. package/src/index.ts +2 -0
  103. package/src/internal/CodeDeployment.ts +81 -0
  104. package/src/internal/CommandRunner.ts +251 -0
  105. package/src/internal/FileLock.ts +136 -0
  106. package/src/internal/Lifecycle.ts +49 -0
  107. package/src/internal/LocalBackend.ts +492 -0
  108. package/src/internal/LocalSidecar.ts +9 -0
  109. package/src/internal/Loopback.ts +34 -0
  110. package/src/internal/PushLock.ts +99 -0
  111. package/src/internal/ResourceIdentity.ts +20 -0
  112. package/src/internal/UserCache.ts +25 -0
  113. package/src/internal/Zip.ts +108 -0
@@ -0,0 +1,224 @@
1
+ import { isOrigin } from "./internal/Loopback.js";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Redacted from "effect/Redacted";
4
+ import * as Schema from "effect/Schema";
5
+ import * as Config from "effect/Config";
6
+ import * as Context from "effect/Context";
7
+ import * as Layer from "effect/Layer";
8
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
9
+ import * as HttpClient from "effect/http/HttpClient";
10
+ import * as HttpClientRequest from "effect/http/HttpClientRequest";
11
+ //#region src/ConvexClient.ts
12
+ const errorFields = {
13
+ operation: Schema.String,
14
+ status: Schema.optionalKey(Schema.Finite),
15
+ code: Schema.Literals([
16
+ "HttpError",
17
+ "TransportError",
18
+ "InvalidResponse",
19
+ "InvalidRequest",
20
+ "InvalidPagination",
21
+ "InvalidConfiguration"
22
+ ])
23
+ };
24
+ var ConvexApiError = class extends Schema.TaggedError()("ConvexApiError", errorFields) {};
25
+ var ConvexNotFound = class extends Schema.TaggedError()("ConvexNotFound", errorFields) {};
26
+ var ConvexConflict = class extends Schema.TaggedError()("ConvexConflict", errorFields) {};
27
+ const ProjectSchema = Schema.Struct({
28
+ id: Schema.Finite,
29
+ name: Schema.String,
30
+ slug: Schema.String,
31
+ teamId: Schema.Finite,
32
+ teamSlug: Schema.String,
33
+ createTime: Schema.Finite,
34
+ prodDeploymentName: Schema.optionalKey(Schema.NullOr(Schema.String)),
35
+ devDeploymentName: Schema.optionalKey(Schema.NullOr(Schema.String))
36
+ });
37
+ const CreatedProjectSchema = Schema.Struct({
38
+ id: Schema.Finite,
39
+ projectId: Schema.Finite,
40
+ slug: Schema.String,
41
+ deploymentName: Schema.optionalKey(Schema.NullOr(Schema.String)),
42
+ deploymentUrl: Schema.optionalKey(Schema.NullOr(Schema.String))
43
+ });
44
+ const deploymentFields = {
45
+ name: Schema.String,
46
+ createTime: Schema.Finite,
47
+ deploymentType: Schema.Literals([
48
+ "dev",
49
+ "prod",
50
+ "preview",
51
+ "custom"
52
+ ]),
53
+ projectId: Schema.Finite,
54
+ previewIdentifier: Schema.optionalKey(Schema.NullOr(Schema.String))
55
+ };
56
+ const DeploymentSchema = Schema.Union([Schema.Struct({
57
+ ...deploymentFields,
58
+ kind: Schema.Literal("cloud"),
59
+ id: Schema.Finite,
60
+ lastDeployTime: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
61
+ creator: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
62
+ region: Schema.Literals([
63
+ "aws-us-east-1",
64
+ "aws-eu-west-1",
65
+ "aws-ap-southeast-2",
66
+ "aws-ca-central-1"
67
+ ]),
68
+ isDefault: Schema.Boolean,
69
+ reference: Schema.String,
70
+ dashboardEditConfirmation: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),
71
+ deploymentUrl: Schema.String,
72
+ expiresAt: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
73
+ class: Schema.String,
74
+ sendLogsToClient: Schema.optionalKey(Schema.NullOr(Schema.Boolean))
75
+ }), Schema.Struct({
76
+ ...deploymentFields,
77
+ kind: Schema.Literal("local"),
78
+ creator: Schema.Finite,
79
+ port: Schema.Finite,
80
+ deviceName: Schema.String,
81
+ isActive: Schema.Boolean
82
+ })]);
83
+ const DeployKeySchema = Schema.Struct({
84
+ id: Schema.Finite,
85
+ name: Schema.String,
86
+ creationTime: Schema.Finite,
87
+ lastUsedTime: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
88
+ expiresAt: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
89
+ creator: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
90
+ managedBy: Schema.optionalKey(Schema.NullOr(Schema.Union([Schema.Literal("vercel"), Schema.Struct({ oauthApp: Schema.String })]))),
91
+ allowedActions: Schema.Array(Schema.String)
92
+ });
93
+ const ProjectsPageSchema = Schema.Struct({
94
+ items: Schema.Array(ProjectSchema),
95
+ pagination: Schema.Struct({
96
+ hasMore: Schema.Boolean,
97
+ nextCursor: Schema.optionalKey(Schema.NullOr(Schema.String))
98
+ })
99
+ });
100
+ const make = Effect.fn("ConvexClient.make")(function* (options) {
101
+ const http = yield* HttpClient.HttpClient;
102
+ const managementAuthorization = Effect.gen(function* () {
103
+ const token = options?.token ?? (yield* Config.Redacted("CONVEX_ACCESS_TOKEN").pipe(Effect.mapError(() => new ConvexApiError({
104
+ operation: "configure",
105
+ code: "InvalidConfiguration"
106
+ }))));
107
+ return Redacted.make(`Bearer ${Redacted.value(token)}`);
108
+ });
109
+ const baseUrl = "https://api.convex.dev/v1";
110
+ const send = Effect.fn("ConvexClient.request")(function* (operation, method, url, authorization, body) {
111
+ let request = HttpClientRequest.make(method)(url).pipe(HttpClientRequest.setHeader("authorization", Redacted.value(authorization)), HttpClientRequest.acceptJson);
112
+ if (body !== void 0) request = yield* HttpClientRequest.bodyJson(request, body).pipe(Effect.mapError(() => new ConvexApiError({
113
+ operation,
114
+ code: "InvalidRequest"
115
+ })));
116
+ const response = yield* http.execute(request).pipe(Effect.provideService(FetchHttpClient.RequestInit, { redirect: "manual" }), Effect.mapError(() => new ConvexApiError({
117
+ operation,
118
+ code: "TransportError"
119
+ })));
120
+ if (response.status === 404) return yield* new ConvexNotFound({
121
+ operation,
122
+ status: 404,
123
+ code: "HttpError"
124
+ });
125
+ if (response.status === 409) return yield* new ConvexConflict({
126
+ operation,
127
+ status: 409,
128
+ code: "HttpError"
129
+ });
130
+ if (response.status < 200 || response.status >= 300) return yield* new ConvexApiError({
131
+ operation,
132
+ status: response.status,
133
+ code: "HttpError"
134
+ });
135
+ return response;
136
+ });
137
+ const decode = Effect.fn("ConvexClient.decode")(function* (operation, response, schema) {
138
+ const invalidResponse = () => new ConvexApiError({
139
+ operation,
140
+ status: response.status,
141
+ code: "InvalidResponse"
142
+ });
143
+ const body = yield* response.json.pipe(Effect.mapError(invalidResponse));
144
+ return yield* Schema.decodeEffect(schema)(body).pipe(Effect.mapError(invalidResponse));
145
+ });
146
+ const management = Effect.fn("ConvexClient.management")(function* (operation, method, path, schema, body) {
147
+ const response = yield* send(operation, method, `${baseUrl}${path}`, yield* managementAuthorization, body);
148
+ return yield* decode(operation, response, schema);
149
+ });
150
+ const managementVoid = Effect.fn("ConvexClient.managementVoid")(function* (operation, method, path, body) {
151
+ yield* send(operation, method, `${baseUrl}${path}`, yield* managementAuthorization, body);
152
+ });
153
+ const deploymentUrl = Effect.fn("ConvexClient.deploymentUrl")(function* (operation, url) {
154
+ const invalidUrl = () => new ConvexApiError({
155
+ operation,
156
+ code: "InvalidRequest"
157
+ });
158
+ if (options?.mode === "local") {
159
+ if (!isOrigin(url)) return yield* invalidUrl();
160
+ return `${url}/api/v1`;
161
+ }
162
+ const parsed = yield* Effect.try({
163
+ try: () => new URL(url),
164
+ catch: invalidUrl
165
+ });
166
+ if (parsed.protocol !== "https:" || parsed.username !== "" || parsed.password !== "" || parsed.port !== "" || parsed.search !== "" || parsed.hash !== "" || parsed.pathname !== "/" || !/^[a-z0-9-]+(?:\.(?:eu-west-1|ap-southeast-2|ca-central-1))?\.convex\.cloud$/.test(parsed.hostname) || url.replace(/\/$/, "") !== parsed.origin) return yield* invalidUrl();
167
+ return `${parsed.origin}/api/v1`;
168
+ });
169
+ return {
170
+ listProjects: Effect.fn("ConvexClient.listProjects")(function* (teamId) {
171
+ const projects = [];
172
+ const seenCursors = /* @__PURE__ */ new Set();
173
+ let cursor;
174
+ while (true) {
175
+ const page = yield* management("listProjects", "GET", `/teams/${teamId}/projects${cursor === void 0 ? "" : `?cursor=${encodeURIComponent(cursor)}`}`, ProjectsPageSchema);
176
+ projects.push(...page.items);
177
+ if (!page.pagination.hasMore) return projects;
178
+ const nextCursor = page.pagination.nextCursor;
179
+ if (!nextCursor || seenCursors.has(nextCursor)) return yield* new ConvexApiError({
180
+ operation: "listProjects",
181
+ code: "InvalidPagination"
182
+ });
183
+ seenCursors.add(nextCursor);
184
+ cursor = nextCursor;
185
+ }
186
+ }),
187
+ getProject: Effect.fn("ConvexClient.getProject")((projectId) => management("getProject", "GET", `/projects/${projectId}`, ProjectSchema)),
188
+ createProject: Effect.fn("ConvexClient.createProject")((teamId, input) => management("createProject", "POST", `/teams/${teamId}/create_project`, CreatedProjectSchema, input)),
189
+ updateProject: Effect.fn("ConvexClient.updateProject")((projectId, input) => management("updateProject", "PATCH", `/projects/${projectId}`, ProjectSchema, input)),
190
+ deleteProject: Effect.fn("ConvexClient.deleteProject")((projectId) => managementVoid("deleteProject", "POST", `/projects/${projectId}/delete`)),
191
+ listDeployments: Effect.fn("ConvexClient.listDeployments")((projectId) => management("listDeployments", "GET", `/projects/${projectId}/list_deployments`, Schema.Array(DeploymentSchema))),
192
+ getDeployment: Effect.fn("ConvexClient.getDeployment")((name) => management("getDeployment", "GET", `/deployments/${encodeURIComponent(name)}`, DeploymentSchema)),
193
+ createDeployment: Effect.fn("ConvexClient.createDeployment")((projectId, input) => management("createDeployment", "POST", `/projects/${projectId}/create_deployment`, DeploymentSchema, input)),
194
+ updateDeployment: Effect.fn("ConvexClient.updateDeployment")((name, input) => managementVoid("updateDeployment", "PATCH", `/deployments/${encodeURIComponent(name)}`, input)),
195
+ deleteDeployment: Effect.fn("ConvexClient.deleteDeployment")((name) => managementVoid("deleteDeployment", "POST", `/deployments/${encodeURIComponent(name)}/delete`)),
196
+ createDeployKey: Effect.fn("ConvexClient.createDeployKey")(function* (name, input) {
197
+ const response = yield* management("createDeployKey", "POST", `/deployments/${encodeURIComponent(name)}/create_deploy_key`, Schema.Struct({ deployKey: Schema.String }), input);
198
+ return { deployKey: Redacted.make(response.deployKey) };
199
+ }),
200
+ listDeployKeys: Effect.fn("ConvexClient.listDeployKeys")((name) => management("listDeployKeys", "GET", `/deployments/${encodeURIComponent(name)}/list_deploy_keys`, Schema.Array(DeployKeySchema))),
201
+ deleteDeployKey: Effect.fn("ConvexClient.deleteDeployKey")((name, id) => managementVoid("deleteDeployKey", "POST", `/deployments/${encodeURIComponent(name)}/delete_deploy_key`, { id: Redacted.isRedacted(id) ? Redacted.value(id) : id })),
202
+ listEnvironmentVariables: Effect.fn("ConvexClient.listEnvironmentVariables")(function* (url, key) {
203
+ const response = yield* send("listEnvironmentVariables", "GET", `${yield* deploymentUrl("listEnvironmentVariables", url)}/list_environment_variables`, Redacted.make(`Convex ${Redacted.value(key)}`));
204
+ const result = yield* decode("listEnvironmentVariables", response, Schema.Struct({ environmentVariables: Schema.Record(Schema.String, Schema.String) }));
205
+ return Object.fromEntries(Object.entries(result.environmentVariables).map(([name, value]) => [name, Redacted.make(value)]));
206
+ }),
207
+ updateEnvironmentVariables: Effect.fn("ConvexClient.updateEnvironmentVariables")(function* (url, key, changes) {
208
+ yield* send("updateEnvironmentVariables", "POST", `${yield* deploymentUrl("updateEnvironmentVariables", url)}/update_environment_variables`, Redacted.make(`Convex ${Redacted.value(key)}`), { changes: changes.map(({ name, value }) => ({
209
+ name,
210
+ ...value === void 0 ? {} : { value: Redacted.isRedacted(value) ? Redacted.value(value) : value }
211
+ })) });
212
+ })
213
+ };
214
+ });
215
+ var ConvexClient = class extends Context.Service()("@confect/alchemy/ConvexClient") {};
216
+ /**
217
+ * `mode: "local"` sends deployment requests only to a loopback backend over
218
+ * HTTP; the default accepts only Convex cloud HTTPS origins.
219
+ */
220
+ const layer = (options) => Layer.effect(ConvexClient, make(options).pipe(Effect.map(ConvexClient.of)));
221
+ //#endregion
222
+ export { ConvexApiError, ConvexClient, ConvexConflict, ConvexNotFound, layer };
223
+
224
+ //# sourceMappingURL=ConvexClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConvexClient.js","names":["Loopback.isOrigin"],"sources":["../src/ConvexClient.ts"],"sourcesContent":["import type * as DeploymentApi from \"@convex-dev/platform/deploymentApi\";\nimport type * as ManagementApi from \"@convex-dev/platform/managementApi\";\nimport type { ProviderMode } from \"alchemy/ProviderMode\";\nimport * as Config from \"effect/Config\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Redacted from \"effect/Redacted\";\nimport * as Schema from \"effect/Schema\";\nimport * as FetchHttpClient from \"effect/http/FetchHttpClient\";\nimport * as HttpClient from \"effect/http/HttpClient\";\nimport * as HttpClientRequest from \"effect/http/HttpClientRequest\";\nimport type * as HttpClientResponse from \"effect/http/HttpClientResponse\";\nimport * as Loopback from \"./internal/Loopback\";\n\nexport type Project = ManagementApi.ProjectResponse;\nexport type CreatedProject = ManagementApi.PlatformCreateProjectResponse;\nexport type Deployment = ManagementApi.PlatformDeploymentResponse;\nexport type DeployKey = Omit<\n ManagementApi.PlatformDeployKeyResponse,\n \"allowedActions\"\n> & {\n readonly allowedActions: readonly string[];\n};\nexport type CreateProjectInput = Pick<\n ManagementApi.PlatformCreateProjectArgs,\n \"projectName\"\n>;\nexport type UpdateProjectInput = Pick<\n ManagementApi.PlatformUpdateProjectArgs,\n \"name\"\n>;\nexport type CreateDeploymentInput = Pick<\n ManagementApi.PlatformCreateDeploymentArgs,\n \"type\" | \"region\" | \"class\"\n> & { readonly reference: string };\nexport type UpdateDeploymentInput = Pick<\n ManagementApi.PlatformUpdateDeploymentArgs,\n \"reference\" | \"expiresAt\" | \"sendLogsToClient\"\n>;\nexport type CreateDeployKeyInput = ManagementApi.PlatformCreateDeployKeyArgs;\nexport type CreatedDeployKey = {\n readonly deployKey: Redacted.Redacted<\n ManagementApi.PlatformCreateDeployKeyResponse[\"deployKey\"]\n >;\n};\nexport type EnvironmentVariableChange = Omit<\n DeploymentApi.UpdateEnvVarRequest,\n \"value\"\n> & {\n readonly value?:\n | Exclude<DeploymentApi.UpdateEnvVarRequest[\"value\"], undefined>\n | Redacted.Redacted<string>;\n};\nexport type EnvironmentVariables = Readonly<\n Record<\n string,\n Redacted.Redacted<\n DeploymentApi.ListEnvVarsResponse[\"environmentVariables\"][string]\n >\n >\n>;\n\nconst errorFields = {\n operation: Schema.String,\n status: Schema.optionalKey(Schema.Finite),\n code: Schema.Literals([\n \"HttpError\",\n \"TransportError\",\n \"InvalidResponse\",\n \"InvalidRequest\",\n \"InvalidPagination\",\n \"InvalidConfiguration\",\n ]),\n};\n\nexport class ConvexApiError extends Schema.TaggedError<ConvexApiError>()(\n \"ConvexApiError\",\n errorFields,\n) {}\n\nexport class ConvexNotFound extends Schema.TaggedError<ConvexNotFound>()(\n \"ConvexNotFound\",\n errorFields,\n) {}\n\nexport class ConvexConflict extends Schema.TaggedError<ConvexConflict>()(\n \"ConvexConflict\",\n errorFields,\n) {}\n\nexport type ConvexClientError =\n | ConvexApiError\n | ConvexNotFound\n | ConvexConflict;\n\nconst ProjectSchema = Schema.Struct({\n id: Schema.Finite,\n name: Schema.String,\n slug: Schema.String,\n teamId: Schema.Finite,\n teamSlug: Schema.String,\n createTime: Schema.Finite,\n prodDeploymentName: Schema.optionalKey(Schema.NullOr(Schema.String)),\n devDeploymentName: Schema.optionalKey(Schema.NullOr(Schema.String)),\n}) satisfies Schema.Schema<Project>;\n\nconst CreatedProjectSchema = Schema.Struct({\n id: Schema.Finite,\n projectId: Schema.Finite,\n slug: Schema.String,\n deploymentName: Schema.optionalKey(Schema.NullOr(Schema.String)),\n deploymentUrl: Schema.optionalKey(Schema.NullOr(Schema.String)),\n}) satisfies Schema.Schema<CreatedProject>;\n\nconst deploymentFields = {\n name: Schema.String,\n createTime: Schema.Finite,\n deploymentType: Schema.Literals([\"dev\", \"prod\", \"preview\", \"custom\"]),\n projectId: Schema.Finite,\n previewIdentifier: Schema.optionalKey(Schema.NullOr(Schema.String)),\n};\n\nconst DeploymentSchema = Schema.Union([\n Schema.Struct({\n ...deploymentFields,\n kind: Schema.Literal(\"cloud\"),\n id: Schema.Finite,\n lastDeployTime: Schema.optionalKey(Schema.NullOr(Schema.Finite)),\n creator: Schema.optionalKey(Schema.NullOr(Schema.Finite)),\n region: Schema.Literals([\n \"aws-us-east-1\",\n \"aws-eu-west-1\",\n \"aws-ap-southeast-2\",\n \"aws-ca-central-1\",\n ]),\n isDefault: Schema.Boolean,\n reference: Schema.String,\n dashboardEditConfirmation: Schema.optionalKey(\n Schema.NullOr(Schema.Boolean),\n ),\n deploymentUrl: Schema.String,\n expiresAt: Schema.optionalKey(Schema.NullOr(Schema.Finite)),\n class: Schema.String,\n sendLogsToClient: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),\n }),\n Schema.Struct({\n ...deploymentFields,\n kind: Schema.Literal(\"local\"),\n creator: Schema.Finite,\n port: Schema.Finite,\n deviceName: Schema.String,\n isActive: Schema.Boolean,\n }),\n]) satisfies Schema.Schema<Deployment>;\n\nconst DeployKeySchema = Schema.Struct({\n id: Schema.Finite,\n name: Schema.String,\n creationTime: Schema.Finite,\n lastUsedTime: Schema.optionalKey(Schema.NullOr(Schema.Finite)),\n expiresAt: Schema.optionalKey(Schema.NullOr(Schema.Finite)),\n creator: Schema.optionalKey(Schema.NullOr(Schema.Finite)),\n managedBy: Schema.optionalKey(\n Schema.NullOr(\n Schema.Union([\n Schema.Literal(\"vercel\"),\n Schema.Struct({ oauthApp: Schema.String }),\n ]),\n ),\n ),\n allowedActions: Schema.Array(Schema.String),\n}) satisfies Schema.Schema<DeployKey>;\n\nconst ProjectsPageSchema = Schema.Struct({\n items: Schema.Array(ProjectSchema),\n pagination: Schema.Struct({\n hasMore: Schema.Boolean,\n nextCursor: Schema.optionalKey(Schema.NullOr(Schema.String)),\n }),\n});\n\nconst make = Effect.fn(\"ConvexClient.make\")(function* (options?: {\n readonly token?: Redacted.Redacted<string>;\n readonly mode?: ProviderMode;\n}) {\n const http = yield* HttpClient.HttpClient;\n const managementAuthorization = Effect.gen(function* () {\n const token =\n options?.token ??\n (yield* Config.Redacted(\"CONVEX_ACCESS_TOKEN\").pipe(\n Effect.mapError(\n () =>\n new ConvexApiError({\n operation: \"configure\",\n code: \"InvalidConfiguration\",\n }),\n ),\n ));\n return Redacted.make(`Bearer ${Redacted.value(token)}`);\n });\n const baseUrl = \"https://api.convex.dev/v1\";\n\n const send = Effect.fn(\"ConvexClient.request\")(function* (\n operation: string,\n method: \"GET\" | \"POST\" | \"PATCH\",\n url: string,\n authorization: Redacted.Redacted<string>,\n body?: unknown,\n ) {\n let request = HttpClientRequest.make(method)(url).pipe(\n HttpClientRequest.setHeader(\n \"authorization\",\n Redacted.value(authorization),\n ),\n HttpClientRequest.acceptJson,\n );\n if (body !== undefined) {\n request = yield* HttpClientRequest.bodyJson(request, body).pipe(\n Effect.mapError(\n () => new ConvexApiError({ operation, code: \"InvalidRequest\" }),\n ),\n );\n }\n const response = yield* http.execute(request).pipe(\n Effect.provideService(FetchHttpClient.RequestInit, {\n redirect: \"manual\",\n }),\n Effect.mapError(\n () => new ConvexApiError({ operation, code: \"TransportError\" }),\n ),\n );\n if (response.status === 404) {\n return yield* new ConvexNotFound({\n operation,\n status: 404,\n code: \"HttpError\",\n });\n }\n if (response.status === 409) {\n return yield* new ConvexConflict({\n operation,\n status: 409,\n code: \"HttpError\",\n });\n }\n if (response.status < 200 || response.status >= 300) {\n return yield* new ConvexApiError({\n operation,\n status: response.status,\n code: \"HttpError\",\n });\n }\n return response;\n });\n\n const decode = Effect.fn(\"ConvexClient.decode\")(function* <A>(\n operation: string,\n response: HttpClientResponse.HttpClientResponse,\n schema: Schema.Decoder<A>,\n ) {\n const invalidResponse = () =>\n new ConvexApiError({\n operation,\n status: response.status,\n code: \"InvalidResponse\",\n });\n const body = yield* response.json.pipe(Effect.mapError(invalidResponse));\n return yield* Schema.decodeEffect(schema)(body).pipe(\n Effect.mapError(invalidResponse),\n );\n });\n\n const management = Effect.fn(\"ConvexClient.management\")(function* <A>(\n operation: string,\n method: \"GET\" | \"POST\" | \"PATCH\",\n path: string,\n schema: Schema.Decoder<A>,\n body?: unknown,\n ) {\n const response = yield* send(\n operation,\n method,\n `${baseUrl}${path}`,\n yield* managementAuthorization,\n body,\n );\n return yield* decode(operation, response, schema);\n });\n\n const managementVoid = Effect.fn(\"ConvexClient.managementVoid\")(function* (\n operation: string,\n method: \"POST\" | \"PATCH\",\n path: string,\n body?: unknown,\n ) {\n yield* send(\n operation,\n method,\n `${baseUrl}${path}`,\n yield* managementAuthorization,\n body,\n );\n });\n\n const deploymentUrl = Effect.fn(\"ConvexClient.deploymentUrl\")(function* (\n operation: string,\n url: string,\n ) {\n const invalidUrl = () =>\n new ConvexApiError({ operation, code: \"InvalidRequest\" });\n if (options?.mode === \"local\") {\n if (!Loopback.isOrigin(url)) return yield* invalidUrl();\n return `${url}/api/v1`;\n }\n const parsed = yield* Effect.try({\n try: () => new URL(url),\n catch: invalidUrl,\n });\n if (\n parsed.protocol !== \"https:\" ||\n parsed.username !== \"\" ||\n parsed.password !== \"\" ||\n parsed.port !== \"\" ||\n parsed.search !== \"\" ||\n parsed.hash !== \"\" ||\n parsed.pathname !== \"/\" ||\n !/^[a-z0-9-]+(?:\\.(?:eu-west-1|ap-southeast-2|ca-central-1))?\\.convex\\.cloud$/.test(\n parsed.hostname,\n ) ||\n url.replace(/\\/$/, \"\") !== parsed.origin\n ) {\n return yield* invalidUrl();\n }\n return `${parsed.origin}/api/v1`;\n });\n\n return {\n listProjects: Effect.fn(\"ConvexClient.listProjects\")(function* (\n teamId: number,\n ) {\n const projects: Project[] = [];\n const seenCursors = new Set<string>();\n let cursor: string | undefined;\n while (true) {\n const page = yield* management(\n \"listProjects\",\n \"GET\",\n `/teams/${teamId}/projects${cursor === undefined ? \"\" : `?cursor=${encodeURIComponent(cursor)}`}`,\n ProjectsPageSchema,\n );\n projects.push(...page.items);\n if (!page.pagination.hasMore) return projects;\n const nextCursor = page.pagination.nextCursor;\n if (!nextCursor || seenCursors.has(nextCursor)) {\n return yield* new ConvexApiError({\n operation: \"listProjects\",\n code: \"InvalidPagination\",\n });\n }\n seenCursors.add(nextCursor);\n cursor = nextCursor;\n }\n }),\n getProject: Effect.fn(\"ConvexClient.getProject\")((projectId: number) =>\n management(\"getProject\", \"GET\", `/projects/${projectId}`, ProjectSchema),\n ),\n createProject: Effect.fn(\"ConvexClient.createProject\")(\n (teamId: number, input: CreateProjectInput) =>\n management(\n \"createProject\",\n \"POST\",\n `/teams/${teamId}/create_project`,\n CreatedProjectSchema,\n input,\n ),\n ),\n updateProject: Effect.fn(\"ConvexClient.updateProject\")(\n (projectId: number, input: UpdateProjectInput) =>\n management(\n \"updateProject\",\n \"PATCH\",\n `/projects/${projectId}`,\n ProjectSchema,\n input,\n ),\n ),\n deleteProject: Effect.fn(\"ConvexClient.deleteProject\")(\n (projectId: number) =>\n managementVoid(\n \"deleteProject\",\n \"POST\",\n `/projects/${projectId}/delete`,\n ),\n ),\n listDeployments: Effect.fn(\"ConvexClient.listDeployments\")(\n (projectId: number) =>\n management(\n \"listDeployments\",\n \"GET\",\n `/projects/${projectId}/list_deployments`,\n Schema.Array(DeploymentSchema),\n ),\n ),\n getDeployment: Effect.fn(\"ConvexClient.getDeployment\")((name: string) =>\n management(\n \"getDeployment\",\n \"GET\",\n `/deployments/${encodeURIComponent(name)}`,\n DeploymentSchema,\n ),\n ),\n createDeployment: Effect.fn(\"ConvexClient.createDeployment\")(\n (projectId: number, input: CreateDeploymentInput) =>\n management(\n \"createDeployment\",\n \"POST\",\n `/projects/${projectId}/create_deployment`,\n DeploymentSchema,\n input,\n ),\n ),\n updateDeployment: Effect.fn(\"ConvexClient.updateDeployment\")(\n (name: string, input: UpdateDeploymentInput) =>\n managementVoid(\n \"updateDeployment\",\n \"PATCH\",\n `/deployments/${encodeURIComponent(name)}`,\n input,\n ),\n ),\n deleteDeployment: Effect.fn(\"ConvexClient.deleteDeployment\")(\n (name: string) =>\n managementVoid(\n \"deleteDeployment\",\n \"POST\",\n `/deployments/${encodeURIComponent(name)}/delete`,\n ),\n ),\n createDeployKey: Effect.fn(\"ConvexClient.createDeployKey\")(function* (\n name: string,\n input: CreateDeployKeyInput,\n ): Effect.fn.Return<CreatedDeployKey, ConvexClientError> {\n const response = yield* management(\n \"createDeployKey\",\n \"POST\",\n `/deployments/${encodeURIComponent(name)}/create_deploy_key`,\n Schema.Struct({ deployKey: Schema.String }),\n input,\n );\n return { deployKey: Redacted.make(response.deployKey) };\n }),\n listDeployKeys: Effect.fn(\"ConvexClient.listDeployKeys\")((name: string) =>\n management(\n \"listDeployKeys\",\n \"GET\",\n `/deployments/${encodeURIComponent(name)}/list_deploy_keys`,\n Schema.Array(DeployKeySchema),\n ),\n ),\n deleteDeployKey: Effect.fn(\"ConvexClient.deleteDeployKey\")(\n (name: string, id: string | Redacted.Redacted<string>) =>\n managementVoid(\n \"deleteDeployKey\",\n \"POST\",\n `/deployments/${encodeURIComponent(name)}/delete_deploy_key`,\n {\n id: Redacted.isRedacted(id) ? Redacted.value(id) : id,\n } satisfies ManagementApi.PlatformDeleteDeployKeyArgs,\n ),\n ),\n listEnvironmentVariables: Effect.fn(\n \"ConvexClient.listEnvironmentVariables\",\n )(function* (\n url: string,\n key: Redacted.Redacted<string>,\n ): Effect.fn.Return<EnvironmentVariables, ConvexClientError> {\n const response = yield* send(\n \"listEnvironmentVariables\",\n \"GET\",\n `${yield* deploymentUrl(\"listEnvironmentVariables\", url)}/list_environment_variables`,\n Redacted.make(`Convex ${Redacted.value(key)}`),\n );\n const result = yield* decode(\n \"listEnvironmentVariables\",\n response,\n Schema.Struct({\n environmentVariables: Schema.Record(Schema.String, Schema.String),\n }),\n );\n return Object.fromEntries(\n Object.entries(result.environmentVariables).map(([name, value]) => [\n name,\n Redacted.make(value),\n ]),\n );\n }),\n updateEnvironmentVariables: Effect.fn(\n \"ConvexClient.updateEnvironmentVariables\",\n )(function* (\n url: string,\n key: Redacted.Redacted<string>,\n changes: readonly EnvironmentVariableChange[],\n ) {\n yield* send(\n \"updateEnvironmentVariables\",\n \"POST\",\n `${yield* deploymentUrl(\"updateEnvironmentVariables\", url)}/update_environment_variables`,\n Redacted.make(`Convex ${Redacted.value(key)}`),\n {\n changes: changes.map(({ name, value }) => ({\n name,\n ...(value === undefined\n ? {}\n : {\n value: Redacted.isRedacted(value)\n ? Redacted.value(value)\n : value,\n }),\n })),\n } satisfies {\n readonly changes: Readonly<\n DeploymentApi.UpdateEnvVarsRequest[\"changes\"]\n >;\n },\n );\n }),\n };\n});\n\nexport class ConvexClient extends Context.Service<\n ConvexClient,\n Effect.Success<ReturnType<typeof make>>\n>()(\"@confect/alchemy/ConvexClient\") {}\n\n/**\n * `mode: \"local\"` sends deployment requests only to a loopback backend over\n * HTTP; the default accepts only Convex cloud HTTPS origins.\n */\nexport const layer = (options?: {\n readonly token?: Redacted.Redacted<string>;\n readonly mode?: ProviderMode;\n}) =>\n Layer.effect(ConvexClient, make(options).pipe(Effect.map(ConvexClient.of)));\n"],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ import type { PlatformCreateDeployKeyArgs } from "@convex-dev/platform/managementApi";
2
+ import * as Provider from "alchemy/Provider";
3
+ import { Resource } from "alchemy/Resource";
4
+ import * as Effect from "effect/Effect";
5
+ import * as FileSystem from "effect/FileSystem";
6
+ import * as Path from "effect/Path";
7
+ import * as Redacted from "effect/Redacted";
8
+ import * as Schema from "effect/Schema";
9
+ import { ConvexClient } from "./ConvexClient";
10
+ import type { Providers } from "./Providers";
11
+ export interface DeployKeyProps {
12
+ readonly deploymentName: string;
13
+ readonly name?: string;
14
+ readonly allowedActions?: ReadonlyArray<NonNullable<PlatformCreateDeployKeyArgs["allowedActions"]>[number]>;
15
+ }
16
+ export interface DeployKeyAttributes {
17
+ readonly deploymentName: string;
18
+ readonly keyId: number;
19
+ readonly name: string;
20
+ readonly deployKey: Redacted.Redacted<string>;
21
+ readonly allowedActions: ReadonlyArray<string>;
22
+ }
23
+ export type DeployKey = Resource<"Convex.DeployKey", DeployKeyProps, DeployKeyAttributes, never, Providers>;
24
+ export declare const DeployKey: import("alchemy/Resource").ResourceClass<DeployKey>;
25
+ declare const DeployKeyRecoveryRequired_base: Schema.Class<DeployKeyRecoveryRequired, Schema.TaggedStruct<"DeployKeyRecoveryRequired", {
26
+ readonly deploymentName: Schema.String;
27
+ readonly name: Schema.String;
28
+ readonly keyIds: Schema.$Array<Schema.Finite>;
29
+ }>, import("effect/Cause").YieldableError>;
30
+ export declare class DeployKeyRecoveryRequired extends DeployKeyRecoveryRequired_base {
31
+ }
32
+ declare const DeployKeyChangeRequiresNewResource_base: Schema.Class<DeployKeyChangeRequiresNewResource, Schema.TaggedStruct<"DeployKeyChangeRequiresNewResource", {
33
+ readonly deploymentName: Schema.String;
34
+ readonly keyId: Schema.Finite;
35
+ readonly field: Schema.String;
36
+ }>, import("effect/Cause").YieldableError>;
37
+ export declare class DeployKeyChangeRequiresNewResource extends DeployKeyChangeRequiresNewResource_base {
38
+ }
39
+ export declare const provider: Effect.Effect<{
40
+ diff: (args_0: {
41
+ id: string;
42
+ fqn: string;
43
+ instanceId: string;
44
+ olds: DeployKeyProps;
45
+ news: import("alchemy/Input").Input<DeployKeyProps>;
46
+ oldBindings: import("alchemy/Resource").ResourceBinding<never>[];
47
+ newBindings: import("alchemy/Input").Input<import("alchemy/Resource").ResourceBinding<never>[]>;
48
+ output: DeployKeyAttributes | undefined;
49
+ }) => Effect.Effect<undefined, import("./ConvexClient").ConvexApiError | import("./ConvexClient").ConvexConflict | import("./ConvexClient").ConvexNotFound | DeployKeyChangeRequiresNewResource | DeployKeyRecoveryRequired, never>;
50
+ read: (args_0: {
51
+ id: string;
52
+ fqn: string;
53
+ instanceId: string;
54
+ olds: DeployKeyProps;
55
+ output: DeployKeyAttributes | undefined;
56
+ }) => Effect.Effect<{
57
+ deploymentName: string;
58
+ keyId: number;
59
+ name: string;
60
+ deployKey: Redacted.Redacted<string>;
61
+ allowedActions: readonly string[];
62
+ } | undefined, import("./ConvexClient").ConvexApiError | import("./ConvexClient").ConvexConflict | import("./ConvexClient").ConvexNotFound | DeployKeyRecoveryRequired, never>;
63
+ reconcile: (args_0: {
64
+ id: string;
65
+ fqn: string;
66
+ instanceId: string;
67
+ news: DeployKeyProps;
68
+ olds: DeployKeyProps | undefined;
69
+ output: DeployKeyAttributes | undefined;
70
+ session: import("alchemy/Report").ScopedPlanStatusSession;
71
+ bindings: import("alchemy/Resource").ResourceBinding<never>[];
72
+ }) => Effect.Effect<{
73
+ deploymentName: string;
74
+ keyId: number;
75
+ name: string;
76
+ deployKey: Redacted.Redacted<string>;
77
+ allowedActions: readonly string[];
78
+ }, DeployKeyChangeRequiresNewResource | DeployKeyRecoveryRequired | import("./internal/Lifecycle").LifecycleStateError | import("alchemy/State/State").StateStoreError | import("./ConvexClient").ConvexClientError, never>;
79
+ delete: (args_0: {
80
+ id: string;
81
+ fqn: string;
82
+ instanceId: string;
83
+ olds: DeployKeyProps;
84
+ output: DeployKeyAttributes;
85
+ session: import("alchemy/Report").ScopedPlanStatusSession;
86
+ bindings: import("alchemy/Resource").ResourceBinding<never>[];
87
+ force?: boolean;
88
+ }) => Effect.Effect<void, import("./ConvexClient").ConvexApiError | import("./ConvexClient").ConvexConflict, never>;
89
+ }, never, ConvexClient>;
90
+ /**
91
+ * Under `alchemy dev` the deploy key is the admin key the local deployment
92
+ * generated. It is read on every apply, so a recreated backend's new key
93
+ * replaces the old one.
94
+ */
95
+ export declare const localProvider: Effect.Effect<{
96
+ diff: () => Effect.Effect<{
97
+ action: "update";
98
+ }, never, never>;
99
+ reconcile: (args_0: {
100
+ id: string;
101
+ fqn: string;
102
+ instanceId: string;
103
+ news: DeployKeyProps;
104
+ olds: DeployKeyProps | undefined;
105
+ output: DeployKeyAttributes | undefined;
106
+ session: import("alchemy/Report").ScopedPlanStatusSession;
107
+ bindings: import("alchemy/Resource").ResourceBinding<never>[];
108
+ }) => Effect.Effect<{
109
+ deploymentName: string;
110
+ keyId: number;
111
+ name: string;
112
+ deployKey: Redacted.Redacted<string>;
113
+ allowedActions: readonly ("deployment:aiGateway:use" | "deployment:auditLog:view" | "deployment:backups:create" | "deployment:backups:delete" | "deployment:backups:download" | "deployment:backups:import" | "deployment:backups:view" | "deployment:data:view" | "deployment:data:write" | "deployment:deploy" | "deployment:env:view" | "deployment:env:write" | "deployment:functions:actAsUser" | "deployment:functions:runInternalActions" | "deployment:functions:runInternalMutations" | "deployment:functions:runInternalQueries" | "deployment:functions:runTestQuery" | "deployment:integrations:view" | "deployment:integrations:write" | "deployment:logs:view" | "deployment:metrics:view" | "deployment:pause" | "deployment:unpause" | "deployment:usage:view" | "deployment:usageLimits:view" | "deployment:usageLimits:write")[];
114
+ }, import("./internal/LocalBackend").LocalBackendError, never>;
115
+ delete: () => Effect.Effect<void, never, never>;
116
+ }, never, FileSystem.FileSystem | Path.Path | import("alchemy/Stack").Stack>;
117
+ export declare const layer: import("effect/Layer").Layer<Provider.Provider<DeployKey>, never, ConvexClient>;
118
+ export declare const localLayer: import("effect/Layer").Layer<Provider.Provider<DeployKey>, never, FileSystem.FileSystem | Path.Path | import("alchemy/Stack").Stack>;
119
+ export {};
120
+ //# sourceMappingURL=DeployKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeployKey.d.ts","sourceRoot":"","sources":["../src/DeployKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AAEtF,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAK7C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CACrC,WAAW,CAAC,2BAA2B,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CACnE,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9C,QAAQ,CAAC,cAAc,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChD;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,CAC9B,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,SAAS,CACV,CAAC;AACF,eAAO,MAAM,SAAS,qDAA0C,CAAC;;;;;;AAEjE,qBAAa,yBAA0B,SAAQ,8BAO9C;CAAG;;;;;;AAEJ,qBAAa,kCAAmC,SAAQ,uCAGvD;CAAG;AAEJ,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;wBA9BM,MAAM;eACf,MAAM;cACP,MAAM;mBACD,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;;;;;;;;;;;;;wBAHpB,MAAM;eACf,MAAM;cACP,MAAM;mBACD,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;;;;;;;;;;;;;uBA4L7C,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;4EA6BxB,CAAC;AAEH,eAAO,MAAM,KAAK,iFAAuC,CAAC;AAC1D,eAAO,MAAM,UAAU,sIAA4C,CAAC"}
@@ -0,0 +1,151 @@
1
+ import { ConvexClient } from "./ConvexClient.js";
2
+ import { checkpointCreate } from "./internal/Lifecycle.js";
3
+ import { resourceName } from "./internal/ResourceIdentity.js";
4
+ import { adminKey, dataDirectories } 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 Redacted from "effect/Redacted";
9
+ import * as Schema from "effect/Schema";
10
+ import * as FileSystem from "effect/FileSystem";
11
+ import * as Path from "effect/Path";
12
+ import { isResolved } from "alchemy/Diff";
13
+ //#region src/DeployKey.ts
14
+ const DeployKey = Resource("Convex.DeployKey");
15
+ var DeployKeyRecoveryRequired = class extends Schema.TaggedError()("DeployKeyRecoveryRequired", {
16
+ deploymentName: Schema.String,
17
+ name: Schema.String,
18
+ keyIds: Schema.Array(Schema.Finite)
19
+ }) {};
20
+ var DeployKeyChangeRequiresNewResource = class extends Schema.TaggedError()("DeployKeyChangeRequiresNewResource", {
21
+ deploymentName: Schema.String,
22
+ keyId: Schema.Finite,
23
+ field: Schema.String
24
+ }) {};
25
+ const provider = Effect.gen(function* () {
26
+ const client = yield* ConvexClient;
27
+ const hasName = (keyName, name) => keyName === name || keyName.startsWith(`${name} (`) && /^[0-9a-f]{8}\)$/.test(keyName.slice(name.length + 2));
28
+ const recover = (deploymentName, name, keyIds) => new DeployKeyRecoveryRequired({
29
+ deploymentName,
30
+ name,
31
+ keyIds
32
+ });
33
+ return {
34
+ diff: Effect.fn("DeployKey.diff")(function* ({ news, output }) {
35
+ if (!isResolved(news) || !output) return;
36
+ for (const field of ["deploymentName", "name"]) if (news[field] !== void 0 && news[field] !== output[field]) return yield* new DeployKeyChangeRequiresNewResource({
37
+ deploymentName: output.deploymentName,
38
+ keyId: output.keyId,
39
+ field
40
+ });
41
+ const key = (yield* client.listDeployKeys(output.deploymentName)).find((candidate) => candidate.id === output.keyId);
42
+ if (!key || !Redacted.isRedacted(output.deployKey)) return yield* recover(output.deploymentName, output.name, [output.keyId]);
43
+ if (!hasName(key.name, news.name ?? output.name)) return yield* new DeployKeyChangeRequiresNewResource({
44
+ deploymentName: output.deploymentName,
45
+ keyId: output.keyId,
46
+ field: "name"
47
+ });
48
+ const allowedActions = news.allowedActions ?? output.allowedActions;
49
+ if (new Set(allowedActions).size !== new Set(key.allowedActions).size || allowedActions.some((action) => !key.allowedActions.includes(action))) return yield* new DeployKeyChangeRequiresNewResource({
50
+ deploymentName: output.deploymentName,
51
+ keyId: output.keyId,
52
+ field: "allowedActions"
53
+ });
54
+ }),
55
+ read: Effect.fn("DeployKey.read")(function* ({ fqn, instanceId, olds, output }) {
56
+ const deploymentName = output?.deploymentName ?? olds.deploymentName;
57
+ if (deploymentName === void 0) return;
58
+ const name = output?.name ?? olds.name ?? (yield* resourceName("key", fqn, instanceId));
59
+ const keys = yield* client.listDeployKeys(deploymentName);
60
+ if (output) {
61
+ const key = keys.find((candidate) => candidate.id === output.keyId);
62
+ if (!key) return yield* recover(deploymentName, name, [output.keyId]);
63
+ if (!Redacted.isRedacted(output.deployKey)) return yield* recover(deploymentName, name, [key.id]);
64
+ return {
65
+ ...output,
66
+ allowedActions: key.allowedActions
67
+ };
68
+ }
69
+ const matches = keys.filter((key) => hasName(key.name, name));
70
+ if (matches.length > 0) return yield* recover(deploymentName, name, matches.map((candidate) => candidate.id));
71
+ }),
72
+ reconcile: Effect.fn("DeployKey.reconcile")(function* ({ fqn, instanceId, news, output }) {
73
+ if (!output) yield* checkpointCreate(fqn, instanceId, news);
74
+ const name = news.name ?? output?.name ?? (yield* resourceName("key", fqn, instanceId));
75
+ if (output) {
76
+ for (const field of ["deploymentName", "name"]) if (news[field] !== void 0 && news[field] !== output[field]) return yield* new DeployKeyChangeRequiresNewResource({
77
+ deploymentName: output.deploymentName,
78
+ keyId: output.keyId,
79
+ field
80
+ });
81
+ const key = (yield* client.listDeployKeys(output.deploymentName)).find((candidate) => candidate.id === output.keyId);
82
+ if (!key || !Redacted.isRedacted(output.deployKey)) return yield* recover(output.deploymentName, name, [output.keyId]);
83
+ if (!hasName(key.name, name)) return yield* new DeployKeyChangeRequiresNewResource({
84
+ deploymentName: output.deploymentName,
85
+ keyId: output.keyId,
86
+ field: "name"
87
+ });
88
+ const allowedActions = news.allowedActions ?? output.allowedActions;
89
+ if (new Set(allowedActions).size !== new Set(key.allowedActions).size || allowedActions.some((action) => !key.allowedActions.includes(action))) return yield* new DeployKeyChangeRequiresNewResource({
90
+ deploymentName: output.deploymentName,
91
+ keyId: output.keyId,
92
+ field: "allowedActions"
93
+ });
94
+ return {
95
+ ...output,
96
+ allowedActions: key.allowedActions
97
+ };
98
+ }
99
+ const existing = (yield* client.listDeployKeys(news.deploymentName)).filter((key) => hasName(key.name, name));
100
+ if (existing.length > 0) return yield* recover(news.deploymentName, name, existing.map((key) => key.id));
101
+ const created = yield* client.createDeployKey(news.deploymentName, {
102
+ name,
103
+ ...news.allowedActions === void 0 ? {} : { allowedActions: [...news.allowedActions] }
104
+ });
105
+ const matches = (yield* client.listDeployKeys(news.deploymentName)).filter((key) => hasName(key.name, name));
106
+ const key = matches[0];
107
+ if (matches.length !== 1 || !key) return yield* recover(news.deploymentName, name, matches.map((candidate) => candidate.id));
108
+ return {
109
+ deploymentName: news.deploymentName,
110
+ keyId: key.id,
111
+ name,
112
+ deployKey: created.deployKey,
113
+ allowedActions: key.allowedActions
114
+ };
115
+ }),
116
+ delete: Effect.fn("DeployKey.delete")(function* ({ output }) {
117
+ yield* client.deleteDeployKey(output.deploymentName, output.deployKey).pipe(Effect.catchTag("ConvexNotFound", () => Effect.void));
118
+ })
119
+ };
120
+ });
121
+ /**
122
+ * Under `alchemy dev` the deploy key is the admin key the local deployment
123
+ * generated. It is read on every apply, so a recreated backend's new key
124
+ * replaces the old one.
125
+ */
126
+ const localProvider = Effect.gen(function* () {
127
+ const fs = yield* FileSystem.FileSystem;
128
+ const path = yield* Path.Path;
129
+ const directory = yield* dataDirectories;
130
+ return {
131
+ diff: () => Effect.succeed({ action: "update" }),
132
+ reconcile: Effect.fn("DeployKey.localReconcile")(function* ({ fqn, instanceId, news }) {
133
+ const name = news.name ?? (yield* resourceName("key", fqn, instanceId));
134
+ const deployKey = yield* adminKey(news.deploymentName, directory(news.deploymentName)).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path));
135
+ return {
136
+ deploymentName: news.deploymentName,
137
+ keyId: 0,
138
+ name,
139
+ deployKey,
140
+ allowedActions: news.allowedActions ?? []
141
+ };
142
+ }),
143
+ delete: () => Effect.void
144
+ };
145
+ });
146
+ const layer = Provider.effect(DeployKey, provider);
147
+ const localLayer = Provider.effect(DeployKey, localProvider);
148
+ //#endregion
149
+ export { DeployKey, DeployKeyChangeRequiresNewResource, DeployKeyRecoveryRequired, layer, localLayer, localProvider, provider };
150
+
151
+ //# sourceMappingURL=DeployKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeployKey.js","names":[],"sources":["../src/DeployKey.ts"],"sourcesContent":["import type { PlatformCreateDeployKeyArgs } from \"@convex-dev/platform/managementApi\";\nimport { isResolved } from \"alchemy/Diff\";\nimport * as Provider from \"alchemy/Provider\";\nimport { Resource } from \"alchemy/Resource\";\nimport * as Effect from \"effect/Effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport * as Redacted from \"effect/Redacted\";\nimport * as Schema from \"effect/Schema\";\n\nimport { ConvexClient } from \"./ConvexClient\";\nimport type { Providers } from \"./Providers\";\nimport { resourceName } from \"./internal/ResourceIdentity\";\nimport { checkpointCreate } from \"./internal/Lifecycle\";\nimport { adminKey, dataDirectories } from \"./internal/LocalBackend\";\n\nexport interface DeployKeyProps {\n readonly deploymentName: string;\n readonly name?: string;\n readonly allowedActions?: ReadonlyArray<\n NonNullable<PlatformCreateDeployKeyArgs[\"allowedActions\"]>[number]\n >;\n}\n\nexport interface DeployKeyAttributes {\n readonly deploymentName: string;\n readonly keyId: number;\n readonly name: string;\n readonly deployKey: Redacted.Redacted<string>;\n readonly allowedActions: ReadonlyArray<string>;\n}\n\nexport type DeployKey = Resource<\n \"Convex.DeployKey\",\n DeployKeyProps,\n DeployKeyAttributes,\n never,\n Providers\n>;\nexport const DeployKey = Resource<DeployKey>(\"Convex.DeployKey\");\n\nexport class DeployKeyRecoveryRequired extends Schema.TaggedError<DeployKeyRecoveryRequired>()(\n \"DeployKeyRecoveryRequired\",\n {\n deploymentName: Schema.String,\n name: Schema.String,\n keyIds: Schema.Array(Schema.Finite),\n },\n) {}\n\nexport class DeployKeyChangeRequiresNewResource extends Schema.TaggedError<DeployKeyChangeRequiresNewResource>()(\n \"DeployKeyChangeRequiresNewResource\",\n { deploymentName: Schema.String, keyId: Schema.Finite, field: Schema.String },\n) {}\n\nexport const provider = Effect.gen(function* () {\n const client = yield* ConvexClient;\n const hasName = (keyName: string, name: string) =>\n keyName === name ||\n (keyName.startsWith(`${name} (`) &&\n /^[0-9a-f]{8}\\)$/.test(keyName.slice(name.length + 2)));\n const recover = (\n deploymentName: string,\n name: string,\n keyIds: ReadonlyArray<number>,\n ) => new DeployKeyRecoveryRequired({ deploymentName, name, keyIds });\n return {\n diff: Effect.fn(\"DeployKey.diff\")(function* ({ news, output }) {\n if (!isResolved(news) || !output) return;\n for (const field of [\"deploymentName\", \"name\"] as const) {\n if (news[field] !== undefined && news[field] !== output[field])\n return yield* new DeployKeyChangeRequiresNewResource({\n deploymentName: output.deploymentName,\n keyId: output.keyId,\n field,\n });\n }\n const keys = yield* client.listDeployKeys(output.deploymentName);\n const key = keys.find((candidate) => candidate.id === output.keyId);\n if (!key || !Redacted.isRedacted(output.deployKey))\n return yield* recover(output.deploymentName, output.name, [\n output.keyId,\n ]);\n if (!hasName(key.name, news.name ?? output.name))\n return yield* new DeployKeyChangeRequiresNewResource({\n deploymentName: output.deploymentName,\n keyId: output.keyId,\n field: \"name\",\n });\n const allowedActions = news.allowedActions ?? output.allowedActions;\n if (\n new Set(allowedActions).size !== new Set(key.allowedActions).size ||\n allowedActions.some((action) => !key.allowedActions.includes(action))\n )\n return yield* new DeployKeyChangeRequiresNewResource({\n deploymentName: output.deploymentName,\n keyId: output.keyId,\n field: \"allowedActions\",\n });\n }),\n read: Effect.fn(\"DeployKey.read\")(function* ({\n fqn,\n instanceId,\n olds,\n output,\n }) {\n const deploymentName = output?.deploymentName ?? olds.deploymentName;\n if (deploymentName === undefined) return;\n const name =\n output?.name ??\n olds.name ??\n (yield* resourceName(\"key\", fqn, instanceId));\n const keys = yield* client.listDeployKeys(deploymentName);\n if (output) {\n const key = keys.find((candidate) => candidate.id === output.keyId);\n if (!key) return yield* recover(deploymentName, name, [output.keyId]);\n if (!Redacted.isRedacted(output.deployKey))\n return yield* recover(deploymentName, name, [key.id]);\n return {\n ...output,\n allowedActions: key.allowedActions,\n };\n }\n const matches = keys.filter((key) => hasName(key.name, name));\n if (matches.length > 0)\n return yield* recover(\n deploymentName,\n name,\n matches.map((candidate) => candidate.id),\n );\n return undefined;\n }),\n reconcile: Effect.fn(\"DeployKey.reconcile\")(function* ({\n fqn,\n instanceId,\n news,\n output,\n }) {\n if (!output) yield* checkpointCreate(fqn, instanceId, news);\n const name =\n news.name ??\n output?.name ??\n (yield* resourceName(\"key\", fqn, instanceId));\n if (output) {\n for (const field of [\"deploymentName\", \"name\"] as const) {\n if (news[field] !== undefined && news[field] !== output[field])\n return yield* new DeployKeyChangeRequiresNewResource({\n deploymentName: output.deploymentName,\n keyId: output.keyId,\n field,\n });\n }\n const keys = yield* client.listDeployKeys(output.deploymentName);\n const key = keys.find((candidate) => candidate.id === output.keyId);\n if (!key || !Redacted.isRedacted(output.deployKey))\n return yield* recover(output.deploymentName, name, [output.keyId]);\n if (!hasName(key.name, name))\n return yield* new DeployKeyChangeRequiresNewResource({\n deploymentName: output.deploymentName,\n keyId: output.keyId,\n field: \"name\",\n });\n const allowedActions = news.allowedActions ?? output.allowedActions;\n if (\n new Set(allowedActions).size !== new Set(key.allowedActions).size ||\n allowedActions.some((action) => !key.allowedActions.includes(action))\n )\n return yield* new DeployKeyChangeRequiresNewResource({\n deploymentName: output.deploymentName,\n keyId: output.keyId,\n field: \"allowedActions\",\n });\n return {\n ...output,\n allowedActions: key.allowedActions,\n };\n }\n const existing = (yield* client.listDeployKeys(\n news.deploymentName,\n )).filter((key) => hasName(key.name, name));\n if (existing.length > 0)\n return yield* recover(\n news.deploymentName,\n name,\n existing.map((key) => key.id),\n );\n const created = yield* client.createDeployKey(news.deploymentName, {\n name,\n ...(news.allowedActions === undefined\n ? {}\n : { allowedActions: [...news.allowedActions] }),\n });\n const matches = (yield* client.listDeployKeys(\n news.deploymentName,\n )).filter((key) => hasName(key.name, name));\n const key = matches[0];\n if (matches.length !== 1 || !key)\n return yield* recover(\n news.deploymentName,\n name,\n matches.map((candidate) => candidate.id),\n );\n return {\n deploymentName: news.deploymentName,\n keyId: key.id,\n name,\n deployKey: created.deployKey,\n allowedActions: key.allowedActions,\n };\n }),\n delete: Effect.fn(\"DeployKey.delete\")(function* ({ output }) {\n yield* client\n .deleteDeployKey(output.deploymentName, output.deployKey)\n .pipe(Effect.catchTag(\"ConvexNotFound\", () => Effect.void));\n }),\n } satisfies Provider.ProviderServiceInput<DeployKey>;\n});\n\n/**\n * Under `alchemy dev` the deploy key is the admin key the local deployment\n * generated. It is read on every apply, so a recreated backend's new key\n * replaces the old one.\n */\nexport const localProvider = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const directory = yield* dataDirectories;\n return {\n diff: () => Effect.succeed({ action: \"update\" }),\n reconcile: Effect.fn(\"DeployKey.localReconcile\")(function* ({\n fqn,\n instanceId,\n news,\n }) {\n const name = news.name ?? (yield* resourceName(\"key\", fqn, instanceId));\n const deployKey = yield* adminKey(\n news.deploymentName,\n directory(news.deploymentName),\n ).pipe(\n Effect.provideService(FileSystem.FileSystem, fs),\n Effect.provideService(Path.Path, path),\n );\n return {\n deploymentName: news.deploymentName,\n keyId: 0,\n name,\n deployKey,\n allowedActions: news.allowedActions ?? [],\n } satisfies DeployKeyAttributes;\n }),\n delete: () => Effect.void,\n } satisfies Provider.ProviderServiceInput<DeployKey>;\n});\n\nexport const layer = Provider.effect(DeployKey, provider);\nexport const localLayer = Provider.effect(DeployKey, localProvider);\n"],"mappings":"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"}