alchemy 0.73.0 → 0.74.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 (98) hide show
  1. package/bin/alchemy.js +3326 -4424
  2. package/bin/alchemy.ts +2 -0
  3. package/bin/commands/configure.ts +4 -1
  4. package/bin/commands/util.ts +510 -0
  5. package/bin/services/execute-alchemy.ts +2 -1
  6. package/bin/trpc.ts +22 -16
  7. package/lib/cloudflare/bound.d.ts +1 -1
  8. package/lib/cloudflare/bound.d.ts.map +1 -1
  9. package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -1
  10. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +6 -14
  11. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -1
  12. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
  13. package/lib/cloudflare/miniflare/remote-binding-proxy.js +12 -4
  14. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
  15. package/lib/cloudflare/tanstack-start/tanstack-start.d.ts.map +1 -1
  16. package/lib/cloudflare/tanstack-start/tanstack-start.js +8 -1
  17. package/lib/cloudflare/tanstack-start/tanstack-start.js.map +1 -1
  18. package/lib/cloudflare/vite/plugin.d.ts.map +1 -1
  19. package/lib/cloudflare/vite/plugin.js +23 -9
  20. package/lib/cloudflare/vite/plugin.js.map +1 -1
  21. package/lib/planetscale/branch.d.ts +6 -0
  22. package/lib/planetscale/branch.d.ts.map +1 -1
  23. package/lib/planetscale/branch.js +2 -1
  24. package/lib/planetscale/branch.js.map +1 -1
  25. package/lib/planetscale/database.d.ts +6 -0
  26. package/lib/planetscale/database.d.ts.map +1 -1
  27. package/lib/planetscale/database.js +2 -1
  28. package/lib/planetscale/database.js.map +1 -1
  29. package/lib/planetscale/password.d.ts +6 -0
  30. package/lib/planetscale/password.d.ts.map +1 -1
  31. package/lib/planetscale/password.js +2 -1
  32. package/lib/planetscale/password.js.map +1 -1
  33. package/lib/planetscale/role.d.ts +6 -0
  34. package/lib/planetscale/role.d.ts.map +1 -1
  35. package/lib/planetscale/role.js +2 -1
  36. package/lib/planetscale/role.js.map +1 -1
  37. package/lib/prisma-postgres/api/client.gen.d.ts +13 -0
  38. package/lib/prisma-postgres/api/client.gen.d.ts.map +1 -0
  39. package/lib/prisma-postgres/api/client.gen.js +6 -0
  40. package/lib/prisma-postgres/api/client.gen.js.map +1 -0
  41. package/lib/prisma-postgres/api/sdk.gen.d.ts +120 -0
  42. package/lib/prisma-postgres/api/sdk.gen.d.ts.map +1 -0
  43. package/lib/prisma-postgres/api/sdk.gen.js +219 -0
  44. package/lib/prisma-postgres/api/sdk.gen.js.map +1 -0
  45. package/lib/prisma-postgres/api/types.gen.d.ts +957 -0
  46. package/lib/prisma-postgres/api/types.gen.d.ts.map +1 -0
  47. package/lib/prisma-postgres/api/types.gen.js +2 -0
  48. package/lib/prisma-postgres/api/types.gen.js.map +1 -0
  49. package/lib/prisma-postgres/api.d.ts +29 -0
  50. package/lib/prisma-postgres/api.d.ts.map +1 -0
  51. package/lib/prisma-postgres/api.js +49 -0
  52. package/lib/prisma-postgres/api.js.map +1 -0
  53. package/lib/prisma-postgres/connection.d.ts +87 -0
  54. package/lib/prisma-postgres/connection.d.ts.map +1 -0
  55. package/lib/prisma-postgres/connection.js +73 -0
  56. package/lib/prisma-postgres/connection.js.map +1 -0
  57. package/lib/prisma-postgres/database.d.ts +104 -0
  58. package/lib/prisma-postgres/database.d.ts.map +1 -0
  59. package/lib/prisma-postgres/database.js +88 -0
  60. package/lib/prisma-postgres/database.js.map +1 -0
  61. package/lib/prisma-postgres/index.d.ts +5 -0
  62. package/lib/prisma-postgres/index.d.ts.map +1 -0
  63. package/lib/prisma-postgres/index.js +5 -0
  64. package/lib/prisma-postgres/index.js.map +1 -0
  65. package/lib/prisma-postgres/project.d.ts +69 -0
  66. package/lib/prisma-postgres/project.d.ts.map +1 -0
  67. package/lib/prisma-postgres/project.js +62 -0
  68. package/lib/prisma-postgres/project.js.map +1 -0
  69. package/lib/prisma-postgres/workspace.d.ts +18 -0
  70. package/lib/prisma-postgres/workspace.d.ts.map +1 -0
  71. package/lib/prisma-postgres/workspace.js +21 -0
  72. package/lib/prisma-postgres/workspace.js.map +1 -0
  73. package/lib/util/http.d.ts +5 -2
  74. package/lib/util/http.d.ts.map +1 -1
  75. package/lib/util/http.js +71 -26
  76. package/lib/util/http.js.map +1 -1
  77. package/package.json +9 -1
  78. package/src/cloudflare/bound.ts +3 -1
  79. package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +10 -13
  80. package/src/cloudflare/miniflare/remote-binding-proxy.ts +12 -4
  81. package/src/cloudflare/tanstack-start/tanstack-start.ts +9 -1
  82. package/src/cloudflare/vite/plugin.ts +24 -10
  83. package/src/planetscale/branch.ts +9 -1
  84. package/src/planetscale/database.ts +9 -1
  85. package/src/planetscale/password.ts +9 -1
  86. package/src/planetscale/role.ts +9 -1
  87. package/src/prisma-postgres/api/client.gen.ts +27 -0
  88. package/src/prisma-postgres/api/sdk.gen.ts +437 -0
  89. package/src/prisma-postgres/api/types.gen.ts +1096 -0
  90. package/src/prisma-postgres/api.ts +79 -0
  91. package/src/prisma-postgres/connection.ts +154 -0
  92. package/src/prisma-postgres/database.ts +178 -0
  93. package/src/prisma-postgres/index.ts +4 -0
  94. package/src/prisma-postgres/project.ts +131 -0
  95. package/src/prisma-postgres/workspace.ts +27 -0
  96. package/src/util/http.ts +79 -33
  97. package/workers/cloudflare-state-store.js +1 -1
  98. package/workers/tunnel-proxy.js +1 -1
@@ -0,0 +1,79 @@
1
+ import type { Secret } from "../secret.ts";
2
+ import { createClient } from "../util/api/client/client.gen.ts";
3
+ import type { ClientOptions } from "../util/api/client/types.gen.ts";
4
+ import { createConfig } from "../util/api/client/utils.gen.ts";
5
+ import { PrismaClient } from "./api/sdk.gen.ts";
6
+
7
+ export interface PrismaApiOptions {
8
+ /**
9
+ * The service token to use for the API
10
+ */
11
+ serviceToken?: Secret<string>;
12
+ }
13
+
14
+ export class PrismaApi extends Error {
15
+ status: number;
16
+ method: string;
17
+ url: string;
18
+ code: string;
19
+
20
+ constructor(props: {
21
+ error: {
22
+ status?: number;
23
+ error?: string;
24
+ };
25
+ request: Request;
26
+ response: Response;
27
+ }) {
28
+ const { status, error } = props.error;
29
+ super(
30
+ `A request to the Prisma API failed (${props.response.status}): ${error}`,
31
+ );
32
+ this.status = props.response.status;
33
+ this.method = props.request.method;
34
+ this.url = props.request.url;
35
+ this.code = status?.toString() ?? "";
36
+ Object.assign(this, props.error);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Create a PrismaApi instance with environment variable fallback
42
+ * @param options API options
43
+ * @returns PrismaApi instance
44
+ */
45
+ export function createPrismaApi(
46
+ options: Partial<PrismaApiOptions> = {},
47
+ ): PrismaClient {
48
+ const serviceToken =
49
+ options.serviceToken?.unencrypted ?? process.env.PRISMA_SERVICE_TOKEN;
50
+ if (!serviceToken) {
51
+ throw new Error("PRISMA_SERVICE_TOKEN is not set");
52
+ }
53
+ const client = createClient(
54
+ createConfig<ClientOptions>({
55
+ baseUrl: "https://api.prisma.io",
56
+ throwOnError: true,
57
+ headers: {
58
+ Authorization: `Bearer ${serviceToken}`,
59
+ },
60
+ }),
61
+ );
62
+
63
+ client.interceptors.error.use((error, response, request, options) => {
64
+ if (options.throwOnError !== false) {
65
+ throw new PrismaApi({
66
+ error: error as {
67
+ status?: number;
68
+ error?: string;
69
+ },
70
+ request,
71
+ response,
72
+ });
73
+ }
74
+ });
75
+
76
+ return new PrismaClient({
77
+ client,
78
+ });
79
+ }
@@ -0,0 +1,154 @@
1
+ import type { Context } from "../context.ts";
2
+ import { Resource } from "../resource.ts";
3
+ import { secret, type Secret } from "../secret.ts";
4
+ import { createPrismaApi } from "./api.ts";
5
+ import type { Database } from "./database.ts";
6
+
7
+ export interface ConnectionProps {
8
+ /**
9
+ * Database (id or resource) the connection belongs to
10
+ */
11
+ database: Database | string;
12
+
13
+ /**
14
+ * The name of the connection
15
+ */
16
+ name?: string;
17
+
18
+ /**
19
+ * The service token to use for the API
20
+ */
21
+ serviceToken?: Secret<string>;
22
+ }
23
+
24
+ export interface Connection {
25
+ /**
26
+ * The prisma id of the connection
27
+ */
28
+ id: string;
29
+
30
+ /**
31
+ * The name of the connection
32
+ */
33
+ name: string;
34
+
35
+ /**
36
+ * The timestamp of the connection creation
37
+ */
38
+ createdAt: string;
39
+
40
+ /**
41
+ * The prisma connection string (prefixed with `prisma+postgres://`)
42
+ */
43
+ prismaConnectionString: Secret<string>;
44
+
45
+ /**
46
+ * The connection string
47
+ */
48
+ connectionString: Secret<string>;
49
+
50
+ /**
51
+ * The prisma id of the database the connection belongs to
52
+ */
53
+ database: string;
54
+
55
+ /**
56
+ * The host of the connection
57
+ */
58
+ host: string | null;
59
+
60
+ /**
61
+ * The password of the connection
62
+ */
63
+ password: Secret<string> | null;
64
+
65
+ /**
66
+ * The user of the connection
67
+ */
68
+ user: string | null;
69
+ }
70
+
71
+ /**
72
+ * Creates and manages Prisma Postgres database connections.
73
+ *
74
+ * Prisma Postgres database connections provide secure credentials
75
+ * and connection details for accessing your databases. Connections
76
+ * belong to a Prisma Postgres database.
77
+ *
78
+ * @example
79
+ * // Create a database connection for a database
80
+ * import { Database, Connection } from "alchemy/prisma-postgres";
81
+ * const project = await Project("my-project");
82
+ * const database = await Database("my-database", { project });
83
+ * const connection = await Connection("my-connection", {
84
+ * database: database,
85
+ * });
86
+ * console.log(`Connection String: ${connection.connectionString.unencrypted}`);
87
+ *
88
+ * @example
89
+ * // Create a database connection and connect it to Cloudflare Hyperdrive
90
+ * import { Hyperdrive } from "alchemy/cloudflare";
91
+ * import { Database, Connection } from "alchemy/prisma-postgres";
92
+ * const project = await Project("my-project");
93
+ * const database = await Database("my-database", { project });
94
+ * const connection = await Connection("my-connection", {
95
+ * database: database,
96
+ * });
97
+ * const db = await Hyperdrive("prisma-postgres", {
98
+ * origin: connection.connectionString.unencrypted,
99
+ * });
100
+ */
101
+ export const Connection = Resource(
102
+ "prisma::Connection",
103
+ async function (
104
+ this: Context<Connection>,
105
+ id: string,
106
+ props: ConnectionProps,
107
+ ): Promise<Connection> {
108
+ const api = createPrismaApi({
109
+ serviceToken: props.serviceToken,
110
+ });
111
+ const name =
112
+ props.name ?? this.output?.name ?? this.scope.createPhysicalName(id);
113
+ const database =
114
+ typeof props.database === "string" ? props.database : props.database.id;
115
+
116
+ if (this.phase === "delete") {
117
+ await api.deleteDatabaseConnectionString({
118
+ path: {
119
+ id: this.output.id,
120
+ },
121
+ });
122
+ return this.destroy();
123
+ }
124
+
125
+ if (this.phase === "update") {
126
+ return this.replace();
127
+ }
128
+
129
+ const connection = await api
130
+ .createDatabaseConnectionString({
131
+ path: {
132
+ databaseId: database,
133
+ },
134
+ body: {
135
+ name,
136
+ },
137
+ })
138
+ .then((response) => response.data.data);
139
+
140
+ return {
141
+ id: connection.id,
142
+ name: connection.name,
143
+ createdAt: connection.createdAt,
144
+ prismaConnectionString: secret(connection.connectionString),
145
+ connectionString: secret(
146
+ `postgres://${connection.user}:${connection.pass}@${connection.host}/${connection.database}`,
147
+ ),
148
+ database: database,
149
+ host: connection.host,
150
+ password: connection.pass ? secret(connection.pass) : null,
151
+ user: connection.user,
152
+ };
153
+ },
154
+ );
@@ -0,0 +1,178 @@
1
+ import type { Context } from "../context.ts";
2
+ import { Resource } from "../resource.ts";
3
+ import type { Secret } from "../secret.ts";
4
+ import { createPrismaApi } from "./api.ts";
5
+ import type { CreateDatabaseData } from "./api/types.gen.ts";
6
+ import type { Project } from "./project.ts";
7
+
8
+ export interface DatabaseProps {
9
+ /**
10
+ * The name of the database
11
+ */
12
+
13
+ project: Project | string;
14
+ /**
15
+ * The region to create the database in
16
+ */
17
+
18
+ name?: string;
19
+ /**
20
+ * The project to create the database in
21
+ */
22
+
23
+ region?:
24
+ | "us-east-1"
25
+ | "us-west-1"
26
+ | "eu-west-3"
27
+ | "eu-central-1"
28
+ | "ap-northeast-1"
29
+ | "ap-southeast-1"
30
+ | (string & {});
31
+
32
+ /**
33
+ * Whether to delete the database if the resource is deleted
34
+ *
35
+ * @default false
36
+ */
37
+ delete?: boolean;
38
+
39
+ /**
40
+ * The service token to use for the API
41
+ */
42
+ serviceToken?: Secret<string>;
43
+ }
44
+
45
+ export interface Database {
46
+ /**
47
+ * The prisma id of the database
48
+ */
49
+ id: string;
50
+
51
+ /**
52
+ * The name of the database
53
+ */
54
+ name: string;
55
+
56
+ /**
57
+ * The status of the database
58
+ */
59
+ status: "failure" | "provisioning" | "ready" | "recovering";
60
+
61
+ /**
62
+ * The region of the database
63
+ */
64
+ region?: string;
65
+
66
+ /**
67
+ * The timestamp of the database creation
68
+ */
69
+ createdAt: string;
70
+
71
+ /**
72
+ * The prisma id of the project the database belongs to
73
+ */
74
+ project: string;
75
+ }
76
+
77
+ /**
78
+ * Creates and manages Prisma Postgres databases.
79
+ *
80
+ * Prisma Postgres databases are fully managed PostgreSQL instances
81
+ * that can be connected to applications. Databases belong to a
82
+ * Prisma Postgres project.
83
+ *
84
+ * @example
85
+ * // Create a database for a project
86
+ * import { Project, Database } from "alchemy/prisma-postgres";
87
+ * const project = await Project("my-app");
88
+ * const database = await Database("my-database", {
89
+ * project: project,
90
+ * });
91
+ *
92
+ * @example
93
+ * // Create a database in the asia pacific region
94
+ * import { Project, Database } from "alchemy/prisma-postgres";
95
+ * const project = await Project("my-app");
96
+ * const database = await Database("my-database", {
97
+ * project: project,
98
+ * region: "ap-northeast-1",
99
+ * });
100
+ *
101
+ * @example
102
+ * // Create a database and fully delete on destroy
103
+ * import { Project, Database } from "alchemy/prisma-postgres";
104
+ * const project = await Project("my-app");
105
+ * const database = await Database("my-database", {
106
+ * project: project,
107
+ * delete: true,
108
+ * });
109
+ */
110
+ export const Database = Resource(
111
+ "prisma::Database",
112
+ async function (
113
+ this: Context<Database>,
114
+ id: string,
115
+ props: DatabaseProps,
116
+ ): Promise<Database> {
117
+ const api = createPrismaApi({
118
+ serviceToken: props.serviceToken,
119
+ });
120
+ const name =
121
+ props.name ?? this.output?.name ?? this.scope.createPhysicalName(id);
122
+ const shouldDelete = props.delete ?? false;
123
+ const project =
124
+ typeof props.project === "string" ? props.project : props.project.id;
125
+
126
+ if (this.phase === "delete") {
127
+ if (shouldDelete) {
128
+ await api.deleteDatabase({
129
+ path: { databaseId: this.output.id },
130
+ });
131
+ }
132
+ return this.destroy();
133
+ }
134
+
135
+ if (this.phase === "update") {
136
+ return this.replace();
137
+ }
138
+
139
+ const database = await api
140
+ .createDatabase({
141
+ path: {
142
+ projectId: project,
143
+ },
144
+ body: {
145
+ isDefault: false,
146
+ name,
147
+ region: props.region,
148
+ } as CreateDatabaseData["body"],
149
+ })
150
+ .then((response) => response.data.data);
151
+
152
+ return {
153
+ id: database.id,
154
+ name: database.name,
155
+ region: database.region?.id,
156
+ status: database.status,
157
+ createdAt: database.createdAt,
158
+ project,
159
+ };
160
+ },
161
+ );
162
+
163
+ export async function findDatabaseByName(props: DatabaseProps) {
164
+ const api = createPrismaApi({
165
+ serviceToken: props.serviceToken,
166
+ });
167
+
168
+ const project =
169
+ typeof props.project === "string" ? props.project : props.project.id;
170
+
171
+ const databases = await api.listDatabases({
172
+ path: {
173
+ projectId: project,
174
+ },
175
+ });
176
+ const database = databases.data.data.find((db) => db.name === props.name);
177
+ return database;
178
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./connection.ts";
2
+ export * from "./database.ts";
3
+ export * from "./project.ts";
4
+ export * from "./workspace.ts";
@@ -0,0 +1,131 @@
1
+ import type { Context } from "../context.ts";
2
+ import { Resource } from "../resource.ts";
3
+ import type { Secret } from "../secret.ts";
4
+ import { createPrismaApi } from "./api.ts";
5
+
6
+ export interface ProjectProps {
7
+ /**
8
+ * The name of the project
9
+ */
10
+ name?: string;
11
+
12
+ /**
13
+ * Whether to delete the project if the resource is deleted
14
+ *
15
+ * @default false
16
+ */
17
+ delete?: boolean;
18
+
19
+ /**
20
+ * The service token to use for the API
21
+ */
22
+ serviceToken?: Secret<string>;
23
+ }
24
+
25
+ export interface Project {
26
+ /**
27
+ * The prisma id of the project
28
+ */
29
+ id: string;
30
+
31
+ /**
32
+ * The name of the project
33
+ */
34
+ name: string;
35
+
36
+ /**
37
+ * The timestamp of the project creation
38
+ */
39
+ createdAt: string;
40
+
41
+ /**
42
+ * The workspace the project belongs to
43
+ */
44
+ workspace: {
45
+ /**
46
+ * The prisma id of the workspace
47
+ */
48
+ id: string;
49
+
50
+ /**
51
+ * The name of the workspace
52
+ */
53
+ name: string;
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Creates and manages Prisma Postgres projects.
59
+ *
60
+ * Prisma Postgres projects are containers for your databases and
61
+ * their configurations. Projects belong to a workspace and can
62
+ * contain multiple databases.
63
+ *
64
+ * @example
65
+ * // Create a database for a project
66
+ * import { Project, Database } from "alchemy/prisma-postgres";
67
+ * const project = await Project("my-app");
68
+ */
69
+ export const Project = Resource(
70
+ "prisma::Project",
71
+ async function (
72
+ this: Context<Project>,
73
+ id: string,
74
+ props?: ProjectProps,
75
+ ): Promise<Project> {
76
+ const api = createPrismaApi({
77
+ serviceToken: props?.serviceToken,
78
+ });
79
+ const name =
80
+ props?.name ?? this.output?.name ?? this.scope.createPhysicalName(id);
81
+ const shouldDelete = props?.delete ?? false;
82
+
83
+ if (this.phase === "delete") {
84
+ if (shouldDelete) {
85
+ await api.deleteProject({
86
+ path: { id: this.output.id },
87
+ });
88
+ }
89
+ return this.destroy();
90
+ }
91
+ if (this.phase === "update") {
92
+ return this.replace();
93
+ }
94
+
95
+ const project = await api
96
+ .createProjectWithPostgresDatabase({
97
+ body: {
98
+ createDatabase: false,
99
+ name,
100
+ //! prisma seems to not support setting the workspace on project creation?
101
+ },
102
+ })
103
+ .then((response) => response.data.data!);
104
+
105
+ return {
106
+ id: project.id,
107
+ name: project.name,
108
+ createdAt: project.createdAt,
109
+ workspace: project.workspace,
110
+ };
111
+ },
112
+ );
113
+
114
+ export async function findProjectByName(props: ProjectProps) {
115
+ const api = createPrismaApi(props);
116
+ let hasMore = true;
117
+ let project:
118
+ | NonNullable<
119
+ Awaited<ReturnType<typeof api.listProjects>>["data"]
120
+ >["data"][number]
121
+ | undefined;
122
+ while (hasMore) {
123
+ const response = await api.listProjects();
124
+ project = response.data.data.find((project) => project.name === props.name);
125
+ if (project != null) {
126
+ break;
127
+ }
128
+ hasMore = response.data.pagination.hasMore;
129
+ }
130
+ return project;
131
+ }
@@ -0,0 +1,27 @@
1
+ import { createPrismaApi, type PrismaApiOptions } from "./api.ts";
2
+
3
+ /**
4
+ * Get a prisma workspace by id or name.
5
+ *
6
+ * @example
7
+ * const workspace = await WorkspaceRef("alchemy-test");
8
+ *
9
+ * @param identifier The id or name of the workspace to get.
10
+ * @param props The api credentials to use.
11
+ * @returns The workspace.
12
+ */
13
+ export async function WorkspaceRef(
14
+ identifier: string,
15
+ props?: PrismaApiOptions,
16
+ ) {
17
+ const api = createPrismaApi(props);
18
+
19
+ const workspaces = await api.listWorkspaces();
20
+ const workspace = workspaces.data.data.find(
21
+ (workspace) => workspace.id === identifier || workspace.name === identifier,
22
+ );
23
+ if (!workspace) {
24
+ throw new Error(`Workspace with identifier ${identifier} not found`);
25
+ }
26
+ return workspace;
27
+ }