@aprovan/patchwork 0.1.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 (225) hide show
  1. package/.eslintrc.json +22 -0
  2. package/.github/workflows/publish.yml +41 -0
  3. package/.prettierignore +17 -0
  4. package/LICENSE +373 -0
  5. package/README.md +15 -0
  6. package/apps/chat/.utcp_config.json +14 -0
  7. package/apps/chat/.working/widgets/27060b91-a2a5-4272-b243-6eb904bd4070/main.tsx +107 -0
  8. package/apps/chat/index.html +17 -0
  9. package/apps/chat/node_modules/.bin/autoprefixer +17 -0
  10. package/apps/chat/node_modules/.bin/browserslist +17 -0
  11. package/apps/chat/node_modules/.bin/conc +17 -0
  12. package/apps/chat/node_modules/.bin/concurrently +17 -0
  13. package/apps/chat/node_modules/.bin/copilot-proxy +17 -0
  14. package/apps/chat/node_modules/.bin/jiti +17 -0
  15. package/apps/chat/node_modules/.bin/tailwind +17 -0
  16. package/apps/chat/node_modules/.bin/tailwindcss +17 -0
  17. package/apps/chat/node_modules/.bin/tsc +17 -0
  18. package/apps/chat/node_modules/.bin/tsserver +17 -0
  19. package/apps/chat/node_modules/.bin/tsx +17 -0
  20. package/apps/chat/node_modules/.bin/vite +17 -0
  21. package/apps/chat/package.json +55 -0
  22. package/apps/chat/postcss.config.js +6 -0
  23. package/apps/chat/src/App.tsx +7 -0
  24. package/apps/chat/src/components/ui/avatar.tsx +48 -0
  25. package/apps/chat/src/components/ui/badge.tsx +36 -0
  26. package/apps/chat/src/components/ui/button.tsx +56 -0
  27. package/apps/chat/src/components/ui/card.tsx +86 -0
  28. package/apps/chat/src/components/ui/collapsible.tsx +9 -0
  29. package/apps/chat/src/components/ui/dialog.tsx +60 -0
  30. package/apps/chat/src/components/ui/input.tsx +25 -0
  31. package/apps/chat/src/components/ui/scroll-area.tsx +46 -0
  32. package/apps/chat/src/index.css +190 -0
  33. package/apps/chat/src/lib/utils.ts +6 -0
  34. package/apps/chat/src/main.tsx +10 -0
  35. package/apps/chat/src/pages/ChatPage.tsx +460 -0
  36. package/apps/chat/tailwind.config.js +71 -0
  37. package/apps/chat/tsconfig.json +25 -0
  38. package/apps/chat/vite.config.ts +26 -0
  39. package/package.json +35 -0
  40. package/packages/bobbin/node_modules/.bin/esbuild +14 -0
  41. package/packages/bobbin/node_modules/.bin/jiti +17 -0
  42. package/packages/bobbin/node_modules/.bin/tsc +17 -0
  43. package/packages/bobbin/node_modules/.bin/tsserver +17 -0
  44. package/packages/bobbin/node_modules/.bin/tsup +17 -0
  45. package/packages/bobbin/node_modules/.bin/tsup-node +17 -0
  46. package/packages/bobbin/node_modules/.bin/tsx +17 -0
  47. package/packages/bobbin/package.json +30 -0
  48. package/packages/bobbin/src/Bobbin.tsx +89 -0
  49. package/packages/bobbin/src/components/EditPanel/EditPanel.tsx +376 -0
  50. package/packages/bobbin/src/components/EditPanel/controls/ColorPicker.tsx +138 -0
  51. package/packages/bobbin/src/components/EditPanel/controls/QuickSelectDropdown.tsx +142 -0
  52. package/packages/bobbin/src/components/EditPanel/controls/SliderInput.tsx +94 -0
  53. package/packages/bobbin/src/components/EditPanel/controls/SpacingControl.tsx +285 -0
  54. package/packages/bobbin/src/components/EditPanel/controls/ToggleGroup.tsx +37 -0
  55. package/packages/bobbin/src/components/EditPanel/controls/TokenDropdown.tsx +33 -0
  56. package/packages/bobbin/src/components/EditPanel/sections/AnnotationSection.tsx +136 -0
  57. package/packages/bobbin/src/components/EditPanel/sections/BackgroundSection.tsx +79 -0
  58. package/packages/bobbin/src/components/EditPanel/sections/EffectsSection.tsx +85 -0
  59. package/packages/bobbin/src/components/EditPanel/sections/LayoutSection.tsx +224 -0
  60. package/packages/bobbin/src/components/EditPanel/sections/SectionWrapper.tsx +57 -0
  61. package/packages/bobbin/src/components/EditPanel/sections/SizeSection.tsx +166 -0
  62. package/packages/bobbin/src/components/EditPanel/sections/SpacingSection.tsx +69 -0
  63. package/packages/bobbin/src/components/EditPanel/sections/TypographySection.tsx +148 -0
  64. package/packages/bobbin/src/components/Inspector/Inspector.tsx +221 -0
  65. package/packages/bobbin/src/components/Overlay/ControlHandles.tsx +572 -0
  66. package/packages/bobbin/src/components/Overlay/MarginPaddingOverlay.tsx +229 -0
  67. package/packages/bobbin/src/components/Overlay/SelectionOverlay.tsx +73 -0
  68. package/packages/bobbin/src/components/Pill/Pill.tsx +155 -0
  69. package/packages/bobbin/src/components/ThemeToggle/ThemeToggle.tsx +72 -0
  70. package/packages/bobbin/src/core/changeSerializer.ts +139 -0
  71. package/packages/bobbin/src/core/useBobbin.ts +399 -0
  72. package/packages/bobbin/src/core/useChangeTracker.ts +186 -0
  73. package/packages/bobbin/src/core/useClipboard.ts +21 -0
  74. package/packages/bobbin/src/core/useElementSelection.ts +146 -0
  75. package/packages/bobbin/src/index.ts +46 -0
  76. package/packages/bobbin/src/tokens/borders.ts +19 -0
  77. package/packages/bobbin/src/tokens/colors.ts +150 -0
  78. package/packages/bobbin/src/tokens/index.ts +37 -0
  79. package/packages/bobbin/src/tokens/shadows.ts +10 -0
  80. package/packages/bobbin/src/tokens/spacing.ts +37 -0
  81. package/packages/bobbin/src/tokens/typography.ts +51 -0
  82. package/packages/bobbin/src/types.ts +157 -0
  83. package/packages/bobbin/src/utils/animation.ts +40 -0
  84. package/packages/bobbin/src/utils/dom.ts +36 -0
  85. package/packages/bobbin/src/utils/selectors.ts +76 -0
  86. package/packages/bobbin/tsconfig.json +10 -0
  87. package/packages/bobbin/tsup.config.ts +10 -0
  88. package/packages/compiler/node_modules/.bin/esbuild +17 -0
  89. package/packages/compiler/node_modules/.bin/jiti +17 -0
  90. package/packages/compiler/node_modules/.bin/tsc +17 -0
  91. package/packages/compiler/node_modules/.bin/tsserver +17 -0
  92. package/packages/compiler/node_modules/.bin/tsup +17 -0
  93. package/packages/compiler/node_modules/.bin/tsup-node +17 -0
  94. package/packages/compiler/node_modules/.bin/tsx +17 -0
  95. package/packages/compiler/package.json +38 -0
  96. package/packages/compiler/src/compiler.ts +258 -0
  97. package/packages/compiler/src/images/index.ts +13 -0
  98. package/packages/compiler/src/images/loader.ts +234 -0
  99. package/packages/compiler/src/images/registry.ts +112 -0
  100. package/packages/compiler/src/index.ts +141 -0
  101. package/packages/compiler/src/mount/bridge.ts +399 -0
  102. package/packages/compiler/src/mount/embedded.ts +306 -0
  103. package/packages/compiler/src/mount/iframe.ts +433 -0
  104. package/packages/compiler/src/mount/index.ts +18 -0
  105. package/packages/compiler/src/schemas.ts +169 -0
  106. package/packages/compiler/src/transforms/cdn.ts +411 -0
  107. package/packages/compiler/src/transforms/index.ts +4 -0
  108. package/packages/compiler/src/transforms/vfs.ts +138 -0
  109. package/packages/compiler/src/types.ts +233 -0
  110. package/packages/compiler/src/vfs/backends/indexeddb.ts +66 -0
  111. package/packages/compiler/src/vfs/backends/local-fs.ts +41 -0
  112. package/packages/compiler/src/vfs/backends/s3.ts +60 -0
  113. package/packages/compiler/src/vfs/index.ts +11 -0
  114. package/packages/compiler/src/vfs/project.ts +56 -0
  115. package/packages/compiler/src/vfs/store.ts +53 -0
  116. package/packages/compiler/src/vfs/types.ts +20 -0
  117. package/packages/compiler/tsconfig.json +8 -0
  118. package/packages/compiler/tsup.config.ts +14 -0
  119. package/packages/editor/node_modules/.bin/jiti +17 -0
  120. package/packages/editor/node_modules/.bin/tsc +17 -0
  121. package/packages/editor/node_modules/.bin/tsserver +17 -0
  122. package/packages/editor/node_modules/.bin/tsup +17 -0
  123. package/packages/editor/node_modules/.bin/tsup-node +17 -0
  124. package/packages/editor/node_modules/.bin/tsx +17 -0
  125. package/packages/editor/package.json +45 -0
  126. package/packages/editor/src/components/CodeBlockExtension.tsx +190 -0
  127. package/packages/editor/src/components/CodePreview.tsx +344 -0
  128. package/packages/editor/src/components/MarkdownEditor.tsx +270 -0
  129. package/packages/editor/src/components/ServicesInspector.tsx +118 -0
  130. package/packages/editor/src/components/edit/EditHistory.tsx +89 -0
  131. package/packages/editor/src/components/edit/EditModal.tsx +236 -0
  132. package/packages/editor/src/components/edit/FileTree.tsx +144 -0
  133. package/packages/editor/src/components/edit/api.ts +100 -0
  134. package/packages/editor/src/components/edit/index.ts +6 -0
  135. package/packages/editor/src/components/edit/types.ts +53 -0
  136. package/packages/editor/src/components/edit/useEditSession.ts +164 -0
  137. package/packages/editor/src/components/index.ts +5 -0
  138. package/packages/editor/src/index.ts +72 -0
  139. package/packages/editor/src/lib/code-extractor.ts +210 -0
  140. package/packages/editor/src/lib/diff.ts +308 -0
  141. package/packages/editor/src/lib/index.ts +4 -0
  142. package/packages/editor/src/lib/utils.ts +6 -0
  143. package/packages/editor/src/lib/vfs.ts +106 -0
  144. package/packages/editor/tsconfig.json +10 -0
  145. package/packages/editor/tsup.config.ts +10 -0
  146. package/packages/images/ink/node_modules/.bin/jiti +17 -0
  147. package/packages/images/ink/node_modules/.bin/tsc +17 -0
  148. package/packages/images/ink/node_modules/.bin/tsserver +17 -0
  149. package/packages/images/ink/node_modules/.bin/tsup +17 -0
  150. package/packages/images/ink/node_modules/.bin/tsup-node +17 -0
  151. package/packages/images/ink/node_modules/.bin/tsx +17 -0
  152. package/packages/images/ink/package.json +53 -0
  153. package/packages/images/ink/src/index.ts +48 -0
  154. package/packages/images/ink/src/runner.ts +331 -0
  155. package/packages/images/ink/src/setup.ts +123 -0
  156. package/packages/images/ink/tsconfig.json +10 -0
  157. package/packages/images/ink/tsup.config.ts +11 -0
  158. package/packages/images/shadcn/node_modules/.bin/jiti +17 -0
  159. package/packages/images/shadcn/node_modules/.bin/tsc +17 -0
  160. package/packages/images/shadcn/node_modules/.bin/tsserver +17 -0
  161. package/packages/images/shadcn/node_modules/.bin/tsup +17 -0
  162. package/packages/images/shadcn/node_modules/.bin/tsup-node +17 -0
  163. package/packages/images/shadcn/node_modules/.bin/tsx +17 -0
  164. package/packages/images/shadcn/package.json +82 -0
  165. package/packages/images/shadcn/src/html.ts +341 -0
  166. package/packages/images/shadcn/src/index.ts +37 -0
  167. package/packages/images/shadcn/src/setup.ts +287 -0
  168. package/packages/images/shadcn/tsconfig.json +9 -0
  169. package/packages/images/shadcn/tsup.config.ts +13 -0
  170. package/packages/images/vanilla/node_modules/.bin/jiti +17 -0
  171. package/packages/images/vanilla/node_modules/.bin/tsc +17 -0
  172. package/packages/images/vanilla/node_modules/.bin/tsserver +17 -0
  173. package/packages/images/vanilla/node_modules/.bin/tsup +17 -0
  174. package/packages/images/vanilla/node_modules/.bin/tsup-node +17 -0
  175. package/packages/images/vanilla/node_modules/.bin/tsx +17 -0
  176. package/packages/images/vanilla/package.json +35 -0
  177. package/packages/images/vanilla/src/index.ts +7 -0
  178. package/packages/images/vanilla/src/setup.ts +6 -0
  179. package/packages/images/vanilla/tsconfig.json +9 -0
  180. package/packages/images/vanilla/tsup.config.ts +10 -0
  181. package/packages/patchwork/node_modules/.bin/jiti +17 -0
  182. package/packages/patchwork/node_modules/.bin/tsc +17 -0
  183. package/packages/patchwork/node_modules/.bin/tsserver +17 -0
  184. package/packages/patchwork/node_modules/.bin/tsup +17 -0
  185. package/packages/patchwork/node_modules/.bin/tsup-node +17 -0
  186. package/packages/patchwork/node_modules/.bin/tsx +17 -0
  187. package/packages/patchwork/package.json +27 -0
  188. package/packages/patchwork/src/index.ts +15 -0
  189. package/packages/patchwork/src/services/index.ts +11 -0
  190. package/packages/patchwork/src/services/proxy.ts +213 -0
  191. package/packages/patchwork/src/services/types.ts +28 -0
  192. package/packages/patchwork/src/types.ts +116 -0
  193. package/packages/patchwork/tsconfig.json +8 -0
  194. package/packages/patchwork/tsup.config.ts +14 -0
  195. package/packages/stitchery/node_modules/.bin/jiti +17 -0
  196. package/packages/stitchery/node_modules/.bin/tsc +17 -0
  197. package/packages/stitchery/node_modules/.bin/tsserver +17 -0
  198. package/packages/stitchery/node_modules/.bin/tsup +17 -0
  199. package/packages/stitchery/node_modules/.bin/tsup-node +17 -0
  200. package/packages/stitchery/node_modules/.bin/tsx +17 -0
  201. package/packages/stitchery/package.json +40 -0
  202. package/packages/stitchery/src/cli.ts +116 -0
  203. package/packages/stitchery/src/index.ts +16 -0
  204. package/packages/stitchery/src/prompts.ts +326 -0
  205. package/packages/stitchery/src/server/index.ts +365 -0
  206. package/packages/stitchery/src/server/local-packages.ts +91 -0
  207. package/packages/stitchery/src/server/routes.ts +122 -0
  208. package/packages/stitchery/src/server/services.ts +382 -0
  209. package/packages/stitchery/src/server/vfs-routes.ts +142 -0
  210. package/packages/stitchery/src/types.ts +59 -0
  211. package/packages/stitchery/tsconfig.json +13 -0
  212. package/packages/stitchery/tsup.config.ts +15 -0
  213. package/packages/utcp/node_modules/.bin/jiti +17 -0
  214. package/packages/utcp/node_modules/.bin/tsc +17 -0
  215. package/packages/utcp/node_modules/.bin/tsserver +17 -0
  216. package/packages/utcp/node_modules/.bin/tsup +17 -0
  217. package/packages/utcp/node_modules/.bin/tsup-node +17 -0
  218. package/packages/utcp/node_modules/.bin/tsx +17 -0
  219. package/packages/utcp/package.json +38 -0
  220. package/packages/utcp/src/index.ts +153 -0
  221. package/packages/utcp/tsconfig.json +8 -0
  222. package/packages/utcp/tsup.config.ts +12 -0
  223. package/pnpm-workspace.yaml +3 -0
  224. package/tsconfig.json +18 -0
  225. package/turbo.json +23 -0
@@ -0,0 +1,36 @@
1
+ export function applyStyleToElement(
2
+ el: HTMLElement,
3
+ property: string,
4
+ value: string,
5
+ ): void {
6
+ el.style.setProperty(property, value);
7
+ }
8
+
9
+ export function enableContentEditable(el: HTMLElement, enabled: boolean): void {
10
+ if (enabled) {
11
+ el.contentEditable = 'true';
12
+ // Recursively enable for text nodes
13
+ const textElements = el.querySelectorAll(
14
+ 'p, span, h1, h2, h3, h4, h5, h6, a, li, td, th, label, div',
15
+ );
16
+ textElements.forEach((child) => {
17
+ if (child instanceof HTMLElement && child.childNodes.length > 0) {
18
+ // Only make editable if it has direct text content
19
+ for (const node of child.childNodes) {
20
+ if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) {
21
+ child.contentEditable = 'true';
22
+ break;
23
+ }
24
+ }
25
+ }
26
+ });
27
+ } else {
28
+ el.contentEditable = 'false';
29
+ const textElements = el.querySelectorAll('[contenteditable="true"]');
30
+ textElements.forEach((child) => {
31
+ if (child instanceof HTMLElement) {
32
+ child.contentEditable = 'false';
33
+ }
34
+ });
35
+ }
36
+ }
@@ -0,0 +1,76 @@
1
+ export function generateId(): string {
2
+ return Math.random().toString(36).substring(2, 15);
3
+ }
4
+
5
+ export function getElementPath(el: HTMLElement): string {
6
+ const path: string[] = [];
7
+ let current: HTMLElement | null = el;
8
+
9
+ while (current && current !== document.body) {
10
+ let selector = current.tagName.toLowerCase();
11
+
12
+ if (current.id) {
13
+ selector = `#${current.id}`;
14
+ path.unshift(selector);
15
+ break;
16
+ }
17
+
18
+ // Add nth-child for uniqueness
19
+ const parent = current.parentElement;
20
+ if (parent) {
21
+ const siblings = Array.from(parent.children).filter(
22
+ (c) => c.tagName === current!.tagName,
23
+ );
24
+ if (siblings.length > 1) {
25
+ const index = siblings.indexOf(current) + 1;
26
+ selector += `:nth-of-type(${index})`;
27
+ }
28
+ }
29
+
30
+ path.unshift(selector);
31
+ current = current.parentElement;
32
+ }
33
+
34
+ return path.join(' > ');
35
+ }
36
+
37
+ export function getElementXPath(el: HTMLElement): string {
38
+ const parts: string[] = [];
39
+ let current: HTMLElement | null = el;
40
+
41
+ while (
42
+ current &&
43
+ current !== document.body &&
44
+ current !== document.documentElement
45
+ ) {
46
+ let part = current.tagName.toLowerCase();
47
+
48
+ // If element has an id, use it as anchor
49
+ if (current.id) {
50
+ parts.unshift(`//*[@id="${current.id}"]`);
51
+ break;
52
+ }
53
+
54
+ // Calculate position among siblings of same tag
55
+ const parent = current.parentElement;
56
+ if (parent) {
57
+ const siblings = Array.from(parent.children).filter(
58
+ (c) => c.tagName === current!.tagName,
59
+ );
60
+ if (siblings.length > 1) {
61
+ const index = siblings.indexOf(current) + 1;
62
+ part += `[${index}]`;
63
+ }
64
+ }
65
+
66
+ parts.unshift(part);
67
+ current = current.parentElement;
68
+ }
69
+
70
+ // If we didn't find an id anchor, start from root
71
+ if (!parts[0]?.startsWith('//*[@id')) {
72
+ parts.unshift('');
73
+ }
74
+
75
+ return parts.join('/') || '//' + el.tagName.toLowerCase();
76
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "jsx": "react-jsx"
7
+ },
8
+ "include": ["src/**/*"],
9
+ "exclude": ["node_modules", "dist"]
10
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['esm'],
6
+ dts: true,
7
+ clean: true,
8
+ external: ['react', 'react-dom'],
9
+ treeshake: true,
10
+ });
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/esbuild-wasm@0.27.3/node_modules/esbuild-wasm/bin/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/esbuild-wasm@0.27.3/node_modules/esbuild-wasm/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/esbuild-wasm@0.27.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/esbuild-wasm@0.27.3/node_modules/esbuild-wasm/bin/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/esbuild-wasm@0.27.3/node_modules/esbuild-wasm/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/esbuild-wasm@0.27.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../esbuild-wasm/bin/esbuild" "$@"
15
+ else
16
+ exec node "$basedir/../esbuild-wasm/bin/esbuild" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/bin/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/jiti@1.21.7/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/bin/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/jiti@1.21.7/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/bin/jiti.js" "$@"
15
+ else
16
+ exec node "$basedir/../../../../node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/bin/jiti.js" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
15
+ else
16
+ exec node "$basedir/../typescript/bin/tsc" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
15
+ else
16
+ exec node "$basedir/../typescript/bin/tsserver" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/dist/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/dist/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../tsup/dist/cli-default.js" "$@"
15
+ else
16
+ exec node "$basedir/../tsup/dist/cli-default.js" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/dist/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/dist/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../tsup/dist/cli-node.js" "$@"
15
+ else
16
+ exec node "$basedir/../tsup/dist/cli-node.js" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/runner/work/patchwork/patchwork/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/cli.mjs" "$@"
15
+ else
16
+ exec node "$basedir/../../../../node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/cli.mjs" "$@"
17
+ fi
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@aprovan/patchwork-compiler",
3
+ "version": "0.1.0",
4
+ "description": "Patchwork compiler - JSX→ESM compilation, image loading, DOM mounting",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "check-types": "tsc --noEmit",
23
+ "dev": "tsup --watch",
24
+ "typecheck": "tsc --noEmit"
25
+ },
26
+ "dependencies": {
27
+ "esbuild-wasm": "^0.27.2",
28
+ "zod": "^3.23.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^22.10.5",
32
+ "tsup": "^8.3.5",
33
+ "typescript": "^5.7.3"
34
+ },
35
+ "engines": {
36
+ "node": ">=20.0.0"
37
+ }
38
+ }
@@ -0,0 +1,258 @@
1
+ import * as esbuild from 'esbuild-wasm';
2
+ import type {
3
+ Compiler,
4
+ CompilerOptions,
5
+ CompileOptions,
6
+ CompiledWidget,
7
+ Manifest,
8
+ MountedWidget,
9
+ MountOptions,
10
+ ServiceProxy,
11
+ } from './types.js';
12
+ import type { VirtualProject } from './vfs/types.js';
13
+ import { createSingleFileProject } from './vfs/project.js';
14
+ import { getImageRegistry } from './images/registry.js';
15
+ import { setCdnBaseUrl as setImageCdnBaseUrl } from './images/loader.js';
16
+ import { setCdnBaseUrl as setTransformCdnBaseUrl } from './transforms/cdn.js';
17
+ import { cdnTransformPlugin } from './transforms/cdn.js';
18
+ import { vfsPlugin } from './transforms/vfs.js';
19
+ import { createHttpServiceProxy } from './mount/bridge.js';
20
+ import { mountEmbedded, reloadEmbedded } from './mount/embedded.js';
21
+ import { mountIframe, reloadIframe } from './mount/iframe.js';
22
+
23
+ // Track esbuild initialization
24
+ let esbuildInitialized = false;
25
+ let esbuildInitPromise: Promise<void> | null = null;
26
+
27
+ /**
28
+ * Initialize esbuild-wasm (must be called before using esbuild)
29
+ */
30
+ async function initEsbuild(): Promise<void> {
31
+ if (esbuildInitialized) return;
32
+ if (esbuildInitPromise) return esbuildInitPromise;
33
+
34
+ esbuildInitPromise = (async () => {
35
+ try {
36
+ await esbuild.initialize({
37
+ wasmURL: 'https://unpkg.com/esbuild-wasm/esbuild.wasm',
38
+ });
39
+ esbuildInitialized = true;
40
+ } catch (error) {
41
+ // If already initialized, that's fine
42
+ if (error instanceof Error && error.message.includes('initialized')) {
43
+ esbuildInitialized = true;
44
+ } else {
45
+ throw error;
46
+ }
47
+ }
48
+ })();
49
+
50
+ return esbuildInitPromise;
51
+ }
52
+
53
+ /**
54
+ * Generate a content hash for caching
55
+ */
56
+ function hashContent(content: string): string {
57
+ // Use Web Crypto API for browser compatibility
58
+ const encoder = new TextEncoder();
59
+ const data = encoder.encode(content);
60
+ // Simple hash for cache key (not cryptographic)
61
+ let hash = 0;
62
+ for (let i = 0; i < data.length; i++) {
63
+ hash = ((hash << 5) - hash + (data[i] ?? 0)) | 0;
64
+ }
65
+ return Math.abs(hash).toString(16).padStart(8, '0');
66
+ }
67
+
68
+ /**
69
+ * Create a compiler instance
70
+ */
71
+ export async function createCompiler(
72
+ options: CompilerOptions,
73
+ ): Promise<Compiler> {
74
+ // Initialize esbuild-wasm
75
+ await initEsbuild();
76
+
77
+ const { image: imageSpec, proxyUrl, cdnBaseUrl, widgetCdnBaseUrl } = options;
78
+
79
+ // Set CDN base URLs (can be different for image loading vs widget imports)
80
+ if (cdnBaseUrl) {
81
+ setImageCdnBaseUrl(cdnBaseUrl);
82
+ }
83
+ // Widget imports use widgetCdnBaseUrl if provided, otherwise fall back to cdnBaseUrl or default
84
+ if (widgetCdnBaseUrl) {
85
+ setTransformCdnBaseUrl(widgetCdnBaseUrl);
86
+ } else if (cdnBaseUrl) {
87
+ setTransformCdnBaseUrl(cdnBaseUrl);
88
+ }
89
+
90
+ const registry = getImageRegistry();
91
+
92
+ // Pre-load the initial image
93
+ await registry.preload(imageSpec);
94
+
95
+ // Create service proxy
96
+ const proxy: ServiceProxy = createHttpServiceProxy(proxyUrl);
97
+
98
+ return new PatchworkCompiler(proxy, registry);
99
+ }
100
+
101
+ /**
102
+ * Patchwork compiler implementation
103
+ */
104
+ class PatchworkCompiler implements Compiler {
105
+ private proxy: ServiceProxy;
106
+ private registry: ReturnType<typeof getImageRegistry>;
107
+
108
+ constructor(
109
+ proxy: ServiceProxy,
110
+ registry: ReturnType<typeof getImageRegistry>,
111
+ ) {
112
+ this.proxy = proxy;
113
+ this.registry = registry;
114
+ }
115
+
116
+ /**
117
+ * Pre-load an image package
118
+ */
119
+ async preloadImage(spec: string): Promise<void> {
120
+ await this.registry.preload(spec);
121
+ }
122
+
123
+ /**
124
+ * Check if an image is loaded
125
+ */
126
+ isImageLoaded(spec: string): boolean {
127
+ return this.registry.has(spec);
128
+ }
129
+
130
+ /**
131
+ * Compile widget source to ESM
132
+ */
133
+ async compile(
134
+ source: string | VirtualProject,
135
+ manifest: Manifest,
136
+ _options: CompileOptions = {},
137
+ ): Promise<CompiledWidget> {
138
+ // Normalize input to VirtualProject (entry defined by project, defaults to main.tsx)
139
+ const project =
140
+ typeof source === 'string' ? createSingleFileProject(source) : source;
141
+
142
+ // Infer loader from entry file extension
143
+ const entryExt = project.entry.split('.').pop();
144
+ const loader = entryExt === 'ts' || entryExt === 'tsx' ? 'tsx' : 'jsx';
145
+
146
+ // Get image from registry based on manifest
147
+ const image = this.registry.get(manifest.image) || null;
148
+
149
+ // Get config from image (with proper typing)
150
+ const esbuildConfig = image?.config.esbuild || {};
151
+ const frameworkConfig = image?.config.framework || {};
152
+
153
+ const target = esbuildConfig.target || 'es2020';
154
+ const format = esbuildConfig.format || 'esm';
155
+ const jsx = esbuildConfig.jsx ?? 'automatic';
156
+
157
+ // Collect all packages (image deps + manifest packages)
158
+ const packages: Record<string, string> = {
159
+ ...(image?.dependencies || {}),
160
+ ...(manifest.packages || {}),
161
+ };
162
+
163
+ const globals = frameworkConfig.globals || {};
164
+
165
+ // Get dependency version overrides from image config (e.g., { react: '18' })
166
+ const deps = frameworkConfig.deps || {};
167
+
168
+ // Get import path aliases from image config (e.g., { '@/components/ui/*': '@packagedcn/react' })
169
+ const aliases = image?.config.aliases || {};
170
+
171
+ // Get entry file content
172
+ const entryFile = project.files.get(project.entry);
173
+ if (!entryFile) {
174
+ throw new Error(`Entry file not found: ${project.entry}`);
175
+ }
176
+
177
+ // Build with esbuild using image-provided configuration
178
+ const result = await esbuild.build({
179
+ stdin: {
180
+ contents: entryFile.content,
181
+ loader,
182
+ sourcefile: project.entry,
183
+ },
184
+ bundle: true,
185
+ format,
186
+ target,
187
+ platform: manifest.platform === 'cli' ? 'node' : 'browser',
188
+ jsx,
189
+ ...(esbuildConfig.jsxFactory
190
+ ? { jsxFactory: esbuildConfig.jsxFactory }
191
+ : {}),
192
+ ...(esbuildConfig.jsxFragment
193
+ ? { jsxFragment: esbuildConfig.jsxFragment }
194
+ : {}),
195
+ write: false,
196
+ sourcemap: 'inline',
197
+ plugins: [
198
+ vfsPlugin(project, { aliases }),
199
+ cdnTransformPlugin({
200
+ packages,
201
+ globals,
202
+ deps,
203
+ aliases,
204
+ }),
205
+ ],
206
+ });
207
+
208
+ const code = result.outputFiles?.[0]?.text || '';
209
+ const hash = hashContent(code);
210
+
211
+ return {
212
+ code,
213
+ hash,
214
+ manifest,
215
+ };
216
+ }
217
+
218
+ /**
219
+ * Mount a compiled widget to the DOM
220
+ */
221
+ async mount(
222
+ widget: CompiledWidget,
223
+ options: MountOptions,
224
+ ): Promise<MountedWidget> {
225
+ const image = this.registry.get(widget.manifest.image) || null;
226
+ if (options.mode === 'iframe') {
227
+ return mountIframe(widget, options, image, this.proxy);
228
+ }
229
+ return mountEmbedded(widget, options, image, this.proxy);
230
+ }
231
+
232
+ /**
233
+ * Unmount a mounted widget
234
+ */
235
+ unmount(mounted: MountedWidget): void {
236
+ mounted.unmount();
237
+ }
238
+
239
+ /**
240
+ * Hot reload a mounted widget
241
+ */
242
+ async reload(
243
+ mounted: MountedWidget,
244
+ source: string | VirtualProject,
245
+ manifest: Manifest,
246
+ ): Promise<void> {
247
+ // Compile new version
248
+ const widget = await this.compile(source, manifest);
249
+ const image = this.registry.get(widget.manifest.image) || null;
250
+
251
+ // Reload based on mode
252
+ if (mounted.mode === 'iframe') {
253
+ await reloadIframe(mounted, widget, image, this.proxy);
254
+ } else {
255
+ await reloadEmbedded(mounted, widget, image, this.proxy);
256
+ }
257
+ }
258
+ }
@@ -0,0 +1,13 @@
1
+ export {
2
+ loadImage,
3
+ parseImageSpec,
4
+ fetchPackageJson,
5
+ setCdnBaseUrl,
6
+ getCdnBaseUrl,
7
+ } from './loader.js';
8
+
9
+ export {
10
+ ImageRegistry,
11
+ getImageRegistry,
12
+ createImageRegistry,
13
+ } from './registry.js';