@samebase/alchemy-convex 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +146 -0
  3. package/lib/Credentials.d.ts +39 -0
  4. package/lib/Credentials.d.ts.map +1 -0
  5. package/lib/Credentials.js +49 -0
  6. package/lib/Credentials.js.map +1 -0
  7. package/lib/DefaultEnvironmentVariable.d.ts +58 -0
  8. package/lib/DefaultEnvironmentVariable.d.ts.map +1 -0
  9. package/lib/DefaultEnvironmentVariable.js +93 -0
  10. package/lib/DefaultEnvironmentVariable.js.map +1 -0
  11. package/lib/Deploy.d.ts +62 -0
  12. package/lib/Deploy.d.ts.map +1 -0
  13. package/lib/Deploy.js +92 -0
  14. package/lib/Deploy.js.map +1 -0
  15. package/lib/DeployKey.d.ts +48 -0
  16. package/lib/DeployKey.d.ts.map +1 -0
  17. package/lib/DeployKey.js +104 -0
  18. package/lib/DeployKey.js.map +1 -0
  19. package/lib/EnvironmentVariable.d.ts +37 -0
  20. package/lib/EnvironmentVariable.d.ts.map +1 -0
  21. package/lib/EnvironmentVariable.js +65 -0
  22. package/lib/EnvironmentVariable.js.map +1 -0
  23. package/lib/ManagementApi.d.ts +50 -0
  24. package/lib/ManagementApi.d.ts.map +1 -0
  25. package/lib/ManagementApi.js +103 -0
  26. package/lib/ManagementApi.js.map +1 -0
  27. package/lib/PreviewDeployKey.d.ts +34 -0
  28. package/lib/PreviewDeployKey.d.ts.map +1 -0
  29. package/lib/PreviewDeployKey.js +78 -0
  30. package/lib/PreviewDeployKey.js.map +1 -0
  31. package/lib/Project.d.ts +29 -0
  32. package/lib/Project.d.ts.map +1 -0
  33. package/lib/Project.js +114 -0
  34. package/lib/Project.js.map +1 -0
  35. package/lib/Providers.d.ts +13 -0
  36. package/lib/Providers.d.ts.map +1 -0
  37. package/lib/Providers.js +30 -0
  38. package/lib/Providers.js.map +1 -0
  39. package/lib/index.d.ts +10 -0
  40. package/lib/index.d.ts.map +1 -0
  41. package/lib/index.js +11 -0
  42. package/lib/index.js.map +1 -0
  43. package/package.json +71 -0
  44. package/src/Credentials.ts +78 -0
  45. package/src/DefaultEnvironmentVariable.ts +165 -0
  46. package/src/Deploy.ts +171 -0
  47. package/src/DeployKey.ts +171 -0
  48. package/src/EnvironmentVariable.ts +129 -0
  49. package/src/ManagementApi.ts +193 -0
  50. package/src/PreviewDeployKey.ts +126 -0
  51. package/src/Project.ts +191 -0
  52. package/src/Providers.ts +51 -0
  53. package/src/index.ts +45 -0
@@ -0,0 +1,34 @@
1
+ import { Resource } from "alchemy";
2
+ import * as Provider from "alchemy/Provider";
3
+ import * as Redacted from "effect/Redacted";
4
+ import * as Schema from "effect/Schema";
5
+ import { ManagementApi } from "./ManagementApi.ts";
6
+ import type { Providers } from "./Providers.ts";
7
+ /** GET /projects/{project_id}/list_preview_deploy_keys */
8
+ export declare const PreviewDeployKeyList: Schema.Struct<{
9
+ readonly items: Schema.$Array<Schema.Struct<{
10
+ readonly name: Schema.String;
11
+ readonly creationTime: Schema.Number;
12
+ }>>;
13
+ }>;
14
+ /** POST /projects/{project_id}/create_preview_deploy_key */
15
+ export declare const CreatedPreviewDeployKey: Schema.Struct<{
16
+ readonly previewDeployKey: Schema.String;
17
+ }>;
18
+ export interface PreviewDeployKeyProps {
19
+ /** Numeric project id, such as `project.projectId`. */
20
+ readonly projectId: number;
21
+ /** Requested key name. Convex appends a short id to make it unique. */
22
+ readonly name: string;
23
+ }
24
+ export interface PreviewDeployKeyAttributes {
25
+ /** The name Convex lists the key under, such as "ci (6308e666)". */
26
+ readonly uniqueName: string;
27
+ readonly projectId: number;
28
+ /** The secret, such as `preview:<team>:<project>|<token>`. Convex returns it only at creation. */
29
+ readonly previewDeployKey: Redacted.Redacted<string>;
30
+ }
31
+ export type PreviewDeployKey = Resource<"Convex.PreviewDeployKey", PreviewDeployKeyProps, PreviewDeployKeyAttributes, never, Providers>;
32
+ export declare const PreviewDeployKey: import("alchemy").ResourceClass<PreviewDeployKey>;
33
+ export declare const PreviewDeployKeyProvider: () => import("effect/Layer").Layer<Provider.Provider<PreviewDeployKey>, never, ManagementApi>;
34
+ //# sourceMappingURL=PreviewDeployKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PreviewDeployKey.d.ts","sourceRoot":"","sources":["../src/PreviewDeployKey.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAqB,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,0DAA0D;AAC1D,eAAO,MAAM,oBAAoB;;;;;EAAoD,CAAC;AAEtF,4DAA4D;AAC5D,eAAO,MAAM,uBAAuB;;EAAqD,CAAC;AAE1F,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,oEAAoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,kGAAkG;IAClG,QAAQ,CAAC,gBAAgB,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACtD;AAED,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CACrC,yBAAyB,EACzB,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,EACL,SAAS,CACV,CAAC;AACF,eAAO,MAAM,gBAAgB,mDAAwD,CAAC;AAEtF,eAAO,MAAM,wBAAwB,+FA8ElC,CAAC"}
@@ -0,0 +1,78 @@
1
+ // Convex.PreviewDeployKey: a project key that creates and deploys preview
2
+ // deployments, such as the key CI passes to `npx convex deploy` for a branch.
3
+ //
4
+ // Convex returns the secret only once, from create_preview_deploy_key. The
5
+ // listing shows each key under a unique name, the requested name plus a short
6
+ // id suffix, and delete_preview_deploy_key accepts that unique name. A key
7
+ // cannot be changed after creation, so every property change is a replacement.
8
+ import { Resource } from "alchemy";
9
+ import { havePropsChanged, isResolved } from "alchemy/Diff";
10
+ import * as Provider from "alchemy/Provider";
11
+ import * as Effect from "effect/Effect";
12
+ import * as Redacted from "effect/Redacted";
13
+ import * as Schema from "effect/Schema";
14
+ import { ListedKey, selectCreatedKey } from "./DeployKey.js";
15
+ import { absentAsUndefined, ManagementApi } from "./ManagementApi.js";
16
+ /** GET /projects/{project_id}/list_preview_deploy_keys */
17
+ export const PreviewDeployKeyList = Schema.Struct({ items: Schema.Array(ListedKey) });
18
+ /** POST /projects/{project_id}/create_preview_deploy_key */
19
+ export const CreatedPreviewDeployKey = Schema.Struct({ previewDeployKey: Schema.String });
20
+ export const PreviewDeployKey = Resource("Convex.PreviewDeployKey");
21
+ export const PreviewDeployKeyProvider = () => Provider.effect(PreviewDeployKey, Effect.gen(function* () {
22
+ const api = yield* ManagementApi;
23
+ const listKeys = (projectId) => api
24
+ .request("list preview deploy keys", (client) => client.GET("/projects/{project_id}/list_preview_deploy_keys", {
25
+ params: { path: { project_id: projectId } },
26
+ }))
27
+ .pipe(Effect.map((body) => Schema.decodeUnknownSync(PreviewDeployKeyList)(body).items));
28
+ return {
29
+ stables: ["uniqueName", "projectId"],
30
+ diff: ({ olds, news, output }) => {
31
+ if (!isResolved(news))
32
+ return Effect.succeed(undefined);
33
+ // State written without the secret cannot hand a key to dependents,
34
+ // and Convex cannot return it again, so only a new key helps.
35
+ return Effect.succeed((output !== undefined && output.previewDeployKey === undefined) ||
36
+ havePropsChanged(olds, news)
37
+ ? { action: "replace" }
38
+ : { action: "noop" });
39
+ },
40
+ read: Effect.fn(function* ({ output }) {
41
+ // A key that is not in state has no known secret, so it is never adopted.
42
+ if (output === undefined)
43
+ return undefined;
44
+ const entries = yield* absentAsUndefined(listKeys(output.projectId));
45
+ return entries?.some((entry) => entry.name === output.uniqueName) ? output : undefined;
46
+ }),
47
+ reconcile: Effect.fn(function* ({ news, output }) {
48
+ if (output !== undefined) {
49
+ // The secret cannot be read back. A key that still exists keeps the one in state.
50
+ const entries = yield* listKeys(news.projectId);
51
+ if (entries.some((entry) => entry.name === output.uniqueName))
52
+ return output;
53
+ }
54
+ const created = yield* api.request("create preview deploy key", (client) => client.POST("/projects/{project_id}/create_preview_deploy_key", {
55
+ params: { path: { project_id: news.projectId } },
56
+ body: { name: news.name },
57
+ }));
58
+ const { previewDeployKey } = Schema.decodeUnknownSync(CreatedPreviewDeployKey)(created);
59
+ const listed = selectCreatedKey(yield* listKeys(news.projectId), news.name);
60
+ if (listed === undefined) {
61
+ return yield* Effect.die(new Error(`Convex created preview deploy key "${news.name}" in project ${news.projectId} but does not list it`));
62
+ }
63
+ return {
64
+ uniqueName: listed.name,
65
+ projectId: news.projectId,
66
+ previewDeployKey: Redacted.make(previewDeployKey),
67
+ };
68
+ }),
69
+ delete: Effect.fn(function* ({ output }) {
70
+ // 404 PreviewDeployKeyNotFound: an earlier attempt or someone else deleted it.
71
+ yield* absentAsUndefined(api.requestVoid("delete preview deploy key", (client) => client.POST("/projects/{project_id}/delete_preview_deploy_key", {
72
+ params: { path: { project_id: output.projectId } },
73
+ body: { id: output.uniqueName },
74
+ })));
75
+ }),
76
+ };
77
+ }));
78
+ //# sourceMappingURL=PreviewDeployKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PreviewDeployKey.js","sourceRoot":"","sources":["../src/PreviewDeployKey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { Resource } from "alchemy";
2
+ import * as Provider from "alchemy/Provider";
3
+ import type { components } from "@convex-dev/platform/managementApi";
4
+ import { ManagementApi } from "./ManagementApi.ts";
5
+ import type { Providers } from "./Providers.ts";
6
+ /** Region names the Management API accepts, from the generated schema. */
7
+ export type DeploymentRegion = components["schemas"]["RegionName"];
8
+ export interface ProjectProps {
9
+ /** Team slug or numeric team id. A slug costs one extra lookup per run. */
10
+ readonly team: string | number;
11
+ /** Display name. Convex derives the slug from it. */
12
+ readonly name: string;
13
+ /** Region of the deployment created with the project. Defaults to the team default. */
14
+ readonly deploymentRegion?: DeploymentRegion;
15
+ /** Deployment created with the project. Defaults to `prod`. */
16
+ readonly deploymentType?: "prod" | "dev";
17
+ }
18
+ export interface ProjectAttributes {
19
+ readonly projectId: number;
20
+ readonly slug: string;
21
+ readonly name: string;
22
+ readonly teamId: number;
23
+ readonly prodDeploymentName: string | undefined;
24
+ readonly prodDeploymentUrl: string | undefined;
25
+ }
26
+ export type Project = Resource<"Convex.Project", ProjectProps, ProjectAttributes, never, Providers>;
27
+ export declare const Project: import("alchemy").ResourceClass<Project>;
28
+ export declare const ProjectProvider: () => import("effect/Layer").Layer<Provider.Provider<Project>, never, ManagementApi>;
29
+ //# sourceMappingURL=Project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../src/Project.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAqB,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;AAEnE,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,+DAA+D;IAC/D,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;CAChD;AAED,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;AACpG,eAAO,MAAM,OAAO,0CAAsC,CAAC;AA2B3D,eAAO,MAAM,eAAe,sFA6HzB,CAAC"}
package/lib/Project.js ADDED
@@ -0,0 +1,114 @@
1
+ // Convex.Project: a project in a Convex team, with its default production deployment.
2
+ //
3
+ // The Management API has no project update endpoint, so every property change
4
+ // is a replacement. Deleting a project deletes all of its deployments and data.
5
+ import { Resource } from "alchemy";
6
+ import { Unowned } from "alchemy/AdoptPolicy";
7
+ import { isResolved } from "alchemy/Diff";
8
+ import * as Provider from "alchemy/Provider";
9
+ import * as Effect from "effect/Effect";
10
+ import * as Schema from "effect/Schema";
11
+ import { absentAsUndefined, ManagementApi } from "./ManagementApi.js";
12
+ export const Project = Resource("Convex.Project");
13
+ /** Fields of GET /projects/{id} and GET /teams/{team}/projects that the provider uses. */
14
+ const ProjectDetails = Schema.Struct({
15
+ id: Schema.Number,
16
+ name: Schema.String,
17
+ slug: Schema.String,
18
+ teamId: Schema.Number,
19
+ prodDeploymentName: Schema.NullOr(Schema.String),
20
+ });
21
+ const ProjectList = Schema.Struct({ items: Schema.Array(ProjectDetails) });
22
+ const CreatedProject = Schema.Struct({
23
+ projectId: Schema.Number,
24
+ slug: Schema.String,
25
+ deploymentName: Schema.NullOr(Schema.String),
26
+ deploymentUrl: Schema.NullOr(Schema.String),
27
+ });
28
+ const DeploymentRow = Schema.Struct({
29
+ name: Schema.String,
30
+ deploymentType: Schema.String,
31
+ isDefault: Schema.Boolean,
32
+ deploymentUrl: Schema.String,
33
+ });
34
+ const DeploymentRows = Schema.Array(DeploymentRow);
35
+ export const ProjectProvider = () => Provider.effect(Project, Effect.gen(function* () {
36
+ const api = yield* ManagementApi;
37
+ const prodDeployment = (projectId) => api
38
+ .request("list deployments", (client) => client.GET("/projects/{project_id}/list_deployments", {
39
+ params: { path: { project_id: projectId } },
40
+ }))
41
+ .pipe(Effect.map((rows) => Schema.decodeUnknownSync(DeploymentRows)(rows).find((row) => row.deploymentType === "prod" && row.isDefault)));
42
+ const attributesOf = (details) => prodDeployment(details.id).pipe(Effect.map((prod) => ({
43
+ projectId: details.id,
44
+ slug: details.slug,
45
+ name: details.name,
46
+ teamId: details.teamId,
47
+ prodDeploymentName: prod?.name ?? details.prodDeploymentName ?? undefined,
48
+ prodDeploymentUrl: prod?.deploymentUrl,
49
+ })));
50
+ const getById = (projectId) => absentAsUndefined(api.request("get project", (client) => client.GET("/projects/{project_id}", { params: { path: { project_id: projectId } } }))).pipe(Effect.map((body) => body === undefined ? undefined : Schema.decodeUnknownSync(ProjectDetails)(body)));
51
+ const findByName = (team, name) => Effect.gen(function* () {
52
+ const teamId = yield* api.resolveTeamId(team);
53
+ const list = yield* api.request("list projects", (client) => client.GET("/teams/{team_id}/projects", { params: { path: { team_id: teamId } } }));
54
+ return Schema.decodeUnknownSync(ProjectList)(list).items.find((row) => row.name === name || row.slug === name);
55
+ });
56
+ return {
57
+ stables: ["projectId", "slug", "teamId"],
58
+ diff: ({ olds, news }) => {
59
+ if (!isResolved(news))
60
+ return Effect.succeed(undefined);
61
+ const changed = olds.team !== news.team ||
62
+ olds.name !== news.name ||
63
+ olds.deploymentRegion !== news.deploymentRegion ||
64
+ olds.deploymentType !== news.deploymentType;
65
+ return Effect.succeed(changed ? { action: "replace" } : { action: "noop" });
66
+ },
67
+ read: Effect.fn(function* ({ olds, output }) {
68
+ if (output !== undefined) {
69
+ const details = yield* getById(output.projectId);
70
+ return details === undefined ? undefined : yield* attributesOf(details);
71
+ }
72
+ // No state: an existing project with this name belongs to someone
73
+ // else until the user passes --adopt. Convex has no ownership tags.
74
+ const existing = yield* findByName(olds.team, olds.name);
75
+ return existing === undefined ? undefined : Unowned(yield* attributesOf(existing));
76
+ }),
77
+ reconcile: Effect.fn(function* ({ news, output }) {
78
+ if (output !== undefined) {
79
+ // Properties are all create-time; diff maps changes to replace.
80
+ const details = yield* getById(output.projectId);
81
+ if (details !== undefined)
82
+ return yield* attributesOf(details);
83
+ }
84
+ // A crash after create and before state write is recovered by read;
85
+ // a project created by an earlier attempt is reused here too.
86
+ const existing = yield* findByName(news.team, news.name);
87
+ if (existing !== undefined)
88
+ return yield* attributesOf(existing);
89
+ const teamId = yield* api.resolveTeamId(news.team);
90
+ const created = yield* api.request("create project", (client) => client.POST("/teams/{team_id}/create_project", {
91
+ params: { path: { team_id: teamId } },
92
+ body: {
93
+ projectName: news.name,
94
+ deploymentType: news.deploymentType ?? "prod",
95
+ ...(news.deploymentRegion === undefined
96
+ ? {}
97
+ : { deploymentRegion: news.deploymentRegion }),
98
+ },
99
+ }));
100
+ const parsed = Schema.decodeUnknownSync(CreatedProject)(created);
101
+ const details = yield* getById(parsed.projectId);
102
+ if (details === undefined) {
103
+ return yield* Effect.die(new Error(`Convex created project ${parsed.projectId} but it cannot be read back`));
104
+ }
105
+ return yield* attributesOf(details);
106
+ }),
107
+ delete: Effect.fn(function* ({ output }) {
108
+ yield* absentAsUndefined(api.requestVoid("delete project", (client) => client.POST("/projects/{project_id}/delete", {
109
+ params: { path: { project_id: output.projectId } },
110
+ })));
111
+ }),
112
+ };
113
+ }));
114
+ //# sourceMappingURL=Project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Project.js","sourceRoot":"","sources":["../src/Project.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import * as Provider from "alchemy/Provider";
2
+ import * as Layer from "effect/Layer";
3
+ import { type Credentials } from "./Credentials.ts";
4
+ declare const Providers_base: Provider.ProviderCollection<Providers, "Convex">;
5
+ export declare class Providers extends Providers_base {
6
+ }
7
+ /**
8
+ * All Convex resource providers. Pass a credentials layer to override the
9
+ * default lookup (`CONVEX_ACCESS_TOKEN`, then the Convex CLI login).
10
+ */
11
+ export declare const providers: (credentials?: Layer.Layer<Credentials>) => Layer.Layer<Providers, never, import("effect/process/ChildProcessSpawner").ChildProcessSpawner | import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
12
+ export {};
13
+ //# sourceMappingURL=Providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Providers.d.ts","sourceRoot":"","sources":["../src/Providers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,kBAAkB,CAAC;;AAYhE,qBAAa,SAAU,SAAQ,cAAkD;CAAG;AAEpF;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,cAAa,KAAK,CAAC,KAAK,CAAC,WAAW,CAAgB,0KA2B3E,CAAC"}
@@ -0,0 +1,30 @@
1
+ // The provider collection users merge into a stack:
2
+ // providers: Layer.mergeAll(Cloudflare.providers(), Convex.providers())
3
+ import { CommandExecutorLive } from "alchemy/Command";
4
+ import * as Provider from "alchemy/Provider";
5
+ import * as Layer from "effect/Layer";
6
+ import { fromConfig } from "./Credentials.js";
7
+ import { DefaultEnvironmentVariable, DefaultEnvironmentVariableProvider, } from "./DefaultEnvironmentVariable.js";
8
+ import { Deploy, DeployProvider } from "./Deploy.js";
9
+ import { DeployKey, DeployKeyProvider } from "./DeployKey.js";
10
+ import { EnvironmentVariable, EnvironmentVariableProvider } from "./EnvironmentVariable.js";
11
+ import { ManagementApiLive } from "./ManagementApi.js";
12
+ import { PreviewDeployKey, PreviewDeployKeyProvider } from "./PreviewDeployKey.js";
13
+ import { Project, ProjectProvider } from "./Project.js";
14
+ export class Providers extends Provider.ProviderCollection()("Convex") {
15
+ }
16
+ /**
17
+ * All Convex resource providers. Pass a credentials layer to override the
18
+ * default lookup (`CONVEX_ACCESS_TOKEN`, then the Convex CLI login).
19
+ */
20
+ export const providers = (credentials = fromConfig()) => Layer.effect(Providers, Provider.collection([
21
+ Project,
22
+ DeployKey,
23
+ PreviewDeployKey,
24
+ EnvironmentVariable,
25
+ DefaultEnvironmentVariable,
26
+ Deploy,
27
+ ])).pipe(Layer.provide(Layer.mergeAll(ProjectProvider(), DeployKeyProvider(), PreviewDeployKeyProvider(), EnvironmentVariableProvider(), DefaultEnvironmentVariableProvider(), DeployProvider())), Layer.provide(ManagementApiLive()), Layer.provide(credentials),
28
+ // Convex.Deploy runs the Convex CLI through Alchemy's command executor.
29
+ Layer.provide(CommandExecutorLive()), Layer.orDie);
30
+ //# sourceMappingURL=Providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Providers.js","sourceRoot":"","sources":["../src/Providers.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,0EAA0E;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAoB,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EACL,0BAA0B,EAC1B,kCAAkC,GACnC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,OAAO,SAAU,SAAQ,QAAQ,CAAC,kBAAkB,EAAa,CAAC,QAAQ,CAAC;CAAG;AAEpF;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,cAAwC,UAAU,EAAE,EAAE,EAAE,CAChF,KAAK,CAAC,MAAM,CACV,SAAS,EACT,QAAQ,CAAC,UAAU,CAAC;IAClB,OAAO;IACP,SAAS;IACT,gBAAgB;IAChB,mBAAmB;IACnB,0BAA0B;IAC1B,MAAM;CACP,CAAC,CACH,CAAC,IAAI,CACJ,KAAK,CAAC,OAAO,CACX,KAAK,CAAC,QAAQ,CACZ,eAAe,EAAE,EACjB,iBAAiB,EAAE,EACnB,wBAAwB,EAAE,EAC1B,2BAA2B,EAAE,EAC7B,kCAAkC,EAAE,EACpC,cAAc,EAAE,CACjB,CACF,EACD,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,EAClC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;AAC1B,wEAAwE;AACxE,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,EACpC,KAAK,CAAC,KAAK,CACZ,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export { ACCESS_TOKEN_ENV, Credentials, CredentialsError, fromConfig, fromToken, } from "./Credentials.ts";
2
+ export { DefaultEnvironmentVariable, type DefaultEnvironmentVariableAttributes, type DefaultEnvironmentVariableProps, type DeploymentType, } from "./DefaultEnvironmentVariable.ts";
3
+ export { Deploy, type DeployAttributes, deployArgs, type DeployProps, parseDeployOutput, } from "./Deploy.ts";
4
+ export { DeployKey, type DeployKeyAction, type DeployKeyAttributes, type DeployKeyProps, } from "./DeployKey.ts";
5
+ export { EnvironmentVariable, type EnvironmentVariableAttributes, type EnvironmentVariableProps, } from "./EnvironmentVariable.ts";
6
+ export { ConvexApiError, ManagementApi } from "./ManagementApi.ts";
7
+ export { PreviewDeployKey, type PreviewDeployKeyAttributes, type PreviewDeployKeyProps, } from "./PreviewDeployKey.ts";
8
+ export { type DeploymentRegion, Project, type ProjectAttributes, type ProjectProps, } from "./Project.ts";
9
+ export { Providers, providers } from "./Providers.ts";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,0BAA0B,EAC1B,KAAK,oCAAoC,EACzC,KAAK,+BAA+B,EACpC,KAAK,cAAc,GACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,MAAM,EACN,KAAK,gBAAgB,EACrB,UAAU,EACV,KAAK,WAAW,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,EACT,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,GAC9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EACL,gBAAgB,EAChB,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,gBAAgB,EACrB,OAAO,EACP,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,11 @@
1
+ // @samebase/alchemy-convex: Convex resources for Alchemy v2.
2
+ export { ACCESS_TOKEN_ENV, Credentials, CredentialsError, fromConfig, fromToken, } from "./Credentials.js";
3
+ export { DefaultEnvironmentVariable, } from "./DefaultEnvironmentVariable.js";
4
+ export { Deploy, deployArgs, parseDeployOutput, } from "./Deploy.js";
5
+ export { DeployKey, } from "./DeployKey.js";
6
+ export { EnvironmentVariable, } from "./EnvironmentVariable.js";
7
+ export { ConvexApiError, ManagementApi } from "./ManagementApi.js";
8
+ export { PreviewDeployKey, } from "./PreviewDeployKey.js";
9
+ export { Project, } from "./Project.js";
10
+ export { Providers, providers } from "./Providers.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,0BAA0B,GAI3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,MAAM,EAEN,UAAU,EAEV,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,GAIV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,GAGpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EACL,gBAAgB,GAGjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,OAAO,GAGR,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@samebase/alchemy-convex",
3
+ "version": "0.1.0",
4
+ "description": "Convex resources for Alchemy v2: projects, deploy keys, environment variables, and a deploy step",
5
+ "keywords": [
6
+ "alchemy",
7
+ "cloudflare",
8
+ "convex",
9
+ "effect",
10
+ "infrastructure-as-code"
11
+ ],
12
+ "homepage": "https://github.com/samebase/alchemy-convex#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/samebase/alchemy-convex/issues"
15
+ },
16
+ "license": "Apache-2.0",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/samebase/alchemy-convex.git"
20
+ },
21
+ "files": [
22
+ "lib",
23
+ "src",
24
+ "README.md",
25
+ "LICENSE"
26
+ ],
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "exports": {
30
+ ".": {
31
+ "types": "./lib/index.d.ts",
32
+ "import": "./lib/index.js"
33
+ }
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "scripts": {
39
+ "check": "vp fmt --check && vp lint && pnpm run typecheck && vp test --run",
40
+ "typecheck": "tsc --noEmit",
41
+ "test": "vp test --run",
42
+ "test:live": "ALCHEMY_CONVEX_LIVE=1 vp test --run test/live",
43
+ "format": "vp fmt",
44
+ "lint": "vp lint",
45
+ "build": "rm -rf lib && tsc -p tsconfig.build.json",
46
+ "prepack": "pnpm run build"
47
+ },
48
+ "dependencies": {
49
+ "@convex-dev/platform": "0.1.11"
50
+ },
51
+ "devDependencies": {
52
+ "@effect/platform-node": "4.0.0",
53
+ "@effect/vitest": "4.0.0",
54
+ "@types/node": "^24.0.0",
55
+ "alchemy": "2.0.0-beta.80",
56
+ "convex": "^1.45.0",
57
+ "effect": "4.0.0",
58
+ "typescript": "^5.9.0",
59
+ "vite-plus": "0.3.0",
60
+ "vitest": "^4.0.0"
61
+ },
62
+ "peerDependencies": {
63
+ "@effect/platform-node": "^4.0.0",
64
+ "alchemy": "2.0.0-beta.80",
65
+ "effect": "^4.0.0"
66
+ },
67
+ "engines": {
68
+ "node": ">=22"
69
+ },
70
+ "packageManager": "pnpm@11.18.0"
71
+ }
@@ -0,0 +1,78 @@
1
+ // Convex control-plane credentials for the provider.
2
+ //
3
+ // The service value is an Effect so that building the providers layer never
4
+ // touches the environment or the filesystem. The token is read on the first
5
+ // lifecycle call, which keeps `alchemy plan` on an unrelated stack free of
6
+ // Convex credential errors.
7
+ import { readFile } from "node:fs/promises";
8
+ import { homedir } from "node:os";
9
+ import { join } from "node:path";
10
+ import * as Config from "effect/Config";
11
+ import * as Context from "effect/Context";
12
+ import * as Effect from "effect/Effect";
13
+ import * as Layer from "effect/Layer";
14
+ import * as Redacted from "effect/Redacted";
15
+ import * as Schema from "effect/Schema";
16
+
17
+ export interface ResolvedCredentials {
18
+ /** Bearer token accepted by https://api.convex.dev/v1: a team access token, an OAuth token, or the Convex CLI login. */
19
+ readonly accessToken: Redacted.Redacted<string>;
20
+ /** Where the token came from, for error messages only. */
21
+ readonly source: "env" | "explicit" | "convex-cli-login";
22
+ }
23
+
24
+ export class Credentials extends Context.Service<Credentials, Effect.Effect<ResolvedCredentials>>()(
25
+ "@samebase/alchemy-convex/Credentials",
26
+ ) {}
27
+
28
+ /** Environment variable read by {@link fromConfig}. */
29
+ export const ACCESS_TOKEN_ENV = "CONVEX_ACCESS_TOKEN";
30
+
31
+ /** The Convex CLI stores its device login here after `npx convex login`. */
32
+ export const convexCliConfigPath = () => join(homedir(), ".convex", "config.json");
33
+
34
+ const CliConfig = Schema.Struct({ accessToken: Schema.String });
35
+
36
+ /**
37
+ * Token the Convex CLI saved on this machine. It works on the Management API
38
+ * for the teams the logged-in user belongs to. Fails when nobody is logged in.
39
+ */
40
+ export const readConvexCliLogin: Effect.Effect<ResolvedCredentials, CredentialsError> = Effect.gen(
41
+ function* () {
42
+ const path = convexCliConfigPath();
43
+ const text = yield* Effect.tryPromise({
44
+ try: () => readFile(path, "utf8"),
45
+ catch: () => new CredentialsError({ reason: `no Convex CLI login at ${path}` }),
46
+ });
47
+ const parsed = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(CliConfig))(text).pipe(
48
+ Effect.mapError(() => new CredentialsError({ reason: `${path} has no accessToken` })),
49
+ );
50
+ return { accessToken: Redacted.make(parsed.accessToken), source: "convex-cli-login" } as const;
51
+ },
52
+ );
53
+
54
+ export class CredentialsError extends Schema.TaggedError<CredentialsError>()("CredentialsError", {
55
+ reason: Schema.String,
56
+ }) {}
57
+
58
+ /**
59
+ * Default resolution: `CONVEX_ACCESS_TOKEN` from the stack ConfigProvider
60
+ * (process env, `.env`, stack secrets), then the Convex CLI login on this
61
+ * machine. CI sets the variable; a developer who ran `npx convex login` needs
62
+ * nothing.
63
+ */
64
+ export const fromConfig = (): Layer.Layer<Credentials> =>
65
+ Layer.succeed(
66
+ Credentials,
67
+ Effect.cached(
68
+ Config.Redacted(ACCESS_TOKEN_ENV).pipe(
69
+ Effect.map((accessToken): ResolvedCredentials => ({ accessToken, source: "env" })),
70
+ Effect.catch(() => readConvexCliLogin),
71
+ Effect.orDie,
72
+ ),
73
+ ).pipe(Effect.flatten),
74
+ );
75
+
76
+ /** Explicit token, for tests or callers that already hold a value. */
77
+ export const fromToken = (accessToken: Redacted.Redacted<string>): Layer.Layer<Credentials> =>
78
+ Layer.succeed(Credentials, Effect.succeed({ accessToken, source: "explicit" } as const));