alchemy 0.12.6 → 0.12.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cloudflare/ai-gateway.d.ts.map +1 -1
- package/lib/cloudflare/ai-gateway.js +1 -2
- package/lib/cloudflare/ai-gateway.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +2 -1
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bound.d.ts +2 -1
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/bucket.d.ts +8 -2
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +1 -1
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/d1-database.d.ts +8 -2
- package/lib/cloudflare/d1-database.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.js +2 -2
- package/lib/cloudflare/d1-database.js.map +1 -1
- package/lib/cloudflare/event-source.d.ts +26 -0
- package/lib/cloudflare/event-source.d.ts.map +1 -0
- package/lib/cloudflare/event-source.js +9 -0
- package/lib/cloudflare/event-source.js.map +1 -0
- package/lib/cloudflare/hyperdrive.d.ts +216 -0
- package/lib/cloudflare/hyperdrive.d.ts.map +1 -0
- package/lib/cloudflare/hyperdrive.js +184 -0
- package/lib/cloudflare/hyperdrive.js.map +1 -0
- package/lib/cloudflare/index.d.ts +2 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +2 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/queue-consumer.d.ts +162 -0
- package/lib/cloudflare/queue-consumer.d.ts.map +1 -0
- package/lib/cloudflare/queue-consumer.js +197 -0
- package/lib/cloudflare/queue-consumer.js.map +1 -0
- package/lib/cloudflare/queue.d.ts +15 -3
- package/lib/cloudflare/queue.d.ts.map +1 -1
- package/lib/cloudflare/queue.js +8 -2
- package/lib/cloudflare/queue.js.map +1 -1
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +8 -10
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +13 -2
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +75 -3
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +13 -3
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +27 -5
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/neon/api-error.d.ts +31 -0
- package/lib/neon/api-error.d.ts.map +1 -0
- package/lib/neon/api-error.js +73 -0
- package/lib/neon/api-error.js.map +1 -0
- package/lib/neon/api.d.ts +70 -0
- package/lib/neon/api.d.ts.map +1 -0
- package/lib/neon/api.js +128 -0
- package/lib/neon/api.js.map +1 -0
- package/lib/neon/index.d.ts +4 -0
- package/lib/neon/index.d.ts.map +1 -0
- package/lib/neon/index.js +4 -0
- package/lib/neon/index.js.map +1 -0
- package/lib/neon/project.d.ts +345 -0
- package/lib/neon/project.d.ts.map +1 -0
- package/lib/neon/project.js +305 -0
- package/lib/neon/project.js.map +1 -0
- package/package.json +2 -1
- package/src/cloudflare/ai-gateway.ts +0 -1
- package/src/cloudflare/bindings.ts +4 -2
- package/src/cloudflare/bound.ts +20 -17
- package/src/cloudflare/bucket.ts +9 -2
- package/src/cloudflare/d1-database.ts +10 -3
- package/src/cloudflare/event-source.ts +33 -0
- package/src/cloudflare/hyperdrive.ts +375 -0
- package/src/cloudflare/index.ts +2 -0
- package/src/cloudflare/queue-consumer.ts +433 -0
- package/src/cloudflare/queue.ts +83 -63
- package/src/cloudflare/website.ts +9 -13
- package/src/cloudflare/worker.ts +109 -5
- package/src/cloudflare/wrangler.json.ts +52 -8
- package/src/neon/api-error.ts +81 -0
- package/src/neon/api.ts +178 -0
- package/src/neon/index.ts +3 -0
- package/src/neon/project.ts +870 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import type { Context } from "../context.js";
|
|
2
|
+
import { Resource } from "../resource.js";
|
|
3
|
+
import type { Secret } from "../secret.js";
|
|
4
|
+
import { handleApiError } from "./api-error.js";
|
|
5
|
+
import { createCloudflareApi, type CloudflareApiOptions } from "./api.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Origin configuration for a PostgreSQL database connection
|
|
9
|
+
*/
|
|
10
|
+
export interface HyperdriveOrigin {
|
|
11
|
+
/**
|
|
12
|
+
* Database name
|
|
13
|
+
*/
|
|
14
|
+
database: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Database host
|
|
18
|
+
*/
|
|
19
|
+
host: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Database password
|
|
23
|
+
* Use alchemy.secret() to securely store this value
|
|
24
|
+
*/
|
|
25
|
+
password: Secret;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Database port
|
|
29
|
+
* @default 5432
|
|
30
|
+
*/
|
|
31
|
+
port?: number;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Connection scheme
|
|
35
|
+
* @default "postgres"
|
|
36
|
+
*/
|
|
37
|
+
scheme?: "postgres";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Database user
|
|
41
|
+
*/
|
|
42
|
+
user: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Origin configuration for a database connection with access tokens
|
|
47
|
+
*/
|
|
48
|
+
export interface HyperdriveOriginWithAccess {
|
|
49
|
+
/**
|
|
50
|
+
* Access client ID
|
|
51
|
+
*/
|
|
52
|
+
access_client_id: string;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Access client secret
|
|
56
|
+
* Use alchemy.secret() to securely store this value
|
|
57
|
+
*/
|
|
58
|
+
access_client_secret: Secret;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Database host
|
|
62
|
+
*/
|
|
63
|
+
host: string;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Database name
|
|
67
|
+
*/
|
|
68
|
+
database: string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Database port
|
|
72
|
+
* @default 5432
|
|
73
|
+
*/
|
|
74
|
+
port?: number;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Connection scheme
|
|
78
|
+
* @default "postgres"
|
|
79
|
+
*/
|
|
80
|
+
scheme?: "postgres";
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Database user
|
|
84
|
+
*/
|
|
85
|
+
user: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Caching configuration for Hyperdrive
|
|
90
|
+
*/
|
|
91
|
+
export interface HyperdriveCaching {
|
|
92
|
+
/**
|
|
93
|
+
* Whether caching is disabled
|
|
94
|
+
* @default false
|
|
95
|
+
*/
|
|
96
|
+
disabled?: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* mTLS configuration for Hyperdrive
|
|
101
|
+
*/
|
|
102
|
+
export interface HyperdriveMtls {
|
|
103
|
+
/**
|
|
104
|
+
* CA certificate ID
|
|
105
|
+
*/
|
|
106
|
+
ca_certificate_id?: string;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* mTLS certificate ID
|
|
110
|
+
*/
|
|
111
|
+
mtls_certificate_id?: string;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* SSL mode
|
|
115
|
+
* @default "verify-full"
|
|
116
|
+
*/
|
|
117
|
+
sslmode?: "verify-ca" | "verify-full";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Properties for creating or updating a Cloudflare Hyperdrive.
|
|
122
|
+
*/
|
|
123
|
+
export interface HyperdriveProps extends CloudflareApiOptions {
|
|
124
|
+
/**
|
|
125
|
+
* Name of the Hyperdrive configuration
|
|
126
|
+
*/
|
|
127
|
+
name: string;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Database connection origin configuration
|
|
131
|
+
*/
|
|
132
|
+
origin: HyperdriveOrigin | HyperdriveOriginWithAccess;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Caching configuration
|
|
136
|
+
*/
|
|
137
|
+
caching?: HyperdriveCaching;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* mTLS configuration
|
|
141
|
+
*/
|
|
142
|
+
mtls?: HyperdriveMtls;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* UUID of the hyperdrive (only used for update/delete operations)
|
|
146
|
+
* This is provided by Cloudflare and is different from the resource ID
|
|
147
|
+
* @internal
|
|
148
|
+
*/
|
|
149
|
+
hyperdriveId?: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Output returned after Cloudflare Hyperdrive creation/update.
|
|
154
|
+
* IMPORTANT: The interface name MUST match the exported resource name.
|
|
155
|
+
*/
|
|
156
|
+
export interface Hyperdrive
|
|
157
|
+
extends Resource<"cloudflare::Hyperdrive">,
|
|
158
|
+
Omit<HyperdriveProps, "origin"> {
|
|
159
|
+
/**
|
|
160
|
+
* The ID of the resource
|
|
161
|
+
*/
|
|
162
|
+
id: string;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The Cloudflare-generated UUID of the hyperdrive
|
|
166
|
+
*/
|
|
167
|
+
hyperdriveId: string;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Database connection origin configuration
|
|
171
|
+
*/
|
|
172
|
+
origin: HyperdriveOrigin | HyperdriveOriginWithAccess;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Resource type identifier for binding.
|
|
176
|
+
* @internal
|
|
177
|
+
*/
|
|
178
|
+
type: "hyperdrive";
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Represents a Cloudflare Hyperdrive configuration.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* // Create a basic Hyperdrive connection to a PostgreSQL database
|
|
186
|
+
* const basicHyperdrive = await Hyperdrive("my-postgres-db", {
|
|
187
|
+
* name: "my-postgres-db",
|
|
188
|
+
* origin: {
|
|
189
|
+
* database: "postgres",
|
|
190
|
+
* host: "database.example.com",
|
|
191
|
+
* password: alchemy.secret("your-password"),
|
|
192
|
+
* port: 5432,
|
|
193
|
+
* user: "postgres"
|
|
194
|
+
* }
|
|
195
|
+
* });
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* // Create a Hyperdrive with caching disabled
|
|
199
|
+
* const noCacheHyperdrive = await Hyperdrive("no-cache-db", {
|
|
200
|
+
* name: "no-cache-db",
|
|
201
|
+
* origin: {
|
|
202
|
+
* database: "postgres",
|
|
203
|
+
* host: "database.example.com",
|
|
204
|
+
* password: alchemy.secret(process.env.DB_PASSWORD),
|
|
205
|
+
* port: 5432,
|
|
206
|
+
* user: "postgres"
|
|
207
|
+
* },
|
|
208
|
+
* caching: {
|
|
209
|
+
* disabled: true
|
|
210
|
+
* }
|
|
211
|
+
* });
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* // Create a Hyperdrive with mTLS configuration
|
|
215
|
+
* const mtlsHyperdrive = await Hyperdrive("secure-db", {
|
|
216
|
+
* name: "secure-db",
|
|
217
|
+
* origin: {
|
|
218
|
+
* database: "postgres",
|
|
219
|
+
* host: "database.example.com",
|
|
220
|
+
* password: alchemy.secret(process.env.DB_PASSWORD),
|
|
221
|
+
* port: 5432,
|
|
222
|
+
* user: "postgres"
|
|
223
|
+
* },
|
|
224
|
+
* mtls: {
|
|
225
|
+
* ca_certificate_id: "00000000-0000-0000-0000-0000000000",
|
|
226
|
+
* mtls_certificate_id: "00000000-0000-0000-0000-0000000000",
|
|
227
|
+
* sslmode: "verify-full"
|
|
228
|
+
* }
|
|
229
|
+
* });
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* // Create a Hyperdrive with access client credentials
|
|
233
|
+
* const accessHyperdrive = await Hyperdrive("access-db", {
|
|
234
|
+
* name: "access-db",
|
|
235
|
+
* origin: {
|
|
236
|
+
* database: "postgres",
|
|
237
|
+
* host: "database.example.com",
|
|
238
|
+
* access_client_id: "client-id",
|
|
239
|
+
* access_client_secret: alchemy.secret(process.env.ACCESS_CLIENT_SECRET),
|
|
240
|
+
* port: 5432,
|
|
241
|
+
* user: "postgres"
|
|
242
|
+
* }
|
|
243
|
+
* });
|
|
244
|
+
*/
|
|
245
|
+
export const Hyperdrive = Resource(
|
|
246
|
+
"cloudflare::Hyperdrive",
|
|
247
|
+
async function (
|
|
248
|
+
this: Context<Hyperdrive>,
|
|
249
|
+
id: string,
|
|
250
|
+
props: HyperdriveProps
|
|
251
|
+
): Promise<Hyperdrive> {
|
|
252
|
+
const api = await createCloudflareApi(props);
|
|
253
|
+
const configsPath = `/accounts/${api.accountId}/hyperdrive/configs`;
|
|
254
|
+
|
|
255
|
+
// For create operations, we don't have a hyperdriveId yet
|
|
256
|
+
// For update/delete operations, we need to use the hyperdriveId from props or output
|
|
257
|
+
const hyperdriveId = props.hyperdriveId || this.output?.hyperdriveId;
|
|
258
|
+
const configPath = hyperdriveId
|
|
259
|
+
? `${configsPath}/${hyperdriveId}`
|
|
260
|
+
: `${configsPath}`;
|
|
261
|
+
|
|
262
|
+
if (this.phase === "delete") {
|
|
263
|
+
if (!hyperdriveId) {
|
|
264
|
+
console.warn(`No hyperdriveId found for ${id}, skipping delete`);
|
|
265
|
+
return this.destroy();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
const deleteResponse = await api.delete(configPath);
|
|
270
|
+
// Only swallow 404 Not Found errors, all other errors should be handled
|
|
271
|
+
if (!deleteResponse.ok && deleteResponse.status !== 404) {
|
|
272
|
+
await handleApiError(deleteResponse, "delete", "hyperdrive", id);
|
|
273
|
+
}
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.error(`Error deleting Hyperdrive ${id}:`, error);
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
return this.destroy();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
let response: Response | undefined;
|
|
282
|
+
let apiResource: any;
|
|
283
|
+
|
|
284
|
+
// Prepare request body with unwrapped secrets
|
|
285
|
+
const requestBody = prepareRequestBody(props);
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
if (this.phase === "update" && hyperdriveId) {
|
|
289
|
+
// Update existing hyperdrive
|
|
290
|
+
response = await api.put(configPath, requestBody);
|
|
291
|
+
} else {
|
|
292
|
+
// Create new hyperdrive
|
|
293
|
+
if (hyperdriveId) {
|
|
294
|
+
// If we have a hyperdriveId but we're in create phase, it could be because
|
|
295
|
+
// the resource exists but wasn't in state. Do a GET to check.
|
|
296
|
+
const getResponse = await api.get(configPath);
|
|
297
|
+
if (getResponse.status === 200) {
|
|
298
|
+
// Hyperdrive exists, update it
|
|
299
|
+
console.log(
|
|
300
|
+
`Hyperdrive '${id}' already exists. Updating existing resource.`
|
|
301
|
+
);
|
|
302
|
+
response = await api.put(configPath, requestBody);
|
|
303
|
+
} else if (getResponse.status === 404) {
|
|
304
|
+
// Hyperdrive doesn't exist, create new
|
|
305
|
+
response = await api.post(configsPath, {
|
|
306
|
+
...requestBody,
|
|
307
|
+
// Ensure name is set correctly if not already set
|
|
308
|
+
name: props.name || id,
|
|
309
|
+
});
|
|
310
|
+
} else {
|
|
311
|
+
// Unexpected error during GET check
|
|
312
|
+
await handleApiError(getResponse, "get", "hyperdrive", id);
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
// No hyperdriveId, create new
|
|
316
|
+
response = await api.post(configsPath, {
|
|
317
|
+
...requestBody,
|
|
318
|
+
// Ensure name is set correctly if not already set
|
|
319
|
+
name: props.name || id,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (!response?.ok) {
|
|
325
|
+
const action = this.phase === "update" ? "update" : "create";
|
|
326
|
+
await handleApiError(response!, action, "hyperdrive", id);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const data: { result: Record<string, any> } = await response!.json();
|
|
330
|
+
apiResource = data.result;
|
|
331
|
+
} catch (error) {
|
|
332
|
+
console.error(`Error ${this.phase} Hyperdrive '${id}':`, error);
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Construct the output object from API response and props
|
|
337
|
+
return this({
|
|
338
|
+
id,
|
|
339
|
+
hyperdriveId: apiResource.id, // Store the Cloudflare-assigned UUID
|
|
340
|
+
name: apiResource.name,
|
|
341
|
+
origin: props.origin, // Keep the original origin with secrets
|
|
342
|
+
caching: apiResource.caching,
|
|
343
|
+
mtls: apiResource.mtls,
|
|
344
|
+
type: "hyperdrive",
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Prepare the request body by unwrapping secret values
|
|
351
|
+
*/
|
|
352
|
+
function prepareRequestBody(props: HyperdriveProps): any {
|
|
353
|
+
const requestBody: any = { ...props };
|
|
354
|
+
|
|
355
|
+
// Remove internal props
|
|
356
|
+
delete requestBody.hyperdriveId;
|
|
357
|
+
|
|
358
|
+
// Deep clone and unwrap secrets in the origin object
|
|
359
|
+
if ("password" in props.origin) {
|
|
360
|
+
// Regular origin with password
|
|
361
|
+
requestBody.origin = {
|
|
362
|
+
...props.origin,
|
|
363
|
+
password: props.origin.password.unencrypted,
|
|
364
|
+
scheme: props.origin.scheme ?? "postgres",
|
|
365
|
+
};
|
|
366
|
+
} else if ("access_client_secret" in props.origin) {
|
|
367
|
+
// Origin with access client secret
|
|
368
|
+
requestBody.origin = {
|
|
369
|
+
...props.origin,
|
|
370
|
+
access_client_secret: props.origin.access_client_secret.unencrypted,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return requestBody;
|
|
375
|
+
}
|
package/src/cloudflare/index.ts
CHANGED
|
@@ -9,11 +9,13 @@ export * from "./custom-domain.js";
|
|
|
9
9
|
export * from "./d1-database.js";
|
|
10
10
|
export * from "./dns-records.js";
|
|
11
11
|
export * from "./durable-object-namespace.js";
|
|
12
|
+
export * from "./hyperdrive.js";
|
|
12
13
|
export * from "./kv-namespace.js";
|
|
13
14
|
export * from "./local-dev-cloudflare-shim.js";
|
|
14
15
|
export * from "./nuxt.js";
|
|
15
16
|
export * from "./permission-groups.js";
|
|
16
17
|
export * from "./pipeline.js";
|
|
18
|
+
export * from "./queue-consumer.js";
|
|
17
19
|
export * from "./queue.js";
|
|
18
20
|
export * from "./r2-rest-state-store.js";
|
|
19
21
|
export * from "./redwood.js";
|