devflare 1.0.0-next.67 → 1.0.0-next.68

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.
@@ -88,6 +88,45 @@ function createDevExecutionContext(pendingErrors) {
88
88
  };
89
89
  }
90
90
  /**
91
+ * Total budget for riding out a transient bridge outage while (re)connecting for a request. An HMR worker
92
+ * reload or a brief coordinator restart drops the bridge socket for well under a second; retrying within this
93
+ * window keeps the request's bindings available instead of failing it. Kept modest so a bridge that is
94
+ * genuinely down (devflare not running) still surfaces the error promptly rather than hanging every request.
95
+ */
96
+ const BRIDGE_CONNECT_MAX_WAIT_MS = 3e3;
97
+ /** Delay between bridge (re)connect attempts within {@link BRIDGE_CONNECT_MAX_WAIT_MS}. */
98
+ const BRIDGE_CONNECT_RETRY_DELAY_MS = 150;
99
+ /**
100
+ * Connect to the bridge, riding out a TRANSIENT outage with a bounded retry.
101
+ *
102
+ * The bridge socket drops for a fraction of a second whenever the dev runtime reloads a worker (HMR /
103
+ * config change) or the coordinator briefly restarts (e.g. after a worker threw). A single per-request
104
+ * `connect()` attempt rejects the instant the socket is refused, which the SvelteKit handle turns into
105
+ * "dropped every binding for this request" — so an unrelated route 500s with a missing D1/KV/R2 binding
106
+ * mid-reload. Retrying for a short window instead lets the reconnect land and the request proceed. The LAST
107
+ * error is rethrown only once the budget is spent (the bridge really is down), so a genuine
108
+ * misconfiguration still fails fast rather than hanging.
109
+ *
110
+ * Exported for unit testing; `sleep`/`now` are injectable so the retry schedule is asserted without real time.
111
+ *
112
+ * @param connect - the bridge client's `connect()`; a fresh attempt each call (the client dedups in-flight ones).
113
+ * @param options - `maxWaitMs` total budget, `retryDelayMs` between attempts, and injectable `sleep`/`now` for tests.
114
+ */
115
+ async function connectBridgeWithRetry(connect, options = {}) {
116
+ const maxWaitMs = options.maxWaitMs ?? BRIDGE_CONNECT_MAX_WAIT_MS;
117
+ const retryDelayMs = options.retryDelayMs ?? BRIDGE_CONNECT_RETRY_DELAY_MS;
118
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
119
+ const now = options.now ?? Date.now;
120
+ const deadline = now() + maxWaitMs;
121
+ for (;;) try {
122
+ await connect();
123
+ return;
124
+ } catch (error) {
125
+ if (now() + retryDelayMs >= deadline) throw error;
126
+ await sleep(retryDelayMs);
127
+ }
128
+ }
129
+ /**
91
130
  * Create a platform object that routes bindings through the bridge
92
131
  *
93
132
  * Use this in dev mode to get access to Miniflare bindings via WebSocket RPC.
@@ -119,7 +158,7 @@ async function createDevflarePlatform(options = {}) {
119
158
  const cacheKey = getPlatformCacheKey(bridgeUrl, hints);
120
159
  if (shouldUseCachedPlatform(localBindings) && platformCache?.key === cacheKey) return platformCache.platform;
121
160
  const client = getClient({ url: bridgeUrl });
122
- await client.connect();
161
+ await connectBridgeWithRetry(() => client.connect());
123
162
  const env = overlayLocalBindings(createEnvProxy({
124
163
  client,
125
164
  hints,
@@ -36,6 +36,28 @@ export interface DevflarePlatformOptions {
36
36
  * Returns a snapshot of the pending errors and clears the buffer.
37
37
  */
38
38
  export declare function drainWaitUntilErrors(platform: Platform): unknown[];
39
+ /**
40
+ * Connect to the bridge, riding out a TRANSIENT outage with a bounded retry.
41
+ *
42
+ * The bridge socket drops for a fraction of a second whenever the dev runtime reloads a worker (HMR /
43
+ * config change) or the coordinator briefly restarts (e.g. after a worker threw). A single per-request
44
+ * `connect()` attempt rejects the instant the socket is refused, which the SvelteKit handle turns into
45
+ * "dropped every binding for this request" — so an unrelated route 500s with a missing D1/KV/R2 binding
46
+ * mid-reload. Retrying for a short window instead lets the reconnect land and the request proceed. The LAST
47
+ * error is rethrown only once the budget is spent (the bridge really is down), so a genuine
48
+ * misconfiguration still fails fast rather than hanging.
49
+ *
50
+ * Exported for unit testing; `sleep`/`now` are injectable so the retry schedule is asserted without real time.
51
+ *
52
+ * @param connect - the bridge client's `connect()`; a fresh attempt each call (the client dedups in-flight ones).
53
+ * @param options - `maxWaitMs` total budget, `retryDelayMs` between attempts, and injectable `sleep`/`now` for tests.
54
+ */
55
+ export declare function connectBridgeWithRetry(connect: () => Promise<void>, options?: {
56
+ maxWaitMs?: number;
57
+ retryDelayMs?: number;
58
+ sleep?: (ms: number) => Promise<void>;
59
+ now?: () => number;
60
+ }): Promise<void>;
39
61
  /**
40
62
  * Create a platform object that routes bindings through the bridge
41
63
  *
@@ -1 +1 @@
1
- {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/sveltekit/platform.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,YAAY,EAA8C,MAAM,WAAW,CAAA;AAUzF;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5B,OAAO,EAAE,gBAAgB,CAAA;IACzB,MAAM,EAAE,YAAY,CAAA;IACpB,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,uBAAuB;IACvC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAA;IAEpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACvC;AAkDD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,EAAE,CAQlE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,QAAQ,CAAC,CAqDnB;AA4BD;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAgGD;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IACnE;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,OAAO,CAAA;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAC3B,CAAC,SAAS;IACT,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;IAChD,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACzD,EACA,OAAO,GAAE,mBAAwB,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAwBpE;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,MAAM,GAClB,CAAC,SAAS;IACT,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;IAChD,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACzD,SAEM,CAAC,KACN,OAAO,CAAC,QAAQ,CAgBlB,CAAA"}
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/sveltekit/platform.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,YAAY,EAA8C,MAAM,WAAW,CAAA;AAUzF;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5B,OAAO,EAAE,gBAAgB,CAAA;IACzB,MAAM,EAAE,YAAY,CAAA;IACpB,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,uBAAuB;IACvC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAA;IAEpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACvC;AAkDD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,EAAE,CAQlE;AAYD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC5B,OAAO,GAAE;IACR,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACb,GACJ,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,QAAQ,CAAC,CAsDnB;AA4BD;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAgGD;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IACnE;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,OAAO,CAAA;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAC3B,CAAC,SAAS;IACT,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;IAChD,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACzD,EACA,OAAO,GAAE,mBAAwB,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAwBpE;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,MAAM,GAClB,CAAC,SAAS;IACT,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;IAChD,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACzD,SAEM,CAAC,KACN,OAAO,CAAC,QAAQ,CAgBlB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devflare",
3
- "version": "1.0.0-next.67",
3
+ "version": "1.0.0-next.68",
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",