@aprovan/patchwork-compiler 0.1.2-dev.98f1b7b → 0.1.2-dev.9c336a0

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/index.js CHANGED
@@ -1,48 +1,6 @@
1
1
  // src/compiler.ts
2
2
  import * as esbuild from "esbuild-wasm";
3
3
 
4
- // src/vfs/project.ts
5
- function createProjectFromFiles(files, id = crypto.randomUUID()) {
6
- const fileMap = /* @__PURE__ */ new Map();
7
- for (const file of files) {
8
- fileMap.set(file.path, file);
9
- }
10
- return { id, entry: resolveEntry(fileMap), files: fileMap };
11
- }
12
- function resolveEntry(files) {
13
- const paths = Array.from(files.keys());
14
- const mainFile = paths.find((p) => /\bmain\.(tsx?|jsx?)$/.test(p));
15
- if (mainFile) return mainFile;
16
- const indexFile = paths.find((p) => /\bindex\.(tsx?|jsx?)$/.test(p));
17
- if (indexFile) return indexFile;
18
- const firstTsx = paths.find((p) => /\.(tsx|jsx)$/.test(p));
19
- if (firstTsx) return firstTsx;
20
- return paths[0] || "main.tsx";
21
- }
22
- function detectMainFile(language) {
23
- switch (language) {
24
- case "tsx":
25
- case "typescript":
26
- return "main.tsx";
27
- case "jsx":
28
- case "javascript":
29
- return "main.jsx";
30
- case "ts":
31
- return "main.ts";
32
- case "js":
33
- return "main.js";
34
- default:
35
- return "main.tsx";
36
- }
37
- }
38
- function createSingleFileProject(content, entry = "main.tsx", id = "inline") {
39
- return {
40
- id,
41
- entry,
42
- files: /* @__PURE__ */ new Map([[entry, { path: entry, content }]])
43
- };
44
- }
45
-
46
4
  // src/schemas.ts
47
5
  import { z } from "zod";
48
6
  var PlatformSchema = z.enum(["browser", "cli"]);
@@ -130,7 +88,7 @@ var DEFAULT_CLI_IMAGE_CONFIG = {
130
88
  }
131
89
  };
132
90
 
133
- // src/images/loader.ts
91
+ // src/cdn-config.ts
134
92
  var DEFAULT_CDN_BASE = "https://esm.sh";
135
93
  var cdnBaseUrl = DEFAULT_CDN_BASE;
136
94
  function setCdnBaseUrl(url) {
@@ -139,7 +97,24 @@ function setCdnBaseUrl(url) {
139
97
  function getCdnBaseUrl() {
140
98
  return cdnBaseUrl;
141
99
  }
142
- function parseImageSpec(spec) {
100
+ function toEsmShUrl(packageName, version2, subpath, deps) {
101
+ let url = `${cdnBaseUrl}/${packageName}`;
102
+ if (version2) {
103
+ url += `@${version2}`;
104
+ }
105
+ if (subpath) {
106
+ url += `/${subpath}`;
107
+ }
108
+ if (deps && Object.keys(deps).length > 0) {
109
+ const depsStr = Object.entries(deps).map(([name, ver]) => `${name}@${ver}`).join(",");
110
+ url += `?deps=${depsStr}`;
111
+ }
112
+ return url;
113
+ }
114
+ function isBareImport(path) {
115
+ return !(path.startsWith(".") || path.startsWith("/") || path.startsWith("http://") || path.startsWith("https://"));
116
+ }
117
+ function parsePackageSpec(spec) {
143
118
  if (spec.startsWith("@")) {
144
119
  const parts = spec.split("/");
145
120
  if (parts.length >= 2) {
@@ -164,14 +139,77 @@ function parseImageSpec(spec) {
164
139
  }
165
140
  return { name: spec };
166
141
  }
167
- async function fetchPackageJson(packageName, version) {
168
- const versionSuffix = version ? `@${version}` : "";
169
- const url = `${cdnBaseUrl}/${packageName}${versionSuffix}/package.json`;
142
+ function parseImportPath(importPath) {
143
+ if (importPath.startsWith("@")) {
144
+ const parts2 = importPath.split("/");
145
+ if (parts2.length >= 2) {
146
+ const packageName2 = `${parts2[0]}/${parts2[1]}`;
147
+ const subpath2 = parts2.slice(2).join("/");
148
+ return { packageName: packageName2, subpath: subpath2 || void 0 };
149
+ }
150
+ }
151
+ const parts = importPath.split("/");
152
+ const packageName = parts[0];
153
+ const subpath = parts.slice(1).join("/");
154
+ return { packageName, subpath: subpath || void 0 };
155
+ }
156
+ function matchAlias(importPath, aliases) {
157
+ for (const [pattern, target] of Object.entries(aliases)) {
158
+ if (pattern.endsWith("/*")) {
159
+ const prefix = pattern.slice(0, -2);
160
+ if (importPath === prefix || importPath.startsWith(prefix + "/")) {
161
+ return target;
162
+ }
163
+ }
164
+ if (importPath === pattern) {
165
+ return target;
166
+ }
167
+ }
168
+ return null;
169
+ }
170
+ var COMMON_EXPORTS = {
171
+ react: [
172
+ "useState",
173
+ "useEffect",
174
+ "useCallback",
175
+ "useMemo",
176
+ "useRef",
177
+ "useContext",
178
+ "useReducer",
179
+ "useLayoutEffect",
180
+ "useId",
181
+ "createContext",
182
+ "createElement",
183
+ "cloneElement",
184
+ "createRef",
185
+ "forwardRef",
186
+ "lazy",
187
+ "memo",
188
+ "Fragment",
189
+ "Suspense",
190
+ "StrictMode",
191
+ "Component",
192
+ "PureComponent",
193
+ "Children",
194
+ "isValidElement"
195
+ ],
196
+ "react-dom": ["createPortal", "flushSync", "render", "hydrate", "unmountComponentAtNode"]
197
+ };
198
+ function getCommonExports(packageName) {
199
+ return COMMON_EXPORTS[packageName] ?? [];
200
+ }
201
+
202
+ // src/images/loader.ts
203
+ function parseImageSpec(spec) {
204
+ return parsePackageSpec(spec);
205
+ }
206
+ async function fetchPackageJson(packageName, version2) {
207
+ const cdnBaseUrl2 = getCdnBaseUrl();
208
+ const versionSuffix = version2 ? `@${version2}` : "";
209
+ const url = `${cdnBaseUrl2}/${packageName}${versionSuffix}/package.json`;
170
210
  const response = await fetch(url);
171
211
  if (!response.ok) {
172
- throw new Error(
173
- `Failed to fetch package.json for ${packageName}: ${response.statusText}`
174
- );
212
+ throw new Error(`Failed to fetch package.json for ${packageName}: ${response.statusText}`);
175
213
  }
176
214
  return response.json();
177
215
  }
@@ -226,21 +264,22 @@ async function loadLocalImage(name) {
226
264
  }
227
265
  }
228
266
  async function loadImage(spec) {
229
- const { name, version } = parseImageSpec(spec);
267
+ const { name, version: version2 } = parseImageSpec(spec);
230
268
  const localImage = await loadLocalImage(name);
231
269
  if (localImage) {
232
270
  return localImage;
233
271
  }
234
- const packageJson = await fetchPackageJson(name, version);
272
+ const packageJson = await fetchPackageJson(name, version2);
235
273
  const config = safeParseImageConfig(packageJson.patchwork) || DEFAULT_IMAGE_CONFIG;
236
274
  let setup;
237
275
  let mount;
238
276
  let moduleUrl;
239
277
  if (packageJson.main && typeof window !== "undefined") {
240
278
  try {
241
- const versionSuffix = version ? `@${version}` : "";
279
+ const cdnBaseUrl2 = getCdnBaseUrl();
280
+ const versionSuffix = version2 ? `@${version2}` : "";
242
281
  const mainEntry = packageJson.main.startsWith("./") ? packageJson.main.slice(2) : packageJson.main;
243
- const importUrl = `${cdnBaseUrl}/${name}${versionSuffix}/${mainEntry}`;
282
+ const importUrl = `${cdnBaseUrl2}/${name}${versionSuffix}/${mainEntry}`;
244
283
  moduleUrl = importUrl;
245
284
  const imageModule = await import(
246
285
  /* @vite-ignore */
@@ -278,436 +317,78 @@ var ImageRegistry = class {
278
317
  const { name } = parseImageSpec(spec);
279
318
  return this.images.get(name);
280
319
  }
281
- /**
282
- * Check if an image is loaded
283
- */
284
- has(spec) {
285
- const { name } = parseImageSpec(spec);
286
- return this.images.has(name);
287
- }
288
- /**
289
- * Load an image (or return cached)
290
- */
291
- async load(spec) {
292
- const { name } = parseImageSpec(spec);
293
- const cached = this.images.get(name);
294
- if (cached) {
295
- return cached;
296
- }
297
- const inProgress = this.loading.get(name);
298
- if (inProgress) {
299
- return inProgress;
300
- }
301
- const loadPromise = loadImage(spec).then((image) => {
302
- this.images.set(name, image);
303
- this.loading.delete(name);
304
- return image;
305
- });
306
- this.loading.set(name, loadPromise);
307
- return loadPromise;
308
- }
309
- /**
310
- * Preload an image
311
- */
312
- async preload(spec) {
313
- await this.load(spec);
314
- }
315
- /**
316
- * Clear a specific image from cache
317
- */
318
- clear(spec) {
319
- const { name } = parseImageSpec(spec);
320
- this.images.delete(name);
321
- this.loading.delete(name);
322
- }
323
- /**
324
- * Clear all cached images
325
- */
326
- clearAll() {
327
- this.images.clear();
328
- this.loading.clear();
329
- }
330
- /**
331
- * Get all loaded image names
332
- */
333
- getLoadedNames() {
334
- return Array.from(this.images.keys());
335
- }
336
- };
337
- var globalRegistry = null;
338
- function getImageRegistry() {
339
- if (!globalRegistry) {
340
- globalRegistry = new ImageRegistry();
341
- }
342
- return globalRegistry;
343
- }
344
- function createImageRegistry() {
345
- return new ImageRegistry();
346
- }
347
-
348
- // src/transforms/cdn.ts
349
- var DEFAULT_CDN_BASE2 = "https://esm.sh";
350
- var cdnBaseUrl2 = DEFAULT_CDN_BASE2;
351
- function setCdnBaseUrl2(url) {
352
- cdnBaseUrl2 = url;
353
- }
354
- var EXTERNAL_PACKAGES = /* @__PURE__ */ new Set(["react", "react-dom", "ink"]);
355
- var NODE_BUILTINS = /* @__PURE__ */ new Set([
356
- "assert",
357
- "buffer",
358
- "child_process",
359
- "cluster",
360
- "crypto",
361
- "dgram",
362
- "dns",
363
- "events",
364
- "fs",
365
- "http",
366
- "http2",
367
- "https",
368
- "net",
369
- "os",
370
- "path",
371
- "perf_hooks",
372
- "process",
373
- "querystring",
374
- "readline",
375
- "stream",
376
- "string_decoder",
377
- "timers",
378
- "tls",
379
- "tty",
380
- "url",
381
- "util",
382
- "v8",
383
- "vm",
384
- "worker_threads",
385
- "zlib"
386
- ]);
387
- function toEsmShUrl(packageName, version, subpath, deps) {
388
- let url = `${cdnBaseUrl2}/${packageName}`;
389
- if (version) {
390
- url += `@${version}`;
391
- }
392
- if (subpath) {
393
- url += `/${subpath}`;
394
- }
395
- if (deps && Object.keys(deps).length > 0) {
396
- const depsStr = Object.entries(deps).map(([name, ver]) => `${name}@${ver}`).join(",");
397
- url += `?deps=${depsStr}`;
398
- }
399
- return url;
400
- }
401
- function isBareImport(path) {
402
- if (path.startsWith(".") || path.startsWith("/") || path.startsWith("http://") || path.startsWith("https://")) {
403
- return false;
404
- }
405
- return true;
406
- }
407
- function parseImportPath(importPath) {
408
- if (importPath.startsWith("@")) {
409
- const parts2 = importPath.split("/");
410
- if (parts2.length >= 2) {
411
- const packageName2 = `${parts2[0]}/${parts2[1]}`;
412
- const subpath2 = parts2.slice(2).join("/");
413
- return { packageName: packageName2, subpath: subpath2 || void 0 };
414
- }
415
- }
416
- const parts = importPath.split("/");
417
- const packageName = parts[0];
418
- const subpath = parts.slice(1).join("/");
419
- return { packageName, subpath: subpath || void 0 };
420
- }
421
- function matchAlias(importPath, aliases) {
422
- for (const [pattern, target] of Object.entries(aliases)) {
423
- if (pattern.endsWith("/*")) {
424
- const prefix = pattern.slice(0, -2);
425
- if (importPath === prefix || importPath.startsWith(prefix + "/")) {
426
- return target;
427
- }
428
- }
429
- if (importPath === pattern) {
430
- return target;
431
- }
432
- }
433
- return null;
434
- }
435
- function cdnTransformPlugin(options = {}) {
436
- const {
437
- packages = {},
438
- external = [],
439
- bundle = false,
440
- globals = {},
441
- deps = {},
442
- aliases = {}
443
- } = options;
444
- const externalSet = /* @__PURE__ */ new Set([...EXTERNAL_PACKAGES, ...external]);
445
- const globalsSet = new Set(Object.keys(globals));
446
- return {
447
- name: "cdn-transform",
448
- setup(build2) {
449
- build2.onResolve({ filter: /.*/ }, (args) => {
450
- const aliasTarget = matchAlias(args.path, aliases);
451
- if (aliasTarget) {
452
- const { packageName, subpath } = parseImportPath(aliasTarget);
453
- if (globalsSet.has(packageName)) {
454
- return {
455
- path: aliasTarget,
456
- namespace: "global-inject"
457
- };
458
- }
459
- const version = packages[packageName];
460
- let url = toEsmShUrl(
461
- packageName,
462
- version,
463
- subpath,
464
- Object.keys(deps).length > 0 ? deps : void 0
465
- );
466
- if (bundle) {
467
- url += url.includes("?") ? "&bundle" : "?bundle";
468
- }
469
- return {
470
- path: url,
471
- external: true
472
- };
473
- }
474
- return null;
475
- });
476
- build2.onResolve({ filter: /.*/ }, (args) => {
477
- if (!isBareImport(args.path)) {
478
- return null;
479
- }
480
- const { packageName } = parseImportPath(args.path);
481
- if (globalsSet.has(packageName)) {
482
- return {
483
- path: args.path,
484
- namespace: "global-inject"
485
- };
486
- }
487
- return null;
488
- });
489
- build2.onLoad({ filter: /.*/, namespace: "global-inject" }, (args) => {
490
- const { packageName, subpath } = parseImportPath(args.path);
491
- const globalName = globals[packageName];
492
- if (!globalName) return null;
493
- if (subpath) {
494
- return {
495
- contents: `export * from '${packageName}'; export { default } from '${packageName}';`,
496
- loader: "js"
497
- };
498
- }
499
- const contents = `
500
- const mod = window.${globalName};
501
- export default mod;
502
- // Re-export all properties as named exports
503
- const { ${getCommonExports(packageName).join(", ")} } = mod;
504
- export { ${getCommonExports(packageName).join(", ")} };
505
- `;
506
- return {
507
- contents,
508
- loader: "js"
509
- };
510
- });
511
- build2.onResolve({ filter: /.*/ }, (args) => {
512
- if (!isBareImport(args.path)) {
513
- return null;
514
- }
515
- if (NODE_BUILTINS.has(args.path)) {
516
- return { external: true };
517
- }
518
- const { packageName, subpath } = parseImportPath(args.path);
519
- if (globalsSet.has(packageName)) {
520
- return null;
521
- }
522
- if (externalSet.has(packageName)) {
523
- return { external: true };
524
- }
525
- const version = packages[packageName];
526
- let url = toEsmShUrl(
527
- packageName,
528
- version,
529
- subpath,
530
- Object.keys(deps).length > 0 ? deps : void 0
531
- );
532
- if (bundle) {
533
- url += url.includes("?") ? "&bundle" : "?bundle";
534
- }
535
- return {
536
- path: url,
537
- external: true
538
- };
539
- });
540
- }
541
- };
542
- }
543
- function getCommonExports(packageName) {
544
- const exports = {
545
- react: [
546
- "useState",
547
- "useEffect",
548
- "useCallback",
549
- "useMemo",
550
- "useRef",
551
- "useContext",
552
- "useReducer",
553
- "useLayoutEffect",
554
- "useId",
555
- "createContext",
556
- "createElement",
557
- "cloneElement",
558
- "createRef",
559
- "forwardRef",
560
- "lazy",
561
- "memo",
562
- "Fragment",
563
- "Suspense",
564
- "StrictMode",
565
- "Component",
566
- "PureComponent",
567
- "Children",
568
- "isValidElement"
569
- ],
570
- "react-dom": [
571
- "createPortal",
572
- "flushSync",
573
- "render",
574
- "hydrate",
575
- "unmountComponentAtNode"
576
- ]
577
- };
578
- return exports[packageName] || [];
579
- }
580
- function generateImportMap(packages) {
581
- const imports = {};
582
- for (const [name, version] of Object.entries(packages)) {
583
- imports[name] = toEsmShUrl(name, version);
584
- }
585
- return imports;
586
- }
587
-
588
- // src/transforms/vfs.ts
589
- function dirname(path) {
590
- const idx = path.lastIndexOf("/");
591
- return idx === -1 ? "." : path.slice(0, idx) || ".";
592
- }
593
- function normalizePath(path) {
594
- const parts = [];
595
- for (const segment of path.split("/")) {
596
- if (segment === "..") parts.pop();
597
- else if (segment && segment !== ".") parts.push(segment);
598
- }
599
- return parts.join("/");
600
- }
601
- function inferLoader(path, language) {
602
- if (language) {
603
- switch (language) {
604
- case "typescript":
605
- case "ts":
606
- return "ts";
607
- case "tsx":
608
- return "tsx";
609
- case "javascript":
610
- case "js":
611
- return "js";
612
- case "jsx":
613
- return "jsx";
614
- case "json":
615
- return "json";
616
- case "css":
617
- return "css";
618
- }
619
- }
620
- const ext = path.split(".").pop();
621
- switch (ext) {
622
- case "ts":
623
- return "ts";
624
- case "tsx":
625
- return "tsx";
626
- case "js":
627
- return "js";
628
- case "jsx":
629
- return "jsx";
630
- case "json":
631
- return "json";
632
- case "css":
633
- return "css";
634
- default:
635
- return "tsx";
636
- }
637
- }
638
- function normalizeVFSPath(path) {
639
- if (path.startsWith("@/")) {
640
- return path.slice(2);
320
+ /**
321
+ * Check if an image is loaded
322
+ */
323
+ has(spec) {
324
+ const { name } = parseImageSpec(spec);
325
+ return this.images.has(name);
641
326
  }
642
- return path;
643
- }
644
- function resolveRelativePath(importer, target) {
645
- const importerDir = dirname(normalizeVFSPath(importer));
646
- const combined = importerDir === "." ? target : `${importerDir}/${target}`;
647
- return normalizePath(combined);
648
- }
649
- function matchAlias2(importPath, aliases) {
650
- if (!aliases) return null;
651
- for (const [pattern, target] of Object.entries(aliases)) {
652
- if (pattern.endsWith("/*")) {
653
- const prefix = pattern.slice(0, -2);
654
- if (importPath === prefix || importPath.startsWith(prefix + "/")) {
655
- return target;
656
- }
327
+ /**
328
+ * Load an image (or return cached)
329
+ */
330
+ async load(spec) {
331
+ const { name } = parseImageSpec(spec);
332
+ const cached = this.images.get(name);
333
+ if (cached) {
334
+ return cached;
657
335
  }
658
- if (importPath === pattern) {
659
- return target;
336
+ const inProgress = this.loading.get(name);
337
+ if (inProgress) {
338
+ return inProgress;
660
339
  }
340
+ const loadPromise = loadImage(spec).then((image) => {
341
+ this.images.set(name, image);
342
+ this.loading.delete(name);
343
+ return image;
344
+ });
345
+ this.loading.set(name, loadPromise);
346
+ return loadPromise;
661
347
  }
662
- return null;
663
- }
664
- function findFile(project, path) {
665
- if (project.files.has(path)) return path;
666
- const extensions = [".tsx", ".ts", ".jsx", ".js", ".json"];
667
- for (const ext of extensions) {
668
- if (project.files.has(path + ext)) return path + ext;
348
+ /**
349
+ * Preload an image
350
+ */
351
+ async preload(spec) {
352
+ await this.load(spec);
669
353
  }
670
- for (const ext of extensions) {
671
- const indexPath = `${path}/index${ext}`;
672
- if (project.files.has(indexPath)) return indexPath;
354
+ /**
355
+ * Clear a specific image from cache
356
+ */
357
+ clear(spec) {
358
+ const { name } = parseImageSpec(spec);
359
+ this.images.delete(name);
360
+ this.loading.delete(name);
673
361
  }
674
- return null;
362
+ /**
363
+ * Clear all cached images
364
+ */
365
+ clearAll() {
366
+ this.images.clear();
367
+ this.loading.clear();
368
+ }
369
+ /**
370
+ * Get all loaded image names
371
+ */
372
+ getLoadedNames() {
373
+ return Array.from(this.images.keys());
374
+ }
375
+ };
376
+ var globalRegistry = null;
377
+ function getImageRegistry() {
378
+ if (!globalRegistry) {
379
+ globalRegistry = new ImageRegistry();
380
+ }
381
+ return globalRegistry;
675
382
  }
676
- function vfsPlugin(project, options = {}) {
677
- return {
678
- name: "patchwork-vfs",
679
- setup(build2) {
680
- build2.onResolve({ filter: /^@\// }, (args) => {
681
- const aliased = matchAlias2(args.path, options.aliases);
682
- if (aliased) return null;
683
- return { path: args.path, namespace: "vfs" };
684
- });
685
- build2.onResolve({ filter: /^\./ }, (args) => {
686
- if (args.namespace !== "vfs") return null;
687
- const resolved = resolveRelativePath(args.importer, args.path);
688
- return { path: resolved, namespace: "vfs" };
689
- });
690
- build2.onLoad({ filter: /.*/, namespace: "vfs" }, (args) => {
691
- const normalPath = normalizeVFSPath(args.path);
692
- const filePath = findFile(project, normalPath);
693
- if (!filePath) {
694
- throw new Error(`File not found in VFS: ${args.path}`);
695
- }
696
- const file = project.files.get(filePath);
697
- return {
698
- contents: file.content,
699
- loader: inferLoader(filePath, file.language)
700
- };
701
- });
702
- }
703
- };
383
+ function createImageRegistry() {
384
+ return new ImageRegistry();
704
385
  }
705
386
 
706
387
  // src/mount/bridge.ts
707
388
  function generateMessageId() {
708
389
  return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
709
390
  }
710
- function createHttpServiceProxy(proxyUrl) {
391
+ function createHttpProxy(proxyUrl) {
711
392
  return {
712
393
  async call(namespace, procedure, args) {
713
394
  const url = `${proxyUrl}/${namespace}/${procedure}`;
@@ -851,7 +532,7 @@ var ParentBridge = class {
851
532
  this.pendingCalls.clear();
852
533
  }
853
534
  };
854
- function createIframeServiceProxy() {
535
+ function createIframeProxy() {
855
536
  const pendingCalls = /* @__PURE__ */ new Map();
856
537
  if (typeof window !== "undefined") {
857
538
  window.addEventListener("message", (event) => {
@@ -983,9 +664,9 @@ function injectImportMap(globals, preloadUrls, deps) {
983
664
  if (preloadUrls[index]) {
984
665
  imports[pkgName] = preloadUrls[index];
985
666
  } else if (deps?.[pkgName]) {
986
- imports[pkgName] = `https://esm.sh/${pkgName}@${deps[pkgName]}`;
667
+ imports[pkgName] = toEsmShUrl(pkgName, deps[pkgName]);
987
668
  } else {
988
- imports[pkgName] = `https://esm.sh/${pkgName}`;
669
+ imports[pkgName] = toEsmShUrl(pkgName);
989
670
  }
990
671
  });
991
672
  if (imports["react-dom"]) {
@@ -1055,13 +736,11 @@ async function mountEmbedded(widget, options, image, proxy) {
1055
736
  const deps = frameworkConfig.deps || {};
1056
737
  injectImportMap(globalMapping, preloadUrls, deps);
1057
738
  const preloadedModules = await Promise.all(
1058
- preloadUrls.map(
1059
- (url) => import(
1060
- /* webpackIgnore: true */
1061
- /* @vite-ignore */
1062
- url
1063
- )
1064
- )
739
+ preloadUrls.map((url) => import(
740
+ /* webpackIgnore: true */
741
+ /* @vite-ignore */
742
+ url
743
+ ))
1065
744
  );
1066
745
  const win = window;
1067
746
  const globalNames = Object.values(globalMapping);
@@ -1105,48 +784,198 @@ async function mountEmbedded(widget, options, image, proxy) {
1105
784
  if (typeof root.unmount === "function") {
1106
785
  moduleCleanup = () => root.unmount();
1107
786
  }
1108
- } else if (createElement && renderer?.kind === "render") {
1109
- renderer.render(createElement(Component, inputs), container);
1110
- } else {
1111
- const result = Component(inputs);
1112
- if (result instanceof HTMLElement) {
1113
- container.appendChild(result);
1114
- } else if (typeof result === "string") {
1115
- container.innerHTML = result;
787
+ } else if (createElement && renderer?.kind === "render") {
788
+ renderer.render(createElement(Component, inputs), container);
789
+ } else {
790
+ const result = Component(inputs);
791
+ if (result instanceof HTMLElement) {
792
+ container.appendChild(result);
793
+ } else if (typeof result === "string") {
794
+ container.innerHTML = result;
795
+ }
796
+ }
797
+ }
798
+ } finally {
799
+ URL.revokeObjectURL(scriptUrl);
800
+ }
801
+ const unmount = () => {
802
+ if (moduleCleanup) {
803
+ moduleCleanup();
804
+ }
805
+ removeNamespaceGlobals(window, namespaceNames);
806
+ const style = document.getElementById(`${mountId}-style`);
807
+ if (style) {
808
+ style.remove();
809
+ }
810
+ container.remove();
811
+ };
812
+ return {
813
+ id: mountId,
814
+ widget,
815
+ mode: "embedded",
816
+ target,
817
+ inputs,
818
+ unmount
819
+ };
820
+ }
821
+ async function reloadEmbedded(mounted, widget, image, proxy) {
822
+ mounted.unmount();
823
+ return mountEmbedded(
824
+ widget,
825
+ { target: mounted.target, mode: "embedded", inputs: mounted.inputs },
826
+ image,
827
+ proxy
828
+ );
829
+ }
830
+
831
+ // src/transforms/cdn.ts
832
+ var EXTERNAL_PACKAGES = /* @__PURE__ */ new Set(["react", "react-dom", "ink"]);
833
+ var NODE_BUILTINS = /* @__PURE__ */ new Set([
834
+ "assert",
835
+ "buffer",
836
+ "child_process",
837
+ "cluster",
838
+ "crypto",
839
+ "dgram",
840
+ "dns",
841
+ "events",
842
+ "fs",
843
+ "http",
844
+ "http2",
845
+ "https",
846
+ "net",
847
+ "os",
848
+ "path",
849
+ "perf_hooks",
850
+ "process",
851
+ "querystring",
852
+ "readline",
853
+ "stream",
854
+ "string_decoder",
855
+ "timers",
856
+ "tls",
857
+ "tty",
858
+ "url",
859
+ "util",
860
+ "v8",
861
+ "vm",
862
+ "worker_threads",
863
+ "zlib"
864
+ ]);
865
+ function cdnTransformPlugin(options = {}) {
866
+ const {
867
+ packages = {},
868
+ external = [],
869
+ bundle = false,
870
+ globals = {},
871
+ deps = {},
872
+ aliases = {}
873
+ } = options;
874
+ const externalSet = /* @__PURE__ */ new Set([...EXTERNAL_PACKAGES, ...external]);
875
+ const globalsSet = new Set(Object.keys(globals));
876
+ return {
877
+ name: "cdn-transform",
878
+ setup(build2) {
879
+ build2.onResolve({ filter: /.*/ }, (args) => {
880
+ const aliasTarget = matchAlias(args.path, aliases);
881
+ if (aliasTarget) {
882
+ const { packageName, subpath } = parseImportPath(aliasTarget);
883
+ if (globalsSet.has(packageName)) {
884
+ return {
885
+ path: aliasTarget,
886
+ namespace: "global-inject"
887
+ };
888
+ }
889
+ const version2 = packages[packageName];
890
+ let url = toEsmShUrl(
891
+ packageName,
892
+ version2,
893
+ subpath,
894
+ Object.keys(deps).length > 0 ? deps : void 0
895
+ );
896
+ if (bundle) {
897
+ url += url.includes("?") ? "&bundle" : "?bundle";
898
+ }
899
+ return {
900
+ path: url,
901
+ external: true
902
+ };
903
+ }
904
+ return null;
905
+ });
906
+ build2.onResolve({ filter: /.*/ }, (args) => {
907
+ if (!isBareImport(args.path)) {
908
+ return null;
909
+ }
910
+ const { packageName } = parseImportPath(args.path);
911
+ if (globalsSet.has(packageName)) {
912
+ return {
913
+ path: args.path,
914
+ namespace: "global-inject"
915
+ };
916
+ }
917
+ return null;
918
+ });
919
+ build2.onLoad({ filter: /.*/, namespace: "global-inject" }, (args) => {
920
+ const { packageName, subpath } = parseImportPath(args.path);
921
+ const globalName = globals[packageName];
922
+ if (!globalName) return null;
923
+ if (subpath) {
924
+ return {
925
+ contents: `export * from '${packageName}'; export { default } from '${packageName}';`,
926
+ loader: "js"
927
+ };
928
+ }
929
+ const contents = `
930
+ const mod = window.${globalName};
931
+ export default mod;
932
+ // Re-export all properties as named exports
933
+ const { ${getCommonExports(packageName).join(", ")} } = mod;
934
+ export { ${getCommonExports(packageName).join(", ")} };
935
+ `;
936
+ return {
937
+ contents,
938
+ loader: "js"
939
+ };
940
+ });
941
+ build2.onResolve({ filter: /.*/ }, (args) => {
942
+ if (!isBareImport(args.path)) {
943
+ return null;
1116
944
  }
1117
- }
1118
- }
1119
- } finally {
1120
- URL.revokeObjectURL(scriptUrl);
1121
- }
1122
- const unmount = () => {
1123
- if (moduleCleanup) {
1124
- moduleCleanup();
1125
- }
1126
- removeNamespaceGlobals(window, namespaceNames);
1127
- const style = document.getElementById(`${mountId}-style`);
1128
- if (style) {
1129
- style.remove();
945
+ if (NODE_BUILTINS.has(args.path)) {
946
+ return { external: true };
947
+ }
948
+ const { packageName, subpath } = parseImportPath(args.path);
949
+ if (globalsSet.has(packageName)) {
950
+ return null;
951
+ }
952
+ if (externalSet.has(packageName)) {
953
+ return { external: true };
954
+ }
955
+ const version2 = packages[packageName];
956
+ let url = toEsmShUrl(
957
+ packageName,
958
+ version2,
959
+ subpath,
960
+ Object.keys(deps).length > 0 ? deps : void 0
961
+ );
962
+ if (bundle) {
963
+ url += url.includes("?") ? "&bundle" : "?bundle";
964
+ }
965
+ return {
966
+ path: url,
967
+ external: true
968
+ };
969
+ });
1130
970
  }
1131
- container.remove();
1132
- };
1133
- return {
1134
- id: mountId,
1135
- widget,
1136
- mode: "embedded",
1137
- target,
1138
- inputs,
1139
- unmount
1140
971
  };
1141
972
  }
1142
- async function reloadEmbedded(mounted, widget, image, proxy) {
1143
- mounted.unmount();
1144
- return mountEmbedded(
1145
- widget,
1146
- { target: mounted.target, mode: "embedded", inputs: mounted.inputs },
1147
- image,
1148
- proxy
1149
- );
973
+ function generateImportMap(packages) {
974
+ const imports = {};
975
+ for (const [name, version2] of Object.entries(packages)) {
976
+ imports[name] = toEsmShUrl(name, version2);
977
+ }
978
+ return imports;
1150
979
  }
1151
980
 
1152
981
  // src/mount/iframe.ts
@@ -1474,10 +1303,171 @@ function disposeIframeBridge() {
1474
1303
  }
1475
1304
  }
1476
1305
 
1306
+ // src/transforms/vfs.ts
1307
+ function dirname(path) {
1308
+ const idx = path.lastIndexOf("/");
1309
+ return idx === -1 ? "." : path.slice(0, idx) || ".";
1310
+ }
1311
+ function normalizePath(path) {
1312
+ const parts = [];
1313
+ for (const segment of path.split("/")) {
1314
+ if (segment === "..") parts.pop();
1315
+ else if (segment && segment !== ".") parts.push(segment);
1316
+ }
1317
+ return parts.join("/");
1318
+ }
1319
+ function inferLoader(path, language) {
1320
+ if (language) {
1321
+ switch (language) {
1322
+ case "typescript":
1323
+ case "ts":
1324
+ return "ts";
1325
+ case "tsx":
1326
+ return "tsx";
1327
+ case "javascript":
1328
+ case "js":
1329
+ return "js";
1330
+ case "jsx":
1331
+ return "jsx";
1332
+ case "json":
1333
+ return "json";
1334
+ case "css":
1335
+ return "css";
1336
+ }
1337
+ }
1338
+ const ext = path.split(".").pop();
1339
+ switch (ext) {
1340
+ case "ts":
1341
+ return "ts";
1342
+ case "tsx":
1343
+ return "tsx";
1344
+ case "js":
1345
+ return "js";
1346
+ case "jsx":
1347
+ return "jsx";
1348
+ case "json":
1349
+ return "json";
1350
+ case "css":
1351
+ return "css";
1352
+ default:
1353
+ return "tsx";
1354
+ }
1355
+ }
1356
+ function normalizeVFSPath(path) {
1357
+ if (path.startsWith("@/")) {
1358
+ return path.slice(2);
1359
+ }
1360
+ return path;
1361
+ }
1362
+ function resolveRelativePath(importer, target) {
1363
+ const importerDir = dirname(normalizeVFSPath(importer));
1364
+ const combined = importerDir === "." ? target : `${importerDir}/${target}`;
1365
+ return normalizePath(combined);
1366
+ }
1367
+ function matchAlias2(importPath, aliases) {
1368
+ if (!aliases) return null;
1369
+ for (const [pattern, target] of Object.entries(aliases)) {
1370
+ if (pattern.endsWith("/*")) {
1371
+ const prefix = pattern.slice(0, -2);
1372
+ if (importPath === prefix || importPath.startsWith(prefix + "/")) {
1373
+ return target;
1374
+ }
1375
+ }
1376
+ if (importPath === pattern) {
1377
+ return target;
1378
+ }
1379
+ }
1380
+ return null;
1381
+ }
1382
+ function findFile(project, path) {
1383
+ if (project.files.has(path)) return path;
1384
+ const extensions = [".tsx", ".ts", ".jsx", ".js", ".json"];
1385
+ for (const ext of extensions) {
1386
+ if (project.files.has(path + ext)) return path + ext;
1387
+ }
1388
+ for (const ext of extensions) {
1389
+ const indexPath = `${path}/index${ext}`;
1390
+ if (project.files.has(indexPath)) return indexPath;
1391
+ }
1392
+ return null;
1393
+ }
1394
+ function vfsPlugin(project, options = {}) {
1395
+ return {
1396
+ name: "patchwork-vfs",
1397
+ setup(build2) {
1398
+ build2.onResolve({ filter: /^@\// }, (args) => {
1399
+ const aliased = matchAlias2(args.path, options.aliases);
1400
+ if (aliased) return null;
1401
+ return { path: args.path, namespace: "vfs" };
1402
+ });
1403
+ build2.onResolve({ filter: /^\./ }, (args) => {
1404
+ const fromEntry = args.namespace !== "vfs" && args.importer === project.entry;
1405
+ if (args.namespace !== "vfs" && !fromEntry) return null;
1406
+ const resolved = resolveRelativePath(args.importer, args.path);
1407
+ return { path: resolved, namespace: "vfs" };
1408
+ });
1409
+ build2.onLoad({ filter: /.*/, namespace: "vfs" }, (args) => {
1410
+ const normalPath = normalizeVFSPath(args.path);
1411
+ const filePath = findFile(project, normalPath);
1412
+ if (!filePath) {
1413
+ throw new Error(`File not found in VFS: ${args.path}`);
1414
+ }
1415
+ const file = project.files.get(filePath);
1416
+ return {
1417
+ contents: file.content,
1418
+ loader: inferLoader(filePath, file.language)
1419
+ };
1420
+ });
1421
+ }
1422
+ };
1423
+ }
1424
+
1425
+ // src/vfs/project.ts
1426
+ function createProjectFromFiles(files, id = crypto.randomUUID()) {
1427
+ const fileMap = /* @__PURE__ */ new Map();
1428
+ for (const file of files) {
1429
+ fileMap.set(file.path, file);
1430
+ }
1431
+ return { id, entry: resolveEntry(fileMap), files: fileMap };
1432
+ }
1433
+ function resolveEntry(files) {
1434
+ const paths = Array.from(files.keys());
1435
+ const mainFile = paths.find((p) => /\bmain\.(tsx?|jsx?)$/.test(p));
1436
+ if (mainFile) return mainFile;
1437
+ const indexFile = paths.find((p) => /\bindex\.(tsx?|jsx?)$/.test(p));
1438
+ if (indexFile) return indexFile;
1439
+ const firstTsx = paths.find((p) => /\.(tsx|jsx)$/.test(p));
1440
+ if (firstTsx) return firstTsx;
1441
+ return paths[0] || "main.tsx";
1442
+ }
1443
+ function detectMainFile(language) {
1444
+ switch (language) {
1445
+ case "tsx":
1446
+ case "typescript":
1447
+ return "main.tsx";
1448
+ case "jsx":
1449
+ case "javascript":
1450
+ return "main.jsx";
1451
+ case "ts":
1452
+ return "main.ts";
1453
+ case "js":
1454
+ return "main.js";
1455
+ default:
1456
+ return "main.tsx";
1457
+ }
1458
+ }
1459
+ function createSingleFileProject(content, entry = "main.tsx", id = "inline") {
1460
+ return {
1461
+ id,
1462
+ entry,
1463
+ files: /* @__PURE__ */ new Map([[entry, { path: entry, content }]])
1464
+ };
1465
+ }
1466
+
1477
1467
  // src/compiler.ts
1478
1468
  var esbuildInitialized = false;
1479
1469
  var esbuildInitPromise = null;
1480
- var DEFAULT_ESBUILD_WASM_URL = "https://unpkg.com/esbuild-wasm/esbuild.wasm";
1470
+ var DEFAULT_ESBUILD_WASM_URL = `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`;
1481
1471
  async function initEsbuild(urlOverrides) {
1482
1472
  if (esbuildInitialized) return;
1483
1473
  if (esbuildInitPromise) return esbuildInitPromise;
@@ -1509,18 +1499,18 @@ function hashContent(content) {
1509
1499
  }
1510
1500
  async function createCompiler(options) {
1511
1501
  await initEsbuild(options.urlOverrides);
1512
- const { image: imageSpec, proxyUrl, cdnBaseUrl: cdnBaseUrl3, widgetCdnBaseUrl } = options;
1513
- if (cdnBaseUrl3) {
1514
- setCdnBaseUrl(cdnBaseUrl3);
1502
+ const { image: imageSpec, proxyUrl, cdnBaseUrl: cdnBaseUrl2, widgetCdnBaseUrl } = options;
1503
+ if (cdnBaseUrl2) {
1504
+ setCdnBaseUrl(cdnBaseUrl2);
1515
1505
  }
1516
1506
  if (widgetCdnBaseUrl) {
1517
- setCdnBaseUrl2(widgetCdnBaseUrl);
1518
- } else if (cdnBaseUrl3) {
1519
- setCdnBaseUrl2(cdnBaseUrl3);
1507
+ setCdnBaseUrl(widgetCdnBaseUrl);
1508
+ } else if (cdnBaseUrl2) {
1509
+ setCdnBaseUrl(cdnBaseUrl2);
1520
1510
  }
1521
1511
  const registry = getImageRegistry();
1522
1512
  await registry.preload(imageSpec);
1523
- const proxy = createHttpServiceProxy(proxyUrl);
1513
+ const proxy = createHttpProxy(proxyUrl);
1524
1514
  return new PatchworkCompiler(proxy, registry);
1525
1515
  }
1526
1516
  var PatchworkCompiler = class {
@@ -1943,6 +1933,8 @@ var SyncEngineImpl = class {
1943
1933
  this.basePath = config.basePath ?? "";
1944
1934
  this.startRemoteWatch();
1945
1935
  }
1936
+ local;
1937
+ remote;
1946
1938
  status = "idle";
1947
1939
  intervalId;
1948
1940
  listeners = /* @__PURE__ */ new Map();
@@ -2248,7 +2240,7 @@ function openDB() {
2248
2240
  const request = indexedDB.open(DB_NAME, DB_VERSION);
2249
2241
  request.onerror = () => reject(request.error);
2250
2242
  request.onsuccess = () => resolve(request.result);
2251
- request.onupgradeneeded = (event) => {
2243
+ request.onupgradeneeded = (_event) => {
2252
2244
  const db = request.result;
2253
2245
  if (!db.objectStoreNames.contains(FILES_STORE)) {
2254
2246
  db.createObjectStore(FILES_STORE);
@@ -2274,6 +2266,7 @@ var IndexedDBBackend = class {
2274
2266
  constructor(prefix = "vfs") {
2275
2267
  this.prefix = prefix;
2276
2268
  }
2269
+ prefix;
2277
2270
  key(path) {
2278
2271
  return `${this.prefix}:${normalizePath2(path)}`;
2279
2272
  }
@@ -2444,6 +2437,7 @@ var HttpBackend = class {
2444
2437
  constructor(config) {
2445
2438
  this.config = config;
2446
2439
  }
2440
+ config;
2447
2441
  async readFile(path) {
2448
2442
  const res = await fetch(this.url(path));
2449
2443
  if (!res.ok) throw new Error(`ENOENT: ${path}`);
@@ -2489,37 +2483,46 @@ var HttpBackend = class {
2489
2483
  const res = await fetch(this.url(path), { method: "HEAD" });
2490
2484
  return res.ok;
2491
2485
  }
2492
- watch(path, callback) {
2486
+ watch(_path, callback) {
2493
2487
  const controller = new AbortController();
2494
- this.startWatch(path, callback, controller.signal);
2488
+ this.startPoll(callback, controller.signal);
2495
2489
  return () => controller.abort();
2496
2490
  }
2497
- async startWatch(path, callback, signal) {
2498
- try {
2499
- const res = await fetch(this.url("", { watch: path }), { signal });
2500
- if (!res.ok) return;
2501
- const reader = res.body?.getReader();
2502
- if (!reader) return;
2503
- const decoder = new TextDecoder();
2504
- let buffer = "";
2505
- while (!signal.aborted) {
2506
- const { done, value } = await reader.read();
2507
- if (done) break;
2508
- buffer += decoder.decode(value, { stream: true });
2509
- const lines = buffer.split("\n");
2510
- buffer = lines.pop() ?? "";
2511
- for (const line of lines) {
2512
- if (line.startsWith("data: ")) {
2513
- try {
2514
- const event = JSON.parse(line.slice(6));
2515
- callback(event.type, event.path);
2516
- } catch {
2517
- }
2518
- }
2491
+ async startPoll(callback, signal) {
2492
+ const intervalMs = this.config.pollIntervalMs ?? 7e3;
2493
+ let since = (/* @__PURE__ */ new Date()).toISOString();
2494
+ const poll = async () => {
2495
+ if (signal.aborted) return;
2496
+ if (typeof document !== "undefined" && document.visibilityState !== "visible") return;
2497
+ const pollStart = (/* @__PURE__ */ new Date()).toISOString();
2498
+ try {
2499
+ const res = await fetch(this.url("", { since }), { signal });
2500
+ if (!res.ok) return;
2501
+ const changes = await res.json();
2502
+ since = pollStart;
2503
+ for (const change of changes) {
2504
+ callback("update", change.path);
2519
2505
  }
2506
+ } catch {
2520
2507
  }
2521
- } catch {
2508
+ };
2509
+ await poll();
2510
+ if (signal.aborted) return;
2511
+ const timer = setInterval(() => void poll(), intervalMs);
2512
+ const onVisibilityChange = () => {
2513
+ if (typeof document !== "undefined" && document.visibilityState === "visible") {
2514
+ void poll();
2515
+ }
2516
+ };
2517
+ if (typeof document !== "undefined") {
2518
+ document.addEventListener("visibilitychange", onVisibilityChange);
2522
2519
  }
2520
+ signal.addEventListener("abort", () => {
2521
+ clearInterval(timer);
2522
+ if (typeof document !== "undefined") {
2523
+ document.removeEventListener("visibilitychange", onVisibilityChange);
2524
+ }
2525
+ });
2523
2526
  }
2524
2527
  url(path, params) {
2525
2528
  const baseUrl = this.config.baseUrl.replace(/\/+$/, "");
@@ -2547,6 +2550,7 @@ var VFSStore = class {
2547
2550
  }
2548
2551
  }
2549
2552
  }
2553
+ provider;
2550
2554
  local;
2551
2555
  syncEngine;
2552
2556
  root;
@@ -2699,6 +2703,7 @@ var VFSStore = class {
2699
2703
  };
2700
2704
  export {
2701
2705
  CompileOptionsSchema,
2706
+ DEFAULT_CDN_BASE,
2702
2707
  DEFAULT_CLI_IMAGE_CONFIG,
2703
2708
  DEFAULT_IMAGE_CONFIG,
2704
2709
  DEV_SANDBOX,
@@ -2717,8 +2722,8 @@ export {
2717
2722
  cdnTransformPlugin,
2718
2723
  createCompiler,
2719
2724
  createFieldAccessProxy,
2720
- createHttpServiceProxy,
2721
- createIframeServiceProxy,
2725
+ createHttpProxy,
2726
+ createIframeProxy,
2722
2727
  createImageRegistry,
2723
2728
  createProjectFromFiles,
2724
2729
  createSingleFileProject,
@@ -2730,14 +2735,19 @@ export {
2730
2735
  generateImportMap,
2731
2736
  generateNamespaceGlobals,
2732
2737
  getCdnBaseUrl,
2738
+ getCommonExports,
2733
2739
  getImageRegistry,
2734
2740
  injectNamespaceGlobals,
2741
+ isBareImport,
2735
2742
  loadImage,
2743
+ matchAlias,
2736
2744
  mountEmbedded,
2737
2745
  mountIframe,
2738
2746
  parseImageConfig,
2739
2747
  parseImageSpec,
2748
+ parseImportPath,
2740
2749
  parseManifest,
2750
+ parsePackageSpec,
2741
2751
  reloadEmbedded,
2742
2752
  reloadIframe,
2743
2753
  removeNamespaceGlobals,
@@ -2745,6 +2755,7 @@ export {
2745
2755
  safeParseImageConfig,
2746
2756
  safeParseManifest,
2747
2757
  setCdnBaseUrl,
2758
+ toEsmShUrl,
2748
2759
  vfsPlugin
2749
2760
  };
2750
2761
  //# sourceMappingURL=index.js.map