@aprovan/patchwork-compiler 0.1.0 → 0.1.2-dev.1a732c5

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.
@@ -0,0 +1,835 @@
1
+ import { z } from 'zod';
2
+ import { Plugin } from 'esbuild-wasm';
3
+
4
+ interface VirtualFile {
5
+ path: string;
6
+ content: string;
7
+ language?: string;
8
+ note?: string;
9
+ encoding?: "utf8" | "base64";
10
+ }
11
+ interface VirtualProject {
12
+ id: string;
13
+ entry: string;
14
+ files: Map<string, VirtualFile>;
15
+ }
16
+
17
+ /**
18
+ * Core types for the Patchwork compiler
19
+ */
20
+ type Platform = 'browser' | 'cli';
21
+ interface Manifest$1 {
22
+ name: string;
23
+ version: string;
24
+ description?: string;
25
+ platform: Platform;
26
+ image: string;
27
+ inputs?: Record<string, InputSpec>;
28
+ services?: string[];
29
+ packages?: Record<string, string>;
30
+ }
31
+ interface InputSpec {
32
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array';
33
+ default?: unknown;
34
+ required?: boolean;
35
+ description?: string;
36
+ }
37
+ interface CompileOptions {
38
+ }
39
+ interface CompiledWidget {
40
+ /** Compiled ESM code */
41
+ code: string;
42
+ /** Content hash for caching */
43
+ hash: string;
44
+ /** Original manifest */
45
+ manifest: Manifest$1;
46
+ /** Source map (if generated) */
47
+ sourceMap?: string;
48
+ }
49
+ type MountMode = 'embedded' | 'iframe';
50
+ interface MountOptions {
51
+ /** Target DOM element to mount into */
52
+ target: HTMLElement;
53
+ /** Mount mode: embedded (trusted) or iframe (sandboxed) */
54
+ mode: MountMode;
55
+ /** CSP sandbox attributes for iframe mode */
56
+ sandbox?: string[];
57
+ /** Initial props/inputs to pass to widget */
58
+ inputs?: Record<string, unknown>;
59
+ }
60
+ interface MountedWidget {
61
+ /** Unique mount ID */
62
+ id: string;
63
+ /** The compiled widget */
64
+ widget: CompiledWidget;
65
+ /** Mount mode used */
66
+ mode: MountMode;
67
+ /** Target element */
68
+ target: HTMLElement;
69
+ /** Iframe element (if mode is 'iframe') */
70
+ iframe?: HTMLIFrameElement;
71
+ /** Inputs used for the mount (if provided) */
72
+ inputs?: Record<string, unknown>;
73
+ /** Sandbox attributes used for iframe mode (if provided) */
74
+ sandbox?: string[];
75
+ /** Unmount function */
76
+ unmount: () => void;
77
+ }
78
+ interface ImageConfig$1 {
79
+ platform: Platform;
80
+ esbuild?: {
81
+ target?: string;
82
+ format?: 'esm' | 'cjs' | 'iife';
83
+ jsx?: 'automatic' | 'transform' | 'preserve';
84
+ jsxFactory?: string;
85
+ jsxFragment?: string;
86
+ };
87
+ framework?: {
88
+ /** Map of package names to window global names (e.g., { react: 'React' }) */
89
+ globals?: Record<string, string>;
90
+ /** CDN URLs to preload before widget execution */
91
+ preload?: string[];
92
+ /** Dependency version overrides for CDN packages (e.g., { react: '18' }) */
93
+ deps?: Record<string, string>;
94
+ };
95
+ /** Import path aliases (e.g., { '@/components/ui/*': '@packagedcn/react' }) */
96
+ aliases?: Record<string, string>;
97
+ }
98
+ /**
99
+ * Mount function signature provided by images to handle widget mounting.
100
+ * Takes the widget module exports and mounts it to the container.
101
+ *
102
+ * @param module - The widget module with its exports (default, mount, render, game, etc.)
103
+ * @param container - The DOM element to mount into
104
+ * @param inputs - Props/inputs to pass to the widget
105
+ * @returns A cleanup function to unmount, or void
106
+ */
107
+ type ImageMountFn = (module: Record<string, unknown>, container: HTMLElement, inputs: Record<string, unknown>) => void | (() => void) | Promise<void | (() => void)>;
108
+ interface LoadedImage {
109
+ /** Package name */
110
+ name: string;
111
+ /** Resolved version */
112
+ version: string;
113
+ /** Browser-importable module URL for this image (when loaded from CDN/local HTTP) */
114
+ moduleUrl?: string;
115
+ /** Package configuration */
116
+ config: ImageConfig$1;
117
+ /** Package dependencies */
118
+ dependencies: Record<string, string>;
119
+ /** Setup function (if available) */
120
+ setup?: (root: HTMLElement) => void | Promise<void>;
121
+ /** CSS content (if available) */
122
+ css?: string;
123
+ /**
124
+ * Mount function to handle widget mounting.
125
+ * Each image defines how it expects widgets to export their entry points.
126
+ * Falls back to default mounting behavior if not provided.
127
+ */
128
+ mount?: ImageMountFn;
129
+ }
130
+ interface CompilerOptions {
131
+ /** Image package to use (e.g., '@aprovan/patchwork-image-shadcnshadcn') */
132
+ image: string;
133
+ /** Backend proxy URL for service calls */
134
+ proxyUrl: string;
135
+ /** Base URL for CDN (default: 'https://esm.sh'). Used for loading image packages. */
136
+ cdnBaseUrl?: string;
137
+ /** Base URL for widget imports (default: same as cdnBaseUrl). Used for transforming imports in widget code. */
138
+ widgetCdnBaseUrl?: string;
139
+ /**
140
+ * URL overrides for bundled assets/packages.
141
+ * Keys are asset identifiers (e.g., 'esbuild-wasm/esbuild.wasm'), values are local URLs.
142
+ * Use this to bundle assets locally for offline support or improved performance.
143
+ */
144
+ urlOverrides?: Record<string, string>;
145
+ }
146
+ interface Compiler {
147
+ /** Pre-load an image package */
148
+ preloadImage(spec: string): Promise<void>;
149
+ /** Check if an image is loaded */
150
+ isImageLoaded(spec: string): boolean;
151
+ /** Compile widget source to ESM */
152
+ compile(source: string | VirtualProject, manifest: Manifest$1, options?: CompileOptions): Promise<CompiledWidget>;
153
+ /** Mount a compiled widget to the DOM */
154
+ mount(widget: CompiledWidget, options: MountOptions): Promise<MountedWidget>;
155
+ /** Unmount a mounted widget */
156
+ unmount(mounted: MountedWidget): void;
157
+ /** Hot reload a mounted widget */
158
+ reload(mounted: MountedWidget, source: string | VirtualProject, manifest: Manifest$1): Promise<void>;
159
+ }
160
+ /**
161
+ * Service proxy interface - abstracts service calls to backend
162
+ *
163
+ * The compiler provides the interface; actual implementation (e.g., UTCP, MCP)
164
+ * is handled by the runtime/backend.
165
+ */
166
+ interface ServiceProxy {
167
+ call(namespace: string, procedure: string, args: unknown[]): Promise<unknown>;
168
+ }
169
+ /**
170
+ * Service call handler - function that handles calls for a specific namespace
171
+ */
172
+ type ServiceCallHandler = (procedure: string, args: unknown[]) => Promise<unknown>;
173
+ /**
174
+ * Global interface definition for code generation
175
+ *
176
+ * Describes available global namespaces and their methods that widgets can call.
177
+ * Used during compilation to generate proper TypeScript declarations.
178
+ */
179
+ interface GlobalInterfaceDefinition {
180
+ /** Namespace name (e.g., 'git', 'github') */
181
+ name: string;
182
+ /** Methods available on this namespace (supports nested paths like 'repos.list') */
183
+ methods: string[];
184
+ /** Optional TypeScript type definitions for methods */
185
+ types?: string;
186
+ }
187
+ type BridgeMessageType = 'service-call' | 'service-result' | 'error';
188
+ interface BridgeMessage {
189
+ type: BridgeMessageType;
190
+ id: string;
191
+ payload: unknown;
192
+ }
193
+ interface ServiceCallPayload {
194
+ namespace: string;
195
+ procedure: string;
196
+ args: unknown[];
197
+ }
198
+ interface ServiceResultPayload {
199
+ result?: unknown;
200
+ error?: string;
201
+ }
202
+
203
+ /**
204
+ * Create a compiler instance
205
+ */
206
+ declare function createCompiler(options: CompilerOptions): Promise<Compiler>;
207
+
208
+ /**
209
+ * Zod schemas for Patchwork compiler types
210
+ *
211
+ * These schemas validate:
212
+ * - ImageConfig from package.json patchwork field
213
+ * - Widget manifests
214
+ * - Input specifications
215
+ */
216
+
217
+ declare const PlatformSchema: z.ZodEnum<["browser", "cli"]>;
218
+ declare const EsbuildConfigSchema: z.ZodOptional<z.ZodObject<{
219
+ target: z.ZodOptional<z.ZodString>;
220
+ format: z.ZodOptional<z.ZodEnum<["esm", "cjs", "iife"]>>;
221
+ jsx: z.ZodOptional<z.ZodEnum<["automatic", "transform", "preserve"]>>;
222
+ jsxFactory: z.ZodOptional<z.ZodString>;
223
+ jsxFragment: z.ZodOptional<z.ZodString>;
224
+ }, "strict", z.ZodTypeAny, {
225
+ jsx?: "automatic" | "transform" | "preserve" | undefined;
226
+ target?: string | undefined;
227
+ format?: "esm" | "cjs" | "iife" | undefined;
228
+ jsxFactory?: string | undefined;
229
+ jsxFragment?: string | undefined;
230
+ }, {
231
+ jsx?: "automatic" | "transform" | "preserve" | undefined;
232
+ target?: string | undefined;
233
+ format?: "esm" | "cjs" | "iife" | undefined;
234
+ jsxFactory?: string | undefined;
235
+ jsxFragment?: string | undefined;
236
+ }>>;
237
+ declare const ImageConfigSchema: z.ZodObject<{
238
+ platform: z.ZodEnum<["browser", "cli"]>;
239
+ dependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
240
+ esbuild: z.ZodOptional<z.ZodObject<{
241
+ target: z.ZodOptional<z.ZodString>;
242
+ format: z.ZodOptional<z.ZodEnum<["esm", "cjs", "iife"]>>;
243
+ jsx: z.ZodOptional<z.ZodEnum<["automatic", "transform", "preserve"]>>;
244
+ jsxFactory: z.ZodOptional<z.ZodString>;
245
+ jsxFragment: z.ZodOptional<z.ZodString>;
246
+ }, "strict", z.ZodTypeAny, {
247
+ jsx?: "automatic" | "transform" | "preserve" | undefined;
248
+ target?: string | undefined;
249
+ format?: "esm" | "cjs" | "iife" | undefined;
250
+ jsxFactory?: string | undefined;
251
+ jsxFragment?: string | undefined;
252
+ }, {
253
+ jsx?: "automatic" | "transform" | "preserve" | undefined;
254
+ target?: string | undefined;
255
+ format?: "esm" | "cjs" | "iife" | undefined;
256
+ jsxFactory?: string | undefined;
257
+ jsxFragment?: string | undefined;
258
+ }>>;
259
+ framework: z.ZodOptional<z.ZodObject<{
260
+ globals: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
261
+ preload: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
262
+ deps: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
263
+ }, "strict", z.ZodTypeAny, {
264
+ globals?: Record<string, string> | undefined;
265
+ preload?: string[] | undefined;
266
+ deps?: Record<string, string> | undefined;
267
+ }, {
268
+ globals?: Record<string, string> | undefined;
269
+ preload?: string[] | undefined;
270
+ deps?: Record<string, string> | undefined;
271
+ }>>;
272
+ aliases: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
273
+ }, "strict", z.ZodTypeAny, {
274
+ platform: "browser" | "cli";
275
+ dependencies?: Record<string, string> | undefined;
276
+ esbuild?: {
277
+ jsx?: "automatic" | "transform" | "preserve" | undefined;
278
+ target?: string | undefined;
279
+ format?: "esm" | "cjs" | "iife" | undefined;
280
+ jsxFactory?: string | undefined;
281
+ jsxFragment?: string | undefined;
282
+ } | undefined;
283
+ framework?: {
284
+ globals?: Record<string, string> | undefined;
285
+ preload?: string[] | undefined;
286
+ deps?: Record<string, string> | undefined;
287
+ } | undefined;
288
+ aliases?: Record<string, string> | undefined;
289
+ }, {
290
+ platform: "browser" | "cli";
291
+ dependencies?: Record<string, string> | undefined;
292
+ esbuild?: {
293
+ jsx?: "automatic" | "transform" | "preserve" | undefined;
294
+ target?: string | undefined;
295
+ format?: "esm" | "cjs" | "iife" | undefined;
296
+ jsxFactory?: string | undefined;
297
+ jsxFragment?: string | undefined;
298
+ } | undefined;
299
+ framework?: {
300
+ globals?: Record<string, string> | undefined;
301
+ preload?: string[] | undefined;
302
+ deps?: Record<string, string> | undefined;
303
+ } | undefined;
304
+ aliases?: Record<string, string> | undefined;
305
+ }>;
306
+ type ImageConfig = z.infer<typeof ImageConfigSchema>;
307
+ declare const InputSpecSchema: z.ZodObject<{
308
+ type: z.ZodEnum<["string", "number", "boolean", "object", "array"]>;
309
+ default: z.ZodOptional<z.ZodUnknown>;
310
+ required: z.ZodOptional<z.ZodBoolean>;
311
+ description: z.ZodOptional<z.ZodString>;
312
+ }, "strip", z.ZodTypeAny, {
313
+ type: "string" | "number" | "boolean" | "object" | "array";
314
+ default?: unknown;
315
+ required?: boolean | undefined;
316
+ description?: string | undefined;
317
+ }, {
318
+ type: "string" | "number" | "boolean" | "object" | "array";
319
+ default?: unknown;
320
+ required?: boolean | undefined;
321
+ description?: string | undefined;
322
+ }>;
323
+ declare const ManifestSchema: z.ZodObject<{
324
+ name: z.ZodString;
325
+ version: z.ZodString;
326
+ description: z.ZodOptional<z.ZodString>;
327
+ platform: z.ZodEnum<["browser", "cli"]>;
328
+ image: z.ZodString;
329
+ inputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
330
+ type: z.ZodEnum<["string", "number", "boolean", "object", "array"]>;
331
+ default: z.ZodOptional<z.ZodUnknown>;
332
+ required: z.ZodOptional<z.ZodBoolean>;
333
+ description: z.ZodOptional<z.ZodString>;
334
+ }, "strip", z.ZodTypeAny, {
335
+ type: "string" | "number" | "boolean" | "object" | "array";
336
+ default?: unknown;
337
+ required?: boolean | undefined;
338
+ description?: string | undefined;
339
+ }, {
340
+ type: "string" | "number" | "boolean" | "object" | "array";
341
+ default?: unknown;
342
+ required?: boolean | undefined;
343
+ description?: string | undefined;
344
+ }>>>;
345
+ services: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
346
+ packages: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
347
+ }, "strip", z.ZodTypeAny, {
348
+ platform: "browser" | "cli";
349
+ name: string;
350
+ version: string;
351
+ image: string;
352
+ description?: string | undefined;
353
+ inputs?: Record<string, {
354
+ type: "string" | "number" | "boolean" | "object" | "array";
355
+ default?: unknown;
356
+ required?: boolean | undefined;
357
+ description?: string | undefined;
358
+ }> | undefined;
359
+ services?: string[] | undefined;
360
+ packages?: Record<string, string> | undefined;
361
+ }, {
362
+ platform: "browser" | "cli";
363
+ name: string;
364
+ version: string;
365
+ image: string;
366
+ description?: string | undefined;
367
+ inputs?: Record<string, {
368
+ type: "string" | "number" | "boolean" | "object" | "array";
369
+ default?: unknown;
370
+ required?: boolean | undefined;
371
+ description?: string | undefined;
372
+ }> | undefined;
373
+ services?: string[] | undefined;
374
+ packages?: Record<string, string> | undefined;
375
+ }>;
376
+ type Manifest = z.infer<typeof ManifestSchema>;
377
+ declare const CompileOptionsSchema: z.ZodOptional<z.ZodObject<{
378
+ typescript: z.ZodOptional<z.ZodBoolean>;
379
+ }, "strict", z.ZodTypeAny, {
380
+ typescript?: boolean | undefined;
381
+ }, {
382
+ typescript?: boolean | undefined;
383
+ }>>;
384
+ declare const MountModeSchema: z.ZodEnum<["embedded", "iframe"]>;
385
+ declare const MountOptionsSchema: z.ZodObject<{
386
+ target: z.ZodType<HTMLElement, z.ZodTypeDef, HTMLElement>;
387
+ mode: z.ZodEnum<["embedded", "iframe"]>;
388
+ sandbox: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
389
+ inputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
390
+ }, "strip", z.ZodTypeAny, {
391
+ target: HTMLElement;
392
+ mode: "embedded" | "iframe";
393
+ inputs?: Record<string, unknown> | undefined;
394
+ sandbox?: string[] | undefined;
395
+ }, {
396
+ target: HTMLElement;
397
+ mode: "embedded" | "iframe";
398
+ inputs?: Record<string, unknown> | undefined;
399
+ sandbox?: string[] | undefined;
400
+ }>;
401
+ /**
402
+ * Parse and validate ImageConfig from package.json patchwork field
403
+ *
404
+ * @param data - Raw data from package.json patchwork field
405
+ * @returns Validated ImageConfig
406
+ * @throws z.ZodError if validation fails
407
+ */
408
+ declare function parseImageConfig(data: unknown): ImageConfig;
409
+ /**
410
+ * Safely parse ImageConfig, returning null on failure
411
+ */
412
+ declare function safeParseImageConfig(data: unknown): ImageConfig | null;
413
+ /**
414
+ * Parse and validate widget manifest
415
+ */
416
+ declare function parseManifest(data: unknown): Manifest;
417
+ /**
418
+ * Safely parse manifest, returning null on failure
419
+ */
420
+ declare function safeParseManifest(data: unknown): Manifest | null;
421
+ declare const DEFAULT_IMAGE_CONFIG: ImageConfig;
422
+ declare const DEFAULT_CLI_IMAGE_CONFIG: ImageConfig;
423
+
424
+ /**
425
+ * Image loader - fetches and loads image packages from CDN or local
426
+ *
427
+ * Images must be installed as npm packages or available on CDN.
428
+ */
429
+
430
+ /**
431
+ * Set the CDN base URL for image loading
432
+ */
433
+ declare function setCdnBaseUrl(url: string): void;
434
+ /**
435
+ * Get the current CDN base URL
436
+ */
437
+ declare function getCdnBaseUrl(): string;
438
+ interface ImagePackageJson {
439
+ name: string;
440
+ version: string;
441
+ main?: string;
442
+ dependencies?: Record<string, string>;
443
+ patchwork?: unknown;
444
+ }
445
+ /**
446
+ * Parse image specifier into name and version
447
+ */
448
+ declare function parseImageSpec(spec: string): {
449
+ name: string;
450
+ version?: string;
451
+ };
452
+ /**
453
+ * Fetch package.json from CDN
454
+ */
455
+ declare function fetchPackageJson(packageName: string, version?: string): Promise<ImagePackageJson>;
456
+ /**
457
+ * Load an image package
458
+ *
459
+ * Priority:
460
+ * 1. Try to resolve locally (require.resolve for installed packages)
461
+ * 2. Fetch from CDN
462
+ *
463
+ * Images must be explicitly installed or available on CDN.
464
+ */
465
+ declare function loadImage(spec: string): Promise<LoadedImage>;
466
+
467
+ /**
468
+ * Image registry - manages loaded images
469
+ */
470
+
471
+ /**
472
+ * Registry of loaded images
473
+ */
474
+ declare class ImageRegistry {
475
+ private images;
476
+ private loading;
477
+ /**
478
+ * Get a loaded image by spec
479
+ */
480
+ get(spec: string): LoadedImage | undefined;
481
+ /**
482
+ * Check if an image is loaded
483
+ */
484
+ has(spec: string): boolean;
485
+ /**
486
+ * Load an image (or return cached)
487
+ */
488
+ load(spec: string): Promise<LoadedImage>;
489
+ /**
490
+ * Preload an image
491
+ */
492
+ preload(spec: string): Promise<void>;
493
+ /**
494
+ * Clear a specific image from cache
495
+ */
496
+ clear(spec: string): void;
497
+ /**
498
+ * Clear all cached images
499
+ */
500
+ clearAll(): void;
501
+ /**
502
+ * Get all loaded image names
503
+ */
504
+ getLoadedNames(): string[];
505
+ }
506
+ /**
507
+ * Get the global image registry
508
+ */
509
+ declare function getImageRegistry(): ImageRegistry;
510
+ /**
511
+ * Create a new isolated image registry
512
+ */
513
+ declare function createImageRegistry(): ImageRegistry;
514
+
515
+ /**
516
+ * CDN transform - converts bare imports to CDN URLs (esm.sh)
517
+ */
518
+
519
+ interface CdnTransformOptions {
520
+ /** Map of package names to versions */
521
+ packages?: Record<string, string>;
522
+ /** Additional external packages */
523
+ external?: string[];
524
+ /** Use bundled versions from esm.sh (adds ?bundle) */
525
+ bundle?: boolean;
526
+ /** Packages to inject from window globals instead of CDN */
527
+ globals?: Record<string, string>;
528
+ /** Dependency version overrides for CDN URLs (e.g., { react: '18' }) */
529
+ deps?: Record<string, string>;
530
+ /** Import path aliases (e.g., { '@/components/ui/*': '@packagedcn/react' }) */
531
+ aliases?: Record<string, string>;
532
+ }
533
+ /**
534
+ * Create an esbuild plugin that transforms bare imports to CDN URLs
535
+ * and injects globals for specified packages (like React)
536
+ */
537
+ declare function cdnTransformPlugin(options?: CdnTransformOptions): Plugin;
538
+ /**
539
+ * Generate import map for CDN dependencies
540
+ */
541
+ declare function generateImportMap(packages: Record<string, string>): Record<string, string>;
542
+
543
+ interface VFSPluginOptions {
544
+ aliases?: Record<string, string>;
545
+ }
546
+ declare function vfsPlugin(project: VirtualProject, options?: VFSPluginOptions): Plugin;
547
+
548
+ /**
549
+ * File statistics matching Node.js fs.Stats subset
550
+ */
551
+ interface FileStats {
552
+ size: number;
553
+ mtime: Date;
554
+ isFile(): boolean;
555
+ isDirectory(): boolean;
556
+ }
557
+ /**
558
+ * Directory entry matching Node.js fs.Dirent
559
+ */
560
+ interface DirEntry {
561
+ name: string;
562
+ isFile(): boolean;
563
+ isDirectory(): boolean;
564
+ }
565
+ type WatchEventType = "create" | "update" | "delete";
566
+ type WatchCallback = (event: WatchEventType, path: string) => void;
567
+ /**
568
+ * FSProvider - Node.js fs/promises compatible interface
569
+ * All paths are relative to provider root
570
+ */
571
+ interface FSProvider {
572
+ readFile(path: string, encoding?: "utf8" | "base64"): Promise<string>;
573
+ writeFile(path: string, content: string): Promise<void>;
574
+ unlink(path: string): Promise<void>;
575
+ stat(path: string): Promise<FileStats>;
576
+ mkdir(path: string, options?: {
577
+ recursive?: boolean;
578
+ }): Promise<void>;
579
+ readdir(path: string): Promise<DirEntry[]>;
580
+ rmdir(path: string, options?: {
581
+ recursive?: boolean;
582
+ }): Promise<void>;
583
+ exists(path: string): Promise<boolean>;
584
+ watch?(path: string, callback: WatchCallback): () => void;
585
+ }
586
+ /**
587
+ * Change record for sync operations
588
+ */
589
+ interface ChangeRecord {
590
+ path: string;
591
+ type: WatchEventType;
592
+ mtime: Date;
593
+ checksum?: string;
594
+ }
595
+ type ConflictStrategy = "local-wins" | "remote-wins" | "newest-wins" | "manual";
596
+ interface SyncResult {
597
+ pushed: number;
598
+ pulled: number;
599
+ conflicts: ConflictRecord[];
600
+ }
601
+ interface ConflictRecord {
602
+ path: string;
603
+ localMtime: Date;
604
+ remoteMtime: Date;
605
+ resolved?: "local" | "remote";
606
+ }
607
+ type SyncStatus = "idle" | "syncing" | "error";
608
+ type SyncEventType = "change" | "conflict" | "error" | "status";
609
+ type SyncEventCallback<T = unknown> = (data: T) => void;
610
+
611
+ declare class IndexedDBBackend implements FSProvider {
612
+ private prefix;
613
+ constructor(prefix?: string);
614
+ private key;
615
+ readFile(path: string): Promise<string>;
616
+ writeFile(path: string, content: string): Promise<void>;
617
+ unlink(path: string): Promise<void>;
618
+ stat(path: string): Promise<FileStats>;
619
+ mkdir(path: string, options?: {
620
+ recursive?: boolean;
621
+ }): Promise<void>;
622
+ readdir(path: string): Promise<DirEntry[]>;
623
+ rmdir(path: string, options?: {
624
+ recursive?: boolean;
625
+ }): Promise<void>;
626
+ exists(path: string): Promise<boolean>;
627
+ private dirExists;
628
+ }
629
+
630
+ interface HttpBackendConfig {
631
+ baseUrl: string;
632
+ }
633
+ /**
634
+ * HTTP-based FSProvider for connecting to remote servers (e.g., stitchery)
635
+ */
636
+ declare class HttpBackend implements FSProvider {
637
+ private config;
638
+ constructor(config: HttpBackendConfig);
639
+ readFile(path: string): Promise<string>;
640
+ writeFile(path: string, content: string): Promise<void>;
641
+ unlink(path: string): Promise<void>;
642
+ stat(path: string): Promise<FileStats>;
643
+ mkdir(path: string, options?: {
644
+ recursive?: boolean;
645
+ }): Promise<void>;
646
+ readdir(path: string): Promise<DirEntry[]>;
647
+ rmdir(path: string, options?: {
648
+ recursive?: boolean;
649
+ }): Promise<void>;
650
+ exists(path: string): Promise<boolean>;
651
+ watch(path: string, callback: WatchCallback): () => void;
652
+ private startWatch;
653
+ private url;
654
+ }
655
+
656
+ declare function createProjectFromFiles(files: VirtualFile[], id?: string): VirtualProject;
657
+ declare function resolveEntry(files: Map<string, VirtualFile>): string;
658
+ declare function detectMainFile(language?: string): string;
659
+ declare function createSingleFileProject(content: string, entry?: string, id?: string): VirtualProject;
660
+
661
+ interface VFSStoreOptions {
662
+ root?: string;
663
+ sync?: boolean;
664
+ conflictStrategy?: ConflictStrategy;
665
+ autoSyncIntervalMs?: number;
666
+ }
667
+ declare class VFSStore {
668
+ private provider;
669
+ private local?;
670
+ private syncEngine?;
671
+ private root;
672
+ constructor(provider: FSProvider, options?: VFSStoreOptions);
673
+ readFile(path: string, encoding?: "utf8" | "base64"): Promise<string>;
674
+ writeFile(path: string, content: string): Promise<void>;
675
+ unlink(path: string): Promise<void>;
676
+ stat(path: string): Promise<FileStats>;
677
+ mkdir(path: string, options?: {
678
+ recursive?: boolean;
679
+ }): Promise<void>;
680
+ readdir(path: string): Promise<DirEntry[]>;
681
+ rmdir(path: string, options?: {
682
+ recursive?: boolean;
683
+ }): Promise<void>;
684
+ exists(path: string): Promise<boolean>;
685
+ listFiles(prefix?: string): Promise<string[]>;
686
+ loadProject(id: string): Promise<VirtualProject | null>;
687
+ saveProject(project: VirtualProject): Promise<void>;
688
+ watch(path: string, callback: WatchCallback): () => void;
689
+ sync(): Promise<SyncResult>;
690
+ on<T extends SyncEventType>(event: T, callback: SyncEventCallback<T extends "change" ? ChangeRecord : T extends "conflict" ? ConflictRecord : T extends "error" ? Error : SyncStatus>): () => void;
691
+ private remotePath;
692
+ private walkFiles;
693
+ }
694
+
695
+ /**
696
+ * Embedded mount mode - mounts widgets directly in the DOM
697
+ *
698
+ * For trusted widgets that need full window access.
699
+ */
700
+
701
+ /**
702
+ * Mount a widget in embedded mode (direct DOM injection)
703
+ */
704
+ declare function mountEmbedded(widget: CompiledWidget, options: MountOptions, image: LoadedImage | null, proxy: ServiceProxy): Promise<MountedWidget>;
705
+ /**
706
+ * Hot reload an embedded widget
707
+ */
708
+ declare function reloadEmbedded(mounted: MountedWidget, widget: CompiledWidget, image: LoadedImage | null, proxy: ServiceProxy): Promise<MountedWidget>;
709
+
710
+ /**
711
+ * Iframe mount mode - mounts widgets in sandboxed iframes
712
+ *
713
+ * For untrusted widgets that need isolation.
714
+ */
715
+
716
+ /**
717
+ * Development sandbox attributes - includes allow-same-origin
718
+ *
719
+ * allow-same-origin is required when:
720
+ * - Fetching modules from the parent origin (e.g., /_local-packages/ in dev)
721
+ * - Using import maps that reference parent-relative URLs
722
+ * - Accessing the parent's CDN proxy
723
+ *
724
+ * Note: This does NOT allow the iframe to access parent's DOM or cookies,
725
+ * but it does allow same-origin network requests.
726
+ *
727
+ * WARNING: Combining allow-scripts + allow-same-origin allows the iframe to
728
+ * escape its sandbox. Only use in development or when hosting on a separate subdomain.
729
+ */
730
+ declare const DEV_SANDBOX: string[];
731
+ /**
732
+ * Mount a widget in iframe mode (sandboxed)
733
+ */
734
+ declare function mountIframe(widget: CompiledWidget, options: MountOptions, image: LoadedImage | null, proxy: ServiceProxy): Promise<MountedWidget>;
735
+ /**
736
+ * Hot reload an iframe widget
737
+ */
738
+ declare function reloadIframe(mounted: MountedWidget, widget: CompiledWidget, image: LoadedImage | null, proxy: ServiceProxy): Promise<MountedWidget>;
739
+ /**
740
+ * Dispose the shared bridge (call on app shutdown)
741
+ */
742
+ declare function disposeIframeBridge(): void;
743
+
744
+ /**
745
+ * Service bridge - handles communication between widgets and service proxy
746
+ */
747
+
748
+ /**
749
+ * Create a service proxy that calls the backend via HTTP
750
+ */
751
+ declare function createHttpServiceProxy(proxyUrl: string): ServiceProxy;
752
+ /**
753
+ * Creates a proxy that enables fluent method chaining for dynamic field access.
754
+ *
755
+ * This allows arbitrary nested property access that resolves to a callable function,
756
+ * supporting patterns like `proxy.foo()`, `proxy.foo.bar()`, `proxy.bar.baz.qux()`.
757
+ *
758
+ * Used to create global namespace objects that proxy calls to a service backend.
759
+ */
760
+ declare function createFieldAccessProxy<T = unknown>(namespace: string, handler: (namespace: string, methodPath: string, ...args: T[]) => Promise<unknown>): Record<string, (...args: T[]) => Promise<unknown>>;
761
+ /**
762
+ * Create namespace globals that proxy calls to a service proxy
763
+ *
764
+ * Creates dynamic proxy objects for each namespace that support arbitrary
765
+ * nested method calls. This replaces the old static method registration.
766
+ *
767
+ * @param services - Array of service names (e.g., ['git', 'github'])
768
+ * @param proxy - The service proxy to forward calls to
769
+ * @returns Record of namespace names to proxy objects
770
+ *
771
+ * @example
772
+ * ```typescript
773
+ * const namespaces = generateNamespaceGlobals(['git', 'github'], proxy);
774
+ * // namespaces.git.status() calls proxy.call('git', 'status', [])
775
+ * // namespaces.github.repos.list_for_user({ username: 'x' })
776
+ * // calls proxy.call('github', 'repos.list_for_user', [{ username: 'x' }])
777
+ * ```
778
+ */
779
+ declare function generateNamespaceGlobals(services: string[], proxy: ServiceProxy): Record<string, unknown>;
780
+ /**
781
+ * Inject namespace globals into a window object
782
+ */
783
+ declare function injectNamespaceGlobals(target: Window | typeof globalThis, namespaces: Record<string, unknown>): void;
784
+ /**
785
+ * Remove namespace globals from a window object
786
+ */
787
+ declare function removeNamespaceGlobals(target: Window | typeof globalThis, namespaceNames: string[]): void;
788
+ /**
789
+ * Extract unique namespace names from services array
790
+ */
791
+ declare function extractNamespaces(services: string[]): string[];
792
+ /**
793
+ * Parent-side bridge for iframe communication
794
+ *
795
+ * Listens for postMessage events from iframes and proxies service calls.
796
+ */
797
+ declare class ParentBridge {
798
+ private proxy;
799
+ private pendingCalls;
800
+ private iframes;
801
+ private messageHandler;
802
+ constructor(proxy: ServiceProxy);
803
+ /**
804
+ * Register an iframe to receive messages from
805
+ */
806
+ registerIframe(iframe: HTMLIFrameElement): void;
807
+ /**
808
+ * Unregister an iframe
809
+ */
810
+ unregisterIframe(iframe: HTMLIFrameElement): void;
811
+ /**
812
+ * Handle incoming messages from iframes
813
+ */
814
+ private handleMessage;
815
+ /**
816
+ * Dispose the bridge
817
+ */
818
+ dispose(): void;
819
+ }
820
+ /**
821
+ * Child-side bridge for iframe communication
822
+ *
823
+ * Creates a service proxy that sends postMessage to parent.
824
+ */
825
+ declare function createIframeServiceProxy(): ServiceProxy;
826
+ /**
827
+ * Generate the bridge script to inject into iframes
828
+ *
829
+ * Creates a self-contained script that sets up:
830
+ * 1. Message handling for service results from parent
831
+ * 2. Dynamic proxy objects for each namespace that support arbitrary nested calls
832
+ */
833
+ declare function generateIframeBridgeScript(services: string[]): string;
834
+
835
+ export { type BridgeMessage, type BridgeMessageType, type CdnTransformOptions, type ChangeRecord, type CompileOptions, CompileOptionsSchema, type CompiledWidget, type Compiler, type CompilerOptions, DEFAULT_CLI_IMAGE_CONFIG, DEFAULT_IMAGE_CONFIG, DEV_SANDBOX, EsbuildConfigSchema, type GlobalInterfaceDefinition, HttpBackend, type HttpBackendConfig, type ImageConfig$1 as ImageConfig, ImageConfigSchema, type ImageMountFn, ImageRegistry, IndexedDBBackend, type InputSpec, InputSpecSchema, type LoadedImage, type Manifest$1 as Manifest, ManifestSchema, type MountMode, MountModeSchema, type MountOptions, MountOptionsSchema, type MountedWidget, ParentBridge, type Platform, PlatformSchema, type ServiceCallHandler, type ServiceCallPayload, type ServiceProxy, type ServiceResultPayload, type VFSPluginOptions, VFSStore, type VFSStoreOptions, type VirtualFile, type VirtualProject, type WatchCallback, type WatchEventType, cdnTransformPlugin, createCompiler, createFieldAccessProxy, createHttpServiceProxy, createIframeServiceProxy, createImageRegistry, createProjectFromFiles, createSingleFileProject, detectMainFile, disposeIframeBridge, extractNamespaces, fetchPackageJson, generateIframeBridgeScript, generateImportMap, generateNamespaceGlobals, getCdnBaseUrl, getImageRegistry, injectNamespaceGlobals, loadImage, mountEmbedded, mountIframe, parseImageConfig, parseImageSpec, parseManifest, reloadEmbedded, reloadIframe, removeNamespaceGlobals, resolveEntry, safeParseImageConfig, safeParseManifest, setCdnBaseUrl, vfsPlugin };