@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
package/src/Code.ts ADDED
@@ -0,0 +1,55 @@
1
+ import * as Provider from "alchemy/Provider";
2
+ import type { ProviderMode } from "alchemy/ProviderMode";
3
+ import { Resource } from "alchemy/Resource";
4
+ import * as Effect from "effect/Effect";
5
+ import type * as Redacted from "effect/Redacted";
6
+ import type { Providers } from "./Providers";
7
+ import { deploy } from "./internal/CodeDeployment";
8
+ import { CommandRunner, type PrepareCommand } from "./internal/CommandRunner";
9
+ import { PushLock } from "./internal/PushLock";
10
+
11
+ export interface CodeProps {
12
+ readonly deployment: { readonly name: string; readonly url: string };
13
+ readonly deployKey: Redacted.Redacted<string>;
14
+ readonly cwd?: string;
15
+ readonly prepare?: PrepareCommand;
16
+ }
17
+
18
+ export interface CodeAttributes {
19
+ readonly name: string;
20
+ readonly url: string;
21
+ }
22
+
23
+ export type Code = Resource<
24
+ "Convex.Code",
25
+ CodeProps,
26
+ CodeAttributes,
27
+ never,
28
+ Providers
29
+ >;
30
+ export const Code = Resource<Code>("Convex.Code");
31
+
32
+ const make = (mode: ProviderMode) =>
33
+ Effect.gen(function* () {
34
+ const runner = yield* CommandRunner;
35
+ const lock = yield* PushLock;
36
+ return {
37
+ read: ({ output }) => Effect.succeed(output),
38
+ diff: () => Effect.succeed({ action: "update" }),
39
+ reconcile: ({ news }) =>
40
+ deploy(news, mode).pipe(
41
+ Effect.provideService(CommandRunner, runner),
42
+ Effect.provideService(PushLock, lock),
43
+ ),
44
+ delete: () => Effect.void,
45
+ } satisfies Provider.ProviderServiceInput<Code>;
46
+ });
47
+
48
+ export const provider = make("live");
49
+ /**
50
+ * Under `alchemy dev`, pushes go to the local backend's self-hosted target.
51
+ */
52
+ export const localProvider = make("local");
53
+
54
+ export const layer = Provider.effect(Code, provider);
55
+ export const localLayer = Provider.effect(Code, localProvider);
package/src/Confect.ts ADDED
@@ -0,0 +1 @@
1
+ export { Backend, type BackendProps } from "./Backend";
package/src/Convex.ts ADDED
@@ -0,0 +1,18 @@
1
+ export { Project, type ProjectProps, type ProjectAttributes } from "./Project";
2
+ export {
3
+ Deployment,
4
+ type DeploymentProps,
5
+ type DeploymentAttributes,
6
+ } from "./Deployment";
7
+ export {
8
+ DeployKey,
9
+ type DeployKeyProps,
10
+ type DeployKeyAttributes,
11
+ } from "./DeployKey";
12
+ export {
13
+ EnvironmentVariables,
14
+ type EnvironmentVariablesProps,
15
+ type EnvironmentVariablesAttributes,
16
+ } from "./EnvironmentVariables";
17
+ export { Code, type CodeProps, type CodeAttributes } from "./Code";
18
+ export { providers, Providers } from "./Providers";
@@ -0,0 +1,544 @@
1
+ import type * as DeploymentApi from "@convex-dev/platform/deploymentApi";
2
+ import type * as ManagementApi from "@convex-dev/platform/managementApi";
3
+ import type { ProviderMode } from "alchemy/ProviderMode";
4
+ import * as Config from "effect/Config";
5
+ import * as Context from "effect/Context";
6
+ import * as Effect from "effect/Effect";
7
+ import * as Layer from "effect/Layer";
8
+ import * as Redacted from "effect/Redacted";
9
+ import * as Schema from "effect/Schema";
10
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
11
+ import * as HttpClient from "effect/http/HttpClient";
12
+ import * as HttpClientRequest from "effect/http/HttpClientRequest";
13
+ import type * as HttpClientResponse from "effect/http/HttpClientResponse";
14
+ import * as Loopback from "./internal/Loopback";
15
+
16
+ export type Project = ManagementApi.ProjectResponse;
17
+ export type CreatedProject = ManagementApi.PlatformCreateProjectResponse;
18
+ export type Deployment = ManagementApi.PlatformDeploymentResponse;
19
+ export type DeployKey = Omit<
20
+ ManagementApi.PlatformDeployKeyResponse,
21
+ "allowedActions"
22
+ > & {
23
+ readonly allowedActions: readonly string[];
24
+ };
25
+ export type CreateProjectInput = Pick<
26
+ ManagementApi.PlatformCreateProjectArgs,
27
+ "projectName"
28
+ >;
29
+ export type UpdateProjectInput = Pick<
30
+ ManagementApi.PlatformUpdateProjectArgs,
31
+ "name"
32
+ >;
33
+ export type CreateDeploymentInput = Pick<
34
+ ManagementApi.PlatformCreateDeploymentArgs,
35
+ "type" | "region" | "class"
36
+ > & { readonly reference: string };
37
+ export type UpdateDeploymentInput = Pick<
38
+ ManagementApi.PlatformUpdateDeploymentArgs,
39
+ "reference" | "expiresAt" | "sendLogsToClient"
40
+ >;
41
+ export type CreateDeployKeyInput = ManagementApi.PlatformCreateDeployKeyArgs;
42
+ export type CreatedDeployKey = {
43
+ readonly deployKey: Redacted.Redacted<
44
+ ManagementApi.PlatformCreateDeployKeyResponse["deployKey"]
45
+ >;
46
+ };
47
+ export type EnvironmentVariableChange = Omit<
48
+ DeploymentApi.UpdateEnvVarRequest,
49
+ "value"
50
+ > & {
51
+ readonly value?:
52
+ | Exclude<DeploymentApi.UpdateEnvVarRequest["value"], undefined>
53
+ | Redacted.Redacted<string>;
54
+ };
55
+ export type EnvironmentVariables = Readonly<
56
+ Record<
57
+ string,
58
+ Redacted.Redacted<
59
+ DeploymentApi.ListEnvVarsResponse["environmentVariables"][string]
60
+ >
61
+ >
62
+ >;
63
+
64
+ const errorFields = {
65
+ operation: Schema.String,
66
+ status: Schema.optionalKey(Schema.Finite),
67
+ code: Schema.Literals([
68
+ "HttpError",
69
+ "TransportError",
70
+ "InvalidResponse",
71
+ "InvalidRequest",
72
+ "InvalidPagination",
73
+ "InvalidConfiguration",
74
+ ]),
75
+ };
76
+
77
+ export class ConvexApiError extends Schema.TaggedError<ConvexApiError>()(
78
+ "ConvexApiError",
79
+ errorFields,
80
+ ) {}
81
+
82
+ export class ConvexNotFound extends Schema.TaggedError<ConvexNotFound>()(
83
+ "ConvexNotFound",
84
+ errorFields,
85
+ ) {}
86
+
87
+ export class ConvexConflict extends Schema.TaggedError<ConvexConflict>()(
88
+ "ConvexConflict",
89
+ errorFields,
90
+ ) {}
91
+
92
+ export type ConvexClientError =
93
+ | ConvexApiError
94
+ | ConvexNotFound
95
+ | ConvexConflict;
96
+
97
+ const ProjectSchema = Schema.Struct({
98
+ id: Schema.Finite,
99
+ name: Schema.String,
100
+ slug: Schema.String,
101
+ teamId: Schema.Finite,
102
+ teamSlug: Schema.String,
103
+ createTime: Schema.Finite,
104
+ prodDeploymentName: Schema.optionalKey(Schema.NullOr(Schema.String)),
105
+ devDeploymentName: Schema.optionalKey(Schema.NullOr(Schema.String)),
106
+ }) satisfies Schema.Schema<Project>;
107
+
108
+ const CreatedProjectSchema = Schema.Struct({
109
+ id: Schema.Finite,
110
+ projectId: Schema.Finite,
111
+ slug: Schema.String,
112
+ deploymentName: Schema.optionalKey(Schema.NullOr(Schema.String)),
113
+ deploymentUrl: Schema.optionalKey(Schema.NullOr(Schema.String)),
114
+ }) satisfies Schema.Schema<CreatedProject>;
115
+
116
+ const deploymentFields = {
117
+ name: Schema.String,
118
+ createTime: Schema.Finite,
119
+ deploymentType: Schema.Literals(["dev", "prod", "preview", "custom"]),
120
+ projectId: Schema.Finite,
121
+ previewIdentifier: Schema.optionalKey(Schema.NullOr(Schema.String)),
122
+ };
123
+
124
+ const DeploymentSchema = Schema.Union([
125
+ Schema.Struct({
126
+ ...deploymentFields,
127
+ kind: Schema.Literal("cloud"),
128
+ id: Schema.Finite,
129
+ lastDeployTime: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
130
+ creator: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
131
+ region: Schema.Literals([
132
+ "aws-us-east-1",
133
+ "aws-eu-west-1",
134
+ "aws-ap-southeast-2",
135
+ "aws-ca-central-1",
136
+ ]),
137
+ isDefault: Schema.Boolean,
138
+ reference: Schema.String,
139
+ dashboardEditConfirmation: Schema.optionalKey(
140
+ Schema.NullOr(Schema.Boolean),
141
+ ),
142
+ deploymentUrl: Schema.String,
143
+ expiresAt: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
144
+ class: Schema.String,
145
+ sendLogsToClient: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),
146
+ }),
147
+ Schema.Struct({
148
+ ...deploymentFields,
149
+ kind: Schema.Literal("local"),
150
+ creator: Schema.Finite,
151
+ port: Schema.Finite,
152
+ deviceName: Schema.String,
153
+ isActive: Schema.Boolean,
154
+ }),
155
+ ]) satisfies Schema.Schema<Deployment>;
156
+
157
+ const DeployKeySchema = Schema.Struct({
158
+ id: Schema.Finite,
159
+ name: Schema.String,
160
+ creationTime: Schema.Finite,
161
+ lastUsedTime: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
162
+ expiresAt: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
163
+ creator: Schema.optionalKey(Schema.NullOr(Schema.Finite)),
164
+ managedBy: Schema.optionalKey(
165
+ Schema.NullOr(
166
+ Schema.Union([
167
+ Schema.Literal("vercel"),
168
+ Schema.Struct({ oauthApp: Schema.String }),
169
+ ]),
170
+ ),
171
+ ),
172
+ allowedActions: Schema.Array(Schema.String),
173
+ }) satisfies Schema.Schema<DeployKey>;
174
+
175
+ const ProjectsPageSchema = Schema.Struct({
176
+ items: Schema.Array(ProjectSchema),
177
+ pagination: Schema.Struct({
178
+ hasMore: Schema.Boolean,
179
+ nextCursor: Schema.optionalKey(Schema.NullOr(Schema.String)),
180
+ }),
181
+ });
182
+
183
+ const make = Effect.fn("ConvexClient.make")(function* (options?: {
184
+ readonly token?: Redacted.Redacted<string>;
185
+ readonly mode?: ProviderMode;
186
+ }) {
187
+ const http = yield* HttpClient.HttpClient;
188
+ const managementAuthorization = Effect.gen(function* () {
189
+ const token =
190
+ options?.token ??
191
+ (yield* Config.Redacted("CONVEX_ACCESS_TOKEN").pipe(
192
+ Effect.mapError(
193
+ () =>
194
+ new ConvexApiError({
195
+ operation: "configure",
196
+ code: "InvalidConfiguration",
197
+ }),
198
+ ),
199
+ ));
200
+ return Redacted.make(`Bearer ${Redacted.value(token)}`);
201
+ });
202
+ const baseUrl = "https://api.convex.dev/v1";
203
+
204
+ const send = Effect.fn("ConvexClient.request")(function* (
205
+ operation: string,
206
+ method: "GET" | "POST" | "PATCH",
207
+ url: string,
208
+ authorization: Redacted.Redacted<string>,
209
+ body?: unknown,
210
+ ) {
211
+ let request = HttpClientRequest.make(method)(url).pipe(
212
+ HttpClientRequest.setHeader(
213
+ "authorization",
214
+ Redacted.value(authorization),
215
+ ),
216
+ HttpClientRequest.acceptJson,
217
+ );
218
+ if (body !== undefined) {
219
+ request = yield* HttpClientRequest.bodyJson(request, body).pipe(
220
+ Effect.mapError(
221
+ () => new ConvexApiError({ operation, code: "InvalidRequest" }),
222
+ ),
223
+ );
224
+ }
225
+ const response = yield* http.execute(request).pipe(
226
+ Effect.provideService(FetchHttpClient.RequestInit, {
227
+ redirect: "manual",
228
+ }),
229
+ Effect.mapError(
230
+ () => new ConvexApiError({ operation, code: "TransportError" }),
231
+ ),
232
+ );
233
+ if (response.status === 404) {
234
+ return yield* new ConvexNotFound({
235
+ operation,
236
+ status: 404,
237
+ code: "HttpError",
238
+ });
239
+ }
240
+ if (response.status === 409) {
241
+ return yield* new ConvexConflict({
242
+ operation,
243
+ status: 409,
244
+ code: "HttpError",
245
+ });
246
+ }
247
+ if (response.status < 200 || response.status >= 300) {
248
+ return yield* new ConvexApiError({
249
+ operation,
250
+ status: response.status,
251
+ code: "HttpError",
252
+ });
253
+ }
254
+ return response;
255
+ });
256
+
257
+ const decode = Effect.fn("ConvexClient.decode")(function* <A>(
258
+ operation: string,
259
+ response: HttpClientResponse.HttpClientResponse,
260
+ schema: Schema.Decoder<A>,
261
+ ) {
262
+ const invalidResponse = () =>
263
+ new ConvexApiError({
264
+ operation,
265
+ status: response.status,
266
+ code: "InvalidResponse",
267
+ });
268
+ const body = yield* response.json.pipe(Effect.mapError(invalidResponse));
269
+ return yield* Schema.decodeEffect(schema)(body).pipe(
270
+ Effect.mapError(invalidResponse),
271
+ );
272
+ });
273
+
274
+ const management = Effect.fn("ConvexClient.management")(function* <A>(
275
+ operation: string,
276
+ method: "GET" | "POST" | "PATCH",
277
+ path: string,
278
+ schema: Schema.Decoder<A>,
279
+ body?: unknown,
280
+ ) {
281
+ const response = yield* send(
282
+ operation,
283
+ method,
284
+ `${baseUrl}${path}`,
285
+ yield* managementAuthorization,
286
+ body,
287
+ );
288
+ return yield* decode(operation, response, schema);
289
+ });
290
+
291
+ const managementVoid = Effect.fn("ConvexClient.managementVoid")(function* (
292
+ operation: string,
293
+ method: "POST" | "PATCH",
294
+ path: string,
295
+ body?: unknown,
296
+ ) {
297
+ yield* send(
298
+ operation,
299
+ method,
300
+ `${baseUrl}${path}`,
301
+ yield* managementAuthorization,
302
+ body,
303
+ );
304
+ });
305
+
306
+ const deploymentUrl = Effect.fn("ConvexClient.deploymentUrl")(function* (
307
+ operation: string,
308
+ url: string,
309
+ ) {
310
+ const invalidUrl = () =>
311
+ new ConvexApiError({ operation, code: "InvalidRequest" });
312
+ if (options?.mode === "local") {
313
+ if (!Loopback.isOrigin(url)) return yield* invalidUrl();
314
+ return `${url}/api/v1`;
315
+ }
316
+ const parsed = yield* Effect.try({
317
+ try: () => new URL(url),
318
+ catch: invalidUrl,
319
+ });
320
+ if (
321
+ parsed.protocol !== "https:" ||
322
+ parsed.username !== "" ||
323
+ parsed.password !== "" ||
324
+ parsed.port !== "" ||
325
+ parsed.search !== "" ||
326
+ parsed.hash !== "" ||
327
+ parsed.pathname !== "/" ||
328
+ !/^[a-z0-9-]+(?:\.(?:eu-west-1|ap-southeast-2|ca-central-1))?\.convex\.cloud$/.test(
329
+ parsed.hostname,
330
+ ) ||
331
+ url.replace(/\/$/, "") !== parsed.origin
332
+ ) {
333
+ return yield* invalidUrl();
334
+ }
335
+ return `${parsed.origin}/api/v1`;
336
+ });
337
+
338
+ return {
339
+ listProjects: Effect.fn("ConvexClient.listProjects")(function* (
340
+ teamId: number,
341
+ ) {
342
+ const projects: Project[] = [];
343
+ const seenCursors = new Set<string>();
344
+ let cursor: string | undefined;
345
+ while (true) {
346
+ const page = yield* management(
347
+ "listProjects",
348
+ "GET",
349
+ `/teams/${teamId}/projects${cursor === undefined ? "" : `?cursor=${encodeURIComponent(cursor)}`}`,
350
+ ProjectsPageSchema,
351
+ );
352
+ projects.push(...page.items);
353
+ if (!page.pagination.hasMore) return projects;
354
+ const nextCursor = page.pagination.nextCursor;
355
+ if (!nextCursor || seenCursors.has(nextCursor)) {
356
+ return yield* new ConvexApiError({
357
+ operation: "listProjects",
358
+ code: "InvalidPagination",
359
+ });
360
+ }
361
+ seenCursors.add(nextCursor);
362
+ cursor = nextCursor;
363
+ }
364
+ }),
365
+ getProject: Effect.fn("ConvexClient.getProject")((projectId: number) =>
366
+ management("getProject", "GET", `/projects/${projectId}`, ProjectSchema),
367
+ ),
368
+ createProject: Effect.fn("ConvexClient.createProject")(
369
+ (teamId: number, input: CreateProjectInput) =>
370
+ management(
371
+ "createProject",
372
+ "POST",
373
+ `/teams/${teamId}/create_project`,
374
+ CreatedProjectSchema,
375
+ input,
376
+ ),
377
+ ),
378
+ updateProject: Effect.fn("ConvexClient.updateProject")(
379
+ (projectId: number, input: UpdateProjectInput) =>
380
+ management(
381
+ "updateProject",
382
+ "PATCH",
383
+ `/projects/${projectId}`,
384
+ ProjectSchema,
385
+ input,
386
+ ),
387
+ ),
388
+ deleteProject: Effect.fn("ConvexClient.deleteProject")(
389
+ (projectId: number) =>
390
+ managementVoid(
391
+ "deleteProject",
392
+ "POST",
393
+ `/projects/${projectId}/delete`,
394
+ ),
395
+ ),
396
+ listDeployments: Effect.fn("ConvexClient.listDeployments")(
397
+ (projectId: number) =>
398
+ management(
399
+ "listDeployments",
400
+ "GET",
401
+ `/projects/${projectId}/list_deployments`,
402
+ Schema.Array(DeploymentSchema),
403
+ ),
404
+ ),
405
+ getDeployment: Effect.fn("ConvexClient.getDeployment")((name: string) =>
406
+ management(
407
+ "getDeployment",
408
+ "GET",
409
+ `/deployments/${encodeURIComponent(name)}`,
410
+ DeploymentSchema,
411
+ ),
412
+ ),
413
+ createDeployment: Effect.fn("ConvexClient.createDeployment")(
414
+ (projectId: number, input: CreateDeploymentInput) =>
415
+ management(
416
+ "createDeployment",
417
+ "POST",
418
+ `/projects/${projectId}/create_deployment`,
419
+ DeploymentSchema,
420
+ input,
421
+ ),
422
+ ),
423
+ updateDeployment: Effect.fn("ConvexClient.updateDeployment")(
424
+ (name: string, input: UpdateDeploymentInput) =>
425
+ managementVoid(
426
+ "updateDeployment",
427
+ "PATCH",
428
+ `/deployments/${encodeURIComponent(name)}`,
429
+ input,
430
+ ),
431
+ ),
432
+ deleteDeployment: Effect.fn("ConvexClient.deleteDeployment")(
433
+ (name: string) =>
434
+ managementVoid(
435
+ "deleteDeployment",
436
+ "POST",
437
+ `/deployments/${encodeURIComponent(name)}/delete`,
438
+ ),
439
+ ),
440
+ createDeployKey: Effect.fn("ConvexClient.createDeployKey")(function* (
441
+ name: string,
442
+ input: CreateDeployKeyInput,
443
+ ): Effect.fn.Return<CreatedDeployKey, ConvexClientError> {
444
+ const response = yield* management(
445
+ "createDeployKey",
446
+ "POST",
447
+ `/deployments/${encodeURIComponent(name)}/create_deploy_key`,
448
+ Schema.Struct({ deployKey: Schema.String }),
449
+ input,
450
+ );
451
+ return { deployKey: Redacted.make(response.deployKey) };
452
+ }),
453
+ listDeployKeys: Effect.fn("ConvexClient.listDeployKeys")((name: string) =>
454
+ management(
455
+ "listDeployKeys",
456
+ "GET",
457
+ `/deployments/${encodeURIComponent(name)}/list_deploy_keys`,
458
+ Schema.Array(DeployKeySchema),
459
+ ),
460
+ ),
461
+ deleteDeployKey: Effect.fn("ConvexClient.deleteDeployKey")(
462
+ (name: string, id: string | Redacted.Redacted<string>) =>
463
+ managementVoid(
464
+ "deleteDeployKey",
465
+ "POST",
466
+ `/deployments/${encodeURIComponent(name)}/delete_deploy_key`,
467
+ {
468
+ id: Redacted.isRedacted(id) ? Redacted.value(id) : id,
469
+ } satisfies ManagementApi.PlatformDeleteDeployKeyArgs,
470
+ ),
471
+ ),
472
+ listEnvironmentVariables: Effect.fn(
473
+ "ConvexClient.listEnvironmentVariables",
474
+ )(function* (
475
+ url: string,
476
+ key: Redacted.Redacted<string>,
477
+ ): Effect.fn.Return<EnvironmentVariables, ConvexClientError> {
478
+ const response = yield* send(
479
+ "listEnvironmentVariables",
480
+ "GET",
481
+ `${yield* deploymentUrl("listEnvironmentVariables", url)}/list_environment_variables`,
482
+ Redacted.make(`Convex ${Redacted.value(key)}`),
483
+ );
484
+ const result = yield* decode(
485
+ "listEnvironmentVariables",
486
+ response,
487
+ Schema.Struct({
488
+ environmentVariables: Schema.Record(Schema.String, Schema.String),
489
+ }),
490
+ );
491
+ return Object.fromEntries(
492
+ Object.entries(result.environmentVariables).map(([name, value]) => [
493
+ name,
494
+ Redacted.make(value),
495
+ ]),
496
+ );
497
+ }),
498
+ updateEnvironmentVariables: Effect.fn(
499
+ "ConvexClient.updateEnvironmentVariables",
500
+ )(function* (
501
+ url: string,
502
+ key: Redacted.Redacted<string>,
503
+ changes: readonly EnvironmentVariableChange[],
504
+ ) {
505
+ yield* send(
506
+ "updateEnvironmentVariables",
507
+ "POST",
508
+ `${yield* deploymentUrl("updateEnvironmentVariables", url)}/update_environment_variables`,
509
+ Redacted.make(`Convex ${Redacted.value(key)}`),
510
+ {
511
+ changes: changes.map(({ name, value }) => ({
512
+ name,
513
+ ...(value === undefined
514
+ ? {}
515
+ : {
516
+ value: Redacted.isRedacted(value)
517
+ ? Redacted.value(value)
518
+ : value,
519
+ }),
520
+ })),
521
+ } satisfies {
522
+ readonly changes: Readonly<
523
+ DeploymentApi.UpdateEnvVarsRequest["changes"]
524
+ >;
525
+ },
526
+ );
527
+ }),
528
+ };
529
+ });
530
+
531
+ export class ConvexClient extends Context.Service<
532
+ ConvexClient,
533
+ Effect.Success<ReturnType<typeof make>>
534
+ >()("@confect/alchemy/ConvexClient") {}
535
+
536
+ /**
537
+ * `mode: "local"` sends deployment requests only to a loopback backend over
538
+ * HTTP; the default accepts only Convex cloud HTTPS origins.
539
+ */
540
+ export const layer = (options?: {
541
+ readonly token?: Redacted.Redacted<string>;
542
+ readonly mode?: ProviderMode;
543
+ }) =>
544
+ Layer.effect(ConvexClient, make(options).pipe(Effect.map(ConvexClient.of)));