camox 0.42.0 → 0.44.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 (99) hide show
  1. package/bin/camox.mjs +9 -1
  2. package/dist/core/components/lexical/{GradientNode.js → HighlightNode.js} +34 -34
  3. package/dist/core/components/lexical/InlineLexicalEditor.js +14 -14
  4. package/dist/core/components/lexical/InlineStylesPlugin.js +25 -9
  5. package/dist/core/components/lexical/SelectionBroadcaster.js +7 -7
  6. package/dist/core/components/lexical/SidebarLexicalEditor.js +24 -24
  7. package/dist/core/components/lexical/TextLinkPopover.js +191 -208
  8. package/dist/core/components/lexical/editorConfig.js +2 -2
  9. package/dist/core/createApp.d.ts +31 -4
  10. package/dist/core/createApp.js +2 -1
  11. package/dist/core/createBlock.js +24 -10
  12. package/dist/core/createLayout.d.ts +16 -3
  13. package/dist/core/createLayout.js +15 -15
  14. package/dist/core/derivedRoutes.js +1 -1
  15. package/dist/core/dom.d.ts +17 -0
  16. package/dist/core/dom.js +22 -0
  17. package/dist/core/editing/createEditableBlock.d.ts +135 -1
  18. package/dist/core/editing/createEditableBlock.js +209 -74
  19. package/dist/core/lib/contentType.d.ts +5 -0
  20. package/dist/core/lib/contentType.js +11 -0
  21. package/dist/core/lib/fieldTypes.js +1 -0
  22. package/dist/core/lib/iconTypes.d.ts +13 -0
  23. package/dist/core/lib/icons.d.ts +6 -0
  24. package/dist/core/lib/icons.js +130 -0
  25. package/dist/core/lib/lexicalReact.js +4 -4
  26. package/dist/core/lib/lexicalState.js +8 -8
  27. package/dist/core/lib/modifierFormats.js +2 -2
  28. package/dist/core/lib/textLinks.js +5 -2
  29. package/dist/core/lib/textStyles.d.ts +3 -3
  30. package/dist/core/lib/textStyles.js +9 -14
  31. package/dist/core/pageDestinations.js +37 -0
  32. package/dist/features/content/components/AssetCard.js +104 -68
  33. package/dist/features/og/imageResponse.node.js +11 -9
  34. package/dist/features/preview/CamoxPreview.js +148 -146
  35. package/dist/features/preview/commentsEnabled.js +2 -2
  36. package/dist/features/preview/components/AddBlockSidebar.js +1 -1
  37. package/dist/features/preview/components/AssetLightbox.js +17 -6
  38. package/dist/features/preview/components/AttachedComments.js +224 -87
  39. package/dist/features/preview/components/BlockActionsPopover.js +1 -1
  40. package/dist/features/preview/components/CommentTargetQuote.js +22 -21
  41. package/dist/features/preview/components/CreatePageModal.js +4 -4
  42. package/dist/features/preview/components/DerivedLayoutDialog.js +36 -21
  43. package/dist/features/preview/components/DerivedLayoutSidebar.js +45 -26
  44. package/dist/features/preview/components/DerivedPageInfoSidebar.js +38 -26
  45. package/dist/features/preview/components/FieldOverlayStyles.js +29 -9
  46. package/dist/features/preview/components/FieldToolbar.js +12 -12
  47. package/dist/features/preview/components/IconFieldEditor.js +231 -0
  48. package/dist/features/preview/components/ItemFieldsEditor.js +21 -14
  49. package/dist/features/preview/components/LinkFieldEditor.js +212 -209
  50. package/dist/features/preview/components/OverlayTracker.js +1 -1
  51. package/dist/features/preview/components/PageEditorSidebar.js +1 -1
  52. package/dist/features/preview/components/PageInfoSidebar.js +28 -28
  53. package/dist/features/preview/components/PagePicker.js +46 -46
  54. package/dist/features/preview/components/PageTree.js +1 -1
  55. package/dist/features/preview/components/PreviewPanel.js +1 -1
  56. package/dist/features/preview/components/PreviewToolbar.js +224 -225
  57. package/dist/features/preview/components/PublicationRow.js +8 -4
  58. package/dist/features/preview/components/SendFeedbackDialog.js +83 -0
  59. package/dist/features/preview/components/useRepeatableItemActions.js +1 -1
  60. package/dist/features/preview/overlayHighlights.js +54 -0
  61. package/dist/features/preview/previewCommentsStore.js +54 -34
  62. package/dist/features/preview/previewSelection.js +28 -23
  63. package/dist/features/preview/publication.js +10 -0
  64. package/dist/features/preview/usePageComments.js +39 -0
  65. package/dist/features/provider/CoreCamoxProvider.js +38 -6
  66. package/dist/features/provider/LocalhostPreviewProvider.js +81 -45
  67. package/dist/features/provider/components/CommandPalette.js +35 -84
  68. package/dist/features/runtime/pageApp.js +32 -28
  69. package/dist/features/runtime/pageServer.js +4 -1
  70. package/dist/features/runtime/runtime.d.ts +2 -0
  71. package/dist/features/runtime/runtime.js +45 -21
  72. package/dist/features/studio/components/EnvironmentMenu.js +76 -63
  73. package/dist/features/studio/components/Navbar.js +53 -80
  74. package/dist/features/vite/auth.js +1 -50
  75. package/dist/features/vite/iconGeneration.js +16 -0
  76. package/dist/features/vite/layoutGeneration.js +7 -3
  77. package/dist/features/vite/vite.d.ts +4 -2
  78. package/dist/features/vite/vite.js +24 -3
  79. package/dist/hooks/use-page-destinations.js +53 -0
  80. package/dist/lib/auth.js +40 -20
  81. package/dist/lib/preview-handoff.js +13 -0
  82. package/dist/lib/queries.js +12 -1
  83. package/dist/lib/server-auth-cookie.js +21 -0
  84. package/dist/lib/use-project-room.js +5 -2
  85. package/dist/studio-overlays.css +19 -15
  86. package/dist/studio.css +1 -1
  87. package/package.json +9 -4
  88. package/skills/camox/SKILL.md +38 -9
  89. package/skills/camox/references/block-definitions.md +107 -286
  90. package/skills/camox/references/cli-common.md +16 -4
  91. package/skills/camox/references/cli-content.md +158 -0
  92. package/skills/camox/references/cli-environments.md +1 -1
  93. package/skills/camox/references/dom-integrations.md +93 -0
  94. package/skills/camox/references/field-styling.md +50 -0
  95. package/skills/camox/references/layout-definitions.md +33 -147
  96. package/skills/camox/references/routed-layouts.md +71 -0
  97. package/skills/camoxify/SKILL.md +66 -0
  98. package/skills/camox/references/cli-blocks.md +0 -78
  99. package/skills/camox/references/cli-pages.md +0 -53
@@ -3,8 +3,8 @@
3
3
  const FORMAT_FLAGS = {
4
4
  bold: 1,
5
5
  italic: 2,
6
- underline: 8,
7
- gradient: 1 << 20
6
+ strikethrough: 4,
7
+ highlight: 1 << 20
8
8
  };
9
9
 
10
10
  //#endregion
@@ -12,12 +12,15 @@ function createPageTextLinkTarget(pageId) {
12
12
  function isHttpTextLinkTarget(target) {
13
13
  return /^https?:\/\//i.test(target);
14
14
  }
15
+ function isInternalTextLinkTarget(target) {
16
+ return /^\/(?!\/)[^\s\\\p{Cc}]*$/u.test(target);
17
+ }
15
18
  function isValidTextLinkTarget(target) {
16
- return getPageIdFromTextLinkTarget(target) != null || isHttpTextLinkTarget(target);
19
+ return getPageIdFromTextLinkTarget(target) != null || isHttpTextLinkTarget(target) || isInternalTextLinkTarget(target);
17
20
  }
18
21
  function resolveTextLinkHref(target, pages, fallbackHref) {
19
22
  const pageId = getPageIdFromTextLinkTarget(target);
20
- if (pageId == null) return isHttpTextLinkTarget(target) ? target : null;
23
+ if (pageId == null) return isValidTextLinkTarget(target) ? target : null;
21
24
  return (pages?.find((p) => String(p.id) === pageId))?.fullPath ?? fallbackHref;
22
25
  }
23
26
  function shouldOpenTextLinkInNewTab(target) {
@@ -6,11 +6,11 @@ interface InlineStyle {
6
6
  style?: CSSProperties;
7
7
  }
8
8
  interface TextStyleData {
9
- /** True when styling the shared gradient wrapper. Other flags are false for this call. */
10
- gradient: boolean;
9
+ /** True when styling the shared highlight wrapper. Other flags are false for this call. */
10
+ highlight: boolean;
11
11
  bold: boolean;
12
12
  italic: boolean;
13
- underline: boolean;
13
+ strikethrough: boolean;
14
14
  }
15
15
  interface TextLinkStyleData {
16
16
  target: string;
@@ -3,10 +3,10 @@ import { FORMAT_FLAGS } from "./modifierFormats.js";
3
3
  //#region src/core/lib/textStyles.ts
4
4
  function getTextStyleData(format) {
5
5
  return {
6
- gradient: false,
6
+ highlight: false,
7
7
  bold: !!(format & FORMAT_FLAGS.bold),
8
8
  italic: !!(format & FORMAT_FLAGS.italic),
9
- underline: !!(format & FORMAT_FLAGS.underline)
9
+ strikethrough: !!(format & FORMAT_FLAGS.strikethrough)
10
10
  };
11
11
  }
12
12
  function getTextAppearance(format, styles) {
@@ -16,32 +16,27 @@ function getTextAppearance(format, styles) {
16
16
  className: custom?.className,
17
17
  style: {
18
18
  ...flags.bold && flags.italic ? { fontStyle: "italic" } : {},
19
- ...flags.underline ? { textDecorationLine: "underline" } : {},
19
+ ...flags.strikethrough ? { textDecorationLine: "line-through" } : {},
20
20
  ...custom?.style
21
21
  }
22
22
  };
23
23
  }
24
- const defaultGradientStyle = {
25
- backgroundImage: "linear-gradient(to right, var(--camox-gradient-from, var(--chart-1, var(--primary, currentColor))), var(--camox-gradient-to, var(--chart-2, var(--muted-foreground, currentColor))))",
26
- backgroundClip: "text",
27
- WebkitBackgroundClip: "text",
28
- WebkitTextFillColor: "transparent"
29
- };
30
- function getGradientStyle(styles) {
24
+ const defaultHighlightStyle = { color: "var(--primary, currentColor)" };
25
+ function getHighlightStyle(styles) {
31
26
  const custom = styles.textStyle?.({
32
- gradient: true,
27
+ highlight: true,
33
28
  bold: false,
34
29
  italic: false,
35
- underline: false
30
+ strikethrough: false
36
31
  });
37
32
  return {
38
33
  className: custom?.className,
39
34
  style: {
40
- ...defaultGradientStyle,
35
+ ...defaultHighlightStyle,
41
36
  ...custom?.style
42
37
  }
43
38
  };
44
39
  }
45
40
 
46
41
  //#endregion
47
- export { getGradientStyle, getTextAppearance };
42
+ export { getHighlightStyle, getTextAppearance };
@@ -0,0 +1,37 @@
1
+ import { createPageTextLinkTarget } from "./lib/textLinks.js";
2
+
3
+ //#region src/core/pageDestinations.ts
4
+ /** Concrete navigable pages, not records that can all be mutated through pages.*. */
5
+ function getPageDestinations(pages, layouts) {
6
+ return [...pages.map((page) => ({
7
+ key: `page:${page.id}`,
8
+ kind: "curated",
9
+ pageId: page.id,
10
+ title: page.nickname,
11
+ fullPath: page.fullPath
12
+ })), ...layouts.filter((layout) => layout._internal.kind === "singleton").map(({ _internal: layout }) => ({
13
+ key: `singleton:${layout.id}`,
14
+ kind: "singleton",
15
+ layoutId: layout.id,
16
+ title: layout.title,
17
+ fullPath: `/${layout.id.split(".").map(encodeURIComponent).join("/")}`
18
+ }))];
19
+ }
20
+ /** Singleton links are ordinary internal URLs, never synthetic database page IDs. */
21
+ function destinationLink(destination) {
22
+ if (destination.kind === "curated") return {
23
+ type: "page",
24
+ pageId: String(destination.pageId)
25
+ };
26
+ return {
27
+ type: "external",
28
+ href: destination.fullPath
29
+ };
30
+ }
31
+ function destinationTextLink(destination) {
32
+ if (destination.kind === "curated") return createPageTextLinkTarget(destination.pageId);
33
+ return destination.fullPath;
34
+ }
35
+
36
+ //#endregion
37
+ export { destinationLink, destinationTextLink, getPageDestinations };
@@ -2,20 +2,21 @@ import { transformImageUrl } from "../../../core/lib/imageTransform.js";
2
2
  import { cn } from "../../../lib/utils.js";
3
3
  import { c } from "react/compiler-runtime";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
- import { FileIcon } from "lucide-react";
5
+ import { FileIcon, Play } from "lucide-react";
6
6
 
7
7
  //#region src/features/content/components/AssetCard.tsx
8
8
  const OPAQUE_IMAGE_MIME_TYPES = new Set(["image/jpeg", "image/jpg"]);
9
9
  const AssetCard = (t0) => {
10
- const $ = c(46);
11
- if ($[0] !== "1047e431261024f9506ec8f4989ecb00b2808af70364054688c5f3d5eb9e1f28") {
12
- for (let $i = 0; $i < 46; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
13
- $[0] = "1047e431261024f9506ec8f4989ecb00b2808af70364054688c5f3d5eb9e1f28";
10
+ const $ = c(50);
11
+ if ($[0] !== "9aebb85bb22fc4b24c35af733cd21a00df48ad736a0749a2028271c210f9e9e9") {
12
+ for (let $i = 0; $i < 50; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
13
+ $[0] = "9aebb85bb22fc4b24c35af733cd21a00df48ad736a0749a2028271c210f9e9e9";
14
14
  }
15
15
  const { file, selected, onSelect, onOpen } = t0;
16
16
  let extension;
17
17
  let isImage;
18
18
  let isOpaqueImage;
19
+ let isVideo;
19
20
  let t1;
20
21
  let t2;
21
22
  let t3;
@@ -24,38 +25,45 @@ const AssetCard = (t0) => {
24
25
  let t6;
25
26
  if ($[1] !== file.filename || $[2] !== file.id || $[3] !== file.mimeType || $[4] !== onOpen || $[5] !== onSelect || $[6] !== selected) {
26
27
  isImage = file.mimeType?.startsWith("image/");
27
- isOpaqueImage = isImage && OPAQUE_IMAGE_MIME_TYPES.has(file.mimeType ?? "");
28
28
  let t7;
29
- if ($[16] !== file.filename) {
30
- t7 = file.filename?.split(".").pop()?.toUpperCase() ?? "";
31
- $[16] = file.filename;
32
- $[17] = t7;
33
- } else t7 = $[17];
34
- extension = t7;
29
+ if ($[17] !== file.mimeType) {
30
+ t7 = file.mimeType?.startsWith("video/");
31
+ $[17] = file.mimeType;
32
+ $[18] = t7;
33
+ } else t7 = $[18];
34
+ isVideo = t7;
35
+ isOpaqueImage = isImage && OPAQUE_IMAGE_MIME_TYPES.has(file.mimeType ?? "");
36
+ let t8;
37
+ if ($[19] !== file.filename) {
38
+ t8 = file.filename?.split(".").pop()?.toUpperCase() ?? "";
39
+ $[19] = file.filename;
40
+ $[20] = t8;
41
+ } else t8 = $[20];
42
+ extension = t8;
35
43
  t2 = "button";
36
44
  t3 = file.id;
37
- const t8 = selected ? "bg-primary/20 border-2 border-primary" : "hover:bg-accent/75";
38
- if ($[18] !== t8) {
39
- t4 = cn("group flex flex-col gap-1.5 rounded-lg p-2 text-left border-2 border-transparent", t8);
40
- $[18] = t8;
41
- $[19] = t4;
42
- } else t4 = $[19];
43
- if ($[20] !== onSelect) {
45
+ const t9 = selected ? "bg-primary/20 border-2 border-primary" : "hover:bg-accent/75";
46
+ if ($[21] !== t9) {
47
+ t4 = cn("group flex flex-col gap-1.5 rounded-lg p-2 text-left border-2 border-transparent", t9);
48
+ $[21] = t9;
49
+ $[22] = t4;
50
+ } else t4 = $[22];
51
+ if ($[23] !== onSelect) {
44
52
  t5 = (e) => {
45
53
  e.stopPropagation();
46
54
  onSelect();
47
55
  };
48
- $[20] = onSelect;
49
- $[21] = t5;
50
- } else t5 = $[21];
51
- if ($[22] !== onOpen) {
56
+ $[23] = onSelect;
57
+ $[24] = t5;
58
+ } else t5 = $[24];
59
+ if ($[25] !== onOpen) {
52
60
  t6 = (e_0) => {
53
61
  e_0.stopPropagation();
54
62
  onOpen();
55
63
  };
56
- $[22] = onOpen;
57
- $[23] = t6;
58
- } else t6 = $[23];
64
+ $[25] = onOpen;
65
+ $[26] = t6;
66
+ } else t6 = $[26];
59
67
  t1 = cn("flex aspect-4/3 w-full items-center justify-center overflow-hidden rounded-sm", isOpaqueImage && "bg-muted", !isImage && "bg-muted", isImage && !isOpaqueImage && "checkered p-1.5");
60
68
  $[1] = file.filename;
61
69
  $[2] = file.id;
@@ -66,25 +74,27 @@ const AssetCard = (t0) => {
66
74
  $[7] = extension;
67
75
  $[8] = isImage;
68
76
  $[9] = isOpaqueImage;
69
- $[10] = t1;
70
- $[11] = t2;
71
- $[12] = t3;
72
- $[13] = t4;
73
- $[14] = t5;
74
- $[15] = t6;
77
+ $[10] = isVideo;
78
+ $[11] = t1;
79
+ $[12] = t2;
80
+ $[13] = t3;
81
+ $[14] = t4;
82
+ $[15] = t5;
83
+ $[16] = t6;
75
84
  } else {
76
85
  extension = $[7];
77
86
  isImage = $[8];
78
87
  isOpaqueImage = $[9];
79
- t1 = $[10];
80
- t2 = $[11];
81
- t3 = $[12];
82
- t4 = $[13];
83
- t5 = $[14];
84
- t6 = $[15];
88
+ isVideo = $[10];
89
+ t1 = $[11];
90
+ t2 = $[12];
91
+ t3 = $[13];
92
+ t4 = $[14];
93
+ t5 = $[15];
94
+ t6 = $[16];
85
95
  }
86
96
  let t7;
87
- if ($[24] !== extension || $[25] !== file.alt || $[26] !== file.filename || $[27] !== file.mimeType || $[28] !== file.size || $[29] !== file.url || $[30] !== isImage || $[31] !== isOpaqueImage) {
97
+ if ($[27] !== extension || $[28] !== file.alt || $[29] !== file.filename || $[30] !== file.mimeType || $[31] !== file.size || $[32] !== file.url || $[33] !== isImage || $[34] !== isOpaqueImage || $[35] !== isVideo) {
88
98
  t7 = isImage ? /* @__PURE__ */ jsx("img", {
89
99
  src: transformImageUrl(file.url, {
90
100
  width: 480,
@@ -94,6 +104,27 @@ const AssetCard = (t0) => {
94
104
  alt: file.alt || file.filename,
95
105
  draggable: false,
96
106
  className: cn("pointer-events-none h-full w-full", isOpaqueImage ? "object-cover" : "object-contain")
107
+ }) : isVideo ? /* @__PURE__ */ jsxs("div", {
108
+ className: "pointer-events-none relative h-full w-full",
109
+ children: [/* @__PURE__ */ jsx("video", {
110
+ src: file.url,
111
+ muted: true,
112
+ playsInline: true,
113
+ preload: "metadata",
114
+ "aria-hidden": "true",
115
+ className: "h-full w-full object-cover",
116
+ onLoadedMetadata: _temp
117
+ }, file.url), /* @__PURE__ */ jsx("span", {
118
+ className: "absolute inset-0 flex items-center justify-center",
119
+ children: /* @__PURE__ */ jsx("span", {
120
+ className: "rounded-full bg-black/50 p-2 text-white",
121
+ children: /* @__PURE__ */ jsx(Play, {
122
+ className: "h-5 w-5",
123
+ fill: "currentColor",
124
+ "aria-hidden": "true"
125
+ })
126
+ })
127
+ })]
97
128
  }) : /* @__PURE__ */ jsxs("div", {
98
129
  className: "text-muted-foreground flex flex-col items-center gap-1",
99
130
  children: [/* @__PURE__ */ jsx(FileIcon, { className: "h-8 w-8" }), extension && /* @__PURE__ */ jsx("span", {
@@ -101,37 +132,38 @@ const AssetCard = (t0) => {
101
132
  children: extension
102
133
  })]
103
134
  });
104
- $[24] = extension;
105
- $[25] = file.alt;
106
- $[26] = file.filename;
107
- $[27] = file.mimeType;
108
- $[28] = file.size;
109
- $[29] = file.url;
110
- $[30] = isImage;
111
- $[31] = isOpaqueImage;
112
- $[32] = t7;
113
- } else t7 = $[32];
135
+ $[27] = extension;
136
+ $[28] = file.alt;
137
+ $[29] = file.filename;
138
+ $[30] = file.mimeType;
139
+ $[31] = file.size;
140
+ $[32] = file.url;
141
+ $[33] = isImage;
142
+ $[34] = isOpaqueImage;
143
+ $[35] = isVideo;
144
+ $[36] = t7;
145
+ } else t7 = $[36];
114
146
  let t8;
115
- if ($[33] !== t1 || $[34] !== t7) {
147
+ if ($[37] !== t1 || $[38] !== t7) {
116
148
  t8 = /* @__PURE__ */ jsx("div", {
117
149
  className: t1,
118
150
  children: t7
119
151
  });
120
- $[33] = t1;
121
- $[34] = t7;
122
- $[35] = t8;
123
- } else t8 = $[35];
152
+ $[37] = t1;
153
+ $[38] = t7;
154
+ $[39] = t8;
155
+ } else t8 = $[39];
124
156
  let t9;
125
- if ($[36] !== file.filename) {
157
+ if ($[40] !== file.filename) {
126
158
  t9 = /* @__PURE__ */ jsx("p", {
127
159
  className: "line-clamp-2 px-0.5 text-xs break-all",
128
160
  children: file.filename
129
161
  });
130
- $[36] = file.filename;
131
- $[37] = t9;
132
- } else t9 = $[37];
162
+ $[40] = file.filename;
163
+ $[41] = t9;
164
+ } else t9 = $[41];
133
165
  let t10;
134
- if ($[38] !== t2 || $[39] !== t3 || $[40] !== t4 || $[41] !== t5 || $[42] !== t6 || $[43] !== t8 || $[44] !== t9) {
166
+ if ($[42] !== t2 || $[43] !== t3 || $[44] !== t4 || $[45] !== t5 || $[46] !== t6 || $[47] !== t8 || $[48] !== t9) {
135
167
  t10 = /* @__PURE__ */ jsxs("button", {
136
168
  type: t2,
137
169
  "data-asset-id": t3,
@@ -140,17 +172,21 @@ const AssetCard = (t0) => {
140
172
  onDoubleClick: t6,
141
173
  children: [t8, t9]
142
174
  });
143
- $[38] = t2;
144
- $[39] = t3;
145
- $[40] = t4;
146
- $[41] = t5;
147
- $[42] = t6;
148
- $[43] = t8;
149
- $[44] = t9;
150
- $[45] = t10;
151
- } else t10 = $[45];
175
+ $[42] = t2;
176
+ $[43] = t3;
177
+ $[44] = t4;
178
+ $[45] = t5;
179
+ $[46] = t6;
180
+ $[47] = t8;
181
+ $[48] = t9;
182
+ $[49] = t10;
183
+ } else t10 = $[49];
152
184
  return t10;
153
185
  };
186
+ function _temp(event) {
187
+ const video = event.currentTarget;
188
+ if (Number.isFinite(video.duration) && video.duration > 0) video.currentTime = Math.min(.1, video.duration / 2);
189
+ }
154
190
 
155
191
  //#endregion
156
192
  export { AssetCard };
@@ -1,7 +1,6 @@
1
1
  import { DEFAULT_FONTS } from "./defaultFonts.js";
2
- import { createRequire } from "node:module";
3
- import { readFileSync } from "node:fs";
4
2
  import { ImageResponse as ImageResponse$1 } from "@takumi-rs/image-response/wasm";
3
+ import wasmModule from "@takumi-rs/wasm/next";
5
4
  import { Renderer, initSync } from "@takumi-rs/wasm/no-bundler";
6
5
 
7
6
  //#region src/features/og/imageResponse.node.ts
@@ -14,12 +13,10 @@ import { Renderer, initSync } from "@takumi-rs/wasm/no-bundler";
14
13
  * about which engine to use any more — it's only about *how* the wasm module
15
14
  * gets loaded:
16
15
  *
17
- * - Here, we read the `.wasm` file off disk and `initSync` it ourselves
18
- * before constructing a `Renderer`. `@takumi-rs/wasm` ships a "node"
19
- * bundler entry that purports to do this, but its source uses an
20
- * extensionless `import "../pkg/takumi_wasm"` which raw Node ESM rejects
21
- * once the package is externalised by Nitro/Vite — so we go through the
22
- * `no-bundler` entry directly.
16
+ * - Here, we import the wasm module and `initSync` it ourselves before
17
+ * constructing a `Renderer`. The static `?module` import lets Nitro emit
18
+ * the asset into the deployment instead of relying on a runtime
19
+ * `require.resolve` that dependency tracing cannot reliably discover.
23
20
  *
24
21
  * - In `imageResponse.workerd.ts` there's no filesystem; instead we pass a
25
22
  * `WebAssembly.Module` reference via `?module` import and let the
@@ -28,7 +25,12 @@ import { Renderer, initSync } from "@takumi-rs/wasm/no-bundler";
28
25
  * We use the BYO-renderer path of `@takumi-rs/image-response/wasm` so the
29
26
  * `module:` option isn't needed here — the renderer is already alive.
30
27
  */
31
- initSync({ module: readFileSync(createRequire(import.meta.url).resolve("@takumi-rs/wasm/takumi_wasm_bg.wasm")) });
28
+ /**
29
+ * Resolve and initialise the wasm module once at module load. `initSync`
30
+ * compiles the wasm and wires up the JS bindings; subsequent `new Renderer()`
31
+ * calls are cheap.
32
+ */
33
+ initSync({ module: wasmModule });
32
34
  /**
33
35
  * Module-scoped singleton — building the renderer compiles the wasm module
34
36
  * and loads Geist; not free, and there's no reason to do it per request.