alchemy 0.71.0 → 0.72.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.
- 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/planetscale/api.d.ts +0 -4
- package/lib/planetscale/api.d.ts.map +1 -1
- package/lib/planetscale/api.js.map +1 -1
- package/lib/planetscale/branch.d.ts +12 -11
- package/lib/planetscale/branch.d.ts.map +1 -1
- package/lib/planetscale/branch.js +40 -23
- package/lib/planetscale/branch.js.map +1 -1
- package/lib/planetscale/database.d.ts +10 -5
- package/lib/planetscale/database.d.ts.map +1 -1
- package/lib/planetscale/database.js +30 -18
- package/lib/planetscale/database.js.map +1 -1
- package/lib/planetscale/index.d.ts +1 -0
- package/lib/planetscale/index.d.ts.map +1 -1
- package/lib/planetscale/index.js +1 -0
- package/lib/planetscale/index.js.map +1 -1
- package/lib/planetscale/organization.d.ts +5 -0
- package/lib/planetscale/organization.d.ts.map +1 -0
- package/lib/planetscale/organization.js +11 -0
- package/lib/planetscale/organization.js.map +1 -0
- package/lib/planetscale/password.d.ts +10 -9
- package/lib/planetscale/password.d.ts.map +1 -1
- package/lib/planetscale/password.js +28 -13
- package/lib/planetscale/password.js.map +1 -1
- package/lib/planetscale/role.d.ts +2 -1
- package/lib/planetscale/role.d.ts.map +1 -1
- package/lib/planetscale/role.js +11 -8
- package/lib/planetscale/role.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/planetscale/api.ts +0 -4
- package/src/planetscale/branch.ts +51 -35
- package/src/planetscale/database.ts +40 -20
- package/src/planetscale/index.ts +1 -0
- package/src/planetscale/organization.ts +17 -0
- package/src/planetscale/password.ts +34 -16
- package/src/planetscale/role.ts +16 -9
- 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
package/src/planetscale/index.ts
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createPlanetScaleClient, type PlanetScaleProps } from "./api.ts";
|
|
2
|
+
import type { Organization } from "./api/types.gen.ts";
|
|
3
|
+
|
|
4
|
+
export type OrganizationRef = Organization;
|
|
5
|
+
|
|
6
|
+
export async function OrganizationRef(
|
|
7
|
+
name: string | Organization,
|
|
8
|
+
options: PlanetScaleProps = {},
|
|
9
|
+
) {
|
|
10
|
+
const api = createPlanetScaleClient(options);
|
|
11
|
+
const organization = await api.getOrganization({
|
|
12
|
+
path: {
|
|
13
|
+
name: typeof name === "string" ? name : name.id,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
return organization.data;
|
|
17
|
+
}
|
|
@@ -22,8 +22,9 @@ export interface PasswordProps extends PlanetScaleProps {
|
|
|
22
22
|
/**
|
|
23
23
|
* The organization ID where the password will be created
|
|
24
24
|
* Required when using string database name, optional when using Database or Branch resource
|
|
25
|
+
* @default process.env.PLANETSCALE_ORGANIZATION
|
|
25
26
|
*/
|
|
26
|
-
|
|
27
|
+
organization?: string;
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* The database where the password will be created
|
|
@@ -114,7 +115,7 @@ export interface Password extends PasswordProps {
|
|
|
114
115
|
*
|
|
115
116
|
* const readerPassword = await Password("app-reader", {
|
|
116
117
|
* name: "app-reader",
|
|
117
|
-
*
|
|
118
|
+
* organization: "my-org",
|
|
118
119
|
* database: "my-app-db",
|
|
119
120
|
* branch: "main",
|
|
120
121
|
* role: "reader"
|
|
@@ -136,7 +137,7 @@ export interface Password extends PasswordProps {
|
|
|
136
137
|
*
|
|
137
138
|
* const writerPassword = await Password("app-writer", {
|
|
138
139
|
* name: "app-writer",
|
|
139
|
-
*
|
|
140
|
+
* organization: "my-org",
|
|
140
141
|
* database: "my-app-db",
|
|
141
142
|
* branch: "development",
|
|
142
143
|
* role: "writer",
|
|
@@ -157,7 +158,7 @@ export interface Password extends PasswordProps {
|
|
|
157
158
|
*
|
|
158
159
|
* const adminPassword = await Password("admin-access", {
|
|
159
160
|
* name: "admin-access",
|
|
160
|
-
*
|
|
161
|
+
* organization: "my-org",
|
|
161
162
|
* database: "my-app-db",
|
|
162
163
|
* branch: "main",
|
|
163
164
|
* role: "admin",
|
|
@@ -176,7 +177,7 @@ export interface Password extends PasswordProps {
|
|
|
176
177
|
*
|
|
177
178
|
* const password = await Password("custom-auth", {
|
|
178
179
|
* name: "custom-auth",
|
|
179
|
-
*
|
|
180
|
+
* organization: "my-org",
|
|
180
181
|
* database: "my-app-db",
|
|
181
182
|
* branch: "main",
|
|
182
183
|
* role: "readwriter",
|
|
@@ -194,7 +195,7 @@ export interface Password extends PasswordProps {
|
|
|
194
195
|
*
|
|
195
196
|
* const replicaPassword = await Password("replica-reader", {
|
|
196
197
|
* name: "replica-reader",
|
|
197
|
-
*
|
|
198
|
+
* organization: "my-org",
|
|
198
199
|
* database: "my-app-db",
|
|
199
200
|
* branch: "main",
|
|
200
201
|
* role: "reader",
|
|
@@ -211,7 +212,7 @@ export interface Password extends PasswordProps {
|
|
|
211
212
|
*
|
|
212
213
|
* const database = await Database("my-db", {
|
|
213
214
|
* name: "my-app-db",
|
|
214
|
-
*
|
|
215
|
+
* organization: "my-org",
|
|
215
216
|
* clusterSize: "PS_10"
|
|
216
217
|
* });
|
|
217
218
|
*
|
|
@@ -232,13 +233,13 @@ export interface Password extends PasswordProps {
|
|
|
232
233
|
*
|
|
233
234
|
* const database = await Database("my-db", {
|
|
234
235
|
* name: "my-app-db",
|
|
235
|
-
*
|
|
236
|
+
* organization: "my-org",
|
|
236
237
|
* clusterSize: "PS_10"
|
|
237
238
|
* });
|
|
238
239
|
*
|
|
239
240
|
* const branch = await Branch("feature-branch", {
|
|
240
241
|
* name: "feature-branch",
|
|
241
|
-
*
|
|
242
|
+
* organization: "my-org",
|
|
242
243
|
* databaseName: "my-app-db",
|
|
243
244
|
* parentBranch: "main",
|
|
244
245
|
* isProduction: false
|
|
@@ -266,19 +267,36 @@ export const Password = Resource(
|
|
|
266
267
|
const name = `${(props.name ?? this.output?.name ?? this.scope.createPhysicalName(id)).toLowerCase()}-${nameSlug}`;
|
|
267
268
|
|
|
268
269
|
const api = createPlanetScaleClient(props);
|
|
270
|
+
if (!props.organization && typeof props.database === "string") {
|
|
271
|
+
throw new Error(
|
|
272
|
+
"Organization ID is required when using string database name",
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const organization =
|
|
277
|
+
// @ts-expect-error - organizationId is a legacy thing, we keep this so we can destroy
|
|
278
|
+
this.output?.organizationId ??
|
|
279
|
+
props.organization ??
|
|
280
|
+
(typeof props.database !== "string"
|
|
281
|
+
? props.database.organization
|
|
282
|
+
: typeof props.branch !== "string" && props.branch
|
|
283
|
+
? props.branch.organization
|
|
284
|
+
: (process.env.PLANETSCALE_ORGANIZATION ??
|
|
285
|
+
process.env.PLANETSCALE_ORG_ID));
|
|
269
286
|
const database =
|
|
270
|
-
|
|
287
|
+
// @ts-expect-error - databaseName is a legacy thing, we keep this so we can destroy
|
|
288
|
+
this.output?.databaseName ??
|
|
289
|
+
(typeof props.database === "string"
|
|
290
|
+
? props.database
|
|
291
|
+
: props.database.name);
|
|
271
292
|
const branch =
|
|
272
293
|
typeof props.branch === "string"
|
|
273
294
|
? props.branch
|
|
274
295
|
: (props.branch?.name ?? "main");
|
|
275
|
-
const organization =
|
|
276
|
-
props.organizationId ??
|
|
277
|
-
((typeof props.branch !== "string" && props.branch?.organizationId) ||
|
|
278
|
-
(typeof props.database !== "string" && props.database.organizationId));
|
|
279
|
-
|
|
280
296
|
if (!organization) {
|
|
281
|
-
throw new Error(
|
|
297
|
+
throw new Error(
|
|
298
|
+
"PlanetScale organization is required. Please set the `organization` property or the `PLANETSCALE_ORGANIZATION` environment variable.",
|
|
299
|
+
);
|
|
282
300
|
}
|
|
283
301
|
|
|
284
302
|
if (this.phase === "delete") {
|
package/src/planetscale/role.ts
CHANGED
|
@@ -16,8 +16,9 @@ export interface RoleProps extends PlanetScaleProps {
|
|
|
16
16
|
/**
|
|
17
17
|
* The organization ID where the role will be created
|
|
18
18
|
* Required when using string database name, optional when using Database resource
|
|
19
|
+
* @default process.env.PLANETSCALE_ORGANIZATION
|
|
19
20
|
*/
|
|
20
|
-
|
|
21
|
+
organization?: string;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* The database where the role will be created
|
|
@@ -164,12 +165,21 @@ export const Role = Resource(
|
|
|
164
165
|
props: RoleProps,
|
|
165
166
|
): Promise<Role> {
|
|
166
167
|
const api = createPlanetScaleClient(props);
|
|
168
|
+
|
|
167
169
|
const organization =
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
// @ts-expect-error - organizationId is a legacy thing, we keep this so we can destroy
|
|
171
|
+
this.output?.organizationId ??
|
|
172
|
+
props.organization ??
|
|
173
|
+
(typeof props.database !== "string"
|
|
174
|
+
? props.database.organization
|
|
175
|
+
: (process.env.PLANETSCALE_ORGANIZATION ??
|
|
176
|
+
process.env.PLANETSCALE_ORG_ID));
|
|
177
|
+
if (!organization) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
"PlanetScale organization is required. Please set the `organization` property or the `PLANETSCALE_ORGANIZATION` environment variable.",
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
173
183
|
const database =
|
|
174
184
|
typeof props.database === "string" ? props.database : props.database.name;
|
|
175
185
|
const branch =
|
|
@@ -179,9 +189,6 @@ export const Role = Resource(
|
|
|
179
189
|
const inheritedRoles = Array.isArray(props.inheritedRoles)
|
|
180
190
|
? props.inheritedRoles
|
|
181
191
|
: props.inheritedRoles.inheritedRoles;
|
|
182
|
-
if (!organization) {
|
|
183
|
-
throw new Error("Organization ID is required");
|
|
184
|
-
}
|
|
185
192
|
|
|
186
193
|
switch (this.phase) {
|
|
187
194
|
case "delete": {
|
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.
|
|
37
|
+
<p class="text-sm text-slate-500">Alchemy 0.72.0</p>
|
|
38
38
|
</div>
|
|
39
39
|
</div>
|
|
40
40
|
</body>
|