devflare 1.0.0-next.60 → 1.0.0-next.62
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/_chunks/{build-Dp8k2SWa.js → build-Bipv3UYU.js} +1 -1
- package/dist/_chunks/{build-artifacts-DLEYfdVL.js → build-artifacts-B5OsATal.js} +1 -1
- package/dist/_chunks/{cli-BlVetiEh.js → cli-sOZfXGua.js} +3 -3
- package/dist/_chunks/{context-CX50Y2Kb.js → context-B6S7cqQW.js} +272 -68
- package/dist/_chunks/{deploy-Blrdr3Gv.js → deploy-cU11igDG.js} +1 -1
- package/dist/_chunks/{dev-DRP6LR2H.js → dev-9XMiBRSG.js} +84 -9
- package/dist/_chunks/{env-S0_nMVz1.js → env-UqevBSTd.js} +1 -1
- package/dist/_chunks/{runtime-RekfD_2X.js → runtime-sEr9b0ns.js} +1 -1
- package/dist/_chunks/{vite-CtvgOi1c.js → vite-CzqppgNp.js} +1 -1
- package/dist/bridge/client.d.ts +47 -4
- package/dist/bridge/client.d.ts.map +1 -1
- package/dist/bridge/do-rpc-dispatch.d.ts +23 -0
- package/dist/bridge/do-rpc-dispatch.d.ts.map +1 -0
- package/dist/bridge/do-websocket-connect.d.ts +33 -0
- package/dist/bridge/do-websocket-connect.d.ts.map +1 -0
- package/dist/bridge/gateway-runtime.d.ts +1 -1
- package/dist/bridge/gateway-runtime.d.ts.map +1 -1
- package/dist/bridge/proxy.d.ts.map +1 -1
- package/dist/bridge/server.d.ts.map +1 -1
- package/dist/bridge/websocket-constructor.d.ts +38 -0
- package/dist/bridge/websocket-constructor.d.ts.map +1 -0
- package/dist/browser.js +2 -2
- package/dist/cli/index.js +1 -1
- package/dist/dev-server/gateway-script.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/runtime/index.js +2 -2
- package/dist/sveltekit/index.js +1 -1
- package/dist/test/index.js +36 -3
- package/dist/test/simple-context-gateway-script.d.ts.map +1 -1
- package/dist/vite/index.js +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as cyanBold, f as logLine, o as dim, r as createCliTheme } from "./ui-BUoZApvE.js";
|
|
2
|
-
import { t as prepareBuildArtifacts } from "./build-artifacts-
|
|
2
|
+
import { t as prepareBuildArtifacts } from "./build-artifacts-B5OsATal.js";
|
|
3
3
|
//#region src/cli/commands/build.ts
|
|
4
4
|
async function runBuildCommand(parsed, logger, options) {
|
|
5
5
|
const theme = createCliTheme(parsed.options);
|
|
@@ -4,7 +4,7 @@ import { c as writeWranglerConfig, i as isolateViteBuildOutputPaths$1, o as reba
|
|
|
4
4
|
import { f as logLine } from "./ui-BUoZApvE.js";
|
|
5
5
|
import { n as getPackageVersion } from "./package-metadata-DjHBLB-z.js";
|
|
6
6
|
import { t as resolvePackageSpecifier } from "./resolve-package-qizBfCIm.js";
|
|
7
|
-
import { i as writeGeneratedViteConfig, l as prepareComposedWorkerEntrypoint, n as resolveEffectiveViteProject } from "./vite-
|
|
7
|
+
import { i as writeGeneratedViteConfig, l as prepareComposedWorkerEntrypoint, n as resolveEffectiveViteProject } from "./vite-CzqppgNp.js";
|
|
8
8
|
import { t as bundleWorkerEntry } from "./worker-bundler-dTTnYU3n.js";
|
|
9
9
|
import { t as detectViteProject } from "./vite-utils-OVLMV605.js";
|
|
10
10
|
import { t as getDependencies } from "./dependencies-C2oxFjU_.js";
|
|
@@ -1101,15 +1101,15 @@ async function runInit(parsed, logger, options) {
|
|
|
1101
1101
|
return runInitCommand(parsed, logger, options);
|
|
1102
1102
|
}
|
|
1103
1103
|
async function runDev(parsed, logger, options) {
|
|
1104
|
-
const { runDevCommand } = await import("./dev-
|
|
1104
|
+
const { runDevCommand } = await import("./dev-9XMiBRSG.js");
|
|
1105
1105
|
return runDevCommand(parsed, logger, options);
|
|
1106
1106
|
}
|
|
1107
1107
|
async function runBuild(parsed, logger, options) {
|
|
1108
|
-
const { runBuildCommand } = await import("./build-
|
|
1108
|
+
const { runBuildCommand } = await import("./build-Bipv3UYU.js");
|
|
1109
1109
|
return runBuildCommand(parsed, logger, options);
|
|
1110
1110
|
}
|
|
1111
1111
|
async function runDeploy(parsed, logger, options) {
|
|
1112
|
-
const { runDeployCommand } = await import("./deploy-
|
|
1112
|
+
const { runDeployCommand } = await import("./deploy-cU11igDG.js");
|
|
1113
1113
|
return runDeployCommand(parsed, logger, {
|
|
1114
1114
|
...options,
|
|
1115
1115
|
requireExplicitDeployTarget: true
|
|
@@ -1,5 +1,234 @@
|
|
|
1
1
|
import { wrapEnvSendEmailBindings } from "../utils/send-email.js";
|
|
2
2
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
//#region src/bridge/v2/wire.ts
|
|
4
|
+
/** Binary frame kinds */
|
|
5
|
+
const BinaryKind = {
|
|
6
|
+
StreamChunk: 1,
|
|
7
|
+
WsData: 2
|
|
8
|
+
};
|
|
9
|
+
/** Binary frame flags */
|
|
10
|
+
const BinaryFlags = {
|
|
11
|
+
FIN: 1,
|
|
12
|
+
TEXT: 2
|
|
13
|
+
};
|
|
14
|
+
/** Encode a binary frame */
|
|
15
|
+
function encodeBinaryFrame(kind, id, seq, flags, payload) {
|
|
16
|
+
const frame = new Uint8Array(10 + payload.byteLength);
|
|
17
|
+
const view = new DataView(frame.buffer);
|
|
18
|
+
view.setUint8(0, kind);
|
|
19
|
+
view.setUint32(1, id, true);
|
|
20
|
+
view.setUint32(5, seq, true);
|
|
21
|
+
view.setUint8(9, flags);
|
|
22
|
+
frame.set(payload, 10);
|
|
23
|
+
return frame;
|
|
24
|
+
}
|
|
25
|
+
/** Parse a JSON message from string */
|
|
26
|
+
function parseJsonMsg(data) {
|
|
27
|
+
const msg = JSON.parse(data);
|
|
28
|
+
if (typeof msg !== "object" || msg === null || !("t" in msg)) throw new Error("Invalid message: missing type field");
|
|
29
|
+
return msg;
|
|
30
|
+
}
|
|
31
|
+
/** Stringify a JSON message */
|
|
32
|
+
function stringifyJsonMsg(msg) {
|
|
33
|
+
return JSON.stringify(msg);
|
|
34
|
+
}
|
|
35
|
+
let streamIdCounter = 0;
|
|
36
|
+
let wsIdCounter = 0;
|
|
37
|
+
/** Generate unique stream ID */
|
|
38
|
+
function nextStreamId() {
|
|
39
|
+
return ++streamIdCounter;
|
|
40
|
+
}
|
|
41
|
+
/** Generate unique WebSocket proxy ID */
|
|
42
|
+
function nextWsId() {
|
|
43
|
+
return ++wsIdCounter;
|
|
44
|
+
}
|
|
45
|
+
/** Default chunk size for streaming (256 KB) */
|
|
46
|
+
const DEFAULT_CHUNK_SIZE = 256 * 1024;
|
|
47
|
+
/** Threshold for switching to HTTP transfer (512 KB — workerd ~1MB WS message limit). */
|
|
48
|
+
const HTTP_TRANSFER_THRESHOLD = 512 * 1024;
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/bridge/websocket-constructor.ts
|
|
51
|
+
let wsPackageConstructorPromise = null;
|
|
52
|
+
/**
|
|
53
|
+
* Lazily import the `ws` package's WebSocket constructor (memoized). Used as the
|
|
54
|
+
* Node fallback and whenever custom upgrade headers are required — unlike the
|
|
55
|
+
* platform global, the `ws` constructor accepts an options object with headers.
|
|
56
|
+
*
|
|
57
|
+
* @returns The `ws` package WebSocket constructor.
|
|
58
|
+
* @throws When the `ws` package does not export a usable WebSocket implementation.
|
|
59
|
+
*/
|
|
60
|
+
async function importWsPackageConstructor() {
|
|
61
|
+
if (!wsPackageConstructorPromise) wsPackageConstructorPromise = (async () => {
|
|
62
|
+
const wsModule = await new Function("specifier", [
|
|
63
|
+
"return ",
|
|
64
|
+
"import",
|
|
65
|
+
"(specifier)"
|
|
66
|
+
].join(""))("ws");
|
|
67
|
+
const defaultExport = wsModule.default;
|
|
68
|
+
const wsConstructor = wsModule.WebSocket ?? (typeof defaultExport === "object" && defaultExport !== null ? defaultExport.WebSocket : void 0) ?? defaultExport;
|
|
69
|
+
if (typeof wsConstructor !== "function") throw new Error("Could not load a WebSocket client implementation from the ws package");
|
|
70
|
+
return wsConstructor;
|
|
71
|
+
})();
|
|
72
|
+
return wsPackageConstructorPromise;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Return the runtime's global WebSocket constructor, or null when the runtime
|
|
76
|
+
* has none (older Node without a global WebSocket).
|
|
77
|
+
*
|
|
78
|
+
* @param runtimeWebSocket - The candidate global (defaults to `globalThis.WebSocket`).
|
|
79
|
+
* @returns The global constructor, or null.
|
|
80
|
+
*/
|
|
81
|
+
function getRuntimeWebSocketConstructor(runtimeWebSocket = globalThis.WebSocket) {
|
|
82
|
+
if (typeof runtimeWebSocket === "function") return runtimeWebSocket;
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve a WebSocket constructor for the bridge socket: prefer the runtime
|
|
87
|
+
* global, fall back to the `ws` package.
|
|
88
|
+
*
|
|
89
|
+
* @param runtimeWebSocket - The candidate global (defaults to `globalThis.WebSocket`).
|
|
90
|
+
* @returns A usable WebSocket constructor.
|
|
91
|
+
*/
|
|
92
|
+
async function resolveBridgeWebSocketConstructor(runtimeWebSocket = globalThis.WebSocket) {
|
|
93
|
+
const runtimeConstructor = getRuntimeWebSocketConstructor(runtimeWebSocket);
|
|
94
|
+
if (runtimeConstructor) return runtimeConstructor;
|
|
95
|
+
return importWsPackageConstructor();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Resolve the WebSocket constructor for a Durable Object pass-through
|
|
99
|
+
* connection. Custom upgrade headers require the `ws` package (whose constructor
|
|
100
|
+
* accepts an options object); the global WebSocket (undici/Bun) cannot set
|
|
101
|
+
* request headers, so it is used only when there are no headers to forward.
|
|
102
|
+
*
|
|
103
|
+
* @param hasHeaders - Whether application headers must ride the upgrade request.
|
|
104
|
+
* @returns A WebSocket constructor suitable for the connection.
|
|
105
|
+
*/
|
|
106
|
+
async function resolveDoWebSocketConstructor(hasHeaders) {
|
|
107
|
+
if (hasHeaders) return importWsPackageConstructor();
|
|
108
|
+
return resolveBridgeWebSocketConstructor();
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/bridge/do-websocket-connect.ts
|
|
112
|
+
/**
|
|
113
|
+
* Hop-by-hop / WebSocket-control request headers that the WebSocket client sets
|
|
114
|
+
* itself. They must never be copied from the user's `connect(url, { headers })`
|
|
115
|
+
* onto the outgoing upgrade — a duplicate `Upgrade`/`Sec-WebSocket-*` breaks the
|
|
116
|
+
* handshake (the `ws` package rejects it). Auth/cookie headers are preserved.
|
|
117
|
+
*/
|
|
118
|
+
const WS_CONTROL_HEADERS = new Set([
|
|
119
|
+
"upgrade",
|
|
120
|
+
"connection",
|
|
121
|
+
"host",
|
|
122
|
+
"sec-websocket-key",
|
|
123
|
+
"sec-websocket-version",
|
|
124
|
+
"sec-websocket-extensions",
|
|
125
|
+
"sec-websocket-protocol"
|
|
126
|
+
]);
|
|
127
|
+
/**
|
|
128
|
+
* Strip WebSocket-control headers from user-supplied upgrade headers, leaving
|
|
129
|
+
* only the application headers (auth, cookies) worth forwarding to the DO.
|
|
130
|
+
*
|
|
131
|
+
* @param headers - Header tuples from `connect(url, { headers })`, or undefined.
|
|
132
|
+
* @returns A plain object of the forwardable headers (may be empty).
|
|
133
|
+
*/
|
|
134
|
+
function forwardableUpgradeHeaders(headers) {
|
|
135
|
+
const out = {};
|
|
136
|
+
for (const [key, value] of headers ?? []) if (!WS_CONTROL_HEADERS.has(key.toLowerCase())) out[key] = value;
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Normalize an inbound WebSocket payload to the `Uint8Array | string` contract
|
|
141
|
+
* the DO Socket facade expects: text frames stay strings, binary frames become
|
|
142
|
+
* a `Uint8Array` view regardless of whether the runtime delivered an
|
|
143
|
+
* `ArrayBuffer`, a `Buffer`, or another typed-array/DataView.
|
|
144
|
+
*
|
|
145
|
+
* @param data - The raw `MessageEvent.data` from the DO pass-through socket.
|
|
146
|
+
* @returns The payload as a string (text) or `Uint8Array` (binary).
|
|
147
|
+
*/
|
|
148
|
+
function normalizeIncomingWsData(data) {
|
|
149
|
+
if (typeof data === "string") return data;
|
|
150
|
+
if (data instanceof Uint8Array) return data;
|
|
151
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
152
|
+
if (ArrayBuffer.isView(data)) {
|
|
153
|
+
const view = data;
|
|
154
|
+
return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
|
|
155
|
+
}
|
|
156
|
+
return String(data);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Open a real pass-through WebSocket to a Durable Object through the gateway's
|
|
160
|
+
* `/_devflare/do-ws` endpoint. Unlike the legacy relay, this is a standalone
|
|
161
|
+
* connection with its own lifecycle, so it is unaffected by the bridge client's
|
|
162
|
+
* `disconnect()`/reconnect bookkeeping.
|
|
163
|
+
*
|
|
164
|
+
* @param bridgeUrl - The bridge/gateway base URL (e.g. `ws://127.0.0.1:8787`).
|
|
165
|
+
* @param binding - DO namespace binding name (e.g. `DOC_ROOM`).
|
|
166
|
+
* @param idHex - Already-resolved Durable Object id, hex form.
|
|
167
|
+
* @param targetUrl - The DO fetch URL the caller passed to `stub.connect(url)`.
|
|
168
|
+
* @param headers - Optional upgrade headers (auth/cookies) forwarded to the DO.
|
|
169
|
+
* @returns A proxy surface (send/close/onMessage/onClose) over the socket.
|
|
170
|
+
* @throws When the pass-through socket fails to open (bad binding/id, or the DO
|
|
171
|
+
* rejected the upgrade).
|
|
172
|
+
*/
|
|
173
|
+
async function openDurableObjectWebSocket(bridgeUrl, binding, idHex, targetUrl, headers) {
|
|
174
|
+
const wsUrl = new URL(bridgeUrl);
|
|
175
|
+
wsUrl.pathname = "/_devflare/do-ws";
|
|
176
|
+
wsUrl.searchParams.set("binding", binding);
|
|
177
|
+
wsUrl.searchParams.set("id", idHex);
|
|
178
|
+
wsUrl.searchParams.set("u", targetUrl);
|
|
179
|
+
const forwardHeaders = forwardableUpgradeHeaders(headers);
|
|
180
|
+
const hasHeaders = Object.keys(forwardHeaders).length > 0;
|
|
181
|
+
const WebSocketCtor = await resolveDoWebSocketConstructor(hasHeaders);
|
|
182
|
+
const socket = hasHeaders ? new WebSocketCtor(wsUrl.toString(), { headers: forwardHeaders }) : new WebSocketCtor(wsUrl.toString());
|
|
183
|
+
socket.binaryType = "arraybuffer";
|
|
184
|
+
let opened = false;
|
|
185
|
+
let messageHandler = null;
|
|
186
|
+
let closeHandler = null;
|
|
187
|
+
const pendingMessages = [];
|
|
188
|
+
let pendingClose = null;
|
|
189
|
+
socket.onmessage = (event) => {
|
|
190
|
+
const data = normalizeIncomingWsData(event.data);
|
|
191
|
+
if (messageHandler) messageHandler(data);
|
|
192
|
+
else pendingMessages.push(data);
|
|
193
|
+
};
|
|
194
|
+
await new Promise((resolve, reject) => {
|
|
195
|
+
socket.onopen = () => {
|
|
196
|
+
opened = true;
|
|
197
|
+
resolve();
|
|
198
|
+
};
|
|
199
|
+
socket.onerror = () => {
|
|
200
|
+
if (!opened) reject(/* @__PURE__ */ new Error(`DO WebSocket connection failed: ${binding}/${idHex}`));
|
|
201
|
+
};
|
|
202
|
+
socket.onclose = (event) => {
|
|
203
|
+
if (!opened) {
|
|
204
|
+
reject(/* @__PURE__ */ new Error(`DO WebSocket closed before open: ${binding}/${idHex}`));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (closeHandler) closeHandler(event?.code, event?.reason);
|
|
208
|
+
else pendingClose = {
|
|
209
|
+
code: event?.code,
|
|
210
|
+
reason: event?.reason
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
wid: nextWsId(),
|
|
216
|
+
send: (data) => socket.send(data),
|
|
217
|
+
close: (code, reason) => socket.close(code, reason),
|
|
218
|
+
onMessage: (handler) => {
|
|
219
|
+
messageHandler = handler;
|
|
220
|
+
if (pendingMessages.length > 0) for (const data of pendingMessages.splice(0)) handler(data);
|
|
221
|
+
},
|
|
222
|
+
onClose: (handler) => {
|
|
223
|
+
closeHandler = handler;
|
|
224
|
+
if (pendingClose) {
|
|
225
|
+
handler(pendingClose.code, pendingClose.reason);
|
|
226
|
+
pendingClose = null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
3
232
|
//#region src/bridge/log.ts
|
|
4
233
|
const isDebugEnabled = () => {
|
|
5
234
|
try {
|
|
@@ -479,53 +708,6 @@ function tryParseWireError(data) {
|
|
|
479
708
|
return parsed;
|
|
480
709
|
}
|
|
481
710
|
//#endregion
|
|
482
|
-
//#region src/bridge/v2/wire.ts
|
|
483
|
-
/** Binary frame kinds */
|
|
484
|
-
const BinaryKind = {
|
|
485
|
-
StreamChunk: 1,
|
|
486
|
-
WsData: 2
|
|
487
|
-
};
|
|
488
|
-
/** Binary frame flags */
|
|
489
|
-
const BinaryFlags = {
|
|
490
|
-
FIN: 1,
|
|
491
|
-
TEXT: 2
|
|
492
|
-
};
|
|
493
|
-
/** Encode a binary frame */
|
|
494
|
-
function encodeBinaryFrame(kind, id, seq, flags, payload) {
|
|
495
|
-
const frame = new Uint8Array(10 + payload.byteLength);
|
|
496
|
-
const view = new DataView(frame.buffer);
|
|
497
|
-
view.setUint8(0, kind);
|
|
498
|
-
view.setUint32(1, id, true);
|
|
499
|
-
view.setUint32(5, seq, true);
|
|
500
|
-
view.setUint8(9, flags);
|
|
501
|
-
frame.set(payload, 10);
|
|
502
|
-
return frame;
|
|
503
|
-
}
|
|
504
|
-
/** Parse a JSON message from string */
|
|
505
|
-
function parseJsonMsg(data) {
|
|
506
|
-
const msg = JSON.parse(data);
|
|
507
|
-
if (typeof msg !== "object" || msg === null || !("t" in msg)) throw new Error("Invalid message: missing type field");
|
|
508
|
-
return msg;
|
|
509
|
-
}
|
|
510
|
-
/** Stringify a JSON message */
|
|
511
|
-
function stringifyJsonMsg(msg) {
|
|
512
|
-
return JSON.stringify(msg);
|
|
513
|
-
}
|
|
514
|
-
let streamIdCounter = 0;
|
|
515
|
-
let wsIdCounter = 0;
|
|
516
|
-
/** Generate unique stream ID */
|
|
517
|
-
function nextStreamId() {
|
|
518
|
-
return ++streamIdCounter;
|
|
519
|
-
}
|
|
520
|
-
/** Generate unique WebSocket proxy ID */
|
|
521
|
-
function nextWsId() {
|
|
522
|
-
return ++wsIdCounter;
|
|
523
|
-
}
|
|
524
|
-
/** Default chunk size for streaming (256 KB) */
|
|
525
|
-
const DEFAULT_CHUNK_SIZE = 256 * 1024;
|
|
526
|
-
/** Threshold for switching to HTTP transfer (512 KB — workerd ~1MB WS message limit). */
|
|
527
|
-
const HTTP_TRANSFER_THRESHOLD = 512 * 1024;
|
|
528
|
-
//#endregion
|
|
529
711
|
//#region src/bridge/v2/value-serialization.ts
|
|
530
712
|
/** Serialize a Request to a POJO */
|
|
531
713
|
async function serializeRequest(request, options) {
|
|
@@ -859,25 +1041,6 @@ const BRIDGE_CLIENT_CAPABILITIES = [
|
|
|
859
1041
|
"ws-relay",
|
|
860
1042
|
"http-transfer"
|
|
861
1043
|
];
|
|
862
|
-
let wsPackageConstructorPromise = null;
|
|
863
|
-
async function importWsPackageConstructor() {
|
|
864
|
-
if (!wsPackageConstructorPromise) wsPackageConstructorPromise = (async () => {
|
|
865
|
-
const wsModule = await new Function("specifier", [
|
|
866
|
-
"return ",
|
|
867
|
-
"import",
|
|
868
|
-
"(specifier)"
|
|
869
|
-
].join(""))("ws");
|
|
870
|
-
const defaultExport = wsModule.default;
|
|
871
|
-
const wsConstructor = wsModule.WebSocket ?? (typeof defaultExport === "object" && defaultExport !== null ? defaultExport.WebSocket : void 0) ?? defaultExport;
|
|
872
|
-
if (typeof wsConstructor !== "function") throw new Error("Could not load a WebSocket client implementation from the ws package");
|
|
873
|
-
return wsConstructor;
|
|
874
|
-
})();
|
|
875
|
-
return wsPackageConstructorPromise;
|
|
876
|
-
}
|
|
877
|
-
function getRuntimeWebSocketConstructor(runtimeWebSocket = globalThis.WebSocket) {
|
|
878
|
-
if (typeof runtimeWebSocket === "function") return runtimeWebSocket;
|
|
879
|
-
return null;
|
|
880
|
-
}
|
|
881
1044
|
var BridgeClient = class {
|
|
882
1045
|
ws = null;
|
|
883
1046
|
codec = null;
|
|
@@ -1072,7 +1235,18 @@ var BridgeClient = class {
|
|
|
1072
1235
|
if (current.size === 0) this.eventListeners.delete(topic);
|
|
1073
1236
|
};
|
|
1074
1237
|
}
|
|
1075
|
-
/**
|
|
1238
|
+
/**
|
|
1239
|
+
* Create a proxied WebSocket to a Durable Object via the in-process bridge
|
|
1240
|
+
* relay (`ws.open` control frame → gateway `stub.fetch()` pump → `WsData`
|
|
1241
|
+
* frames).
|
|
1242
|
+
*
|
|
1243
|
+
* DEPRECATED for DO connect(): this relay pumps the DO's WebSocket in-process,
|
|
1244
|
+
* which does NOT trigger workerd's hibernation dispatch — so a DO that uses
|
|
1245
|
+
* `ctx.acceptWebSocket()` never sees `webSocketMessage`/`webSocketClose` and
|
|
1246
|
+
* cross-socket `ctx.getWebSockets()` broadcasts never cross. `connect()` now
|
|
1247
|
+
* uses `openDoWebSocket()` (a real pass-through) instead. This method is
|
|
1248
|
+
* retained for the `ws-relay` wire capability and backward compatibility.
|
|
1249
|
+
*/
|
|
1076
1250
|
async createWsProxy(binding, id, url, headers) {
|
|
1077
1251
|
await this.ensureConnected();
|
|
1078
1252
|
const wid = nextWsId();
|
|
@@ -1131,6 +1305,36 @@ var BridgeClient = class {
|
|
|
1131
1305
|
}
|
|
1132
1306
|
};
|
|
1133
1307
|
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Open a REAL WebSocket to the gateway's DO pass-through endpoint
|
|
1310
|
+
* (`/_devflare/do-ws`), which forwards the upgrade to the target Durable
|
|
1311
|
+
* Object and passes through its `101` response.
|
|
1312
|
+
*
|
|
1313
|
+
* This is the ONLY way a bridged DO WebSocket triggers the runtime's
|
|
1314
|
+
* hibernation dispatch under miniflare: the gateway returns the DO's client
|
|
1315
|
+
* socket for a genuine inbound connection, so workerd pumps it and invokes
|
|
1316
|
+
* `webSocketMessage`/`webSocketClose` and delivers `ctx.getWebSockets()`
|
|
1317
|
+
* broadcasts. The legacy in-process relay (`createWsProxy` + gateway
|
|
1318
|
+
* `stub.fetch()` pump) never fires hibernation, so two sockets to the same
|
|
1319
|
+
* `getByName(id)` could not see each other's messages. Here they share ONE DO
|
|
1320
|
+
* instance and broadcast across each other, exactly as on real Cloudflare.
|
|
1321
|
+
*
|
|
1322
|
+
* Unlike `createWsProxy`, this does not multiplex over the bridge socket: it
|
|
1323
|
+
* is a standalone connection (see `openDurableObjectWebSocket`) with its own
|
|
1324
|
+
* lifecycle, so it is unaffected by the bridge client's disconnect/reconnect
|
|
1325
|
+
* bookkeeping. It also does not require the bridge socket to be connected.
|
|
1326
|
+
*
|
|
1327
|
+
* @param binding - DO namespace binding name (e.g. `DOC_ROOM`).
|
|
1328
|
+
* @param idHex - Already-resolved Durable Object id, hex form.
|
|
1329
|
+
* @param targetUrl - The DO fetch URL the caller passed to `stub.connect(url)`.
|
|
1330
|
+
* @param headers - Optional upgrade headers (auth/cookies) forwarded to the DO.
|
|
1331
|
+
* @returns A minimal proxy surface (send/close/onMessage/onClose) over the socket.
|
|
1332
|
+
* @throws When the pass-through socket fails to open (bad binding/id, or the
|
|
1333
|
+
* DO rejected the upgrade).
|
|
1334
|
+
*/
|
|
1335
|
+
async openDoWebSocket(binding, idHex, targetUrl, headers) {
|
|
1336
|
+
return openDurableObjectWebSocket(this.url, binding, idHex, targetUrl, headers);
|
|
1337
|
+
}
|
|
1134
1338
|
/** Create a readable stream that pulls from the bridge */
|
|
1135
1339
|
createReadableStream(sid) {
|
|
1136
1340
|
return new ReadableStream({
|
|
@@ -1574,7 +1778,7 @@ function createDOStubProxy(client, bindingName, idInfo, proxyOptions = {}) {
|
|
|
1574
1778
|
if (options?.headers) new Headers(options.headers).forEach((value, key) => {
|
|
1575
1779
|
headersList.push([key, value]);
|
|
1576
1780
|
});
|
|
1577
|
-
const wsProxy = await client.
|
|
1781
|
+
const wsProxy = await client.openDoWebSocket(bindingName, id.hex, url, headersList);
|
|
1578
1782
|
let readController = null;
|
|
1579
1783
|
const readable = new ReadableStream({
|
|
1580
1784
|
start(controller) {
|
|
@@ -7,7 +7,7 @@ import { _ as yellowBold, d as green, f as logLine, g as yellow, o as dim, r as
|
|
|
7
7
|
import { n as getPackageVersion } from "./package-metadata-DjHBLB-z.js";
|
|
8
8
|
import { t as resolvePackageSpecifier } from "./resolve-package-qizBfCIm.js";
|
|
9
9
|
import { t as asOptionalString } from "./command-utils-CSnoFdxM.js";
|
|
10
|
-
import { a as createBuildManifest, i as compareManifests, n as applyDeploymentStrategy, o as formatDriftWarning, r as describeDeploymentStrategy, s as readBuildManifest, t as prepareBuildArtifacts } from "./build-artifacts-
|
|
10
|
+
import { a as createBuildManifest, i as compareManifests, n as applyDeploymentStrategy, o as formatDriftWarning, r as describeDeploymentStrategy, s as readBuildManifest, t as prepareBuildArtifacts } from "./build-artifacts-B5OsATal.js";
|
|
11
11
|
import { t as getDependencies } from "./dependencies-C2oxFjU_.js";
|
|
12
12
|
import { n as preparePreviewScopedResourcesForDeploy } from "./preview-resources-D_aFwtZR.js";
|
|
13
13
|
import { mkdir, open, readFile, rm, writeFile } from "node:fs/promises";
|
|
@@ -7,7 +7,7 @@ import { clearLocalSendEmailBindings, setLocalSendEmailBindings } from "../utils
|
|
|
7
7
|
import { C as buildSendEmailConfig, D as buildVersionMetadataConfig, E as buildTailConsumersConfig, O as buildWorkerLoadersConfig, S as buildSecretsStoreConfig, T as buildStreamingTailConsumersConfig, _ as buildMtlsCertificatesConfig, b as buildQueueProducers, c as buildAiSearchInstancesConfig, d as buildArtifactsConfig, f as buildDispatchNamespacesConfig, g as buildMediaConfig, h as buildImagesConfig, k as buildWorkflowsConfig, l as buildAiSearchNamespacesConfig, m as buildHyperdrivesConfig, n as getRouteDirectoryCandidate, p as buildFlagshipConfig, s as resolveServiceBindings, t as discoverRoutes, u as buildAnalyticsEngineConfig, v as buildPipelinesConfig, w as buildStreamConfig, x as buildRateLimitsConfig, y as buildQueueConsumers } from "./routes-BMU7ga_l.js";
|
|
8
8
|
import { r as transformDurableObject } from "./durable-object-DMtH0XYX.js";
|
|
9
9
|
import { i as findFiles } from "./glob-CmQOvunB.js";
|
|
10
|
-
import { d as DEFAULT_FETCH_ENTRY_FILES, f as DEFAULT_QUEUE_ENTRY_FILES, g as discoverDurableObjectFiles, h as resolveWorkerSurfacePaths, i as writeGeneratedViteConfig, l as prepareComposedWorkerEntrypoint, m as hasWorkerSurfacePaths, n as resolveEffectiveViteProject, p as DEFAULT_SCHEDULED_ENTRY_FILES, u as DEFAULT_EMAIL_ENTRY_FILES } from "./vite-
|
|
10
|
+
import { d as DEFAULT_FETCH_ENTRY_FILES, f as DEFAULT_QUEUE_ENTRY_FILES, g as discoverDurableObjectFiles, h as resolveWorkerSurfacePaths, i as writeGeneratedViteConfig, l as prepareComposedWorkerEntrypoint, m as hasWorkerSurfacePaths, n as resolveEffectiveViteProject, p as DEFAULT_SCHEDULED_ENTRY_FILES, u as DEFAULT_EMAIL_ENTRY_FILES } from "./vite-CzqppgNp.js";
|
|
11
11
|
import { a as createWorkerdBundlerDefaults, i as writeWorkerCompatibleBundle, n as ensureDebugShim, r as resolveWorkerCompatibleRolldownConfig, t as bundleWorkerEntry } from "./worker-bundler-dTTnYU3n.js";
|
|
12
12
|
import { n as bundleWorkflowEntrypointScript, t as R2_PRESIGN_RUNTIME_JS } from "./r2-presign-runtime-zTOLS0Ea.js";
|
|
13
13
|
import { n as buildLocalSecretWrappedBindingConfig } from "./local-secrets-6sMstHXw.js";
|
|
@@ -542,6 +542,42 @@ function resolveDoNamespace(binding, jurisdiction) {
|
|
|
542
542
|
return binding
|
|
543
543
|
}
|
|
544
544
|
|
|
545
|
+
// Dispatch a single Durable Object RPC method call to its stub.
|
|
546
|
+
//
|
|
547
|
+
// A DO that extends DurableObject (from cloudflare:workers) exposes its methods
|
|
548
|
+
// as native RPC on the stub, so the method is invoked DIRECTLY as
|
|
549
|
+
// stub[method](...args) — exactly as on real Cloudflare. This is the ONLY
|
|
550
|
+
// correct path for a DO that ALSO defines its own fetch(): routing the call
|
|
551
|
+
// through fetch() would hand devflare's internal _rpc probe to the user handler,
|
|
552
|
+
// which may reject it (e.g. a websocket-only fetch() returning 426) and yield a
|
|
553
|
+
// non-JSON body that then fails to parse (the reported crash).
|
|
554
|
+
//
|
|
555
|
+
// The fetch _rpc convention is kept only as a fallback for DOs that are not
|
|
556
|
+
// RPC-enabled: the stub proxies every property as callable, so such a DO only
|
|
557
|
+
// reveals itself when the native call throws "does not support RPC".
|
|
558
|
+
async function callDurableObjectRpc(stub, methodName, args) {
|
|
559
|
+
if (typeof stub[methodName] === 'function') {
|
|
560
|
+
try {
|
|
561
|
+
return await stub[methodName](...args)
|
|
562
|
+
} catch (error) {
|
|
563
|
+
if (!isDurableObjectRpcUnsupported(error)) throw error
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
const response = await stub.fetch(new Request('http://do/_rpc', {
|
|
567
|
+
method: 'POST',
|
|
568
|
+
headers: { 'Content-Type': 'application/json' },
|
|
569
|
+
body: JSON.stringify({ method: methodName, params: args })
|
|
570
|
+
}))
|
|
571
|
+
const result = await response.json()
|
|
572
|
+
if (!result.ok) throw new Error(result.error?.message || 'RPC failed')
|
|
573
|
+
return result.result
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function isDurableObjectRpcUnsupported(error) {
|
|
577
|
+
const message = error && error.message ? String(error.message) : String(error)
|
|
578
|
+
return message.indexOf('does not support RPC') !== -1
|
|
579
|
+
}
|
|
580
|
+
|
|
545
581
|
/**
|
|
546
582
|
* Execute an RPC method against the gateway's bindings.
|
|
547
583
|
*
|
|
@@ -668,14 +704,7 @@ async function executeRpcMethod(method, params, env, _ctx) {
|
|
|
668
704
|
const [, serializedId, methodName, args] = params
|
|
669
705
|
const id = binding.idFromString(serializedId.hex)
|
|
670
706
|
const stub = binding.get(id)
|
|
671
|
-
|
|
672
|
-
method: 'POST',
|
|
673
|
-
headers: { 'Content-Type': 'application/json' },
|
|
674
|
-
body: JSON.stringify({ method: methodName, params: args })
|
|
675
|
-
}))
|
|
676
|
-
const result = await response.json()
|
|
677
|
-
if (!result.ok) throw new Error(result.error?.message || 'RPC failed')
|
|
678
|
-
return result.result
|
|
707
|
+
return callDurableObjectRpc(stub, methodName, Array.isArray(args) ? args : [])
|
|
679
708
|
}
|
|
680
709
|
|
|
681
710
|
// Service Bindings
|
|
@@ -902,6 +931,47 @@ async function handleBridgeJsonMessage(data, ws, env, ctx, wsProxies) {
|
|
|
902
931
|
}
|
|
903
932
|
}
|
|
904
933
|
|
|
934
|
+
// Pass-through DO WebSocket upgrade (bridge client -> gateway -> DO).
|
|
935
|
+
//
|
|
936
|
+
// The bridge client's openDoWebSocket() opens a REAL loopback WebSocket to this
|
|
937
|
+
// endpoint (/_devflare/do-ws?binding&id&u) instead of tunneling frames over the
|
|
938
|
+
// bridge socket. We resolve the DO by id and RETURN the DO's 101 response
|
|
939
|
+
// verbatim (webSocket included), so miniflare wires the inbound connection to
|
|
940
|
+
// the DO's client socket. That genuine inbound connection is what makes workerd
|
|
941
|
+
// dispatch the DO's hibernation handlers (webSocketMessage/webSocketClose) and
|
|
942
|
+
// deliver ctx.getWebSockets() broadcasts. Pumping the DO socket in-process (the
|
|
943
|
+
// legacy handleBridgeWsOpen path) never triggers hibernation, so two sockets to
|
|
944
|
+
// one getByName(id) could not see each other's messages. This mirrors the
|
|
945
|
+
// browser WS_ROUTES pass-through (handleDoWebSocket) and real Cloudflare.
|
|
946
|
+
//
|
|
947
|
+
// NOTE: the devflare/test gateway (src/test/simple-context-gateway-script.ts)
|
|
948
|
+
// keeps a byte-equivalent copy of this handler because it is a separately-bundled
|
|
949
|
+
// Worker template that cannot import this runtime — keep the two in sync.
|
|
950
|
+
async function handleBridgeDoWebSocket(request, env, url) {
|
|
951
|
+
try {
|
|
952
|
+
const bindingName = url.searchParams.get('binding')
|
|
953
|
+
const idHex = url.searchParams.get('id')
|
|
954
|
+
const targetUrl = url.searchParams.get('u') || url.toString()
|
|
955
|
+
|
|
956
|
+
const binding = env[bindingName]
|
|
957
|
+
if (!binding || typeof binding.idFromString !== 'function') {
|
|
958
|
+
return new Response('Durable Object binding not found: ' + bindingName, { status: 500 })
|
|
959
|
+
}
|
|
960
|
+
if (!idHex) {
|
|
961
|
+
return new Response('Missing Durable Object id', { status: 400 })
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
const stub = binding.get(binding.idFromString(idHex))
|
|
965
|
+
// Forward the real upgrade request (its headers carry any auth/cookies the
|
|
966
|
+
// caller passed to connect()) and pass the DO's 101 response straight back.
|
|
967
|
+
return stub.fetch(new Request(targetUrl, { method: 'GET', headers: request.headers }))
|
|
968
|
+
} catch (error) {
|
|
969
|
+
return new Response('Error opening DO WebSocket: ' + (error?.message || String(error)), {
|
|
970
|
+
status: 500
|
|
971
|
+
})
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
905
975
|
function handleBridgeWebSocket(request, env, ctx) {
|
|
906
976
|
const { 0: client, 1: server } = new WebSocketPair()
|
|
907
977
|
server.accept()
|
|
@@ -1627,6 +1697,11 @@ export default {
|
|
|
1627
1697
|
const isWebSocket = request.headers.get('Upgrade') === 'websocket'
|
|
1628
1698
|
|
|
1629
1699
|
if (isWebSocket) {
|
|
1700
|
+
// Bridge DO connect(): a real pass-through upgrade to a Durable Object
|
|
1701
|
+
// (hibernation-correct), distinct from the bridge RPC/relay socket.
|
|
1702
|
+
if (url.pathname === '/_devflare/do-ws') {
|
|
1703
|
+
return handleBridgeDoWebSocket(request, env, url)
|
|
1704
|
+
}
|
|
1630
1705
|
const matchedRoute = matchWsRoute(url.pathname)
|
|
1631
1706
|
if (matchedRoute) {
|
|
1632
1707
|
return handleDoWebSocket(request, env, url, matchedRoute)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as createFetchEvent, b as createContextProxy, n as getContextOrNull, v as runWithEventContext } from "./context-
|
|
1
|
+
import { D as createFetchEvent, b as createContextProxy, n as getContextOrNull, v as runWithEventContext } from "./context-B6S7cqQW.js";
|
|
2
2
|
import { AwsV4Signer } from "aws4fetch";
|
|
3
3
|
//#region src/runtime/exports.ts
|
|
4
4
|
/**
|
|
@@ -2,7 +2,7 @@ import { d as resolveConfigEnvVars } from "./preview-C3Cdr8an.js";
|
|
|
2
2
|
import { i as resolveConfigPath, o as loadResolvedConfig, r as loadConfig, s as resolveResources, u as resolveConfigForEnvironment } from "./loader-E_UGyTrJ.js";
|
|
3
3
|
import { o as normalizeDOBinding } from "./schema-normalization-Zgm4W6O6.js";
|
|
4
4
|
import { c as writeWranglerConfig, i as isolateViteBuildOutputPaths, n as compileConfig, o as rebaseWranglerConfigPaths, r as compileToProgrammaticConfig, t as compileBuildConfig } from "./compiler-CgIFPfRA.js";
|
|
5
|
-
import { _ as resolveFetchHandler, o as assertExplicit2ArgStyle } from "./runtime-
|
|
5
|
+
import { _ as resolveFetchHandler, o as assertExplicit2ArgStyle } from "./runtime-sEr9b0ns.js";
|
|
6
6
|
import { s as resolveServiceBindings, t as discoverRoutes } from "./routes-BMU7ga_l.js";
|
|
7
7
|
import { n as findDurableObjectClasses } from "./durable-object-DMtH0XYX.js";
|
|
8
8
|
import { r as SUPPORTED_WORKER_EXTENSIONS } from "./worker-entrypoint-CQW77lG8.js";
|
package/dist/bridge/client.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function resolveBridgeWebSocketConstructor(runtimeWebSocket?: unknown): Promise<WebSocketConstructor>;
|
|
1
|
+
export { resolveBridgeWebSocketConstructor } from './websocket-constructor.js';
|
|
3
2
|
export interface BridgeClientOptions {
|
|
4
3
|
/** Bridge WebSocket URL (default: ws://localhost:8787) */
|
|
5
4
|
url?: string;
|
|
@@ -85,7 +84,18 @@ export declare class BridgeClient {
|
|
|
85
84
|
* surface is provided so consumers can register ahead of that work.
|
|
86
85
|
*/
|
|
87
86
|
on(topic: string, cb: (data: unknown) => void): () => void;
|
|
88
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Create a proxied WebSocket to a Durable Object via the in-process bridge
|
|
89
|
+
* relay (`ws.open` control frame → gateway `stub.fetch()` pump → `WsData`
|
|
90
|
+
* frames).
|
|
91
|
+
*
|
|
92
|
+
* DEPRECATED for DO connect(): this relay pumps the DO's WebSocket in-process,
|
|
93
|
+
* which does NOT trigger workerd's hibernation dispatch — so a DO that uses
|
|
94
|
+
* `ctx.acceptWebSocket()` never sees `webSocketMessage`/`webSocketClose` and
|
|
95
|
+
* cross-socket `ctx.getWebSockets()` broadcasts never cross. `connect()` now
|
|
96
|
+
* uses `openDoWebSocket()` (a real pass-through) instead. This method is
|
|
97
|
+
* retained for the `ws-relay` wire capability and backward compatibility.
|
|
98
|
+
*/
|
|
89
99
|
createWsProxy(binding: string, id: string, url: string, headers?: [string, string][]): Promise<{
|
|
90
100
|
wid: number;
|
|
91
101
|
send: (data: Uint8Array | string) => void;
|
|
@@ -93,6 +103,40 @@ export declare class BridgeClient {
|
|
|
93
103
|
onMessage: (handler: (data: Uint8Array | string) => void) => void;
|
|
94
104
|
onClose: (handler: (code?: number, reason?: string) => void) => void;
|
|
95
105
|
}>;
|
|
106
|
+
/**
|
|
107
|
+
* Open a REAL WebSocket to the gateway's DO pass-through endpoint
|
|
108
|
+
* (`/_devflare/do-ws`), which forwards the upgrade to the target Durable
|
|
109
|
+
* Object and passes through its `101` response.
|
|
110
|
+
*
|
|
111
|
+
* This is the ONLY way a bridged DO WebSocket triggers the runtime's
|
|
112
|
+
* hibernation dispatch under miniflare: the gateway returns the DO's client
|
|
113
|
+
* socket for a genuine inbound connection, so workerd pumps it and invokes
|
|
114
|
+
* `webSocketMessage`/`webSocketClose` and delivers `ctx.getWebSockets()`
|
|
115
|
+
* broadcasts. The legacy in-process relay (`createWsProxy` + gateway
|
|
116
|
+
* `stub.fetch()` pump) never fires hibernation, so two sockets to the same
|
|
117
|
+
* `getByName(id)` could not see each other's messages. Here they share ONE DO
|
|
118
|
+
* instance and broadcast across each other, exactly as on real Cloudflare.
|
|
119
|
+
*
|
|
120
|
+
* Unlike `createWsProxy`, this does not multiplex over the bridge socket: it
|
|
121
|
+
* is a standalone connection (see `openDurableObjectWebSocket`) with its own
|
|
122
|
+
* lifecycle, so it is unaffected by the bridge client's disconnect/reconnect
|
|
123
|
+
* bookkeeping. It also does not require the bridge socket to be connected.
|
|
124
|
+
*
|
|
125
|
+
* @param binding - DO namespace binding name (e.g. `DOC_ROOM`).
|
|
126
|
+
* @param idHex - Already-resolved Durable Object id, hex form.
|
|
127
|
+
* @param targetUrl - The DO fetch URL the caller passed to `stub.connect(url)`.
|
|
128
|
+
* @param headers - Optional upgrade headers (auth/cookies) forwarded to the DO.
|
|
129
|
+
* @returns A minimal proxy surface (send/close/onMessage/onClose) over the socket.
|
|
130
|
+
* @throws When the pass-through socket fails to open (bad binding/id, or the
|
|
131
|
+
* DO rejected the upgrade).
|
|
132
|
+
*/
|
|
133
|
+
openDoWebSocket(binding: string, idHex: string, targetUrl: string, headers?: [string, string][]): Promise<{
|
|
134
|
+
wid: number;
|
|
135
|
+
send: (data: Uint8Array | string) => void;
|
|
136
|
+
close: (code?: number, reason?: string) => void;
|
|
137
|
+
onMessage: (handler: (data: Uint8Array | string) => void) => void;
|
|
138
|
+
onClose: (handler: (code?: number, reason?: string) => void) => void;
|
|
139
|
+
}>;
|
|
96
140
|
/** Create a readable stream that pulls from the bridge */
|
|
97
141
|
createReadableStream(sid: number): ReadableStream<Uint8Array>;
|
|
98
142
|
private handleJsonMessage;
|
|
@@ -120,5 +164,4 @@ export declare class BridgeClient {
|
|
|
120
164
|
export declare function getClient(options?: BridgeClientOptions): BridgeClient;
|
|
121
165
|
/** Reset the default client (for testing) */
|
|
122
166
|
export declare function resetClient(): void;
|
|
123
|
-
export {};
|
|
124
167
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/bridge/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/bridge/client.ts"],"names":[],"mappings":"AA6CA,OAAO,EAAE,iCAAiC,EAAE,MAAM,yBAAyB,CAAA;AAkC3E,MAAM,WAAW,mBAAmB;IACnC,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,mCAAmC;IACnC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,4BAA4B;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACjC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC9B,OAAO,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,YAAY;IAC5B,UAAU,EAAE,+BAA+B,CAAC,UAAU,CAAC,CAAA;IACvD,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,0DAA0D;IAC1D,WAAW,EAAE;QACZ,OAAO,EAAE,MAAM,IAAI,CAAA;QACnB,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;KAC9B,GAAG,IAAI,CAAA;IACR,kEAAkE;IAClE,KAAK,EAAE,OAAO,CAAA;IACd,8CAA8C;IAC9C,MAAM,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,KAAK,IAAI,CAAA;IAC9C,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CACjD;AAED,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAC9B;AAMD,qBAAa,YAAY;IACxB,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,GAAG,CAAQ;IACnB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,cAAc,CAAQ;IAE9B,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,cAAc,CAAkD;IAExE,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,WAAW,CAAQ;IAE3B,YAAY,OAAO,GAAE,mBAAwB,EAK5C;IAED,4BAA4B;IAC5B,MAAM,IAAI,MAAM,CAEf;IAED,6CAA6C;IAC7C,UAAU,IAAI,MAAM,CAGnB;IAMD,4BAA4B;IACtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAgB7B;YAEa,iCAAiC;IAK/C,OAAO,CAAC,cAAc;IA8DtB,iEAAiE;IACjE,UAAU,IAAI,IAAI,CAgBjB;IAED,6BAA6B;IAC7B,KAAK,IAAI,IAAI,CAEZ;IAED,yBAAyB;IACzB,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,OAAO,CAAC,gBAAgB;IAmBxB,gFAAgF;IAChF,OAAO,CAAC,cAAc;IAwCtB,yBAAyB;IACnB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,SAAS,SAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CA0CjF;IAMD;;;;;;;;;;OAUG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAazD;IAMD;;;;;;;;;;;OAWG;IACG,aAAa,CAClB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAC1B,OAAO,CAAC;QACV,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,KAAK,IAAI,CAAA;QACzC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;QAC/C,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,KAAK,IAAI,KAAK,IAAI,CAAA;QACjE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAA;KACpE,CAAC,CAqDD;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACG,eAAe,CACpB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAC1B,OAAO,CAAC;QACV,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,KAAK,IAAI,CAAA;QACzC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;QAC/C,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,KAAK,IAAI,KAAK,IAAI,CAAA;QACjE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAA;KACpE,CAAC,CAED;IAMD,0DAA0D;IAC1D,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAqE5D;IASD,OAAO,CAAC,iBAAiB;IA6BzB;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,gBAAgB;YAQV,UAAU;IAmCxB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,cAAc;YAWR,eAAe;IAM7B,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,UAAU;CAOlB;AAQD,8CAA8C;AAC9C,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,YAAY,CAKrE;AAED,6CAA6C;AAC7C,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch a single Durable Object RPC method call to its stub.
|
|
3
|
+
*
|
|
4
|
+
* A DO that `extends DurableObject` (from `cloudflare:workers`) exposes its
|
|
5
|
+
* methods as native RPC on the stub, so the method is invoked DIRECTLY as
|
|
6
|
+
* `stub[method](...args)` — exactly as on real Cloudflare. This is the ONLY
|
|
7
|
+
* correct path for a DO that ALSO defines its own `fetch()`: routing the call
|
|
8
|
+
* through `fetch()` would hand devflare's internal `_rpc` probe to the user
|
|
9
|
+
* handler, which may reject it (e.g. a websocket-only `fetch()` returning 426),
|
|
10
|
+
* yielding a non-JSON body that then fails to parse.
|
|
11
|
+
*
|
|
12
|
+
* The fetch `_rpc` convention is kept only as a fallback for DOs that are not
|
|
13
|
+
* RPC-enabled (see `callDurableObjectRpcViaFetch`).
|
|
14
|
+
*
|
|
15
|
+
* @param stub - The resolved Durable Object stub to dispatch against.
|
|
16
|
+
* @param methodName - The RPC method name requested by the client proxy.
|
|
17
|
+
* @param args - The already-deserialized positional arguments for the method.
|
|
18
|
+
* @returns The method's return value (or the `_rpc` fallback's result).
|
|
19
|
+
* @throws Re-throws any genuine error from the method; only a workerd
|
|
20
|
+
* "does not support RPC" signal is swallowed to trigger the fetch fallback.
|
|
21
|
+
*/
|
|
22
|
+
export declare function callDurableObjectRpc(stub: DurableObjectStub, methodName: string, args: unknown[]): Promise<unknown>;
|
|
23
|
+
//# sourceMappingURL=do-rpc-dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"do-rpc-dispatch.d.ts","sourceRoot":"","sources":["../../src/bridge/do-rpc-dispatch.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CACzC,IAAI,EAAE,iBAAiB,EACvB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,EAAE,GACb,OAAO,CAAC,OAAO,CAAC,CAelB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The minimal proxy surface over a DO pass-through socket, matching the shape
|
|
3
|
+
* consumed by the DO Socket facade in `proxy.ts` `connect()`.
|
|
4
|
+
*/
|
|
5
|
+
export interface DoWebSocketProxy {
|
|
6
|
+
/** Synthetic id for parity with the legacy relay proxy (not on the wire). */
|
|
7
|
+
wid: number;
|
|
8
|
+
/** Send a frame to the DO (binary for bytes, text for strings). */
|
|
9
|
+
send: (data: Uint8Array | string) => void;
|
|
10
|
+
/** Close the socket. */
|
|
11
|
+
close: (code?: number, reason?: string) => void;
|
|
12
|
+
/** Attach the inbound-frame handler; buffered frames flush immediately. */
|
|
13
|
+
onMessage: (handler: (data: Uint8Array | string) => void) => void;
|
|
14
|
+
/** Attach the close handler; a buffered close fires immediately. */
|
|
15
|
+
onClose: (handler: (code?: number, reason?: string) => void) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Open a real pass-through WebSocket to a Durable Object through the gateway's
|
|
19
|
+
* `/_devflare/do-ws` endpoint. Unlike the legacy relay, this is a standalone
|
|
20
|
+
* connection with its own lifecycle, so it is unaffected by the bridge client's
|
|
21
|
+
* `disconnect()`/reconnect bookkeeping.
|
|
22
|
+
*
|
|
23
|
+
* @param bridgeUrl - The bridge/gateway base URL (e.g. `ws://127.0.0.1:8787`).
|
|
24
|
+
* @param binding - DO namespace binding name (e.g. `DOC_ROOM`).
|
|
25
|
+
* @param idHex - Already-resolved Durable Object id, hex form.
|
|
26
|
+
* @param targetUrl - The DO fetch URL the caller passed to `stub.connect(url)`.
|
|
27
|
+
* @param headers - Optional upgrade headers (auth/cookies) forwarded to the DO.
|
|
28
|
+
* @returns A proxy surface (send/close/onMessage/onClose) over the socket.
|
|
29
|
+
* @throws When the pass-through socket fails to open (bad binding/id, or the DO
|
|
30
|
+
* rejected the upgrade).
|
|
31
|
+
*/
|
|
32
|
+
export declare function openDurableObjectWebSocket(bridgeUrl: string, binding: string, idHex: string, targetUrl: string, headers?: [string, string][]): Promise<DoWebSocketProxy>;
|
|
33
|
+
//# sourceMappingURL=do-websocket-connect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"do-websocket-connect.d.ts","sourceRoot":"","sources":["../../src/bridge/do-websocket-connect.ts"],"names":[],"mappings":"AAqEA;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAA;IACX,mEAAmE;IACnE,IAAI,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,KAAK,IAAI,CAAA;IACzC,wBAAwB;IACxB,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,2EAA2E;IAC3E,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,KAAK,IAAI,KAAK,IAAI,CAAA;IACjE,oEAAoE;IACpE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAA;CACpE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,0BAA0B,CAC/C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAC1B,OAAO,CAAC,gBAAgB,CAAC,CAyE3B"}
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* module. All symbols are declared with `function`/`const` so they are
|
|
5
5
|
* hoisted in both embedding sites.
|
|
6
6
|
*/
|
|
7
|
-
export declare const GATEWAY_RUNTIME_JS = "\nconst RAW_EMAIL = 'EmailMessage::raw'\n\n// Inline body cap for proxied DO/service-fetch responses. Matches\n// HTTP_TRANSFER_THRESHOLD in wire.ts (512 KB). A larger body would exceed\n// workerd's ~1 MB WebSocket message limit once base64-encoded into the rpc.ok\n// frame, so it is rejected with a clear error rather than silently truncated.\nconst HTTP_TRANSFER_THRESHOLD = 512 * 1024\n\nfunction arrayBufferToBase64(buffer) {\n\tconst bytes = new Uint8Array(buffer)\n\tlet binary = ''\n\tfor (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i])\n\treturn btoa(binary)\n}\n\nfunction base64ToArrayBuffer(base64) {\n\tconst binary = atob(base64)\n\tconst bytes = new Uint8Array(binary.length)\n\tfor (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n\treturn bytes.buffer\n}\n\n// Binary WsData frame codec (10-byte header: kind:u8, id:u32 LE, seq:u32 LE,\n// flags:u8 + payload). MUST match wire.ts encodeBinaryFrame/decodeBinaryFrame so\n// the bridge client and this gateway agree on the WS-data wire format\n// (BinaryKind.WsData = 2, BinaryFlags.TEXT = 2).\nfunction encodeWsDataFrame(wid, flags, payload) {\n\tconst frame = new Uint8Array(10 + payload.byteLength)\n\tconst view = new DataView(frame.buffer)\n\tview.setUint8(0, 2)\n\tview.setUint32(1, wid, true)\n\tview.setUint32(5, 0, true)\n\tview.setUint8(9, flags)\n\tframe.set(payload, 10)\n\treturn frame\n}\n\nfunction decodeWsDataFrame(buffer) {\n\tconst bytes = new Uint8Array(buffer)\n\tif (bytes.byteLength < 10) return null\n\tconst view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\treturn {\n\t\tkind: view.getUint8(0),\n\t\tid: view.getUint32(1, true),\n\t\tflags: view.getUint8(9),\n\t\tpayload: bytes.subarray(10)\n\t}\n}\n\nfunction serializeR2Object(obj) {\n\tif (!obj) return null\n\treturn {\n\t\t__type: 'R2Object',\n\t\tkey: obj.key,\n\t\tversion: obj.version,\n\t\tsize: obj.size,\n\t\tetag: obj.etag,\n\t\thttpEtag: obj.httpEtag,\n\t\tchecksums: obj.checksums,\n\t\tuploaded: obj.uploaded?.toISOString(),\n\t\thttpMetadata: obj.httpMetadata,\n\t\tcustomMetadata: obj.customMetadata,\n\t\trange: obj.range,\n\t\tstorageClass: obj.storageClass\n\t}\n}\n\nfunction serializeR2ObjectBody(obj, bodyData) {\n\tif (!obj) return null\n\treturn {\n\t\t__type: 'R2ObjectBody',\n\t\tkey: obj.key,\n\t\tversion: obj.version,\n\t\tsize: obj.size,\n\t\tetag: obj.etag,\n\t\thttpEtag: obj.httpEtag,\n\t\tchecksums: obj.checksums,\n\t\tuploaded: obj.uploaded?.toISOString(),\n\t\thttpMetadata: obj.httpMetadata,\n\t\tcustomMetadata: obj.customMetadata,\n\t\trange: obj.range,\n\t\tstorageClass: obj.storageClass,\n\t\tbodyData\n\t}\n}\n\nfunction serializeR2Objects(result) {\n\tif (!result) return null\n\treturn {\n\t\tobjects: result.objects.map(serializeR2Object),\n\t\ttruncated: result.truncated,\n\t\tcursor: result.cursor,\n\t\tdelimitedPrefixes: result.delimitedPrefixes\n\t}\n}\n\nasync function serializeResponse(response) {\n\tlet body = null\n\tif (response.body) {\n\t\tconst bytes = await response.arrayBuffer()\n\t\tif (bytes.byteLength > HTTP_TRANSFER_THRESHOLD) {\n\t\t\tthrow new Error(\n\t\t\t\t'[devflare][bridge] Response body (' + bytes.byteLength + ' bytes) exceeds the '\n\t\t\t\t+ HTTP_TRANSFER_THRESHOLD + '-byte inline limit. DO and service-binding fetch responses '\n\t\t\t\t+ 'are delivered inline over the bridge WebSocket and cannot be streamed locally; keep '\n\t\t\t\t+ 'proxied response bodies under the limit (large R2 objects are exempt \u2014 read them through '\n\t\t\t\t+ 'the R2 binding, which uses the HTTP transfer side-channel).'\n\t\t\t)\n\t\t}\n\t\tif (bytes.byteLength > 0) {\n\t\t\tbody = { type: 'bytes', data: arrayBufferToBase64(bytes) }\n\t\t}\n\t}\n\treturn {\n\t\tstatus: response.status,\n\t\tstatusText: response.statusText,\n\t\theaders: [...response.headers.entries()],\n\t\tbody\n\t}\n}\n\nfunction deserializeRequest(serializedReq) {\n\treturn new Request(serializedReq.url, {\n\t\tmethod: serializedReq.method,\n\t\theaders: serializedReq.headers,\n\t\tbody: serializedReq.body?.type === 'bytes'\n\t\t\t? base64ToArrayBuffer(serializedReq.body.data)\n\t\t\t: undefined,\n\t\tredirect: serializedReq.redirect\n\t})\n}\n\nfunction createEmailMessageRaw(raw) {\n\tif (typeof raw === 'string' || raw instanceof ReadableStream) {\n\t\treturn raw\n\t}\n\tif (raw instanceof ArrayBuffer || raw instanceof Uint8Array) {\n\t\treturn new Response(raw).body\n\t}\n\tthrow new Error('Unsupported EmailMessage raw payload')\n}\n\nfunction isDurableObjectNamespace(binding) {\n\treturn !!binding\n\t\t&& typeof binding.idFromName === 'function'\n\t\t&& typeof binding.idFromString === 'function'\n\t\t&& typeof binding.newUniqueId === 'function'\n}\n\n/**\n * Resolve a (possibly jurisdiction-scoped) DurableObjectNamespace.\n * Forwards the jurisdiction faithfully when the binding supports it\n * (real Cloudflare), and degrades to the plain binding otherwise\n * (miniflare/workerd local emulation, which does not pin jurisdictions).\n */\nfunction resolveDoNamespace(binding, jurisdiction) {\n\tif (jurisdiction && typeof binding.jurisdiction === 'function') {\n\t\treturn binding.jurisdiction(jurisdiction)\n\t}\n\treturn binding\n}\n\n/**\n * Execute an RPC method against the gateway's bindings.\n *\n * Method format: \"binding.operation\". Operations must be namespaced by\n * binding kind (e.g. \"kv.get\", \"r2.head\", \"d1.stmt.first\", \"do.fetch\",\n * \"service.fetch\", \"queue.send\", \"email.send\", \"ai.run\"). Bare verbs and the legacy\n * \"stmt.*\" / \"stub.*\" sub-prefixes were removed in B3-final and now throw.\n * Method vocabulary must stay in sync with the canonical server in\n * src/bridge/server.ts.\n */\nasync function executeRpcMethod(method, params, env, _ctx) {\n\tconst parts = method.split('.')\n\tif (parts.length < 2) throw new Error('Invalid method format: ' + method)\n\n\tconst bindingName = parts[0]\n\tconst operation = parts.slice(1).join('.')\n\tconst binding = env[bindingName]\n\n\tif (!binding) throw new Error('Binding not found: ' + bindingName)\n\n\tconst isNamespaced =\n\t\toperation.indexOf('kv.') === 0 ||\n\t\toperation.indexOf('r2.') === 0 ||\n\t\toperation.indexOf('d1.') === 0 ||\n\t\toperation.indexOf('do.') === 0 ||\n\t\toperation.indexOf('service.') === 0 ||\n\t\toperation.indexOf('queue.') === 0 ||\n\t\toperation.indexOf('email.') === 0 ||\n\t\toperation.indexOf('ai.') === 0 ||\n\t\toperation.indexOf('workflow.') === 0 ||\n\t\toperation.indexOf('var.') === 0\n\tif (!isNamespaced) {\n\t\tthrow new Error(createUnsupportedBridgeOperationErrorMessage(bindingName, operation))\n\t}\n\n\t// KV\n\tif (operation === 'kv.get') return binding.get(params[0], params[1])\n\tif (operation === 'kv.put') return binding.put(params[0], params[1], params[2])\n\tif (operation === 'kv.delete') return binding.delete(params[0])\n\tif (operation === 'kv.list') return binding.list(params[0])\n\tif (operation === 'kv.getWithMetadata') return binding.getWithMetadata(params[0], params[1])\n\n\t// DO get (returns DOStub reference)\n\tif (operation === 'do.get') {\n\t\treturn { __type: 'DOStub', binding: bindingName, id: params[0] }\n\t}\n\n\t// R2\n\tif (operation === 'r2.head') return serializeR2Object(await binding.head(params[0]))\n\tif (operation === 'r2.get') {\n\t\tconst obj = await binding.get(params[0], params[1])\n\t\tif (!obj) return null\n\t\tconst body = await obj.arrayBuffer()\n\t\treturn serializeR2ObjectBody(obj, arrayBufferToBase64(body))\n\t}\n\tif (operation === 'r2.put') {\n\t\tlet value = params[1]\n\t\tif (value && typeof value === 'object') {\n\t\t\tif (value.__type === 'ArrayBuffer' || value.__type === 'Uint8Array') {\n\t\t\t\tvalue = base64ToArrayBuffer(value.data)\n\t\t\t}\n\t\t}\n\t\treturn serializeR2Object(await binding.put(params[0], value, params[2]))\n\t}\n\tif (operation === 'r2.delete') return binding.delete(params[0])\n\tif (operation === 'r2.list') return serializeR2Objects(await binding.list(params[0]))\n\n\t// D1\n\tif (operation === 'd1.exec') return binding.exec(params[0])\n\tif (operation === 'd1.batch') {\n\t\tconst statements = params[0].map((s) => binding.prepare(s.sql).bind(...(s.bindings || [])))\n\t\treturn binding.batch(statements)\n\t}\n\tif (operation.indexOf('d1.stmt.') === 0) {\n\t\tconst mode = operation.split('.')[2]\n\t\tconst [sql, ...rest] = params\n\t\tlet bindings = rest\n\t\tlet extraParam\n\t\tif (mode === 'first' || mode === 'raw') {\n\t\t\textraParam = rest[rest.length - 1]\n\t\t\tbindings = rest.slice(0, -1)\n\t\t}\n\t\tlet stmt = binding.prepare(sql)\n\t\tif (bindings.length > 0) stmt = stmt.bind(...bindings)\n\t\tif (mode === 'first') {\n\t\t\tif (typeof extraParam === 'string' && extraParam.length > 0) return stmt.first(extraParam)\n\t\t\treturn stmt.first()\n\t\t}\n\t\tif (mode === 'all') return stmt.all()\n\t\tif (mode === 'run') return stmt.run()\n\t\tif (mode === 'raw') return stmt.raw(extraParam)\n\t\tthrow new Error('Unknown stmt mode: ' + mode)\n\t}\n\n\t// Durable Objects\n\tif (operation === 'do.idFromName') {\n\t\tconst ns = resolveDoNamespace(binding, params[1])\n\t\tconst id = ns.idFromName(params[0])\n\t\treturn { __type: 'DOId', hex: id.toString() }\n\t}\n\tif (operation === 'do.idFromString') {\n\t\tconst id = binding.idFromString(params[0])\n\t\treturn { __type: 'DOId', hex: id.toString() }\n\t}\n\tif (operation === 'do.newUniqueId') {\n\t\tconst ns = resolveDoNamespace(binding, params[1])\n\t\tconst id = ns.newUniqueId(params[0])\n\t\treturn { __type: 'DOId', hex: id.toString() }\n\t}\n\tif (operation === 'do.fetch') {\n\t\tconst [, serializedId, serializedReq] = params\n\t\tconst id = binding.idFromString(serializedId.hex)\n\t\tconst stub = binding.get(id)\n\t\tconst response = await stub.fetch(new Request(serializedReq.url, {\n\t\t\tmethod: serializedReq.method,\n\t\t\theaders: serializedReq.headers,\n\t\t\tbody: serializedReq.body?.type === 'bytes'\n\t\t\t\t? base64ToArrayBuffer(serializedReq.body.data)\n\t\t\t\t: undefined\n\t\t}))\n\t\treturn serializeResponse(response)\n\t}\n\tif (operation === 'do.rpc') {\n\t\tconst [, serializedId, methodName, args] = params\n\t\tconst id = binding.idFromString(serializedId.hex)\n\t\tconst stub = binding.get(id)\n\t\tconst response = await stub.fetch(new Request('http://do/_rpc', {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ method: methodName, params: args })\n\t\t}))\n\t\tconst result = await response.json()\n\t\tif (!result.ok) throw new Error(result.error?.message || 'RPC failed')\n\t\treturn result.result\n\t}\n\n\t// Service Bindings\n\tif (operation === 'service.fetch') {\n\t\tif (!binding || typeof binding.fetch !== 'function') {\n\t\t\tthrow new Error('Service binding ' + bindingName + ' does not support fetch()')\n\t\t}\n\t\tconst response = await binding.fetch(deserializeRequest(params[0]))\n\t\treturn serializeResponse(response)\n\t}\n\tif (operation === 'service.rpc') {\n\t\tconst methodName = params[0]\n\t\tif (typeof methodName !== 'string') {\n\t\t\tthrow new Error('Service binding ' + bindingName + ' RPC method name must be a string')\n\t\t}\n\t\tconst args = Array.isArray(params[1]) ? params[1] : []\n\t\tconst method = binding && binding[methodName]\n\t\tif (typeof method !== 'function') {\n\t\t\tthrow new Error('Service binding ' + bindingName + ' does not support ' + methodName + '()')\n\t\t}\n\t\treturn method.apply(binding, args)\n\t}\n\n\t// Queues\n\tif (operation === 'queue.send') return binding.send(params[0], params[1])\n\tif (operation === 'queue.sendBatch') return binding.sendBatch(params[0], params[1])\n\n\t// Send Email\n\tif (operation === 'email.send') {\n\t\tif (binding && typeof binding.send === 'function') {\n\t\t\tconst message = params[0]\n\t\t\tif (message && typeof message === 'object' && 'from' in message && 'to' in message && 'raw' in message) {\n\t\t\t\treturn binding.send({\n\t\t\t\t\tfrom: message.from,\n\t\t\t\t\tto: message.to,\n\t\t\t\t\t[RAW_EMAIL]: createEmailMessageRaw(message.raw)\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn binding.send(message)\n\t\t}\n\t\treturn { ok: true, simulated: true }\n\t}\n\n\t// Workflows\n\tif (operation === 'workflow.create') {\n\t\treturn serializeWorkflowInstance(await binding.create(params[0]))\n\t}\n\tif (operation === 'workflow.get') {\n\t\treturn serializeWorkflowInstance(await binding.get(params[0]))\n\t}\n\tif (operation === 'workflow.status') {\n\t\treturn (await binding.get(params[0])).status()\n\t}\n\tif (operation === 'workflow.pause') {\n\t\treturn (await binding.get(params[0])).pause()\n\t}\n\tif (operation === 'workflow.resume') {\n\t\treturn (await binding.get(params[0])).resume()\n\t}\n\tif (operation === 'workflow.terminate') {\n\t\treturn (await binding.get(params[0])).terminate()\n\t}\n\tif (operation === 'workflow.restart') {\n\t\treturn (await binding.get(params[0])).restart()\n\t}\n\tif (operation === 'workflow.sendEvent') {\n\t\treturn (await binding.get(params[0])).sendEvent(params[1])\n\t}\n\n\t// AI / generic run()\n\tif (operation === 'ai.run') {\n\t\tif (typeof binding.run !== 'function') {\n\t\t\tthrow new Error('Binding ' + bindingName + ' does not support run(): ' + method)\n\t\t}\n\t\treturn binding.run(params[0], params[1])\n\t}\n\n\tthrow new Error('Unknown operation: ' + method)\n}\n\nfunction createUnsupportedBridgeOperationErrorMessage(bindingName, operation) {\n\tconst base = \"[devflare][bridge] Unsupported bridge operation '\" + operation + \"' for binding '\" + bindingName + \"'.\"\n\tif (operation === 'fetch') {\n\t\treturn base + ' Devflare could not dispatch fetch() for this binding through the local bridge. '\n\t\t\t+ 'Expected Cloudflare API: env.' + bindingName + '.fetch(request). '\n\t\t\t+ 'If this came from SvelteKit platform.env, make sure the binding is declared as a service binding; '\n\t\t\t+ 'this is a Devflare local bridge issue when service bindings fall back to a bare fetch operation.'\n\t}\n\tif (operation === 'toString') {\n\t\treturn base + ' A platform.env value was coerced to a string through the bridge. '\n\t\t\t+ 'For SvelteKit local dev, declared vars should be plain string values and missing env names should read as undefined.'\n\t}\n\treturn base + ' Bare verbs and the legacy stmt.*/stub.* sub-prefixes are not supported; '\n\t\t+ 'use the namespaced form (e.g. kv.get, r2.put, d1.stmt.first, do.fetch, service.fetch).'\n}\n\nfunction serializeWorkflowInstance(instance) {\n\treturn {\n\t\t__type: 'WorkflowInstance',\n\t\tid: instance.id\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// WebSocket bridge (shared with src/bridge/server.ts in shape)\n// ---------------------------------------------------------------------------\n// NOTE: wsProxies is intentionally created per handleBridgeWebSocket call so\n// state never leaks across connections or across gateway-script regenerations.\n\nasync function handleBridgeRpcCall(msg, ws, env, ctx) {\n\ttry {\n\t\tconst result = await executeRpcMethod(msg.method, msg.params, env, ctx)\n\t\tws.send(JSON.stringify({ t: 'rpc.ok', id: msg.id, result }))\n\t} catch (error) {\n\t\tws.send(JSON.stringify({\n\t\t\tt: 'rpc.err',\n\t\t\tid: msg.id,\n\t\t\terror: {\n\t\t\t\tcode: error?.code || 'INTERNAL_ERROR',\n\t\t\t\tmessage: error?.message || String(error)\n\t\t\t}\n\t\t}))\n\t}\n}\n\nasync function handleBridgeWsOpen(msg, ws, env, wsProxies) {\n\ttry {\n\t\tconst binding = env[msg.target.binding]\n\t\tconst id = binding.idFromString(msg.target.id)\n\t\tconst stub = binding.get(id)\n\n\t\tconst headers = new Headers(msg.target.headers || [])\n\t\theaders.set('Upgrade', 'websocket')\n\n\t\tconst response = await stub.fetch(new Request(msg.target.url, { method: 'GET', headers }))\n\t\tconst doWs = response.webSocket\n\n\t\tif (!doWs) {\n\t\t\tws.send(JSON.stringify({\n\t\t\t\tt: 'rpc.err',\n\t\t\t\tid: 'ws_' + msg.wid,\n\t\t\t\terror: { code: 'WS_FAILED', message: 'No WebSocket returned' }\n\t\t\t}))\n\t\t\treturn\n\t\t}\n\n\t\tdoWs.accept()\n\t\twsProxies.set(msg.wid, { doWs })\n\n\t\tdoWs.addEventListener('message', (event) => {\n\t\t\tconst isText = typeof event.data === 'string'\n\t\t\tconst payload = isText\n\t\t\t\t? new TextEncoder().encode(event.data)\n\t\t\t\t: new Uint8Array(event.data)\n\t\t\tconst flags = isText ? 2 : 0\n\t\t\tws.send(encodeWsDataFrame(msg.wid, flags, payload))\n\t\t})\n\n\t\tdoWs.addEventListener('close', (event) => {\n\t\t\tws.send(JSON.stringify({ t: 'ws.close', wid: msg.wid, code: event.code, reason: event.reason }))\n\t\t\twsProxies.delete(msg.wid)\n\t\t})\n\n\t\tws.send(JSON.stringify({ t: 'ws.opened', wid: msg.wid }))\n\t} catch (error) {\n\t\tws.send(JSON.stringify({\n\t\t\tt: 'rpc.err',\n\t\t\tid: 'ws_' + msg.wid,\n\t\t\terror: { code: 'WS_FAILED', message: error.message }\n\t\t}))\n\t}\n}\n\nfunction handleBridgeWsClose(msg, wsProxies) {\n\tconst proxy = wsProxies.get(msg.wid)\n\tif (proxy) {\n\t\tproxy.doWs.close(msg.code, msg.reason)\n\t\twsProxies.delete(msg.wid)\n\t}\n}\n\n// Relay an inbound binary WsData frame (client -> DO). Mirrors server.ts\n// handleBinaryMessage: decode the frame, look up the proxy by ws id, and forward\n// the payload to the DO socket honoring the TEXT flag.\nfunction handleBridgeBinaryMessage(buffer, wsProxies) {\n\tconst frame = decodeWsDataFrame(buffer)\n\tif (!frame || frame.kind !== 2) return\n\tconst proxy = wsProxies.get(frame.id)\n\tif (!proxy) return\n\tif ((frame.flags & 2) !== 0) {\n\t\tproxy.doWs.send(new TextDecoder().decode(frame.payload))\n\t} else {\n\t\tproxy.doWs.send(frame.payload)\n\t}\n}\n\nasync function handleBridgeJsonMessage(data, ws, env, ctx, wsProxies) {\n\tconst msg = JSON.parse(data)\n\tswitch (msg.t) {\n\t\tcase 'hello':\n\t\t\t// v2 handshake \u2014 acknowledge with welcome echoing the negotiated\n\t\t\t// capability intersection. The gateway advertises only what it\n\t\t\t// implements end-to-end: 'ws-relay' (binary WsData relay to/from DO\n\t\t\t// sockets) and 'http-transfer' (the R2 transfer HTTP side-channel).\n\t\t\t// 'streams' is intentionally NOT advertised \u2014 large DO/service-fetch\n\t\t\t// responses are inlined, not streamed, in this gateway.\n\t\t\tws.send(JSON.stringify({\n\t\t\t\tt: 'welcome',\n\t\t\t\tprotocolVersion: 2,\n\t\t\t\tcapabilities: ['ws-relay', 'http-transfer']\n\t\t\t\t\t.filter((c) => Array.isArray(msg.capabilities) && msg.capabilities.includes(c))\n\t\t\t\t\t.sort()\n\t\t\t}))\n\t\t\tbreak\n\t\tcase 'rpc.call':\n\t\t\tawait handleBridgeRpcCall(msg, ws, env, ctx)\n\t\t\tbreak\n\t\tcase 'ws.open':\n\t\t\tawait handleBridgeWsOpen(msg, ws, env, wsProxies)\n\t\t\tbreak\n\t\tcase 'ws.close':\n\t\t\thandleBridgeWsClose(msg, wsProxies)\n\t\t\tbreak\n\t}\n}\n\nfunction handleBridgeWebSocket(request, env, ctx) {\n\tconst { 0: client, 1: server } = new WebSocketPair()\n\tserver.accept()\n\n\t// Per-connection state: recreated for every bridge client so reloads and\n\t// concurrent clients never share WS proxy entries.\n\tconst wsProxies = new Map()\n\n\tserver.addEventListener('message', async (event) => {\n\t\ttry {\n\t\t\tif (typeof event.data === 'string') {\n\t\t\t\tawait handleBridgeJsonMessage(event.data, server, env, ctx, wsProxies)\n\t\t\t} else {\n\t\t\t\thandleBridgeBinaryMessage(event.data, wsProxies)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('[Gateway] Error:', error)\n\t\t}\n\t})\n\n\tserver.addEventListener('close', () => {\n\t\tfor (const proxy of wsProxies.values()) {\n\t\t\t// Best-effort cleanup: the DO-side WS may already be closed or in an\n\t\t\t// invalid state; any throw here would abort sibling closes. Surface\n\t\t\t// the swallowed error when DEVFLARE_DEBUG_BRIDGE is enabled.\n\t\t\ttry { proxy.doWs.close() } catch (error) {\n\t\t\t\tif (globalThis.DEVFLARE_DEBUG_BRIDGE) {\n\t\t\t\t\tconsole.warn('[devflare:bridge] proxy.doWs.close() failed', error)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twsProxies.clear()\n\t})\n\n\treturn new Response(null, { status: 101, webSocket: client })\n}\n\n// ---------------------------------------------------------------------------\n// HTTP transfer for R2 bodies (shared with src/bridge/server.ts in shape)\n// ---------------------------------------------------------------------------\n\nasync function handleHttpTransfer(request, env, url) {\n\tconst transferIdEncoded = url.pathname.split('/').pop()\n\tconst transferId = decodeURIComponent(transferIdEncoded || '')\n\tconst [binding, ...keyParts] = transferId.split(':')\n\tconst key = keyParts.join(':')\n\tconst bucket = env[binding]\n\n\tif (!bucket) return new Response('Bucket not found: ' + binding, { status: 404 })\n\n\tif (request.method === 'PUT' || request.method === 'POST') {\n\t\tconst result = await bucket.put(key, request.body)\n\t\treturn new Response(JSON.stringify(serializeR2Object(result)), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t})\n\t}\n\n\tif (request.method === 'GET') {\n\t\tconst object = await bucket.get(key)\n\t\tif (!object) return new Response('Not found', { status: 404 })\n\t\treturn new Response(object.body, {\n\t\t\theaders: {\n\t\t\t\t'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream',\n\t\t\t\t'Content-Length': String(object.size)\n\t\t\t}\n\t\t})\n\t}\n\n\treturn new Response('Method not allowed', { status: 405 })\n}\n";
|
|
7
|
+
export declare const GATEWAY_RUNTIME_JS = "\nconst RAW_EMAIL = 'EmailMessage::raw'\n\n// Inline body cap for proxied DO/service-fetch responses. Matches\n// HTTP_TRANSFER_THRESHOLD in wire.ts (512 KB). A larger body would exceed\n// workerd's ~1 MB WebSocket message limit once base64-encoded into the rpc.ok\n// frame, so it is rejected with a clear error rather than silently truncated.\nconst HTTP_TRANSFER_THRESHOLD = 512 * 1024\n\nfunction arrayBufferToBase64(buffer) {\n\tconst bytes = new Uint8Array(buffer)\n\tlet binary = ''\n\tfor (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i])\n\treturn btoa(binary)\n}\n\nfunction base64ToArrayBuffer(base64) {\n\tconst binary = atob(base64)\n\tconst bytes = new Uint8Array(binary.length)\n\tfor (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n\treturn bytes.buffer\n}\n\n// Binary WsData frame codec (10-byte header: kind:u8, id:u32 LE, seq:u32 LE,\n// flags:u8 + payload). MUST match wire.ts encodeBinaryFrame/decodeBinaryFrame so\n// the bridge client and this gateway agree on the WS-data wire format\n// (BinaryKind.WsData = 2, BinaryFlags.TEXT = 2).\nfunction encodeWsDataFrame(wid, flags, payload) {\n\tconst frame = new Uint8Array(10 + payload.byteLength)\n\tconst view = new DataView(frame.buffer)\n\tview.setUint8(0, 2)\n\tview.setUint32(1, wid, true)\n\tview.setUint32(5, 0, true)\n\tview.setUint8(9, flags)\n\tframe.set(payload, 10)\n\treturn frame\n}\n\nfunction decodeWsDataFrame(buffer) {\n\tconst bytes = new Uint8Array(buffer)\n\tif (bytes.byteLength < 10) return null\n\tconst view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\treturn {\n\t\tkind: view.getUint8(0),\n\t\tid: view.getUint32(1, true),\n\t\tflags: view.getUint8(9),\n\t\tpayload: bytes.subarray(10)\n\t}\n}\n\nfunction serializeR2Object(obj) {\n\tif (!obj) return null\n\treturn {\n\t\t__type: 'R2Object',\n\t\tkey: obj.key,\n\t\tversion: obj.version,\n\t\tsize: obj.size,\n\t\tetag: obj.etag,\n\t\thttpEtag: obj.httpEtag,\n\t\tchecksums: obj.checksums,\n\t\tuploaded: obj.uploaded?.toISOString(),\n\t\thttpMetadata: obj.httpMetadata,\n\t\tcustomMetadata: obj.customMetadata,\n\t\trange: obj.range,\n\t\tstorageClass: obj.storageClass\n\t}\n}\n\nfunction serializeR2ObjectBody(obj, bodyData) {\n\tif (!obj) return null\n\treturn {\n\t\t__type: 'R2ObjectBody',\n\t\tkey: obj.key,\n\t\tversion: obj.version,\n\t\tsize: obj.size,\n\t\tetag: obj.etag,\n\t\thttpEtag: obj.httpEtag,\n\t\tchecksums: obj.checksums,\n\t\tuploaded: obj.uploaded?.toISOString(),\n\t\thttpMetadata: obj.httpMetadata,\n\t\tcustomMetadata: obj.customMetadata,\n\t\trange: obj.range,\n\t\tstorageClass: obj.storageClass,\n\t\tbodyData\n\t}\n}\n\nfunction serializeR2Objects(result) {\n\tif (!result) return null\n\treturn {\n\t\tobjects: result.objects.map(serializeR2Object),\n\t\ttruncated: result.truncated,\n\t\tcursor: result.cursor,\n\t\tdelimitedPrefixes: result.delimitedPrefixes\n\t}\n}\n\nasync function serializeResponse(response) {\n\tlet body = null\n\tif (response.body) {\n\t\tconst bytes = await response.arrayBuffer()\n\t\tif (bytes.byteLength > HTTP_TRANSFER_THRESHOLD) {\n\t\t\tthrow new Error(\n\t\t\t\t'[devflare][bridge] Response body (' + bytes.byteLength + ' bytes) exceeds the '\n\t\t\t\t+ HTTP_TRANSFER_THRESHOLD + '-byte inline limit. DO and service-binding fetch responses '\n\t\t\t\t+ 'are delivered inline over the bridge WebSocket and cannot be streamed locally; keep '\n\t\t\t\t+ 'proxied response bodies under the limit (large R2 objects are exempt \u2014 read them through '\n\t\t\t\t+ 'the R2 binding, which uses the HTTP transfer side-channel).'\n\t\t\t)\n\t\t}\n\t\tif (bytes.byteLength > 0) {\n\t\t\tbody = { type: 'bytes', data: arrayBufferToBase64(bytes) }\n\t\t}\n\t}\n\treturn {\n\t\tstatus: response.status,\n\t\tstatusText: response.statusText,\n\t\theaders: [...response.headers.entries()],\n\t\tbody\n\t}\n}\n\nfunction deserializeRequest(serializedReq) {\n\treturn new Request(serializedReq.url, {\n\t\tmethod: serializedReq.method,\n\t\theaders: serializedReq.headers,\n\t\tbody: serializedReq.body?.type === 'bytes'\n\t\t\t? base64ToArrayBuffer(serializedReq.body.data)\n\t\t\t: undefined,\n\t\tredirect: serializedReq.redirect\n\t})\n}\n\nfunction createEmailMessageRaw(raw) {\n\tif (typeof raw === 'string' || raw instanceof ReadableStream) {\n\t\treturn raw\n\t}\n\tif (raw instanceof ArrayBuffer || raw instanceof Uint8Array) {\n\t\treturn new Response(raw).body\n\t}\n\tthrow new Error('Unsupported EmailMessage raw payload')\n}\n\nfunction isDurableObjectNamespace(binding) {\n\treturn !!binding\n\t\t&& typeof binding.idFromName === 'function'\n\t\t&& typeof binding.idFromString === 'function'\n\t\t&& typeof binding.newUniqueId === 'function'\n}\n\n/**\n * Resolve a (possibly jurisdiction-scoped) DurableObjectNamespace.\n * Forwards the jurisdiction faithfully when the binding supports it\n * (real Cloudflare), and degrades to the plain binding otherwise\n * (miniflare/workerd local emulation, which does not pin jurisdictions).\n */\nfunction resolveDoNamespace(binding, jurisdiction) {\n\tif (jurisdiction && typeof binding.jurisdiction === 'function') {\n\t\treturn binding.jurisdiction(jurisdiction)\n\t}\n\treturn binding\n}\n\n// Dispatch a single Durable Object RPC method call to its stub.\n//\n// A DO that extends DurableObject (from cloudflare:workers) exposes its methods\n// as native RPC on the stub, so the method is invoked DIRECTLY as\n// stub[method](...args) \u2014 exactly as on real Cloudflare. This is the ONLY\n// correct path for a DO that ALSO defines its own fetch(): routing the call\n// through fetch() would hand devflare's internal _rpc probe to the user handler,\n// which may reject it (e.g. a websocket-only fetch() returning 426) and yield a\n// non-JSON body that then fails to parse (the reported crash).\n//\n// The fetch _rpc convention is kept only as a fallback for DOs that are not\n// RPC-enabled: the stub proxies every property as callable, so such a DO only\n// reveals itself when the native call throws \"does not support RPC\".\nasync function callDurableObjectRpc(stub, methodName, args) {\n\tif (typeof stub[methodName] === 'function') {\n\t\ttry {\n\t\t\treturn await stub[methodName](...args)\n\t\t} catch (error) {\n\t\t\tif (!isDurableObjectRpcUnsupported(error)) throw error\n\t\t}\n\t}\n\tconst response = await stub.fetch(new Request('http://do/_rpc', {\n\t\tmethod: 'POST',\n\t\theaders: { 'Content-Type': 'application/json' },\n\t\tbody: JSON.stringify({ method: methodName, params: args })\n\t}))\n\tconst result = await response.json()\n\tif (!result.ok) throw new Error(result.error?.message || 'RPC failed')\n\treturn result.result\n}\n\nfunction isDurableObjectRpcUnsupported(error) {\n\tconst message = error && error.message ? String(error.message) : String(error)\n\treturn message.indexOf('does not support RPC') !== -1\n}\n\n/**\n * Execute an RPC method against the gateway's bindings.\n *\n * Method format: \"binding.operation\". Operations must be namespaced by\n * binding kind (e.g. \"kv.get\", \"r2.head\", \"d1.stmt.first\", \"do.fetch\",\n * \"service.fetch\", \"queue.send\", \"email.send\", \"ai.run\"). Bare verbs and the legacy\n * \"stmt.*\" / \"stub.*\" sub-prefixes were removed in B3-final and now throw.\n * Method vocabulary must stay in sync with the canonical server in\n * src/bridge/server.ts.\n */\nasync function executeRpcMethod(method, params, env, _ctx) {\n\tconst parts = method.split('.')\n\tif (parts.length < 2) throw new Error('Invalid method format: ' + method)\n\n\tconst bindingName = parts[0]\n\tconst operation = parts.slice(1).join('.')\n\tconst binding = env[bindingName]\n\n\tif (!binding) throw new Error('Binding not found: ' + bindingName)\n\n\tconst isNamespaced =\n\t\toperation.indexOf('kv.') === 0 ||\n\t\toperation.indexOf('r2.') === 0 ||\n\t\toperation.indexOf('d1.') === 0 ||\n\t\toperation.indexOf('do.') === 0 ||\n\t\toperation.indexOf('service.') === 0 ||\n\t\toperation.indexOf('queue.') === 0 ||\n\t\toperation.indexOf('email.') === 0 ||\n\t\toperation.indexOf('ai.') === 0 ||\n\t\toperation.indexOf('workflow.') === 0 ||\n\t\toperation.indexOf('var.') === 0\n\tif (!isNamespaced) {\n\t\tthrow new Error(createUnsupportedBridgeOperationErrorMessage(bindingName, operation))\n\t}\n\n\t// KV\n\tif (operation === 'kv.get') return binding.get(params[0], params[1])\n\tif (operation === 'kv.put') return binding.put(params[0], params[1], params[2])\n\tif (operation === 'kv.delete') return binding.delete(params[0])\n\tif (operation === 'kv.list') return binding.list(params[0])\n\tif (operation === 'kv.getWithMetadata') return binding.getWithMetadata(params[0], params[1])\n\n\t// DO get (returns DOStub reference)\n\tif (operation === 'do.get') {\n\t\treturn { __type: 'DOStub', binding: bindingName, id: params[0] }\n\t}\n\n\t// R2\n\tif (operation === 'r2.head') return serializeR2Object(await binding.head(params[0]))\n\tif (operation === 'r2.get') {\n\t\tconst obj = await binding.get(params[0], params[1])\n\t\tif (!obj) return null\n\t\tconst body = await obj.arrayBuffer()\n\t\treturn serializeR2ObjectBody(obj, arrayBufferToBase64(body))\n\t}\n\tif (operation === 'r2.put') {\n\t\tlet value = params[1]\n\t\tif (value && typeof value === 'object') {\n\t\t\tif (value.__type === 'ArrayBuffer' || value.__type === 'Uint8Array') {\n\t\t\t\tvalue = base64ToArrayBuffer(value.data)\n\t\t\t}\n\t\t}\n\t\treturn serializeR2Object(await binding.put(params[0], value, params[2]))\n\t}\n\tif (operation === 'r2.delete') return binding.delete(params[0])\n\tif (operation === 'r2.list') return serializeR2Objects(await binding.list(params[0]))\n\n\t// D1\n\tif (operation === 'd1.exec') return binding.exec(params[0])\n\tif (operation === 'd1.batch') {\n\t\tconst statements = params[0].map((s) => binding.prepare(s.sql).bind(...(s.bindings || [])))\n\t\treturn binding.batch(statements)\n\t}\n\tif (operation.indexOf('d1.stmt.') === 0) {\n\t\tconst mode = operation.split('.')[2]\n\t\tconst [sql, ...rest] = params\n\t\tlet bindings = rest\n\t\tlet extraParam\n\t\tif (mode === 'first' || mode === 'raw') {\n\t\t\textraParam = rest[rest.length - 1]\n\t\t\tbindings = rest.slice(0, -1)\n\t\t}\n\t\tlet stmt = binding.prepare(sql)\n\t\tif (bindings.length > 0) stmt = stmt.bind(...bindings)\n\t\tif (mode === 'first') {\n\t\t\tif (typeof extraParam === 'string' && extraParam.length > 0) return stmt.first(extraParam)\n\t\t\treturn stmt.first()\n\t\t}\n\t\tif (mode === 'all') return stmt.all()\n\t\tif (mode === 'run') return stmt.run()\n\t\tif (mode === 'raw') return stmt.raw(extraParam)\n\t\tthrow new Error('Unknown stmt mode: ' + mode)\n\t}\n\n\t// Durable Objects\n\tif (operation === 'do.idFromName') {\n\t\tconst ns = resolveDoNamespace(binding, params[1])\n\t\tconst id = ns.idFromName(params[0])\n\t\treturn { __type: 'DOId', hex: id.toString() }\n\t}\n\tif (operation === 'do.idFromString') {\n\t\tconst id = binding.idFromString(params[0])\n\t\treturn { __type: 'DOId', hex: id.toString() }\n\t}\n\tif (operation === 'do.newUniqueId') {\n\t\tconst ns = resolveDoNamespace(binding, params[1])\n\t\tconst id = ns.newUniqueId(params[0])\n\t\treturn { __type: 'DOId', hex: id.toString() }\n\t}\n\tif (operation === 'do.fetch') {\n\t\tconst [, serializedId, serializedReq] = params\n\t\tconst id = binding.idFromString(serializedId.hex)\n\t\tconst stub = binding.get(id)\n\t\tconst response = await stub.fetch(new Request(serializedReq.url, {\n\t\t\tmethod: serializedReq.method,\n\t\t\theaders: serializedReq.headers,\n\t\t\tbody: serializedReq.body?.type === 'bytes'\n\t\t\t\t? base64ToArrayBuffer(serializedReq.body.data)\n\t\t\t\t: undefined\n\t\t}))\n\t\treturn serializeResponse(response)\n\t}\n\tif (operation === 'do.rpc') {\n\t\tconst [, serializedId, methodName, args] = params\n\t\tconst id = binding.idFromString(serializedId.hex)\n\t\tconst stub = binding.get(id)\n\t\treturn callDurableObjectRpc(stub, methodName, Array.isArray(args) ? args : [])\n\t}\n\n\t// Service Bindings\n\tif (operation === 'service.fetch') {\n\t\tif (!binding || typeof binding.fetch !== 'function') {\n\t\t\tthrow new Error('Service binding ' + bindingName + ' does not support fetch()')\n\t\t}\n\t\tconst response = await binding.fetch(deserializeRequest(params[0]))\n\t\treturn serializeResponse(response)\n\t}\n\tif (operation === 'service.rpc') {\n\t\tconst methodName = params[0]\n\t\tif (typeof methodName !== 'string') {\n\t\t\tthrow new Error('Service binding ' + bindingName + ' RPC method name must be a string')\n\t\t}\n\t\tconst args = Array.isArray(params[1]) ? params[1] : []\n\t\tconst method = binding && binding[methodName]\n\t\tif (typeof method !== 'function') {\n\t\t\tthrow new Error('Service binding ' + bindingName + ' does not support ' + methodName + '()')\n\t\t}\n\t\treturn method.apply(binding, args)\n\t}\n\n\t// Queues\n\tif (operation === 'queue.send') return binding.send(params[0], params[1])\n\tif (operation === 'queue.sendBatch') return binding.sendBatch(params[0], params[1])\n\n\t// Send Email\n\tif (operation === 'email.send') {\n\t\tif (binding && typeof binding.send === 'function') {\n\t\t\tconst message = params[0]\n\t\t\tif (message && typeof message === 'object' && 'from' in message && 'to' in message && 'raw' in message) {\n\t\t\t\treturn binding.send({\n\t\t\t\t\tfrom: message.from,\n\t\t\t\t\tto: message.to,\n\t\t\t\t\t[RAW_EMAIL]: createEmailMessageRaw(message.raw)\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn binding.send(message)\n\t\t}\n\t\treturn { ok: true, simulated: true }\n\t}\n\n\t// Workflows\n\tif (operation === 'workflow.create') {\n\t\treturn serializeWorkflowInstance(await binding.create(params[0]))\n\t}\n\tif (operation === 'workflow.get') {\n\t\treturn serializeWorkflowInstance(await binding.get(params[0]))\n\t}\n\tif (operation === 'workflow.status') {\n\t\treturn (await binding.get(params[0])).status()\n\t}\n\tif (operation === 'workflow.pause') {\n\t\treturn (await binding.get(params[0])).pause()\n\t}\n\tif (operation === 'workflow.resume') {\n\t\treturn (await binding.get(params[0])).resume()\n\t}\n\tif (operation === 'workflow.terminate') {\n\t\treturn (await binding.get(params[0])).terminate()\n\t}\n\tif (operation === 'workflow.restart') {\n\t\treturn (await binding.get(params[0])).restart()\n\t}\n\tif (operation === 'workflow.sendEvent') {\n\t\treturn (await binding.get(params[0])).sendEvent(params[1])\n\t}\n\n\t// AI / generic run()\n\tif (operation === 'ai.run') {\n\t\tif (typeof binding.run !== 'function') {\n\t\t\tthrow new Error('Binding ' + bindingName + ' does not support run(): ' + method)\n\t\t}\n\t\treturn binding.run(params[0], params[1])\n\t}\n\n\tthrow new Error('Unknown operation: ' + method)\n}\n\nfunction createUnsupportedBridgeOperationErrorMessage(bindingName, operation) {\n\tconst base = \"[devflare][bridge] Unsupported bridge operation '\" + operation + \"' for binding '\" + bindingName + \"'.\"\n\tif (operation === 'fetch') {\n\t\treturn base + ' Devflare could not dispatch fetch() for this binding through the local bridge. '\n\t\t\t+ 'Expected Cloudflare API: env.' + bindingName + '.fetch(request). '\n\t\t\t+ 'If this came from SvelteKit platform.env, make sure the binding is declared as a service binding; '\n\t\t\t+ 'this is a Devflare local bridge issue when service bindings fall back to a bare fetch operation.'\n\t}\n\tif (operation === 'toString') {\n\t\treturn base + ' A platform.env value was coerced to a string through the bridge. '\n\t\t\t+ 'For SvelteKit local dev, declared vars should be plain string values and missing env names should read as undefined.'\n\t}\n\treturn base + ' Bare verbs and the legacy stmt.*/stub.* sub-prefixes are not supported; '\n\t\t+ 'use the namespaced form (e.g. kv.get, r2.put, d1.stmt.first, do.fetch, service.fetch).'\n}\n\nfunction serializeWorkflowInstance(instance) {\n\treturn {\n\t\t__type: 'WorkflowInstance',\n\t\tid: instance.id\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// WebSocket bridge (shared with src/bridge/server.ts in shape)\n// ---------------------------------------------------------------------------\n// NOTE: wsProxies is intentionally created per handleBridgeWebSocket call so\n// state never leaks across connections or across gateway-script regenerations.\n\nasync function handleBridgeRpcCall(msg, ws, env, ctx) {\n\ttry {\n\t\tconst result = await executeRpcMethod(msg.method, msg.params, env, ctx)\n\t\tws.send(JSON.stringify({ t: 'rpc.ok', id: msg.id, result }))\n\t} catch (error) {\n\t\tws.send(JSON.stringify({\n\t\t\tt: 'rpc.err',\n\t\t\tid: msg.id,\n\t\t\terror: {\n\t\t\t\tcode: error?.code || 'INTERNAL_ERROR',\n\t\t\t\tmessage: error?.message || String(error)\n\t\t\t}\n\t\t}))\n\t}\n}\n\nasync function handleBridgeWsOpen(msg, ws, env, wsProxies) {\n\ttry {\n\t\tconst binding = env[msg.target.binding]\n\t\tconst id = binding.idFromString(msg.target.id)\n\t\tconst stub = binding.get(id)\n\n\t\tconst headers = new Headers(msg.target.headers || [])\n\t\theaders.set('Upgrade', 'websocket')\n\n\t\tconst response = await stub.fetch(new Request(msg.target.url, { method: 'GET', headers }))\n\t\tconst doWs = response.webSocket\n\n\t\tif (!doWs) {\n\t\t\tws.send(JSON.stringify({\n\t\t\t\tt: 'rpc.err',\n\t\t\t\tid: 'ws_' + msg.wid,\n\t\t\t\terror: { code: 'WS_FAILED', message: 'No WebSocket returned' }\n\t\t\t}))\n\t\t\treturn\n\t\t}\n\n\t\tdoWs.accept()\n\t\twsProxies.set(msg.wid, { doWs })\n\n\t\tdoWs.addEventListener('message', (event) => {\n\t\t\tconst isText = typeof event.data === 'string'\n\t\t\tconst payload = isText\n\t\t\t\t? new TextEncoder().encode(event.data)\n\t\t\t\t: new Uint8Array(event.data)\n\t\t\tconst flags = isText ? 2 : 0\n\t\t\tws.send(encodeWsDataFrame(msg.wid, flags, payload))\n\t\t})\n\n\t\tdoWs.addEventListener('close', (event) => {\n\t\t\tws.send(JSON.stringify({ t: 'ws.close', wid: msg.wid, code: event.code, reason: event.reason }))\n\t\t\twsProxies.delete(msg.wid)\n\t\t})\n\n\t\tws.send(JSON.stringify({ t: 'ws.opened', wid: msg.wid }))\n\t} catch (error) {\n\t\tws.send(JSON.stringify({\n\t\t\tt: 'rpc.err',\n\t\t\tid: 'ws_' + msg.wid,\n\t\t\terror: { code: 'WS_FAILED', message: error.message }\n\t\t}))\n\t}\n}\n\nfunction handleBridgeWsClose(msg, wsProxies) {\n\tconst proxy = wsProxies.get(msg.wid)\n\tif (proxy) {\n\t\tproxy.doWs.close(msg.code, msg.reason)\n\t\twsProxies.delete(msg.wid)\n\t}\n}\n\n// Relay an inbound binary WsData frame (client -> DO). Mirrors server.ts\n// handleBinaryMessage: decode the frame, look up the proxy by ws id, and forward\n// the payload to the DO socket honoring the TEXT flag.\nfunction handleBridgeBinaryMessage(buffer, wsProxies) {\n\tconst frame = decodeWsDataFrame(buffer)\n\tif (!frame || frame.kind !== 2) return\n\tconst proxy = wsProxies.get(frame.id)\n\tif (!proxy) return\n\tif ((frame.flags & 2) !== 0) {\n\t\tproxy.doWs.send(new TextDecoder().decode(frame.payload))\n\t} else {\n\t\tproxy.doWs.send(frame.payload)\n\t}\n}\n\nasync function handleBridgeJsonMessage(data, ws, env, ctx, wsProxies) {\n\tconst msg = JSON.parse(data)\n\tswitch (msg.t) {\n\t\tcase 'hello':\n\t\t\t// v2 handshake \u2014 acknowledge with welcome echoing the negotiated\n\t\t\t// capability intersection. The gateway advertises only what it\n\t\t\t// implements end-to-end: 'ws-relay' (binary WsData relay to/from DO\n\t\t\t// sockets) and 'http-transfer' (the R2 transfer HTTP side-channel).\n\t\t\t// 'streams' is intentionally NOT advertised \u2014 large DO/service-fetch\n\t\t\t// responses are inlined, not streamed, in this gateway.\n\t\t\tws.send(JSON.stringify({\n\t\t\t\tt: 'welcome',\n\t\t\t\tprotocolVersion: 2,\n\t\t\t\tcapabilities: ['ws-relay', 'http-transfer']\n\t\t\t\t\t.filter((c) => Array.isArray(msg.capabilities) && msg.capabilities.includes(c))\n\t\t\t\t\t.sort()\n\t\t\t}))\n\t\t\tbreak\n\t\tcase 'rpc.call':\n\t\t\tawait handleBridgeRpcCall(msg, ws, env, ctx)\n\t\t\tbreak\n\t\tcase 'ws.open':\n\t\t\tawait handleBridgeWsOpen(msg, ws, env, wsProxies)\n\t\t\tbreak\n\t\tcase 'ws.close':\n\t\t\thandleBridgeWsClose(msg, wsProxies)\n\t\t\tbreak\n\t}\n}\n\n// Pass-through DO WebSocket upgrade (bridge client -> gateway -> DO).\n//\n// The bridge client's openDoWebSocket() opens a REAL loopback WebSocket to this\n// endpoint (/_devflare/do-ws?binding&id&u) instead of tunneling frames over the\n// bridge socket. We resolve the DO by id and RETURN the DO's 101 response\n// verbatim (webSocket included), so miniflare wires the inbound connection to\n// the DO's client socket. That genuine inbound connection is what makes workerd\n// dispatch the DO's hibernation handlers (webSocketMessage/webSocketClose) and\n// deliver ctx.getWebSockets() broadcasts. Pumping the DO socket in-process (the\n// legacy handleBridgeWsOpen path) never triggers hibernation, so two sockets to\n// one getByName(id) could not see each other's messages. This mirrors the\n// browser WS_ROUTES pass-through (handleDoWebSocket) and real Cloudflare.\n//\n// NOTE: the devflare/test gateway (src/test/simple-context-gateway-script.ts)\n// keeps a byte-equivalent copy of this handler because it is a separately-bundled\n// Worker template that cannot import this runtime \u2014 keep the two in sync.\nasync function handleBridgeDoWebSocket(request, env, url) {\n\ttry {\n\t\tconst bindingName = url.searchParams.get('binding')\n\t\tconst idHex = url.searchParams.get('id')\n\t\tconst targetUrl = url.searchParams.get('u') || url.toString()\n\n\t\tconst binding = env[bindingName]\n\t\tif (!binding || typeof binding.idFromString !== 'function') {\n\t\t\treturn new Response('Durable Object binding not found: ' + bindingName, { status: 500 })\n\t\t}\n\t\tif (!idHex) {\n\t\t\treturn new Response('Missing Durable Object id', { status: 400 })\n\t\t}\n\n\t\tconst stub = binding.get(binding.idFromString(idHex))\n\t\t// Forward the real upgrade request (its headers carry any auth/cookies the\n\t\t// caller passed to connect()) and pass the DO's 101 response straight back.\n\t\treturn stub.fetch(new Request(targetUrl, { method: 'GET', headers: request.headers }))\n\t} catch (error) {\n\t\treturn new Response('Error opening DO WebSocket: ' + (error?.message || String(error)), {\n\t\t\tstatus: 500\n\t\t})\n\t}\n}\n\nfunction handleBridgeWebSocket(request, env, ctx) {\n\tconst { 0: client, 1: server } = new WebSocketPair()\n\tserver.accept()\n\n\t// Per-connection state: recreated for every bridge client so reloads and\n\t// concurrent clients never share WS proxy entries.\n\tconst wsProxies = new Map()\n\n\tserver.addEventListener('message', async (event) => {\n\t\ttry {\n\t\t\tif (typeof event.data === 'string') {\n\t\t\t\tawait handleBridgeJsonMessage(event.data, server, env, ctx, wsProxies)\n\t\t\t} else {\n\t\t\t\thandleBridgeBinaryMessage(event.data, wsProxies)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('[Gateway] Error:', error)\n\t\t}\n\t})\n\n\tserver.addEventListener('close', () => {\n\t\tfor (const proxy of wsProxies.values()) {\n\t\t\t// Best-effort cleanup: the DO-side WS may already be closed or in an\n\t\t\t// invalid state; any throw here would abort sibling closes. Surface\n\t\t\t// the swallowed error when DEVFLARE_DEBUG_BRIDGE is enabled.\n\t\t\ttry { proxy.doWs.close() } catch (error) {\n\t\t\t\tif (globalThis.DEVFLARE_DEBUG_BRIDGE) {\n\t\t\t\t\tconsole.warn('[devflare:bridge] proxy.doWs.close() failed', error)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twsProxies.clear()\n\t})\n\n\treturn new Response(null, { status: 101, webSocket: client })\n}\n\n// ---------------------------------------------------------------------------\n// HTTP transfer for R2 bodies (shared with src/bridge/server.ts in shape)\n// ---------------------------------------------------------------------------\n\nasync function handleHttpTransfer(request, env, url) {\n\tconst transferIdEncoded = url.pathname.split('/').pop()\n\tconst transferId = decodeURIComponent(transferIdEncoded || '')\n\tconst [binding, ...keyParts] = transferId.split(':')\n\tconst key = keyParts.join(':')\n\tconst bucket = env[binding]\n\n\tif (!bucket) return new Response('Bucket not found: ' + binding, { status: 404 })\n\n\tif (request.method === 'PUT' || request.method === 'POST') {\n\t\tconst result = await bucket.put(key, request.body)\n\t\treturn new Response(JSON.stringify(serializeR2Object(result)), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t})\n\t}\n\n\tif (request.method === 'GET') {\n\t\tconst object = await bucket.get(key)\n\t\tif (!object) return new Response('Not found', { status: 404 })\n\t\treturn new Response(object.body, {\n\t\t\theaders: {\n\t\t\t\t'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream',\n\t\t\t\t'Content-Length': String(object.size)\n\t\t\t}\n\t\t})\n\t}\n\n\treturn new Response('Method not allowed', { status: 405 })\n}\n";
|
|
8
8
|
//# sourceMappingURL=gateway-runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-runtime.d.ts","sourceRoot":"","sources":["../../src/bridge/gateway-runtime.ts"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"gateway-runtime.d.ts","sourceRoot":"","sources":["../../src/bridge/gateway-runtime.ts"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,6xwBAupB9B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/bridge/proxy.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,UAAU,CAAA;AAavD,MAAM,WAAW,eAAe;IAC/B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,qCAAqC;IACrC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wEAAwE;IACxE,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAA;CAC9C;
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/bridge/proxy.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,UAAU,CAAA;AAavD,MAAM,WAAW,eAAe;IAC/B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,qCAAqC;IACrC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wEAAwE;IACxE,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAA;CAC9C;AAooBD,mDAAmD;AACnD,MAAM,MAAM,WAAW,GACpB,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,OAAO,GACP,IAAI,GACJ,SAAS,GACT,WAAW,GACX,UAAU,GACV,QAAQ,GACR,KAAK,CAAA;AAER,MAAM,WAAW,YAAY;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAA;CAC1B;AAKD;;GAEG;AACH,wBAAgB,cAAc,CAC7B,OAAO,GAAE,eAAe,GAAG;IAAE,KAAK,CAAC,EAAE,YAAY,CAAA;CAAO,GACtD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoFzB;AAwFD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAO5C,CAAA;AAEF;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,GAAE,eAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAG9E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAIzD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/bridge/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/bridge/server.ts"],"names":[],"mappings":"AAwCA,MAAM,WAAW,UAAU;IAE1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB;;IAiBM,KAAK,UAAU,OAAO,OAAO,UAAU,OAAO,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;;;AA+LzF,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EAAE,EACjB,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,gBAAgB,GACnB,OAAO,CAAC,OAAO,CAAC,CA+KlB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** A WebSocket constructor callable as `new Ctor(url)`. */
|
|
2
|
+
export type WebSocketConstructor = new (url: string) => WebSocket;
|
|
3
|
+
/**
|
|
4
|
+
* Lazily import the `ws` package's WebSocket constructor (memoized). Used as the
|
|
5
|
+
* Node fallback and whenever custom upgrade headers are required — unlike the
|
|
6
|
+
* platform global, the `ws` constructor accepts an options object with headers.
|
|
7
|
+
*
|
|
8
|
+
* @returns The `ws` package WebSocket constructor.
|
|
9
|
+
* @throws When the `ws` package does not export a usable WebSocket implementation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function importWsPackageConstructor(): Promise<WebSocketConstructor>;
|
|
12
|
+
/**
|
|
13
|
+
* Return the runtime's global WebSocket constructor, or null when the runtime
|
|
14
|
+
* has none (older Node without a global WebSocket).
|
|
15
|
+
*
|
|
16
|
+
* @param runtimeWebSocket - The candidate global (defaults to `globalThis.WebSocket`).
|
|
17
|
+
* @returns The global constructor, or null.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getRuntimeWebSocketConstructor(runtimeWebSocket?: unknown): WebSocketConstructor | null;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a WebSocket constructor for the bridge socket: prefer the runtime
|
|
22
|
+
* global, fall back to the `ws` package.
|
|
23
|
+
*
|
|
24
|
+
* @param runtimeWebSocket - The candidate global (defaults to `globalThis.WebSocket`).
|
|
25
|
+
* @returns A usable WebSocket constructor.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveBridgeWebSocketConstructor(runtimeWebSocket?: unknown): Promise<WebSocketConstructor>;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the WebSocket constructor for a Durable Object pass-through
|
|
30
|
+
* connection. Custom upgrade headers require the `ws` package (whose constructor
|
|
31
|
+
* accepts an options object); the global WebSocket (undici/Bun) cannot set
|
|
32
|
+
* request headers, so it is used only when there are no headers to forward.
|
|
33
|
+
*
|
|
34
|
+
* @param hasHeaders - Whether application headers must ride the upgrade request.
|
|
35
|
+
* @returns A WebSocket constructor suitable for the connection.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveDoWebSocketConstructor(hasHeaders: boolean): Promise<WebSocketConstructor>;
|
|
38
|
+
//# sourceMappingURL=websocket-constructor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-constructor.d.ts","sourceRoot":"","sources":["../../src/bridge/websocket-constructor.ts"],"names":[],"mappings":"AAUA,2DAA2D;AAC3D,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,EAAE,MAAM,KAAK,SAAS,CAAA;AAIjE;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,oBAAoB,CAAC,CA4BhF;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC7C,gBAAgB,GAAE,OAA8B,GAC9C,oBAAoB,GAAG,IAAI,CAM7B;AAED;;;;;;GAMG;AACH,wBAAsB,iCAAiC,CACtD,gBAAgB,GAAE,OAA8B,GAC9C,OAAO,CAAC,oBAAoB,CAAC,CAK/B;AAED;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CAClD,UAAU,EAAE,OAAO,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAG/B"}
|
package/dist/browser.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as defineConfig, t as ref } from "./_chunks/ref-CYJNAAe_.js";
|
|
2
2
|
import { t as workerName } from "./_chunks/workerName-CFJsLZA-.js";
|
|
3
3
|
import { n as getDurableObjectOptions, t as durableObject } from "./_chunks/decorators-QmV57ixr.js";
|
|
4
|
-
import { F as BridgeClient, I as getClient, M as createEnvProxy, N as initEnv, P as setBindingHints } from "./_chunks/context-
|
|
5
|
-
import { i as vars, r as env } from "./_chunks/env-
|
|
4
|
+
import { F as BridgeClient, I as getClient, M as createEnvProxy, N as initEnv, P as setBindingHints } from "./_chunks/context-B6S7cqQW.js";
|
|
5
|
+
import { i as vars, r as env } from "./_chunks/env-UqevBSTd.js";
|
|
6
6
|
//#region src/browser.ts
|
|
7
7
|
function createUnsupportedApiError(name) {
|
|
8
8
|
return /* @__PURE__ */ new Error(`${name} is not available in browser environments; import from devflare/test or devflare/runtime in a worker/Node context instead.`);
|
package/dist/cli/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as runCli, t as parseArgs } from "../_chunks/cli-
|
|
1
|
+
import { n as runCli, t as parseArgs } from "../_chunks/cli-sOZfXGua.js";
|
|
2
2
|
export { parseArgs, runCli };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-script.d.ts","sourceRoot":"","sources":["../../src/dev-server/gateway-script.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,GAAE,aAAa,EAAO,EAC9B,KAAK,UAAQ,EACb,qBAAqB,GAAE,MAAM,GAAG,IAAW,GACzC,MAAM,
|
|
1
|
+
{"version":3,"file":"gateway-script.d.ts","sourceRoot":"","sources":["../../src/dev-server/gateway-script.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,GAAE,aAAa,EAAO,EAC9B,KAAK,UAAQ,EACb,qBAAqB,GAAE,MAAM,GAAG,IAAW,GACzC,MAAM,CA4QR"}
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,6 @@ import { a as ConfigResourceResolutionError, d as configSchema, n as ConfigValid
|
|
|
4
4
|
import { n as compileConfig, s as stringifyConfig } from "./_chunks/compiler-CgIFPfRA.js";
|
|
5
5
|
import { t as workerName } from "./_chunks/workerName-CFJsLZA-.js";
|
|
6
6
|
import { n as getDurableObjectOptions, t as durableObject } from "./_chunks/decorators-QmV57ixr.js";
|
|
7
|
-
import { n as runCli, t as parseArgs } from "./_chunks/cli-
|
|
8
|
-
import { i as vars, r as env } from "./_chunks/env-
|
|
7
|
+
import { n as runCli, t as parseArgs } from "./_chunks/cli-sOZfXGua.js";
|
|
8
|
+
import { i as vars, r as env } from "./_chunks/env-UqevBSTd.js";
|
|
9
9
|
export { ConfigNotFoundError, ConfigResourceResolutionError, ConfigValidationError, compileConfig, configSchema, defineConfig as default, defineConfig, durableObject, env, getDurableObjectOptions, loadConfig, loadResolvedConfig, parseArgs, preview, ref, runCli, stringifyConfig, vars, workerName };
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as getDurableObjectOptions, t as durableObject } from "../_chunks/decorators-QmV57ixr.js";
|
|
2
|
-
import { A as createTailEvent, C as createDurableObjectWebSocketCloseEvent, D as createFetchEvent, E as createEmailEvent, O as createQueueEvent, S as createDurableObjectFetchEvent, T as createDurableObjectWebSocketMessageEvent, _ as runWithContext, a as getDurableObjectFetchEvent, b as createContextProxy, c as getDurableObjectWebSocketMessageEvent, d as getEventContextOrNull, f as getFetchEvent, g as hasContext, h as getTailEvent, i as getDurableObjectEvent, k as createScheduledEvent, l as getEmailEvent, m as getScheduledEvent, n as getContextOrNull, o as getDurableObjectWebSocketCloseEvent, p as getQueueEvent, r as getDurableObjectAlarmEvent, s as getDurableObjectWebSocketErrorEvent, t as getContext, u as getEventContext, v as runWithEventContext, w as createDurableObjectWebSocketErrorEvent, x as createDurableObjectAlarmEvent, y as ContextAccessError } from "../_chunks/context-
|
|
2
|
+
import { A as createTailEvent, C as createDurableObjectWebSocketCloseEvent, D as createFetchEvent, E as createEmailEvent, O as createQueueEvent, S as createDurableObjectFetchEvent, T as createDurableObjectWebSocketMessageEvent, _ as runWithContext, a as getDurableObjectFetchEvent, b as createContextProxy, c as getDurableObjectWebSocketMessageEvent, d as getEventContextOrNull, f as getFetchEvent, g as hasContext, h as getTailEvent, i as getDurableObjectEvent, k as createScheduledEvent, l as getEmailEvent, m as getScheduledEvent, n as getContextOrNull, o as getDurableObjectWebSocketCloseEvent, p as getQueueEvent, r as getDurableObjectAlarmEvent, s as getDurableObjectWebSocketErrorEvent, t as getContext, u as getEventContext, v as runWithEventContext, w as createDurableObjectWebSocketErrorEvent, x as createDurableObjectAlarmEvent, y as ContextAccessError } from "../_chunks/context-B6S7cqQW.js";
|
|
3
3
|
import { clearLocalSendEmailBindings, setLocalSendEmailBindings } from "../utils/send-email.js";
|
|
4
|
-
import { C as vars, S as locals, _ as resolveFetchHandler, a as matchFetchRoute, b as env, c as assertExplicitScheduledHandlerStyle, d as defineQueueHandler, f as defineScheduledHandler, g as markWorkerStyle, h as markResolveStyle, i as invokeRouteModules, l as createResolveFetch, m as invokeFetchModule, n as presignR2Put, o as assertExplicit2ArgStyle, p as invokeFetchHandler, r as createRouteResolve, s as assertExplicitQueueHandlerStyle, t as presignR2Get, u as defineFetchHandler, v as sequence, x as event, y as ctx } from "../_chunks/runtime-
|
|
4
|
+
import { C as vars, S as locals, _ as resolveFetchHandler, a as matchFetchRoute, b as env, c as assertExplicitScheduledHandlerStyle, d as defineQueueHandler, f as defineScheduledHandler, g as markWorkerStyle, h as markResolveStyle, i as invokeRouteModules, l as createResolveFetch, m as invokeFetchModule, n as presignR2Put, o as assertExplicit2ArgStyle, p as invokeFetchHandler, r as createRouteResolve, s as assertExplicitQueueHandlerStyle, t as presignR2Get, u as defineFetchHandler, v as sequence, x as event, y as ctx } from "../_chunks/runtime-sEr9b0ns.js";
|
|
5
5
|
export { ContextAccessError, assertExplicit2ArgStyle, assertExplicitQueueHandlerStyle, assertExplicitScheduledHandlerStyle, clearLocalSendEmailBindings, createContextProxy, createDurableObjectAlarmEvent, createDurableObjectFetchEvent, createDurableObjectWebSocketCloseEvent, createDurableObjectWebSocketErrorEvent, createDurableObjectWebSocketMessageEvent, createEmailEvent, createFetchEvent, createQueueEvent, createResolveFetch, createRouteResolve, createScheduledEvent, createTailEvent, ctx, defineFetchHandler, defineQueueHandler, defineScheduledHandler, durableObject, env, event, getContext, getContextOrNull, getDurableObjectAlarmEvent, getDurableObjectEvent, getDurableObjectFetchEvent, getDurableObjectOptions, getDurableObjectWebSocketCloseEvent, getDurableObjectWebSocketErrorEvent, getDurableObjectWebSocketMessageEvent, getEmailEvent, getEventContext, getEventContextOrNull, getFetchEvent, getQueueEvent, getScheduledEvent, getTailEvent, hasContext, invokeFetchHandler, invokeFetchModule, invokeRouteModules, locals, markResolveStyle, markWorkerStyle, matchFetchRoute, presignR2Get, presignR2Put, resolveFetchHandler, runWithContext, runWithEventContext, sequence, setLocalSendEmailBindings, vars };
|
package/dist/sveltekit/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as loadConfig } from "../_chunks/loader-E_UGyTrJ.js";
|
|
2
2
|
import { l as normalizeHyperdriveBinding } from "../_chunks/schema-normalization-Zgm4W6O6.js";
|
|
3
|
-
import { D as createFetchEvent, I as getClient, M as createEnvProxy, P as setBindingHints, v as runWithEventContext } from "../_chunks/context-
|
|
3
|
+
import { D as createFetchEvent, I as getClient, M as createEnvProxy, P as setBindingHints, v as runWithEventContext } from "../_chunks/context-B6S7cqQW.js";
|
|
4
4
|
import { createLocalSendEmailBinding } from "../utils/send-email.js";
|
|
5
5
|
import { i as extractBindingHints, n as createLocalWorkerLoaderBinding, t as createLocalHyperdrive } from "../_chunks/local-hyperdrive-CJ90j46O.js";
|
|
6
6
|
import { t as buildLocalSecretNodeBindings } from "../_chunks/local-secrets-6sMstHXw.js";
|
package/dist/test/index.js
CHANGED
|
@@ -4,10 +4,10 @@ import { _ as normalizeSecretsStoreBinding, f as normalizeMediaBinding, h as nor
|
|
|
4
4
|
import { t as applyLocalDevVarsToConfig } from "../_chunks/local-dev-vars-CTSa-wvF.js";
|
|
5
5
|
import { g as isAuthenticated, p as getApiToken } from "../_chunks/api-TzdliH-6.js";
|
|
6
6
|
import { d as getPrimaryAccount, n as getEffectiveAccountId } from "../_chunks/preferences-BKp_7XJx.js";
|
|
7
|
-
import { A as createTailEvent, D as createFetchEvent, E as createEmailEvent, F as BridgeClient, M as createEnvProxy, O as createQueueEvent, P as setBindingHints, _ as runWithContext, k as createScheduledEvent, v as runWithEventContext, x as createDurableObjectAlarmEvent } from "../_chunks/context-
|
|
7
|
+
import { A as createTailEvent, D as createFetchEvent, E as createEmailEvent, F as BridgeClient, M as createEnvProxy, O as createQueueEvent, P as setBindingHints, _ as runWithContext, k as createScheduledEvent, v as runWithEventContext, x as createDurableObjectAlarmEvent } from "../_chunks/context-B6S7cqQW.js";
|
|
8
8
|
import { createLocalSendEmailBinding, wrapEnvSendEmailBindings } from "../utils/send-email.js";
|
|
9
|
-
import { n as __setTestContext, r as env, t as __clearTestContext } from "../_chunks/env-
|
|
10
|
-
import { _ as resolveFetchHandler, a as matchFetchRoute, m as invokeFetchModule, r as createRouteResolve } from "../_chunks/runtime-
|
|
9
|
+
import { n as __setTestContext, r as env, t as __clearTestContext } from "../_chunks/env-UqevBSTd.js";
|
|
10
|
+
import { _ as resolveFetchHandler, a as matchFetchRoute, m as invokeFetchModule, r as createRouteResolve } from "../_chunks/runtime-sEr9b0ns.js";
|
|
11
11
|
import { i as extractBindingHints, n as createLocalWorkerLoaderBinding, r as disposeLocalWorkerLoaderBindings, t as createLocalHyperdrive } from "../_chunks/local-hyperdrive-CJ90j46O.js";
|
|
12
12
|
import { E as buildTailConsumersConfig, T as buildStreamingTailConsumersConfig, a as hasServiceBindings, i as hasCrossWorkerDOs, m as buildHyperdrivesConfig, o as resolveDOBindings, r as clearBundleCache, s as resolveServiceBindings, t as discoverRoutes, u as buildAnalyticsEngineConfig } from "../_chunks/routes-BMU7ga_l.js";
|
|
13
13
|
import { i as findFiles, t as DEFAULT_DO_PATTERN } from "../_chunks/glob-CmQOvunB.js";
|
|
@@ -1617,6 +1617,39 @@ function __encodeTransport(value) {
|
|
|
1617
1617
|
export default {
|
|
1618
1618
|
async fetch(request, env) {
|
|
1619
1619
|
if (request.headers.get('Upgrade') === 'websocket') {
|
|
1620
|
+
const wsUrl = new URL(request.url)
|
|
1621
|
+
// Bridge DO connect(): a real pass-through upgrade to a Durable Object.
|
|
1622
|
+
// The client's openDoWebSocket() opens a real loopback WS here rather
|
|
1623
|
+
// than tunneling frames over the RPC socket; we forward the upgrade to
|
|
1624
|
+
// the DO and pass its 101 response straight back so miniflare wires the
|
|
1625
|
+
// inbound connection to the DO's client socket. That genuine inbound
|
|
1626
|
+
// connection is what makes the runtime dispatch the DO's hibernation
|
|
1627
|
+
// handlers (webSocketMessage/webSocketClose) and deliver
|
|
1628
|
+
// ctx.getWebSockets() broadcasts — an in-process pump never does.
|
|
1629
|
+
//
|
|
1630
|
+
// This is a byte-equivalent copy of handleBridgeDoWebSocket in
|
|
1631
|
+
// src/bridge/gateway-runtime.ts (this gateway is a separately-bundled
|
|
1632
|
+
// Worker template that cannot import that runtime) — keep the two in sync.
|
|
1633
|
+
if (wsUrl.pathname === '/_devflare/do-ws') {
|
|
1634
|
+
try {
|
|
1635
|
+
const bindingName = wsUrl.searchParams.get('binding')
|
|
1636
|
+
const idHex = wsUrl.searchParams.get('id')
|
|
1637
|
+
const targetUrl = wsUrl.searchParams.get('u') || request.url
|
|
1638
|
+
const doBinding = env[bindingName]
|
|
1639
|
+
if (!doBinding || typeof doBinding.idFromString !== 'function') {
|
|
1640
|
+
return new Response('Durable Object binding not found: ' + bindingName, { status: 500 })
|
|
1641
|
+
}
|
|
1642
|
+
if (!idHex) {
|
|
1643
|
+
return new Response('Missing Durable Object id', { status: 400 })
|
|
1644
|
+
}
|
|
1645
|
+
const stub = doBinding.get(doBinding.idFromString(idHex))
|
|
1646
|
+
return stub.fetch(new Request(targetUrl, { method: 'GET', headers: request.headers }))
|
|
1647
|
+
} catch (error) {
|
|
1648
|
+
return new Response('Error opening DO WebSocket: ' + (error?.message || String(error)), {
|
|
1649
|
+
status: 500
|
|
1650
|
+
})
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1620
1653
|
const { 0: client, 1: server } = new WebSocketPair()
|
|
1621
1654
|
server.accept()
|
|
1622
1655
|
server.addEventListener('message', async (e) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simple-context-gateway-script.d.ts","sourceRoot":"","sources":["../../src/test/simple-context-gateway-script.ts"],"names":[],"mappings":"AAEA,wBAAgB,kBAAkB,CACjC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,qBAAqB,GAAE,MAAM,EAAO,GAClC,MAAM,
|
|
1
|
+
{"version":3,"file":"simple-context-gateway-script.d.ts","sourceRoot":"","sources":["../../src/test/simple-context-gateway-script.ts"],"names":[],"mappings":"AAEA,wBAAgB,kBAAkB,CACjC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,qBAAqB,GAAE,MAAM,EAAO,GAClC,MAAM,CA2PR"}
|
package/dist/vite/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as devflarePlugin, c as getDevflareConfigs, i as writeGeneratedViteConfig, n as resolveEffectiveViteProject, o as getPluginContext, r as resolveViteUserConfig, s as getCloudflareConfig, t as hasInlineViteConfig } from "../_chunks/vite-
|
|
1
|
+
import { a as devflarePlugin, c as getDevflareConfigs, i as writeGeneratedViteConfig, n as resolveEffectiveViteProject, o as getPluginContext, r as resolveViteUserConfig, s as getCloudflareConfig, t as hasInlineViteConfig } from "../_chunks/vite-CzqppgNp.js";
|
|
2
2
|
export { devflarePlugin as default, devflarePlugin, getCloudflareConfig, getDevflareConfigs, getPluginContext, hasInlineViteConfig, resolveEffectiveViteProject, resolveViteUserConfig, writeGeneratedViteConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devflare",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.62",
|
|
4
4
|
"description": "Devflare is a developer-first toolkit for Cloudflare Workers that sits on top of Miniflare and Wrangler-compatible config",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"test:unit": "bun test tests/unit",
|
|
85
85
|
"test:coverage": "bun test tests/unit --coverage",
|
|
86
86
|
"test:integration:control": "bun test tests/integration/cli tests/integration/examples tests/integration/package-entry tests/integration/vite",
|
|
87
|
-
"test:integration:bridge": "bun test tests/integration/bridge/bridge-proxy.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/case18-do.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/durable-object.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/do-websocket.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/miniflare.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/r2-transfer.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/r2-presign.test.ts --parallel=1 --max-concurrency=1",
|
|
87
|
+
"test:integration:bridge": "bun test tests/integration/bridge/bridge-proxy.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/case18-do.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/durable-object.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/do-websocket.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/do-rpc-native.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/do-websocket-hibernation.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/do-websocket-hibernation-test-context.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/miniflare.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/r2-transfer.test.ts --parallel=1 --max-concurrency=1 && bun test tests/integration/bridge/r2-presign.test.ts --parallel=1 --max-concurrency=1",
|
|
88
88
|
"test:integration:test-context": "bun test tests/integration/test-context --parallel=1 --max-concurrency=1",
|
|
89
89
|
"test:integration:dev-server": "bun test tests/integration/dev-server --parallel=1 --max-concurrency=1",
|
|
90
90
|
"test:integration:shims": "bun test tests/integration/shims --parallel=1 --max-concurrency=1",
|