alchemy 0.83.3 → 0.85.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/bin/alchemy.js +1 -1
- package/lib/cloudflare/api-error.d.ts +11 -0
- package/lib/cloudflare/api-error.d.ts.map +1 -1
- package/lib/cloudflare/api-error.js +11 -0
- package/lib/cloudflare/api-error.js.map +1 -1
- package/lib/cloudflare/api.js +1 -1
- package/lib/cloudflare/api.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 +2 -1
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.js +9 -1
- package/lib/cloudflare/d1-database.js.map +1 -1
- 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/kv-namespace.d.ts.map +1 -1
- package/lib/cloudflare/kv-namespace.js +2 -2
- package/lib/cloudflare/kv-namespace.js.map +1 -1
- package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/build-worker-options.js +15 -0
- package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-controller.d.ts +1 -1
- package/lib/cloudflare/miniflare/miniflare-controller.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +41 -3
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -1
- package/lib/cloudflare/vpc-service.d.ts +288 -0
- package/lib/cloudflare/vpc-service.d.ts.map +1 -0
- package/lib/cloudflare/vpc-service.js +238 -0
- package/lib/cloudflare/vpc-service.js.map +1 -0
- package/lib/cloudflare/worker-metadata.d.ts +1 -0
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +8 -0
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker-stub.d.ts.map +1 -1
- package/lib/cloudflare/worker-stub.js +8 -10
- package/lib/cloudflare/worker-stub.js.map +1 -1
- package/lib/cloudflare/worker-subdomain.d.ts +11 -8
- package/lib/cloudflare/worker-subdomain.d.ts.map +1 -1
- package/lib/cloudflare/worker-subdomain.js +16 -25
- package/lib/cloudflare/worker-subdomain.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +16 -0
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +50 -24
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +9 -0
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/planetscale/api/sdk.gen.d.ts +874 -190
- package/lib/planetscale/api/sdk.gen.d.ts.map +1 -1
- package/lib/planetscale/api/sdk.gen.js +1250 -306
- package/lib/planetscale/api/sdk.gen.js.map +1 -1
- package/lib/planetscale/api/types.gen.d.ts +8241 -4128
- package/lib/planetscale/api/types.gen.d.ts.map +1 -1
- package/lib/planetscale/branch.js +4 -4
- package/lib/planetscale/branch.js.map +1 -1
- package/lib/planetscale/database.d.ts +43 -24
- package/lib/planetscale/database.d.ts.map +1 -1
- package/lib/planetscale/database.js +39 -18
- package/lib/planetscale/database.js.map +1 -1
- package/lib/planetscale/default-role.d.ts +51 -0
- package/lib/planetscale/default-role.d.ts.map +1 -0
- package/lib/planetscale/default-role.js +100 -0
- package/lib/planetscale/default-role.js.map +1 -0
- 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.js +1 -1
- package/lib/planetscale/organization.js.map +1 -1
- package/lib/planetscale/role.d.ts +1 -1
- package/lib/planetscale/role.d.ts.map +1 -1
- package/lib/planetscale/role.js +1 -1
- package/lib/planetscale/role.js.map +1 -1
- package/lib/planetscale/utils.d.ts +1 -1
- package/lib/planetscale/utils.d.ts.map +1 -1
- package/lib/planetscale/utils.js +9 -10
- package/lib/planetscale/utils.js.map +1 -1
- package/lib/state/sqlite-state-store.js +2 -0
- package/lib/state/sqlite-state-store.js.map +1 -1
- package/package.json +2 -2
- package/src/cloudflare/api-error.ts +19 -0
- package/src/cloudflare/api.ts +1 -1
- package/src/cloudflare/bindings.ts +15 -2
- package/src/cloudflare/bound.ts +6 -3
- package/src/cloudflare/d1-database.ts +11 -4
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/kv-namespace.ts +6 -2
- package/src/cloudflare/miniflare/build-worker-options.ts +30 -18
- package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +47 -2
- package/src/cloudflare/vpc-service.ts +466 -0
- package/src/cloudflare/worker-metadata.ts +8 -0
- package/src/cloudflare/worker-stub.ts +9 -11
- package/src/cloudflare/worker-subdomain.ts +29 -34
- package/src/cloudflare/worker.ts +170 -98
- package/src/cloudflare/wrangler.json.ts +8 -0
- package/src/planetscale/api/sdk.gen.ts +2331 -987
- package/src/planetscale/api/types.gen.ts +8980 -4574
- package/src/planetscale/branch.ts +4 -4
- package/src/planetscale/database.ts +87 -46
- package/src/planetscale/default-role.ts +162 -0
- package/src/planetscale/index.ts +1 -0
- package/src/planetscale/organization.ts +1 -1
- package/src/planetscale/role.ts +3 -2
- package/src/planetscale/utils.ts +10 -10
- package/src/state/sqlite-state-store.ts +2 -0
- package/workers/tunnel-proxy.js +1 -1
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import type { Context } from "../context";
|
|
2
|
+
import { Resource } from "../resource.ts";
|
|
3
|
+
import { isCloudflareApiError } from "./api-error.ts";
|
|
4
|
+
import { extractCloudflareResult } from "./api-response.ts";
|
|
5
|
+
import {
|
|
6
|
+
createCloudflareApi,
|
|
7
|
+
type CloudflareApi,
|
|
8
|
+
type CloudflareApiOptions,
|
|
9
|
+
} from "./api.ts";
|
|
10
|
+
import type { Tunnel } from "./tunnel.ts";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Properties for creating or updating a VPC service.
|
|
14
|
+
*/
|
|
15
|
+
export interface VpcServiceProps extends CloudflareApiOptions {
|
|
16
|
+
/**
|
|
17
|
+
* The name of the VPC service to create.
|
|
18
|
+
*
|
|
19
|
+
* @default ${app}-${stage}-${id}
|
|
20
|
+
*/
|
|
21
|
+
name?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The type of the VPC service. Currently only "http" is supported, but tcp will be supported in the future.
|
|
24
|
+
*
|
|
25
|
+
* @default "http"
|
|
26
|
+
*/
|
|
27
|
+
serviceType?: "http";
|
|
28
|
+
/**
|
|
29
|
+
* The TCP port for the VPC service.
|
|
30
|
+
*/
|
|
31
|
+
tcpPort?: number;
|
|
32
|
+
/**
|
|
33
|
+
* The application protocol for the VPC service.
|
|
34
|
+
*/
|
|
35
|
+
appProtocol?: string;
|
|
36
|
+
/**
|
|
37
|
+
* The HTTP port for the VPC service.
|
|
38
|
+
*
|
|
39
|
+
* @default 80
|
|
40
|
+
*/
|
|
41
|
+
httpPort?: number;
|
|
42
|
+
/**
|
|
43
|
+
* The HTTPS port for the VPC service.
|
|
44
|
+
*
|
|
45
|
+
* @default 443
|
|
46
|
+
*/
|
|
47
|
+
httpsPort?: number;
|
|
48
|
+
/**
|
|
49
|
+
* The host for the VPC service.
|
|
50
|
+
*/
|
|
51
|
+
host:
|
|
52
|
+
| VpcService.IPv4Host
|
|
53
|
+
| VpcService.IPv6Host
|
|
54
|
+
| VpcService.DualStackHost
|
|
55
|
+
| VpcService.HostnameHost;
|
|
56
|
+
/**
|
|
57
|
+
* Whether to adopt the VPC service if it already exists.
|
|
58
|
+
*
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
adopt?: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export declare namespace VpcService {
|
|
65
|
+
/** Host definition: hostname (with resolver network) or IPv4/IPv6/dual-stack with network. */
|
|
66
|
+
export type Host = IPv4Host | IPv6Host | DualStackHost | HostnameHost;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Represents a VPC service that is accessible via an IPv4 address.
|
|
70
|
+
*/
|
|
71
|
+
export interface IPv4Host {
|
|
72
|
+
ipv4: string;
|
|
73
|
+
network: Network;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Represents a VPC service that is accessible via an IPv6 address.
|
|
78
|
+
*/
|
|
79
|
+
export interface IPv6Host {
|
|
80
|
+
ipv6: string;
|
|
81
|
+
network: Network;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Represents a VPC service that is accessible via both IPv4 and IPv6 addresses.
|
|
86
|
+
*/
|
|
87
|
+
export interface DualStackHost {
|
|
88
|
+
ipv4: string;
|
|
89
|
+
ipv6: string;
|
|
90
|
+
network: Network;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Network the VPC service is reached through. Use a `Tunnel` resource or an existing `tunnelId`.
|
|
95
|
+
*/
|
|
96
|
+
export type Network = { tunnelId: string } | { tunnel: Tunnel };
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Hostname-based host. DNS is resolved over the resolver network (tunnel).
|
|
100
|
+
* Optionally specify `resolverIps` for explicit DNS resolver IPs.
|
|
101
|
+
*/
|
|
102
|
+
export interface HostnameHost {
|
|
103
|
+
hostname: string;
|
|
104
|
+
resolverNetwork: Network & { resolverIps?: string[] };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A VPC service instance. Bind to a Worker to allow the Worker to fetch from
|
|
110
|
+
* the private host (hostname or IP) over the configured tunnel.
|
|
111
|
+
*/
|
|
112
|
+
export type VpcService = Omit<VpcServiceProps, "name" | "adopt"> & {
|
|
113
|
+
/** Display name of the service. */
|
|
114
|
+
name: string;
|
|
115
|
+
/** Cloudflare-assigned service ID. */
|
|
116
|
+
serviceId: string;
|
|
117
|
+
/** Creation time (Unix ms). */
|
|
118
|
+
createdAt: number;
|
|
119
|
+
/** Last update time (Unix ms). */
|
|
120
|
+
updatedAt: number;
|
|
121
|
+
/** Resource kind for bindings. */
|
|
122
|
+
type: "vpc_service";
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Create or update a VPC service that routes Worker traffic to a private host
|
|
127
|
+
* (hostname or IP) through a Cloudflare Tunnel.
|
|
128
|
+
*
|
|
129
|
+
* [VPC Services](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/)
|
|
130
|
+
* enable Workers to securely access private network resources through Cloudflare Tunnel.
|
|
131
|
+
* Configure a host (hostname or IP) and optional ports, then bind the service to a Worker
|
|
132
|
+
* to reach private backends.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Minimal: hostname through a tunnel
|
|
136
|
+
* ```ts
|
|
137
|
+
* const tunnel = await Tunnel("my-tunnel", {
|
|
138
|
+
* ingress: [{ service: "http://localhost:3000" }],
|
|
139
|
+
* });
|
|
140
|
+
* const vpcService = await VpcService("my-service", {
|
|
141
|
+
* host: {
|
|
142
|
+
* hostname: "localhost",
|
|
143
|
+
* resolverNetwork: { tunnel, resolverIps: ["127.0.0.1"] },
|
|
144
|
+
* },
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* // IPv4 address
|
|
150
|
+
* ```ts
|
|
151
|
+
* const vpcService = await VpcService("internal-api", {
|
|
152
|
+
* host: {
|
|
153
|
+
* ipv4: "192.168.1.100",
|
|
154
|
+
* network: { tunnel },
|
|
155
|
+
* },
|
|
156
|
+
* });
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* // IPv6 address
|
|
161
|
+
* ```ts
|
|
162
|
+
* const vpcService = await VpcService("ipv6-service", {
|
|
163
|
+
* host: { ipv6: "::1", network: { tunnel } },
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* // Dual stack (IPv4 + IPv6)
|
|
169
|
+
* ```ts
|
|
170
|
+
* const vpcService = await VpcService("dual-stack-service", {
|
|
171
|
+
* host: {
|
|
172
|
+
* ipv4: "192.168.1.100",
|
|
173
|
+
* ipv6: "::1",
|
|
174
|
+
* network: { tunnel },
|
|
175
|
+
* },
|
|
176
|
+
* });
|
|
177
|
+
* ```
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* // Custom HTTP/HTTPS ports
|
|
181
|
+
* ```ts
|
|
182
|
+
* const vpcService = await VpcService("dev-server", {
|
|
183
|
+
* httpPort: 5173,
|
|
184
|
+
* httpsPort: 5174,
|
|
185
|
+
* host: {
|
|
186
|
+
* hostname: "localhost",
|
|
187
|
+
* resolverNetwork: { tunnel, resolverIps: ["127.0.0.1"] },
|
|
188
|
+
* },
|
|
189
|
+
* });
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* // Bind to a Worker
|
|
194
|
+
* ```ts
|
|
195
|
+
* const vpcService = await VpcService("private-api", {
|
|
196
|
+
* httpPort: 8080,
|
|
197
|
+
* host: {
|
|
198
|
+
* hostname: "internal-api",
|
|
199
|
+
* resolverNetwork: { tunnel, resolverIps: ["10.0.0.1"] },
|
|
200
|
+
* },
|
|
201
|
+
* });
|
|
202
|
+
* const worker = await Worker("api-gateway", {
|
|
203
|
+
* entrypoint: "./src/worker.ts",
|
|
204
|
+
* bindings: { PRIVATE_API: vpcService },
|
|
205
|
+
* });
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* // Existing tunnel by ID
|
|
210
|
+
* ```ts
|
|
211
|
+
* const vpcService = await VpcService("existing-tunnel-service", {
|
|
212
|
+
* host: {
|
|
213
|
+
* hostname: "internal.example.com",
|
|
214
|
+
* resolverNetwork: {
|
|
215
|
+
* tunnelId: "e6a0817c-79c5-40ca-9776-a1c019defe70",
|
|
216
|
+
* resolverIps: ["10.0.0.53"],
|
|
217
|
+
* },
|
|
218
|
+
* },
|
|
219
|
+
* });
|
|
220
|
+
* ```
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* // Adopt an existing VPC service
|
|
224
|
+
* ```ts
|
|
225
|
+
* const vpcService = await VpcService("adopted-service", {
|
|
226
|
+
* name: "existing-service-name",
|
|
227
|
+
* adopt: true,
|
|
228
|
+
* host: {
|
|
229
|
+
* hostname: "localhost",
|
|
230
|
+
* resolverNetwork: { tunnel },
|
|
231
|
+
* },
|
|
232
|
+
* });
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
export const VpcService = Resource(
|
|
236
|
+
"cloudflare::VpcService",
|
|
237
|
+
async function (
|
|
238
|
+
this: Context<VpcService>,
|
|
239
|
+
id: string,
|
|
240
|
+
props: VpcServiceProps,
|
|
241
|
+
): Promise<VpcService> {
|
|
242
|
+
const api = await createCloudflareApi(props);
|
|
243
|
+
if (this.phase === "delete") {
|
|
244
|
+
if (this.output?.serviceId) {
|
|
245
|
+
await deleteService(api, this.output.serviceId);
|
|
246
|
+
}
|
|
247
|
+
return this.destroy();
|
|
248
|
+
}
|
|
249
|
+
const input: ConnectivityService.Input = {
|
|
250
|
+
name: props.name ?? this.scope.createPhysicalName(id),
|
|
251
|
+
type: props.serviceType ?? "http",
|
|
252
|
+
tcp_port: props.tcpPort,
|
|
253
|
+
app_protocol: props.appProtocol,
|
|
254
|
+
http_port: props.httpPort,
|
|
255
|
+
https_port: props.httpsPort,
|
|
256
|
+
host: normalizeHost(props.host),
|
|
257
|
+
};
|
|
258
|
+
switch (this.phase) {
|
|
259
|
+
case "create": {
|
|
260
|
+
const adopt = props.adopt ?? this.scope.adopt;
|
|
261
|
+
const service = await createService(api, input).catch(async (err) => {
|
|
262
|
+
if (isCloudflareApiError(err, { code: 5101 }) && adopt) {
|
|
263
|
+
const services = await listServices(api);
|
|
264
|
+
const service = services.find((s) => s.name === input.name);
|
|
265
|
+
if (service) {
|
|
266
|
+
return await updateService(api, service.service_id, input);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
throw err;
|
|
270
|
+
});
|
|
271
|
+
return formatOutput(service);
|
|
272
|
+
}
|
|
273
|
+
case "update": {
|
|
274
|
+
const service = await updateService(api, this.output.serviceId, input);
|
|
275
|
+
return formatOutput(service);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function normalizeHost(host: VpcService.Host): ConnectivityService.Host {
|
|
280
|
+
if ("hostname" in host) {
|
|
281
|
+
return {
|
|
282
|
+
hostname: host.hostname,
|
|
283
|
+
resolver_network: normalizeNetwork(host.resolverNetwork),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
...host,
|
|
288
|
+
network: normalizeNetwork(host.network),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function normalizeNetwork<T extends VpcService.Network>(
|
|
293
|
+
network: T,
|
|
294
|
+
): ConnectivityService.Network {
|
|
295
|
+
if ("tunnelId" in network) {
|
|
296
|
+
const { tunnelId, ...rest } = network;
|
|
297
|
+
return { tunnel_id: network.tunnelId, ...rest };
|
|
298
|
+
}
|
|
299
|
+
const { tunnel, ...rest } = network;
|
|
300
|
+
return { tunnel_id: tunnel.tunnelId, ...rest };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function formatOutput(service: ConnectivityService): VpcService {
|
|
304
|
+
return {
|
|
305
|
+
name: service.name,
|
|
306
|
+
serviceId: service.service_id,
|
|
307
|
+
serviceType: service.type,
|
|
308
|
+
tcpPort: service.tcp_port,
|
|
309
|
+
appProtocol: service.app_protocol,
|
|
310
|
+
httpPort: service.http_port,
|
|
311
|
+
httpsPort: service.https_port,
|
|
312
|
+
host:
|
|
313
|
+
"hostname" in service.host
|
|
314
|
+
? {
|
|
315
|
+
hostname: service.host.hostname,
|
|
316
|
+
resolverNetwork: {
|
|
317
|
+
tunnelId: service.host.resolver_network.tunnel_id,
|
|
318
|
+
resolverIps: service.host.resolver_network.resolver_ips,
|
|
319
|
+
},
|
|
320
|
+
}
|
|
321
|
+
: {
|
|
322
|
+
...service.host,
|
|
323
|
+
network: { tunnelId: service.host.network.tunnel_id },
|
|
324
|
+
},
|
|
325
|
+
createdAt: new Date(service.created_at).getTime(),
|
|
326
|
+
updatedAt: new Date(service.updated_at).getTime(),
|
|
327
|
+
type: "vpc_service",
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Create a connectivity (VPC) service via the Cloudflare API.
|
|
335
|
+
* @internal
|
|
336
|
+
*/
|
|
337
|
+
export async function createService(
|
|
338
|
+
api: CloudflareApi,
|
|
339
|
+
body: ConnectivityService.Input,
|
|
340
|
+
): Promise<ConnectivityService> {
|
|
341
|
+
return await extractCloudflareResult<ConnectivityService>(
|
|
342
|
+
`create connectivity service`,
|
|
343
|
+
api.post(
|
|
344
|
+
`/accounts/${api.accountId}/connectivity/directory/services`,
|
|
345
|
+
body,
|
|
346
|
+
),
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Delete a connectivity (VPC) service. No-op if the service is already gone (404).
|
|
352
|
+
* @internal
|
|
353
|
+
*/
|
|
354
|
+
export async function deleteService(
|
|
355
|
+
api: CloudflareApi,
|
|
356
|
+
serviceId: string,
|
|
357
|
+
): Promise<void> {
|
|
358
|
+
await extractCloudflareResult(
|
|
359
|
+
`delete connectivity service "${serviceId}"`,
|
|
360
|
+
api.delete(
|
|
361
|
+
`/accounts/${api.accountId}/connectivity/directory/services/${serviceId}`,
|
|
362
|
+
),
|
|
363
|
+
).catch((err) => {
|
|
364
|
+
if (!isCloudflareApiError(err, { status: 404 })) {
|
|
365
|
+
throw err;
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Fetch a single connectivity (VPC) service by ID.
|
|
372
|
+
* @internal
|
|
373
|
+
*/
|
|
374
|
+
export async function getService(
|
|
375
|
+
api: CloudflareApi,
|
|
376
|
+
serviceId: string,
|
|
377
|
+
): Promise<ConnectivityService> {
|
|
378
|
+
return await extractCloudflareResult<ConnectivityService>(
|
|
379
|
+
`get connectivity service "${serviceId}"`,
|
|
380
|
+
api.get(
|
|
381
|
+
`/accounts/${api.accountId}/connectivity/directory/services/${serviceId}`,
|
|
382
|
+
),
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* List connectivity (VPC) services for the account.
|
|
388
|
+
* @internal
|
|
389
|
+
*/
|
|
390
|
+
export async function listServices(
|
|
391
|
+
api: CloudflareApi,
|
|
392
|
+
): Promise<ConnectivityService[]> {
|
|
393
|
+
return await extractCloudflareResult<ConnectivityService[]>(
|
|
394
|
+
`list connectivity services`,
|
|
395
|
+
api.get(
|
|
396
|
+
`/accounts/${api.accountId}/connectivity/directory/services?per_page=1000`,
|
|
397
|
+
),
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Update an existing connectivity (VPC) service.
|
|
403
|
+
* @internal
|
|
404
|
+
*/
|
|
405
|
+
export async function updateService(
|
|
406
|
+
api: CloudflareApi,
|
|
407
|
+
serviceId: string,
|
|
408
|
+
body: ConnectivityService.Input,
|
|
409
|
+
): Promise<ConnectivityService> {
|
|
410
|
+
return await extractCloudflareResult<ConnectivityService>(
|
|
411
|
+
`update connectivity service "${serviceId}"`,
|
|
412
|
+
api.put(
|
|
413
|
+
`/accounts/${api.accountId}/connectivity/directory/services/${serviceId}`,
|
|
414
|
+
body,
|
|
415
|
+
),
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
interface ConnectivityService extends ConnectivityService.Input {
|
|
420
|
+
service_id: string;
|
|
421
|
+
created_at: string;
|
|
422
|
+
updated_at: string;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
declare namespace ConnectivityService {
|
|
426
|
+
export interface Input {
|
|
427
|
+
name: string;
|
|
428
|
+
type: "http";
|
|
429
|
+
tcp_port?: number;
|
|
430
|
+
app_protocol?: string;
|
|
431
|
+
http_port?: number;
|
|
432
|
+
https_port?: number;
|
|
433
|
+
host: Host;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export type Host = IPv4Host | IPv6Host | DualStackHost | HostnameHost;
|
|
437
|
+
|
|
438
|
+
export interface IPv4Host {
|
|
439
|
+
ipv4: string;
|
|
440
|
+
network: Network;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export interface IPv6Host {
|
|
444
|
+
ipv6: string;
|
|
445
|
+
network: Network;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export interface DualStackHost {
|
|
449
|
+
ipv4: string;
|
|
450
|
+
ipv6: string;
|
|
451
|
+
network: Network;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export interface Network {
|
|
455
|
+
tunnel_id: string;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export interface HostnameHost {
|
|
459
|
+
hostname: string;
|
|
460
|
+
resolver_network: ResolverNetwork;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export interface ResolverNetwork extends Network {
|
|
464
|
+
resolver_ips?: string[];
|
|
465
|
+
}
|
|
466
|
+
}
|
|
@@ -221,6 +221,7 @@ export interface WorkerMetadata {
|
|
|
221
221
|
placement?: WorkerPlacement;
|
|
222
222
|
limits?: {
|
|
223
223
|
cpu_ms?: number;
|
|
224
|
+
subrequests?: number;
|
|
224
225
|
};
|
|
225
226
|
tail_consumers?: Array<Worker | { service: string }>;
|
|
226
227
|
}
|
|
@@ -625,6 +626,13 @@ export async function prepareWorkerMetadata(
|
|
|
625
626
|
namespace_id: binding.namespace_id.toString(),
|
|
626
627
|
simple: binding.simple,
|
|
627
628
|
});
|
|
629
|
+
} else if (binding.type === "vpc_service") {
|
|
630
|
+
meta.bindings.push({
|
|
631
|
+
type: "vpc_service",
|
|
632
|
+
name: bindingName,
|
|
633
|
+
service_name: binding.name,
|
|
634
|
+
service_id: binding.serviceId,
|
|
635
|
+
});
|
|
628
636
|
} else {
|
|
629
637
|
assertNever(
|
|
630
638
|
binding,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
type CloudflareApi,
|
|
10
10
|
type CloudflareApiOptions,
|
|
11
11
|
} from "./api.ts";
|
|
12
|
-
import {
|
|
12
|
+
import { createWorkerUrl, enableWorkerSubdomain } from "./worker-subdomain.ts";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Properties for creating a Worker stub
|
|
@@ -105,26 +105,24 @@ export const WorkerStub = Resource("cloudflare::WorkerStub", async function <
|
|
|
105
105
|
return this.destroy();
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
const scriptName = props.name;
|
|
109
|
+
|
|
108
110
|
// If worker doesn't exist and we're in create phase, create an empty one
|
|
109
|
-
if (!(await exists(api,
|
|
110
|
-
await createEmptyWorker(api,
|
|
111
|
+
if (!(await exists(api, scriptName)) && this.phase === "create") {
|
|
112
|
+
await createEmptyWorker(api, scriptName);
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
// Configure URL if requested (defaults to true)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
...props,
|
|
118
|
-
scriptName: props.name,
|
|
119
|
-
})
|
|
120
|
-
: undefined;
|
|
116
|
+
if (props.url !== false) {
|
|
117
|
+
await enableWorkerSubdomain(api, scriptName);
|
|
118
|
+
}
|
|
121
119
|
|
|
122
120
|
// Return the worker stub info
|
|
123
121
|
return {
|
|
124
122
|
type: "service",
|
|
125
123
|
__rpc__: props.rpc as unknown as RPC,
|
|
126
124
|
...props,
|
|
127
|
-
url:
|
|
125
|
+
url: await createWorkerUrl(api, scriptName),
|
|
128
126
|
} as WorkerStub<RPC>;
|
|
129
127
|
});
|
|
130
128
|
|
|
@@ -4,11 +4,7 @@ import { memoize } from "../util/memoize.ts";
|
|
|
4
4
|
import { withExponentialBackoff } from "../util/retry.ts";
|
|
5
5
|
import { CloudflareApiError } from "./api-error.ts";
|
|
6
6
|
import { extractCloudflareResult } from "./api-response.ts";
|
|
7
|
-
import {
|
|
8
|
-
createCloudflareApi,
|
|
9
|
-
type CloudflareApi,
|
|
10
|
-
type CloudflareApiOptions,
|
|
11
|
-
} from "./api.ts";
|
|
7
|
+
import { type CloudflareApi, type CloudflareApiOptions } from "./api.ts";
|
|
12
8
|
|
|
13
9
|
interface WorkerSubdomainProps extends CloudflareApiOptions {
|
|
14
10
|
/**
|
|
@@ -21,6 +17,14 @@ interface WorkerSubdomainProps extends CloudflareApiOptions {
|
|
|
21
17
|
* @default undefined
|
|
22
18
|
*/
|
|
23
19
|
previewVersionId?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to enable previews for the subdomain.
|
|
22
|
+
*
|
|
23
|
+
* Must be `false` when the worker has Durable Object bindings.
|
|
24
|
+
*
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
previewsEnabled?: boolean;
|
|
24
28
|
/**
|
|
25
29
|
* Prevents the subdomain from being deleted when the worker is deleted.
|
|
26
30
|
*
|
|
@@ -37,12 +41,7 @@ interface WorkerSubdomainProps extends CloudflareApiOptions {
|
|
|
37
41
|
dev?: boolean;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
export interface WorkerSubdomain {
|
|
41
|
-
/**
|
|
42
|
-
* The `workers.dev` URL for the worker or preview version.
|
|
43
|
-
*/
|
|
44
|
-
url: string;
|
|
45
|
-
}
|
|
44
|
+
export interface WorkerSubdomain {}
|
|
46
45
|
|
|
47
46
|
export const WorkerSubdomain = Resource(
|
|
48
47
|
"cloudflare::WorkerSubdomain",
|
|
@@ -51,31 +50,10 @@ export const WorkerSubdomain = Resource(
|
|
|
51
50
|
_id: string,
|
|
52
51
|
props: WorkerSubdomainProps,
|
|
53
52
|
) {
|
|
54
|
-
if (this.scope.local && props.dev) {
|
|
55
|
-
return {
|
|
56
|
-
url: this.output?.url ?? "https://unavailable.alchemy.run",
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const api = await createCloudflareApi(props);
|
|
61
53
|
if (this.phase === "delete") {
|
|
62
|
-
if (!props.retain) {
|
|
63
|
-
await disableWorkerSubdomain(api, props.scriptName);
|
|
64
|
-
}
|
|
65
54
|
return this.destroy();
|
|
66
55
|
}
|
|
67
|
-
|
|
68
|
-
const subdomain = await getAccountSubdomain(api);
|
|
69
|
-
const base = `${subdomain}.workers.dev`;
|
|
70
|
-
let url: string;
|
|
71
|
-
if (props.previewVersionId) {
|
|
72
|
-
url = `https://${props.previewVersionId.substring(0, 8)}-${props.scriptName}.${base}`;
|
|
73
|
-
} else {
|
|
74
|
-
url = `https://${props.scriptName}.${base}`;
|
|
75
|
-
}
|
|
76
|
-
return {
|
|
77
|
-
url,
|
|
78
|
-
};
|
|
56
|
+
return {};
|
|
79
57
|
},
|
|
80
58
|
);
|
|
81
59
|
|
|
@@ -102,6 +80,7 @@ export async function disableWorkerSubdomain(
|
|
|
102
80
|
export async function enableWorkerSubdomain(
|
|
103
81
|
api: CloudflareApi,
|
|
104
82
|
scriptName: string,
|
|
83
|
+
previewsEnabled: boolean = true,
|
|
105
84
|
) {
|
|
106
85
|
await withExponentialBackoff(
|
|
107
86
|
() =>
|
|
@@ -111,7 +90,7 @@ export async function enableWorkerSubdomain(
|
|
|
111
90
|
`/accounts/${api.accountId}/workers/scripts/${scriptName}/subdomain`,
|
|
112
91
|
{
|
|
113
92
|
enabled: true,
|
|
114
|
-
previews_enabled:
|
|
93
|
+
previews_enabled: previewsEnabled,
|
|
115
94
|
},
|
|
116
95
|
),
|
|
117
96
|
),
|
|
@@ -160,3 +139,19 @@ export const getAccountSubdomain = memoize(
|
|
|
160
139
|
},
|
|
161
140
|
(api) => api.accountId,
|
|
162
141
|
);
|
|
142
|
+
|
|
143
|
+
export async function createWorkerUrl(
|
|
144
|
+
api: CloudflareApi,
|
|
145
|
+
scriptName: string,
|
|
146
|
+
previewVersionId?: string,
|
|
147
|
+
) {
|
|
148
|
+
const subdomain = await getAccountSubdomain(api);
|
|
149
|
+
const base = `${subdomain}.workers.dev`;
|
|
150
|
+
let url: string;
|
|
151
|
+
if (previewVersionId) {
|
|
152
|
+
url = `https://${previewVersionId.substring(0, 8)}-${scriptName}.${base}`;
|
|
153
|
+
} else {
|
|
154
|
+
url = `https://${scriptName}.${base}`;
|
|
155
|
+
}
|
|
156
|
+
return url;
|
|
157
|
+
}
|