@getforma/core 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.
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/chunk-27QSSN4E.cjs +1773 -0
- package/dist/chunk-27QSSN4E.cjs.map +1 -0
- package/dist/chunk-DB2ULMOM.js +1750 -0
- package/dist/chunk-DB2ULMOM.js.map +1 -0
- package/dist/chunk-FPSLC62A.cjs +31 -0
- package/dist/chunk-FPSLC62A.cjs.map +1 -0
- package/dist/chunk-KX5WRZH7.js +27 -0
- package/dist/chunk-KX5WRZH7.js.map +1 -0
- package/dist/formajs-runtime-hardened.global.js +2 -0
- package/dist/formajs-runtime-hardened.global.js.map +1 -0
- package/dist/formajs-runtime.global.js +2 -0
- package/dist/formajs-runtime.global.js.map +1 -0
- package/dist/formajs.global.js +2 -0
- package/dist/formajs.global.js.map +1 -0
- package/dist/index.cjs +1626 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1382 -0
- package/dist/index.d.ts +1382 -0
- package/dist/index.js +1482 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime-hardened.cjs +2805 -0
- package/dist/runtime-hardened.cjs.map +1 -0
- package/dist/runtime-hardened.js +2786 -0
- package/dist/runtime-hardened.js.map +1 -0
- package/dist/runtime.cjs +2531 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +86 -0
- package/dist/runtime.d.ts +86 -0
- package/dist/runtime.js +2512 -0
- package/dist/runtime.js.map +1 -0
- package/dist/signal-CfLDwMyg.d.cts +29 -0
- package/dist/signal-CfLDwMyg.d.ts +29 -0
- package/dist/ssr/index.cjs +381 -0
- package/dist/ssr/index.cjs.map +1 -0
- package/dist/ssr/index.d.cts +154 -0
- package/dist/ssr/index.d.ts +154 -0
- package/dist/ssr/index.js +371 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/tc39-compat.cjs +45 -0
- package/dist/tc39-compat.cjs.map +1 -0
- package/dist/tc39-compat.d.cts +50 -0
- package/dist/tc39-compat.d.ts +50 -0
- package/dist/tc39-compat.js +42 -0
- package/dist/tc39-compat.js.map +1 -0
- package/package.json +122 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1626 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk27QSSN4E_cjs = require('./chunk-27QSSN4E.cjs');
|
|
4
|
+
var chunkFPSLC62A_cjs = require('./chunk-FPSLC62A.cjs');
|
|
5
|
+
|
|
6
|
+
// src/dom/text.ts
|
|
7
|
+
function createText(value) {
|
|
8
|
+
if (typeof value === "function") {
|
|
9
|
+
const node = new Text("");
|
|
10
|
+
chunk27QSSN4E_cjs.internalEffect(() => {
|
|
11
|
+
node.data = value();
|
|
12
|
+
});
|
|
13
|
+
return node;
|
|
14
|
+
}
|
|
15
|
+
return new Text(value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/dom/mount.ts
|
|
19
|
+
function mount(component, container) {
|
|
20
|
+
const target = typeof container === "string" ? document.querySelector(container) : container;
|
|
21
|
+
if (!target) {
|
|
22
|
+
throw new Error(`mount: container not found \u2014 "${container}"`);
|
|
23
|
+
}
|
|
24
|
+
let disposeRoot;
|
|
25
|
+
if (target.hasAttribute("data-forma-ssr")) {
|
|
26
|
+
chunk27QSSN4E_cjs.createRoot((dispose) => {
|
|
27
|
+
disposeRoot = dispose;
|
|
28
|
+
chunk27QSSN4E_cjs.hydrateIsland(component, target);
|
|
29
|
+
});
|
|
30
|
+
} else {
|
|
31
|
+
const dom = chunk27QSSN4E_cjs.createRoot((dispose) => {
|
|
32
|
+
disposeRoot = dispose;
|
|
33
|
+
return component();
|
|
34
|
+
});
|
|
35
|
+
target.innerHTML = "";
|
|
36
|
+
target.appendChild(dom);
|
|
37
|
+
}
|
|
38
|
+
let unmounted = false;
|
|
39
|
+
return () => {
|
|
40
|
+
if (unmounted) return;
|
|
41
|
+
unmounted = true;
|
|
42
|
+
disposeRoot();
|
|
43
|
+
target.innerHTML = "";
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/dom/switch.ts
|
|
48
|
+
function createSwitch(value, cases, fallback) {
|
|
49
|
+
const startMarker = document.createComment("forma-switch");
|
|
50
|
+
const endMarker = document.createComment("/forma-switch");
|
|
51
|
+
const fragment2 = document.createDocumentFragment();
|
|
52
|
+
fragment2.appendChild(startMarker);
|
|
53
|
+
fragment2.appendChild(endMarker);
|
|
54
|
+
const cache = /* @__PURE__ */ new Map();
|
|
55
|
+
let currentNode = null;
|
|
56
|
+
let currentMatch = UNSET;
|
|
57
|
+
const switchDispose = chunk27QSSN4E_cjs.internalEffect(() => {
|
|
58
|
+
const val = value();
|
|
59
|
+
if (val === currentMatch) return;
|
|
60
|
+
const DEBUG = typeof globalThis.__FORMA_DEBUG__ !== "undefined";
|
|
61
|
+
if (DEBUG) console.log("[forma:switch] transition", String(currentMatch), "\u2192", String(val));
|
|
62
|
+
currentMatch = val;
|
|
63
|
+
const parent2 = startMarker.parentNode;
|
|
64
|
+
if (!parent2) {
|
|
65
|
+
if (DEBUG) console.warn("[forma:switch] markers not in DOM yet, skipping");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (currentNode) {
|
|
69
|
+
if (currentNode.parentNode === parent2) {
|
|
70
|
+
if (DEBUG) console.log("[forma:switch] removing single node");
|
|
71
|
+
parent2.removeChild(currentNode);
|
|
72
|
+
} else if (currentNode.nodeType === 11) {
|
|
73
|
+
if (DEBUG) console.log("[forma:switch] scooping nodes back into fragment");
|
|
74
|
+
let scooped = 0;
|
|
75
|
+
while (startMarker.nextSibling && startMarker.nextSibling !== endMarker) {
|
|
76
|
+
currentNode.appendChild(startMarker.nextSibling);
|
|
77
|
+
scooped++;
|
|
78
|
+
}
|
|
79
|
+
if (DEBUG) console.log("[forma:switch] scooped", scooped, "nodes back into fragment");
|
|
80
|
+
} else {
|
|
81
|
+
if (DEBUG) console.log("[forma:switch] clearing detached node between markers");
|
|
82
|
+
while (startMarker.nextSibling && startMarker.nextSibling !== endMarker) {
|
|
83
|
+
parent2.removeChild(startMarker.nextSibling);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const matchedCase = cases.find((c) => c.match === val);
|
|
88
|
+
if (matchedCase) {
|
|
89
|
+
let entry = cache.get(val);
|
|
90
|
+
if (!entry) {
|
|
91
|
+
let branchDispose;
|
|
92
|
+
const node = chunk27QSSN4E_cjs.createRoot((dispose) => {
|
|
93
|
+
branchDispose = dispose;
|
|
94
|
+
return chunk27QSSN4E_cjs.untrack(() => matchedCase.render());
|
|
95
|
+
});
|
|
96
|
+
entry = { node, dispose: branchDispose };
|
|
97
|
+
cache.set(val, entry);
|
|
98
|
+
if (DEBUG) console.log("[forma:switch] rendered new branch for", String(val), "\u2192", node.nodeName, "type", node.nodeType);
|
|
99
|
+
} else {
|
|
100
|
+
if (DEBUG) console.log("[forma:switch] reusing cached branch for", String(val), "\u2192", entry.node.nodeName, "type", entry.node.nodeType, "childNodes", entry.node.childNodes?.length);
|
|
101
|
+
}
|
|
102
|
+
currentNode = entry.node;
|
|
103
|
+
} else {
|
|
104
|
+
currentNode = fallback?.() ?? null;
|
|
105
|
+
if (DEBUG) console.log("[forma:switch] no match, using fallback");
|
|
106
|
+
}
|
|
107
|
+
if (currentNode) {
|
|
108
|
+
parent2.insertBefore(currentNode, endMarker);
|
|
109
|
+
if (DEBUG) console.log("[forma:switch] inserted", currentNode.nodeName, "before end marker");
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
fragment2.__switchDispose = () => {
|
|
113
|
+
switchDispose();
|
|
114
|
+
for (const entry of cache.values()) {
|
|
115
|
+
entry.dispose();
|
|
116
|
+
}
|
|
117
|
+
cache.clear();
|
|
118
|
+
};
|
|
119
|
+
return fragment2;
|
|
120
|
+
}
|
|
121
|
+
var UNSET = /* @__PURE__ */ Symbol("unset");
|
|
122
|
+
|
|
123
|
+
// src/dom/portal.ts
|
|
124
|
+
function createPortal(children2, target) {
|
|
125
|
+
const placeholder = document.createComment("forma-portal");
|
|
126
|
+
const resolvedTarget = typeof target === "string" ? document.querySelector(target) : target ?? document.body;
|
|
127
|
+
if (!resolvedTarget) {
|
|
128
|
+
throw new Error(`createPortal: target not found: ${target}`);
|
|
129
|
+
}
|
|
130
|
+
let mountedNode = null;
|
|
131
|
+
const removeMountedNode = () => {
|
|
132
|
+
if (mountedNode && mountedNode.parentNode === resolvedTarget) {
|
|
133
|
+
resolvedTarget.removeChild(mountedNode);
|
|
134
|
+
}
|
|
135
|
+
mountedNode = null;
|
|
136
|
+
};
|
|
137
|
+
chunk27QSSN4E_cjs.createEffect(() => {
|
|
138
|
+
const node = children2();
|
|
139
|
+
removeMountedNode();
|
|
140
|
+
mountedNode = node;
|
|
141
|
+
resolvedTarget.appendChild(node);
|
|
142
|
+
return () => {
|
|
143
|
+
removeMountedNode();
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
return placeholder;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/dom/error-boundary.ts
|
|
150
|
+
function createErrorBoundary(tryFn, catchFn) {
|
|
151
|
+
const startMarker = document.createComment("forma-error-boundary");
|
|
152
|
+
const endMarker = document.createComment("/forma-error-boundary");
|
|
153
|
+
const fragment2 = document.createDocumentFragment();
|
|
154
|
+
fragment2.appendChild(startMarker);
|
|
155
|
+
fragment2.appendChild(endMarker);
|
|
156
|
+
const [retryCount, setRetryCount] = chunkFPSLC62A_cjs.createSignal(0);
|
|
157
|
+
let currentNode = null;
|
|
158
|
+
chunk27QSSN4E_cjs.internalEffect(() => {
|
|
159
|
+
retryCount();
|
|
160
|
+
const parent2 = startMarker.parentNode;
|
|
161
|
+
if (!parent2) return;
|
|
162
|
+
if (currentNode && currentNode.parentNode === parent2) {
|
|
163
|
+
parent2.removeChild(currentNode);
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
currentNode = tryFn();
|
|
167
|
+
} catch (e) {
|
|
168
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
169
|
+
const retry = () => setRetryCount((c) => c + 1);
|
|
170
|
+
currentNode = catchFn(error, retry);
|
|
171
|
+
}
|
|
172
|
+
if (currentNode) {
|
|
173
|
+
parent2.insertBefore(currentNode, endMarker);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
return fragment2;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/dom/suspense.ts
|
|
180
|
+
function createSuspense(fallback, children2) {
|
|
181
|
+
const startMarker = document.createComment("forma-suspense");
|
|
182
|
+
const endMarker = document.createComment("/forma-suspense");
|
|
183
|
+
const fragment2 = document.createDocumentFragment();
|
|
184
|
+
fragment2.appendChild(startMarker);
|
|
185
|
+
fragment2.appendChild(endMarker);
|
|
186
|
+
const [pending, setPending] = chunkFPSLC62A_cjs.createSignal(0);
|
|
187
|
+
let currentNode = null;
|
|
188
|
+
let resolvedNode = null;
|
|
189
|
+
let fallbackNode = null;
|
|
190
|
+
const ctx = {
|
|
191
|
+
increment() {
|
|
192
|
+
setPending((p) => p + 1);
|
|
193
|
+
},
|
|
194
|
+
decrement() {
|
|
195
|
+
setPending((p) => Math.max(0, p - 1));
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
chunk27QSSN4E_cjs.pushSuspenseContext(ctx);
|
|
199
|
+
try {
|
|
200
|
+
resolvedNode = children2();
|
|
201
|
+
} finally {
|
|
202
|
+
chunk27QSSN4E_cjs.popSuspenseContext();
|
|
203
|
+
}
|
|
204
|
+
chunk27QSSN4E_cjs.internalEffect(() => {
|
|
205
|
+
const parent2 = startMarker.parentNode;
|
|
206
|
+
if (!parent2) return;
|
|
207
|
+
const isPending = pending() > 0;
|
|
208
|
+
const newNode = isPending ? fallbackNode ??= fallback() : resolvedNode;
|
|
209
|
+
if (newNode === currentNode) return;
|
|
210
|
+
if (currentNode && currentNode.parentNode === parent2) {
|
|
211
|
+
parent2.removeChild(currentNode);
|
|
212
|
+
}
|
|
213
|
+
if (newNode) {
|
|
214
|
+
parent2.insertBefore(newNode, endMarker);
|
|
215
|
+
}
|
|
216
|
+
currentNode = newNode;
|
|
217
|
+
});
|
|
218
|
+
return fragment2;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/dom/activate.ts
|
|
222
|
+
function loadIslandProps(root, id, sharedProps) {
|
|
223
|
+
const inline = root.getAttribute("data-forma-props");
|
|
224
|
+
if (inline) {
|
|
225
|
+
return JSON.parse(inline);
|
|
226
|
+
}
|
|
227
|
+
if (sharedProps && String(id) in sharedProps) {
|
|
228
|
+
return sharedProps[String(id)];
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
function activateIslands(registry2) {
|
|
233
|
+
const scriptBlock = document.getElementById("__forma_islands");
|
|
234
|
+
const sharedProps = scriptBlock ? JSON.parse(scriptBlock.textContent) : null;
|
|
235
|
+
const islands = document.querySelectorAll("[data-forma-island]");
|
|
236
|
+
for (const root of islands) {
|
|
237
|
+
const id = parseInt(root.getAttribute("data-forma-island"), 10);
|
|
238
|
+
const componentName = root.getAttribute("data-forma-component");
|
|
239
|
+
const hydrateFn = registry2[componentName];
|
|
240
|
+
if (!hydrateFn) {
|
|
241
|
+
console.warn(`[forma] No hydrate function for island "${componentName}" (id=${id})`);
|
|
242
|
+
root.setAttribute("data-forma-status", "error");
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const trigger = root.getAttribute("data-forma-hydrate") || "load";
|
|
246
|
+
if (trigger === "interaction" || trigger === "idle") {
|
|
247
|
+
console.warn(`[forma] Trigger "${trigger}" not yet implemented for island "${componentName}" (id=${id}), falling back to load`);
|
|
248
|
+
}
|
|
249
|
+
if (trigger === "visible") {
|
|
250
|
+
const observer = new IntersectionObserver(
|
|
251
|
+
(entries) => {
|
|
252
|
+
for (const entry of entries) {
|
|
253
|
+
if (!entry.isIntersecting) continue;
|
|
254
|
+
observer.disconnect();
|
|
255
|
+
hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps);
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
{ rootMargin: "200px" }
|
|
259
|
+
);
|
|
260
|
+
observer.observe(root);
|
|
261
|
+
} else {
|
|
262
|
+
hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps) {
|
|
267
|
+
try {
|
|
268
|
+
const props = loadIslandProps(root, id, sharedProps);
|
|
269
|
+
root.setAttribute("data-forma-status", "hydrating");
|
|
270
|
+
let activeRoot = root;
|
|
271
|
+
chunk27QSSN4E_cjs.createRoot((dispose) => {
|
|
272
|
+
activeRoot = chunk27QSSN4E_cjs.hydrateIsland(() => hydrateFn(props), root);
|
|
273
|
+
activeRoot.__formaDispose = dispose;
|
|
274
|
+
});
|
|
275
|
+
activeRoot.setAttribute("data-forma-status", "active");
|
|
276
|
+
} catch (err) {
|
|
277
|
+
console.error(`[forma] Island "${componentName}" (id=${id}) failed:`, err);
|
|
278
|
+
root.setAttribute("data-forma-status", "error");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/component/define.ts
|
|
283
|
+
var currentLifecycleContext = null;
|
|
284
|
+
var lifecycleStack = [];
|
|
285
|
+
function pushLifecycleContext(ctx) {
|
|
286
|
+
lifecycleStack.push(currentLifecycleContext);
|
|
287
|
+
currentLifecycleContext = ctx;
|
|
288
|
+
}
|
|
289
|
+
function popLifecycleContext() {
|
|
290
|
+
currentLifecycleContext = lifecycleStack.pop() ?? null;
|
|
291
|
+
}
|
|
292
|
+
function onMount(fn) {
|
|
293
|
+
if (currentLifecycleContext === null) {
|
|
294
|
+
throw new Error("onMount() must be called inside a component setup function");
|
|
295
|
+
}
|
|
296
|
+
currentLifecycleContext.mountCallbacks.push(fn);
|
|
297
|
+
}
|
|
298
|
+
function onUnmount(fn) {
|
|
299
|
+
if (currentLifecycleContext === null) {
|
|
300
|
+
throw new Error("onUnmount() must be called inside a component setup function");
|
|
301
|
+
}
|
|
302
|
+
currentLifecycleContext.unmountCallbacks.push(fn);
|
|
303
|
+
}
|
|
304
|
+
var DISPOSE_KEY = /* @__PURE__ */ Symbol("forma:component:dispose");
|
|
305
|
+
function defineComponent(setupOrDef) {
|
|
306
|
+
const setup = typeof setupOrDef === "function" ? setupOrDef : setupOrDef.setup;
|
|
307
|
+
typeof setupOrDef === "function" ? void 0 : setupOrDef.name;
|
|
308
|
+
return function componentFactory() {
|
|
309
|
+
const ctx = {
|
|
310
|
+
disposers: [],
|
|
311
|
+
mountCallbacks: [],
|
|
312
|
+
unmountCallbacks: []
|
|
313
|
+
};
|
|
314
|
+
pushLifecycleContext(ctx);
|
|
315
|
+
let dom;
|
|
316
|
+
try {
|
|
317
|
+
dom = setup();
|
|
318
|
+
} finally {
|
|
319
|
+
popLifecycleContext();
|
|
320
|
+
}
|
|
321
|
+
const dispose = () => {
|
|
322
|
+
for (const cb of ctx.unmountCallbacks) {
|
|
323
|
+
try {
|
|
324
|
+
cb();
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
for (const d of ctx.disposers) {
|
|
329
|
+
try {
|
|
330
|
+
d();
|
|
331
|
+
} catch {
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
ctx.disposers.length = 0;
|
|
335
|
+
ctx.mountCallbacks.length = 0;
|
|
336
|
+
ctx.unmountCallbacks.length = 0;
|
|
337
|
+
};
|
|
338
|
+
dom[DISPOSE_KEY] = dispose;
|
|
339
|
+
for (const cb of ctx.mountCallbacks) {
|
|
340
|
+
try {
|
|
341
|
+
const cleanup2 = cb();
|
|
342
|
+
if (typeof cleanup2 === "function") {
|
|
343
|
+
ctx.unmountCallbacks.push(cleanup2);
|
|
344
|
+
}
|
|
345
|
+
} catch {
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return dom;
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function disposeComponent(dom) {
|
|
352
|
+
const disposable = dom;
|
|
353
|
+
if (typeof disposable[DISPOSE_KEY] === "function") {
|
|
354
|
+
disposable[DISPOSE_KEY]();
|
|
355
|
+
delete disposable[DISPOSE_KEY];
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function trackDisposer(dispose) {
|
|
359
|
+
if (currentLifecycleContext !== null) {
|
|
360
|
+
currentLifecycleContext.disposers.push(dispose);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/component/context.ts
|
|
365
|
+
var contextStacks = /* @__PURE__ */ new Map();
|
|
366
|
+
function createContext(defaultValue) {
|
|
367
|
+
return {
|
|
368
|
+
id: /* @__PURE__ */ Symbol("forma:context"),
|
|
369
|
+
defaultValue
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function provide(ctx, value) {
|
|
373
|
+
let stack = contextStacks.get(ctx.id);
|
|
374
|
+
if (stack === void 0) {
|
|
375
|
+
stack = [];
|
|
376
|
+
contextStacks.set(ctx.id, stack);
|
|
377
|
+
}
|
|
378
|
+
stack.push(value);
|
|
379
|
+
}
|
|
380
|
+
function inject(ctx) {
|
|
381
|
+
const stack = contextStacks.get(ctx.id);
|
|
382
|
+
if (stack === void 0 || stack.length === 0) {
|
|
383
|
+
return ctx.defaultValue;
|
|
384
|
+
}
|
|
385
|
+
return stack[stack.length - 1];
|
|
386
|
+
}
|
|
387
|
+
function unprovide(ctx) {
|
|
388
|
+
const stack = contextStacks.get(ctx.id);
|
|
389
|
+
if (stack !== void 0 && stack.length > 0) {
|
|
390
|
+
stack.pop();
|
|
391
|
+
if (stack.length === 0) {
|
|
392
|
+
contextStacks.delete(ctx.id);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/state/store.ts
|
|
398
|
+
var RAW = /* @__PURE__ */ Symbol("forma-raw");
|
|
399
|
+
var PROXY = /* @__PURE__ */ Symbol("forma-proxy");
|
|
400
|
+
var ARRAY_MUTATORS = /* @__PURE__ */ new Set([
|
|
401
|
+
"push",
|
|
402
|
+
"pop",
|
|
403
|
+
"shift",
|
|
404
|
+
"unshift",
|
|
405
|
+
"splice",
|
|
406
|
+
"sort",
|
|
407
|
+
"reverse",
|
|
408
|
+
"fill",
|
|
409
|
+
"copyWithin"
|
|
410
|
+
]);
|
|
411
|
+
function shouldWrap(v) {
|
|
412
|
+
if (v == null || typeof v !== "object") return false;
|
|
413
|
+
if (v instanceof Date || v instanceof RegExp || v instanceof Map || v instanceof Set || v instanceof WeakMap || v instanceof WeakSet || v instanceof Error || v instanceof Promise) {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
if (v[PROXY]) return false;
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
function deepClone(obj) {
|
|
420
|
+
if (obj == null || typeof obj !== "object") return obj;
|
|
421
|
+
if (Array.isArray(obj)) return obj.map(deepClone);
|
|
422
|
+
if (obj instanceof Date) return new Date(obj.getTime());
|
|
423
|
+
const out = {};
|
|
424
|
+
for (const key of Object.keys(obj)) {
|
|
425
|
+
out[key] = deepClone(obj[key]);
|
|
426
|
+
}
|
|
427
|
+
return out;
|
|
428
|
+
}
|
|
429
|
+
function createStore(initial) {
|
|
430
|
+
const signals = /* @__PURE__ */ new Map();
|
|
431
|
+
const children2 = /* @__PURE__ */ new Map();
|
|
432
|
+
function registerChild(path) {
|
|
433
|
+
const lastDot = path.lastIndexOf(".");
|
|
434
|
+
if (lastDot === -1) return;
|
|
435
|
+
const parentPath = path.substring(0, lastDot);
|
|
436
|
+
let set = children2.get(parentPath);
|
|
437
|
+
if (!set) {
|
|
438
|
+
set = /* @__PURE__ */ new Set();
|
|
439
|
+
children2.set(parentPath, set);
|
|
440
|
+
}
|
|
441
|
+
set.add(path);
|
|
442
|
+
}
|
|
443
|
+
function getSignal(path, initialValue) {
|
|
444
|
+
let pair = signals.get(path);
|
|
445
|
+
if (!pair) {
|
|
446
|
+
pair = chunkFPSLC62A_cjs.createSignal(initialValue);
|
|
447
|
+
signals.set(path, pair);
|
|
448
|
+
registerChild(path);
|
|
449
|
+
}
|
|
450
|
+
return pair;
|
|
451
|
+
}
|
|
452
|
+
const proxyCache = /* @__PURE__ */ new WeakMap();
|
|
453
|
+
function invalidateChildren(parentPath) {
|
|
454
|
+
const childSet = children2.get(parentPath);
|
|
455
|
+
if (!childSet) return;
|
|
456
|
+
for (const childPath of childSet) {
|
|
457
|
+
invalidateChildren(childPath);
|
|
458
|
+
signals.delete(childPath);
|
|
459
|
+
children2.delete(childPath);
|
|
460
|
+
}
|
|
461
|
+
childSet.clear();
|
|
462
|
+
}
|
|
463
|
+
function wrap(raw, basePath) {
|
|
464
|
+
if (!shouldWrap(raw)) return raw;
|
|
465
|
+
const cached = proxyCache.get(raw);
|
|
466
|
+
if (cached) return cached;
|
|
467
|
+
const isArr = Array.isArray(raw);
|
|
468
|
+
const basePrefix = basePath ? basePath + "." : "";
|
|
469
|
+
let lastKey = "";
|
|
470
|
+
let lastSignal;
|
|
471
|
+
const proxy = new Proxy(raw, {
|
|
472
|
+
// -------------------------------------------------------------------
|
|
473
|
+
// GET
|
|
474
|
+
// -------------------------------------------------------------------
|
|
475
|
+
get(target, prop, receiver) {
|
|
476
|
+
if (prop === RAW) return target;
|
|
477
|
+
if (prop === PROXY) return true;
|
|
478
|
+
if (typeof prop === "symbol") {
|
|
479
|
+
return Reflect.get(target, prop, receiver);
|
|
480
|
+
}
|
|
481
|
+
const key = String(prop);
|
|
482
|
+
const childPath = basePrefix + key;
|
|
483
|
+
if (isArr && ARRAY_MUTATORS.has(key)) {
|
|
484
|
+
return (...args) => {
|
|
485
|
+
let result;
|
|
486
|
+
chunk27QSSN4E_cjs.batch(() => {
|
|
487
|
+
const rawArgs = args.map(
|
|
488
|
+
(a) => a != null && typeof a === "object" && a[RAW] ? a[RAW] : a
|
|
489
|
+
);
|
|
490
|
+
result = target[key].apply(target, rawArgs);
|
|
491
|
+
invalidateChildren(basePath);
|
|
492
|
+
const [, setLen] = getSignal(
|
|
493
|
+
basePrefix + "length",
|
|
494
|
+
target.length
|
|
495
|
+
);
|
|
496
|
+
setLen(target.length);
|
|
497
|
+
});
|
|
498
|
+
return result;
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
if (isArr && key === "length") {
|
|
502
|
+
const [getter] = getSignal(childPath, target.length);
|
|
503
|
+
getter();
|
|
504
|
+
return target.length;
|
|
505
|
+
}
|
|
506
|
+
const value = Reflect.get(target, prop);
|
|
507
|
+
let pair;
|
|
508
|
+
if (key === lastKey && lastSignal) {
|
|
509
|
+
pair = lastSignal;
|
|
510
|
+
} else {
|
|
511
|
+
pair = getSignal(childPath, value);
|
|
512
|
+
lastKey = key;
|
|
513
|
+
lastSignal = pair;
|
|
514
|
+
}
|
|
515
|
+
pair[0]();
|
|
516
|
+
if (shouldWrap(value)) {
|
|
517
|
+
return wrap(value, childPath);
|
|
518
|
+
}
|
|
519
|
+
return value;
|
|
520
|
+
},
|
|
521
|
+
// -------------------------------------------------------------------
|
|
522
|
+
// SET
|
|
523
|
+
// -------------------------------------------------------------------
|
|
524
|
+
set(target, prop, value) {
|
|
525
|
+
if (typeof prop === "symbol") {
|
|
526
|
+
return Reflect.set(target, prop, value);
|
|
527
|
+
}
|
|
528
|
+
const key = String(prop);
|
|
529
|
+
const childPath = basePrefix + key;
|
|
530
|
+
const rawValue = value != null && typeof value === "object" && value[RAW] ? value[RAW] : value;
|
|
531
|
+
Reflect.set(target, prop, rawValue);
|
|
532
|
+
if (rawValue != null && typeof rawValue === "object") {
|
|
533
|
+
invalidateChildren(childPath);
|
|
534
|
+
}
|
|
535
|
+
if (isArr && key !== "length") {
|
|
536
|
+
const lengthPath = basePrefix + "length";
|
|
537
|
+
const lenPair = signals.get(lengthPath);
|
|
538
|
+
if (lenPair) {
|
|
539
|
+
lenPair[1](target.length);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
const [, setter2] = getSignal(childPath, rawValue);
|
|
543
|
+
setter2(rawValue);
|
|
544
|
+
return true;
|
|
545
|
+
},
|
|
546
|
+
// -------------------------------------------------------------------
|
|
547
|
+
// HAS — track membership checks
|
|
548
|
+
// -------------------------------------------------------------------
|
|
549
|
+
has(target, prop) {
|
|
550
|
+
if (typeof prop === "symbol") {
|
|
551
|
+
return Reflect.has(target, prop);
|
|
552
|
+
}
|
|
553
|
+
const key = String(prop);
|
|
554
|
+
const childPath = basePrefix + key;
|
|
555
|
+
const [getter] = getSignal(childPath, Reflect.get(target, prop));
|
|
556
|
+
getter();
|
|
557
|
+
return Reflect.has(target, prop);
|
|
558
|
+
},
|
|
559
|
+
// -------------------------------------------------------------------
|
|
560
|
+
// OWNKEYS — return keys from the raw target
|
|
561
|
+
// -------------------------------------------------------------------
|
|
562
|
+
ownKeys(target) {
|
|
563
|
+
return Reflect.ownKeys(target);
|
|
564
|
+
},
|
|
565
|
+
// -------------------------------------------------------------------
|
|
566
|
+
// GETOWNPROPERTYDESCRIPTOR — needed for Object.keys / spread / ...
|
|
567
|
+
// -------------------------------------------------------------------
|
|
568
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
569
|
+
return Object.getOwnPropertyDescriptor(target, prop);
|
|
570
|
+
},
|
|
571
|
+
// -------------------------------------------------------------------
|
|
572
|
+
// DELETEPROPERTY — clean up signals when a key is removed
|
|
573
|
+
// -------------------------------------------------------------------
|
|
574
|
+
deleteProperty(target, prop) {
|
|
575
|
+
if (typeof prop === "symbol") {
|
|
576
|
+
return Reflect.deleteProperty(target, prop);
|
|
577
|
+
}
|
|
578
|
+
const key = String(prop);
|
|
579
|
+
const childPath = basePrefix + key;
|
|
580
|
+
const result = Reflect.deleteProperty(target, prop);
|
|
581
|
+
invalidateChildren(childPath);
|
|
582
|
+
signals.delete(childPath);
|
|
583
|
+
const parentPath = basePath;
|
|
584
|
+
if (parentPath !== void 0) {
|
|
585
|
+
const parentSet = children2.get(parentPath);
|
|
586
|
+
if (parentSet) {
|
|
587
|
+
parentSet.delete(childPath);
|
|
588
|
+
if (parentSet.size === 0) children2.delete(parentPath);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
children2.delete(childPath);
|
|
592
|
+
return result;
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
proxyCache.set(raw, proxy);
|
|
596
|
+
return proxy;
|
|
597
|
+
}
|
|
598
|
+
const rootProxy = wrap(initial, "");
|
|
599
|
+
function getCurrentSnapshot() {
|
|
600
|
+
return chunk27QSSN4E_cjs.untrack(() => deepClone(initial));
|
|
601
|
+
}
|
|
602
|
+
const setter = (partial) => {
|
|
603
|
+
const updates = typeof partial === "function" ? partial(getCurrentSnapshot()) : partial;
|
|
604
|
+
chunk27QSSN4E_cjs.batch(() => {
|
|
605
|
+
for (const key of Object.keys(updates)) {
|
|
606
|
+
rootProxy[key] = updates[key];
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
};
|
|
610
|
+
return [rootProxy, setter];
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/state/history.ts
|
|
614
|
+
function createHistory(source, options) {
|
|
615
|
+
const [sourceGet, sourceSet] = source;
|
|
616
|
+
const maxLength = options?.maxLength ?? 100;
|
|
617
|
+
let _stack = [sourceGet()];
|
|
618
|
+
let _cursor = 0;
|
|
619
|
+
const [stackSignal, setStackSignal] = chunkFPSLC62A_cjs.createValueSignal([..._stack]);
|
|
620
|
+
const [cursorSignal, setCursorSignal] = chunkFPSLC62A_cjs.createValueSignal(_cursor);
|
|
621
|
+
const [stackLenSignal, setStackLenSignal] = chunkFPSLC62A_cjs.createValueSignal(_stack.length);
|
|
622
|
+
function syncSignals() {
|
|
623
|
+
chunk27QSSN4E_cjs.batch(() => {
|
|
624
|
+
setStackSignal([..._stack]);
|
|
625
|
+
setCursorSignal(_cursor);
|
|
626
|
+
setStackLenSignal(_stack.length);
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
let ignoreNext = false;
|
|
630
|
+
let isFirstRun = true;
|
|
631
|
+
chunk27QSSN4E_cjs.internalEffect(() => {
|
|
632
|
+
const value = sourceGet();
|
|
633
|
+
if (isFirstRun) {
|
|
634
|
+
isFirstRun = false;
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
if (ignoreNext) {
|
|
638
|
+
ignoreNext = false;
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
_stack = _stack.slice(0, _cursor + 1);
|
|
642
|
+
_stack.push(value);
|
|
643
|
+
if (_stack.length > maxLength) {
|
|
644
|
+
_stack.splice(0, _stack.length - maxLength);
|
|
645
|
+
}
|
|
646
|
+
_cursor = _stack.length - 1;
|
|
647
|
+
syncSignals();
|
|
648
|
+
});
|
|
649
|
+
const canUndo = () => cursorSignal() > 0;
|
|
650
|
+
const canRedo = () => cursorSignal() < stackLenSignal() - 1;
|
|
651
|
+
const undo = () => {
|
|
652
|
+
if (_cursor <= 0) return;
|
|
653
|
+
_cursor--;
|
|
654
|
+
ignoreNext = true;
|
|
655
|
+
sourceSet(_stack[_cursor]);
|
|
656
|
+
syncSignals();
|
|
657
|
+
};
|
|
658
|
+
const redo = () => {
|
|
659
|
+
if (_cursor >= _stack.length - 1) return;
|
|
660
|
+
_cursor++;
|
|
661
|
+
ignoreNext = true;
|
|
662
|
+
sourceSet(_stack[_cursor]);
|
|
663
|
+
syncSignals();
|
|
664
|
+
};
|
|
665
|
+
const clear = () => {
|
|
666
|
+
const currentValue = sourceGet();
|
|
667
|
+
_stack = [currentValue];
|
|
668
|
+
_cursor = 0;
|
|
669
|
+
syncSignals();
|
|
670
|
+
};
|
|
671
|
+
return {
|
|
672
|
+
undo,
|
|
673
|
+
redo,
|
|
674
|
+
canUndo,
|
|
675
|
+
canRedo,
|
|
676
|
+
history: () => stackSignal(),
|
|
677
|
+
cursor: () => cursorSignal(),
|
|
678
|
+
clear
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// src/state/persist.ts
|
|
683
|
+
function persist(source, key, options) {
|
|
684
|
+
const [sourceGet, sourceSet] = source;
|
|
685
|
+
const storage = options?.storage ?? globalThis.localStorage;
|
|
686
|
+
const serialize = options?.serialize ?? JSON.stringify;
|
|
687
|
+
const deserialize = options?.deserialize ?? JSON.parse;
|
|
688
|
+
try {
|
|
689
|
+
const stored = storage.getItem(key);
|
|
690
|
+
if (stored !== null) {
|
|
691
|
+
const value = deserialize(stored);
|
|
692
|
+
sourceSet(value);
|
|
693
|
+
}
|
|
694
|
+
} catch {
|
|
695
|
+
}
|
|
696
|
+
chunk27QSSN4E_cjs.internalEffect(() => {
|
|
697
|
+
const value = sourceGet();
|
|
698
|
+
try {
|
|
699
|
+
const serialized = serialize(value);
|
|
700
|
+
storage.setItem(key, serialized);
|
|
701
|
+
} catch {
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// src/events/bus.ts
|
|
707
|
+
function createBus() {
|
|
708
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
709
|
+
function getHandlers(event) {
|
|
710
|
+
let set = listeners.get(event);
|
|
711
|
+
if (!set) {
|
|
712
|
+
set = /* @__PURE__ */ new Set();
|
|
713
|
+
listeners.set(event, set);
|
|
714
|
+
}
|
|
715
|
+
return set;
|
|
716
|
+
}
|
|
717
|
+
function on2(event, handler) {
|
|
718
|
+
const set = getHandlers(event);
|
|
719
|
+
set.add(handler);
|
|
720
|
+
return () => {
|
|
721
|
+
set.delete(handler);
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
function once(event, handler) {
|
|
725
|
+
const wrapper = (payload) => {
|
|
726
|
+
off(event, wrapper);
|
|
727
|
+
handler(payload);
|
|
728
|
+
};
|
|
729
|
+
return on2(event, wrapper);
|
|
730
|
+
}
|
|
731
|
+
function emit(event, payload) {
|
|
732
|
+
const set = listeners.get(event);
|
|
733
|
+
if (set) {
|
|
734
|
+
for (const handler of [...set]) {
|
|
735
|
+
try {
|
|
736
|
+
handler(payload);
|
|
737
|
+
} catch (e) {
|
|
738
|
+
console.error(`[forma] Bus handler error on "${String(event)}":`, e);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
function off(event, handler) {
|
|
744
|
+
const set = listeners.get(event);
|
|
745
|
+
if (set) {
|
|
746
|
+
set.delete(handler);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function clear() {
|
|
750
|
+
listeners.clear();
|
|
751
|
+
}
|
|
752
|
+
return { on: on2, once, emit, off, clear };
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// src/events/delegate.ts
|
|
756
|
+
function delegate(container, selector, event, handler, options) {
|
|
757
|
+
const listener = (e) => {
|
|
758
|
+
const target = e.target;
|
|
759
|
+
if (!(target instanceof HTMLElement)) return;
|
|
760
|
+
const root = container instanceof Document ? container.documentElement : container;
|
|
761
|
+
const matched = target.closest(selector);
|
|
762
|
+
if (matched instanceof HTMLElement && root.contains(matched)) {
|
|
763
|
+
handler(e, matched);
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
container.addEventListener(event, listener, options);
|
|
767
|
+
return () => {
|
|
768
|
+
container.removeEventListener(event, listener, options);
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// src/events/keyboard.ts
|
|
773
|
+
function parseCombo(combo) {
|
|
774
|
+
const parts = combo.toLowerCase().split("+").map((p) => p.trim());
|
|
775
|
+
const modifiers = {
|
|
776
|
+
ctrl: false,
|
|
777
|
+
shift: false,
|
|
778
|
+
alt: false,
|
|
779
|
+
meta: false,
|
|
780
|
+
key: ""
|
|
781
|
+
};
|
|
782
|
+
for (const part of parts) {
|
|
783
|
+
switch (part) {
|
|
784
|
+
case "ctrl":
|
|
785
|
+
case "control":
|
|
786
|
+
modifiers.ctrl = true;
|
|
787
|
+
break;
|
|
788
|
+
case "shift":
|
|
789
|
+
modifiers.shift = true;
|
|
790
|
+
break;
|
|
791
|
+
case "alt":
|
|
792
|
+
modifiers.alt = true;
|
|
793
|
+
break;
|
|
794
|
+
case "meta":
|
|
795
|
+
case "cmd":
|
|
796
|
+
case "command":
|
|
797
|
+
modifiers.meta = true;
|
|
798
|
+
break;
|
|
799
|
+
default:
|
|
800
|
+
modifiers.key = part;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return modifiers;
|
|
804
|
+
}
|
|
805
|
+
function matchesCombo(e, parsed) {
|
|
806
|
+
if (e.ctrlKey !== parsed.ctrl) return false;
|
|
807
|
+
if (e.shiftKey !== parsed.shift) return false;
|
|
808
|
+
if (e.altKey !== parsed.alt) return false;
|
|
809
|
+
if (e.metaKey !== parsed.meta) return false;
|
|
810
|
+
return e.key.toLowerCase() === parsed.key;
|
|
811
|
+
}
|
|
812
|
+
function onKey(combo, handler, options) {
|
|
813
|
+
const target = options?.target ?? document;
|
|
814
|
+
const shouldPreventDefault = options?.preventDefault ?? true;
|
|
815
|
+
const parsed = parseCombo(combo);
|
|
816
|
+
const listener = (e) => {
|
|
817
|
+
if (!(e instanceof KeyboardEvent)) return;
|
|
818
|
+
if (matchesCombo(e, parsed)) {
|
|
819
|
+
if (shouldPreventDefault) {
|
|
820
|
+
e.preventDefault();
|
|
821
|
+
}
|
|
822
|
+
handler(e);
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
target.addEventListener("keydown", listener);
|
|
826
|
+
return () => {
|
|
827
|
+
target.removeEventListener("keydown", listener);
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// src/dom-utils/query.ts
|
|
832
|
+
function $(selector, parent2) {
|
|
833
|
+
return (parent2 ?? document).querySelector(selector);
|
|
834
|
+
}
|
|
835
|
+
function $$(selector, parent2) {
|
|
836
|
+
return Array.from((parent2 ?? document).querySelectorAll(selector));
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// src/dom-utils/mutate.ts
|
|
840
|
+
function addClass(el, ...classes) {
|
|
841
|
+
el.classList.add(...classes);
|
|
842
|
+
}
|
|
843
|
+
function removeClass(el, ...classes) {
|
|
844
|
+
el.classList.remove(...classes);
|
|
845
|
+
}
|
|
846
|
+
function toggleClass(el, className, force) {
|
|
847
|
+
return el.classList.toggle(className, force);
|
|
848
|
+
}
|
|
849
|
+
function setStyle(el, styles) {
|
|
850
|
+
for (const [key, value] of Object.entries(styles)) {
|
|
851
|
+
if (value !== void 0) {
|
|
852
|
+
el.style[key] = value;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
function setAttr(el, attrs) {
|
|
857
|
+
for (const [name, value] of Object.entries(attrs)) {
|
|
858
|
+
if (value === false || value === null) {
|
|
859
|
+
el.removeAttribute(name);
|
|
860
|
+
} else if (value === true) {
|
|
861
|
+
el.setAttribute(name, "");
|
|
862
|
+
} else {
|
|
863
|
+
el.setAttribute(name, value);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
function setText(el, text) {
|
|
868
|
+
el.textContent = text;
|
|
869
|
+
}
|
|
870
|
+
function setHTML(el, html) {
|
|
871
|
+
el.innerHTML = html;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// src/dom-utils/traverse.ts
|
|
875
|
+
function closest(el, selector) {
|
|
876
|
+
return el.closest(selector);
|
|
877
|
+
}
|
|
878
|
+
function children(el, selector) {
|
|
879
|
+
const all = Array.from(el.children);
|
|
880
|
+
if (!selector) return all;
|
|
881
|
+
return all.filter((child) => child.matches(selector));
|
|
882
|
+
}
|
|
883
|
+
function siblings(el, selector) {
|
|
884
|
+
const parentEl = el.parentElement;
|
|
885
|
+
if (!parentEl) return [];
|
|
886
|
+
const all = Array.from(parentEl.children);
|
|
887
|
+
const sibs = all.filter((child) => child !== el);
|
|
888
|
+
if (!selector) return sibs;
|
|
889
|
+
return sibs.filter((child) => child.matches(selector));
|
|
890
|
+
}
|
|
891
|
+
function parent(el) {
|
|
892
|
+
return el.parentElement;
|
|
893
|
+
}
|
|
894
|
+
function nextSibling(el, selector) {
|
|
895
|
+
let sib = el.nextElementSibling;
|
|
896
|
+
while (sib) {
|
|
897
|
+
if (sib instanceof HTMLElement) {
|
|
898
|
+
if (!selector || sib.matches(selector)) {
|
|
899
|
+
return sib;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
sib = sib.nextElementSibling;
|
|
903
|
+
}
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
function prevSibling(el, selector) {
|
|
907
|
+
let sib = el.previousElementSibling;
|
|
908
|
+
while (sib) {
|
|
909
|
+
if (sib instanceof HTMLElement) {
|
|
910
|
+
if (!selector || sib.matches(selector)) {
|
|
911
|
+
return sib;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
sib = sib.previousElementSibling;
|
|
915
|
+
}
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// src/dom-utils/observe.ts
|
|
920
|
+
function onResize(el, handler) {
|
|
921
|
+
const observer = new ResizeObserver((entries) => {
|
|
922
|
+
for (const entry of entries) {
|
|
923
|
+
handler(entry);
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
observer.observe(el);
|
|
927
|
+
return () => {
|
|
928
|
+
observer.disconnect();
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
function onIntersect(el, handler, options) {
|
|
932
|
+
const observer = new IntersectionObserver((entries) => {
|
|
933
|
+
for (const entry of entries) {
|
|
934
|
+
handler(entry);
|
|
935
|
+
}
|
|
936
|
+
}, options);
|
|
937
|
+
observer.observe(el);
|
|
938
|
+
return () => {
|
|
939
|
+
observer.disconnect();
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
function onMutation(el, handler, options) {
|
|
943
|
+
const observer = new MutationObserver((mutations) => {
|
|
944
|
+
handler(mutations);
|
|
945
|
+
});
|
|
946
|
+
observer.observe(el, options ?? { childList: true, subtree: true });
|
|
947
|
+
return () => {
|
|
948
|
+
observer.disconnect();
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// src/storage/local.ts
|
|
953
|
+
function createLocalStorage(key, options) {
|
|
954
|
+
const serialize = options?.serialize ?? JSON.stringify;
|
|
955
|
+
const deserialize = options?.deserialize ?? JSON.parse;
|
|
956
|
+
return {
|
|
957
|
+
key,
|
|
958
|
+
get() {
|
|
959
|
+
try {
|
|
960
|
+
const raw = localStorage.getItem(key);
|
|
961
|
+
if (raw === null) return null;
|
|
962
|
+
return deserialize(raw);
|
|
963
|
+
} catch {
|
|
964
|
+
return null;
|
|
965
|
+
}
|
|
966
|
+
},
|
|
967
|
+
set(value) {
|
|
968
|
+
const serialized = serialize(value);
|
|
969
|
+
localStorage.setItem(key, serialized);
|
|
970
|
+
},
|
|
971
|
+
remove() {
|
|
972
|
+
localStorage.removeItem(key);
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// src/storage/session.ts
|
|
978
|
+
function createSessionStorage(key, options) {
|
|
979
|
+
const serialize = options?.serialize ?? JSON.stringify;
|
|
980
|
+
const deserialize = options?.deserialize ?? JSON.parse;
|
|
981
|
+
return {
|
|
982
|
+
key,
|
|
983
|
+
get() {
|
|
984
|
+
try {
|
|
985
|
+
const raw = sessionStorage.getItem(key);
|
|
986
|
+
if (raw === null) return null;
|
|
987
|
+
return deserialize(raw);
|
|
988
|
+
} catch {
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
set(value) {
|
|
993
|
+
const serialized = serialize(value);
|
|
994
|
+
sessionStorage.setItem(key, serialized);
|
|
995
|
+
},
|
|
996
|
+
remove() {
|
|
997
|
+
sessionStorage.removeItem(key);
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// src/storage/indexed.ts
|
|
1003
|
+
var dbCache = /* @__PURE__ */ new Map();
|
|
1004
|
+
function openDB(dbName, storeName) {
|
|
1005
|
+
const cacheKey = `${dbName}::${storeName}`;
|
|
1006
|
+
const cached = dbCache.get(cacheKey);
|
|
1007
|
+
if (cached) return cached;
|
|
1008
|
+
const promise = new Promise((resolve, reject) => {
|
|
1009
|
+
const probe = indexedDB.open(dbName);
|
|
1010
|
+
probe.onerror = () => reject(probe.error);
|
|
1011
|
+
probe.onsuccess = () => {
|
|
1012
|
+
const db = probe.result;
|
|
1013
|
+
if (db.objectStoreNames.contains(storeName)) {
|
|
1014
|
+
resolve(db);
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
const nextVersion = db.version + 1;
|
|
1018
|
+
db.close();
|
|
1019
|
+
const upgrade = indexedDB.open(dbName, nextVersion);
|
|
1020
|
+
upgrade.onerror = () => reject(upgrade.error);
|
|
1021
|
+
upgrade.onupgradeneeded = () => {
|
|
1022
|
+
const upgradedDB = upgrade.result;
|
|
1023
|
+
if (!upgradedDB.objectStoreNames.contains(storeName)) {
|
|
1024
|
+
upgradedDB.createObjectStore(storeName);
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
upgrade.onsuccess = () => resolve(upgrade.result);
|
|
1028
|
+
};
|
|
1029
|
+
probe.onupgradeneeded = () => {
|
|
1030
|
+
const db = probe.result;
|
|
1031
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
1032
|
+
db.createObjectStore(storeName);
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
});
|
|
1036
|
+
dbCache.set(cacheKey, promise);
|
|
1037
|
+
promise.catch(() => {
|
|
1038
|
+
dbCache.delete(cacheKey);
|
|
1039
|
+
});
|
|
1040
|
+
return promise;
|
|
1041
|
+
}
|
|
1042
|
+
function createIndexedDB(dbName, storeName = "default") {
|
|
1043
|
+
function withStore(mode, fn) {
|
|
1044
|
+
return openDB(dbName, storeName).then(
|
|
1045
|
+
(db) => new Promise((resolve, reject) => {
|
|
1046
|
+
const tx = db.transaction(storeName, mode);
|
|
1047
|
+
const store = tx.objectStore(storeName);
|
|
1048
|
+
const request = fn(store);
|
|
1049
|
+
request.onsuccess = () => resolve(request.result);
|
|
1050
|
+
request.onerror = () => reject(request.error);
|
|
1051
|
+
})
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
return {
|
|
1055
|
+
get(key) {
|
|
1056
|
+
return withStore("readonly", (store) => store.get(key));
|
|
1057
|
+
},
|
|
1058
|
+
set(key, value) {
|
|
1059
|
+
return withStore("readwrite", (store) => store.put(value, key)).then(
|
|
1060
|
+
() => void 0
|
|
1061
|
+
);
|
|
1062
|
+
},
|
|
1063
|
+
delete(key) {
|
|
1064
|
+
return withStore("readwrite", (store) => store.delete(key)).then(
|
|
1065
|
+
() => void 0
|
|
1066
|
+
);
|
|
1067
|
+
},
|
|
1068
|
+
getAll() {
|
|
1069
|
+
return withStore("readonly", (store) => store.getAll());
|
|
1070
|
+
},
|
|
1071
|
+
keys() {
|
|
1072
|
+
return withStore("readonly", (store) => store.getAllKeys()).then(
|
|
1073
|
+
(keys) => keys.map(String)
|
|
1074
|
+
);
|
|
1075
|
+
},
|
|
1076
|
+
clear() {
|
|
1077
|
+
return withStore("readwrite", (store) => store.clear()).then(
|
|
1078
|
+
() => void 0
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// src/http/fetch.ts
|
|
1085
|
+
function createFetch(url, options) {
|
|
1086
|
+
const [data, setData] = chunkFPSLC62A_cjs.createSignal(null);
|
|
1087
|
+
const [error, setError] = chunkFPSLC62A_cjs.createSignal(null);
|
|
1088
|
+
const [loading, setLoading] = chunkFPSLC62A_cjs.createSignal(false);
|
|
1089
|
+
let currentController = null;
|
|
1090
|
+
function resolveURL() {
|
|
1091
|
+
const raw = typeof url === "function" ? url() : url;
|
|
1092
|
+
const base = options?.base ?? "";
|
|
1093
|
+
const fullURL = new URL(raw, base || void 0);
|
|
1094
|
+
if (options?.params) {
|
|
1095
|
+
for (const [key, value] of Object.entries(options.params)) {
|
|
1096
|
+
fullURL.searchParams.set(key, value);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return fullURL.toString();
|
|
1100
|
+
}
|
|
1101
|
+
async function execute() {
|
|
1102
|
+
if (currentController) {
|
|
1103
|
+
currentController.abort();
|
|
1104
|
+
}
|
|
1105
|
+
currentController = new AbortController();
|
|
1106
|
+
const controller = currentController;
|
|
1107
|
+
const timeoutMs = options?.timeout ?? 3e4;
|
|
1108
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
1109
|
+
setLoading(true);
|
|
1110
|
+
setError(null);
|
|
1111
|
+
try {
|
|
1112
|
+
const resolvedURL = resolveURL();
|
|
1113
|
+
const { base: _base, params: _params, timeout: _timeout, transform, ...fetchInit } = options ?? {};
|
|
1114
|
+
const response = await fetch(resolvedURL, {
|
|
1115
|
+
...fetchInit,
|
|
1116
|
+
signal: controller.signal
|
|
1117
|
+
});
|
|
1118
|
+
if (!response.ok) {
|
|
1119
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
1120
|
+
}
|
|
1121
|
+
const json = await response.json();
|
|
1122
|
+
const transformed = transform ? transform(json) : json;
|
|
1123
|
+
setData(transformed);
|
|
1124
|
+
} catch (err) {
|
|
1125
|
+
if (err?.name === "AbortError") {
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1129
|
+
} finally {
|
|
1130
|
+
clearTimeout(timeoutId);
|
|
1131
|
+
if (currentController === controller) {
|
|
1132
|
+
currentController = null;
|
|
1133
|
+
setLoading(false);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
if (typeof url === "function") {
|
|
1138
|
+
chunk27QSSN4E_cjs.internalEffect(() => {
|
|
1139
|
+
url();
|
|
1140
|
+
execute();
|
|
1141
|
+
});
|
|
1142
|
+
} else {
|
|
1143
|
+
execute();
|
|
1144
|
+
}
|
|
1145
|
+
return {
|
|
1146
|
+
data,
|
|
1147
|
+
error,
|
|
1148
|
+
loading,
|
|
1149
|
+
refetch: execute,
|
|
1150
|
+
abort() {
|
|
1151
|
+
if (currentController) {
|
|
1152
|
+
currentController.abort();
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
async function fetchJSON(url, options) {
|
|
1158
|
+
const response = await fetch(url, options);
|
|
1159
|
+
if (!response.ok) {
|
|
1160
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
1161
|
+
}
|
|
1162
|
+
return await response.json();
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// src/http/sse.ts
|
|
1166
|
+
function createSSE(url, options) {
|
|
1167
|
+
const [data, setData] = chunkFPSLC62A_cjs.createSignal(null);
|
|
1168
|
+
const [error, setError] = chunkFPSLC62A_cjs.createSignal(null);
|
|
1169
|
+
const [connected, setConnected] = chunkFPSLC62A_cjs.createSignal(false);
|
|
1170
|
+
const source = new EventSource(url, {
|
|
1171
|
+
withCredentials: options?.withCredentials ?? false
|
|
1172
|
+
});
|
|
1173
|
+
source.onopen = () => {
|
|
1174
|
+
setConnected(true);
|
|
1175
|
+
setError(null);
|
|
1176
|
+
};
|
|
1177
|
+
source.onmessage = (event) => {
|
|
1178
|
+
try {
|
|
1179
|
+
const parsed = JSON.parse(event.data);
|
|
1180
|
+
setData(parsed);
|
|
1181
|
+
} catch {
|
|
1182
|
+
setData(event.data);
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
source.onerror = (event) => {
|
|
1186
|
+
setError(event);
|
|
1187
|
+
setConnected(false);
|
|
1188
|
+
};
|
|
1189
|
+
return {
|
|
1190
|
+
data,
|
|
1191
|
+
error,
|
|
1192
|
+
connected,
|
|
1193
|
+
close() {
|
|
1194
|
+
source.close();
|
|
1195
|
+
setConnected(false);
|
|
1196
|
+
},
|
|
1197
|
+
on(event, handler) {
|
|
1198
|
+
const listener = (e) => {
|
|
1199
|
+
try {
|
|
1200
|
+
handler(JSON.parse(e.data));
|
|
1201
|
+
} catch {
|
|
1202
|
+
handler(e.data);
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
source.addEventListener(event, listener);
|
|
1206
|
+
return () => {
|
|
1207
|
+
source.removeEventListener(event, listener);
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
// src/http/ws.ts
|
|
1214
|
+
function createWebSocket(url, options) {
|
|
1215
|
+
const shouldReconnect = options?.reconnect ?? true;
|
|
1216
|
+
const baseInterval = options?.reconnectInterval ?? 1e3;
|
|
1217
|
+
const maxReconnects = options?.maxReconnects ?? 5;
|
|
1218
|
+
const [data, setData] = chunkFPSLC62A_cjs.createSignal(null);
|
|
1219
|
+
const [status, setStatus] = chunkFPSLC62A_cjs.createSignal("connecting");
|
|
1220
|
+
const handlers = /* @__PURE__ */ new Set();
|
|
1221
|
+
let socket = null;
|
|
1222
|
+
let reconnectCount = 0;
|
|
1223
|
+
let reconnectTimer = null;
|
|
1224
|
+
let permanentlyClosed = false;
|
|
1225
|
+
function connect() {
|
|
1226
|
+
if (permanentlyClosed) return;
|
|
1227
|
+
setStatus("connecting");
|
|
1228
|
+
socket = new WebSocket(url, options?.protocols);
|
|
1229
|
+
socket.onopen = () => {
|
|
1230
|
+
setStatus("open");
|
|
1231
|
+
reconnectCount = 0;
|
|
1232
|
+
};
|
|
1233
|
+
socket.onmessage = (event) => {
|
|
1234
|
+
let parsed;
|
|
1235
|
+
try {
|
|
1236
|
+
parsed = JSON.parse(event.data);
|
|
1237
|
+
} catch {
|
|
1238
|
+
parsed = event.data;
|
|
1239
|
+
}
|
|
1240
|
+
setData(parsed);
|
|
1241
|
+
for (const handler of handlers) {
|
|
1242
|
+
handler(parsed);
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
socket.onerror = () => {
|
|
1246
|
+
setStatus("error");
|
|
1247
|
+
};
|
|
1248
|
+
socket.onclose = () => {
|
|
1249
|
+
if (permanentlyClosed) {
|
|
1250
|
+
setStatus("closed");
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
setStatus("closed");
|
|
1254
|
+
if (shouldReconnect && reconnectCount < maxReconnects) {
|
|
1255
|
+
const delay = baseInterval * Math.pow(2, reconnectCount);
|
|
1256
|
+
reconnectCount++;
|
|
1257
|
+
reconnectTimer = setTimeout(connect, delay);
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
connect();
|
|
1262
|
+
return {
|
|
1263
|
+
data,
|
|
1264
|
+
status,
|
|
1265
|
+
send(value) {
|
|
1266
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
1267
|
+
socket.send(JSON.stringify(value));
|
|
1268
|
+
}
|
|
1269
|
+
},
|
|
1270
|
+
close() {
|
|
1271
|
+
permanentlyClosed = true;
|
|
1272
|
+
if (reconnectTimer !== null) {
|
|
1273
|
+
clearTimeout(reconnectTimer);
|
|
1274
|
+
reconnectTimer = null;
|
|
1275
|
+
}
|
|
1276
|
+
if (socket) {
|
|
1277
|
+
socket.close();
|
|
1278
|
+
socket = null;
|
|
1279
|
+
}
|
|
1280
|
+
setStatus("closed");
|
|
1281
|
+
},
|
|
1282
|
+
on(handler) {
|
|
1283
|
+
handlers.add(handler);
|
|
1284
|
+
return () => {
|
|
1285
|
+
handlers.delete(handler);
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
// src/server/action.ts
|
|
1292
|
+
function createAction(serverFn, options) {
|
|
1293
|
+
const [pending, setPending] = chunkFPSLC62A_cjs.createValueSignal(false);
|
|
1294
|
+
const [error, setError] = chunkFPSLC62A_cjs.createValueSignal(void 0);
|
|
1295
|
+
const action = async (...args) => {
|
|
1296
|
+
setPending(true);
|
|
1297
|
+
setError(void 0);
|
|
1298
|
+
if (options?.optimistic) {
|
|
1299
|
+
try {
|
|
1300
|
+
chunk27QSSN4E_cjs.batch(() => options.optimistic(...args));
|
|
1301
|
+
} catch {
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
try {
|
|
1305
|
+
const result = await serverFn(...args);
|
|
1306
|
+
if (options?.onSuccess) {
|
|
1307
|
+
chunk27QSSN4E_cjs.batch(() => options.onSuccess(result, ...args));
|
|
1308
|
+
}
|
|
1309
|
+
if (options?.invalidates) {
|
|
1310
|
+
for (const resource of options.invalidates) {
|
|
1311
|
+
resource.refetch();
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
setPending(false);
|
|
1315
|
+
return result;
|
|
1316
|
+
} catch (err) {
|
|
1317
|
+
if (options?.onError) {
|
|
1318
|
+
try {
|
|
1319
|
+
chunk27QSSN4E_cjs.batch(() => options.onError(err, ...args));
|
|
1320
|
+
} catch {
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
setError(err);
|
|
1324
|
+
setPending(false);
|
|
1325
|
+
throw err;
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
const typedAction = action;
|
|
1329
|
+
typedAction.pending = pending;
|
|
1330
|
+
typedAction.error = error;
|
|
1331
|
+
typedAction.clearError = () => setError(void 0);
|
|
1332
|
+
return typedAction;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// src/server/mutation.ts
|
|
1336
|
+
var resourceRegistry = /* @__PURE__ */ new Map();
|
|
1337
|
+
function registerResource(key, resource) {
|
|
1338
|
+
resourceRegistry.set(key, resource);
|
|
1339
|
+
}
|
|
1340
|
+
function unregisterResource(key) {
|
|
1341
|
+
resourceRegistry.delete(key);
|
|
1342
|
+
}
|
|
1343
|
+
function applyRevalidation(revalidateData) {
|
|
1344
|
+
for (const [key, freshData] of Object.entries(revalidateData)) {
|
|
1345
|
+
const resource = resourceRegistry.get(key);
|
|
1346
|
+
if (resource) {
|
|
1347
|
+
resource.mutate(freshData);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
function enableAutoRevalidation() {
|
|
1352
|
+
const handler = (event) => {
|
|
1353
|
+
const detail = event.detail;
|
|
1354
|
+
if (detail && typeof detail === "object") {
|
|
1355
|
+
applyRevalidation(detail);
|
|
1356
|
+
}
|
|
1357
|
+
};
|
|
1358
|
+
window.addEventListener("forma:revalidate", handler);
|
|
1359
|
+
return () => window.removeEventListener("forma:revalidate", handler);
|
|
1360
|
+
}
|
|
1361
|
+
function withRevalidation(data, revalidate) {
|
|
1362
|
+
return { data, __revalidate: revalidate };
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// src/server/rpc-client.ts
|
|
1366
|
+
function $$serverFunction(endpoint) {
|
|
1367
|
+
const rpcFn = async (...args) => {
|
|
1368
|
+
const response = await fetch(endpoint, {
|
|
1369
|
+
method: "POST",
|
|
1370
|
+
headers: {
|
|
1371
|
+
"Content-Type": "application/json",
|
|
1372
|
+
"X-Forma-RPC": "1"
|
|
1373
|
+
},
|
|
1374
|
+
body: JSON.stringify({ args })
|
|
1375
|
+
});
|
|
1376
|
+
if (!response.ok) {
|
|
1377
|
+
const errorText = await response.text();
|
|
1378
|
+
throw new Error(`Server function failed (${response.status}): ${errorText}`);
|
|
1379
|
+
}
|
|
1380
|
+
const result = await response.json();
|
|
1381
|
+
if (result && typeof result === "object" && "__revalidate" in result) {
|
|
1382
|
+
if (typeof window !== "undefined") {
|
|
1383
|
+
window.dispatchEvent(new CustomEvent("forma:revalidate", {
|
|
1384
|
+
detail: result.__revalidate
|
|
1385
|
+
}));
|
|
1386
|
+
}
|
|
1387
|
+
return result.data;
|
|
1388
|
+
}
|
|
1389
|
+
return result;
|
|
1390
|
+
};
|
|
1391
|
+
return rpcFn;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
// src/server/rpc-handler.ts
|
|
1395
|
+
var registry = /* @__PURE__ */ new Map();
|
|
1396
|
+
function registerServerFunction(endpoint, fn) {
|
|
1397
|
+
registry.set(endpoint, fn);
|
|
1398
|
+
}
|
|
1399
|
+
function getServerFunction(endpoint) {
|
|
1400
|
+
return registry.get(endpoint);
|
|
1401
|
+
}
|
|
1402
|
+
function getRegisteredEndpoints() {
|
|
1403
|
+
return [...registry.keys()];
|
|
1404
|
+
}
|
|
1405
|
+
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1406
|
+
async function handleRPC(endpoint, body, revalidateData) {
|
|
1407
|
+
const endpointName = endpoint.split("/").pop() ?? "";
|
|
1408
|
+
if (FORBIDDEN_KEYS.has(endpointName)) {
|
|
1409
|
+
return { error: "Forbidden endpoint name" };
|
|
1410
|
+
}
|
|
1411
|
+
const fn = registry.get(endpoint);
|
|
1412
|
+
if (!fn) {
|
|
1413
|
+
return { error: `Unknown server function: ${endpoint}` };
|
|
1414
|
+
}
|
|
1415
|
+
try {
|
|
1416
|
+
const result = await fn(...body.args);
|
|
1417
|
+
if (revalidateData) {
|
|
1418
|
+
return { data: result, __revalidate: revalidateData };
|
|
1419
|
+
}
|
|
1420
|
+
return result;
|
|
1421
|
+
} catch (err) {
|
|
1422
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1423
|
+
return { error: message };
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
function createRPCMiddleware() {
|
|
1427
|
+
return async (req, res) => {
|
|
1428
|
+
if (req.method !== "POST") {
|
|
1429
|
+
res.status(405).json({ error: "Method not allowed" });
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
const body = req.body;
|
|
1433
|
+
if (!body || !Array.isArray(body.args)) {
|
|
1434
|
+
res.status(400).json({ error: "Invalid RPC request: missing args array" });
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
const result = await handleRPC(req.url, body);
|
|
1438
|
+
if (result.error) {
|
|
1439
|
+
res.status(500).json(result);
|
|
1440
|
+
} else {
|
|
1441
|
+
res.json(result);
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// src/wasm/forma-wasm.ts
|
|
1447
|
+
var wasmModule = null;
|
|
1448
|
+
var irCache = /* @__PURE__ */ new Map();
|
|
1449
|
+
async function ensureWasm() {
|
|
1450
|
+
if (wasmModule) return wasmModule;
|
|
1451
|
+
const config = window.__FORMA_WASM__;
|
|
1452
|
+
if (!config) throw new Error("No __FORMA_WASM__ config");
|
|
1453
|
+
const mod = await import(
|
|
1454
|
+
/* @vite-ignore */
|
|
1455
|
+
config.loader
|
|
1456
|
+
);
|
|
1457
|
+
await mod.default(config.binary);
|
|
1458
|
+
wasmModule = mod;
|
|
1459
|
+
return wasmModule;
|
|
1460
|
+
}
|
|
1461
|
+
async function getIR() {
|
|
1462
|
+
const config = window.__FORMA_WASM__;
|
|
1463
|
+
if (!config) throw new Error("No __FORMA_WASM__ config");
|
|
1464
|
+
const cached = irCache.get(config.ir);
|
|
1465
|
+
if (cached) return cached;
|
|
1466
|
+
const response = await fetch(config.ir);
|
|
1467
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
1468
|
+
irCache.set(config.ir, bytes);
|
|
1469
|
+
return bytes;
|
|
1470
|
+
}
|
|
1471
|
+
async function renderLocal(slotsJson) {
|
|
1472
|
+
const [wasm, ir] = await Promise.all([ensureWasm(), getIR()]);
|
|
1473
|
+
return wasm.render(ir, slotsJson);
|
|
1474
|
+
}
|
|
1475
|
+
async function renderIsland(slotsJson, islandId) {
|
|
1476
|
+
const [wasm, ir] = await Promise.all([ensureWasm(), getIR()]);
|
|
1477
|
+
return wasm.render_island(ir, slotsJson, islandId);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
Object.defineProperty(exports, "batch", {
|
|
1481
|
+
enumerable: true,
|
|
1482
|
+
get: function () { return chunk27QSSN4E_cjs.batch; }
|
|
1483
|
+
});
|
|
1484
|
+
Object.defineProperty(exports, "cleanup", {
|
|
1485
|
+
enumerable: true,
|
|
1486
|
+
get: function () { return chunk27QSSN4E_cjs.cleanup; }
|
|
1487
|
+
});
|
|
1488
|
+
Object.defineProperty(exports, "createEffect", {
|
|
1489
|
+
enumerable: true,
|
|
1490
|
+
get: function () { return chunk27QSSN4E_cjs.createEffect; }
|
|
1491
|
+
});
|
|
1492
|
+
Object.defineProperty(exports, "createList", {
|
|
1493
|
+
enumerable: true,
|
|
1494
|
+
get: function () { return chunk27QSSN4E_cjs.createList; }
|
|
1495
|
+
});
|
|
1496
|
+
Object.defineProperty(exports, "createMemo", {
|
|
1497
|
+
enumerable: true,
|
|
1498
|
+
get: function () { return chunk27QSSN4E_cjs.createMemo; }
|
|
1499
|
+
});
|
|
1500
|
+
Object.defineProperty(exports, "createReducer", {
|
|
1501
|
+
enumerable: true,
|
|
1502
|
+
get: function () { return chunk27QSSN4E_cjs.createReducer; }
|
|
1503
|
+
});
|
|
1504
|
+
Object.defineProperty(exports, "createRef", {
|
|
1505
|
+
enumerable: true,
|
|
1506
|
+
get: function () { return chunk27QSSN4E_cjs.createRef; }
|
|
1507
|
+
});
|
|
1508
|
+
Object.defineProperty(exports, "createResource", {
|
|
1509
|
+
enumerable: true,
|
|
1510
|
+
get: function () { return chunk27QSSN4E_cjs.createResource; }
|
|
1511
|
+
});
|
|
1512
|
+
Object.defineProperty(exports, "createRoot", {
|
|
1513
|
+
enumerable: true,
|
|
1514
|
+
get: function () { return chunk27QSSN4E_cjs.createRoot; }
|
|
1515
|
+
});
|
|
1516
|
+
Object.defineProperty(exports, "createShow", {
|
|
1517
|
+
enumerable: true,
|
|
1518
|
+
get: function () { return chunk27QSSN4E_cjs.createShow; }
|
|
1519
|
+
});
|
|
1520
|
+
Object.defineProperty(exports, "fragment", {
|
|
1521
|
+
enumerable: true,
|
|
1522
|
+
get: function () { return chunk27QSSN4E_cjs.fragment; }
|
|
1523
|
+
});
|
|
1524
|
+
Object.defineProperty(exports, "h", {
|
|
1525
|
+
enumerable: true,
|
|
1526
|
+
get: function () { return chunk27QSSN4E_cjs.h; }
|
|
1527
|
+
});
|
|
1528
|
+
Object.defineProperty(exports, "hydrateIsland", {
|
|
1529
|
+
enumerable: true,
|
|
1530
|
+
get: function () { return chunk27QSSN4E_cjs.hydrateIsland; }
|
|
1531
|
+
});
|
|
1532
|
+
Object.defineProperty(exports, "longestIncreasingSubsequence", {
|
|
1533
|
+
enumerable: true,
|
|
1534
|
+
get: function () { return chunk27QSSN4E_cjs.longestIncreasingSubsequence; }
|
|
1535
|
+
});
|
|
1536
|
+
Object.defineProperty(exports, "on", {
|
|
1537
|
+
enumerable: true,
|
|
1538
|
+
get: function () { return chunk27QSSN4E_cjs.on; }
|
|
1539
|
+
});
|
|
1540
|
+
Object.defineProperty(exports, "onCleanup", {
|
|
1541
|
+
enumerable: true,
|
|
1542
|
+
get: function () { return chunk27QSSN4E_cjs.onCleanup; }
|
|
1543
|
+
});
|
|
1544
|
+
Object.defineProperty(exports, "onError", {
|
|
1545
|
+
enumerable: true,
|
|
1546
|
+
get: function () { return chunk27QSSN4E_cjs.onError; }
|
|
1547
|
+
});
|
|
1548
|
+
Object.defineProperty(exports, "reconcileList", {
|
|
1549
|
+
enumerable: true,
|
|
1550
|
+
get: function () { return chunk27QSSN4E_cjs.reconcileList; }
|
|
1551
|
+
});
|
|
1552
|
+
Object.defineProperty(exports, "untrack", {
|
|
1553
|
+
enumerable: true,
|
|
1554
|
+
get: function () { return chunk27QSSN4E_cjs.untrack; }
|
|
1555
|
+
});
|
|
1556
|
+
Object.defineProperty(exports, "createComputed", {
|
|
1557
|
+
enumerable: true,
|
|
1558
|
+
get: function () { return chunkFPSLC62A_cjs.createComputed; }
|
|
1559
|
+
});
|
|
1560
|
+
Object.defineProperty(exports, "createSignal", {
|
|
1561
|
+
enumerable: true,
|
|
1562
|
+
get: function () { return chunkFPSLC62A_cjs.createSignal; }
|
|
1563
|
+
});
|
|
1564
|
+
exports.$ = $;
|
|
1565
|
+
exports.$$ = $$;
|
|
1566
|
+
exports.$$serverFunction = $$serverFunction;
|
|
1567
|
+
exports.activateIslands = activateIslands;
|
|
1568
|
+
exports.addClass = addClass;
|
|
1569
|
+
exports.applyRevalidation = applyRevalidation;
|
|
1570
|
+
exports.children = children;
|
|
1571
|
+
exports.closest = closest;
|
|
1572
|
+
exports.createAction = createAction;
|
|
1573
|
+
exports.createBus = createBus;
|
|
1574
|
+
exports.createContext = createContext;
|
|
1575
|
+
exports.createErrorBoundary = createErrorBoundary;
|
|
1576
|
+
exports.createFetch = createFetch;
|
|
1577
|
+
exports.createHistory = createHistory;
|
|
1578
|
+
exports.createIndexedDB = createIndexedDB;
|
|
1579
|
+
exports.createLocalStorage = createLocalStorage;
|
|
1580
|
+
exports.createPortal = createPortal;
|
|
1581
|
+
exports.createRPCMiddleware = createRPCMiddleware;
|
|
1582
|
+
exports.createSSE = createSSE;
|
|
1583
|
+
exports.createSessionStorage = createSessionStorage;
|
|
1584
|
+
exports.createStore = createStore;
|
|
1585
|
+
exports.createSuspense = createSuspense;
|
|
1586
|
+
exports.createSwitch = createSwitch;
|
|
1587
|
+
exports.createText = createText;
|
|
1588
|
+
exports.createWebSocket = createWebSocket;
|
|
1589
|
+
exports.defineComponent = defineComponent;
|
|
1590
|
+
exports.delegate = delegate;
|
|
1591
|
+
exports.disposeComponent = disposeComponent;
|
|
1592
|
+
exports.enableAutoRevalidation = enableAutoRevalidation;
|
|
1593
|
+
exports.fetchJSON = fetchJSON;
|
|
1594
|
+
exports.getRegisteredEndpoints = getRegisteredEndpoints;
|
|
1595
|
+
exports.getServerFunction = getServerFunction;
|
|
1596
|
+
exports.handleRPC = handleRPC;
|
|
1597
|
+
exports.inject = inject;
|
|
1598
|
+
exports.mount = mount;
|
|
1599
|
+
exports.nextSibling = nextSibling;
|
|
1600
|
+
exports.onIntersect = onIntersect;
|
|
1601
|
+
exports.onKey = onKey;
|
|
1602
|
+
exports.onMount = onMount;
|
|
1603
|
+
exports.onMutation = onMutation;
|
|
1604
|
+
exports.onResize = onResize;
|
|
1605
|
+
exports.onUnmount = onUnmount;
|
|
1606
|
+
exports.parent = parent;
|
|
1607
|
+
exports.persist = persist;
|
|
1608
|
+
exports.prevSibling = prevSibling;
|
|
1609
|
+
exports.provide = provide;
|
|
1610
|
+
exports.registerResource = registerResource;
|
|
1611
|
+
exports.registerServerFunction = registerServerFunction;
|
|
1612
|
+
exports.removeClass = removeClass;
|
|
1613
|
+
exports.renderIsland = renderIsland;
|
|
1614
|
+
exports.renderLocal = renderLocal;
|
|
1615
|
+
exports.setAttr = setAttr;
|
|
1616
|
+
exports.setHTML = setHTML;
|
|
1617
|
+
exports.setStyle = setStyle;
|
|
1618
|
+
exports.setText = setText;
|
|
1619
|
+
exports.siblings = siblings;
|
|
1620
|
+
exports.toggleClass = toggleClass;
|
|
1621
|
+
exports.trackDisposer = trackDisposer;
|
|
1622
|
+
exports.unprovide = unprovide;
|
|
1623
|
+
exports.unregisterResource = unregisterResource;
|
|
1624
|
+
exports.withRevalidation = withRevalidation;
|
|
1625
|
+
//# sourceMappingURL=index.cjs.map
|
|
1626
|
+
//# sourceMappingURL=index.cjs.map
|