@mmapp/react 0.1.0-alpha.18 → 0.1.0-alpha.19

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 (52) hide show
  1. package/dist/actions-MFI2V4DX.mjs +116 -0
  2. package/dist/atoms/index.d.mts +2 -2
  3. package/dist/atoms/index.d.ts +2 -2
  4. package/dist/atoms/index.js +1 -1
  5. package/dist/atoms/index.mjs +1 -1
  6. package/dist/builtin-atoms-C-sNyYJl.d.mts +647 -0
  7. package/dist/builtin-atoms-C-sNyYJl.d.ts +647 -0
  8. package/dist/builtin-atoms-DCKrjG7i.d.mts +96 -0
  9. package/dist/builtin-atoms-DCKrjG7i.d.ts +96 -0
  10. package/dist/builtin-atoms-DRD3EwG6.d.mts +648 -0
  11. package/dist/builtin-atoms-DRD3EwG6.d.ts +648 -0
  12. package/dist/builtin-atoms-jt04b7Rw.d.mts +643 -0
  13. package/dist/builtin-atoms-jt04b7Rw.d.ts +643 -0
  14. package/dist/chunk-247T4GDJ.mjs +677 -0
  15. package/dist/chunk-3H6CR7E7.mjs +1924 -0
  16. package/dist/chunk-3PL6FL6I.mjs +96 -0
  17. package/dist/chunk-3SJSW3C4.mjs +2039 -0
  18. package/dist/chunk-5OI2VI57.mjs +1964 -0
  19. package/dist/chunk-CL6FYZ43.mjs +105 -0
  20. package/dist/chunk-ENQOCZI5.mjs +1938 -0
  21. package/dist/chunk-FB3WCZAU.mjs +512 -0
  22. package/dist/chunk-GLJ7VC7Z.mjs +684 -0
  23. package/dist/chunk-HHMWR6NA.mjs +504 -0
  24. package/dist/chunk-HULEMSN2.mjs +120 -0
  25. package/dist/chunk-J5MW6CRU.mjs +1938 -0
  26. package/dist/chunk-PNTTKNYU.mjs +677 -0
  27. package/dist/chunk-TY5OTJP4.mjs +684 -0
  28. package/dist/chunk-WV7DVCP6.mjs +513 -0
  29. package/dist/chunk-YFMPTGUF.mjs +677 -0
  30. package/dist/{chunk-2VJQJM7S.mjs → chunk-ZDWACXZN.mjs} +1 -1
  31. package/dist/composition-BJ6QQTWT.mjs +12 -0
  32. package/dist/composition-XBGKKCI7.mjs +57 -0
  33. package/dist/content-QVPFUG4P.mjs +246 -0
  34. package/dist/control-flow-CBREHWJW.mjs +35 -0
  35. package/dist/control-flow-FWBOI6SM.mjs +35 -0
  36. package/dist/control-flow-ZWUGCDSP.mjs +35 -0
  37. package/dist/data-WCMIZYKD.mjs +97 -0
  38. package/dist/grouping-E6F377VZ.mjs +204 -0
  39. package/dist/grouping-FRPOEXO3.mjs +233 -0
  40. package/dist/index.d.mts +4 -433
  41. package/dist/index.d.ts +4 -433
  42. package/dist/index.js +3648 -581
  43. package/dist/index.mjs +335 -1040
  44. package/dist/input-PUOZDNSI.mjs +222 -0
  45. package/dist/layout-RATDMCLP.mjs +106 -0
  46. package/dist/navigation-VCT7ZBMA.mjs +15 -0
  47. package/dist/navigation-WFV7YWOU.mjs +14 -0
  48. package/dist/player/index.d.mts +37 -11
  49. package/dist/player/index.d.ts +37 -11
  50. package/dist/player/index.js +3280 -174
  51. package/dist/player/index.mjs +55 -5
  52. package/package.json +4 -4
@@ -0,0 +1,1964 @@
1
+ import {
2
+ ScopeContext,
3
+ buildScope,
4
+ builtinFunctions,
5
+ evaluateExpression,
6
+ resolvePath,
7
+ useScope
8
+ } from "./chunk-HHMWR6NA.mjs";
9
+
10
+ // src/hooks/useQuery.ts
11
+ import { useState, useEffect, useCallback, useRef } from "react";
12
+ var _globalResolver = null;
13
+ function setQueryResolver(resolver) {
14
+ _globalResolver = resolver;
15
+ }
16
+ function useQuery(slugOrDef, params = {}) {
17
+ const slug = typeof slugOrDef === "string" ? slugOrDef : slugOrDef.slug;
18
+ const [data, setData] = useState([]);
19
+ const [loading, setLoading] = useState(true);
20
+ const [error, setError] = useState(null);
21
+ const [total, setTotal] = useState(void 0);
22
+ const paramsRef = useRef(params);
23
+ paramsRef.current = params;
24
+ const fetchData = useCallback(async () => {
25
+ if (paramsRef.current.enabled === false) {
26
+ setLoading(false);
27
+ return;
28
+ }
29
+ const resolver = _globalResolver;
30
+ if (!resolver) {
31
+ setError(new Error(`useQuery: No query resolver configured. Wrap your app in a WorkflowProvider.`));
32
+ setLoading(false);
33
+ return;
34
+ }
35
+ try {
36
+ setLoading(true);
37
+ setError(null);
38
+ const result2 = await resolver.query(slug, paramsRef.current);
39
+ setData(result2.data);
40
+ setTotal(result2.total);
41
+ } catch (err) {
42
+ setError(err instanceof Error ? err : new Error(String(err)));
43
+ } finally {
44
+ setLoading(false);
45
+ }
46
+ }, [slug]);
47
+ useEffect(() => {
48
+ fetchData();
49
+ }, [fetchData]);
50
+ useEffect(() => {
51
+ if (!params.refetchInterval || params.refetchInterval <= 0) return;
52
+ const interval = setInterval(fetchData, params.refetchInterval);
53
+ return () => clearInterval(interval);
54
+ }, [fetchData, params.refetchInterval]);
55
+ const hasMore = total !== void 0 && data.length < total;
56
+ const result = {
57
+ data,
58
+ loading,
59
+ error,
60
+ refetch: fetchData,
61
+ total,
62
+ hasMore
63
+ };
64
+ return result;
65
+ }
66
+
67
+ // src/hooks/useMutation.ts
68
+ import { useState as useState2, useCallback as useCallback2, useRef as useRef2 } from "react";
69
+ var _globalMutationResolver = null;
70
+ function setMutationResolver(resolver) {
71
+ _globalMutationResolver = resolver;
72
+ }
73
+ function useMutation(slugOrDef) {
74
+ const slug = typeof slugOrDef === "string" ? slugOrDef : slugOrDef.slug;
75
+ const [isPending, setIsPending] = useState2(false);
76
+ const [error, setError] = useState2(null);
77
+ const slugRef = useRef2(slug);
78
+ slugRef.current = slug;
79
+ const getResolver = useCallback2(() => {
80
+ const resolver = _globalMutationResolver;
81
+ if (!resolver) {
82
+ throw new Error(`useMutation: No mutation resolver configured. Wrap your app in a WorkflowProvider.`);
83
+ }
84
+ return resolver;
85
+ }, []);
86
+ const create = useCallback2(async (input) => {
87
+ try {
88
+ setIsPending(true);
89
+ setError(null);
90
+ const resolver = getResolver();
91
+ return await resolver.create(slugRef.current, input);
92
+ } catch (err) {
93
+ const e = err instanceof Error ? err : new Error(String(err));
94
+ setError(e);
95
+ throw e;
96
+ } finally {
97
+ setIsPending(false);
98
+ }
99
+ }, [getResolver]);
100
+ const update = useCallback2(async (instanceId, fields) => {
101
+ try {
102
+ setIsPending(true);
103
+ setError(null);
104
+ const resolver = getResolver();
105
+ await resolver.update(slugRef.current, instanceId, fields);
106
+ } catch (err) {
107
+ const e = err instanceof Error ? err : new Error(String(err));
108
+ setError(e);
109
+ throw e;
110
+ } finally {
111
+ setIsPending(false);
112
+ }
113
+ }, [getResolver]);
114
+ const transitionFn = useCallback2(async (instanceId, transitionName, input) => {
115
+ try {
116
+ setIsPending(true);
117
+ setError(null);
118
+ const resolver = getResolver();
119
+ await resolver.transition(slugRef.current, instanceId, transitionName, input);
120
+ } catch (err) {
121
+ const e = err instanceof Error ? err : new Error(String(err));
122
+ setError(e);
123
+ throw e;
124
+ } finally {
125
+ setIsPending(false);
126
+ }
127
+ }, [getResolver]);
128
+ const next = useCallback2(async (instanceId, input) => {
129
+ try {
130
+ setIsPending(true);
131
+ setError(null);
132
+ const resolver = getResolver();
133
+ if (resolver.next) {
134
+ await resolver.next(slugRef.current, instanceId, input);
135
+ } else {
136
+ await resolver.transition(slugRef.current, instanceId, "__next__", input);
137
+ }
138
+ } catch (err) {
139
+ const e = err instanceof Error ? err : new Error(String(err));
140
+ setError(e);
141
+ throw e;
142
+ } finally {
143
+ setIsPending(false);
144
+ }
145
+ }, [getResolver]);
146
+ const remove = useCallback2(async (instanceId) => {
147
+ try {
148
+ setIsPending(true);
149
+ setError(null);
150
+ const resolver = getResolver();
151
+ await resolver.remove(slugRef.current, instanceId);
152
+ } catch (err) {
153
+ const e = err instanceof Error ? err : new Error(String(err));
154
+ setError(e);
155
+ throw e;
156
+ } finally {
157
+ setIsPending(false);
158
+ }
159
+ }, [getResolver]);
160
+ const reset = useCallback2(() => setError(null), []);
161
+ const handle = {
162
+ create,
163
+ update,
164
+ transition: transitionFn,
165
+ trigger: transitionFn,
166
+ next,
167
+ remove,
168
+ isPending,
169
+ error,
170
+ reset
171
+ };
172
+ return handle;
173
+ }
174
+
175
+ // src/player/binding-resolver.ts
176
+ var classCache = /* @__PURE__ */ new Map();
177
+ var MAX_CLASS_CACHE = 500;
178
+ function evictIfNeeded() {
179
+ if (classCache.size >= MAX_CLASS_CACHE) {
180
+ const first = classCache.keys().next().value;
181
+ if (first !== void 0) classCache.delete(first);
182
+ }
183
+ }
184
+ function classifyBinding(expr) {
185
+ const cached = classCache.get(expr);
186
+ if (cached) return cached;
187
+ evictIfNeeded();
188
+ const result = classifyBindingUncached(expr);
189
+ classCache.set(expr, result);
190
+ return result;
191
+ }
192
+ function classifyBindingUncached(expr) {
193
+ const t = expr.trim();
194
+ if (t === "[Expression]" || t.includes("[Expression]")) {
195
+ return { type: "literal", value: void 0 };
196
+ }
197
+ if (t.startsWith("$expr(") && t.endsWith(")")) {
198
+ return { type: "condition", expression: t.slice(6, -1) };
199
+ }
200
+ if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) {
201
+ return { type: "literal", value: t.slice(1, -1) };
202
+ }
203
+ if (/^-?\d+(\.\d+)?$/.test(t)) {
204
+ return { type: "literal", value: Number(t) };
205
+ }
206
+ if (t === "true") return { type: "literal", value: true };
207
+ if (t === "false") return { type: "literal", value: false };
208
+ if (t === "null") return { type: "literal", value: null };
209
+ if (t === "undefined") return { type: "literal", value: void 0 };
210
+ const fnCall = parseFunctionCall(t);
211
+ if (fnCall) {
212
+ if (fnCall.namespace === "action") {
213
+ return { type: "action", name: fnCall.name, rawArgs: fnCall.args };
214
+ }
215
+ return { type: "function", name: fnCall.name, rawArgs: fnCall.args };
216
+ }
217
+ if (t.startsWith("$action.") && !t.includes("(")) {
218
+ return { type: "action", name: t.slice("$action.".length), rawArgs: [] };
219
+ }
220
+ if (t.startsWith("$")) {
221
+ if (!/[!=<>&|+\-*/%?:]/.test(t) && !t.includes("(")) {
222
+ const dotIdx = t.indexOf(".");
223
+ if (dotIdx === -1) {
224
+ return { type: "path", root: t, rest: "" };
225
+ }
226
+ return { type: "path", root: t.slice(0, dotIdx), rest: t.slice(dotIdx + 1) };
227
+ }
228
+ }
229
+ if (/^[a-zA-Z_]\w*(\.\w+)*$/.test(t) && !/[!=<>&|+\-*/%?:]/.test(t)) {
230
+ const dotIdx = t.indexOf(".");
231
+ if (dotIdx === -1) {
232
+ return { type: "path", root: t, rest: "" };
233
+ }
234
+ return { type: "path", root: t.slice(0, dotIdx), rest: t.slice(dotIdx + 1) };
235
+ }
236
+ return { type: "condition", expression: t };
237
+ }
238
+ function parseFunctionCall(expr) {
239
+ const match = expr.match(/^\$(fn|action)\.(\w+)\((.*)\)$/s);
240
+ if (!match) return null;
241
+ const [, namespace, name, argsStr] = match;
242
+ const args = argsStr.trim() ? splitArgs(argsStr.trim()) : [];
243
+ return { namespace, name, args };
244
+ }
245
+ function splitArgs(argsStr) {
246
+ const args = [];
247
+ let current = "";
248
+ let depth = 0;
249
+ let inString = null;
250
+ for (let i = 0; i < argsStr.length; i++) {
251
+ const ch = argsStr[i];
252
+ if (inString) {
253
+ current += ch;
254
+ if (ch === inString && argsStr[i - 1] !== "\\") inString = null;
255
+ } else if (ch === '"' || ch === "'") {
256
+ current += ch;
257
+ inString = ch;
258
+ } else if (ch === "(" || ch === "[") {
259
+ current += ch;
260
+ depth++;
261
+ } else if (ch === ")" || ch === "]") {
262
+ current += ch;
263
+ depth--;
264
+ } else if (ch === "," && depth === 0) {
265
+ args.push(current.trim());
266
+ current = "";
267
+ } else {
268
+ current += ch;
269
+ }
270
+ }
271
+ if (current.trim()) args.push(current.trim());
272
+ return args;
273
+ }
274
+ function resolveBinding(expr, scope) {
275
+ const binding = classifyBinding(expr);
276
+ switch (binding.type) {
277
+ case "literal":
278
+ return binding.value;
279
+ case "path":
280
+ return resolveScopedPath(binding.root, binding.rest, scope);
281
+ case "function":
282
+ return resolveFunction(binding.name, binding.rawArgs, scope);
283
+ case "action":
284
+ return resolveAction(binding.name, binding.rawArgs, scope);
285
+ case "condition":
286
+ return resolveCondition(binding.expression ?? expr, scope);
287
+ default:
288
+ return void 0;
289
+ }
290
+ }
291
+ function resolveAllBindings(bindings, scope) {
292
+ const resolved = {};
293
+ for (const [propName, expr] of Object.entries(bindings)) {
294
+ try {
295
+ resolved[propName] = resolveBinding(expr, scope);
296
+ } catch {
297
+ resolved[propName] = void 0;
298
+ }
299
+ }
300
+ return resolved;
301
+ }
302
+ function resolveScopedPath(root, rest, scope) {
303
+ let rootValue;
304
+ switch (root) {
305
+ case "$instance":
306
+ rootValue = scope.$instance;
307
+ break;
308
+ case "$instances":
309
+ rootValue = scope.$instances;
310
+ break;
311
+ case "$definition":
312
+ rootValue = scope.$definition;
313
+ break;
314
+ case "$pagination":
315
+ rootValue = scope.$pagination;
316
+ break;
317
+ case "$entity":
318
+ rootValue = scope.$entity;
319
+ break;
320
+ case "$local":
321
+ rootValue = scope.$local;
322
+ break;
323
+ case "$user":
324
+ rootValue = scope.$user;
325
+ break;
326
+ case "$action":
327
+ rootValue = scope.$action;
328
+ break;
329
+ case "$fn":
330
+ rootValue = scope.$fn;
331
+ break;
332
+ case "$item":
333
+ rootValue = scope.$item;
334
+ break;
335
+ case "$index":
336
+ rootValue = scope.$index;
337
+ break;
338
+ default:
339
+ rootValue = scope[root];
340
+ if (rootValue === void 0) {
341
+ rootValue = scope.$item;
342
+ if (rootValue != null && rest) {
343
+ return resolvePath(`${root}.${rest}`, { [root]: scope.$item });
344
+ }
345
+ }
346
+ }
347
+ if (!rest) return rootValue;
348
+ if (rootValue == null) return void 0;
349
+ return resolvePath(rest, rootValue);
350
+ }
351
+ function resolveFunction(name, rawArgs, scope) {
352
+ const fn = scope.$fn?.[name] ?? builtinFunctions[name];
353
+ if (typeof fn !== "function") {
354
+ console.warn(`[binding-resolver] Unknown function: $fn.${name}`);
355
+ return void 0;
356
+ }
357
+ const resolvedArgs = rawArgs.map((arg) => resolveBinding(arg.trim(), scope));
358
+ try {
359
+ return fn(...resolvedArgs);
360
+ } catch (err) {
361
+ console.warn(`[binding-resolver] Error calling $fn.${name}:`, err);
362
+ return void 0;
363
+ }
364
+ }
365
+ function resolveAction(name, rawArgs, scope) {
366
+ const actions = scope.$action;
367
+ if (!actions) return void 0;
368
+ if (rawArgs.length === 0) {
369
+ const actionFn2 = actions[name];
370
+ if (typeof actionFn2 === "function") return actionFn2;
371
+ return void 0;
372
+ }
373
+ const actionFn = actions[name];
374
+ if (typeof actionFn !== "function") return void 0;
375
+ return (...callArgs) => {
376
+ const resolvedArgs = rawArgs.map((arg) => resolveBinding(arg.trim(), scope));
377
+ return actionFn(...resolvedArgs, ...callArgs);
378
+ };
379
+ }
380
+ function resolveCondition(expression, scope) {
381
+ const context = buildEvalContext(scope);
382
+ return evaluateExpression(expression, context);
383
+ }
384
+ function buildEvalContext(scope) {
385
+ const ctx = {};
386
+ ctx.$instance = scope.$instance;
387
+ ctx.$instances = scope.$instances;
388
+ ctx.$definition = scope.$definition;
389
+ ctx.$pagination = scope.$pagination;
390
+ ctx.$entity = scope.$entity;
391
+ ctx.$local = scope.$local;
392
+ ctx.$user = scope.$user;
393
+ ctx.$action = scope.$action;
394
+ ctx.$fn = scope.$fn;
395
+ ctx.$item = scope.$item;
396
+ ctx.$index = scope.$index;
397
+ if (scope.$instances) ctx.items = scope.$instances;
398
+ if (scope.$instance) {
399
+ ctx.instance = scope.$instance;
400
+ ctx.loading = false;
401
+ }
402
+ if (scope.$item) ctx.item = scope.$item;
403
+ if (scope.$index != null) ctx.index = scope.$index;
404
+ if (scope.state_data) ctx.state_data = scope.state_data;
405
+ if (scope.memory) ctx.memory = scope.memory;
406
+ if (scope.context) ctx.context = scope.context;
407
+ return ctx;
408
+ }
409
+ function buildActionScope(opts) {
410
+ const { resolver, instanceId, slug, setLocal, router, toast, refreshQuery, onEvent } = opts;
411
+ return {
412
+ transition: async (name, id, data) => {
413
+ const targetId = id ?? instanceId;
414
+ if (!targetId) {
415
+ console.warn("[action] transition called without instanceId");
416
+ return;
417
+ }
418
+ await resolver.transition(targetId, name, data);
419
+ refreshQuery?.();
420
+ },
421
+ create: async (targetSlug, data) => {
422
+ const id = await resolver.create(targetSlug || slug || "", data);
423
+ refreshQuery?.();
424
+ return id;
425
+ },
426
+ update: async (id, fields) => {
427
+ await resolver.update(id, fields);
428
+ refreshQuery?.();
429
+ },
430
+ remove: async (id) => {
431
+ await resolver.remove(id);
432
+ refreshQuery?.();
433
+ },
434
+ setLocal: (key, value) => {
435
+ setLocal(key, value);
436
+ },
437
+ navigate: (path) => {
438
+ router?.push(path);
439
+ },
440
+ toast: (message, variant) => {
441
+ toast?.(message, variant);
442
+ },
443
+ refreshQuery: (dataSourceName) => {
444
+ refreshQuery?.(dataSourceName);
445
+ },
446
+ scrollTo: (elementId) => {
447
+ if (typeof document !== "undefined") {
448
+ const el = document.getElementById(elementId);
449
+ el?.scrollIntoView({ behavior: "smooth" });
450
+ }
451
+ },
452
+ openModal: (modalId) => {
453
+ if (typeof window !== "undefined") {
454
+ window.dispatchEvent(new CustomEvent("player:open_modal", { detail: { id: modalId } }));
455
+ }
456
+ },
457
+ closeModal: (modalId) => {
458
+ if (typeof window !== "undefined") {
459
+ window.dispatchEvent(new CustomEvent("player:close_modal", { detail: { id: modalId } }));
460
+ }
461
+ },
462
+ emit: (event, payload) => {
463
+ onEvent?.(event, payload);
464
+ }
465
+ };
466
+ }
467
+
468
+ // src/player/atom-registry.ts
469
+ import React from "react";
470
+ function namedExport(loader, exportName) {
471
+ return () => loader().then((mod) => ({ default: mod[exportName] }));
472
+ }
473
+ var AtomRegistryImpl = class _AtomRegistryImpl {
474
+ loaders = /* @__PURE__ */ new Map();
475
+ lazyCache = /* @__PURE__ */ new Map();
476
+ eagerCache = /* @__PURE__ */ new Map();
477
+ register(name, loader) {
478
+ this.loaders.set(name, loader);
479
+ this.lazyCache.delete(name);
480
+ }
481
+ registerEager(name, component) {
482
+ this.eagerCache.set(name, component);
483
+ }
484
+ resolve(name) {
485
+ const eager = this.eagerCache.get(name);
486
+ if (eager) {
487
+ const cached2 = this.lazyCache.get(name);
488
+ if (cached2) return cached2;
489
+ const lazy2 = React.lazy(() => Promise.resolve({ default: eager }));
490
+ this.lazyCache.set(name, lazy2);
491
+ return lazy2;
492
+ }
493
+ const cached = this.lazyCache.get(name);
494
+ if (cached) return cached;
495
+ const loader = this.loaders.get(name);
496
+ if (!loader) return null;
497
+ const lazy = React.lazy(loader);
498
+ this.lazyCache.set(name, lazy);
499
+ return lazy;
500
+ }
501
+ resolveSync(name) {
502
+ return this.eagerCache.get(name) ?? null;
503
+ }
504
+ has(name) {
505
+ return this.loaders.has(name) || this.eagerCache.has(name);
506
+ }
507
+ list() {
508
+ const names = /* @__PURE__ */ new Set();
509
+ for (const k of this.loaders.keys()) names.add(k);
510
+ for (const k of this.eagerCache.keys()) names.add(k);
511
+ return Array.from(names).sort();
512
+ }
513
+ merge(other) {
514
+ const merged = new _AtomRegistryImpl();
515
+ for (const [name, loader] of this.loaders) merged.loaders.set(name, loader);
516
+ for (const [name, comp] of this.eagerCache) merged.eagerCache.set(name, comp);
517
+ for (const name of other.list()) {
518
+ const otherImpl = other;
519
+ if (otherImpl.loaders?.has(name)) {
520
+ merged.loaders.set(name, otherImpl.loaders.get(name));
521
+ }
522
+ if (otherImpl.eagerCache?.has(name)) {
523
+ merged.eagerCache.set(name, otherImpl.eagerCache.get(name));
524
+ }
525
+ }
526
+ return merged;
527
+ }
528
+ toRecord() {
529
+ const record = {};
530
+ for (const name of this.eagerCache.keys()) {
531
+ record[name] = this.eagerCache.get(name);
532
+ }
533
+ return record;
534
+ }
535
+ };
536
+ function createCoreAtomRegistry() {
537
+ const registry = new AtomRegistryImpl();
538
+ registry.register("Stack", namedExport(() => import("./layout-RATDMCLP.mjs"), "Stack"));
539
+ registry.register("Row", namedExport(() => import("./layout-RATDMCLP.mjs"), "Row"));
540
+ registry.register("Grid", namedExport(() => import("./layout-RATDMCLP.mjs"), "Grid"));
541
+ registry.register("Column", namedExport(() => import("./layout-RATDMCLP.mjs"), "Column"));
542
+ registry.register("Divider", namedExport(() => import("./layout-RATDMCLP.mjs"), "Divider"));
543
+ registry.register("Spacer", namedExport(() => import("./layout-RATDMCLP.mjs"), "Spacer"));
544
+ registry.register("Text", namedExport(() => import("./content-QVPFUG4P.mjs"), "Text"));
545
+ registry.register("Heading", namedExport(() => import("./content-QVPFUG4P.mjs"), "Heading"));
546
+ registry.register("Field", namedExport(() => import("./content-QVPFUG4P.mjs"), "Field"));
547
+ registry.register("Image", namedExport(() => import("./content-QVPFUG4P.mjs"), "Image"));
548
+ registry.register("Badge", namedExport(() => import("./content-QVPFUG4P.mjs"), "Badge"));
549
+ registry.register("Icon", namedExport(() => import("./content-QVPFUG4P.mjs"), "Icon"));
550
+ registry.register("Button", namedExport(() => import("./actions-MFI2V4DX.mjs"), "Button"));
551
+ registry.register("Link", namedExport(() => import("./actions-MFI2V4DX.mjs"), "Link"));
552
+ registry.register("Show", namedExport(() => import("./control-flow-CBREHWJW.mjs"), "Show"));
553
+ registry.register("Each", namedExport(() => import("./control-flow-CBREHWJW.mjs"), "Each"));
554
+ registry.register("TextInput", namedExport(() => import("./input-PUOZDNSI.mjs"), "TextInput"));
555
+ registry.register("Input", namedExport(() => import("./input-PUOZDNSI.mjs"), "TextInput"));
556
+ registry.register("Select", namedExport(() => import("./input-PUOZDNSI.mjs"), "Select"));
557
+ registry.register("Toggle", namedExport(() => import("./input-PUOZDNSI.mjs"), "Toggle"));
558
+ registry.register("Slider", namedExport(() => import("./input-PUOZDNSI.mjs"), "Slider"));
559
+ registry.register("Card", namedExport(() => import("./grouping-E6F377VZ.mjs"), "Card"));
560
+ registry.register("Section", namedExport(() => import("./grouping-E6F377VZ.mjs"), "Section"));
561
+ registry.register("Tabs", namedExport(() => import("./grouping-E6F377VZ.mjs"), "Tabs"));
562
+ registry.register("Accordion", namedExport(() => import("./grouping-E6F377VZ.mjs"), "Accordion"));
563
+ registry.register("Modal", namedExport(() => import("./grouping-E6F377VZ.mjs"), "Modal"));
564
+ registry.register("Router", namedExport(() => import("./navigation-WFV7YWOU.mjs"), "Router"));
565
+ registry.register("Route", namedExport(() => import("./navigation-WFV7YWOU.mjs"), "Route"));
566
+ registry.register("NavLink", namedExport(() => import("./navigation-WFV7YWOU.mjs"), "NavLink"));
567
+ registry.register("RoleGuard", namedExport(() => import("./navigation-WFV7YWOU.mjs"), "RoleGuard"));
568
+ registry.register("Slot", namedExport(() => import("./composition-XBGKKCI7.mjs"), "Slot"));
569
+ registry.register("ModuleOutlet", namedExport(() => import("./composition-XBGKKCI7.mjs"), "ModuleOutlet"));
570
+ registry.register("Markdown", namedExport(() => import("./content-QVPFUG4P.mjs"), "Markdown"));
571
+ registry.register("ScrollArea", namedExport(() => import("./grouping-E6F377VZ.mjs"), "ScrollArea"));
572
+ registry.register("Table", namedExport(() => import("./data-WCMIZYKD.mjs"), "Table"));
573
+ registry.register("DataGrid", namedExport(() => import("./data-WCMIZYKD.mjs"), "DataGrid"));
574
+ registry.register("Alert", namedExport(() => import("./content-QVPFUG4P.mjs"), "Alert"));
575
+ registry.register("EmptyState", namedExport(() => import("./content-QVPFUG4P.mjs"), "EmptyState"));
576
+ registry.register("Progress", namedExport(() => import("./content-QVPFUG4P.mjs"), "Progress"));
577
+ registry.register("Separator", namedExport(() => import("./content-QVPFUG4P.mjs"), "Separator"));
578
+ return registry;
579
+ }
580
+ function mergeRegistries(...registries) {
581
+ let merged = new AtomRegistryImpl();
582
+ for (const r of registries) {
583
+ merged = merged.merge(r);
584
+ }
585
+ return merged;
586
+ }
587
+
588
+ // src/player/PlayerProvider.tsx
589
+ import { createContext, useContext, useEffect as useEffect2, useMemo, useRef as useRef3 } from "react";
590
+ import { jsx } from "react/jsx-runtime";
591
+ var PlayerContext = createContext(null);
592
+ function usePlayerContext() {
593
+ return useContext(PlayerContext);
594
+ }
595
+ var PlayerProvider = ({
596
+ resolver,
597
+ atomRegistry: userAtomRegistry,
598
+ auth,
599
+ router,
600
+ toast,
601
+ onEvent,
602
+ children
603
+ }) => {
604
+ const atomRegistry = useMemo(
605
+ () => userAtomRegistry ?? createCoreAtomRegistry(),
606
+ [userAtomRegistry]
607
+ );
608
+ const resolverRef = useRef3(resolver);
609
+ resolverRef.current = resolver;
610
+ useEffect2(() => {
611
+ if (!resolver) return;
612
+ setQueryResolver({
613
+ query: async (_slug, params) => {
614
+ const r = resolverRef.current;
615
+ if (!r) return { data: [] };
616
+ const result = await r.query(_slug, {
617
+ state: params.state,
618
+ filter: params.filter,
619
+ limit: params.limit,
620
+ offset: params.offset,
621
+ search: params.search,
622
+ searchFields: params.searchFields,
623
+ sort: params.sort
624
+ });
625
+ return { data: result.data, total: result.total };
626
+ }
627
+ });
628
+ setMutationResolver({
629
+ create: async (_slug, input) => {
630
+ const r = resolverRef.current;
631
+ if (!r) throw new Error("No resolver");
632
+ return r.create(_slug, input);
633
+ },
634
+ update: async (_slug, instanceId, fields) => {
635
+ const r = resolverRef.current;
636
+ if (!r) throw new Error("No resolver");
637
+ await r.update(instanceId, fields);
638
+ },
639
+ transition: async (_slug, instanceId, transitionName, input) => {
640
+ const r = resolverRef.current;
641
+ if (!r) throw new Error("No resolver");
642
+ await r.transition(instanceId, transitionName, input);
643
+ },
644
+ remove: async (_slug, instanceId) => {
645
+ const r = resolverRef.current;
646
+ if (!r) throw new Error("No resolver");
647
+ await r.remove(instanceId);
648
+ }
649
+ });
650
+ return () => {
651
+ setQueryResolver(null);
652
+ setMutationResolver(null);
653
+ };
654
+ }, [resolver]);
655
+ const value = useMemo(() => ({
656
+ resolver: resolver ?? null,
657
+ atomRegistry,
658
+ auth,
659
+ router,
660
+ toast,
661
+ onEvent
662
+ }), [resolver, atomRegistry, auth, router, toast, onEvent]);
663
+ return /* @__PURE__ */ jsx(PlayerContext.Provider, { value, children });
664
+ };
665
+
666
+ // src/player/ExperienceRenderer.tsx
667
+ import React3, {
668
+ useState as useState3,
669
+ useEffect as useEffect3,
670
+ useCallback as useCallback3,
671
+ useMemo as useMemo2,
672
+ useRef as useRef4,
673
+ Suspense
674
+ } from "react";
675
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
676
+ var NodeErrorBoundary = class extends React3.Component {
677
+ constructor(props) {
678
+ super(props);
679
+ this.state = { hasError: false };
680
+ }
681
+ static getDerivedStateFromError(error) {
682
+ return { hasError: true, error };
683
+ }
684
+ componentDidCatch(error, info) {
685
+ console.error(`[ExperienceRenderer] Error in node ${this.props.nodeId}:`, error, info);
686
+ }
687
+ render() {
688
+ if (this.state.hasError) {
689
+ return this.props.fallback ?? /* @__PURE__ */ jsxs("div", { style: { padding: 8, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 6, fontSize: 12, color: "#c53030" }, children: [
690
+ "Error: ",
691
+ this.state.error?.message ?? "Render failed"
692
+ ] });
693
+ }
694
+ return this.props.children;
695
+ }
696
+ };
697
+ function useDataSources(dataSources, resolver, scope) {
698
+ const [results, setResults] = useState3({});
699
+ const mountedRef = useRef4(true);
700
+ useEffect3(() => {
701
+ mountedRef.current = true;
702
+ return () => {
703
+ mountedRef.current = false;
704
+ };
705
+ }, []);
706
+ useEffect3(() => {
707
+ if (!dataSources?.length || !resolver) return;
708
+ const loading = {};
709
+ for (const ds of dataSources) {
710
+ loading[ds.name] = { loading: true, error: null };
711
+ }
712
+ setResults(loading);
713
+ const fetchAll = async () => {
714
+ const entries = await Promise.all(
715
+ dataSources.map(async (ds) => {
716
+ try {
717
+ const result = await fetchDataSource(ds, resolver, scope);
718
+ return [ds.name, result];
719
+ } catch (err) {
720
+ return [ds.name, { loading: false, error: err instanceof Error ? err : new Error(String(err)) }];
721
+ }
722
+ })
723
+ );
724
+ if (mountedRef.current) {
725
+ setResults(Object.fromEntries(entries));
726
+ }
727
+ };
728
+ fetchAll();
729
+ }, [dataSources, resolver]);
730
+ return results;
731
+ }
732
+ async function fetchDataSource(ds, resolver, scope) {
733
+ switch (ds.type) {
734
+ case "workflow": {
735
+ const slug = ds.slug ?? "";
736
+ if (!slug) return { loading: false, error: new Error("workflow dataSource missing slug") };
737
+ const queryResult = await resolver.query(slug, {
738
+ state: ds.filter?.current_state,
739
+ filter: ds.filter,
740
+ limit: ds.pageSize ?? 20,
741
+ page: scope.$local?.[ds.pageKey ?? "page"] ?? 1,
742
+ search: ds.search ? interpolateTemplate(ds.search, scope) : void 0,
743
+ searchFields: ds.searchFields,
744
+ sort: ds.sort,
745
+ facets: ds.facets,
746
+ entity: ds.entity,
747
+ includeDefinition: ds.includeDefinition,
748
+ parentInstanceId: ds.parentInstanceId ? interpolateTemplate(ds.parentInstanceId, scope) : void 0
749
+ });
750
+ const result = {
751
+ instances: queryResult.data,
752
+ loading: false,
753
+ error: null
754
+ };
755
+ if (queryResult.data.length === 1 && ds.query !== "list") {
756
+ result.instance = queryResult.data[0];
757
+ }
758
+ if (queryResult.definition) result.definition = queryResult.definition;
759
+ if (queryResult.total != null) {
760
+ result.pagination = {
761
+ total: queryResult.total,
762
+ page: queryResult.page,
763
+ pageSize: queryResult.pageSize
764
+ };
765
+ }
766
+ if (queryResult.facets) result.facets = queryResult.facets;
767
+ if (queryResult.aggregates) result.aggregates = queryResult.aggregates;
768
+ if (ds.autoStart && queryResult.data.length === 0) {
769
+ try {
770
+ const id = await resolver.create(slug, ds.initialData);
771
+ const instance = await resolver.getInstance(id);
772
+ result.instance = instance;
773
+ result.instances = [instance];
774
+ } catch {
775
+ }
776
+ }
777
+ return result;
778
+ }
779
+ case "api": {
780
+ if (!resolver.fetch) return { loading: false, error: new Error("API datasource: resolver.fetch not implemented") };
781
+ const endpoint = interpolateTemplate(ds.endpoint, scope);
782
+ const raw = await resolver.fetch(endpoint, {
783
+ method: ds.method,
784
+ body: ds.body,
785
+ headers: ds.headers
786
+ });
787
+ const mapped = mapApiResponse(raw, ds.mapping);
788
+ return { instances: mapped.items, loading: false, error: null, pagination: mapped.pagination };
789
+ }
790
+ case "static": {
791
+ const data = ds.data;
792
+ if (Array.isArray(data)) {
793
+ return {
794
+ instances: data.map((d, i) => ({
795
+ id: String(d.id ?? i),
796
+ state: "static",
797
+ fields: d
798
+ })),
799
+ loading: false,
800
+ error: null
801
+ };
802
+ }
803
+ return {
804
+ instance: { id: "static", state: "static", fields: data },
805
+ loading: false,
806
+ error: null
807
+ };
808
+ }
809
+ case "ref":
810
+ return { loading: false, error: null };
811
+ // Stub — ref resolution TBD
812
+ default:
813
+ return { loading: false, error: new Error(`Unknown dataSource type: ${ds.type}`) };
814
+ }
815
+ }
816
+ function interpolateTemplate(template, scope) {
817
+ return template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, path) => {
818
+ const val = resolveBinding(`$${path}`, scope) ?? resolveBinding(path, scope);
819
+ return val != null ? String(val) : "";
820
+ });
821
+ }
822
+ function mapApiResponse(raw, mapping) {
823
+ if (!raw || typeof raw !== "object") return { items: [] };
824
+ const obj = raw;
825
+ let items;
826
+ if (mapping?.items || mapping?.data) {
827
+ items = obj[mapping.items ?? mapping.data ?? "data"] ?? [];
828
+ } else if (Array.isArray(raw)) {
829
+ items = raw;
830
+ } else if (Array.isArray(obj.data)) {
831
+ items = obj.data;
832
+ } else if (Array.isArray(obj.items)) {
833
+ items = obj.items;
834
+ } else {
835
+ items = [raw];
836
+ }
837
+ const result = items.map((item, i) => ({
838
+ id: String(item?.id ?? i),
839
+ state: String(item?.state ?? "unknown"),
840
+ fields: item ?? {}
841
+ }));
842
+ let pagination;
843
+ const total = mapping?.total ? obj[mapping.total] : obj.total;
844
+ if (total != null) {
845
+ pagination = { total: Number(total), page: Number(obj.page ?? 1), pageSize: Number(obj.pageSize ?? items.length) };
846
+ }
847
+ return { items: result, pagination };
848
+ }
849
+ var NodeRenderer = ({ node, fallback }) => {
850
+ const parentScope = useScope();
851
+ const playerCtx = usePlayerContext();
852
+ const resolver = playerCtx?.resolver ?? null;
853
+ const atomRegistry = playerCtx?.atomRegistry;
854
+ const localDefaults = node.config?.localDefaults ?? {};
855
+ const [localState, setLocalState] = useState3(() => ({
856
+ ...localDefaults
857
+ }));
858
+ const handleSetLocal = useCallback3((key, value) => {
859
+ setLocalState((prev) => ({ ...prev, [key]: value }));
860
+ }, []);
861
+ const [, setFetchVersion] = useState3(0);
862
+ const handleRefreshQuery = useCallback3(() => {
863
+ setFetchVersion((v) => v + 1);
864
+ }, []);
865
+ const dsResults = useDataSources(node.dataSources, resolver, parentScope);
866
+ const primaryInstance = Object.values(dsResults).find((r) => r.instance)?.instance;
867
+ const primarySlug = node.dataSources?.find((ds) => ds.type === "workflow")?.slug;
868
+ const actionScope = useMemo2(() => {
869
+ if (!resolver) {
870
+ return {
871
+ transition: async () => {
872
+ },
873
+ create: async () => "",
874
+ update: async () => {
875
+ },
876
+ remove: async () => {
877
+ },
878
+ setLocal: handleSetLocal,
879
+ navigate: () => {
880
+ },
881
+ toast: () => {
882
+ },
883
+ refreshQuery: handleRefreshQuery,
884
+ scrollTo: () => {
885
+ },
886
+ openModal: () => {
887
+ },
888
+ closeModal: () => {
889
+ },
890
+ emit: () => {
891
+ }
892
+ };
893
+ }
894
+ return buildActionScope({
895
+ resolver,
896
+ instanceId: primaryInstance?.id,
897
+ slug: primarySlug,
898
+ setLocal: handleSetLocal,
899
+ router: playerCtx?.router,
900
+ toast: playerCtx?.toast,
901
+ refreshQuery: handleRefreshQuery,
902
+ onEvent: playerCtx?.onEvent
903
+ });
904
+ }, [resolver, primaryInstance?.id, primarySlug, handleSetLocal, handleRefreshQuery, playerCtx]);
905
+ const scope = useMemo2(() => buildScope({
906
+ dataSources: dsResults,
907
+ localState,
908
+ auth: playerCtx?.auth,
909
+ entity: node.dataSources?.find((ds) => ds.type === "workflow")?.entity,
910
+ parentScope,
911
+ actionScope
912
+ }), [dsResults, localState, parentScope, actionScope, playerCtx?.auth]);
913
+ const enrichedScope = useMemo2(() => ({
914
+ ...scope,
915
+ // Compiler emits `$instance.handleCreate` style bindings
916
+ // These need to map to $action functions
917
+ handleCreate: () => {
918
+ if (primarySlug && resolver) {
919
+ resolver.create(primarySlug).then(() => handleRefreshQuery());
920
+ }
921
+ },
922
+ setSearch: (e) => {
923
+ const val = typeof e === "object" && e !== null && "target" in e ? e.target.value : String(e ?? "");
924
+ handleSetLocal("search", val);
925
+ }
926
+ }), [scope, primarySlug, resolver, handleRefreshQuery, handleSetLocal]);
927
+ if (node.visible_when) {
928
+ const ctx = buildEvalContext(enrichedScope);
929
+ const visible = evaluateExpression(node.visible_when, ctx);
930
+ if (!visible) return null;
931
+ }
932
+ if (node.$if) {
933
+ const ctx = buildEvalContext(enrichedScope);
934
+ const visible = evaluateExpression(node.$if, ctx);
935
+ if (!visible) return null;
936
+ }
937
+ const resolvedBindings = node.bindings ? resolveAllBindings(node.bindings, enrichedScope) : {};
938
+ const config = node.config ?? node.props ?? {};
939
+ const mergedProps = { ...config, ...resolvedBindings };
940
+ if (node.className) mergedProps.className = node.className;
941
+ if (node.id) mergedProps["data-node-id"] = node.id;
942
+ const loadingAny = Object.values(dsResults).some((r) => r.loading);
943
+ if (Object.keys(dsResults).length > 0) {
944
+ mergedProps.loading = loadingAny;
945
+ const firstResult = Object.values(dsResults)[0];
946
+ if (firstResult?.instances) mergedProps.data = firstResult.instances;
947
+ if (firstResult?.instance) mergedProps.instance = firstResult.instance;
948
+ if (firstResult?.pagination) mergedProps.pagination = firstResult.pagination;
949
+ if (firstResult?.definition) mergedProps.definition = firstResult.definition;
950
+ }
951
+ const componentName = node.component ?? node.type ?? "";
952
+ let AtomComponent = null;
953
+ if (atomRegistry) {
954
+ const lazy = atomRegistry.resolve(componentName);
955
+ if (lazy) AtomComponent = lazy;
956
+ }
957
+ if (!AtomComponent) {
958
+ if (!componentName && node.children?.length) {
959
+ return /* @__PURE__ */ jsx2(ScopeContext.Provider, { value: enrichedScope, children: /* @__PURE__ */ jsx2("div", { className: node.className, style: node.style, children: node.children.map((child, i) => /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: child.id, children: /* @__PURE__ */ jsx2(NodeRenderer, { node: child, fallback }) }, child.id ?? i)) }) });
960
+ }
961
+ if (componentName) {
962
+ return /* @__PURE__ */ jsxs("div", { style: { border: "1px dashed #e53e3e", borderRadius: 6, padding: "8px 12px", margin: 4, fontSize: 13, color: "#e53e3e", background: "#fff5f5" }, children: [
963
+ "Unknown: ",
964
+ componentName
965
+ ] });
966
+ }
967
+ return null;
968
+ }
969
+ let children = null;
970
+ if (node.children?.length) {
971
+ children = node.children.map((child, i) => /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: child.id, children: /* @__PURE__ */ jsx2(NodeRenderer, { node: child, fallback }) }, child.id ?? i));
972
+ }
973
+ if (!children && mergedProps.children != null) {
974
+ children = mergedProps.children;
975
+ delete mergedProps.children;
976
+ }
977
+ delete mergedProps.localDefaults;
978
+ delete mergedProps.dataSources;
979
+ delete mergedProps.bindings;
980
+ delete mergedProps.visible_when;
981
+ return /* @__PURE__ */ jsx2(ScopeContext.Provider, { value: enrichedScope, children: /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: node.id, fallback, children: /* @__PURE__ */ jsx2(Suspense, { fallback: /* @__PURE__ */ jsxs("div", { style: { padding: 8, color: "#a0aec0", fontSize: 13 }, children: [
982
+ "Loading ",
983
+ componentName,
984
+ "..."
985
+ ] }), children: /* @__PURE__ */ jsx2(AtomComponent, { ...mergedProps, children }) }) }) });
986
+ };
987
+ var ExperienceRenderer = ({
988
+ tree,
989
+ initialScope,
990
+ entity,
991
+ fallback,
992
+ className
993
+ }) => {
994
+ const playerCtx = usePlayerContext();
995
+ const nodes = Array.isArray(tree) ? tree : [tree];
996
+ const rootScope = useMemo2(() => buildScope({
997
+ auth: playerCtx?.auth ?? initialScope?.auth,
998
+ entity,
999
+ localState: initialScope?.$local ?? {},
1000
+ actionScope: initialScope?.$action ?? {
1001
+ transition: async () => {
1002
+ },
1003
+ create: async () => "",
1004
+ update: async () => {
1005
+ },
1006
+ remove: async () => {
1007
+ },
1008
+ setLocal: () => {
1009
+ },
1010
+ navigate: () => {
1011
+ },
1012
+ toast: () => {
1013
+ },
1014
+ refreshQuery: () => {
1015
+ },
1016
+ scrollTo: () => {
1017
+ },
1018
+ openModal: () => {
1019
+ },
1020
+ closeModal: () => {
1021
+ },
1022
+ emit: () => {
1023
+ }
1024
+ }
1025
+ }), [playerCtx?.auth, entity, initialScope]);
1026
+ return /* @__PURE__ */ jsx2(ScopeContext.Provider, { value: rootScope, children: /* @__PURE__ */ jsx2("div", { className, children: nodes.map((node, i) => /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: node.id, children: /* @__PURE__ */ jsx2(NodeRenderer, { node, fallback }) }, node.id ?? i)) }) });
1027
+ };
1028
+
1029
+ // src/player/resolver.ts
1030
+ function getToken(token) {
1031
+ if (!token) return null;
1032
+ if (typeof token === "function") return token();
1033
+ return token;
1034
+ }
1035
+ function normalizeInstance(raw) {
1036
+ return {
1037
+ id: String(raw.id ?? ""),
1038
+ state: String(raw.current_state ?? raw.state ?? "unknown"),
1039
+ fields: raw.state_data ?? raw.fields ?? {},
1040
+ slug: raw.definition_slug,
1041
+ created_at: raw.created_at,
1042
+ updated_at: raw.updated_at,
1043
+ ...raw
1044
+ };
1045
+ }
1046
+ function createApiResolver(config) {
1047
+ const { baseUrl, defaults } = config;
1048
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
1049
+ const defCache = /* @__PURE__ */ new Map();
1050
+ async function apiRequest(path, options = {}) {
1051
+ const tok = getToken(config.token);
1052
+ const headers = {
1053
+ "Content-Type": "application/json",
1054
+ ...options.headers ?? {}
1055
+ };
1056
+ if (tok) headers["Authorization"] = `Bearer ${tok}`;
1057
+ const response = await fetchFn(`${baseUrl}${path}`, {
1058
+ ...options,
1059
+ headers
1060
+ });
1061
+ if (!response.ok) {
1062
+ const body = await response.text().catch(() => "");
1063
+ let message = `API error ${response.status}: ${response.statusText}`;
1064
+ try {
1065
+ const parsed = JSON.parse(body);
1066
+ if (parsed.message) message = parsed.message;
1067
+ if (parsed.error) message = `${parsed.error}: ${parsed.message || ""}`;
1068
+ } catch {
1069
+ }
1070
+ throw new Error(message);
1071
+ }
1072
+ return response.json();
1073
+ }
1074
+ const resolver = {
1075
+ async query(slug, params) {
1076
+ const searchParams = new URLSearchParams();
1077
+ searchParams.set("definition", slug);
1078
+ if (params.state) {
1079
+ const states = Array.isArray(params.state) ? params.state : [params.state];
1080
+ states.forEach((s) => searchParams.append("state", s));
1081
+ }
1082
+ if (params.status) searchParams.set("status", params.status);
1083
+ if (params.limit ?? defaults?.limit) searchParams.set("limit", String(params.limit ?? defaults?.limit ?? 20));
1084
+ if (params.page) searchParams.set("page", String(params.page));
1085
+ if (params.offset) searchParams.set("offset", String(params.offset));
1086
+ if (params.search) searchParams.set("search", params.search);
1087
+ if (params.searchFields?.length) searchParams.set("search_fields", params.searchFields.join(","));
1088
+ if (params.sort) {
1089
+ if (typeof params.sort === "string") {
1090
+ searchParams.set("sort", params.sort);
1091
+ } else if (Array.isArray(params.sort)) {
1092
+ const sortStr = params.sort.map((s) => `${s.direction === "desc" ? "-" : ""}${s.field}`).join(",");
1093
+ searchParams.set("sort", sortStr);
1094
+ }
1095
+ }
1096
+ if (params.filter) {
1097
+ searchParams.set("state_filter", JSON.stringify(params.filter));
1098
+ }
1099
+ if (params.facets?.length) {
1100
+ searchParams.set("facets", params.facets.join(","));
1101
+ }
1102
+ if (params.entity) {
1103
+ searchParams.set("entity_type", params.entity.type);
1104
+ searchParams.set("entity_id", params.entity.id);
1105
+ }
1106
+ if (params.parentInstanceId) {
1107
+ searchParams.set("spawned_by_instance_id", params.parentInstanceId);
1108
+ }
1109
+ if (params.includeDefinition) {
1110
+ searchParams.set("include_definition", "true");
1111
+ }
1112
+ const raw = await apiRequest(
1113
+ `/workflow/instances?${searchParams.toString()}`
1114
+ );
1115
+ const items = raw.items ?? raw.data ?? [];
1116
+ const total = Number(raw.total ?? raw.count ?? items.length);
1117
+ const page = Number(raw.page ?? params.page ?? 1);
1118
+ const pageSize = Number(raw.page_size ?? raw.pageSize ?? params.limit ?? defaults?.limit ?? 20);
1119
+ const result = {
1120
+ data: items.map(normalizeInstance),
1121
+ total,
1122
+ page,
1123
+ pageSize
1124
+ };
1125
+ if (raw.definition) result.definition = raw.definition;
1126
+ if (raw.facets) result.facets = raw.facets;
1127
+ if (raw.aggregates) result.aggregates = raw.aggregates;
1128
+ if (raw.grouped) result.grouped = raw.grouped;
1129
+ return result;
1130
+ },
1131
+ async getInstance(id) {
1132
+ const raw = await apiRequest(`/workflow/instances/${id}`);
1133
+ return normalizeInstance(raw);
1134
+ },
1135
+ async getDefinition(slug) {
1136
+ const cached = defCache.get(slug);
1137
+ if (cached && cached.expires > Date.now()) return cached.data;
1138
+ const raw = await apiRequest(`/workflow/definitions/slug/${slug}`);
1139
+ defCache.set(slug, { data: raw, expires: Date.now() + 5 * 60 * 1e3 });
1140
+ return raw;
1141
+ },
1142
+ async create(slug, data) {
1143
+ const raw = await apiRequest("/workflow/instances", {
1144
+ method: "POST",
1145
+ body: JSON.stringify({
1146
+ definition_slug: slug,
1147
+ state_data: data ?? {}
1148
+ })
1149
+ });
1150
+ return String(raw.id);
1151
+ },
1152
+ async update(id, fields) {
1153
+ await apiRequest(`/workflow/instances/${id}/state-data`, {
1154
+ method: "PATCH",
1155
+ body: JSON.stringify(fields)
1156
+ });
1157
+ },
1158
+ async transition(id, name, data) {
1159
+ const raw = await apiRequest(
1160
+ `/workflow/instances/${id}/transitions/${name}`,
1161
+ {
1162
+ method: "POST",
1163
+ body: JSON.stringify({ data: data ?? {} })
1164
+ }
1165
+ );
1166
+ return raw;
1167
+ },
1168
+ async remove(id) {
1169
+ await apiRequest(`/workflow/instances/${id}`, { method: "DELETE" });
1170
+ },
1171
+ async availableTransitions(id) {
1172
+ const raw = await apiRequest(`/workflow/instances/${id}/transitions`);
1173
+ return Array.isArray(raw) ? raw : [];
1174
+ },
1175
+ async fetch(endpoint, fetchConfig) {
1176
+ return apiRequest(endpoint, {
1177
+ method: fetchConfig.method ?? "GET",
1178
+ body: fetchConfig.body ? JSON.stringify(fetchConfig.body) : void 0,
1179
+ headers: fetchConfig.headers
1180
+ });
1181
+ }
1182
+ };
1183
+ return resolver;
1184
+ }
1185
+ function createMockResolver(fixtures) {
1186
+ const instances = /* @__PURE__ */ new Map();
1187
+ let nextId = 1e3;
1188
+ for (const [slug, items] of Object.entries(fixtures)) {
1189
+ for (const item of items) {
1190
+ const inst = normalizeInstance({ ...item, definition_slug: slug });
1191
+ instances.set(inst.id, inst);
1192
+ }
1193
+ }
1194
+ return {
1195
+ async query(slug, params) {
1196
+ let data = Array.from(instances.values()).filter((i) => i.slug === slug);
1197
+ if (params.state) {
1198
+ const states = Array.isArray(params.state) ? params.state : [params.state];
1199
+ data = data.filter((i) => states.includes(i.state));
1200
+ }
1201
+ if (params.search) {
1202
+ const q = params.search.toLowerCase();
1203
+ data = data.filter(
1204
+ (i) => JSON.stringify(i.fields).toLowerCase().includes(q)
1205
+ );
1206
+ }
1207
+ const total = data.length;
1208
+ const limit = params.limit ?? 20;
1209
+ const page = params.page ?? 1;
1210
+ const offset = (page - 1) * limit;
1211
+ data = data.slice(offset, offset + limit);
1212
+ return { data, total, page, pageSize: limit };
1213
+ },
1214
+ async getInstance(id) {
1215
+ const inst = instances.get(id);
1216
+ if (!inst) throw new Error(`Instance ${id} not found`);
1217
+ return inst;
1218
+ },
1219
+ async getDefinition(slug) {
1220
+ return {
1221
+ id: slug,
1222
+ slug,
1223
+ name: slug,
1224
+ fields: [],
1225
+ states: [{ name: "initial", type: "START" }],
1226
+ transitions: []
1227
+ };
1228
+ },
1229
+ async create(slug, data) {
1230
+ const id = `mock-${nextId++}`;
1231
+ const inst = {
1232
+ id,
1233
+ state: "initial",
1234
+ fields: data ?? {},
1235
+ slug,
1236
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
1237
+ };
1238
+ instances.set(id, inst);
1239
+ return id;
1240
+ },
1241
+ async update(id, fields) {
1242
+ const inst = instances.get(id);
1243
+ if (inst) {
1244
+ inst.fields = { ...inst.fields, ...fields };
1245
+ inst.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1246
+ }
1247
+ },
1248
+ async transition(id, name) {
1249
+ const inst = instances.get(id);
1250
+ if (!inst) return { success: false, error: `Instance ${id} not found` };
1251
+ const from = inst.state;
1252
+ inst.state = name;
1253
+ return { success: true, from_state: from, to_state: name };
1254
+ },
1255
+ async remove(id) {
1256
+ instances.delete(id);
1257
+ },
1258
+ async availableTransitions() {
1259
+ return [];
1260
+ }
1261
+ };
1262
+ }
1263
+
1264
+ // src/player/evaluator.ts
1265
+ var EXPR_PATTERN = /\{\{(.+?)\}\}/g;
1266
+ function containsExpression(value) {
1267
+ return typeof value === "string" && EXPR_PATTERN.test(value);
1268
+ }
1269
+ function resolvePath2(path, scope) {
1270
+ const parts = path.trim().split(".");
1271
+ let current = scope;
1272
+ for (const part of parts) {
1273
+ if (current == null || typeof current !== "object") return void 0;
1274
+ current = current[part];
1275
+ }
1276
+ return current;
1277
+ }
1278
+ function evaluateExpression2(expr, scopes) {
1279
+ const trimmed = expr.trim();
1280
+ if (trimmed.startsWith("'") && trimmed.endsWith("'") || trimmed.startsWith('"') && trimmed.endsWith('"')) {
1281
+ return trimmed.slice(1, -1);
1282
+ }
1283
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
1284
+ return Number(trimmed);
1285
+ }
1286
+ if (trimmed === "true") return true;
1287
+ if (trimmed === "false") return false;
1288
+ if (trimmed === "null" || trimmed === "undefined") return void 0;
1289
+ const flatScope = { ...scopes };
1290
+ if (scopes.state_data && typeof scopes.state_data === "object") {
1291
+ Object.assign(flatScope, scopes.state_data);
1292
+ }
1293
+ if (scopes.context && typeof scopes.context === "object") {
1294
+ Object.assign(flatScope, scopes.context);
1295
+ }
1296
+ return resolvePath2(trimmed, flatScope);
1297
+ }
1298
+ function evaluateProp(value, scopes) {
1299
+ if (typeof value !== "string") return value;
1300
+ const fullMatch = value.match(/^\{\{(.+)\}\}$/s);
1301
+ if (fullMatch) {
1302
+ return evaluateExpression2(fullMatch[1], scopes);
1303
+ }
1304
+ if (containsExpression(value)) {
1305
+ return value.replace(EXPR_PATTERN, (_, expr) => {
1306
+ const result = evaluateExpression2(expr, scopes);
1307
+ return result == null ? "" : String(result);
1308
+ });
1309
+ }
1310
+ return value;
1311
+ }
1312
+
1313
+ // src/player/ComponentTreeRenderer.tsx
1314
+ import React4, { useMemo as useMemo3, useCallback as useCallback4 } from "react";
1315
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1316
+ var UnknownAtom = ({ type, children }) => /* @__PURE__ */ jsxs2("div", { style: { border: "1px dashed #e53e3e", borderRadius: 6, padding: "8px 12px", margin: 4, fontSize: 13, color: "#e53e3e", background: "#fff5f5" }, children: [
1317
+ /* @__PURE__ */ jsxs2("span", { style: { fontWeight: 600 }, children: [
1318
+ "Unknown: ",
1319
+ type
1320
+ ] }),
1321
+ children && /* @__PURE__ */ jsx3("div", { style: { marginTop: 4 }, children })
1322
+ ] });
1323
+ var RenderNode = ({ node, scopes, atoms, onEvent }) => {
1324
+ const nodeType = node.type || node.component || "";
1325
+ const nodeProps = node.props || node.config || {};
1326
+ if (node.$if) {
1327
+ const condition = evaluateProp(node.$if, scopes);
1328
+ if (!condition) return null;
1329
+ }
1330
+ if (node.$for) {
1331
+ const { each, as, key: keyField } = node.$for;
1332
+ const items = evaluateProp(each, scopes);
1333
+ if (!Array.isArray(items)) return null;
1334
+ return /* @__PURE__ */ jsx3(Fragment, { children: items.map((item, index) => {
1335
+ const loopScopes = {
1336
+ ...scopes,
1337
+ state_data: {
1338
+ ...scopes.state_data ?? {},
1339
+ [as]: item,
1340
+ [`${as}Index`]: index
1341
+ }
1342
+ };
1343
+ const nodeWithoutFor = { ...node, $for: void 0 };
1344
+ const itemKey = keyField ? String(item[keyField] ?? index) : String(index);
1345
+ return /* @__PURE__ */ jsx3(RenderNode, { node: nodeWithoutFor, scopes: loopScopes, atoms, onEvent }, itemKey);
1346
+ }) });
1347
+ }
1348
+ const Component = atoms[nodeType];
1349
+ if (!Component) {
1350
+ return /* @__PURE__ */ jsx3(UnknownAtom, { type: nodeType });
1351
+ }
1352
+ const evaluatedProps = {};
1353
+ if (node.className) evaluatedProps.className = node.className;
1354
+ if (node.id) evaluatedProps["data-node-id"] = node.id;
1355
+ for (const [key, value] of Object.entries(nodeProps)) {
1356
+ if (key.startsWith("on") && typeof value === "string") {
1357
+ evaluatedProps[key] = (...args) => {
1358
+ if (containsExpression(value)) {
1359
+ evaluateExpression2(value.replace(/^\{\{|\}\}$/g, ""), scopes);
1360
+ } else {
1361
+ onEvent(value, args[0]);
1362
+ }
1363
+ };
1364
+ } else {
1365
+ evaluatedProps[key] = evaluateProp(value, scopes);
1366
+ }
1367
+ }
1368
+ let children = null;
1369
+ if (node.children) {
1370
+ if (typeof node.children === "string") {
1371
+ children = evaluateProp(node.children, scopes);
1372
+ } else if (Array.isArray(node.children)) {
1373
+ children = node.children.map((child, index) => /* @__PURE__ */ jsx3(RenderNode, { node: child, scopes, atoms, onEvent }, child.id || index));
1374
+ }
1375
+ }
1376
+ return /* @__PURE__ */ jsx3(Component, { ...evaluatedProps, children });
1377
+ };
1378
+ var CTRErrorBoundary = class extends React4.Component {
1379
+ constructor(props) {
1380
+ super(props);
1381
+ this.state = { hasError: false };
1382
+ }
1383
+ static getDerivedStateFromError(error) {
1384
+ return { hasError: true, error };
1385
+ }
1386
+ componentDidCatch(error, errorInfo) {
1387
+ console.error("CTR rendering error:", error, errorInfo);
1388
+ }
1389
+ render() {
1390
+ if (this.state.hasError) {
1391
+ return this.props.fallback || /* @__PURE__ */ jsxs2("div", { style: { padding: 16, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 8 }, children: [
1392
+ /* @__PURE__ */ jsx3("strong", { style: { color: "#c53030" }, children: "Rendering Error" }),
1393
+ /* @__PURE__ */ jsx3("p", { style: { color: "#e53e3e", fontSize: 14, marginTop: 4 }, children: this.state.error?.message || "An error occurred while rendering" })
1394
+ ] });
1395
+ }
1396
+ return this.props.children;
1397
+ }
1398
+ };
1399
+ var ComponentTreeRenderer = ({
1400
+ tree,
1401
+ scopes,
1402
+ atoms = {},
1403
+ onEvent = () => {
1404
+ },
1405
+ fallback
1406
+ }) => {
1407
+ const allAtoms = useMemo3(() => ({ ...atoms }), [atoms]);
1408
+ const handleEvent = useCallback4(
1409
+ (eventName, payload) => onEvent(eventName, payload),
1410
+ [onEvent]
1411
+ );
1412
+ const nodes = Array.isArray(tree) ? tree : [tree];
1413
+ return /* @__PURE__ */ jsx3(CTRErrorBoundary, { fallback, children: nodes.map((node, index) => /* @__PURE__ */ jsx3(RenderNode, { node, scopes, atoms: allAtoms, onEvent: handleEvent }, index)) });
1414
+ };
1415
+
1416
+ // src/player/builtin-atoms.tsx
1417
+ import React5 from "react";
1418
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1419
+ var Stack = ({ children, gap = 8, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "column", gap, ...style }, ...rest, children });
1420
+ var Row = ({ children, gap = 8, align, justify, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "row", gap, alignItems: align, justifyContent: justify, ...style }, ...rest, children });
1421
+ var Column = ({ children, span, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { flex: span ? `0 0 ${Number(span) / 12 * 100}%` : 1, ...style }, ...rest, children });
1422
+ var Grid = ({ children, columns = 2, gap = 8, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap, ...style }, ...rest, children });
1423
+ var Divider = ({ style }) => /* @__PURE__ */ jsx4("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: "8px 0", ...style } });
1424
+ var Spacer = ({ size = 16 }) => /* @__PURE__ */ jsx4("div", { style: { height: size, flexShrink: 0 } });
1425
+ var Text = ({ children, size, weight, color, style, ...rest }) => /* @__PURE__ */ jsx4("span", { style: { fontSize: size, fontWeight: weight, color, ...style }, ...rest, children });
1426
+ var Heading = ({ children, level = 2, style, ...rest }) => {
1427
+ const lvl = Math.min(Math.max(Number(level), 1), 6);
1428
+ const s = { margin: "0 0 8px", ...style };
1429
+ const c = children;
1430
+ if (lvl === 1) return /* @__PURE__ */ jsx4("h1", { style: s, ...rest, children: c });
1431
+ if (lvl === 2) return /* @__PURE__ */ jsx4("h2", { style: s, ...rest, children: c });
1432
+ if (lvl === 3) return /* @__PURE__ */ jsx4("h3", { style: s, ...rest, children: c });
1433
+ if (lvl === 4) return /* @__PURE__ */ jsx4("h4", { style: s, ...rest, children: c });
1434
+ if (lvl === 5) return /* @__PURE__ */ jsx4("h5", { style: s, ...rest, children: c });
1435
+ return /* @__PURE__ */ jsx4("h6", { style: s, ...rest, children: c });
1436
+ };
1437
+ var Field = ({ label, value, children, style }) => /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8, ...style }, children: [
1438
+ label ? /* @__PURE__ */ jsx4("div", { style: { fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1439
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: 14 }, children: children ?? value ?? "\u2014" })
1440
+ ] });
1441
+ var Badge = ({ children, variant = "default", style }) => {
1442
+ const colors = {
1443
+ default: { bg: "#edf2f7", fg: "#4a5568" },
1444
+ success: { bg: "#c6f6d5", fg: "#276749" },
1445
+ warning: { bg: "#fefcbf", fg: "#975a16" },
1446
+ error: { bg: "#fed7d7", fg: "#9b2c2c" },
1447
+ info: { bg: "#bee3f8", fg: "#2a4365" }
1448
+ };
1449
+ const c = colors[variant] ?? colors.default;
1450
+ return /* @__PURE__ */ jsx4("span", { style: { display: "inline-block", padding: "2px 8px", borderRadius: 9999, fontSize: 12, fontWeight: 500, background: c.bg, color: c.fg, ...style }, children });
1451
+ };
1452
+ var ImageAtom = ({ src, alt, width, height, style, ...rest }) => /* @__PURE__ */ jsx4("img", { src, alt: alt ?? "", width, height, style: { maxWidth: "100%", ...style }, ...rest });
1453
+ var Button = ({ children, onClick, variant = "primary", disabled, style, ...rest }) => {
1454
+ const styles = {
1455
+ primary: { background: "#3182ce", color: "#fff", border: "none" },
1456
+ secondary: { background: "#edf2f7", color: "#4a5568", border: "1px solid #e2e8f0" },
1457
+ danger: { background: "#e53e3e", color: "#fff", border: "none" },
1458
+ ghost: { background: "transparent", color: "#4a5568", border: "none" }
1459
+ };
1460
+ const base = styles[variant] ?? styles.primary;
1461
+ return /* @__PURE__ */ jsx4(
1462
+ "button",
1463
+ {
1464
+ onClick,
1465
+ disabled,
1466
+ style: { padding: "6px 16px", borderRadius: 6, fontSize: 14, fontWeight: 500, cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.5 : 1, ...base, ...style },
1467
+ ...rest,
1468
+ children
1469
+ }
1470
+ );
1471
+ };
1472
+ var LinkAtom = ({ children, href, style, ...rest }) => /* @__PURE__ */ jsx4("a", { href, style: { color: "#3182ce", textDecoration: "underline", ...style }, ...rest, children });
1473
+ var TextInput = ({ value, onChange, placeholder, label, bind: _bind, style }) => {
1474
+ const isControlled = typeof onChange === "function";
1475
+ const [localValue, setLocalValue] = React5.useState(value ?? "");
1476
+ const handleChange = (e) => {
1477
+ setLocalValue(e.target.value);
1478
+ if (typeof onChange === "function") onChange(e);
1479
+ };
1480
+ return /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8 }, children: [
1481
+ label ? /* @__PURE__ */ jsx4("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1482
+ /* @__PURE__ */ jsx4(
1483
+ "input",
1484
+ {
1485
+ type: "text",
1486
+ value: isControlled ? value ?? "" : localValue,
1487
+ onChange: handleChange,
1488
+ placeholder,
1489
+ style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style }
1490
+ }
1491
+ )
1492
+ ] });
1493
+ };
1494
+ var SelectAtom = ({ value, onChange, options, label, placeholder, style }) => /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8 }, children: [
1495
+ label ? /* @__PURE__ */ jsx4("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1496
+ /* @__PURE__ */ jsxs3(
1497
+ "select",
1498
+ {
1499
+ value: value ?? "",
1500
+ onChange,
1501
+ style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style },
1502
+ children: [
1503
+ placeholder ? /* @__PURE__ */ jsx4("option", { value: "", children: placeholder }) : null,
1504
+ Array.isArray(options) && options.map((opt) => {
1505
+ const v = typeof opt === "string" ? opt : opt.value;
1506
+ const l = typeof opt === "string" ? opt : opt.label;
1507
+ return /* @__PURE__ */ jsx4("option", { value: v, children: l }, v);
1508
+ })
1509
+ ]
1510
+ }
1511
+ )
1512
+ ] });
1513
+ var Card = ({ children, title, style, ...rest }) => /* @__PURE__ */ jsxs3("div", { style: { border: "1px solid #e2e8f0", borderRadius: 8, padding: 16, background: "#fff", ...style }, ...rest, children: [
1514
+ title ? /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, fontSize: 16, marginBottom: 12 }, children: title }) : null,
1515
+ children
1516
+ ] });
1517
+ var Section = ({ children, title, style, ...rest }) => /* @__PURE__ */ jsxs3("section", { style: { marginBottom: 24, ...style }, ...rest, children: [
1518
+ title ? /* @__PURE__ */ jsx4("h3", { style: { fontSize: 18, fontWeight: 600, marginBottom: 8 }, children: title }) : null,
1519
+ children
1520
+ ] });
1521
+ var Show = ({ when, children, fallback }) => when ? /* @__PURE__ */ jsx4(Fragment2, { children }) : /* @__PURE__ */ jsx4(Fragment2, { children: fallback ?? null });
1522
+ var Each = ({ items, children, renderItem }) => {
1523
+ if (!Array.isArray(items)) return null;
1524
+ if (typeof renderItem === "function") return /* @__PURE__ */ jsx4(Fragment2, { children: items.map((item, i) => renderItem(item, i)) });
1525
+ return /* @__PURE__ */ jsx4(Fragment2, { children });
1526
+ };
1527
+ var RouterContext = React5.createContext({ path: "/", navigate: () => {
1528
+ } });
1529
+ var Router = ({ children, basePath, className, style, ...rest }) => {
1530
+ const [path, setPath] = React5.useState("/");
1531
+ const navigate = React5.useCallback((to) => setPath(to), []);
1532
+ return /* @__PURE__ */ jsx4(RouterContext.Provider, { value: { path, navigate }, children: /* @__PURE__ */ jsx4("div", { className, style, ...rest, children }) });
1533
+ };
1534
+ var Route = ({ children, path, exact, fallback: _fallback, className, style }) => {
1535
+ const { path: currentPath } = React5.useContext(RouterContext);
1536
+ const routePath = path || "/";
1537
+ const isExact = exact !== false;
1538
+ const matches = isExact ? currentPath === routePath || routePath === "/" && currentPath === "/" : currentPath.startsWith(routePath);
1539
+ if (!matches) return null;
1540
+ return /* @__PURE__ */ jsx4("div", { className, style, children });
1541
+ };
1542
+ var NavLink = ({ children, to, label, icon, className, style, ...rest }) => {
1543
+ const { path, navigate } = React5.useContext(RouterContext);
1544
+ const target = to || "/";
1545
+ const isActive = path === target;
1546
+ return /* @__PURE__ */ jsx4(
1547
+ "button",
1548
+ {
1549
+ onClick: () => navigate(target),
1550
+ className,
1551
+ style: {
1552
+ background: isActive ? "#edf2f7" : "transparent",
1553
+ border: "none",
1554
+ borderRadius: 4,
1555
+ padding: "4px 12px",
1556
+ fontSize: 13,
1557
+ cursor: "pointer",
1558
+ fontWeight: isActive ? 600 : 400,
1559
+ color: isActive ? "#2d3748" : "#718096",
1560
+ ...style
1561
+ },
1562
+ ...rest,
1563
+ children: children || label || target
1564
+ }
1565
+ );
1566
+ };
1567
+ var RoleGuard = ({ children, role: _role, fallback: _fallback }) => {
1568
+ return /* @__PURE__ */ jsx4(Fragment2, { children });
1569
+ };
1570
+ var Icon = ({ name, size = 16, color, style }) => /* @__PURE__ */ jsx4("span", { style: { display: "inline-flex", alignItems: "center", justifyContent: "center", width: size, height: size, fontSize: size, color, ...style }, title: name, children: iconGlyphs[name] || "\u25A1" });
1571
+ var iconGlyphs = {
1572
+ home: "\u2302",
1573
+ settings: "\u2699",
1574
+ plus: "+",
1575
+ search: "\u{1F50D}",
1576
+ box: "\u25A1",
1577
+ inbox: "\u2709",
1578
+ chevronRight: "\u203A",
1579
+ chevronLeft: "\u2039",
1580
+ x: "\u2715",
1581
+ check: "\u2713",
1582
+ edit: "\u270E",
1583
+ trash: "\u{1F5D1}",
1584
+ star: "\u2605",
1585
+ heart: "\u2665",
1586
+ user: "\u{1F464}",
1587
+ menu: "\u2630",
1588
+ close: "\u2715",
1589
+ arrow_right: "\u2192",
1590
+ arrow_left: "\u2190"
1591
+ };
1592
+ var Tabs = ({ children, tabs, defaultTab, style }) => {
1593
+ const tabList = tabs || [];
1594
+ const [active, setActive] = React5.useState(defaultTab || tabList[0]?.id || "");
1595
+ return /* @__PURE__ */ jsxs3("div", { style, children: [
1596
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", borderBottom: "1px solid #e2e8f0", marginBottom: 12 }, children: tabList.map((t) => /* @__PURE__ */ jsx4(
1597
+ "button",
1598
+ {
1599
+ onClick: () => setActive(t.id),
1600
+ style: { padding: "6px 16px", border: "none", borderBottom: active === t.id ? "2px solid #3182ce" : "2px solid transparent", background: "none", cursor: "pointer", fontWeight: active === t.id ? 600 : 400, color: active === t.id ? "#3182ce" : "#718096" },
1601
+ children: t.label
1602
+ },
1603
+ t.id
1604
+ )) }),
1605
+ children
1606
+ ] });
1607
+ };
1608
+ var Accordion = ({ children, style }) => /* @__PURE__ */ jsx4("div", { style, children });
1609
+ var Modal = ({ children, open, title, onClose: _onClose, style }) => {
1610
+ if (!open) return null;
1611
+ return /* @__PURE__ */ jsx4("div", { style: { position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1e3 }, children: /* @__PURE__ */ jsxs3("div", { style: { background: "#fff", borderRadius: 12, padding: 24, maxWidth: 480, width: "100%", ...style }, children: [
1612
+ title ? /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, fontSize: 18, marginBottom: 16 }, children: String(title) }) : null,
1613
+ children
1614
+ ] }) });
1615
+ };
1616
+ var Markdown = ({ content, children, style }) => /* @__PURE__ */ jsx4("div", { style: { lineHeight: 1.6, ...style }, children: content || children });
1617
+ var ScrollArea = ({ children, maxHeight = 400, style }) => /* @__PURE__ */ jsx4("div", { style: { overflow: "auto", maxHeight, ...style }, children });
1618
+ var Slot = ({ children, fallback }) => /* @__PURE__ */ jsx4(Fragment2, { children: children || fallback || null });
1619
+ var ModuleOutlet = ({ children, module: moduleName, fallback }) => /* @__PURE__ */ jsx4("div", { "data-module": moduleName, children: children || fallback || /* @__PURE__ */ jsxs3("span", { style: { color: "#a0aec0", fontSize: 13 }, children: [
1620
+ "Module: ",
1621
+ moduleName
1622
+ ] }) });
1623
+ var builtinAtoms = {
1624
+ // Layout
1625
+ Stack,
1626
+ Row,
1627
+ Column,
1628
+ Grid,
1629
+ Divider,
1630
+ Spacer,
1631
+ // Typography
1632
+ Text,
1633
+ Heading,
1634
+ Field,
1635
+ Badge,
1636
+ Image: ImageAtom,
1637
+ Icon,
1638
+ // Interactive
1639
+ Button,
1640
+ Link: LinkAtom,
1641
+ // Form
1642
+ TextInput,
1643
+ Select: SelectAtom,
1644
+ // Containers
1645
+ Card,
1646
+ Section,
1647
+ Tabs,
1648
+ Accordion,
1649
+ Modal,
1650
+ // Content
1651
+ Markdown,
1652
+ ScrollArea,
1653
+ // Control Flow
1654
+ Show,
1655
+ Each,
1656
+ // Routing
1657
+ Router,
1658
+ Route,
1659
+ NavLink,
1660
+ RoleGuard,
1661
+ // Composition
1662
+ Slot,
1663
+ ModuleOutlet
1664
+ };
1665
+
1666
+ // src/player/DevPlayer.tsx
1667
+ import { useState as useState4, useCallback as useCallback5, useRef as useRef5, useEffect as useEffect4, useMemo as useMemo4 } from "react";
1668
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1669
+ var S = {
1670
+ shell: {
1671
+ display: "flex",
1672
+ flexDirection: "column",
1673
+ height: "100%",
1674
+ minHeight: "100vh",
1675
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1676
+ background: "#f7fafc",
1677
+ color: "#1a202c"
1678
+ },
1679
+ toolbar: {
1680
+ display: "flex",
1681
+ alignItems: "center",
1682
+ gap: 12,
1683
+ padding: "8px 16px",
1684
+ background: "#1a202c",
1685
+ color: "#e2e8f0",
1686
+ fontSize: 13,
1687
+ flexShrink: 0
1688
+ },
1689
+ toolbarTitle: { fontWeight: 600, fontSize: 14 },
1690
+ toolbarBadge: {
1691
+ display: "inline-block",
1692
+ padding: "1px 8px",
1693
+ borderRadius: 4,
1694
+ background: "#2d3748",
1695
+ color: "#a0aec0",
1696
+ fontSize: 11,
1697
+ fontFamily: "monospace"
1698
+ },
1699
+ toolbarBtn: {
1700
+ background: "none",
1701
+ border: "1px solid #4a5568",
1702
+ borderRadius: 4,
1703
+ color: "#a0aec0",
1704
+ padding: "2px 10px",
1705
+ fontSize: 12,
1706
+ cursor: "pointer"
1707
+ },
1708
+ toolbarBtnActive: {
1709
+ background: "#2b6cb0",
1710
+ borderColor: "#2b6cb0",
1711
+ color: "#fff"
1712
+ },
1713
+ body: { display: "flex", flex: 1, overflow: "hidden" },
1714
+ preview: { flex: 1, overflow: "auto", padding: 24 },
1715
+ sidebar: {
1716
+ width: 340,
1717
+ flexShrink: 0,
1718
+ borderLeft: "1px solid #e2e8f0",
1719
+ background: "#fff",
1720
+ overflow: "auto",
1721
+ fontSize: 13
1722
+ },
1723
+ sidebarSection: { padding: "12px 16px", borderBottom: "1px solid #f0f0f0" },
1724
+ sidebarHeading: {
1725
+ fontSize: 11,
1726
+ fontWeight: 700,
1727
+ textTransform: "uppercase",
1728
+ color: "#a0aec0",
1729
+ letterSpacing: "0.05em",
1730
+ marginBottom: 8
1731
+ },
1732
+ pre: {
1733
+ background: "#f7fafc",
1734
+ border: "1px solid #e2e8f0",
1735
+ borderRadius: 6,
1736
+ padding: "8px 12px",
1737
+ fontSize: 12,
1738
+ fontFamily: "monospace",
1739
+ whiteSpace: "pre-wrap",
1740
+ wordBreak: "break-word",
1741
+ maxHeight: 260,
1742
+ overflow: "auto"
1743
+ },
1744
+ eventRow: {
1745
+ display: "flex",
1746
+ gap: 8,
1747
+ padding: "4px 0",
1748
+ borderBottom: "1px solid #f7fafc",
1749
+ fontSize: 12,
1750
+ fontFamily: "monospace"
1751
+ },
1752
+ eventTime: { color: "#a0aec0", flexShrink: 0 },
1753
+ eventName: { color: "#3182ce", fontWeight: 500 },
1754
+ dot: (connected) => ({
1755
+ width: 8,
1756
+ height: 8,
1757
+ borderRadius: "50%",
1758
+ background: connected ? "#48bb78" : "#e53e3e",
1759
+ flexShrink: 0
1760
+ })
1761
+ };
1762
+ function useDevSocket(wsUrl, onReload) {
1763
+ const [connected, setConnected] = useState4(false);
1764
+ const wsRef = useRef5(null);
1765
+ useEffect4(() => {
1766
+ if (typeof window === "undefined") return;
1767
+ const url = wsUrl ?? `ws://${window.location.host}/__mm_dev`;
1768
+ let ws;
1769
+ let reconnectTimer;
1770
+ function connect() {
1771
+ try {
1772
+ ws = new WebSocket(url);
1773
+ wsRef.current = ws;
1774
+ ws.onopen = () => setConnected(true);
1775
+ ws.onclose = () => {
1776
+ setConnected(false);
1777
+ reconnectTimer = setTimeout(connect, 3e3);
1778
+ };
1779
+ ws.onmessage = (ev) => {
1780
+ try {
1781
+ const msg = JSON.parse(ev.data);
1782
+ if (msg.type === "workflow:compiled" || msg.type === "workflow:rebuild") {
1783
+ onReload?.();
1784
+ }
1785
+ } catch {
1786
+ }
1787
+ };
1788
+ } catch {
1789
+ reconnectTimer = setTimeout(connect, 3e3);
1790
+ }
1791
+ }
1792
+ connect();
1793
+ return () => {
1794
+ clearTimeout(reconnectTimer);
1795
+ wsRef.current?.close();
1796
+ wsRef.current = null;
1797
+ };
1798
+ }, [wsUrl, onReload]);
1799
+ return connected;
1800
+ }
1801
+ var DevPlayer = ({
1802
+ tree,
1803
+ scopes = {},
1804
+ atoms: userAtoms,
1805
+ title = "DevPlayer",
1806
+ bare = false,
1807
+ wsUrl,
1808
+ onReload,
1809
+ onEvent: externalOnEvent
1810
+ }) => {
1811
+ const [showSidebar, setShowSidebar] = useState4(true);
1812
+ const [events, setEvents] = useState4([]);
1813
+ const nextId = useRef5(0);
1814
+ const connected = useDevSocket(wsUrl, onReload);
1815
+ const mergedAtoms = useMemo4(
1816
+ () => ({ ...builtinAtoms, ...userAtoms }),
1817
+ [userAtoms]
1818
+ );
1819
+ const handleEvent = useCallback5(
1820
+ (name, payload) => {
1821
+ setEvents((prev) => {
1822
+ const entry = {
1823
+ id: nextId.current++,
1824
+ time: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }),
1825
+ name,
1826
+ payload
1827
+ };
1828
+ const next = [entry, ...prev];
1829
+ return next.length > 100 ? next.slice(0, 100) : next;
1830
+ });
1831
+ externalOnEvent?.(name, payload);
1832
+ },
1833
+ [externalOnEvent]
1834
+ );
1835
+ if (bare) {
1836
+ return /* @__PURE__ */ jsx5(
1837
+ ComponentTreeRenderer,
1838
+ {
1839
+ tree,
1840
+ scopes,
1841
+ atoms: mergedAtoms,
1842
+ onEvent: handleEvent
1843
+ }
1844
+ );
1845
+ }
1846
+ return /* @__PURE__ */ jsxs4("div", { style: S.shell, children: [
1847
+ /* @__PURE__ */ jsxs4("div", { style: S.toolbar, children: [
1848
+ /* @__PURE__ */ jsx5("div", { style: S.dot(connected), title: connected ? "HMR connected" : "HMR disconnected" }),
1849
+ /* @__PURE__ */ jsx5("span", { style: S.toolbarTitle, children: title }),
1850
+ /* @__PURE__ */ jsxs4("span", { style: S.toolbarBadge, children: [
1851
+ Array.isArray(tree) ? tree.length : 1,
1852
+ " node",
1853
+ Array.isArray(tree) && tree.length !== 1 ? "s" : ""
1854
+ ] }),
1855
+ /* @__PURE__ */ jsxs4("span", { style: S.toolbarBadge, children: [
1856
+ Object.keys(mergedAtoms).length,
1857
+ " atoms"
1858
+ ] }),
1859
+ /* @__PURE__ */ jsx5("div", { style: { flex: 1 } }),
1860
+ /* @__PURE__ */ jsx5(
1861
+ "button",
1862
+ {
1863
+ style: { ...S.toolbarBtn, ...showSidebar ? S.toolbarBtnActive : {} },
1864
+ onClick: () => setShowSidebar((v) => !v),
1865
+ children: "Inspector"
1866
+ }
1867
+ )
1868
+ ] }),
1869
+ /* @__PURE__ */ jsxs4("div", { style: S.body, children: [
1870
+ /* @__PURE__ */ jsx5("div", { style: S.preview, children: /* @__PURE__ */ jsx5(
1871
+ ComponentTreeRenderer,
1872
+ {
1873
+ tree,
1874
+ scopes,
1875
+ atoms: mergedAtoms,
1876
+ onEvent: handleEvent
1877
+ }
1878
+ ) }),
1879
+ showSidebar && /* @__PURE__ */ jsxs4("div", { style: S.sidebar, children: [
1880
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1881
+ /* @__PURE__ */ jsx5("div", { style: S.sidebarHeading, children: "Scopes" }),
1882
+ /* @__PURE__ */ jsx5("pre", { style: S.pre, children: JSON.stringify(scopes, null, 2) })
1883
+ ] }),
1884
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1885
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarHeading, children: [
1886
+ "Atoms (",
1887
+ Object.keys(mergedAtoms).length,
1888
+ ")"
1889
+ ] }),
1890
+ /* @__PURE__ */ jsx5("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: Object.keys(mergedAtoms).sort().map((name) => /* @__PURE__ */ jsx5(
1891
+ "span",
1892
+ {
1893
+ style: {
1894
+ display: "inline-block",
1895
+ padding: "1px 6px",
1896
+ borderRadius: 3,
1897
+ background: userAtoms?.[name] ? "#ebf8ff" : "#f7fafc",
1898
+ border: `1px solid ${userAtoms?.[name] ? "#90cdf4" : "#e2e8f0"}`,
1899
+ fontSize: 11,
1900
+ fontFamily: "monospace",
1901
+ color: userAtoms?.[name] ? "#2b6cb0" : "#718096"
1902
+ },
1903
+ children: name
1904
+ },
1905
+ name
1906
+ )) })
1907
+ ] }),
1908
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1909
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
1910
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarHeading, children: [
1911
+ "Events (",
1912
+ events.length,
1913
+ ")"
1914
+ ] }),
1915
+ events.length > 0 && /* @__PURE__ */ jsx5(
1916
+ "button",
1917
+ {
1918
+ style: { background: "none", border: "none", color: "#a0aec0", fontSize: 11, cursor: "pointer" },
1919
+ onClick: () => setEvents([]),
1920
+ children: "Clear"
1921
+ }
1922
+ )
1923
+ ] }),
1924
+ events.length === 0 && /* @__PURE__ */ jsx5("div", { style: { color: "#a0aec0", fontSize: 12, fontStyle: "italic" }, children: "No events yet" }),
1925
+ events.slice(0, 50).map((e) => /* @__PURE__ */ jsxs4("div", { style: S.eventRow, children: [
1926
+ /* @__PURE__ */ jsx5("span", { style: S.eventTime, children: e.time }),
1927
+ /* @__PURE__ */ jsx5("span", { style: S.eventName, children: e.name }),
1928
+ e.payload !== void 0 && /* @__PURE__ */ jsx5("span", { style: { color: "#718096", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: JSON.stringify(e.payload) })
1929
+ ] }, e.id))
1930
+ ] }),
1931
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1932
+ /* @__PURE__ */ jsx5("div", { style: S.sidebarHeading, children: "Tree (JSON)" }),
1933
+ /* @__PURE__ */ jsx5("pre", { style: { ...S.pre, maxHeight: 400 }, children: JSON.stringify(tree, null, 2) })
1934
+ ] })
1935
+ ] })
1936
+ ] })
1937
+ ] });
1938
+ };
1939
+
1940
+ export {
1941
+ setQueryResolver,
1942
+ useQuery,
1943
+ setMutationResolver,
1944
+ useMutation,
1945
+ classifyBinding,
1946
+ resolveBinding,
1947
+ resolveAllBindings,
1948
+ buildEvalContext,
1949
+ buildActionScope,
1950
+ AtomRegistryImpl,
1951
+ createCoreAtomRegistry,
1952
+ mergeRegistries,
1953
+ usePlayerContext,
1954
+ PlayerProvider,
1955
+ ExperienceRenderer,
1956
+ createApiResolver,
1957
+ createMockResolver,
1958
+ containsExpression,
1959
+ evaluateExpression2 as evaluateExpression,
1960
+ evaluateProp,
1961
+ ComponentTreeRenderer,
1962
+ builtinAtoms,
1963
+ DevPlayer
1964
+ };