alchemy 0.71.0 → 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 +119 -44
- 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.js +1 -1
- package/lib/apply.js.map +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 +1 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +1 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +8 -8
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +9 -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/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 +16 -15
- 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/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/package.json +10 -8
- package/src/alchemy.ts +25 -11
- package/src/apply.ts +1 -1
- package/src/cloudflare/d1-database.ts +2 -2
- package/src/cloudflare/health-check.ts +617 -0
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/wrangler.json.ts +21 -23
- package/src/cloudflare/zone.ts +1 -1
- package/src/destroy.ts +32 -0
- package/src/docker/image.ts +1 -1
- package/src/resource.ts +1 -1
- package/src/scope.ts +25 -15
- package/src/state/instrumented-state-store.ts +1 -1
- package/src/util/cli-args.ts +11 -0
- package/src/util/telemetry.ts +68 -2
- package/workers/tunnel-proxy.js +1 -1
|
@@ -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
|
/**
|
|
@@ -396,7 +396,7 @@ export interface WranglerJsonSpec {
|
|
|
396
396
|
vectorize?: {
|
|
397
397
|
binding: string;
|
|
398
398
|
index_name: string;
|
|
399
|
-
|
|
399
|
+
remote?: boolean;
|
|
400
400
|
}[];
|
|
401
401
|
|
|
402
402
|
/**
|
|
@@ -416,7 +416,7 @@ export interface WranglerJsonSpec {
|
|
|
416
416
|
* The ID of the D1 database used during `wrangler dev`
|
|
417
417
|
*/
|
|
418
418
|
preview_database_id?: string;
|
|
419
|
-
|
|
419
|
+
remote?: boolean;
|
|
420
420
|
}[];
|
|
421
421
|
|
|
422
422
|
/**
|
|
@@ -499,7 +499,7 @@ export interface WranglerJsonSpec {
|
|
|
499
499
|
dispatch_namespaces?: {
|
|
500
500
|
binding: string;
|
|
501
501
|
namespace: string;
|
|
502
|
-
|
|
502
|
+
remote?: boolean;
|
|
503
503
|
}[];
|
|
504
504
|
|
|
505
505
|
/**
|
|
@@ -559,7 +559,7 @@ function processBindings(
|
|
|
559
559
|
binding: string;
|
|
560
560
|
id: string;
|
|
561
561
|
preview_id: string;
|
|
562
|
-
|
|
562
|
+
remote?: boolean;
|
|
563
563
|
}[] = [];
|
|
564
564
|
const durableObjects: {
|
|
565
565
|
name: string;
|
|
@@ -592,7 +592,7 @@ function processBindings(
|
|
|
592
592
|
database_name: string;
|
|
593
593
|
migrations_dir?: string;
|
|
594
594
|
preview_database_id: string;
|
|
595
|
-
|
|
595
|
+
remote?: boolean;
|
|
596
596
|
}[] = [];
|
|
597
597
|
const queues: {
|
|
598
598
|
producers: { queue: string; binding: string }[];
|
|
@@ -608,7 +608,7 @@ function processBindings(
|
|
|
608
608
|
const vectorizeIndexes: {
|
|
609
609
|
binding: string;
|
|
610
610
|
index_name: string;
|
|
611
|
-
|
|
611
|
+
remote?: boolean;
|
|
612
612
|
}[] = [];
|
|
613
613
|
const analyticsEngineDatasets: { binding: string; dataset: string }[] = [];
|
|
614
614
|
const hyperdrive: {
|
|
@@ -625,7 +625,7 @@ function processBindings(
|
|
|
625
625
|
const dispatchNamespaces: {
|
|
626
626
|
binding: string;
|
|
627
627
|
namespace: string;
|
|
628
|
-
|
|
628
|
+
remote?: boolean;
|
|
629
629
|
}[] = [];
|
|
630
630
|
const unsafeBindings: WranglerJsonRateLimit[] = [];
|
|
631
631
|
const containers: {
|
|
@@ -693,9 +693,7 @@ function processBindings(
|
|
|
693
693
|
binding: bindingName,
|
|
694
694
|
id: id,
|
|
695
695
|
preview_id: id,
|
|
696
|
-
...("dev" in binding && binding.dev?.remote
|
|
697
|
-
? { experimental_remote: true }
|
|
698
|
-
: {}),
|
|
696
|
+
...("dev" in binding && binding.dev?.remote ? { remote: true } : {}),
|
|
699
697
|
});
|
|
700
698
|
} else if (
|
|
701
699
|
typeof binding === "object" &&
|
|
@@ -725,7 +723,7 @@ function processBindings(
|
|
|
725
723
|
preview_bucket_name: name,
|
|
726
724
|
jurisdiction:
|
|
727
725
|
binding.jurisdiction === "default" ? undefined : binding.jurisdiction,
|
|
728
|
-
...(binding.dev?.remote ? {
|
|
726
|
+
...(binding.dev?.remote ? { remote: true } : {}),
|
|
729
727
|
});
|
|
730
728
|
} else if (binding.type === "secret") {
|
|
731
729
|
// Secret binding
|
|
@@ -753,7 +751,7 @@ function processBindings(
|
|
|
753
751
|
database_name: binding.name,
|
|
754
752
|
migrations_dir: binding.migrationsDir,
|
|
755
753
|
preview_database_id: id,
|
|
756
|
-
...(binding.dev?.remote ? {
|
|
754
|
+
...(binding.dev?.remote ? { remote: true } : {}),
|
|
757
755
|
});
|
|
758
756
|
} else if (binding.type === "queue") {
|
|
759
757
|
const id =
|
|
@@ -769,7 +767,7 @@ function processBindings(
|
|
|
769
767
|
binding: bindingName,
|
|
770
768
|
index_name: binding.name,
|
|
771
769
|
// https://developers.cloudflare.com/workers/development-testing/#recommended-remote-bindings
|
|
772
|
-
|
|
770
|
+
remote: true,
|
|
773
771
|
});
|
|
774
772
|
} else if (binding.type === "browser") {
|
|
775
773
|
if (spec.browser) {
|
|
@@ -778,7 +776,7 @@ function processBindings(
|
|
|
778
776
|
spec.browser = {
|
|
779
777
|
binding: bindingName,
|
|
780
778
|
// https://developers.cloudflare.com/workers/development-testing/#recommended-remote-bindings
|
|
781
|
-
|
|
779
|
+
remote: true,
|
|
782
780
|
};
|
|
783
781
|
} else if (binding.type === "ai") {
|
|
784
782
|
if (spec.ai) {
|
|
@@ -787,7 +785,7 @@ function processBindings(
|
|
|
787
785
|
spec.ai = {
|
|
788
786
|
binding: bindingName,
|
|
789
787
|
// https://developers.cloudflare.com/workers/development-testing/#recommended-remote-bindings
|
|
790
|
-
|
|
788
|
+
remote: true,
|
|
791
789
|
};
|
|
792
790
|
} else if (binding.type === "images") {
|
|
793
791
|
if (spec.images) {
|
|
@@ -796,7 +794,7 @@ function processBindings(
|
|
|
796
794
|
spec.images = {
|
|
797
795
|
binding: bindingName,
|
|
798
796
|
// https://developers.cloudflare.com/workers/development-testing/#recommended-remote-bindings
|
|
799
|
-
|
|
797
|
+
remote: true,
|
|
800
798
|
};
|
|
801
799
|
} else if (binding.type === "analytics_engine") {
|
|
802
800
|
analyticsEngineDatasets.push({
|
|
@@ -837,7 +835,7 @@ function processBindings(
|
|
|
837
835
|
dispatchNamespaces.push({
|
|
838
836
|
binding: bindingName,
|
|
839
837
|
namespace: binding.namespaceName,
|
|
840
|
-
|
|
838
|
+
remote: true,
|
|
841
839
|
});
|
|
842
840
|
} else if (binding.type === "ratelimit") {
|
|
843
841
|
unsafeBindings.push({
|
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/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
|
@@ -116,6 +116,11 @@ export interface ScopeOptions extends ProviderCredentials {
|
|
|
116
116
|
* `undefined` if the program was not run with `--app`
|
|
117
117
|
*/
|
|
118
118
|
isSelected?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* @internal
|
|
121
|
+
* The timestamp when the scope was started.
|
|
122
|
+
*/
|
|
123
|
+
startedAt?: DOMHighResTimeStamp;
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
/**
|
|
@@ -209,6 +214,7 @@ export class Scope {
|
|
|
209
214
|
public readonly dotAlchemy: string;
|
|
210
215
|
public readonly isSelected: boolean | undefined;
|
|
211
216
|
public readonly profile: string | undefined;
|
|
217
|
+
public readonly startedAt: DOMHighResTimeStamp;
|
|
212
218
|
|
|
213
219
|
// Provider credentials for scope-level credential overrides
|
|
214
220
|
public readonly providerCredentials: ProviderCredentials;
|
|
@@ -216,7 +222,6 @@ export class Scope {
|
|
|
216
222
|
private isErrored = false;
|
|
217
223
|
private isSkipped = false;
|
|
218
224
|
private finalized = false;
|
|
219
|
-
private startedAt = performance.now();
|
|
220
225
|
private deferred: (() => Promise<any>)[] = [];
|
|
221
226
|
private cleanups: (() => Promise<void>)[] = [];
|
|
222
227
|
|
|
@@ -249,6 +254,7 @@ export class Scope {
|
|
|
249
254
|
isSelected,
|
|
250
255
|
noTrack,
|
|
251
256
|
profile,
|
|
257
|
+
startedAt,
|
|
252
258
|
...providerCredentials
|
|
253
259
|
} = options;
|
|
254
260
|
|
|
@@ -257,7 +263,7 @@ export class Scope {
|
|
|
257
263
|
this.parent = parent ?? Scope.getScope();
|
|
258
264
|
this.rootDir = rootDir ?? this.parent?.rootDir ?? ALCHEMY_ROOT;
|
|
259
265
|
this.isSelected = isSelected ?? this.parent?.isSelected;
|
|
260
|
-
|
|
266
|
+
this.startedAt = startedAt ?? this.parent?.startedAt ?? performance.now();
|
|
261
267
|
this.dotAlchemy =
|
|
262
268
|
dotAlchemy ??
|
|
263
269
|
this.parent?.dotAlchemy ??
|
|
@@ -305,7 +311,7 @@ export class Scope {
|
|
|
305
311
|
destroyStrategy ?? this.parent?.destroyStrategy ?? "sequential";
|
|
306
312
|
if (this.local) {
|
|
307
313
|
this.logger.warnOnce(
|
|
308
|
-
"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.",
|
|
309
315
|
);
|
|
310
316
|
}
|
|
311
317
|
|
|
@@ -515,10 +521,15 @@ export class Scope {
|
|
|
515
521
|
this.parent === undefined ||
|
|
516
522
|
this?.parent?.scopeName === this.root.scopeName;
|
|
517
523
|
if (this.phase === "read") {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
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
|
+
}
|
|
522
533
|
return;
|
|
523
534
|
}
|
|
524
535
|
if (this.finalized && !shouldForce) {
|
|
@@ -566,18 +577,17 @@ export class Scope {
|
|
|
566
577
|
force: shouldForce,
|
|
567
578
|
noop: options?.noop,
|
|
568
579
|
});
|
|
569
|
-
createAndSendEvent({
|
|
570
|
-
event: "alchemy.success",
|
|
571
|
-
duration: performance.now() - this.startedAt,
|
|
572
|
-
});
|
|
573
580
|
} else if (this.isErrored) {
|
|
574
581
|
this.logger.warn("Scope is in error, skipping finalize");
|
|
575
|
-
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (this.parent == null) {
|
|
585
|
+
await createAndSendEvent(
|
|
576
586
|
{
|
|
577
|
-
event: "alchemy.error",
|
|
587
|
+
event: this.isErrored ? "alchemy.error" : "alchemy.success",
|
|
578
588
|
duration: performance.now() - this.startedAt,
|
|
579
589
|
},
|
|
580
|
-
new Error("Scope failed"),
|
|
590
|
+
this.isErrored ? new Error("Scope failed") : undefined,
|
|
581
591
|
);
|
|
582
592
|
}
|
|
583
593
|
|
|
@@ -596,7 +606,7 @@ export class Scope {
|
|
|
596
606
|
throw e;
|
|
597
607
|
})) ?? [];
|
|
598
608
|
|
|
599
|
-
//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
|
|
600
610
|
let hasCorruptedResources = false;
|
|
601
611
|
if (pendingDeletions) {
|
|
602
612
|
for (const { resource, oldProps } of pendingDeletions) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const cliArgs = process.argv.slice(2);
|
|
2
|
+
|
|
3
|
+
export function parseOption<D extends string | undefined>(
|
|
4
|
+
option: string,
|
|
5
|
+
defaultValue?: D,
|
|
6
|
+
): D {
|
|
7
|
+
const i = cliArgs.indexOf(option);
|
|
8
|
+
return (
|
|
9
|
+
i !== -1 && i + 1 < cliArgs.length ? cliArgs[i + 1] : defaultValue
|
|
10
|
+
) as D;
|
|
11
|
+
}
|
package/src/util/telemetry.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import envPaths from "env-paths";
|
|
2
2
|
import { exec } from "node:child_process";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
|
+
import http from "node:http";
|
|
5
|
+
import https from "node:https";
|
|
4
6
|
import os from "node:os";
|
|
7
|
+
import { URL } from "node:url";
|
|
5
8
|
import path from "pathe";
|
|
6
9
|
import pkg from "../../package.json" with { type: "json" };
|
|
7
10
|
import type { Phase } from "../alchemy.ts";
|
|
8
11
|
import { Scope } from "../scope.ts";
|
|
12
|
+
import { parseOption } from "./cli-args.ts";
|
|
9
13
|
import { logger } from "./logger.ts";
|
|
10
14
|
import { memoize } from "./memoize.ts";
|
|
11
15
|
|
|
@@ -170,9 +174,25 @@ export const collectData = memoize(async (): Promise<GenericTelemetryData> => {
|
|
|
170
174
|
getRuntime(),
|
|
171
175
|
getEnvironment(),
|
|
172
176
|
]);
|
|
177
|
+
|
|
178
|
+
const sessionId =
|
|
179
|
+
parseOption("--telemetry-session-id") ??
|
|
180
|
+
process.env.ALCHEMY_TELEMETRY_SESSION_ID ??
|
|
181
|
+
//@ts-expect-error
|
|
182
|
+
globalThis.ALCHEMY_TELEMETRY_SESSION_ID ??
|
|
183
|
+
crypto.randomUUID();
|
|
184
|
+
|
|
185
|
+
const referrer =
|
|
186
|
+
parseOption("--telemetry-ref") ??
|
|
187
|
+
process.env.ALCHEMY_TELEMETRY_REF ??
|
|
188
|
+
//@ts-expect-error
|
|
189
|
+
globalThis.ALCHEMY_TELEMETRY_REF ??
|
|
190
|
+
"";
|
|
191
|
+
|
|
173
192
|
return {
|
|
174
193
|
userId: userId ?? "",
|
|
175
|
-
sessionId
|
|
194
|
+
sessionId,
|
|
195
|
+
referrer,
|
|
176
196
|
platform: os.platform(),
|
|
177
197
|
osVersion: os.release(),
|
|
178
198
|
arch: os.arch(),
|
|
@@ -192,6 +212,7 @@ export const collectData = memoize(async (): Promise<GenericTelemetryData> => {
|
|
|
192
212
|
export type GenericTelemetryData = {
|
|
193
213
|
userId: string;
|
|
194
214
|
sessionId: string;
|
|
215
|
+
referrer: string;
|
|
195
216
|
platform: string;
|
|
196
217
|
osVersion: string;
|
|
197
218
|
arch: string;
|
|
@@ -287,7 +308,7 @@ export async function createAndSendEvent(
|
|
|
287
308
|
...(await collectData()),
|
|
288
309
|
...serializeError(error),
|
|
289
310
|
};
|
|
290
|
-
await
|
|
311
|
+
await fetchNoResponse(TELEMETRY_API_URL, {
|
|
291
312
|
method: "POST",
|
|
292
313
|
headers: {
|
|
293
314
|
"Content-Type": "application/json",
|
|
@@ -326,3 +347,48 @@ function serializeError(error: Error | undefined) {
|
|
|
326
347
|
errorStack: "",
|
|
327
348
|
};
|
|
328
349
|
}
|
|
350
|
+
|
|
351
|
+
async function fetchNoResponse(
|
|
352
|
+
url: string,
|
|
353
|
+
options: {
|
|
354
|
+
body?: string;
|
|
355
|
+
headers?: Record<string, string>;
|
|
356
|
+
method?: string;
|
|
357
|
+
} = {},
|
|
358
|
+
) {
|
|
359
|
+
const parsedUrl = new URL(url);
|
|
360
|
+
const isHttps = parsedUrl.protocol === "https:";
|
|
361
|
+
const client = isHttps ? https : http;
|
|
362
|
+
|
|
363
|
+
const body = options.body || "";
|
|
364
|
+
const headers = {
|
|
365
|
+
...options.headers,
|
|
366
|
+
"Content-Length": Buffer.byteLength(body),
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const requestOptions = {
|
|
370
|
+
hostname: parsedUrl.hostname,
|
|
371
|
+
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
372
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
373
|
+
method: options.method || "GET",
|
|
374
|
+
headers,
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
await new Promise<void>((resolve, reject) => {
|
|
378
|
+
const req = client.request(requestOptions);
|
|
379
|
+
|
|
380
|
+
req.on("error", (error) => {
|
|
381
|
+
reject(error);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
if (body) {
|
|
385
|
+
req.write(body);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
req.once("finish", () => {
|
|
389
|
+
resolve(void 0);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
req.end();
|
|
393
|
+
});
|
|
394
|
+
}
|
package/workers/tunnel-proxy.js
CHANGED
|
@@ -34,7 +34,7 @@ var h={async fetch(e,r){let n=new URL(e.url);n.host=r.TUNNEL_HOST;let l=new Head
|
|
|
34
34
|
Alchemy</a>.</p>
|
|
35
35
|
</div>
|
|
36
36
|
<div class="bg-slate-200 px-5 py-3 flex flex-col w-full max-w-lg">
|
|
37
|
-
<p class="text-sm text-slate-500">Alchemy 0.71.
|
|
37
|
+
<p class="text-sm text-slate-500">Alchemy 0.71.1</p>
|
|
38
38
|
</div>
|
|
39
39
|
</div>
|
|
40
40
|
</body>
|