@wtfalch/edge 0.13.0 → 0.15.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/dist/client.d.ts +19 -3
- package/dist/client.js +23 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/transport.d.ts +2 -0
- package/dist/transport.js +18 -8
- package/dist/types.d.ts +79 -1
- package/dist/worker-app-port.d.ts +81 -0
- package/dist/worker-app-port.js +285 -0
- package/package.json +4 -2
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ClientOptions } from './transport.js';
|
|
2
|
-
import type { AccessProviderView, AccessReadinessResponse, AdoptAccessAppsRequest, AdoptAccessAppsResponse, AdoptRateLimitRulesRequest, AdoptRateLimitRulesResponse, AdoptRecordsRequest, AdoptRecordsResponse, AdoptTunnelsRequest, AdoptTunnelsResponse, AdoptWorkersRequest, AdoptWorkersResponse, AdoptZonesRequest, AdoptZonesResponse, AvailableResponse, ClaimNameRequest, CreatePlatformAccessAppRequest, CreatePlatformAccessPolicyRequest, CreatePlatformGateRequest, CreatePlatformRateLimitRuleRequest, CreatePlatformRecordRequest, CreatePlatformServiceTokenRequest, CreatePlatformServiceTokenResponse, CreatePlatformTunnelRequest, CreatePlatformWorkerRouteRequest, CreatePlatformZoneRequest, EnsureAccessProviderRequest, FindServiceTokenResponse, ListClaimsResponse, ListGatesResponse, ListPlatformAccessAppsRequest, ListPlatformAccessAppsResponse, ListPlatformAccessPoliciesResponse, ListPlatformRateLimitRulesRequest, ListPlatformRateLimitRulesResponse, ListPlatformRecordsRequest, ListPlatformRecordsResponse, ListPlatformTunnelsResponse, ListPlatformWorkerRoutesRequest, ListPlatformWorkerRoutesResponse, ListPlatformWorkerScriptsResponse, ListPlatformZonesRequest, ListPlatformZonesResponse, ListRecordsResponse, MintKeyRequest, MintKeyResponse, NameClaim, OneTimePinProviderView, OrgSettingsRequest, PlatformAccessAppView, PlatformAccessPolicyView, PlatformGateView, PlatformRateLimitRuleView, PlatformRecordView, PlatformTunnelView, PlatformWorkerRouteView, PlatformWorkerScriptView, PlatformZoneView, PutPlatformTunnelConfigRequest, RecordInput, RecordPatch, RecordView, ReplacePlatformGateHostnamesRequest, SetGatePeopleResponse, SetPlatformWorkerSchedulesRequest, SetPlatformWorkerSchedulesResponse, SetPlatformWorkerSecretsRequest, SetPlatformWorkerSecretsResponse, TokenResponse, UpdatePlatformRecordRequest, UploadPlatformWorkerScriptRequest } from './types.js';
|
|
2
|
+
import type { AccessProviderView, AccessReadinessResponse, AdoptAccessAppsRequest, AdoptAccessAppsResponse, AdoptRateLimitRulesRequest, AdoptRateLimitRulesResponse, AdoptRecordsRequest, AdoptRecordsResponse, AdoptTunnelsRequest, AdoptTunnelsResponse, AdoptWorkersRequest, AdoptWorkersResponse, AdoptZonesRequest, AdoptZonesResponse, AvailableResponse, ClaimNameRequest, CreatePlatformAccessAppRequest, CreatePlatformAccessPolicyRequest, CreatePlatformGateRequest, CreatePlatformRateLimitRuleRequest, CreatePlatformRecordRequest, CreatePlatformServiceTokenRequest, CreatePlatformServiceTokenResponse, CreatePlatformTunnelRequest, CreatePlatformWorkerRouteRequest, CreatePlatformZoneRequest, EnsureAccessProviderRequest, EnsurePlatformWorkerContainerRequest, EnsureRequestHeaderStripResponse, FindServiceTokenResponse, ListClaimsResponse, ListGatesResponse, ListPlatformAccessAppsRequest, ListPlatformAccessAppsResponse, ListPlatformAccessPoliciesResponse, ListPlatformRateLimitRulesRequest, ListPlatformRateLimitRulesResponse, ListPlatformRecordsRequest, ListPlatformRecordsResponse, ListPlatformTunnelsResponse, ListPlatformWorkerRoutesRequest, ListPlatformWorkerRoutesResponse, ListPlatformWorkerScriptsResponse, ListPlatformZonesRequest, ListPlatformZonesResponse, ListRecordsResponse, MintKeyRequest, MintKeyResponse, NameClaim, OneTimePinProviderView, OrgSettingsRequest, PlatformAccessAppView, PlatformAccessPolicyView, PlatformGateView, PlatformRateLimitRuleView, PlatformRecordView, PlatformTunnelView, PlatformWorkerContainerView, PlatformWorkerRouteView, PlatformWorkerScriptView, PlatformZoneView, PutPlatformTunnelConfigRequest, RecordInput, RecordPatch, RecordView, RemovePlatformWorkerContainerResponse, RemovePlatformWorkerSecretResponse, ReplacePlatformGateHostnamesRequest, RequestHeaderStripRule, SetGatePeopleResponse, SetPlatformWorkerSchedulesRequest, SetPlatformWorkerSchedulesResponse, SetPlatformWorkerSecretsRequest, SetPlatformWorkerSecretsResponse, TokenResponse, UpdatePlatformRecordRequest, UploadPlatformWorkerScriptRequest } from './types.js';
|
|
3
3
|
export { EdgeApiError, type ClientOptions } from './transport.js';
|
|
4
4
|
/** Called with an entry's key: the key carries its organisation and domain, so
|
|
5
5
|
* no call names either. `setReservedLabels`, `mintKey` and `revokeKey` are
|
|
@@ -138,6 +138,16 @@ export declare function createEdgeClient(options: ClientOptions): {
|
|
|
138
138
|
* Cloudflare, and anything nobody names is left alone. */
|
|
139
139
|
adopt: (input: AdoptRateLimitRulesRequest) => Promise<AdoptRateLimitRulesResponse>;
|
|
140
140
|
};
|
|
141
|
+
/** Request-header Transform Rules in a zone. */
|
|
142
|
+
requestHeaders: {
|
|
143
|
+
/** Keeps one rule, named by `rule.description`, that removes `rule.headers`
|
|
144
|
+
* from requests matching `rule.expression` (the zone's
|
|
145
|
+
* `http_request_late_transform` phase). Creates the rule, or rewrites it
|
|
146
|
+
* when it exists; no other rule in the zone changes. Safe to repeat. Needs
|
|
147
|
+
* the platform credential. Rejects with `conflict` (reason
|
|
148
|
+
* `upstream_rejected`) when Cloudflare refuses the rule for good. */
|
|
149
|
+
ensureRequestHeaderStrip: (zoneId: string, rule: RequestHeaderStripRule) => Promise<EnsureRequestHeaderStripResponse>;
|
|
150
|
+
};
|
|
141
151
|
/** Cloudflare zones the platform made or adopted. A zone is the root of a
|
|
142
152
|
* company's domain, so there is no delete. A zone's `id` is Cloudflare's zone id. */
|
|
143
153
|
zones: {
|
|
@@ -177,8 +187,14 @@ export declare function createEdgeClient(options: ClientOptions): {
|
|
|
177
187
|
* one is skipped (`changed: false`); a new version sets the value again.
|
|
178
188
|
* Survives `uploadScript` redeploys. Deleting the script removes them. */
|
|
179
189
|
setSecrets: (name: string, input: SetPlatformWorkerSecretsRequest) => Promise<SetPlatformWorkerSecretsResponse>;
|
|
190
|
+
/** Removes one secret of a script edge owns. Safe to repeat: a secret that is gone counts as removed. Rejects with `not_found` when edge does not own an active script of that name. */
|
|
191
|
+
removeSecret: (name: string, secret: string, organisationId?: string) => Promise<RemovePlatformWorkerSecretResponse>;
|
|
192
|
+
/** Creates the container application of the Durable Object class `className` the script exports (201), or brings the one that exists to the image, instance type and cap (200). Safe to repeat, and a repeat finishes a call that failed halfway. Rejects with `not_found` when the script exports no such class. */
|
|
193
|
+
ensureContainer: (name: string, className: string, input: EnsurePlatformWorkerContainerRequest) => Promise<PlatformWorkerContainerView>;
|
|
194
|
+
/** Deletes a container application of a script edge owns. One that is gone counts as removed; one that serves no edge script rejects with `not_found`. */
|
|
195
|
+
removeContainer: (id: string, organisationId?: string) => Promise<RemovePlatformWorkerContainerResponse>;
|
|
180
196
|
/** Deletes the script, its cron triggers and the KV namespaces edge created for it; returns the tombstone. Repeating it rejects with `not_found`. */
|
|
181
|
-
removeScript: (name: string) => Promise<PlatformWorkerScriptView>;
|
|
197
|
+
removeScript: (name: string, organisationId?: string) => Promise<PlatformWorkerScriptView>;
|
|
182
198
|
/** Every live route in the zone with its owner (`null`: no row), optionally only one pattern. */
|
|
183
199
|
listRoutes: (filter: ListPlatformWorkerRoutesRequest) => Promise<ListPlatformWorkerRoutesResponse>;
|
|
184
200
|
/** Creates the route, or returns the one edge already made for that
|
|
@@ -186,7 +202,7 @@ export declare function createEdgeClient(options: ClientOptions): {
|
|
|
186
202
|
* holds the pattern that nobody adopted (adopt it instead). */
|
|
187
203
|
createRoute: (input: CreatePlatformWorkerRouteRequest) => Promise<PlatformWorkerRouteView>;
|
|
188
204
|
/** Deletes the route in `zoneId`; returns the tombstone. Repeating it rejects with `not_found`. */
|
|
189
|
-
removeRoute: (zoneId: string, id: string) => Promise<PlatformWorkerRouteView>;
|
|
205
|
+
removeRoute: (zoneId: string, id: string, organisationId?: string) => Promise<PlatformWorkerRouteView>;
|
|
190
206
|
/** Writes platform rows for the scripts and routes named. Nothing is
|
|
191
207
|
* deleted or recreated, and anything nobody names is left alone. */
|
|
192
208
|
adopt: (input: AdoptWorkersRequest) => Promise<AdoptWorkersResponse>;
|
package/dist/client.js
CHANGED
|
@@ -143,6 +143,21 @@ export function createEdgeClient(options) {
|
|
|
143
143
|
* Cloudflare, and anything nobody names is left alone. */
|
|
144
144
|
adopt: (input) => call('POST', '/v1/platform/ratelimits/adopt', input),
|
|
145
145
|
},
|
|
146
|
+
/** Request-header Transform Rules in a zone. */
|
|
147
|
+
requestHeaders: {
|
|
148
|
+
/** Keeps one rule, named by `rule.description`, that removes `rule.headers`
|
|
149
|
+
* from requests matching `rule.expression` (the zone's
|
|
150
|
+
* `http_request_late_transform` phase). Creates the rule, or rewrites it
|
|
151
|
+
* when it exists; no other rule in the zone changes. Safe to repeat. Needs
|
|
152
|
+
* the platform credential. Rejects with `conflict` (reason
|
|
153
|
+
* `upstream_rejected`) when Cloudflare refuses the rule for good. */
|
|
154
|
+
ensureRequestHeaderStrip: (zoneId, rule) => call('PUT', '/v1/platform/transforms/request-headers', {
|
|
155
|
+
zoneId,
|
|
156
|
+
description: rule.description,
|
|
157
|
+
expression: rule.expression,
|
|
158
|
+
headers: rule.headers,
|
|
159
|
+
}),
|
|
160
|
+
},
|
|
146
161
|
/** Cloudflare zones the platform made or adopted. A zone is the root of a
|
|
147
162
|
* company's domain, so there is no delete. A zone's `id` is Cloudflare's zone id. */
|
|
148
163
|
zones: {
|
|
@@ -180,8 +195,14 @@ export function createEdgeClient(options) {
|
|
|
180
195
|
* one is skipped (`changed: false`); a new version sets the value again.
|
|
181
196
|
* Survives `uploadScript` redeploys. Deleting the script removes them. */
|
|
182
197
|
setSecrets: (name, input) => call('PUT', `/v1/platform/workers/scripts/${encodeURIComponent(name)}/secrets`, input),
|
|
198
|
+
/** Removes one secret of a script edge owns. Safe to repeat: a secret that is gone counts as removed. Rejects with `not_found` when edge does not own an active script of that name. */
|
|
199
|
+
removeSecret: (name, secret, organisationId) => call('DELETE', `/v1/platform/workers/scripts/${encodeURIComponent(name)}/secrets/${encodeURIComponent(secret)}${organisationId === undefined ? '' : `?${new URLSearchParams({ organisationId })}`}`),
|
|
200
|
+
/** Creates the container application of the Durable Object class `className` the script exports (201), or brings the one that exists to the image, instance type and cap (200). Safe to repeat, and a repeat finishes a call that failed halfway. Rejects with `not_found` when the script exports no such class. */
|
|
201
|
+
ensureContainer: (name, className, input) => call('PUT', `/v1/platform/workers/scripts/${encodeURIComponent(name)}/containers/${encodeURIComponent(className)}`, input),
|
|
202
|
+
/** Deletes a container application of a script edge owns. One that is gone counts as removed; one that serves no edge script rejects with `not_found`. */
|
|
203
|
+
removeContainer: (id, organisationId) => call('DELETE', `/v1/platform/workers/containers/${encodeURIComponent(id)}${organisationId === undefined ? '' : `?${new URLSearchParams({ organisationId })}`}`),
|
|
183
204
|
/** Deletes the script, its cron triggers and the KV namespaces edge created for it; returns the tombstone. Repeating it rejects with `not_found`. */
|
|
184
|
-
removeScript: (name) => call('DELETE', `/v1/platform/workers/scripts/${encodeURIComponent(name)}`),
|
|
205
|
+
removeScript: (name, organisationId) => call('DELETE', `/v1/platform/workers/scripts/${encodeURIComponent(name)}${organisationId === undefined ? '' : `?${new URLSearchParams({ organisationId })}`}`),
|
|
185
206
|
/** Every live route in the zone with its owner (`null`: no row), optionally only one pattern. */
|
|
186
207
|
listRoutes: (filter) => call('GET', `/v1/platform/workers/routes?${new URLSearchParams(Object.entries(filter).filter((entry) => entry[1] !== undefined))}`),
|
|
187
208
|
/** Creates the route, or returns the one edge already made for that
|
|
@@ -189,7 +210,7 @@ export function createEdgeClient(options) {
|
|
|
189
210
|
* holds the pattern that nobody adopted (adopt it instead). */
|
|
190
211
|
createRoute: (input) => call('POST', '/v1/platform/workers/routes', input),
|
|
191
212
|
/** Deletes the route in `zoneId`; returns the tombstone. Repeating it rejects with `not_found`. */
|
|
192
|
-
removeRoute: (zoneId, id) => call('DELETE', `/v1/platform/workers/routes/${encodeURIComponent(id)}?${new URLSearchParams({ zoneId })}`),
|
|
213
|
+
removeRoute: (zoneId, id, organisationId) => call('DELETE', `/v1/platform/workers/routes/${encodeURIComponent(id)}?${new URLSearchParams({ zoneId, ...(organisationId === undefined ? {} : { organisationId }) })}`),
|
|
193
214
|
/** Writes platform rows for the scripts and routes named. Nothing is
|
|
194
215
|
* deleted or recreated, and anything nobody names is left alone. */
|
|
195
216
|
adopt: (input) => call('POST', '/v1/platform/workers/adopt', input),
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/transport.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export interface ClientOptions {
|
|
|
5
5
|
/** The entry's key (foundry's `EDGE_API_KEY`), or the platform credential. */
|
|
6
6
|
apiKey: string;
|
|
7
7
|
fetch?: typeof fetch;
|
|
8
|
+
/** Every call is cut off after this long and rejects with `unavailable`. Default 120 s. */
|
|
9
|
+
timeoutMs?: number;
|
|
8
10
|
}
|
|
9
11
|
/** A typed failure, never a bare `Error`. `status` is the HTTP status; `code`
|
|
10
12
|
* and `message` are the service's own wire error (see `EdgeError`). */
|
package/dist/transport.js
CHANGED
|
@@ -59,14 +59,24 @@ function errorFrom(value) {
|
|
|
59
59
|
* every request. No Node-only imports -- this runs in a browser too. */
|
|
60
60
|
export function createTransport(options) {
|
|
61
61
|
return async (method, path, input) => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
let response;
|
|
63
|
+
try {
|
|
64
|
+
response = await (options.fetch ?? fetch)(new URL(path.replace(/^\//, ''), options.url.endsWith('/') ? options.url : `${options.url}/`), {
|
|
65
|
+
method,
|
|
66
|
+
headers: {
|
|
67
|
+
authorization: `Bearer ${options.apiKey}`,
|
|
68
|
+
...(input === undefined ? {} : { 'content-type': 'application/json' }),
|
|
69
|
+
},
|
|
70
|
+
body: input === undefined ? undefined : JSON.stringify(input),
|
|
71
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? 120_000),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
// Only the timeout is typed here; any other failure reaches the caller as it was.
|
|
76
|
+
if (error instanceof Error && error.name === 'TimeoutError')
|
|
77
|
+
throw new EdgeApiError(0, 'unavailable', 'Request timed out');
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
70
80
|
let value;
|
|
71
81
|
try {
|
|
72
82
|
value = response.status === 204 ? undefined : await response.json();
|
package/dist/types.d.ts
CHANGED
|
@@ -502,6 +502,8 @@ export interface PlatformWorkerScriptView {
|
|
|
502
502
|
/** The company the script serves; `'platform'` when none. `null` for a script with no row. */
|
|
503
503
|
organisationId: string | null;
|
|
504
504
|
state: 'pending' | 'active' | 'removing' | 'removed';
|
|
505
|
+
/** The Durable Object migration tag the live script holds, read from Cloudflare by `listScripts`. Absent when it has none. */
|
|
506
|
+
migrationTag?: string;
|
|
505
507
|
}
|
|
506
508
|
export interface ListPlatformWorkerScriptsResponse {
|
|
507
509
|
scripts: PlatformWorkerScriptView[];
|
|
@@ -531,8 +533,30 @@ export interface WorkerPlainTextBinding {
|
|
|
531
533
|
name: string;
|
|
532
534
|
text: string;
|
|
533
535
|
}
|
|
536
|
+
/** A Durable Object namespace for a class the script exports. The class must come from a migration (this upload's or an earlier one). */
|
|
537
|
+
export interface WorkerDurableObjectBinding {
|
|
538
|
+
type: 'durable_object_namespace';
|
|
539
|
+
name: string;
|
|
540
|
+
/** The exported class name. */
|
|
541
|
+
class_name: string;
|
|
542
|
+
}
|
|
534
543
|
/** Everything `uploadScript` accepts in `bindings`. Secrets are not here: see `setSecrets`. */
|
|
535
|
-
export type WorkerBinding = WorkerRateLimitBinding | WorkerKvBinding | WorkerPlainTextBinding;
|
|
544
|
+
export type WorkerBinding = WorkerRateLimitBinding | WorkerKvBinding | WorkerPlainTextBinding | WorkerDurableObjectBinding;
|
|
545
|
+
/** A Durable Object migration applied with the upload. `oldTag` is the tag the
|
|
546
|
+
* live script holds now (omit for a script with none): Cloudflare refuses the
|
|
547
|
+
* upload when it is not. Send only the steps not yet applied. */
|
|
548
|
+
export interface WorkerMigrations {
|
|
549
|
+
oldTag?: string;
|
|
550
|
+
newTag: string;
|
|
551
|
+
steps: Array<{
|
|
552
|
+
newSqliteClasses?: string[];
|
|
553
|
+
deletedClasses?: string[];
|
|
554
|
+
renamedClasses?: Array<{
|
|
555
|
+
from: string;
|
|
556
|
+
to: string;
|
|
557
|
+
}>;
|
|
558
|
+
}>;
|
|
559
|
+
}
|
|
536
560
|
/** Uploads (or redeploys) a script. Edge fetches nothing: the caller sends the
|
|
537
561
|
* script, edge checks its size and sha256, and sends it to Cloudflare. The body
|
|
538
562
|
* is never stored or returned. */
|
|
@@ -545,6 +569,10 @@ export interface UploadPlatformWorkerScriptRequest {
|
|
|
545
569
|
compatibilityDate: string;
|
|
546
570
|
/** The script's bindings, all of them: a redeploy replaces the list. Secrets set by `setSecrets` survive a redeploy. */
|
|
547
571
|
bindings?: WorkerBinding[];
|
|
572
|
+
/** Runtime flags like `nodejs_compat`, all of them: a redeploy replaces the list. */
|
|
573
|
+
compatibilityFlags?: string[];
|
|
574
|
+
/** Durable Object migrations to apply with this upload. */
|
|
575
|
+
migrations?: WorkerMigrations;
|
|
548
576
|
/** The company the script serves. Omit for a script that serves none. */
|
|
549
577
|
organisationId?: string;
|
|
550
578
|
}
|
|
@@ -552,6 +580,8 @@ export interface UploadPlatformWorkerScriptRequest {
|
|
|
552
580
|
export interface SetPlatformWorkerSchedulesRequest {
|
|
553
581
|
/** Up to 50 expressions of five fields, like `* * * * *`. Duplicates collapse. */
|
|
554
582
|
crons: string[];
|
|
583
|
+
/** The company the script serves; edge refuses the call when the script serves another. Omit for a script that serves none. */
|
|
584
|
+
organisationId?: string;
|
|
555
585
|
}
|
|
556
586
|
export interface SetPlatformWorkerSchedulesResponse {
|
|
557
587
|
name: string;
|
|
@@ -574,6 +604,8 @@ export interface PlatformWorkerSecretInput {
|
|
|
574
604
|
export interface SetPlatformWorkerSecretsRequest {
|
|
575
605
|
/** 1 to 50 secrets, names unique. */
|
|
576
606
|
secrets: PlatformWorkerSecretInput[];
|
|
607
|
+
/** The company the script serves; edge refuses the call when the script serves another. Omit for a script that serves none. */
|
|
608
|
+
organisationId?: string;
|
|
577
609
|
}
|
|
578
610
|
export interface PlatformWorkerSecretView {
|
|
579
611
|
name: string;
|
|
@@ -585,6 +617,39 @@ export interface SetPlatformWorkerSecretsResponse {
|
|
|
585
617
|
name: string;
|
|
586
618
|
secrets: PlatformWorkerSecretView[];
|
|
587
619
|
}
|
|
620
|
+
export interface RemovePlatformWorkerSecretResponse {
|
|
621
|
+
name: string;
|
|
622
|
+
secret: string;
|
|
623
|
+
removed: true;
|
|
624
|
+
}
|
|
625
|
+
/** The container application of one Durable Object class on a script edge owns. */
|
|
626
|
+
export interface EnsurePlatformWorkerContainerRequest {
|
|
627
|
+
/** `registry.cloudflare.com/<platform account id>/<repository>@sha256:<digest>`: a digest, never a tag, under the platform account's own path. */
|
|
628
|
+
image: string;
|
|
629
|
+
/** `lite`, `basic`, `standard-1`, `standard-2`, `standard-3` or `standard-4`. */
|
|
630
|
+
instanceType: string;
|
|
631
|
+
/** 1 to 1000. */
|
|
632
|
+
maxInstances: number;
|
|
633
|
+
/** The company the script serves; edge refuses the call when the script serves another. Omit for a script that serves none. */
|
|
634
|
+
organisationId?: string;
|
|
635
|
+
}
|
|
636
|
+
export interface PlatformWorkerContainerView {
|
|
637
|
+
/** Cloudflare's application id: what `removeContainer` takes. */
|
|
638
|
+
id: string;
|
|
639
|
+
script: string;
|
|
640
|
+
className: string;
|
|
641
|
+
image: string;
|
|
642
|
+
instanceType: string;
|
|
643
|
+
maxInstances: number;
|
|
644
|
+
/** True when this call made the application. */
|
|
645
|
+
created: boolean;
|
|
646
|
+
/** True when this call started a rollout to a new image or instance type. */
|
|
647
|
+
rolledOut: boolean;
|
|
648
|
+
}
|
|
649
|
+
export interface RemovePlatformWorkerContainerResponse {
|
|
650
|
+
id: string;
|
|
651
|
+
removed: true;
|
|
652
|
+
}
|
|
588
653
|
/** A Workers route seen with the platform credential. `id` is Cloudflare's
|
|
589
654
|
* route id, which every platform route call takes. */
|
|
590
655
|
export interface PlatformWorkerRouteView {
|
|
@@ -698,6 +763,19 @@ export interface CreatePlatformRateLimitRuleRequest {
|
|
|
698
763
|
/** The company the rule serves. Omit for a rule that serves none. */
|
|
699
764
|
organisationId?: string;
|
|
700
765
|
}
|
|
766
|
+
/** A rule that removes request headers from every request its expression matches. */
|
|
767
|
+
export interface RequestHeaderStripRule {
|
|
768
|
+
/** Names the rule in the zone: the key that makes a repeat safe. 1 to 500 printable characters. */
|
|
769
|
+
description: string;
|
|
770
|
+
/** Cloudflare's rule expression, 1 to 4096 printable characters. */
|
|
771
|
+
expression: string;
|
|
772
|
+
/** 1 to 20 header names of letters, digits and hyphens. */
|
|
773
|
+
headers: readonly string[];
|
|
774
|
+
}
|
|
775
|
+
export interface EnsureRequestHeaderStripResponse {
|
|
776
|
+
/** Cloudflare's rule id. */
|
|
777
|
+
id: string;
|
|
778
|
+
}
|
|
701
779
|
export interface AdoptRateLimitRuleEntry {
|
|
702
780
|
zoneId: string;
|
|
703
781
|
/** Match the live rule by description, by id, or both. At least one is needed. */
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { createEdgeClient } from './client.js';
|
|
2
|
+
import type { WorkerBinding, WorkerMigrations } from './types.js';
|
|
3
|
+
/** The edge SDK's platform Workers client: `createEdgeClient({ ... }).platform.workers`. */
|
|
4
|
+
export type EdgePlatformWorkers = ReturnType<typeof createEdgeClient>['platform']['workers'];
|
|
5
|
+
/** What foundry's `WorkerAppPort.uploadWorkerApp` receives. */
|
|
6
|
+
export interface WorkerAppUploadInput {
|
|
7
|
+
name: string;
|
|
8
|
+
artifactUrl: string;
|
|
9
|
+
/** 64 hex characters. */
|
|
10
|
+
artifactSha256: string;
|
|
11
|
+
compatibilityDate: string;
|
|
12
|
+
compatibilityFlags: string[];
|
|
13
|
+
bindings: WorkerBinding[];
|
|
14
|
+
migrations?: WorkerMigrations;
|
|
15
|
+
}
|
|
16
|
+
export interface WorkerAppContainerInput {
|
|
17
|
+
className: string;
|
|
18
|
+
/** `<repository>@sha256:<digest>`. */
|
|
19
|
+
image: string;
|
|
20
|
+
instanceType: string;
|
|
21
|
+
maxInstances: number;
|
|
22
|
+
scriptName: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Foundry's `WorkerAppPort` (packages/foundry/src/plan/worker-app.ts), repeated
|
|
26
|
+
* structurally so a host passes {@link createWorkerAppPort}'s result straight in.
|
|
27
|
+
* Every method is idempotent.
|
|
28
|
+
*/
|
|
29
|
+
export interface WorkerAppPort {
|
|
30
|
+
scriptExists(name: string): Promise<boolean>;
|
|
31
|
+
findRoute(zoneId: string, pattern: string): Promise<{
|
|
32
|
+
id: string;
|
|
33
|
+
script?: string;
|
|
34
|
+
} | undefined>;
|
|
35
|
+
createRoute(zoneId: string, pattern: string, script?: string): Promise<{
|
|
36
|
+
id: string;
|
|
37
|
+
}>;
|
|
38
|
+
deleteRoute(zoneId: string, routeId: string): Promise<void>;
|
|
39
|
+
deleteScript(name: string): Promise<void>;
|
|
40
|
+
uploadWorkerApp(input: WorkerAppUploadInput): Promise<void>;
|
|
41
|
+
liveMigrationTag(name: string): Promise<string | undefined>;
|
|
42
|
+
setSecrets(name: string, secrets: readonly {
|
|
43
|
+
name: string;
|
|
44
|
+
value: string;
|
|
45
|
+
version: string;
|
|
46
|
+
}[]): Promise<void>;
|
|
47
|
+
deleteSecret(name: string, secretName: string): Promise<void>;
|
|
48
|
+
ensureContainerApplication(input: WorkerAppContainerInput): Promise<{
|
|
49
|
+
id: string;
|
|
50
|
+
}>;
|
|
51
|
+
deleteContainerApplication(id: string): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
export interface WorkerAppPortOptions {
|
|
54
|
+
/** The company every call acts for. Edge refuses a call on a script, route or container that serves another. */
|
|
55
|
+
organisationId: string;
|
|
56
|
+
/** A read-only GitHub token for the artifact repositories. Sent to api.github.com and nowhere else. */
|
|
57
|
+
githubToken: string;
|
|
58
|
+
fetch?: typeof fetch;
|
|
59
|
+
/** The artifact download is cut off after this long. Default 60 s. */
|
|
60
|
+
artifactTimeoutMs?: number;
|
|
61
|
+
/** Larger artifacts are refused. Default 10 MB, edge's own cap. */
|
|
62
|
+
maxArtifactBytes?: number;
|
|
63
|
+
}
|
|
64
|
+
/** The artifact could not be fetched, or is not the artifact declared. Carries no bytes and no credential. */
|
|
65
|
+
export declare class WorkerAppArtifactError extends Error {
|
|
66
|
+
constructor(message: string);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Foundry's `WorkerAppPort` over edge's `platform.workers`. The adapter
|
|
70
|
+
* fetches the module itself (from a private GitHub release, with `githubToken`) and checks its sha256 before anything is sent: a
|
|
71
|
+
* mismatch throws {@link WorkerAppArtifactError} and edge is never called.
|
|
72
|
+
* Edge checks the digest again. Secret values go to edge and nowhere else; no
|
|
73
|
+
* error made here carries one, or the API key.
|
|
74
|
+
*
|
|
75
|
+
* A script or route that exists with no edge row is not adopted: the upload
|
|
76
|
+
* answers `conflict`, and the caller sees it. `not_found` on a delete counts as
|
|
77
|
+
* gone. Every call is bounded by the client's `timeoutMs`; a failure halfway
|
|
78
|
+
* (the upload done, the container call refused) throws, and repeating the
|
|
79
|
+
* port call finishes the rest because every method is idempotent.
|
|
80
|
+
*/
|
|
81
|
+
export declare function createWorkerAppPort(workers: EdgePlatformWorkers, options: WorkerAppPortOptions): WorkerAppPort;
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { EdgeApiError } from './transport.js';
|
|
2
|
+
/** The artifact could not be fetched, or is not the artifact declared. Carries no bytes and no credential. */
|
|
3
|
+
export class WorkerAppArtifactError extends Error {
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'WorkerAppArtifactError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const SHA256 = /^[0-9a-f]{64}$/i;
|
|
10
|
+
const DEFAULT_MAX_BYTES = 10 * 1024 * 1024;
|
|
11
|
+
const isNotFound = (error) => error instanceof EdgeApiError && error.code === 'not_found';
|
|
12
|
+
const toHex = (buffer) => [...new Uint8Array(buffer)].map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
13
|
+
function toBase64(bytes) {
|
|
14
|
+
let text = '';
|
|
15
|
+
for (let i = 0; i < bytes.length; i += 0x8000)
|
|
16
|
+
text += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
|
|
17
|
+
return btoa(text);
|
|
18
|
+
}
|
|
19
|
+
const GITHUB_OWNER = 'wtfalch';
|
|
20
|
+
const GITHUB_PATH = /^\/wtfalch\/([A-Za-z0-9._-]+)\/releases\/download\/([^/]+)\/([^/]+)$/;
|
|
21
|
+
/** Where GitHub sends a release asset download. Source: GitHub's list of domains for
|
|
22
|
+
* runners (https://docs.github.com/en/actions/reference/runners/github-hosted-runners).
|
|
23
|
+
* The asset endpoint answers 302 or streams (https://docs.github.com/en/rest/releases/assets). */
|
|
24
|
+
const ASSET_HOSTS = new Set([
|
|
25
|
+
'release-assets.githubusercontent.com',
|
|
26
|
+
'objects.githubusercontent.com',
|
|
27
|
+
'objects-origin.githubusercontent.com',
|
|
28
|
+
'github-releases.githubusercontent.com',
|
|
29
|
+
]);
|
|
30
|
+
const MAX_REDIRECTS = 3;
|
|
31
|
+
/** `https://github.com/wtfalch/<repo>/releases/download/<tag>/<file>` and nothing else. */
|
|
32
|
+
function parseArtifactUrl(url) {
|
|
33
|
+
let parsed;
|
|
34
|
+
try {
|
|
35
|
+
parsed = new URL(url);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
throw new WorkerAppArtifactError('artifactUrl is not a URL');
|
|
39
|
+
}
|
|
40
|
+
if (parsed.protocol !== 'https:')
|
|
41
|
+
throw new WorkerAppArtifactError('artifactUrl must be https');
|
|
42
|
+
if (parsed.hostname !== 'github.com' ||
|
|
43
|
+
parsed.port !== '' ||
|
|
44
|
+
parsed.username !== '' ||
|
|
45
|
+
parsed.password !== '' ||
|
|
46
|
+
parsed.search !== '' ||
|
|
47
|
+
parsed.hash !== '')
|
|
48
|
+
throw new WorkerAppArtifactError(`artifactUrl must be https://github.com/${GITHUB_OWNER}/<repo>/releases/download/<tag>/<file>`);
|
|
49
|
+
const match = GITHUB_PATH.exec(parsed.pathname);
|
|
50
|
+
if (!match)
|
|
51
|
+
throw new WorkerAppArtifactError(`artifactUrl must be https://github.com/${GITHUB_OWNER}/<repo>/releases/download/<tag>/<file>`);
|
|
52
|
+
let tag;
|
|
53
|
+
let file;
|
|
54
|
+
try {
|
|
55
|
+
tag = decodeURIComponent(match[2]);
|
|
56
|
+
file = decodeURIComponent(match[3]);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw new WorkerAppArtifactError('artifactUrl is not a GitHub release asset URL');
|
|
60
|
+
}
|
|
61
|
+
if ([tag, file].some((part) => part === '.' || part === '..' || part.includes('/')))
|
|
62
|
+
throw new WorkerAppArtifactError('artifactUrl is not a GitHub release asset URL');
|
|
63
|
+
return { repo: match[1], tag, file };
|
|
64
|
+
}
|
|
65
|
+
/** A redirect target is an https GitHub asset host by name: no port, no userinfo, no address literal. */
|
|
66
|
+
function checkAssetLocation(location, from) {
|
|
67
|
+
let target;
|
|
68
|
+
try {
|
|
69
|
+
target = new URL(location, from);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw new WorkerAppArtifactError('artifact redirect is not a URL');
|
|
73
|
+
}
|
|
74
|
+
if (target.protocol !== 'https:' ||
|
|
75
|
+
target.port !== '' ||
|
|
76
|
+
target.username !== '' ||
|
|
77
|
+
target.password !== '' ||
|
|
78
|
+
!ASSET_HOSTS.has(target.hostname))
|
|
79
|
+
throw new WorkerAppArtifactError('artifact redirect to a host that is not GitHub asset storage');
|
|
80
|
+
return target;
|
|
81
|
+
}
|
|
82
|
+
/** Reads the body, aborting at `max` bytes without buffering the rest. */
|
|
83
|
+
async function readCapped(response, max) {
|
|
84
|
+
const declared = Number(response.headers.get('content-length'));
|
|
85
|
+
if (Number.isFinite(declared) && declared > max) {
|
|
86
|
+
await response.body?.cancel();
|
|
87
|
+
throw new WorkerAppArtifactError(`artifact must be 1 byte to ${max} bytes`);
|
|
88
|
+
}
|
|
89
|
+
if (!response.body)
|
|
90
|
+
throw new WorkerAppArtifactError('artifact fetch failed');
|
|
91
|
+
const reader = response.body.getReader();
|
|
92
|
+
const chunks = [];
|
|
93
|
+
let total = 0;
|
|
94
|
+
for (;;) {
|
|
95
|
+
const { done, value } = await reader.read();
|
|
96
|
+
if (done)
|
|
97
|
+
break;
|
|
98
|
+
total += value.length;
|
|
99
|
+
if (total > max) {
|
|
100
|
+
await reader.cancel();
|
|
101
|
+
throw new WorkerAppArtifactError(`artifact must be 1 byte to ${max} bytes`);
|
|
102
|
+
}
|
|
103
|
+
chunks.push(value);
|
|
104
|
+
}
|
|
105
|
+
const bytes = new Uint8Array(total);
|
|
106
|
+
let offset = 0;
|
|
107
|
+
for (const chunk of chunks) {
|
|
108
|
+
bytes.set(chunk, offset);
|
|
109
|
+
offset += chunk.length;
|
|
110
|
+
}
|
|
111
|
+
return bytes;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Fetches the release asset through GitHub's API and refuses it unless its
|
|
115
|
+
* sha256 is the declared one. The token goes to api.github.com only; the
|
|
116
|
+
* download redirect is followed by hand, to GitHub's asset hosts only, and
|
|
117
|
+
* without the token.
|
|
118
|
+
*/
|
|
119
|
+
async function fetchVerified(url, sha256, options) {
|
|
120
|
+
if (!SHA256.test(sha256))
|
|
121
|
+
throw new WorkerAppArtifactError('artifactSha256 must be 64 hex digits');
|
|
122
|
+
const { repo, tag, file } = parseArtifactUrl(url);
|
|
123
|
+
const max = options.maxArtifactBytes ?? DEFAULT_MAX_BYTES;
|
|
124
|
+
const doFetch = options.fetch ?? fetch;
|
|
125
|
+
const signal = AbortSignal.timeout(options.artifactTimeoutMs ?? 60_000);
|
|
126
|
+
const api = (path, accept) => doFetch(`https://api.github.com/repos/${GITHUB_OWNER}/${repo}/${path}`, {
|
|
127
|
+
redirect: 'manual',
|
|
128
|
+
signal,
|
|
129
|
+
headers: {
|
|
130
|
+
Accept: accept,
|
|
131
|
+
Authorization: `Bearer ${options.githubToken}`,
|
|
132
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
133
|
+
'User-Agent': 'edge-worker-app-port',
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
let bytes;
|
|
137
|
+
try {
|
|
138
|
+
const release = await api(`releases/tags/${encodeURIComponent(tag)}`, 'application/vnd.github+json');
|
|
139
|
+
if (!release.ok)
|
|
140
|
+
throw new WorkerAppArtifactError(`artifact release lookup answered status ${release.status}`);
|
|
141
|
+
const assets = (await release.json())
|
|
142
|
+
.assets;
|
|
143
|
+
const asset = assets?.find((a) => a.name === file);
|
|
144
|
+
if (!asset || typeof asset.id !== 'number' || !Number.isSafeInteger(asset.id))
|
|
145
|
+
throw new WorkerAppArtifactError('the release has no asset of that name');
|
|
146
|
+
let response = await api(`releases/assets/${asset.id}`, 'application/octet-stream');
|
|
147
|
+
let from = new URL(`https://api.github.com/repos/${GITHUB_OWNER}/${repo}/releases/assets/${asset.id}`);
|
|
148
|
+
for (let hops = 0; response.status >= 300 && response.status < 400; hops++) {
|
|
149
|
+
const location = response.headers.get('location');
|
|
150
|
+
await response.body?.cancel();
|
|
151
|
+
if (!location || hops >= MAX_REDIRECTS)
|
|
152
|
+
throw new WorkerAppArtifactError('artifact fetch failed');
|
|
153
|
+
from = checkAssetLocation(location, from);
|
|
154
|
+
// No Authorization header: the asset host never sees the token.
|
|
155
|
+
response = await doFetch(from, { redirect: 'manual', signal });
|
|
156
|
+
}
|
|
157
|
+
if (!response.ok)
|
|
158
|
+
throw new WorkerAppArtifactError(`artifact fetch answered status ${response.status}`);
|
|
159
|
+
bytes = await readCapped(response, max);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
if (error instanceof WorkerAppArtifactError)
|
|
163
|
+
throw error;
|
|
164
|
+
// The cause is dropped: it can carry a signed download URL.
|
|
165
|
+
throw new WorkerAppArtifactError(error instanceof Error && error.name === 'TimeoutError'
|
|
166
|
+
? 'artifact fetch timed out'
|
|
167
|
+
: 'artifact fetch failed');
|
|
168
|
+
}
|
|
169
|
+
if (bytes.length === 0 || bytes.length > max)
|
|
170
|
+
throw new WorkerAppArtifactError(`artifact must be 1 byte to ${max} bytes`);
|
|
171
|
+
const actual = toHex(await crypto.subtle.digest('SHA-256', bytes));
|
|
172
|
+
if (actual !== sha256.toLowerCase())
|
|
173
|
+
throw new WorkerAppArtifactError(`artifact sha256 ${actual} is not the declared ${sha256.toLowerCase()}`);
|
|
174
|
+
return bytes;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Foundry's `WorkerAppPort` over edge's `platform.workers`. The adapter
|
|
178
|
+
* fetches the module itself (from a private GitHub release, with `githubToken`) and checks its sha256 before anything is sent: a
|
|
179
|
+
* mismatch throws {@link WorkerAppArtifactError} and edge is never called.
|
|
180
|
+
* Edge checks the digest again. Secret values go to edge and nowhere else; no
|
|
181
|
+
* error made here carries one, or the API key.
|
|
182
|
+
*
|
|
183
|
+
* A script or route that exists with no edge row is not adopted: the upload
|
|
184
|
+
* answers `conflict`, and the caller sees it. `not_found` on a delete counts as
|
|
185
|
+
* gone. Every call is bounded by the client's `timeoutMs`; a failure halfway
|
|
186
|
+
* (the upload done, the container call refused) throws, and repeating the
|
|
187
|
+
* port call finishes the rest because every method is idempotent.
|
|
188
|
+
*/
|
|
189
|
+
export function createWorkerAppPort(workers, options) {
|
|
190
|
+
const org = options.organisationId;
|
|
191
|
+
// A script that serves another organisation is not visible: edge would refuse the upload anyway.
|
|
192
|
+
const liveScript = async (name) => {
|
|
193
|
+
const { scripts } = await workers.listScripts({ name });
|
|
194
|
+
return scripts.find((s) => s.name === name &&
|
|
195
|
+
s.state !== 'removed' &&
|
|
196
|
+
(s.organisationId === null || s.organisationId === org));
|
|
197
|
+
};
|
|
198
|
+
return {
|
|
199
|
+
async scriptExists(name) {
|
|
200
|
+
return (await liveScript(name)) !== undefined;
|
|
201
|
+
},
|
|
202
|
+
async findRoute(zoneId, pattern) {
|
|
203
|
+
const { routes } = await workers.listRoutes({ zoneId, pattern });
|
|
204
|
+
const route = routes.find((r) => r.pattern === pattern &&
|
|
205
|
+
r.state !== 'removed' &&
|
|
206
|
+
(r.organisationId === null || r.organisationId === org));
|
|
207
|
+
return route
|
|
208
|
+
? { id: route.id, ...(route.script ? { script: route.script } : {}) }
|
|
209
|
+
: undefined;
|
|
210
|
+
},
|
|
211
|
+
async createRoute(zoneId, pattern, script) {
|
|
212
|
+
const route = await workers.createRoute({
|
|
213
|
+
zoneId,
|
|
214
|
+
pattern,
|
|
215
|
+
organisationId: org,
|
|
216
|
+
...(script ? { script } : {}),
|
|
217
|
+
});
|
|
218
|
+
return { id: route.id };
|
|
219
|
+
},
|
|
220
|
+
async deleteRoute(zoneId, routeId) {
|
|
221
|
+
try {
|
|
222
|
+
await workers.removeRoute(zoneId, routeId, org);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
if (!isNotFound(error))
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
async deleteScript(name) {
|
|
230
|
+
try {
|
|
231
|
+
await workers.removeScript(name, org);
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
if (!isNotFound(error))
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
async uploadWorkerApp(input) {
|
|
239
|
+
const bytes = await fetchVerified(input.artifactUrl, input.artifactSha256, options);
|
|
240
|
+
await workers.uploadScript(input.name, {
|
|
241
|
+
script: toBase64(bytes),
|
|
242
|
+
organisationId: org,
|
|
243
|
+
artifactSha256: input.artifactSha256.toLowerCase(),
|
|
244
|
+
compatibilityDate: input.compatibilityDate,
|
|
245
|
+
...(input.compatibilityFlags.length
|
|
246
|
+
? { compatibilityFlags: input.compatibilityFlags }
|
|
247
|
+
: {}),
|
|
248
|
+
bindings: input.bindings,
|
|
249
|
+
...(input.migrations ? { migrations: input.migrations } : {}),
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
async liveMigrationTag(name) {
|
|
253
|
+
return (await liveScript(name))?.migrationTag;
|
|
254
|
+
},
|
|
255
|
+
async setSecrets(name, secrets) {
|
|
256
|
+
if (secrets.length === 0)
|
|
257
|
+
return;
|
|
258
|
+
await workers.setSecrets(name, {
|
|
259
|
+
organisationId: org,
|
|
260
|
+
secrets: secrets.map((s) => ({ ...s })),
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
async deleteSecret(name, secretName) {
|
|
264
|
+
try {
|
|
265
|
+
await workers.removeSecret(name, secretName, org);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
if (!isNotFound(error))
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
async ensureContainerApplication(input) {
|
|
273
|
+
const { id } = await workers.ensureContainer(input.scriptName, input.className, {
|
|
274
|
+
organisationId: org,
|
|
275
|
+
image: input.image,
|
|
276
|
+
instanceType: input.instanceType,
|
|
277
|
+
maxInstances: input.maxInstances,
|
|
278
|
+
});
|
|
279
|
+
return { id };
|
|
280
|
+
},
|
|
281
|
+
async deleteContainerApplication(id) {
|
|
282
|
+
await workers.removeContainer(id, org);
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtfalch/edge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Public client SDK and API types for the edge service.",
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
"dist/transport.d.ts",
|
|
20
20
|
"dist/transport.js",
|
|
21
21
|
"dist/types.d.ts",
|
|
22
|
-
"dist/types.js"
|
|
22
|
+
"dist/types.js",
|
|
23
|
+
"dist/worker-app-port.d.ts",
|
|
24
|
+
"dist/worker-app-port.js"
|
|
23
25
|
],
|
|
24
26
|
"exports": {
|
|
25
27
|
".": {
|