cindel 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -1572,15 +1572,15 @@ var FileLoader = class {
1572
1572
  fetch(url).then((r) => {
1573
1573
  if (!r.ok) throw new Error(`Failed to fetch CSS: ${path} (${r.status})`);
1574
1574
  return r.text();
1575
- }).then((code) => {
1576
- this._inject("css", code, path);
1577
- })
1575
+ }).then((code) => this._inject("css", code, path))
1578
1576
  );
1579
1577
  }
1580
1578
  if (toParent) {
1581
1579
  ops.push(this._loadCSSInParent(path, url));
1582
1580
  }
1583
- await Promise.all(ops);
1581
+ const results = await Promise.allSettled(ops);
1582
+ const failed = results.find((r) => r.status === "rejected");
1583
+ if (failed) throw failed.reason;
1584
1584
  return true;
1585
1585
  }
1586
1586
  _loadCSSInParent(path, url) {
@@ -1608,7 +1608,7 @@ var FileLoader = class {
1608
1608
  if (!r.ok) throw new Error(`Failed to fetch module: ${path} (${r.status})`);
1609
1609
  return r.text();
1610
1610
  });
1611
- this._inject("module", code, path);
1611
+ await this._inject("module", code, path);
1612
1612
  return true;
1613
1613
  }
1614
1614
  await import(url);
@@ -1623,7 +1623,7 @@ var FileLoader = class {
1623
1623
  if (!r.ok) throw new Error(`Failed to fetch script: ${path} (${r.status})`);
1624
1624
  return r.text();
1625
1625
  });
1626
- this._inject("script", code, path);
1626
+ await this._inject("script", code, path);
1627
1627
  return true;
1628
1628
  }
1629
1629
  const script = document.createElement("script");
@@ -1672,8 +1672,7 @@ var FileLoader = class {
1672
1672
  this.loadQueue.delete(path);
1673
1673
  }
1674
1674
  if (this.iframeTarget) {
1675
- this._post({ type: "hmr:remove", file: path });
1676
- await Promise.resolve();
1675
+ await this._postAndAwaitAck({ type: "hmr:remove", file: path });
1677
1676
  } else {
1678
1677
  const el = document.querySelector(`[data-file="${path}"]`);
1679
1678
  if (el) {
@@ -1689,13 +1688,27 @@ var FileLoader = class {
1689
1688
  this.versions.set(path, v);
1690
1689
  return `${this.httpUrl}${path}?v=${v}`;
1691
1690
  }
1692
- // Send a raw postMessage to the iframe target
1693
- _post(message) {
1694
- this.iframeTarget.postMessage(message, this.iframeOrigin);
1691
+ // Post a message and resolve once the stub sends back hmr:ack
1692
+ _postAndAwaitAck(message) {
1693
+ return new Promise((resolve) => {
1694
+ const onAck = (e) => {
1695
+ if (e.source !== this.iframeTarget) return;
1696
+ let data;
1697
+ try {
1698
+ data = JSON.parse(e.data);
1699
+ } catch {
1700
+ return;
1701
+ }
1702
+ if (data?.type !== "hmr:ack") return;
1703
+ window.removeEventListener("message", onAck);
1704
+ resolve();
1705
+ };
1706
+ window.addEventListener("message", onAck);
1707
+ this.iframeTarget.postMessage(JSON.stringify(message), this.iframeOrigin);
1708
+ });
1695
1709
  }
1696
- // Forward a file payload to the iframe target
1697
1710
  _inject(kind, code, file) {
1698
- this._post({ type: "hmr:inject", kind, code, file });
1711
+ return this._postAndAwaitAck({ type: "hmr:inject", kind, code, file });
1699
1712
  }
1700
1713
  };
1701
1714
 
@@ -2199,15 +2212,22 @@ var HMRClient = class {
2199
2212
  this._processingMessages = false;
2200
2213
  }
2201
2214
  // Wait for stub's hmr:ready signal. Stub fires it proactively on run.
2202
- // Times out after 5s if stub was never injected.
2215
+ // Times out after 5s and resolves anyway, a missing stub degrades gracefully.
2203
2216
  _waitForStub() {
2204
- return new Promise((resolve, reject) => {
2217
+ return new Promise((resolve) => {
2205
2218
  const timer = setTimeout(() => {
2206
2219
  window.removeEventListener("message", onReady);
2207
- reject(new Error("Timed out waiting for hmr:ready. Was HMR.stub() called in the iframe?"));
2220
+ this.log("warning", "Timed out waiting for hmr:ready. Was HMR.stub() called in the iframe?");
2221
+ resolve();
2208
2222
  }, 5e3);
2209
2223
  const onReady = (e) => {
2210
- if (e.data?.type !== "hmr:ready") return;
2224
+ let data;
2225
+ try {
2226
+ data = JSON.parse(e.data);
2227
+ } catch {
2228
+ return;
2229
+ }
2230
+ if (data?.type !== "hmr:ready") return;
2211
2231
  const originOk = this._iframeOrigin === "*" || e.origin === this._iframeOrigin;
2212
2232
  if (!originOk) return;
2213
2233
  clearTimeout(timer);
@@ -2227,15 +2247,25 @@ var HMRClient = class {
2227
2247
  _listenForReattach() {
2228
2248
  if (this._onReattach) return;
2229
2249
  this._onReattach = async (e) => {
2230
- if (e.data?.type !== "hmr:ready") return;
2250
+ let data;
2251
+ try {
2252
+ data = JSON.parse(e.data);
2253
+ } catch {
2254
+ return;
2255
+ }
2256
+ if (data?.type !== "hmr:ready") return;
2231
2257
  const originOk = this._iframeOrigin === "*" || e.origin === this._iframeOrigin;
2232
2258
  if (!originOk) return;
2233
2259
  if (e.source === this._iframeTarget) return;
2234
2260
  this._iframeTarget = e.source;
2235
2261
  this.fileLoader.iframeTarget = e.source;
2236
2262
  this.log("success", "HMR reattached to new iframe");
2237
- for (const path of this.fileLoader.versions.keys()) {
2238
- await this.fileLoader.loadFile(path);
2263
+ for (const path of this.sortFiles([...this.fileLoader.versions.keys()])) {
2264
+ try {
2265
+ await this.fileLoader.loadFile(path);
2266
+ } catch (e2) {
2267
+ this.log("error", `Reattach failed to load ${path}: ${e2.message}`);
2268
+ }
2239
2269
  }
2240
2270
  };
2241
2271
  window.addEventListener("message", this._onReattach);
@@ -2271,15 +2301,8 @@ var HMRClient = class {
2271
2301
  this._messageQueue = [];
2272
2302
  this._processingMessages = true;
2273
2303
  if (this._iframeTarget || this._stubManaged) {
2274
- try {
2275
- await this._waitForStub();
2276
- if (this._stubManaged) this._listenForReattach();
2277
- } catch (e) {
2278
- this.log("error", e.message);
2279
- this._processingMessages = false;
2280
- reject(e);
2281
- return;
2282
- }
2304
+ await this._waitForStub();
2305
+ if (this._stubManaged) this._listenForReattach();
2283
2306
  }
2284
2307
  this._processingMessages = false;
2285
2308
  if (this._messageQueue.length > 0) this._drainMessageQueue();
@@ -2355,36 +2378,72 @@ function stub() {
2355
2378
  const removeIfExists = (el) => {
2356
2379
  if (el) el.remove();
2357
2380
  };
2358
- const injectScript = (kind, code, file) => {
2359
- removeIfExists(byFile("script", file));
2360
- const script = document.createElement("script");
2361
- if (kind === "module") script.type = "module";
2362
- script.textContent = code;
2363
- script.dataset.file = file;
2364
- document.documentElement.appendChild(script);
2365
- script.remove();
2381
+ const injectScript = async (kind, code, file) => {
2382
+ const url = URL.createObjectURL(new Blob([code + `
2383
+ //# sourceURL=${file}`], { type: "text/javascript" }));
2384
+ try {
2385
+ if (kind === "module") {
2386
+ await import(url);
2387
+ } else {
2388
+ const script = document.createElement("script");
2389
+ script.src = url;
2390
+ await new Promise((resolve, reject) => {
2391
+ script.onload = resolve;
2392
+ script.onerror = () => reject(new Error(`Failed to execute script: ${file}`));
2393
+ document.documentElement.appendChild(script);
2394
+ });
2395
+ }
2396
+ } finally {
2397
+ URL.revokeObjectURL(url);
2398
+ }
2366
2399
  };
2367
- const injectStyle = (code, file) => {
2368
- const existing = byFile("style", file);
2369
- const style = document.createElement("style");
2370
- style.textContent = code;
2371
- style.dataset.file = file;
2372
- document.head.appendChild(style);
2400
+ const injectStyle = async (code, file) => {
2401
+ const existing = byFile("link", file);
2402
+ const url = URL.createObjectURL(new Blob([code + `
2403
+ /*# sourceURL=${file} */`], { type: "text/css" }));
2404
+ const link = document.createElement("link");
2405
+ link.rel = "stylesheet";
2406
+ link.href = url;
2407
+ link.dataset.file = file;
2408
+ await new Promise((resolve, reject) => {
2409
+ link.onload = () => {
2410
+ URL.revokeObjectURL(url);
2411
+ resolve();
2412
+ };
2413
+ link.onerror = () => {
2414
+ URL.revokeObjectURL(url);
2415
+ reject(new Error(`Failed to load CSS: ${file}`));
2416
+ };
2417
+ document.head.appendChild(link);
2418
+ });
2373
2419
  removeIfExists(existing);
2374
2420
  };
2375
- window.addEventListener("message", (e) => {
2376
- const data = e.data;
2421
+ window.addEventListener("message", async (e) => {
2422
+ let data;
2423
+ try {
2424
+ data = JSON.parse(e.data);
2425
+ } catch {
2426
+ return;
2427
+ }
2377
2428
  if (!data?.type) return;
2429
+ const ackOrigin = e.origin && e.origin !== "null" ? e.origin : "*";
2430
+ const ack = () => e.source?.postMessage(JSON.stringify({ type: "hmr:ack" }), ackOrigin);
2378
2431
  if (data.type === "hmr:remove") {
2379
2432
  removeIfExists(document.querySelector(`[data-file="${CSS.escape(data.file)}"]`));
2433
+ ack();
2380
2434
  return;
2381
2435
  }
2382
2436
  if (data.type !== "hmr:inject") return;
2383
2437
  const { kind, code, file } = data;
2384
- if (kind === "script" || kind === "module") injectScript(kind, code, file);
2385
- else if (kind === "css") injectStyle(code, file);
2438
+ try {
2439
+ if (kind === "script" || kind === "module") await injectScript(kind, code, file);
2440
+ else if (kind === "css") await injectStyle(code, file);
2441
+ } catch (err) {
2442
+ console.error(`Failed to inject ${file}:`, err.message ?? err, "\n" + err.stack);
2443
+ }
2444
+ ack();
2386
2445
  });
2387
- window.parent.postMessage({ type: "hmr:ready" }, "*");
2446
+ window.parent.postMessage(JSON.stringify({ type: "hmr:ready" }), "*");
2388
2447
  }
2389
2448
  export {
2390
2449
  HMRClient,