sibujs 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/README.md +105 -119
  2. package/dist/browser.cjs +288 -80
  3. package/dist/browser.d.cts +19 -9
  4. package/dist/browser.d.ts +19 -9
  5. package/dist/browser.js +6 -6
  6. package/dist/build.cjs +1019 -313
  7. package/dist/build.d.cts +1 -1
  8. package/dist/build.d.ts +1 -1
  9. package/dist/build.js +15 -13
  10. package/dist/cdn.global.js +17 -16
  11. package/dist/chunk-2RA7SHDA.js +65 -0
  12. package/dist/chunk-2UPRY23K.js +80 -0
  13. package/dist/chunk-3JHCYHWN.js +125 -0
  14. package/dist/{chunk-ZWKZCBO6.js → chunk-3LR7GLWQ.js} +154 -33
  15. package/dist/{chunk-3AIRKM3B.js → chunk-3NSGB5JN.js} +115 -34
  16. package/dist/{chunk-3ARAQO7B.js → chunk-52YJLLRO.js} +29 -6
  17. package/dist/chunk-54EDRCEF.js +93 -0
  18. package/dist/chunk-7JDB7I65.js +1327 -0
  19. package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
  20. package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
  21. package/dist/{chunk-WR5D4EGH.js → chunk-GTBNNBJ6.js} +14 -2
  22. package/dist/chunk-HB24TBAF.js +121 -0
  23. package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
  24. package/dist/{chunk-JAKHTMQU.js → chunk-JA6667UN.js} +206 -46
  25. package/dist/{chunk-77L6NL3X.js → chunk-JXMMDLBY.js} +306 -183
  26. package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
  27. package/dist/{chunk-F3FA4F32.js → chunk-KLRMB5ZS.js} +135 -79
  28. package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
  29. package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
  30. package/dist/{chunk-TSOKIX5Z.js → chunk-MIUAXB7K.js} +126 -74
  31. package/dist/{chunk-QWZG56ET.js → chunk-ND2664SF.js} +558 -190
  32. package/dist/{chunk-JCI5M6U6.js → chunk-O2MNQFLP.js} +261 -79
  33. package/dist/{chunk-EWFVA3TJ.js → chunk-R73P76YZ.js} +1 -1
  34. package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
  35. package/dist/chunk-UCS6AMJ7.js +79 -0
  36. package/dist/{chunk-ZD6OAMTH.js → chunk-VLPPXTYG.js} +90 -35
  37. package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
  38. package/dist/{contracts-xo5ckdRP.d.cts → contracts-ey_Qh8ef.d.cts} +7 -8
  39. package/dist/{contracts-xo5ckdRP.d.ts → contracts-ey_Qh8ef.d.ts} +7 -8
  40. package/dist/{customElement-D2DJp_xn.d.cts → customElement-CPfIrbvg.d.cts} +18 -9
  41. package/dist/{customElement-D2DJp_xn.d.ts → customElement-CPfIrbvg.d.ts} +18 -9
  42. package/dist/data.cjs +452 -100
  43. package/dist/data.d.cts +20 -2
  44. package/dist/data.d.ts +20 -2
  45. package/dist/data.js +11 -9
  46. package/dist/devtools.cjs +535 -247
  47. package/dist/devtools.d.cts +1 -1
  48. package/dist/devtools.d.ts +1 -1
  49. package/dist/devtools.js +34 -30
  50. package/dist/ecosystem.cjs +499 -143
  51. package/dist/ecosystem.d.cts +13 -11
  52. package/dist/ecosystem.d.ts +13 -11
  53. package/dist/ecosystem.js +12 -11
  54. package/dist/extras.cjs +3639 -1629
  55. package/dist/extras.d.cts +11 -11
  56. package/dist/extras.d.ts +11 -11
  57. package/dist/extras.js +58 -45
  58. package/dist/index.cjs +1023 -313
  59. package/dist/index.d.cts +128 -55
  60. package/dist/index.d.ts +128 -55
  61. package/dist/index.js +28 -16
  62. package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
  63. package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
  64. package/dist/motion.cjs +90 -36
  65. package/dist/motion.d.cts +1 -1
  66. package/dist/motion.d.ts +1 -1
  67. package/dist/motion.js +4 -4
  68. package/dist/patterns.cjs +414 -81
  69. package/dist/patterns.d.cts +53 -20
  70. package/dist/patterns.d.ts +53 -20
  71. package/dist/patterns.js +7 -7
  72. package/dist/performance.cjs +364 -108
  73. package/dist/performance.d.cts +29 -17
  74. package/dist/performance.d.ts +29 -17
  75. package/dist/performance.js +13 -6
  76. package/dist/plugin-D30wlGW5.d.cts +71 -0
  77. package/dist/plugin-D30wlGW5.d.ts +71 -0
  78. package/dist/plugins.cjs +652 -271
  79. package/dist/plugins.d.cts +13 -6
  80. package/dist/plugins.d.ts +13 -6
  81. package/dist/plugins.js +116 -50
  82. package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
  83. package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
  84. package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
  85. package/dist/ssr.cjs +648 -219
  86. package/dist/ssr.d.cts +27 -7
  87. package/dist/ssr.d.ts +27 -7
  88. package/dist/ssr.js +12 -11
  89. package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.cts} +9 -1
  90. package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.ts} +9 -1
  91. package/dist/testing.cjs +252 -63
  92. package/dist/testing.d.cts +17 -4
  93. package/dist/testing.d.ts +17 -4
  94. package/dist/testing.js +100 -44
  95. package/dist/ui.cjs +576 -168
  96. package/dist/ui.d.cts +13 -16
  97. package/dist/ui.d.ts +13 -16
  98. package/dist/ui.js +20 -17
  99. package/dist/widgets.cjs +1001 -93
  100. package/dist/widgets.d.cts +104 -2
  101. package/dist/widgets.d.ts +104 -2
  102. package/dist/widgets.js +9 -7
  103. package/package.json +8 -2
  104. package/dist/chunk-32DY64NT.js +0 -282
  105. package/dist/chunk-3CRQALYP.js +0 -877
  106. package/dist/chunk-4EI4AG32.js +0 -482
  107. package/dist/chunk-4MYMUBRS.js +0 -21
  108. package/dist/chunk-6HLLIF3K.js +0 -398
  109. package/dist/chunk-6LSNVCS2.js +0 -937
  110. package/dist/chunk-6SA3QQES.js +0 -61
  111. package/dist/chunk-7BF6TK55.js +0 -1097
  112. package/dist/chunk-7TQKR4PP.js +0 -294
  113. package/dist/chunk-7V26P53V.js +0 -712
  114. package/dist/chunk-AZ3ISID5.js +0 -298
  115. package/dist/chunk-B7SWRFUT.js +0 -332
  116. package/dist/chunk-BGN5ZMP4.js +0 -26
  117. package/dist/chunk-BTU3TJDS.js +0 -365
  118. package/dist/chunk-BW3WT46K.js +0 -937
  119. package/dist/chunk-C6KFWOFV.js +0 -616
  120. package/dist/chunk-CHF5OHIA.js +0 -61
  121. package/dist/chunk-CHJ27IGK.js +0 -26
  122. package/dist/chunk-CMBFNA7L.js +0 -27
  123. package/dist/chunk-DAHRH4ON.js +0 -331
  124. package/dist/chunk-DKOHBI74.js +0 -924
  125. package/dist/chunk-DTCOOBMX.js +0 -725
  126. package/dist/chunk-EBGIRKQY.js +0 -616
  127. package/dist/chunk-EUZND3CB.js +0 -27
  128. package/dist/chunk-EVCZO745.js +0 -365
  129. package/dist/chunk-FGOEVHY3.js +0 -60
  130. package/dist/chunk-G3BOQPVO.js +0 -365
  131. package/dist/chunk-GCOK2LC3.js +0 -282
  132. package/dist/chunk-HGMJFBC7.js +0 -654
  133. package/dist/chunk-K5ZUMYVS.js +0 -89
  134. package/dist/chunk-KQPDEVVS.js +0 -398
  135. package/dist/chunk-L6JRBDNS.js +0 -60
  136. package/dist/chunk-LA6KQEDU.js +0 -712
  137. package/dist/chunk-MDVXJWFN.js +0 -304
  138. package/dist/chunk-MEZVEBPN.js +0 -2008
  139. package/dist/chunk-MK4ERFYL.js +0 -2249
  140. package/dist/chunk-MLKGABMK.js +0 -9
  141. package/dist/chunk-MQ5GOYPH.js +0 -2249
  142. package/dist/chunk-N6IZB6KJ.js +0 -567
  143. package/dist/chunk-NEKUBFPT.js +0 -60
  144. package/dist/chunk-NHUC2QWH.js +0 -282
  145. package/dist/chunk-NMRUZALC.js +0 -1097
  146. package/dist/chunk-NYVAC6P5.js +0 -37
  147. package/dist/chunk-OF7UZIVB.js +0 -725
  148. package/dist/chunk-P6W3STU4.js +0 -2249
  149. package/dist/chunk-PBHF5WKN.js +0 -616
  150. package/dist/chunk-PTQJDMRT.js +0 -146
  151. package/dist/chunk-PZEGYCF5.js +0 -61
  152. package/dist/chunk-QBMDLBU2.js +0 -975
  153. package/dist/chunk-RQGQSLQK.js +0 -725
  154. package/dist/chunk-SDLZDHKP.js +0 -107
  155. package/dist/chunk-TNQWPPE6.js +0 -37
  156. package/dist/chunk-UHNL42EF.js +0 -2730
  157. package/dist/chunk-UNXCEF6S.js +0 -21
  158. package/dist/chunk-V2XTI523.js +0 -347
  159. package/dist/chunk-VAU366PN.js +0 -2241
  160. package/dist/chunk-VMVDTCXB.js +0 -712
  161. package/dist/chunk-VRW3FULF.js +0 -725
  162. package/dist/chunk-WADYRCO2.js +0 -304
  163. package/dist/chunk-WILQZRO4.js +0 -282
  164. package/dist/chunk-WUHJISPP.js +0 -298
  165. package/dist/chunk-XYU6TZOW.js +0 -182
  166. package/dist/chunk-Y6GP4QGG.js +0 -276
  167. package/dist/chunk-YECR7UIA.js +0 -347
  168. package/dist/chunk-YUTWTI4B.js +0 -654
  169. package/dist/chunk-Z65KYU7I.js +0 -26
  170. package/dist/chunk-Z6POF5YC.js +0 -975
  171. package/dist/chunk-ZBJP6WFL.js +0 -482
  172. package/dist/contracts-DDrwxvJ-.d.cts +0 -245
  173. package/dist/contracts-DDrwxvJ-.d.ts +0 -245
  174. package/dist/contracts-DOrhwbke.d.cts +0 -245
  175. package/dist/contracts-DOrhwbke.d.ts +0 -245
  176. package/dist/customElement-BKQfbSZQ.d.cts +0 -262
  177. package/dist/customElement-BKQfbSZQ.d.ts +0 -262
  178. package/dist/customElement-yz8uyk-0.d.cts +0 -308
  179. package/dist/customElement-yz8uyk-0.d.ts +0 -308
  180. package/dist/introspect-Cb0zgpi2.d.cts +0 -477
  181. package/dist/introspect-Y2xNXGSf.d.ts +0 -477
  182. package/dist/plugin-Bek4RhJY.d.cts +0 -43
  183. package/dist/plugin-Bek4RhJY.d.ts +0 -43
  184. package/dist/ssr-3RXHP5ES.js +0 -38
  185. package/dist/ssr-6GIMY5MX.js +0 -38
  186. package/dist/ssr-BA6sxxUd.d.cts +0 -135
  187. package/dist/ssr-BA6sxxUd.d.ts +0 -135
  188. package/dist/ssr-WKUPVSSK.js +0 -36
  189. package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
  190. package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  div,
3
3
  span
4
- } from "./chunk-32DY64NT.js";
4
+ } from "./chunk-R73P76YZ.js";
5
5
  import {
6
6
  sanitizeUrl
7
- } from "./chunk-CMBFNA7L.js";
7
+ } from "./chunk-UCS6AMJ7.js";
8
8
  import {
9
9
  effect
10
- } from "./chunk-CHF5OHIA.js";
10
+ } from "./chunk-HB24TBAF.js";
11
11
  import {
12
12
  batch,
13
13
  signal
14
- } from "./chunk-WZSPOOER.js";
14
+ } from "./chunk-CC65Y57T.js";
15
15
 
16
16
  // src/platform/head.ts
17
17
  var HEAD_URL_ATTRS = /* @__PURE__ */ new Set(["href", "src"]);
@@ -148,24 +148,37 @@ function worker(workerFn2) {
148
148
  const [error, setError] = signal(null);
149
149
  const [loading, setLoading] = signal(false);
150
150
  let worker2 = null;
151
+ let blobUrl = null;
152
+ const revokeBlobUrl = () => {
153
+ if (blobUrl) {
154
+ URL.revokeObjectURL(blobUrl);
155
+ blobUrl = null;
156
+ }
157
+ };
151
158
  try {
152
159
  if (typeof Worker === "undefined") {
153
160
  throw new Error("Web Workers are not supported in this environment");
154
161
  }
155
162
  const fnBody = workerFn2.toString();
156
163
  const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
157
- const url = URL.createObjectURL(blob);
158
- worker2 = new Worker(url);
159
- URL.revokeObjectURL(url);
160
- worker2.onmessage = (e) => {
164
+ blobUrl = URL.createObjectURL(blob);
165
+ worker2 = new Worker(blobUrl);
166
+ worker2.addEventListener("message", (e) => {
167
+ revokeBlobUrl();
161
168
  setResult(e.data);
162
169
  setLoading(false);
163
- };
164
- worker2.onerror = (e) => {
170
+ });
171
+ worker2.addEventListener("error", (e) => {
172
+ revokeBlobUrl();
165
173
  setError(new Error(e.message || "Worker error"));
166
174
  setLoading(false);
167
- };
175
+ if (worker2) {
176
+ worker2.terminate();
177
+ worker2 = null;
178
+ }
179
+ });
168
180
  } catch (err) {
181
+ revokeBlobUrl();
169
182
  setError(err instanceof Error ? err : new Error(String(err)));
170
183
  }
171
184
  function post(data) {
@@ -179,6 +192,7 @@ function worker(workerFn2) {
179
192
  if (!worker2) return;
180
193
  worker2.terminate();
181
194
  worker2 = null;
195
+ revokeBlobUrl();
182
196
  setLoading(false);
183
197
  }
184
198
  return { post, result, error, loading, terminate };
@@ -186,6 +200,14 @@ function worker(workerFn2) {
186
200
  function workerFn(fn) {
187
201
  const [loading, setLoading] = signal(false);
188
202
  let worker2 = null;
203
+ let blobUrl = null;
204
+ const revokeBlobUrl = () => {
205
+ if (blobUrl) {
206
+ URL.revokeObjectURL(blobUrl);
207
+ blobUrl = null;
208
+ }
209
+ };
210
+ const queue = [];
189
211
  try {
190
212
  if (typeof Worker === "undefined") {
191
213
  throw new Error("Web Workers are not supported in this environment");
@@ -201,10 +223,26 @@ function workerFn(fn) {
201
223
  ],
202
224
  { type: "application/javascript" }
203
225
  );
204
- const url = URL.createObjectURL(blob);
205
- worker2 = new Worker(url);
206
- URL.revokeObjectURL(url);
226
+ blobUrl = URL.createObjectURL(blob);
227
+ worker2 = new Worker(blobUrl);
228
+ worker2.addEventListener("message", (e) => {
229
+ revokeBlobUrl();
230
+ const head = queue.shift();
231
+ if (queue.length === 0) setLoading(false);
232
+ if (head) head.resolve(e.data);
233
+ });
234
+ worker2.addEventListener("error", (e) => {
235
+ revokeBlobUrl();
236
+ const err = new Error(e.message || "Worker error");
237
+ while (queue.length > 0) queue.shift().reject(err);
238
+ setLoading(false);
239
+ if (worker2) {
240
+ worker2.terminate();
241
+ worker2 = null;
242
+ }
243
+ });
207
244
  } catch {
245
+ revokeBlobUrl();
208
246
  }
209
247
  function run(...args) {
210
248
  return new Promise((resolve, reject) => {
@@ -213,14 +251,7 @@ function workerFn(fn) {
213
251
  return;
214
252
  }
215
253
  setLoading(true);
216
- worker2.onmessage = (e) => {
217
- setLoading(false);
218
- resolve(e.data);
219
- };
220
- worker2.onerror = (e) => {
221
- setLoading(false);
222
- reject(new Error(e.message || "Worker error"));
223
- };
254
+ queue.push({ resolve, reject });
224
255
  worker2.postMessage(args);
225
256
  });
226
257
  }
@@ -228,6 +259,9 @@ function workerFn(fn) {
228
259
  if (!worker2) return;
229
260
  worker2.terminate();
230
261
  worker2 = null;
262
+ const err = new Error("Worker terminated");
263
+ while (queue.length > 0) queue.shift().reject(err);
264
+ revokeBlobUrl();
231
265
  setLoading(false);
232
266
  }
233
267
  return { run, loading, terminate };
@@ -235,20 +269,63 @@ function workerFn(fn) {
235
269
  function createWorkerPool(workerFn2, poolSize) {
236
270
  const size = poolSize || typeof navigator !== "undefined" && navigator.hardwareConcurrency || 4;
237
271
  const workers = [];
272
+ const queues = [];
273
+ const inflight = [];
238
274
  let currentIndex = 0;
239
275
  let alive = true;
276
+ let blobUrl = null;
277
+ let firedOnce = false;
278
+ const revokeBlobUrl = () => {
279
+ if (blobUrl) {
280
+ URL.revokeObjectURL(blobUrl);
281
+ blobUrl = null;
282
+ }
283
+ };
284
+ function dispatchNext(idx) {
285
+ if (!alive || inflight[idx] || queues[idx].length === 0) return;
286
+ const w = workers[idx];
287
+ const slot = queues[idx].shift();
288
+ const onMsg = (e) => {
289
+ if (!firedOnce) {
290
+ firedOnce = true;
291
+ revokeBlobUrl();
292
+ }
293
+ w.removeEventListener("message", onMsg);
294
+ w.removeEventListener("error", onErr);
295
+ inflight[idx] = null;
296
+ slot.resolve(e.data);
297
+ dispatchNext(idx);
298
+ };
299
+ const onErr = (e) => {
300
+ if (!firedOnce) {
301
+ firedOnce = true;
302
+ revokeBlobUrl();
303
+ }
304
+ w.removeEventListener("message", onMsg);
305
+ w.removeEventListener("error", onErr);
306
+ inflight[idx] = null;
307
+ slot.reject(new Error(e.message || "Worker error"));
308
+ dispatchNext(idx);
309
+ };
310
+ inflight[idx] = { ...slot, onMsg, onErr };
311
+ w.addEventListener("message", onMsg);
312
+ w.addEventListener("error", onErr);
313
+ w.postMessage(slot.data);
314
+ }
240
315
  try {
241
316
  if (typeof Worker === "undefined") {
242
317
  throw new Error("Web Workers are not supported in this environment");
243
318
  }
244
319
  const fnBody = workerFn2.toString();
245
320
  const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
246
- const url = URL.createObjectURL(blob);
321
+ blobUrl = URL.createObjectURL(blob);
247
322
  for (let i = 0; i < size; i++) {
248
- workers.push(new Worker(url));
323
+ workers.push(new Worker(blobUrl));
324
+ queues.push([]);
325
+ inflight.push(null);
249
326
  }
250
- URL.revokeObjectURL(url);
251
327
  } catch {
328
+ revokeBlobUrl();
252
329
  }
253
330
  function execute(data) {
254
331
  return new Promise((resolve, reject) => {
@@ -256,23 +333,25 @@ function createWorkerPool(workerFn2, poolSize) {
256
333
  reject(new Error("Worker pool is not available"));
257
334
  return;
258
335
  }
259
- const worker2 = workers[currentIndex % workers.length];
336
+ const idx = currentIndex % workers.length;
260
337
  currentIndex++;
261
- worker2.onmessage = (e) => {
262
- resolve(e.data);
263
- };
264
- worker2.onerror = (e) => {
265
- reject(new Error(e.message || "Worker error"));
266
- };
267
- worker2.postMessage(data);
338
+ queues[idx].push({ data, resolve, reject });
339
+ dispatchNext(idx);
268
340
  });
269
341
  }
270
342
  function terminate() {
271
343
  alive = false;
272
- for (const w of workers) {
273
- w.terminate();
344
+ for (const w of workers) w.terminate();
345
+ const err = new Error("Worker pool terminated");
346
+ for (let i = 0; i < queues.length; i++) {
347
+ const inf = inflight[i];
348
+ if (inf) inf.reject(err);
349
+ for (const s of queues[i]) s.reject(err);
350
+ queues[i] = [];
351
+ inflight[i] = null;
274
352
  }
275
353
  workers.length = 0;
354
+ revokeBlobUrl();
276
355
  }
277
356
  return { execute, terminate };
278
357
  }
@@ -308,7 +387,28 @@ function wasm(source, config = {}) {
308
387
  };
309
388
  }
310
389
  async function loadWasmModule(source, imports, cacheKey) {
311
- const key = cacheKey || (typeof source === "string" ? source : void 0);
390
+ const isOptionsBag = !!(imports && ("allowedOrigins" in imports || "unsafelyAllowAnyOrigin" in imports));
391
+ const opts = isOptionsBag ? imports : { imports, cacheKey };
392
+ const wasmImports = opts.imports;
393
+ const key = opts.cacheKey || (typeof source === "string" ? source : void 0);
394
+ if (typeof source === "string") {
395
+ const allowed = opts.allowedOrigins ?? [];
396
+ if (allowed.length > 0) {
397
+ let parsed;
398
+ try {
399
+ parsed = new URL(source, typeof location !== "undefined" ? location.href : void 0);
400
+ } catch {
401
+ throw new Error(`loadWasmModule: invalid URL "${source}"`);
402
+ }
403
+ if (!allowed.includes(parsed.origin)) {
404
+ throw new Error(`loadWasmModule: origin "${parsed.origin}" is not in the allowlist`);
405
+ }
406
+ } else if (!opts.unsafelyAllowAnyOrigin) {
407
+ throw new Error(
408
+ `loadWasmModule: refused to fetch "${source}" with no allowedOrigins. Pass { allowedOrigins: [...] } to restrict the origin, or { unsafelyAllowAnyOrigin: true } to opt in (CWE-829).`
409
+ );
410
+ }
411
+ }
312
412
  if (key) {
313
413
  const cachedInstance = instanceCache.get(key);
314
414
  if (cachedInstance) {
@@ -324,7 +424,7 @@ async function loadWasmModule(source, imports, cacheKey) {
324
424
  if (typeof source === "string") {
325
425
  if (typeof WebAssembly.instantiateStreaming === "function") {
326
426
  const response2 = fetch(source);
327
- const result = await WebAssembly.instantiateStreaming(response2, imports || {});
427
+ const result = await WebAssembly.instantiateStreaming(response2, wasmImports || {});
328
428
  if (key) {
329
429
  moduleCache.set(key, result.module);
330
430
  instanceCache.set(key, result.instance);
@@ -341,12 +441,28 @@ async function loadWasmModule(source, imports, cacheKey) {
341
441
  module = await WebAssembly.compile(bytes);
342
442
  if (key) moduleCache.set(key, module);
343
443
  }
344
- const instance = await WebAssembly.instantiate(module, imports || {});
444
+ const instance = await WebAssembly.instantiate(module, wasmImports || {});
345
445
  if (key) instanceCache.set(key, instance);
346
446
  return instance;
347
447
  }
348
- async function preloadWasm(url) {
448
+ async function preloadWasm(url, options = {}) {
349
449
  if (moduleCache.has(url)) return;
450
+ const allowed = options.allowedOrigins ?? [];
451
+ if (allowed.length > 0) {
452
+ let parsed;
453
+ try {
454
+ parsed = new URL(url, typeof location !== "undefined" ? location.href : void 0);
455
+ } catch {
456
+ throw new Error(`preloadWasm: invalid URL "${url}"`);
457
+ }
458
+ if (!allowed.includes(parsed.origin)) {
459
+ throw new Error(`preloadWasm: origin "${parsed.origin}" is not in the allowlist`);
460
+ }
461
+ } else if (!options.unsafelyAllowAnyOrigin) {
462
+ throw new Error(
463
+ `preloadWasm: refused to fetch "${url}" with no allowedOrigins. Pass { allowedOrigins: [...] } or { unsafelyAllowAnyOrigin: true } (CWE-829).`
464
+ );
465
+ }
350
466
  let module;
351
467
  if (typeof WebAssembly.compileStreaming === "function") {
352
468
  module = await WebAssembly.compileStreaming(fetch(url));
@@ -415,31 +531,38 @@ function createMicroApp(config) {
415
531
  }
416
532
  let mounted = false;
417
533
  function mount(component) {
418
- if (root instanceof ShadowRoot) {
419
- root.innerHTML = "";
420
- } else {
421
- while (root.firstChild) {
422
- root.removeChild(root.firstChild);
423
- }
424
- }
534
+ root.replaceChildren();
425
535
  const el = component();
426
536
  root.appendChild(el);
427
537
  mounted = true;
428
538
  }
429
539
  function unmount() {
430
540
  if (!mounted) return;
431
- if (root instanceof ShadowRoot) {
432
- root.innerHTML = "";
433
- } else {
434
- while (root.firstChild) {
435
- root.removeChild(root.firstChild);
436
- }
437
- }
541
+ root.replaceChildren();
438
542
  mounted = false;
439
543
  }
440
544
  return { mount, unmount, element: host };
441
545
  }
442
- function loadRemoteModule(url) {
546
+ function loadRemoteModule(url, optionsOrAllowedOrigins = []) {
547
+ const opts = Array.isArray(optionsOrAllowedOrigins) ? { allowedOrigins: optionsOrAllowedOrigins } : optionsOrAllowedOrigins;
548
+ const allowedOrigins = opts.allowedOrigins ?? [];
549
+ if (allowedOrigins.length > 0) {
550
+ let parsed;
551
+ try {
552
+ parsed = new URL(url, typeof location !== "undefined" ? location.href : void 0);
553
+ } catch {
554
+ return Promise.reject(new Error(`loadRemoteModule: invalid URL "${url}"`));
555
+ }
556
+ if (!allowedOrigins.includes(parsed.origin)) {
557
+ return Promise.reject(new Error(`loadRemoteModule: origin "${parsed.origin}" is not in the allowlist`));
558
+ }
559
+ } else if (!opts.unsafelyAllowAnyOrigin) {
560
+ return Promise.reject(
561
+ new Error(
562
+ `loadRemoteModule: refused to import "${url}" with no allowedOrigins. Pass { allowedOrigins: [...] } to restrict the origin, or { unsafelyAllowAnyOrigin: true } to opt in to unrestricted imports (CWE-829).`
563
+ )
564
+ );
565
+ }
443
566
  const cached = moduleCache2.get(url);
444
567
  if (cached) return cached;
445
568
  const promise = import(
@@ -529,21 +652,49 @@ function serviceWorker(scriptUrl, options) {
529
652
  const [isReady, setIsReady] = signal(false);
530
653
  const [isUpdateAvailable, setIsUpdateAvailable] = signal(false);
531
654
  const [error, setError] = signal(null);
655
+ let disposed = false;
656
+ let updateFoundHandler = null;
657
+ let stateChangeHandler = null;
658
+ let trackedWorker = null;
659
+ let trackedReg = null;
660
+ function detachListeners() {
661
+ if (trackedReg && updateFoundHandler) {
662
+ trackedReg.removeEventListener("updatefound", updateFoundHandler);
663
+ }
664
+ if (trackedWorker && stateChangeHandler) {
665
+ trackedWorker.removeEventListener("statechange", stateChangeHandler);
666
+ }
667
+ updateFoundHandler = null;
668
+ stateChangeHandler = null;
669
+ trackedWorker = null;
670
+ trackedReg = null;
671
+ }
532
672
  if ("serviceWorker" in navigator) {
533
673
  navigator.serviceWorker.register(scriptUrl, options).then((reg) => {
674
+ if (disposed) return;
534
675
  setRegistration(reg);
535
676
  setIsReady(true);
536
- reg.addEventListener("updatefound", () => {
677
+ trackedReg = reg;
678
+ updateFoundHandler = () => {
679
+ if (disposed) return;
537
680
  const newWorker = reg.installing;
538
681
  if (newWorker) {
539
- newWorker.addEventListener("statechange", () => {
682
+ if (trackedWorker && stateChangeHandler) {
683
+ trackedWorker.removeEventListener("statechange", stateChangeHandler);
684
+ }
685
+ trackedWorker = newWorker;
686
+ stateChangeHandler = () => {
687
+ if (disposed) return;
540
688
  if (newWorker.state === "installed" && navigator.serviceWorker.controller) {
541
689
  setIsUpdateAvailable(true);
542
690
  }
543
- });
691
+ };
692
+ newWorker.addEventListener("statechange", stateChangeHandler);
544
693
  }
545
- });
694
+ };
695
+ reg.addEventListener("updatefound", updateFoundHandler);
546
696
  }).catch((err) => {
697
+ if (disposed) return;
547
698
  setError(err instanceof Error ? err : new Error(String(err)));
548
699
  });
549
700
  }
@@ -554,6 +705,8 @@ function serviceWorker(scriptUrl, options) {
554
705
  }
555
706
  }
556
707
  async function unregister() {
708
+ disposed = true;
709
+ detachListeners();
557
710
  const reg = registration();
558
711
  if (reg) {
559
712
  const result = await reg.unregister();
@@ -592,24 +745,42 @@ function createISR(options) {
592
745
  const { revalidateAfter, fetcher, initialData } = options;
593
746
  const [data, setData] = signal(initialData);
594
747
  const [timestamp, setTimestamp] = signal(initialData !== void 0 ? Date.now() : 0);
748
+ const controller = new AbortController();
749
+ let inFlight = false;
750
+ let disposed = false;
595
751
  const isStale = () => {
596
752
  const ts = timestamp();
597
753
  if (ts === 0) return true;
598
754
  return Date.now() - ts >= revalidateAfter;
599
755
  };
600
756
  const revalidate = async () => {
601
- const result = await fetcher();
602
- setData(result);
603
- setTimestamp(Date.now());
757
+ if (disposed || inFlight) return;
758
+ if (controller.signal.aborted) return;
759
+ inFlight = true;
760
+ try {
761
+ const result = await fetcher({ signal: controller.signal });
762
+ if (disposed || controller.signal.aborted) return;
763
+ setData(result);
764
+ setTimestamp(Date.now());
765
+ } finally {
766
+ inFlight = false;
767
+ }
604
768
  };
605
769
  if (initialData === void 0) {
606
- revalidate();
770
+ revalidate().catch((err) => {
771
+ if (typeof console !== "undefined") console.warn("[SibuJS ISR] initial fetch failed", err);
772
+ });
607
773
  }
608
774
  const intervalId = setInterval(() => {
609
- revalidate();
775
+ revalidate().catch((err) => {
776
+ if (typeof console !== "undefined") console.warn("[SibuJS ISR] revalidate failed", err);
777
+ });
610
778
  }, revalidateAfter);
611
779
  const dispose = () => {
780
+ if (disposed) return;
781
+ disposed = true;
612
782
  clearInterval(intervalId);
783
+ controller.abort();
613
784
  };
614
785
  return { data, isStale, revalidate, dispose };
615
786
  }
@@ -0,0 +1,79 @@
1
+ // src/utils/sanitize.ts
2
+ var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
3
+ function sanitizeUrl(url) {
4
+ const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
5
+ if (!trimmed) return "";
6
+ const lower = trimmed.toLowerCase();
7
+ let schemeEnd = -1;
8
+ for (let i = 0; i < lower.length; i++) {
9
+ const ch = lower.charCodeAt(i);
10
+ if (ch === 58) {
11
+ schemeEnd = i;
12
+ break;
13
+ }
14
+ if (ch === 47 || ch === 63 || ch === 35) break;
15
+ }
16
+ if (schemeEnd === -1) return trimmed;
17
+ const scheme = lower.slice(0, schemeEnd + 1);
18
+ if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return trimmed;
19
+ if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
20
+ return trimmed;
21
+ }
22
+ function sanitizeSrcset(value) {
23
+ const parts = value.split(",");
24
+ const out = [];
25
+ for (let i = 0; i < parts.length; i++) {
26
+ const part = parts[i].trim();
27
+ if (!part) continue;
28
+ const m = part.match(/^(\S+)(\s+.+)?$/);
29
+ if (!m) continue;
30
+ const safe = sanitizeUrl(m[1]);
31
+ if (!safe) continue;
32
+ out.push(m[2] ? `${safe}${m[2]}` : safe);
33
+ }
34
+ return out.join(", ");
35
+ }
36
+ function sanitizeCSSValue(value) {
37
+ const decoded = value.replace(/\\([0-9a-fA-F]{1,6})\s?/g, (_m, hex) => {
38
+ const code = Number.parseInt(hex, 16);
39
+ if (!Number.isFinite(code) || code < 0 || code > 1114111) return "";
40
+ try {
41
+ return String.fromCodePoint(code);
42
+ } catch {
43
+ return "";
44
+ }
45
+ });
46
+ const lower = decoded.toLowerCase().replace(/\s+/g, "");
47
+ if (lower.includes("url(") || lower.includes("expression(") || lower.includes("javascript:") || lower.includes("vbscript:") || lower.includes("-moz-binding") || lower.includes("behavior:") || lower.includes("@import") || lower.includes("image-set(") || lower.includes("filter:progid")) {
48
+ return "";
49
+ }
50
+ return value;
51
+ }
52
+ function stripHtml(html) {
53
+ return String(html).replace(/<[^>]*>/g, "");
54
+ }
55
+ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
56
+ "href",
57
+ "xlink:href",
58
+ "src",
59
+ "action",
60
+ "formaction",
61
+ "formtarget",
62
+ "cite",
63
+ "poster",
64
+ "background",
65
+ "srcset",
66
+ "ping",
67
+ "data"
68
+ ]);
69
+ function isUrlAttribute(attr) {
70
+ return URL_ATTRIBUTES.has(attr);
71
+ }
72
+
73
+ export {
74
+ sanitizeUrl,
75
+ sanitizeSrcset,
76
+ sanitizeCSSValue,
77
+ stripHtml,
78
+ isUrlAttribute
79
+ };