alchemy 0.70.2 → 0.71.1
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/README.md +1 -1
- package/bin/alchemy.js +131 -58
- package/bin/commands/init.ts +0 -10
- package/bin/services/execute-alchemy.ts +12 -3
- package/bin/trpc.ts +12 -12
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +21 -6
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +3 -1
- package/lib/apply.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +12 -2
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bindings.js.map +1 -1
- package/lib/cloudflare/bound.d.ts +3 -2
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/bucket.d.ts +6 -0
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +5 -3
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/bun-spa/bun-spa.d.ts +6 -1
- package/lib/cloudflare/bun-spa/bun-spa.d.ts.map +1 -1
- package/lib/cloudflare/bun-spa/bun-spa.js +29 -9
- package/lib/cloudflare/bun-spa/bun-spa.js.map +1 -1
- package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
- package/lib/cloudflare/compatibility-date.gen.js +1 -1
- package/lib/cloudflare/d1-database.d.ts +1 -1
- package/lib/cloudflare/d1-database.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.js +1 -1
- package/lib/cloudflare/d1-database.js.map +1 -1
- package/lib/cloudflare/health-check.d.ts +261 -0
- package/lib/cloudflare/health-check.d.ts.map +1 -0
- package/lib/cloudflare/health-check.js +277 -0
- package/lib/cloudflare/health-check.js.map +1 -0
- package/lib/cloudflare/index.d.ts +3 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +3 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/logpush-job.d.ts +349 -0
- package/lib/cloudflare/logpush-job.d.ts.map +1 -0
- package/lib/cloudflare/logpush-job.js +277 -0
- package/lib/cloudflare/logpush-job.js.map +1 -0
- package/lib/cloudflare/miniflare/build-worker-options.d.ts +1 -0
- package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/build-worker-options.js +16 -6
- package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.js +2 -0
- package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
- package/lib/cloudflare/queue-consumer.js +2 -2
- package/lib/cloudflare/queue-consumer.js.map +1 -1
- package/lib/cloudflare/worker-loader.d.ts +9 -0
- package/lib/cloudflare/worker-loader.d.ts.map +1 -0
- package/lib/cloudflare/worker-loader.js +6 -0
- package/lib/cloudflare/worker-loader.js.map +1 -0
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +6 -0
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker-subdomain.js +1 -1
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +7 -0
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +11 -8
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +18 -11
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/cloudflare/zone.js +1 -1
- package/lib/destroy.d.ts.map +1 -1
- package/lib/destroy.js +27 -0
- package/lib/destroy.js.map +1 -1
- package/lib/docker/image.js +1 -1
- package/lib/docker/image.js.map +1 -1
- package/lib/github/comment.d.ts.map +1 -1
- package/lib/github/comment.js +14 -7
- package/lib/github/comment.js.map +1 -1
- package/lib/resource.js +1 -1
- package/lib/resource.js.map +1 -1
- package/lib/scope.d.ts +6 -1
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +22 -22
- package/lib/scope.js.map +1 -1
- package/lib/state/instrumented-state-store.js +1 -1
- package/lib/state/instrumented-state-store.js.map +1 -1
- package/lib/util/cli-args.d.ts +3 -0
- package/lib/util/cli-args.d.ts.map +1 -0
- package/lib/util/cli-args.js +6 -0
- package/lib/util/cli-args.js.map +1 -0
- package/lib/util/retry.d.ts +1 -1
- package/lib/util/retry.d.ts.map +1 -1
- package/lib/util/retry.js +2 -2
- package/lib/util/retry.js.map +1 -1
- package/lib/util/telemetry.d.ts +1 -0
- package/lib/util/telemetry.d.ts.map +1 -1
- package/lib/util/telemetry.js +47 -2
- package/lib/util/telemetry.js.map +1 -1
- package/lib/util/validate-resource-id.d.ts +2 -0
- package/lib/util/validate-resource-id.d.ts.map +1 -0
- package/lib/util/validate-resource-id.js +11 -0
- package/lib/util/validate-resource-id.js.map +1 -0
- package/package.json +11 -9
- package/src/alchemy.ts +25 -11
- package/src/apply.ts +3 -1
- package/src/cloudflare/bindings.ts +13 -0
- package/src/cloudflare/bound.ts +36 -32
- package/src/cloudflare/bucket.ts +13 -4
- package/src/cloudflare/bun-spa/bun-spa.ts +42 -10
- package/src/cloudflare/compatibility-date.gen.ts +1 -1
- package/src/cloudflare/d1-database.ts +2 -2
- package/src/cloudflare/health-check.ts +617 -0
- package/src/cloudflare/index.ts +3 -0
- package/src/cloudflare/logpush-job.ts +768 -0
- package/src/cloudflare/miniflare/build-worker-options.ts +18 -6
- package/src/cloudflare/miniflare/remote-binding-proxy.ts +2 -0
- package/src/cloudflare/queue-consumer.ts +2 -2
- package/src/cloudflare/worker-loader.ts +12 -0
- package/src/cloudflare/worker-metadata.ts +5 -0
- package/src/cloudflare/worker-subdomain.ts +1 -1
- package/src/cloudflare/worker.ts +8 -0
- package/src/cloudflare/wrangler.json.ts +36 -23
- package/src/cloudflare/zone.ts +1 -1
- package/src/destroy.ts +32 -0
- package/src/docker/image.ts +1 -1
- package/src/github/comment.ts +17 -8
- package/src/resource.ts +1 -1
- package/src/scope.ts +32 -25
- package/src/state/instrumented-state-store.ts +1 -1
- package/src/util/cli-args.ts +11 -0
- package/src/util/retry.ts +2 -1
- package/src/util/telemetry.ts +68 -2
- package/src/util/validate-resource-id.ts +10 -0
- package/workers/tunnel-proxy.js +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as miniflare from "miniflare";
|
|
2
|
+
import path from "pathe";
|
|
2
3
|
import { assertNever } from "../../util/assert-never.ts";
|
|
3
4
|
import type { HTTPServer } from "../../util/http.ts";
|
|
4
5
|
import { logger } from "../../util/logger.ts";
|
|
@@ -26,6 +27,7 @@ export interface MiniflareWorkerInput {
|
|
|
26
27
|
bundle: WorkerBundleSource;
|
|
27
28
|
port: number | undefined;
|
|
28
29
|
tunnel: boolean | undefined;
|
|
30
|
+
cwd: string;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
type RemoteOnlyBindingType =
|
|
@@ -78,11 +80,6 @@ export const buildWorkerOptions = async (
|
|
|
78
80
|
proxy: true,
|
|
79
81
|
},
|
|
80
82
|
],
|
|
81
|
-
containerEngine: {
|
|
82
|
-
localDocker: {
|
|
83
|
-
socketPath: await getDockerSocketPath(),
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
83
|
// This exposes the worker as a route that can be accessed by setting the MF-Route-Override header.
|
|
87
84
|
routes: [input.name],
|
|
88
85
|
};
|
|
@@ -119,7 +116,7 @@ export const buildWorkerOptions = async (
|
|
|
119
116
|
case "assets": {
|
|
120
117
|
options.assets = {
|
|
121
118
|
binding: key,
|
|
122
|
-
directory: binding.path,
|
|
119
|
+
directory: path.resolve(input.cwd, binding.path),
|
|
123
120
|
assetConfig: {
|
|
124
121
|
html_handling: input.assets?.html_handling,
|
|
125
122
|
not_found_handling: input.assets?.not_found_handling,
|
|
@@ -144,6 +141,11 @@ export const buildWorkerOptions = async (
|
|
|
144
141
|
imageName: binding.image.imageRef,
|
|
145
142
|
},
|
|
146
143
|
};
|
|
144
|
+
options.containerEngine = {
|
|
145
|
+
localDocker: {
|
|
146
|
+
socketPath: await getDockerSocketPath(),
|
|
147
|
+
},
|
|
148
|
+
};
|
|
147
149
|
break;
|
|
148
150
|
}
|
|
149
151
|
case "d1": {
|
|
@@ -268,6 +270,10 @@ export const buildWorkerOptions = async (
|
|
|
268
270
|
type: "r2_bucket",
|
|
269
271
|
name: key,
|
|
270
272
|
bucket_name: binding.name,
|
|
273
|
+
jurisdiction:
|
|
274
|
+
binding.jurisdiction === "default"
|
|
275
|
+
? undefined
|
|
276
|
+
: binding.jurisdiction,
|
|
271
277
|
raw: true,
|
|
272
278
|
});
|
|
273
279
|
} else {
|
|
@@ -308,6 +314,10 @@ export const buildWorkerOptions = async (
|
|
|
308
314
|
};
|
|
309
315
|
break;
|
|
310
316
|
}
|
|
317
|
+
case "worker_loader": {
|
|
318
|
+
(options.workerLoaders ??= {})[key] = {};
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
311
321
|
case "workflow": {
|
|
312
322
|
(options.workflows ??= {})[key] = {
|
|
313
323
|
name: binding.workflowName,
|
|
@@ -329,11 +339,13 @@ export const buildWorkerOptions = async (
|
|
|
329
339
|
);
|
|
330
340
|
}
|
|
331
341
|
if (isQueueEventSource(eventSource)) {
|
|
342
|
+
const dlq = eventSource.settings?.deadLetterQueue;
|
|
332
343
|
(options.queueConsumers ??= {})[queue.name] = {
|
|
333
344
|
maxBatchSize: eventSource.settings?.batchSize,
|
|
334
345
|
maxBatchTimeout: eventSource.settings?.maxWaitTimeMs,
|
|
335
346
|
maxRetries: eventSource.settings?.maxRetries,
|
|
336
347
|
retryDelay: eventSource.settings?.retryDelay,
|
|
348
|
+
deadLetterQueue: typeof dlq === "string" ? dlq : dlq?.name,
|
|
337
349
|
};
|
|
338
350
|
} else {
|
|
339
351
|
(options.queueConsumers ??= {})[eventSource.name] = {};
|
|
@@ -82,6 +82,8 @@ export async function createRemoteProxyWorker(input: {
|
|
|
82
82
|
headers,
|
|
83
83
|
body: req.body,
|
|
84
84
|
redirect: "manual",
|
|
85
|
+
// @ts-expect-error - caused by @cloudflare/workers-types
|
|
86
|
+
duplex: req.body ? "half" : undefined,
|
|
85
87
|
});
|
|
86
88
|
|
|
87
89
|
const responseHeaders = new Headers(res.headers);
|
|
@@ -318,7 +318,7 @@ export async function createQueueConsumer(
|
|
|
318
318
|
typeof props.settings.deadLetterQueue === "string"
|
|
319
319
|
? props.settings.deadLetterQueue
|
|
320
320
|
: props.settings.deadLetterQueue.name;
|
|
321
|
-
createPayload.
|
|
321
|
+
createPayload.dead_letter_queue = dlqName;
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
|
|
@@ -405,7 +405,7 @@ async function updateQueueConsumer(
|
|
|
405
405
|
typeof props.settings.deadLetterQueue === "string"
|
|
406
406
|
? props.settings.deadLetterQueue
|
|
407
407
|
: props.settings.deadLetterQueue.name;
|
|
408
|
-
updatePayload.
|
|
408
|
+
updatePayload.dead_letter_queue = dlqName;
|
|
409
409
|
}
|
|
410
410
|
}
|
|
411
411
|
|
|
@@ -568,6 +568,11 @@ export async function prepareWorkerMetadata(
|
|
|
568
568
|
name: bindingName,
|
|
569
569
|
namespace: binding.namespaceName,
|
|
570
570
|
});
|
|
571
|
+
} else if (binding.type === "worker_loader") {
|
|
572
|
+
meta.bindings.push({
|
|
573
|
+
type: "worker_loader",
|
|
574
|
+
name: bindingName,
|
|
575
|
+
});
|
|
571
576
|
} else if (binding.type === "secret_key") {
|
|
572
577
|
meta.bindings.push({
|
|
573
578
|
type: "secret_key",
|
package/src/cloudflare/worker.ts
CHANGED
|
@@ -982,9 +982,11 @@ const _Worker = Resource(
|
|
|
982
982
|
bundle,
|
|
983
983
|
port: props.dev?.port,
|
|
984
984
|
tunnel: props.dev?.tunnel ?? this.scope.tunnel,
|
|
985
|
+
cwd: props.cwd ?? process.cwd(),
|
|
985
986
|
});
|
|
986
987
|
this.onCleanup(() => controller.dispose());
|
|
987
988
|
}
|
|
989
|
+
|
|
988
990
|
await provisionResources(
|
|
989
991
|
{
|
|
990
992
|
...props,
|
|
@@ -1240,12 +1242,18 @@ async function provisionResources<B extends Bindings>(
|
|
|
1240
1242
|
containers: options.containers,
|
|
1241
1243
|
domains: props.domains?.map((domain) => {
|
|
1242
1244
|
if (typeof domain === "string") {
|
|
1245
|
+
if (domain === "") {
|
|
1246
|
+
throw new Error("Domain names cannot be empty strings");
|
|
1247
|
+
}
|
|
1243
1248
|
return {
|
|
1244
1249
|
name: domain,
|
|
1245
1250
|
zoneId: undefined,
|
|
1246
1251
|
adopt: props.adopt,
|
|
1247
1252
|
};
|
|
1248
1253
|
}
|
|
1254
|
+
if (domain.domainName === "") {
|
|
1255
|
+
throw new Error("Domain names cannot be empty strings");
|
|
1256
|
+
}
|
|
1249
1257
|
return {
|
|
1250
1258
|
name: domain.domainName,
|
|
1251
1259
|
zoneId: domain.zoneId,
|
|
@@ -4,7 +4,6 @@ import type { Context } from "../context.ts";
|
|
|
4
4
|
import { Resource } from "../resource.ts";
|
|
5
5
|
import { Scope } from "../scope.ts";
|
|
6
6
|
import { isSecret } from "../secret.ts";
|
|
7
|
-
import { unencryptSecrets } from "./util/filter-env-bindings.ts";
|
|
8
7
|
import { assertNever } from "../util/assert-never.ts";
|
|
9
8
|
import type { Bindings, WorkerBindingRateLimit } from "./bindings.ts";
|
|
10
9
|
import type { R2BucketJurisdiction } from "./bucket.ts";
|
|
@@ -12,6 +11,7 @@ import type { DurableObjectNamespace } from "./durable-object-namespace.ts";
|
|
|
12
11
|
import type { EventSource } from "./event-source.ts";
|
|
13
12
|
import { isQueueEventSource } from "./event-source.ts";
|
|
14
13
|
import { isQueue } from "./queue.ts";
|
|
14
|
+
import { unencryptSecrets } from "./util/filter-env-bindings.ts";
|
|
15
15
|
import { isWorker, type Worker, type WorkerProps } from "./worker.ts";
|
|
16
16
|
|
|
17
17
|
type WranglerJsonRateLimit = Omit<WorkerBindingRateLimit, "type"> & {
|
|
@@ -301,7 +301,7 @@ export interface WranglerJsonSpec {
|
|
|
301
301
|
*/
|
|
302
302
|
ai?: {
|
|
303
303
|
binding: string;
|
|
304
|
-
|
|
304
|
+
remote?: boolean;
|
|
305
305
|
};
|
|
306
306
|
|
|
307
307
|
/**
|
|
@@ -309,7 +309,7 @@ export interface WranglerJsonSpec {
|
|
|
309
309
|
*/
|
|
310
310
|
browser?: {
|
|
311
311
|
binding: string;
|
|
312
|
-
|
|
312
|
+
remote?: boolean;
|
|
313
313
|
};
|
|
314
314
|
|
|
315
315
|
/**
|
|
@@ -317,7 +317,7 @@ export interface WranglerJsonSpec {
|
|
|
317
317
|
*/
|
|
318
318
|
images?: {
|
|
319
319
|
binding: string;
|
|
320
|
-
|
|
320
|
+
remote?: boolean;
|
|
321
321
|
};
|
|
322
322
|
|
|
323
323
|
/**
|
|
@@ -330,7 +330,7 @@ export interface WranglerJsonSpec {
|
|
|
330
330
|
* The ID of the KV namespace used during `wrangler dev`
|
|
331
331
|
*/
|
|
332
332
|
preview_id?: string;
|
|
333
|
-
|
|
333
|
+
remote?: boolean;
|
|
334
334
|
}[];
|
|
335
335
|
|
|
336
336
|
/**
|
|
@@ -355,7 +355,7 @@ export interface WranglerJsonSpec {
|
|
|
355
355
|
* The preview name of this R2 bucket at the edge.
|
|
356
356
|
*/
|
|
357
357
|
preview_bucket_name?: string;
|
|
358
|
-
|
|
358
|
+
remote?: boolean;
|
|
359
359
|
}[];
|
|
360
360
|
|
|
361
361
|
/**
|
|
@@ -376,6 +376,10 @@ export interface WranglerJsonSpec {
|
|
|
376
376
|
entrypoint?: string;
|
|
377
377
|
}[];
|
|
378
378
|
|
|
379
|
+
worker_loaders?: {
|
|
380
|
+
binding: string;
|
|
381
|
+
}[];
|
|
382
|
+
|
|
379
383
|
/**
|
|
380
384
|
* Workflow bindings
|
|
381
385
|
*/
|
|
@@ -392,7 +396,7 @@ export interface WranglerJsonSpec {
|
|
|
392
396
|
vectorize?: {
|
|
393
397
|
binding: string;
|
|
394
398
|
index_name: string;
|
|
395
|
-
|
|
399
|
+
remote?: boolean;
|
|
396
400
|
}[];
|
|
397
401
|
|
|
398
402
|
/**
|
|
@@ -412,7 +416,7 @@ export interface WranglerJsonSpec {
|
|
|
412
416
|
* The ID of the D1 database used during `wrangler dev`
|
|
413
417
|
*/
|
|
414
418
|
preview_database_id?: string;
|
|
415
|
-
|
|
419
|
+
remote?: boolean;
|
|
416
420
|
}[];
|
|
417
421
|
|
|
418
422
|
/**
|
|
@@ -495,7 +499,7 @@ export interface WranglerJsonSpec {
|
|
|
495
499
|
dispatch_namespaces?: {
|
|
496
500
|
binding: string;
|
|
497
501
|
namespace: string;
|
|
498
|
-
|
|
502
|
+
remote?: boolean;
|
|
499
503
|
}[];
|
|
500
504
|
|
|
501
505
|
/**
|
|
@@ -555,7 +559,7 @@ function processBindings(
|
|
|
555
559
|
binding: string;
|
|
556
560
|
id: string;
|
|
557
561
|
preview_id: string;
|
|
558
|
-
|
|
562
|
+
remote?: boolean;
|
|
559
563
|
}[] = [];
|
|
560
564
|
const durableObjects: {
|
|
561
565
|
name: string;
|
|
@@ -588,7 +592,7 @@ function processBindings(
|
|
|
588
592
|
database_name: string;
|
|
589
593
|
migrations_dir?: string;
|
|
590
594
|
preview_database_id: string;
|
|
591
|
-
|
|
595
|
+
remote?: boolean;
|
|
592
596
|
}[] = [];
|
|
593
597
|
const queues: {
|
|
594
598
|
producers: { queue: string; binding: string }[];
|
|
@@ -604,7 +608,7 @@ function processBindings(
|
|
|
604
608
|
const vectorizeIndexes: {
|
|
605
609
|
binding: string;
|
|
606
610
|
index_name: string;
|
|
607
|
-
|
|
611
|
+
remote?: boolean;
|
|
608
612
|
}[] = [];
|
|
609
613
|
const analyticsEngineDatasets: { binding: string; dataset: string }[] = [];
|
|
610
614
|
const hyperdrive: {
|
|
@@ -621,12 +625,15 @@ function processBindings(
|
|
|
621
625
|
const dispatchNamespaces: {
|
|
622
626
|
binding: string;
|
|
623
627
|
namespace: string;
|
|
624
|
-
|
|
628
|
+
remote?: boolean;
|
|
625
629
|
}[] = [];
|
|
626
630
|
const unsafeBindings: WranglerJsonRateLimit[] = [];
|
|
627
631
|
const containers: {
|
|
628
632
|
class_name: string;
|
|
629
633
|
}[] = [];
|
|
634
|
+
const workerLoaders: {
|
|
635
|
+
binding: string;
|
|
636
|
+
}[] = [];
|
|
630
637
|
|
|
631
638
|
for (const eventSource of eventSources ?? []) {
|
|
632
639
|
if (isQueueEventSource(eventSource)) {
|
|
@@ -686,9 +693,7 @@ function processBindings(
|
|
|
686
693
|
binding: bindingName,
|
|
687
694
|
id: id,
|
|
688
695
|
preview_id: id,
|
|
689
|
-
...("dev" in binding && binding.dev?.remote
|
|
690
|
-
? { experimental_remote: true }
|
|
691
|
-
: {}),
|
|
696
|
+
...("dev" in binding && binding.dev?.remote ? { remote: true } : {}),
|
|
692
697
|
});
|
|
693
698
|
} else if (
|
|
694
699
|
typeof binding === "object" &&
|
|
@@ -718,7 +723,7 @@ function processBindings(
|
|
|
718
723
|
preview_bucket_name: name,
|
|
719
724
|
jurisdiction:
|
|
720
725
|
binding.jurisdiction === "default" ? undefined : binding.jurisdiction,
|
|
721
|
-
...(binding.dev?.remote ? {
|
|
726
|
+
...(binding.dev?.remote ? { remote: true } : {}),
|
|
722
727
|
});
|
|
723
728
|
} else if (binding.type === "secret") {
|
|
724
729
|
// Secret binding
|
|
@@ -746,7 +751,7 @@ function processBindings(
|
|
|
746
751
|
database_name: binding.name,
|
|
747
752
|
migrations_dir: binding.migrationsDir,
|
|
748
753
|
preview_database_id: id,
|
|
749
|
-
...(binding.dev?.remote ? {
|
|
754
|
+
...(binding.dev?.remote ? { remote: true } : {}),
|
|
750
755
|
});
|
|
751
756
|
} else if (binding.type === "queue") {
|
|
752
757
|
const id =
|
|
@@ -762,7 +767,7 @@ function processBindings(
|
|
|
762
767
|
binding: bindingName,
|
|
763
768
|
index_name: binding.name,
|
|
764
769
|
// https://developers.cloudflare.com/workers/development-testing/#recommended-remote-bindings
|
|
765
|
-
|
|
770
|
+
remote: true,
|
|
766
771
|
});
|
|
767
772
|
} else if (binding.type === "browser") {
|
|
768
773
|
if (spec.browser) {
|
|
@@ -771,7 +776,7 @@ function processBindings(
|
|
|
771
776
|
spec.browser = {
|
|
772
777
|
binding: bindingName,
|
|
773
778
|
// https://developers.cloudflare.com/workers/development-testing/#recommended-remote-bindings
|
|
774
|
-
|
|
779
|
+
remote: true,
|
|
775
780
|
};
|
|
776
781
|
} else if (binding.type === "ai") {
|
|
777
782
|
if (spec.ai) {
|
|
@@ -780,7 +785,7 @@ function processBindings(
|
|
|
780
785
|
spec.ai = {
|
|
781
786
|
binding: bindingName,
|
|
782
787
|
// https://developers.cloudflare.com/workers/development-testing/#recommended-remote-bindings
|
|
783
|
-
|
|
788
|
+
remote: true,
|
|
784
789
|
};
|
|
785
790
|
} else if (binding.type === "images") {
|
|
786
791
|
if (spec.images) {
|
|
@@ -789,7 +794,7 @@ function processBindings(
|
|
|
789
794
|
spec.images = {
|
|
790
795
|
binding: bindingName,
|
|
791
796
|
// https://developers.cloudflare.com/workers/development-testing/#recommended-remote-bindings
|
|
792
|
-
|
|
797
|
+
remote: true,
|
|
793
798
|
};
|
|
794
799
|
} else if (binding.type === "analytics_engine") {
|
|
795
800
|
analyticsEngineDatasets.push({
|
|
@@ -830,7 +835,7 @@ function processBindings(
|
|
|
830
835
|
dispatchNamespaces.push({
|
|
831
836
|
binding: bindingName,
|
|
832
837
|
namespace: binding.namespaceName,
|
|
833
|
-
|
|
838
|
+
remote: true,
|
|
834
839
|
});
|
|
835
840
|
} else if (binding.type === "ratelimit") {
|
|
836
841
|
unsafeBindings.push({
|
|
@@ -850,6 +855,10 @@ function processBindings(
|
|
|
850
855
|
containers.push({
|
|
851
856
|
class_name: binding.className,
|
|
852
857
|
});
|
|
858
|
+
} else if (binding.type === "worker_loader") {
|
|
859
|
+
workerLoaders.push({
|
|
860
|
+
binding: bindingName,
|
|
861
|
+
});
|
|
853
862
|
} else {
|
|
854
863
|
console.log("binding", binding);
|
|
855
864
|
// biome-ignore lint/correctness/noVoidTypeReturn: it returns never
|
|
@@ -930,4 +939,8 @@ function processBindings(
|
|
|
930
939
|
bindings: unsafeBindings,
|
|
931
940
|
};
|
|
932
941
|
}
|
|
942
|
+
|
|
943
|
+
if (workerLoaders.length > 0) {
|
|
944
|
+
spec.worker_loaders = workerLoaders;
|
|
945
|
+
}
|
|
933
946
|
}
|
package/src/cloudflare/zone.ts
CHANGED
|
@@ -414,7 +414,7 @@ export const Zone = Resource(
|
|
|
414
414
|
|
|
415
415
|
// Add a small delay to ensure settings are propagated
|
|
416
416
|
// TODO(michael): do we need this?
|
|
417
|
-
// https://github.com/
|
|
417
|
+
// https://github.com/alchemy-run/alchemy/issues/681
|
|
418
418
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
419
419
|
|
|
420
420
|
// Update Bot Management configuration if provided
|
package/src/destroy.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { isScope, type PendingDeletions, Scope } from "./scope.ts";
|
|
|
14
14
|
import type { State } from "./state.ts";
|
|
15
15
|
import { formatFQN } from "./util/cli.ts";
|
|
16
16
|
import { logger } from "./util/logger.ts";
|
|
17
|
+
import { createAndSendEvent } from "./util/telemetry.ts";
|
|
17
18
|
|
|
18
19
|
export function isDestroyedSignal(error: any): error is DestroyedSignal {
|
|
19
20
|
return error instanceof Error && (error as any).kind === "DestroyedSignal";
|
|
@@ -109,6 +110,7 @@ export async function destroy(
|
|
|
109
110
|
logger.warn(`Resource "${instance[ResourceFQN]}" has no scope`);
|
|
110
111
|
}
|
|
111
112
|
const quiet = options?.quiet ?? scope.quiet;
|
|
113
|
+
const start = performance.now();
|
|
112
114
|
|
|
113
115
|
try {
|
|
114
116
|
if (!quiet && !options?.noop) {
|
|
@@ -122,6 +124,15 @@ export async function destroy(
|
|
|
122
124
|
});
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
await createAndSendEvent({
|
|
128
|
+
event: "resource.start",
|
|
129
|
+
resource: instance[ResourceKind],
|
|
130
|
+
status: "deleting",
|
|
131
|
+
phase: "destroy",
|
|
132
|
+
duration: performance.now() - start,
|
|
133
|
+
replaced: !!options?.replace,
|
|
134
|
+
});
|
|
135
|
+
|
|
125
136
|
let state: State;
|
|
126
137
|
let props: ResourceProps | undefined;
|
|
127
138
|
if (options?.replace) {
|
|
@@ -224,7 +235,28 @@ export async function destroy(
|
|
|
224
235
|
status: "success",
|
|
225
236
|
});
|
|
226
237
|
}
|
|
238
|
+
|
|
239
|
+
await createAndSendEvent({
|
|
240
|
+
event: "resource.success",
|
|
241
|
+
resource: instance[ResourceKind],
|
|
242
|
+
status: "deleted",
|
|
243
|
+
phase: "destroy",
|
|
244
|
+
duration: performance.now() - start,
|
|
245
|
+
replaced: !!options?.replace,
|
|
246
|
+
});
|
|
227
247
|
} catch (error) {
|
|
248
|
+
let errorToSend = error instanceof Error ? error : new Error(String(error));
|
|
249
|
+
await createAndSendEvent(
|
|
250
|
+
{
|
|
251
|
+
event: "resource.error",
|
|
252
|
+
resource: instance[ResourceKind],
|
|
253
|
+
duration: performance.now() - start,
|
|
254
|
+
phase: "destroy",
|
|
255
|
+
status: "deleting",
|
|
256
|
+
replaced: !!options?.replace,
|
|
257
|
+
},
|
|
258
|
+
errorToSend,
|
|
259
|
+
);
|
|
228
260
|
logger.error(error);
|
|
229
261
|
throw error;
|
|
230
262
|
}
|
package/src/docker/image.ts
CHANGED
|
@@ -190,7 +190,7 @@ export const Image = Resource(
|
|
|
190
190
|
|
|
191
191
|
// Add build arguments
|
|
192
192
|
for (const [key, value] of Object.entries(buildOptions)) {
|
|
193
|
-
buildArgs.push("--build-arg", `${key}
|
|
193
|
+
buildArgs.push("--build-arg", `${key}=${value}`);
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
buildArgs.push("-f", dockerfile);
|
package/src/github/comment.ts
CHANGED
|
@@ -173,17 +173,17 @@ export const GitHubComment = Resource(
|
|
|
173
173
|
props: GitHubCommentProps,
|
|
174
174
|
): Promise<GitHubComment> {
|
|
175
175
|
// Create authenticated Octokit client - will automatically handle token resolution
|
|
176
|
-
const octokit = await createGitHubClient({
|
|
177
|
-
token: props.token?.unencrypted,
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// Verify authentication and permissions
|
|
181
|
-
if (!this.quiet) {
|
|
182
|
-
await verifyGitHubAuth(octokit, props.owner, props.repository);
|
|
183
|
-
}
|
|
184
176
|
|
|
185
177
|
if (this.phase === "delete") {
|
|
186
178
|
if (this.output?.commentId && props.allowDelete) {
|
|
179
|
+
const octokit = await createGitHubClient({
|
|
180
|
+
token: props.token?.unencrypted,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Verify authentication and permissions
|
|
184
|
+
if (!this.quiet) {
|
|
185
|
+
await verifyGitHubAuth(octokit, props.owner, props.repository);
|
|
186
|
+
}
|
|
187
187
|
try {
|
|
188
188
|
// Delete the comment
|
|
189
189
|
await octokit.rest.issues.deleteComment({
|
|
@@ -209,6 +209,15 @@ export const GitHubComment = Resource(
|
|
|
209
209
|
return this.destroy();
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
const octokit = await createGitHubClient({
|
|
213
|
+
token: props.token?.unencrypted,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Verify authentication and permissions
|
|
217
|
+
if (!this.quiet) {
|
|
218
|
+
await verifyGitHubAuth(octokit, props.owner, props.repository);
|
|
219
|
+
}
|
|
220
|
+
|
|
212
221
|
try {
|
|
213
222
|
if (this.phase === "update" && this.output?.commentId) {
|
|
214
223
|
// Update existing comment
|
package/src/resource.ts
CHANGED
|
@@ -179,7 +179,7 @@ export function Resource<
|
|
|
179
179
|
const error = new Error(
|
|
180
180
|
`Resource ${resourceID} already exists in the stack and is of a different type: '${otherResource?.[ResourceKind]}' !== '${type}'`,
|
|
181
181
|
);
|
|
182
|
-
createAndSendEvent(
|
|
182
|
+
await createAndSendEvent(
|
|
183
183
|
{
|
|
184
184
|
event: "resource.error",
|
|
185
185
|
resource: type,
|
package/src/scope.ts
CHANGED
|
@@ -30,6 +30,7 @@ import { logger } from "./util/logger.ts";
|
|
|
30
30
|
import { AsyncMutex } from "./util/mutex.ts";
|
|
31
31
|
import { ALCHEMY_ROOT } from "./util/root-dir.ts";
|
|
32
32
|
import { createAndSendEvent } from "./util/telemetry.ts";
|
|
33
|
+
import { validateResourceID } from "./util/validate-resource-id.ts";
|
|
33
34
|
|
|
34
35
|
export class RootScopeStateAttemptError extends Error {
|
|
35
36
|
constructor() {
|
|
@@ -115,6 +116,11 @@ export interface ScopeOptions extends ProviderCredentials {
|
|
|
115
116
|
* `undefined` if the program was not run with `--app`
|
|
116
117
|
*/
|
|
117
118
|
isSelected?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* @internal
|
|
121
|
+
* The timestamp when the scope was started.
|
|
122
|
+
*/
|
|
123
|
+
startedAt?: DOMHighResTimeStamp;
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
/**
|
|
@@ -208,6 +214,7 @@ export class Scope {
|
|
|
208
214
|
public readonly dotAlchemy: string;
|
|
209
215
|
public readonly isSelected: boolean | undefined;
|
|
210
216
|
public readonly profile: string | undefined;
|
|
217
|
+
public readonly startedAt: DOMHighResTimeStamp;
|
|
211
218
|
|
|
212
219
|
// Provider credentials for scope-level credential overrides
|
|
213
220
|
public readonly providerCredentials: ProviderCredentials;
|
|
@@ -215,7 +222,6 @@ export class Scope {
|
|
|
215
222
|
private isErrored = false;
|
|
216
223
|
private isSkipped = false;
|
|
217
224
|
private finalized = false;
|
|
218
|
-
private startedAt = performance.now();
|
|
219
225
|
private deferred: (() => Promise<any>)[] = [];
|
|
220
226
|
private cleanups: (() => Promise<void>)[] = [];
|
|
221
227
|
|
|
@@ -248,6 +254,7 @@ export class Scope {
|
|
|
248
254
|
isSelected,
|
|
249
255
|
noTrack,
|
|
250
256
|
profile,
|
|
257
|
+
startedAt,
|
|
251
258
|
...providerCredentials
|
|
252
259
|
} = options;
|
|
253
260
|
|
|
@@ -256,7 +263,7 @@ export class Scope {
|
|
|
256
263
|
this.parent = parent ?? Scope.getScope();
|
|
257
264
|
this.rootDir = rootDir ?? this.parent?.rootDir ?? ALCHEMY_ROOT;
|
|
258
265
|
this.isSelected = isSelected ?? this.parent?.isSelected;
|
|
259
|
-
|
|
266
|
+
this.startedAt = startedAt ?? this.parent?.startedAt ?? performance.now();
|
|
260
267
|
this.dotAlchemy =
|
|
261
268
|
dotAlchemy ??
|
|
262
269
|
this.parent?.dotAlchemy ??
|
|
@@ -265,21 +272,17 @@ export class Scope {
|
|
|
265
272
|
// Store provider credentials (TypeScript ensures no conflicts with core options)
|
|
266
273
|
this.providerCredentials = providerCredentials as ProviderCredentials;
|
|
267
274
|
|
|
268
|
-
const isChild = this.parent !== undefined;
|
|
269
|
-
if (this.scopeName?.includes(":") && isChild) {
|
|
270
|
-
// TODO(sam): relax this constraint once we move to SQLite3 store
|
|
271
|
-
throw new Error(
|
|
272
|
-
`Scope name "${this.scopeName}" cannot contain double colons`,
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
275
|
this.stage = stage ?? this.parent?.stage ?? DEFAULT_STAGE;
|
|
277
276
|
this.profile = profile ?? this.parent?.profile;
|
|
278
277
|
this.parent?.children.set(this.scopeName!, this);
|
|
279
278
|
this.quiet = quiet ?? this.parent?.quiet ?? false;
|
|
280
|
-
if (this.parent
|
|
281
|
-
|
|
279
|
+
if (this.parent) {
|
|
280
|
+
if (!this.scopeName) {
|
|
281
|
+
throw new Error("Scope name is required when creating a child scope");
|
|
282
|
+
}
|
|
283
|
+
validateResourceID(this.scopeName, "Scope");
|
|
282
284
|
}
|
|
285
|
+
|
|
283
286
|
this.password = password ?? this.parent?.password;
|
|
284
287
|
this.noTrack = noTrack ?? this.parent?.noTrack ?? false;
|
|
285
288
|
const resolvedPhase = phase ?? this.parent?.phase;
|
|
@@ -308,7 +311,7 @@ export class Scope {
|
|
|
308
311
|
destroyStrategy ?? this.parent?.destroyStrategy ?? "sequential";
|
|
309
312
|
if (this.local) {
|
|
310
313
|
this.logger.warnOnce(
|
|
311
|
-
"Development mode is in beta. Please report any issues to https://github.com/
|
|
314
|
+
"Development mode is in beta. Please report any issues to https://github.com/alchemy-run/alchemy/issues.",
|
|
312
315
|
);
|
|
313
316
|
}
|
|
314
317
|
|
|
@@ -518,10 +521,15 @@ export class Scope {
|
|
|
518
521
|
this.parent === undefined ||
|
|
519
522
|
this?.parent?.scopeName === this.root.scopeName;
|
|
520
523
|
if (this.phase === "read") {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
524
|
+
if (this.parent == null) {
|
|
525
|
+
await createAndSendEvent(
|
|
526
|
+
{
|
|
527
|
+
event: this.isErrored ? "alchemy.error" : "alchemy.success",
|
|
528
|
+
duration: performance.now() - this.startedAt,
|
|
529
|
+
},
|
|
530
|
+
this.isErrored ? new Error("Scope failed") : undefined,
|
|
531
|
+
);
|
|
532
|
+
}
|
|
525
533
|
return;
|
|
526
534
|
}
|
|
527
535
|
if (this.finalized && !shouldForce) {
|
|
@@ -569,18 +577,17 @@ export class Scope {
|
|
|
569
577
|
force: shouldForce,
|
|
570
578
|
noop: options?.noop,
|
|
571
579
|
});
|
|
572
|
-
createAndSendEvent({
|
|
573
|
-
event: "alchemy.success",
|
|
574
|
-
duration: performance.now() - this.startedAt,
|
|
575
|
-
});
|
|
576
580
|
} else if (this.isErrored) {
|
|
577
581
|
this.logger.warn("Scope is in error, skipping finalize");
|
|
578
|
-
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (this.parent == null) {
|
|
585
|
+
await createAndSendEvent(
|
|
579
586
|
{
|
|
580
|
-
event: "alchemy.error",
|
|
587
|
+
event: this.isErrored ? "alchemy.error" : "alchemy.success",
|
|
581
588
|
duration: performance.now() - this.startedAt,
|
|
582
589
|
},
|
|
583
|
-
new Error("Scope failed"),
|
|
590
|
+
this.isErrored ? new Error("Scope failed") : undefined,
|
|
584
591
|
);
|
|
585
592
|
}
|
|
586
593
|
|
|
@@ -599,7 +606,7 @@ export class Scope {
|
|
|
599
606
|
throw e;
|
|
600
607
|
})) ?? [];
|
|
601
608
|
|
|
602
|
-
//todo(michael): remove once we deprecate doss; see: https://github.com/
|
|
609
|
+
//todo(michael): remove once we deprecate doss; see: https://github.com/alchemy-run/alchemy/issues/585
|
|
603
610
|
let hasCorruptedResources = false;
|
|
604
611
|
if (pendingDeletions) {
|
|
605
612
|
for (const { resource, oldProps } of pendingDeletions) {
|