@mmapp/react 0.1.0-alpha.1 → 0.1.0-alpha.4

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 (94) hide show
  1. package/README.md +112 -0
  2. package/dist/index.d.mts +1378 -94
  3. package/dist/index.d.ts +1378 -94
  4. package/dist/index.js +1094 -1309
  5. package/dist/index.mjs +1038 -1296
  6. package/package.json +4 -3
  7. package/package.json.backup +0 -41
  8. package/src/Blueprint.ts +0 -216
  9. package/src/__tests__/Blueprint.test.ts +0 -106
  10. package/src/__tests__/action-context.test.ts +0 -166
  11. package/src/__tests__/actionCreators.test.ts +0 -179
  12. package/src/__tests__/builders.test.ts +0 -336
  13. package/src/__tests__/defineBlueprint-composition.test.ts +0 -106
  14. package/src/__tests__/factories.test.ts +0 -229
  15. package/src/__tests__/loader.test.ts +0 -159
  16. package/src/__tests__/logger.test.ts +0 -70
  17. package/src/__tests__/type-inference.test.ts +0 -160
  18. package/src/__tests__/typed-transitions.test.ts +0 -126
  19. package/src/__tests__/useModuleConfig.test.ts +0 -61
  20. package/src/actionCreators.ts +0 -132
  21. package/src/actions.ts +0 -547
  22. package/src/atoms/index.ts +0 -600
  23. package/src/authoring.ts +0 -92
  24. package/src/browser-player.ts +0 -783
  25. package/src/builders.ts +0 -1342
  26. package/src/components/ExperienceWorkflowBridge.tsx +0 -123
  27. package/src/components/PlayerProvider.tsx +0 -43
  28. package/src/components/atoms/index.tsx +0 -269
  29. package/src/components/index.ts +0 -36
  30. package/src/conditions.ts +0 -692
  31. package/src/config/defineBlueprint.ts +0 -329
  32. package/src/config/defineModel.ts +0 -753
  33. package/src/config/defineWorkspace.ts +0 -24
  34. package/src/core/WorkflowRuntime.ts +0 -153
  35. package/src/factories.ts +0 -425
  36. package/src/grammar/index.ts +0 -173
  37. package/src/hooks/index.ts +0 -106
  38. package/src/hooks/useAuth.ts +0 -288
  39. package/src/hooks/useChannel.ts +0 -304
  40. package/src/hooks/useComputed.ts +0 -154
  41. package/src/hooks/useDomainSubscription.ts +0 -110
  42. package/src/hooks/useDuringAction.ts +0 -99
  43. package/src/hooks/useExperienceState.ts +0 -59
  44. package/src/hooks/useExpressionLibrary.ts +0 -129
  45. package/src/hooks/useForm.ts +0 -352
  46. package/src/hooks/useGeolocation.ts +0 -207
  47. package/src/hooks/useMapView.ts +0 -259
  48. package/src/hooks/useMiddleware.ts +0 -291
  49. package/src/hooks/useModel.ts +0 -363
  50. package/src/hooks/useModule.ts +0 -59
  51. package/src/hooks/useModuleConfig.ts +0 -61
  52. package/src/hooks/useMutation.ts +0 -237
  53. package/src/hooks/useNotification.ts +0 -151
  54. package/src/hooks/useOnChange.ts +0 -30
  55. package/src/hooks/useOnEnter.ts +0 -59
  56. package/src/hooks/useOnEvent.ts +0 -37
  57. package/src/hooks/useOnExit.ts +0 -27
  58. package/src/hooks/useOnTransition.ts +0 -30
  59. package/src/hooks/usePackage.ts +0 -128
  60. package/src/hooks/useParams.ts +0 -33
  61. package/src/hooks/usePlayer.ts +0 -308
  62. package/src/hooks/useQuery.ts +0 -184
  63. package/src/hooks/useRealtimeQuery.ts +0 -222
  64. package/src/hooks/useRole.ts +0 -191
  65. package/src/hooks/useRouteParams.ts +0 -100
  66. package/src/hooks/useRouter.ts +0 -347
  67. package/src/hooks/useServerAction.ts +0 -178
  68. package/src/hooks/useServerState.ts +0 -284
  69. package/src/hooks/useToast.ts +0 -164
  70. package/src/hooks/useTransition.ts +0 -39
  71. package/src/hooks/useView.ts +0 -102
  72. package/src/hooks/useWhileIn.ts +0 -48
  73. package/src/hooks/useWorkflow.ts +0 -63
  74. package/src/index.ts +0 -465
  75. package/src/loader/experience-workflow-loader.ts +0 -192
  76. package/src/loader/index.ts +0 -6
  77. package/src/local/LocalEngine.ts +0 -388
  78. package/src/local/LocalEngineAdapter.ts +0 -175
  79. package/src/local/LocalEngineContext.ts +0 -30
  80. package/src/logger.ts +0 -37
  81. package/src/mixins.ts +0 -1160
  82. package/src/providers/RuntimeContext.ts +0 -20
  83. package/src/providers/WorkflowProvider.tsx +0 -28
  84. package/src/routing/instance-key.ts +0 -107
  85. package/src/server/transition-context.ts +0 -172
  86. package/src/testing/index.ts +0 -9
  87. package/src/testing/useBlueprintTestRunner.ts +0 -91
  88. package/src/testing/useGraphAnalysis.ts +0 -18
  89. package/src/testing/useTestRunner.ts +0 -77
  90. package/src/testing.ts +0 -995
  91. package/src/types/workflow-inference.ts +0 -158
  92. package/src/types.ts +0 -114
  93. package/tsconfig.json +0 -27
  94. package/vitest.config.ts +0 -8
package/dist/index.mjs CHANGED
@@ -1,1087 +1,11 @@
1
- // ../player-core/dist/index.mjs
2
- var add = {
3
- name: "add",
4
- fn: (a, b) => Number(a) + Number(b),
5
- arity: 2
6
- };
7
- var subtract = {
8
- name: "subtract",
9
- fn: (a, b) => Number(a) - Number(b),
10
- arity: 2
11
- };
12
- var multiply = {
13
- name: "multiply",
14
- fn: (a, b) => Number(a) * Number(b),
15
- arity: 2
16
- };
17
- var divide = {
18
- name: "divide",
19
- fn: (a, b) => {
20
- const d = Number(b);
21
- return d === 0 ? 0 : Number(a) / d;
22
- },
23
- arity: 2
24
- };
25
- var abs = {
26
- name: "abs",
27
- fn: (a) => Math.abs(Number(a)),
28
- arity: 1
29
- };
30
- var round = {
31
- name: "round",
32
- fn: (a, decimals) => {
33
- const d = decimals != null ? Number(decimals) : 0;
34
- const factor = Math.pow(10, d);
35
- return Math.round(Number(a) * factor) / factor;
36
- },
37
- arity: -1
38
- };
39
- var min = {
40
- name: "min",
41
- fn: (...args) => {
42
- const nums = args.flat().map(Number).filter((n) => !isNaN(n));
43
- return nums.length === 0 ? 0 : Math.min(...nums);
44
- },
45
- arity: -1
46
- };
47
- var max = {
48
- name: "max",
49
- fn: (...args) => {
50
- const nums = args.flat().map(Number).filter((n) => !isNaN(n));
51
- return nums.length === 0 ? 0 : Math.max(...nums);
52
- },
53
- arity: -1
54
- };
55
- var eq = {
56
- name: "eq",
57
- fn: (a, b) => a === b || String(a) === String(b),
58
- arity: 2
59
- };
60
- var neq = {
61
- name: "neq",
62
- fn: (a, b) => a !== b && String(a) !== String(b),
63
- arity: 2
64
- };
65
- var gt = {
66
- name: "gt",
67
- fn: (a, b) => Number(a) > Number(b),
68
- arity: 2
69
- };
70
- var gte = {
71
- name: "gte",
72
- fn: (a, b) => Number(a) >= Number(b),
73
- arity: 2
74
- };
75
- var lt = {
76
- name: "lt",
77
- fn: (a, b) => Number(a) < Number(b),
78
- arity: 2
79
- };
80
- var lte = {
81
- name: "lte",
82
- fn: (a, b) => Number(a) <= Number(b),
83
- arity: 2
84
- };
85
- var if_fn = {
86
- name: "if",
87
- fn: (cond, then, else_) => cond ? then : else_,
88
- arity: 3
89
- };
90
- var and = {
91
- name: "and",
92
- fn: (...args) => args.every(Boolean),
93
- arity: -1
94
- };
95
- var or = {
96
- name: "or",
97
- fn: (...args) => args.some(Boolean),
98
- arity: -1
99
- };
100
- var not = {
101
- name: "not",
102
- fn: (a) => !a,
103
- arity: 1
104
- };
105
- var coalesce = {
106
- name: "coalesce",
107
- fn: (...args) => {
108
- for (const arg of args) {
109
- if (arg != null) return arg;
110
- }
111
- return null;
112
- },
113
- arity: -1
114
- };
115
- var concat = {
116
- name: "concat",
117
- fn: (...args) => args.map(String).join(""),
118
- arity: -1
119
- };
120
- var upper = {
121
- name: "upper",
122
- fn: (s) => String(s ?? "").toUpperCase(),
123
- arity: 1
124
- };
125
- var lower = {
126
- name: "lower",
127
- fn: (s) => String(s ?? "").toLowerCase(),
128
- arity: 1
129
- };
130
- var trim = {
131
- name: "trim",
132
- fn: (s) => String(s ?? "").trim(),
133
- arity: 1
134
- };
135
- var format = {
136
- name: "format",
137
- fn: (template, ...args) => {
138
- let result = String(template ?? "");
139
- args.forEach((arg, i) => {
140
- result = result.replace(`{${i}}`, String(arg ?? ""));
141
- });
142
- return result;
143
- },
144
- arity: -1
145
- };
146
- var length = {
147
- name: "length",
148
- fn: (v) => {
149
- if (Array.isArray(v)) return v.length;
150
- if (typeof v === "string") return v.length;
151
- if (v && typeof v === "object") return Object.keys(v).length;
152
- return 0;
153
- },
154
- arity: 1
155
- };
156
- var get = {
157
- name: "get",
158
- fn: (obj, path) => {
159
- if (obj == null || typeof path !== "string") return void 0;
160
- const parts = path.split(".");
161
- let current = obj;
162
- for (const part of parts) {
163
- if (current == null || typeof current !== "object") return void 0;
164
- current = current[part];
165
- }
166
- return current;
167
- },
168
- arity: 2
169
- };
170
- var includes = {
171
- name: "includes",
172
- fn: (collection, value) => {
173
- if (Array.isArray(collection)) return collection.includes(value);
174
- if (typeof collection === "string") return collection.includes(String(value));
175
- return false;
176
- },
177
- arity: 2
178
- };
179
- var is_defined = {
180
- name: "is_defined",
181
- fn: (v) => v !== void 0 && v !== null,
182
- arity: 1
183
- };
184
- var is_empty = {
185
- name: "is_empty",
186
- fn: (v) => {
187
- if (v == null) return true;
188
- if (typeof v === "string") return v.length === 0;
189
- if (Array.isArray(v)) return v.length === 0;
190
- if (typeof v === "object") return Object.keys(v).length === 0;
191
- return false;
192
- },
193
- arity: 1
194
- };
195
- var is_null = {
196
- name: "is_null",
197
- fn: (v) => v === null || v === void 0,
198
- arity: 1
199
- };
200
- var to_string = {
201
- name: "to_string",
202
- fn: (v) => {
203
- if (v == null) return "";
204
- if (typeof v === "object") return JSON.stringify(v);
205
- return String(v);
206
- },
207
- arity: 1
208
- };
209
- var CORE_FUNCTIONS = [
210
- // Math (8)
211
- add,
212
- subtract,
213
- multiply,
214
- divide,
215
- abs,
216
- round,
217
- min,
218
- max,
219
- // Comparison (6)
220
- eq,
221
- neq,
222
- gt,
223
- gte,
224
- lt,
225
- lte,
226
- // Logic (5)
227
- if_fn,
228
- and,
229
- or,
230
- not,
231
- coalesce,
232
- // String (6)
233
- concat,
234
- upper,
235
- lower,
236
- trim,
237
- format,
238
- length,
239
- // Path (3)
240
- get,
241
- includes,
242
- is_defined,
243
- // Type (3)
244
- is_empty,
245
- is_null,
246
- to_string
247
- ];
248
- function buildFunctionMap(functions) {
249
- const map = /* @__PURE__ */ new Map();
250
- for (const fn of functions) {
251
- map.set(fn.name, fn.fn);
252
- }
253
- return map;
254
- }
255
- var MAX_DEPTH = 50;
256
- var Parser = class {
257
- pos = 0;
258
- depth = 0;
259
- input;
260
- constructor(input) {
261
- this.input = input;
262
- }
263
- parse() {
264
- this.skipWhitespace();
265
- const node = this.parseExpression();
266
- this.skipWhitespace();
267
- if (this.pos < this.input.length) {
268
- throw new Error(`Unexpected character at position ${this.pos}: '${this.input[this.pos]}'`);
269
- }
270
- return node;
271
- }
272
- guardDepth() {
273
- if (++this.depth > MAX_DEPTH) {
274
- throw new Error("Expression too deeply nested");
275
- }
276
- }
277
- parseExpression() {
278
- this.guardDepth();
279
- try {
280
- return this.parseTernary();
281
- } finally {
282
- this.depth--;
283
- }
284
- }
285
- parseTernary() {
286
- let node = this.parseLogicalOr();
287
- this.skipWhitespace();
288
- if (this.peek() === "?") {
289
- this.advance();
290
- const consequent = this.parseExpression();
291
- this.skipWhitespace();
292
- this.expect(":");
293
- const alternate = this.parseExpression();
294
- node = { type: "ternary", condition: node, consequent, alternate };
295
- }
296
- return node;
297
- }
298
- parseLogicalOr() {
299
- let left = this.parseLogicalAnd();
300
- this.skipWhitespace();
301
- while (this.match("||")) {
302
- const right = this.parseLogicalAnd();
303
- left = { type: "binary", operator: "||", left, right };
304
- this.skipWhitespace();
305
- }
306
- return left;
307
- }
308
- parseLogicalAnd() {
309
- let left = this.parseEquality();
310
- this.skipWhitespace();
311
- while (this.match("&&")) {
312
- const right = this.parseEquality();
313
- left = { type: "binary", operator: "&&", left, right };
314
- this.skipWhitespace();
315
- }
316
- return left;
317
- }
318
- parseEquality() {
319
- let left = this.parseComparison();
320
- this.skipWhitespace();
321
- while (true) {
322
- if (this.match("==")) {
323
- const right = this.parseComparison();
324
- left = { type: "binary", operator: "==", left, right };
325
- } else if (this.match("!=")) {
326
- const right = this.parseComparison();
327
- left = { type: "binary", operator: "!=", left, right };
328
- } else {
329
- break;
330
- }
331
- this.skipWhitespace();
332
- }
333
- return left;
334
- }
335
- parseComparison() {
336
- let left = this.parseUnary();
337
- this.skipWhitespace();
338
- while (true) {
339
- if (this.match(">=")) {
340
- const right = this.parseUnary();
341
- left = { type: "binary", operator: ">=", left, right };
342
- } else if (this.match("<=")) {
343
- const right = this.parseUnary();
344
- left = { type: "binary", operator: "<=", left, right };
345
- } else if (this.peek() === ">" && !this.lookAhead(">=")) {
346
- this.advance();
347
- const right = this.parseUnary();
348
- left = { type: "binary", operator: ">", left, right };
349
- } else if (this.peek() === "<" && !this.lookAhead("<=")) {
350
- this.advance();
351
- const right = this.parseUnary();
352
- left = { type: "binary", operator: "<", left, right };
353
- } else {
354
- break;
355
- }
356
- this.skipWhitespace();
357
- }
358
- return left;
359
- }
360
- parseUnary() {
361
- this.skipWhitespace();
362
- if (this.peek() === "!") {
363
- this.advance();
364
- const operand = this.parseUnary();
365
- return { type: "unary", operator: "!", operand };
366
- }
367
- if (this.peek() === "-") {
368
- const nextChar = this.input[this.pos + 1];
369
- if (nextChar !== void 0 && (nextChar >= "0" && nextChar <= "9" || nextChar === ".")) {
370
- return this.parseCallChain();
371
- }
372
- }
373
- return this.parseCallChain();
374
- }
375
- parseCallChain() {
376
- let node = this.parsePrimary();
377
- while (true) {
378
- this.skipWhitespace();
379
- if (this.peek() === "(") {
380
- this.advance();
381
- const args = this.parseArgList();
382
- this.expect(")");
383
- if (node.type === "identifier") {
384
- node = { type: "call", name: node.name, args };
385
- } else if (node.type === "path") {
386
- const name = node.segments.join(".");
387
- node = { type: "call", name, args };
388
- } else if (node.type === "member") {
389
- node = { type: "method_call", object: node.object, method: node.property, args };
390
- } else {
391
- throw new Error("Cannot call non-function");
392
- }
393
- } else if (this.peek() === ".") {
394
- this.advance();
395
- const prop = this.parseIdentifierName();
396
- node = { type: "member", object: node, property: prop };
397
- } else {
398
- break;
399
- }
400
- }
401
- return node;
402
- }
403
- parsePrimary() {
404
- this.skipWhitespace();
405
- const ch = this.peek();
406
- if (ch === "(") {
407
- this.advance();
408
- const expr2 = this.parseExpression();
409
- this.skipWhitespace();
410
- this.expect(")");
411
- return expr2;
412
- }
413
- if (ch === "'" || ch === '"') {
414
- return this.parseString();
415
- }
416
- if (ch === "-" || ch >= "0" && ch <= "9") {
417
- return this.parseNumber();
418
- }
419
- if (this.isIdentStart(ch)) {
420
- return this.parseIdentifierOrPath();
421
- }
422
- throw new Error(
423
- `Unexpected character at position ${this.pos}: '${ch || "EOF"}'`
424
- );
425
- }
426
- parseString() {
427
- const quote = this.advance();
428
- let value = "";
429
- while (this.pos < this.input.length && this.peek() !== quote) {
430
- if (this.peek() === "\\") {
431
- this.advance();
432
- const esc = this.advance();
433
- if (esc === "n") value += "\n";
434
- else if (esc === "t") value += " ";
435
- else if (esc === "r") value += "\r";
436
- else value += esc;
437
- } else {
438
- value += this.advance();
439
- }
440
- }
441
- if (this.pos >= this.input.length) {
442
- throw new Error("Unterminated string literal");
443
- }
444
- this.advance();
445
- return { type: "string", value };
446
- }
447
- parseNumber() {
448
- let numStr = "";
449
- if (this.peek() === "-") {
450
- numStr += this.advance();
451
- }
452
- while (this.pos < this.input.length && (this.input[this.pos] >= "0" && this.input[this.pos] <= "9")) {
453
- numStr += this.advance();
454
- }
455
- if (this.peek() === "." && this.pos + 1 < this.input.length && this.input[this.pos + 1] >= "0" && this.input[this.pos + 1] <= "9") {
456
- numStr += this.advance();
457
- while (this.pos < this.input.length && (this.input[this.pos] >= "0" && this.input[this.pos] <= "9")) {
458
- numStr += this.advance();
459
- }
460
- }
461
- return { type: "number", value: Number(numStr) };
462
- }
463
- parseIdentifierOrPath() {
464
- const name = this.parseIdentifierName();
465
- if (name === "true") return { type: "boolean", value: true };
466
- if (name === "false") return { type: "boolean", value: false };
467
- if (name === "null") return { type: "null" };
468
- if (name === "undefined") return { type: "null" };
469
- return { type: "identifier", name };
470
- }
471
- parseIdentifierName() {
472
- let name = "";
473
- if (this.peek() === "$") name += this.advance();
474
- while (this.pos < this.input.length && this.isIdentPart(this.input[this.pos])) {
475
- name += this.advance();
476
- }
477
- if (!name) {
478
- throw new Error(`Expected identifier at position ${this.pos}`);
479
- }
480
- return name;
481
- }
482
- parseArgList() {
483
- this.skipWhitespace();
484
- if (this.peek() === ")") return [];
485
- const args = [];
486
- args.push(this.parseExpression());
487
- this.skipWhitespace();
488
- while (this.peek() === ",") {
489
- this.advance();
490
- args.push(this.parseExpression());
491
- this.skipWhitespace();
492
- }
493
- return args;
494
- }
495
- // Character utilities
496
- peek() {
497
- return this.input[this.pos] ?? "";
498
- }
499
- advance() {
500
- return this.input[this.pos++] ?? "";
501
- }
502
- match(str) {
503
- if (this.input.startsWith(str, this.pos)) {
504
- this.pos += str.length;
505
- return true;
506
- }
507
- return false;
508
- }
509
- lookAhead(str) {
510
- return this.input.startsWith(str, this.pos);
511
- }
512
- expect(ch) {
513
- this.skipWhitespace();
514
- if (this.peek() !== ch) {
515
- throw new Error(`Expected '${ch}' at position ${this.pos}, got '${this.peek() || "EOF"}'`);
516
- }
517
- this.advance();
518
- }
519
- skipWhitespace() {
520
- while (this.pos < this.input.length && " \n\r".includes(this.input[this.pos])) {
521
- this.pos++;
522
- }
523
- }
524
- isIdentStart(ch) {
525
- return ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch === "_" || ch === "$";
526
- }
527
- isIdentPart(ch) {
528
- return this.isIdentStart(ch) || ch >= "0" && ch <= "9";
529
- }
530
- };
531
- function evaluateAST(node, context, fnMap) {
532
- switch (node.type) {
533
- case "number":
534
- return node.value;
535
- case "string":
536
- return node.value;
537
- case "boolean":
538
- return node.value;
539
- case "null":
540
- return null;
541
- case "identifier":
542
- return resolvePath(node.name, context);
543
- case "path":
544
- return resolvePath(node.segments.join("."), context);
545
- case "member": {
546
- const obj = evaluateAST(node.object, context, fnMap);
547
- if (obj == null || typeof obj !== "object") return void 0;
548
- return obj[node.property];
549
- }
550
- case "call": {
551
- const fn = fnMap.get(node.name);
552
- if (!fn) return void 0;
553
- const args = node.args.map((a) => evaluateAST(a, context, fnMap));
554
- return fn(...args);
555
- }
556
- case "method_call": {
557
- const obj = evaluateAST(node.object, context, fnMap);
558
- if (obj != null && typeof obj === "object") {
559
- const method = obj[node.method];
560
- if (typeof method === "function") {
561
- const args = node.args.map((a) => evaluateAST(a, context, fnMap));
562
- return method.apply(obj, args);
563
- }
564
- }
565
- return void 0;
566
- }
567
- case "unary": {
568
- const operand = evaluateAST(node.operand, context, fnMap);
569
- return !operand;
570
- }
571
- case "binary": {
572
- if (node.operator === "&&") {
573
- const left2 = evaluateAST(node.left, context, fnMap);
574
- if (!left2) return left2;
575
- return evaluateAST(node.right, context, fnMap);
576
- }
577
- if (node.operator === "||") {
578
- const left2 = evaluateAST(node.left, context, fnMap);
579
- if (left2) return left2;
580
- return evaluateAST(node.right, context, fnMap);
581
- }
582
- const left = evaluateAST(node.left, context, fnMap);
583
- const right = evaluateAST(node.right, context, fnMap);
584
- switch (node.operator) {
585
- // eslint-disable-next-line eqeqeq
586
- case "==":
587
- return left == right;
588
- // eslint-disable-next-line eqeqeq
589
- case "!=":
590
- return left != right;
591
- case ">":
592
- return Number(left) > Number(right);
593
- case "<":
594
- return Number(left) < Number(right);
595
- case ">=":
596
- return Number(left) >= Number(right);
597
- case "<=":
598
- return Number(left) <= Number(right);
599
- default:
600
- return void 0;
601
- }
602
- }
603
- case "ternary": {
604
- const condition = evaluateAST(node.condition, context, fnMap);
605
- return condition ? evaluateAST(node.consequent, context, fnMap) : evaluateAST(node.alternate, context, fnMap);
606
- }
607
- }
608
- }
609
- var MAX_CACHE = 500;
610
- var astCache = /* @__PURE__ */ new Map();
611
- function evictIfNeeded() {
612
- if (astCache.size > MAX_CACHE) {
613
- const keys = Array.from(astCache.keys());
614
- const evictCount = Math.floor(MAX_CACHE * 0.25);
615
- for (let i = 0; i < evictCount; i++) {
616
- astCache.delete(keys[i]);
617
- }
618
- }
619
- }
620
- function parseAndCache(expr2) {
621
- const cached = astCache.get(expr2);
622
- if (cached) return cached;
623
- const parser = new Parser(expr2);
624
- const ast = parser.parse();
625
- astCache.set(expr2, ast);
626
- evictIfNeeded();
627
- return ast;
628
- }
629
- var TEMPLATE_RE = /\{\{(.+?)\}\}/g;
630
- function resolvePath(path, context) {
631
- const parts = path.split(".");
632
- let current = context;
633
- for (const part of parts) {
634
- if (current == null || typeof current !== "object") return void 0;
635
- current = current[part];
636
- }
637
- return current;
638
- }
639
- function evaluateExpression(expr2, context, fnMap) {
640
- const trimmed = expr2.trim();
641
- if (trimmed === "true") return true;
642
- if (trimmed === "false") return false;
643
- if (trimmed === "null") return null;
644
- if (trimmed === "undefined") return void 0;
645
- const num = Number(trimmed);
646
- if (!isNaN(num) && trimmed !== "") return num;
647
- if (trimmed.startsWith("'") && trimmed.endsWith("'") || trimmed.startsWith('"') && trimmed.endsWith('"')) {
648
- return trimmed.slice(1, -1);
649
- }
650
- if (/^[a-zA-Z_$][\w$.]*$/.test(trimmed)) {
651
- return resolvePath(trimmed, context);
652
- }
653
- const ast = parseAndCache(trimmed);
654
- return evaluateAST(ast, context, fnMap);
655
- }
656
- var WEB_FAILURE_POLICIES = {
657
- VIEW_BINDING: {
658
- on_error: "return_fallback",
659
- fallback_value: "",
660
- log_level: "warn"
661
- },
662
- EVENT_REACTION: {
663
- on_error: "log_and_skip",
664
- fallback_value: void 0,
665
- log_level: "error"
666
- },
667
- DURING_ACTION: {
668
- on_error: "log_and_skip",
669
- fallback_value: void 0,
670
- log_level: "error"
671
- },
672
- CONDITIONAL_VISIBILITY: {
673
- on_error: "return_fallback",
674
- fallback_value: true,
675
- // Show by default if condition fails
676
- log_level: "warn"
677
- }
678
- };
679
- function createEvaluator(config) {
680
- const allFunctions = [...CORE_FUNCTIONS, ...config.functions];
681
- const fnMap = buildFunctionMap(allFunctions);
682
- const policy = config.failurePolicy;
683
- function handleError(expr2, error) {
684
- const message = error instanceof Error ? error.message : String(error);
685
- if (policy.log_level === "error") {
686
- console.error(`[player-core] Expression error: "${expr2}" \u2014 ${message}`);
687
- } else if (policy.log_level === "warn") {
688
- console.warn(`[player-core] Expression error: "${expr2}" \u2014 ${message}`);
689
- }
690
- switch (policy.on_error) {
691
- case "throw":
692
- throw error;
693
- case "return_fallback":
694
- return { value: policy.fallback_value, status: "fallback", error: message };
695
- case "log_and_skip":
696
- default:
697
- return { value: policy.fallback_value, status: "error", error: message };
698
- }
699
- }
700
- return {
701
- evaluate(expression, context) {
702
- try {
703
- const value = evaluateExpression(expression, context, fnMap);
704
- return { value, status: "ok" };
705
- } catch (error) {
706
- return handleError(expression, error);
707
- }
708
- },
709
- evaluateTemplate(template, context) {
710
- try {
711
- if (!template.includes("{{")) {
712
- return { value: template, status: "ok" };
713
- }
714
- const result = template.replace(TEMPLATE_RE, (_match, expr2) => {
715
- const value = evaluateExpression(expr2, context, fnMap);
716
- return value != null ? String(value) : "";
717
- });
718
- return { value: result, status: "ok" };
719
- } catch (error) {
720
- return handleError(template, error);
721
- }
722
- },
723
- validate(expression) {
724
- const errors = [];
725
- try {
726
- parseAndCache(expression);
727
- } catch (e) {
728
- errors.push(e instanceof Error ? e.message : String(e));
729
- }
730
- return { valid: errors.length === 0, errors };
731
- }
732
- };
733
- }
734
- var MAX_AUTO_CHAIN = 10;
735
- var StateMachine = class {
736
- evaluator;
737
- actionHandlers;
738
- listeners = /* @__PURE__ */ new Set();
739
- instance;
740
- constructor(definition, initialData = {}, config) {
741
- this.evaluator = config.evaluator;
742
- this.actionHandlers = config.actionHandlers ?? /* @__PURE__ */ new Map();
743
- const startState = definition.states.find((s) => s.type === "START");
744
- if (!startState) {
745
- throw new Error(`No START state found in definition ${definition.slug}`);
746
- }
747
- this.instance = {
748
- definition,
749
- current_state: startState.name,
750
- state_data: { ...initialData },
751
- memory: {},
752
- status: "ACTIVE"
753
- };
754
- }
755
- /** Get the current instance snapshot (immutable copy) */
756
- getSnapshot() {
757
- return { ...this.instance, state_data: { ...this.instance.state_data }, memory: { ...this.instance.memory } };
758
- }
759
- /** Get current state name */
760
- get currentState() {
761
- return this.instance.current_state;
762
- }
763
- /** Get current state_data */
764
- get stateData() {
765
- return this.instance.state_data;
766
- }
767
- /** Get current status */
768
- get status() {
769
- return this.instance.status;
770
- }
771
- /** Subscribe to state machine events */
772
- on(listener) {
773
- this.listeners.add(listener);
774
- return () => this.listeners.delete(listener);
775
- }
776
- /** Register an action handler */
777
- registerAction(type, handler) {
778
- this.actionHandlers.set(type, handler);
779
- }
780
- /** Execute a named transition */
781
- async transition(transitionName, data) {
782
- if (this.instance.status !== "ACTIVE") {
783
- return {
784
- success: false,
785
- from_state: this.instance.current_state,
786
- to_state: this.instance.current_state,
787
- actions_executed: [],
788
- error: `Cannot transition: instance status is ${this.instance.status}`
789
- };
790
- }
791
- const transition2 = this.instance.definition.transitions.find(
792
- (t) => t.name === transitionName && t.from.includes(this.instance.current_state)
793
- );
794
- if (!transition2) {
795
- return {
796
- success: false,
797
- from_state: this.instance.current_state,
798
- to_state: this.instance.current_state,
799
- actions_executed: [],
800
- error: `Transition "${transitionName}" not valid from state "${this.instance.current_state}"`
801
- };
802
- }
803
- if (data) {
804
- this.instance.state_data = { ...this.instance.state_data, ...data };
805
- }
806
- if (transition2.conditions && transition2.conditions.length > 0) {
807
- const ctx = this.buildContext();
808
- for (const condition of transition2.conditions) {
809
- const result2 = this.evaluator.evaluate(condition, ctx);
810
- if (!result2.value) {
811
- return {
812
- success: false,
813
- from_state: this.instance.current_state,
814
- to_state: this.instance.current_state,
815
- actions_executed: [],
816
- error: `Transition condition not met: ${condition}`
817
- };
818
- }
819
- }
820
- }
821
- const result = await this.executeTransition(transition2);
822
- if (result.success) {
823
- await this.drainAutoTransitions();
824
- }
825
- return result;
826
- }
827
- /** Update state_data directly (for on_event set_field actions) */
828
- setField(field2, value) {
829
- this.instance.state_data = { ...this.instance.state_data, [field2]: value };
830
- }
831
- /** Update memory */
832
- setMemory(key, value) {
833
- this.instance.memory = { ...this.instance.memory, [key]: value };
834
- }
835
- /** Get available transitions from the current state */
836
- getAvailableTransitions() {
837
- return this.instance.definition.transitions.filter(
838
- (t) => t.from.includes(this.instance.current_state) && !t.auto
839
- );
840
- }
841
- /** Get the current state definition */
842
- getCurrentStateDefinition() {
843
- return this.instance.definition.states.find((s) => s.name === this.instance.current_state);
844
- }
845
- // ===========================================================================
846
- // Private implementation
847
- // ===========================================================================
848
- async executeTransition(transition2) {
849
- const fromState = this.instance.current_state;
850
- const allActionsExecuted = [];
851
- const fromStateDef = this.getCurrentStateDefinition();
852
- if (fromStateDef?.on_exit) {
853
- await this.executeActions(fromStateDef.on_exit, allActionsExecuted);
854
- }
855
- this.emit({
856
- type: "state_exit",
857
- instance_id: this.instance.definition.id,
858
- from_state: fromState
859
- });
860
- if (transition2.actions) {
861
- await this.executeActions(transition2.actions, allActionsExecuted);
862
- }
863
- this.instance.current_state = transition2.to;
864
- const toStateDef = this.instance.definition.states.find((s) => s.name === transition2.to);
865
- if (toStateDef?.type === "END") {
866
- this.instance.status = "COMPLETED";
867
- } else if (toStateDef?.type === "CANCELLED") {
868
- this.instance.status = "CANCELLED";
869
- }
870
- this.emit({
871
- type: "state_enter",
872
- instance_id: this.instance.definition.id,
873
- to_state: transition2.to
874
- });
875
- if (toStateDef?.on_enter) {
876
- await this.executeActions(toStateDef.on_enter, allActionsExecuted);
877
- }
878
- this.emit({
879
- type: "transition",
880
- instance_id: this.instance.definition.id,
881
- from_state: fromState,
882
- to_state: transition2.to
883
- });
884
- return {
885
- success: true,
886
- from_state: fromState,
887
- to_state: transition2.to,
888
- actions_executed: allActionsExecuted
889
- };
890
- }
891
- async drainAutoTransitions() {
892
- for (let depth = 0; depth < MAX_AUTO_CHAIN; depth++) {
893
- if (this.instance.status !== "ACTIVE") break;
894
- const autoTransition = this.findMatchingAutoTransition();
895
- if (!autoTransition) break;
896
- const result = await this.executeTransition(autoTransition);
897
- if (!result.success) break;
898
- }
899
- }
900
- findMatchingAutoTransition() {
901
- const candidates = this.instance.definition.transitions.filter(
902
- (t) => t.auto && t.from.includes(this.instance.current_state)
903
- );
904
- const ctx = this.buildContext();
905
- for (const candidate of candidates) {
906
- if (!candidate.conditions || candidate.conditions.length === 0) {
907
- return candidate;
908
- }
909
- const allMet = candidate.conditions.every((condition) => {
910
- const result = this.evaluator.evaluate(condition, ctx);
911
- return result.value === true;
912
- });
913
- if (allMet) return candidate;
914
- }
915
- return null;
916
- }
917
- async executeActions(actions, collector) {
918
- const ctx = this.buildContext();
919
- for (const action2 of actions) {
920
- if (action2.condition) {
921
- const condResult = this.evaluator.evaluate(action2.condition, ctx);
922
- if (!condResult.value) continue;
923
- }
924
- const handler = this.actionHandlers.get(action2.type);
925
- if (handler) {
926
- try {
927
- await handler(action2, ctx);
928
- collector.push(action2);
929
- this.emit({
930
- type: "action_executed",
931
- instance_id: this.instance.definition.id,
932
- action: action2
933
- });
934
- } catch (error) {
935
- this.emit({
936
- type: "error",
937
- instance_id: this.instance.definition.id,
938
- action: action2,
939
- error: error instanceof Error ? error.message : String(error)
940
- });
941
- }
942
- }
943
- }
944
- }
945
- buildContext() {
946
- return {
947
- state_data: this.instance.state_data,
948
- memory: this.instance.memory,
949
- current_state: this.instance.current_state,
950
- status: this.instance.status,
951
- // Spread state_data for direct field access (e.g., "title" instead of "state_data.title")
952
- ...this.instance.state_data
953
- };
954
- }
955
- emit(event) {
956
- for (const listener of this.listeners) {
957
- try {
958
- listener(event);
959
- } catch {
960
- }
961
- }
962
- }
963
- };
964
- var patternCache = /* @__PURE__ */ new Map();
965
- var MAX_CACHE2 = 200;
966
- function compilePattern(pattern) {
967
- const cached = patternCache.get(pattern);
968
- if (cached) return cached;
969
- const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<DOUBLESTAR>>").replace(/\*/g, "[^:.]+").replace(/<<DOUBLESTAR>>/g, ".*");
970
- const regex = new RegExp(`^${escaped}$`);
971
- if (patternCache.size >= MAX_CACHE2) {
972
- const firstKey = patternCache.keys().next().value;
973
- if (firstKey) patternCache.delete(firstKey);
974
- }
975
- patternCache.set(pattern, regex);
976
- return regex;
977
- }
978
- function matchTopic(pattern, topic) {
979
- return pattern.test(topic);
980
- }
981
- var EventBus = class {
982
- subscriptions = [];
983
- /**
984
- * Subscribe to events matching a glob pattern.
985
- * Returns an unsubscribe function.
986
- */
987
- subscribe(pattern, handler) {
988
- const regex = compilePattern(pattern);
989
- const subscription = { pattern, regex, handler };
990
- this.subscriptions.push(subscription);
991
- return () => {
992
- const idx = this.subscriptions.indexOf(subscription);
993
- if (idx !== -1) this.subscriptions.splice(idx, 1);
994
- };
995
- }
996
- /**
997
- * Publish an event. All matching subscriptions fire (async).
998
- * Errors in handlers are caught and logged, never propagated.
999
- */
1000
- async publish(topic, payload = {}) {
1001
- const event = { topic, payload };
1002
- for (const sub of this.subscriptions) {
1003
- if (matchTopic(sub.regex, topic)) {
1004
- try {
1005
- await sub.handler(event);
1006
- } catch (error) {
1007
- console.warn(
1008
- `[player-core] Event handler error for pattern "${sub.pattern}" on topic "${topic}":`,
1009
- error
1010
- );
1011
- }
1012
- }
1013
- }
1014
- }
1015
- /**
1016
- * Publish synchronously (fire-and-forget).
1017
- * Useful when you don't need to await handler completion.
1018
- */
1019
- emit(topic, payload = {}) {
1020
- void this.publish(topic, payload);
1021
- }
1022
- /** Get count of active subscriptions */
1023
- get size() {
1024
- return this.subscriptions.length;
1025
- }
1026
- /** Remove all subscriptions */
1027
- clear() {
1028
- this.subscriptions.length = 0;
1029
- }
1030
- };
1031
- var ActionDispatcher = class {
1032
- handlers = /* @__PURE__ */ new Map();
1033
- /** Register a handler for an action type */
1034
- register(type, handler) {
1035
- this.handlers.set(type, handler);
1036
- }
1037
- /** Unregister a handler */
1038
- unregister(type) {
1039
- this.handlers.delete(type);
1040
- }
1041
- /** Check if a handler is registered for the given type */
1042
- has(type) {
1043
- return this.handlers.has(type);
1044
- }
1045
- /**
1046
- * Execute a list of actions sequentially.
1047
- * Each action's condition is evaluated first (if present).
1048
- * Missing handlers are skipped with a warning.
1049
- */
1050
- async execute(actions, context, evaluator) {
1051
- const results = [];
1052
- for (const action2 of actions) {
1053
- if (action2.condition && evaluator) {
1054
- const condResult = evaluator.evaluate(action2.condition, context);
1055
- if (!condResult.value) continue;
1056
- }
1057
- const handler = this.handlers.get(action2.type);
1058
- if (!handler) {
1059
- console.warn(`[player-core] No handler registered for action type "${action2.type}"`);
1060
- results.push({ type: action2.type, success: false, error: `No handler for "${action2.type}"` });
1061
- continue;
1062
- }
1063
- try {
1064
- await handler(action2.config, context);
1065
- results.push({ type: action2.type, success: true });
1066
- } catch (error) {
1067
- const message = error instanceof Error ? error.message : String(error);
1068
- console.warn(`[player-core] Action "${action2.type}" failed: ${message}`);
1069
- results.push({ type: action2.type, success: false, error: message });
1070
- }
1071
- }
1072
- return results;
1073
- }
1074
- /** Get count of registered handlers */
1075
- get size() {
1076
- return this.handlers.size;
1077
- }
1078
- /** Remove all handlers */
1079
- clear() {
1080
- this.handlers.clear();
1081
- }
1082
- };
1083
-
1084
1
  // src/core/WorkflowRuntime.ts
2
+ import {
3
+ StateMachine,
4
+ EventBus,
5
+ ActionDispatcher,
6
+ createEvaluator,
7
+ WEB_FAILURE_POLICIES
8
+ } from "@mmapp/player-core";
1085
9
  var WorkflowRuntime = class {
1086
10
  sm;
1087
11
  eventBus;
@@ -1180,24 +104,24 @@ import { useEffect, useRef } from "react";
1180
104
  import { createContext, useContext } from "react";
1181
105
  var RuntimeContext = createContext(null);
1182
106
  function useRuntimeContext() {
1183
- const runtime = useContext(RuntimeContext);
1184
- if (!runtime) {
107
+ const runtime2 = useContext(RuntimeContext);
108
+ if (!runtime2) {
1185
109
  throw new Error(
1186
110
  "useRuntimeContext must be used within a WorkflowProvider or RuntimeContext.Provider"
1187
111
  );
1188
112
  }
1189
- return runtime;
113
+ return runtime2;
1190
114
  }
1191
115
 
1192
116
  // src/hooks/useOnEnter.ts
1193
117
  function useOnEnter(stateName, effect) {
1194
- const runtime = useRuntimeContext();
118
+ const runtime2 = useRuntimeContext();
1195
119
  const effectRef = useRef(effect);
1196
120
  effectRef.current = effect;
1197
121
  const cleanupRef = useRef(null);
1198
122
  const states = Array.isArray(stateName) ? stateName : [stateName];
1199
123
  useEffect(() => {
1200
- if (states.includes(runtime.sm.currentState)) {
124
+ if (states.includes(runtime2.sm.currentState)) {
1201
125
  const result = effectRef.current();
1202
126
  if (result instanceof Promise) {
1203
127
  result.then((cleanup) => {
@@ -1207,7 +131,7 @@ function useOnEnter(stateName, effect) {
1207
131
  cleanupRef.current = result;
1208
132
  }
1209
133
  }
1210
- const unsub = runtime.sm.on((event) => {
134
+ const unsub = runtime2.sm.on((event) => {
1211
135
  if (event.type === "state_enter" && event.to_state && states.includes(event.to_state)) {
1212
136
  cleanupRef.current?.();
1213
137
  const result = effectRef.current();
@@ -1228,34 +152,34 @@ function useOnEnter(stateName, effect) {
1228
152
  unsub();
1229
153
  cleanupRef.current?.();
1230
154
  };
1231
- }, [runtime, ...states]);
155
+ }, [runtime2, ...states]);
1232
156
  }
1233
157
 
1234
158
  // src/hooks/useOnExit.ts
1235
159
  import { useEffect as useEffect2, useRef as useRef2 } from "react";
1236
160
  function useOnExit(stateName, effect) {
1237
- const runtime = useRuntimeContext();
161
+ const runtime2 = useRuntimeContext();
1238
162
  const effectRef = useRef2(effect);
1239
163
  effectRef.current = effect;
1240
164
  const states = Array.isArray(stateName) ? stateName : [stateName];
1241
165
  useEffect2(() => {
1242
- const unsub = runtime.sm.on((event) => {
166
+ const unsub = runtime2.sm.on((event) => {
1243
167
  if (event.type === "state_exit" && event.from_state && states.includes(event.from_state)) {
1244
168
  effectRef.current();
1245
169
  }
1246
170
  });
1247
171
  return unsub;
1248
- }, [runtime, ...states]);
172
+ }, [runtime2, ...states]);
1249
173
  }
1250
174
 
1251
175
  // src/hooks/useOnTransition.ts
1252
176
  import { useEffect as useEffect3, useRef as useRef3 } from "react";
1253
177
  function useOnTransition(effect) {
1254
- const runtime = useRuntimeContext();
178
+ const runtime2 = useRuntimeContext();
1255
179
  const effectRef = useRef3(effect);
1256
180
  effectRef.current = effect;
1257
181
  useEffect3(() => {
1258
- const unsub = runtime.sm.on((event) => {
182
+ const unsub = runtime2.sm.on((event) => {
1259
183
  if (event.type === "transition") {
1260
184
  effectRef.current({
1261
185
  from: event.from_state,
@@ -1264,33 +188,33 @@ function useOnTransition(effect) {
1264
188
  }
1265
189
  });
1266
190
  return unsub;
1267
- }, [runtime]);
191
+ }, [runtime2]);
1268
192
  }
1269
193
 
1270
194
  // src/hooks/useOnEvent.ts
1271
195
  import { useEffect as useEffect4, useRef as useRef4 } from "react";
1272
196
  function useOnEvent(pattern, handler, options) {
1273
- const runtime = useRuntimeContext();
197
+ const runtime2 = useRuntimeContext();
1274
198
  const handlerRef = useRef4(handler);
1275
199
  handlerRef.current = handler;
1276
200
  useEffect4(() => {
1277
- const unsub = runtime.eventBus.subscribe(pattern, (event) => {
1278
- if (options?.while && runtime.sm.currentState !== options.while) return;
201
+ const unsub = runtime2.eventBus.subscribe(pattern, (event) => {
202
+ if (options?.while && runtime2.sm.currentState !== options.while) return;
1279
203
  handlerRef.current(event);
1280
204
  });
1281
205
  return unsub;
1282
- }, [runtime, pattern, options?.while]);
206
+ }, [runtime2, pattern, options?.while]);
1283
207
  }
1284
208
 
1285
209
  // src/hooks/useOnChange.ts
1286
210
  import { useEffect as useEffect5, useRef as useRef5 } from "react";
1287
211
  function useOnChange(field2, handler) {
1288
- const runtime = useRuntimeContext();
212
+ const runtime2 = useRuntimeContext();
1289
213
  const handlerRef = useRef5(handler);
1290
214
  handlerRef.current = handler;
1291
- const prevRef = useRef5(runtime.sm.stateData[field2]);
215
+ const prevRef = useRef5(runtime2.sm.stateData[field2]);
1292
216
  useEffect5(() => {
1293
- const unsub = runtime.subscribe((snap) => {
217
+ const unsub = runtime2.subscribe((snap) => {
1294
218
  const newVal = snap.stateData[field2];
1295
219
  if (newVal !== prevRef.current) {
1296
220
  handlerRef.current(newVal, prevRef.current);
@@ -1298,13 +222,13 @@ function useOnChange(field2, handler) {
1298
222
  }
1299
223
  });
1300
224
  return unsub;
1301
- }, [runtime, field2]);
225
+ }, [runtime2, field2]);
1302
226
  }
1303
227
 
1304
228
  // src/hooks/useWhileIn.ts
1305
229
  import { useEffect as useEffect6, useRef as useRef6 } from "react";
1306
230
  function useWhileIn(stateName, intervalMs, effect) {
1307
- const runtime = useRuntimeContext();
231
+ const runtime2 = useRuntimeContext();
1308
232
  const effectRef = useRef6(effect);
1309
233
  effectRef.current = effect;
1310
234
  useEffect6(() => {
@@ -1319,8 +243,8 @@ function useWhileIn(stateName, intervalMs, effect) {
1319
243
  timer = null;
1320
244
  }
1321
245
  }
1322
- if (runtime.sm.currentState === stateName) startInterval();
1323
- const unsub = runtime.sm.on((event) => {
246
+ if (runtime2.sm.currentState === stateName) startInterval();
247
+ const unsub = runtime2.sm.on((event) => {
1324
248
  if (event.type === "state_enter" && event.to_state === stateName) startInterval();
1325
249
  if (event.type === "state_exit" && event.from_state === stateName) stopInterval();
1326
250
  });
@@ -1328,13 +252,13 @@ function useWhileIn(stateName, intervalMs, effect) {
1328
252
  unsub();
1329
253
  stopInterval();
1330
254
  };
1331
- }, [runtime, stateName, intervalMs]);
255
+ }, [runtime2, stateName, intervalMs]);
1332
256
  }
1333
257
 
1334
258
  // src/hooks/useDuringAction.ts
1335
259
  import { useEffect as useEffect7, useRef as useRef7 } from "react";
1336
260
  function useDuringAction(config) {
1337
- const runtime = useRuntimeContext();
261
+ const runtime2 = useRuntimeContext();
1338
262
  const actionRef = useRef7(config.action);
1339
263
  actionRef.current = config.action;
1340
264
  const states = Array.isArray(config.state) ? config.state : [config.state];
@@ -1372,10 +296,10 @@ function useDuringAction(config) {
1372
296
  timer = null;
1373
297
  }
1374
298
  }
1375
- if (states.includes(runtime.sm.currentState)) {
299
+ if (states.includes(runtime2.sm.currentState)) {
1376
300
  startAction();
1377
301
  }
1378
- const unsub = runtime.sm.on((event) => {
302
+ const unsub = runtime2.sm.on((event) => {
1379
303
  if (event.type === "state_enter" && event.to_state && states.includes(event.to_state)) {
1380
304
  startAction();
1381
305
  }
@@ -1387,7 +311,7 @@ function useDuringAction(config) {
1387
311
  unsub();
1388
312
  stopAction();
1389
313
  };
1390
- }, [runtime, intervalMs, immediate, enabled, ...states]);
314
+ }, [runtime2, intervalMs, immediate, enabled, ...states]);
1391
315
  }
1392
316
 
1393
317
  // src/hooks/useQuery.ts
@@ -1880,29 +804,29 @@ function useServerState(instanceId, options = {}) {
1880
804
  // src/hooks/useWorkflow.ts
1881
805
  import { useState as useState7, useEffect as useEffect12, useMemo, useCallback as useCallback7 } from "react";
1882
806
  function useWorkflow(definition, options) {
1883
- const runtime = useMemo(() => new WorkflowRuntime({
807
+ const runtime2 = useMemo(() => new WorkflowRuntime({
1884
808
  definition,
1885
809
  initialData: options?.initialData,
1886
810
  actionHandlers: options?.actionHandlers
1887
811
  }), [definition.id]);
1888
- const [snapshot, setSnapshot] = useState7(() => runtime.getSnapshot());
812
+ const [snapshot, setSnapshot] = useState7(() => runtime2.getSnapshot());
1889
813
  useEffect12(() => {
1890
- const unsub = runtime.subscribe(setSnapshot);
814
+ const unsub = runtime2.subscribe(setSnapshot);
1891
815
  return unsub;
1892
- }, [runtime]);
816
+ }, [runtime2]);
1893
817
  const transition2 = useCallback7(async (name, data) => {
1894
- const result = await runtime.transition(name, data);
818
+ const result = await runtime2.transition(name, data);
1895
819
  options?.onTransition?.(result);
1896
820
  return result;
1897
- }, [runtime, options?.onTransition]);
821
+ }, [runtime2, options?.onTransition]);
1898
822
  const handle = {
1899
823
  slug: definition.slug,
1900
824
  ...snapshot,
1901
825
  transition: transition2,
1902
- setField: runtime.setField.bind(runtime),
1903
- setMemory: runtime.setMemory.bind(runtime),
1904
- publishEvent: runtime.publishEvent.bind(runtime),
1905
- runtime
826
+ setField: runtime2.setField.bind(runtime2),
827
+ setMemory: runtime2.setMemory.bind(runtime2),
828
+ publishEvent: runtime2.publishEvent.bind(runtime2),
829
+ runtime: runtime2
1906
830
  };
1907
831
  return handle;
1908
832
  }
@@ -1910,17 +834,17 @@ function useWorkflow(definition, options) {
1910
834
  // src/hooks/useTransition.ts
1911
835
  import { useCallback as useCallback8, useState as useState8 } from "react";
1912
836
  function useTransition(transitionName, _config) {
1913
- const runtime = useRuntimeContext();
837
+ const runtime2 = useRuntimeContext();
1914
838
  const [pending, setPending] = useState8(false);
1915
- const available = runtime.sm.getAvailableTransitions().some((t) => t.name === transitionName);
839
+ const available = runtime2.sm.getAvailableTransitions().some((t) => t.name === transitionName);
1916
840
  const fire = useCallback8(async (data) => {
1917
841
  setPending(true);
1918
842
  try {
1919
- return await runtime.transition(transitionName, data);
843
+ return await runtime2.transition(transitionName, data);
1920
844
  } finally {
1921
845
  setPending(false);
1922
846
  }
1923
- }, [runtime, transitionName]);
847
+ }, [runtime2, transitionName]);
1924
848
  const handle = { fire, available, pending };
1925
849
  return handle;
1926
850
  }
@@ -1932,12 +856,12 @@ function setRoleHierarchy(hierarchy) {
1932
856
  _globalHierarchy = hierarchy;
1933
857
  }
1934
858
  function useRole(roleName, options = {}) {
1935
- const runtime = useRuntimeContext();
859
+ const runtime2 = useRuntimeContext();
1936
860
  const hierarchy = options.hierarchy ?? _globalHierarchy ?? [];
1937
861
  const inheritPermissions = options.inheritPermissions ?? true;
1938
862
  const result = useMemo2(() => {
1939
- const snapshot = runtime.getSnapshot();
1940
- const definition = runtime.config?.definition;
863
+ const snapshot = runtime2.getSnapshot();
864
+ const definition = runtime2.config?.definition;
1941
865
  const userRoles = snapshot.stateData?._userRoles ?? snapshot.stateData?.user_roles ?? [];
1942
866
  let hasRole2 = userRoles.includes(roleName);
1943
867
  if (!hasRole2 && hierarchy.length > 0) {
@@ -1985,7 +909,7 @@ function useRole(roleName, options = {}) {
1985
909
  }
1986
910
  }
1987
911
  return { hasRole: hasRole2, permissions, roles: userRoles, highestRole };
1988
- }, [runtime, roleName, hierarchy, inheritPermissions]);
912
+ }, [runtime2, roleName, hierarchy, inheritPermissions]);
1989
913
  const isAbove = useCallback9(
1990
914
  (role) => {
1991
915
  if (hierarchy.length === 0) return false;
@@ -2036,21 +960,21 @@ function useRole(roleName, options = {}) {
2036
960
  // src/hooks/useParams.ts
2037
961
  import { useMemo as useMemo3 } from "react";
2038
962
  function useParams() {
2039
- const runtime = useRuntimeContext();
963
+ const runtime2 = useRuntimeContext();
2040
964
  return useMemo3(() => {
2041
- const snapshot = runtime.getSnapshot();
965
+ const snapshot = runtime2.getSnapshot();
2042
966
  const params = snapshot.stateData?._params ?? snapshot.memory?._callParams ?? {};
2043
967
  return params;
2044
- }, [runtime]);
968
+ }, [runtime2]);
2045
969
  }
2046
970
 
2047
971
  // src/hooks/usePackage.ts
2048
972
  import { useMemo as useMemo4 } from "react";
2049
973
  function usePackage(packageSlug) {
2050
- const runtime = useRuntimeContext();
974
+ const runtime2 = useRuntimeContext();
2051
975
  return useMemo4(() => {
2052
- const snapshot = runtime.getSnapshot();
2053
- const definition = runtime.config?.definition;
976
+ const snapshot = runtime2.getSnapshot();
977
+ const definition = runtime2.config?.definition;
2054
978
  const childDefs = definition?.child_definitions ?? [];
2055
979
  const metadata = definition?.metadata ?? {};
2056
980
  if (definition?.slug === packageSlug && definition?.category === "blueprint") {
@@ -2113,7 +1037,7 @@ function usePackage(packageSlug) {
2113
1037
  isResolved: false,
2114
1038
  dependencySlugs: []
2115
1039
  };
2116
- }, [runtime, packageSlug]);
1040
+ }, [runtime2, packageSlug]);
2117
1041
  }
2118
1042
 
2119
1043
  // src/hooks/useRouter.ts
@@ -2239,16 +1163,16 @@ function useRouter(options = {}) {
2239
1163
  };
2240
1164
  setIsNavigating(true);
2241
1165
  try {
2242
- for (const guard of guardsRef.current) {
2243
- const allowed = await guard(to, location);
1166
+ for (const guard2 of guardsRef.current) {
1167
+ const allowed = await guard2(to, location);
2244
1168
  if (!allowed) {
2245
1169
  onRejectRef.current?.(to);
2246
1170
  return false;
2247
1171
  }
2248
1172
  }
2249
1173
  if (found?.route?.guards) {
2250
- for (const guard of found.route.guards) {
2251
- const allowed = await guard(to, location);
1174
+ for (const guard2 of found.route.guards) {
1175
+ const allowed = await guard2(to, location);
2252
1176
  if (!allowed) {
2253
1177
  if (found.route.redirectOnFail) {
2254
1178
  const fullRedirect = basePathRef.current + found.route.redirectOnFail;
@@ -2674,7 +1598,7 @@ function useGeolocation(options = {}) {
2674
1598
  const {
2675
1599
  enableHighAccuracy = false,
2676
1600
  maximumAge = 0,
2677
- timeout = 1e4,
1601
+ timeout: timeout2 = 1e4,
2678
1602
  watch = false,
2679
1603
  enabled = true
2680
1604
  } = options;
@@ -2685,8 +1609,8 @@ function useGeolocation(options = {}) {
2685
1609
  const watchIdRef = useRef18(null);
2686
1610
  const supported = typeof navigator !== "undefined" && "geolocation" in navigator;
2687
1611
  const positionOptions = useMemo8(
2688
- () => ({ enableHighAccuracy, maximumAge, timeout }),
2689
- [enableHighAccuracy, maximumAge, timeout]
1612
+ () => ({ enableHighAccuracy, maximumAge, timeout: timeout2 }),
1613
+ [enableHighAccuracy, maximumAge, timeout2]
2690
1614
  );
2691
1615
  const handleSuccess = useCallback13((pos) => {
2692
1616
  setPosition({
@@ -3046,7 +1970,7 @@ import { useState as useState16, useCallback as useCallback16, useMemo as useMem
3046
1970
  function useForm(config) {
3047
1971
  const {
3048
1972
  initialValues,
3049
- validate,
1973
+ validate: validate2,
3050
1974
  fieldValidators,
3051
1975
  onSubmit,
3052
1976
  onError,
@@ -3059,8 +1983,8 @@ function useForm(config) {
3059
1983
  const [isSubmitting, setIsSubmitting] = useState16(false);
3060
1984
  const [submitCount, setSubmitCount] = useState16(0);
3061
1985
  const initialRef = useRef20(initialValues);
3062
- const validateRef = useRef20(validate);
3063
- validateRef.current = validate;
1986
+ const validateRef = useRef20(validate2);
1987
+ validateRef.current = validate2;
3064
1988
  const fieldValidatorsRef = useRef20(fieldValidators);
3065
1989
  fieldValidatorsRef.current = fieldValidators;
3066
1990
  const onSubmitRef = useRef20(onSubmit);
@@ -3277,7 +2201,7 @@ function useNotification() {
3277
2201
  setPermission(result);
3278
2202
  return result;
3279
2203
  }, [supported]);
3280
- const notify2 = useCallback17(
2204
+ const notify3 = useCallback17(
3281
2205
  (title, options = {}) => {
3282
2206
  if (!supported || permission !== "granted") return null;
3283
2207
  const {
@@ -3310,8 +2234,8 @@ function useNotification() {
3310
2234
  [supported, permission]
3311
2235
  );
3312
2236
  return useMemo12(
3313
- () => ({ permission, supported, requestPermission, notify: notify2 }),
3314
- [permission, supported, requestPermission, notify2]
2237
+ () => ({ permission, supported, requestPermission, notify: notify3 }),
2238
+ [permission, supported, requestPermission, notify3]
3315
2239
  );
3316
2240
  }
3317
2241
 
@@ -3328,12 +2252,12 @@ function notifyListeners() {
3328
2252
  }
3329
2253
  function addToast(config) {
3330
2254
  const id = `toast-${++_nextId}`;
3331
- const instance = {
2255
+ const instance2 = {
3332
2256
  ...config,
3333
2257
  id,
3334
2258
  createdAt: Date.now()
3335
2259
  };
3336
- _toasts = [..._toasts, instance];
2260
+ _toasts = [..._toasts, instance2];
3337
2261
  const duration = config.duration ?? 5e3;
3338
2262
  if (duration > 0) {
3339
2263
  const timer = setTimeout(() => {
@@ -3384,8 +2308,191 @@ function useToast() {
3384
2308
  );
3385
2309
  }
3386
2310
 
2311
+ // src/hooks/useVisibility.ts
2312
+ import { useMemo as useMemo14 } from "react";
2313
+ function useVisibility(model2, role, playerType) {
2314
+ return useMemo14(() => {
2315
+ return computeVisibility(model2, role, playerType);
2316
+ }, [model2, role, playerType]);
2317
+ }
2318
+ function computeVisibility(model2, role, playerType) {
2319
+ const allFields = Object.keys(model2.fields || {});
2320
+ const allStates = Object.keys(model2.states || {});
2321
+ const vis = model2.orchestration?.visibility;
2322
+ if (!vis) {
2323
+ return makeResult(allFields, allStates);
2324
+ }
2325
+ let roleFields;
2326
+ let roleStates;
2327
+ let playerFields;
2328
+ if (role && vis.roles && vis.roles[role]) {
2329
+ const rv = vis.roles[role];
2330
+ roleFields = rv.fields === "*" ? "*" : [...rv.fields];
2331
+ roleStates = rv.states === "*" ? "*" : rv.states ? [...rv.states] : "*";
2332
+ }
2333
+ if (playerType && vis.players && vis.players[playerType]) {
2334
+ const pv = vis.players[playerType];
2335
+ playerFields = pv.fields === "*" ? "*" : [...pv.fields];
2336
+ }
2337
+ if (roleFields === void 0 && playerFields === void 0) {
2338
+ return makeResult(allFields, allStates);
2339
+ }
2340
+ let resolvedFields;
2341
+ if (roleFields === "*" && playerFields === "*") {
2342
+ resolvedFields = allFields;
2343
+ } else if (roleFields === "*") {
2344
+ resolvedFields = playerFields === void 0 ? allFields : playerFields;
2345
+ } else if (playerFields === "*") {
2346
+ resolvedFields = roleFields === void 0 ? allFields : roleFields;
2347
+ } else if (roleFields !== void 0 && playerFields !== void 0) {
2348
+ const roleSet = new Set(roleFields);
2349
+ resolvedFields = playerFields.filter((f) => roleSet.has(f));
2350
+ } else {
2351
+ resolvedFields = roleFields || playerFields || allFields;
2352
+ }
2353
+ const resolvedStates = roleStates === "*" || roleStates === void 0 ? allStates : roleStates;
2354
+ return makeResult(resolvedFields, resolvedStates);
2355
+ }
2356
+ function makeResult(fields, states) {
2357
+ const fieldSet = new Set(fields);
2358
+ const stateSet = new Set(states);
2359
+ return {
2360
+ visibleFields: fields,
2361
+ visibleStates: states,
2362
+ canSeeField: (f) => fieldSet.has(f),
2363
+ canSeeState: (s) => stateSet.has(s)
2364
+ };
2365
+ }
2366
+
2367
+ // src/hooks/usePresence.ts
2368
+ import { useState as useState19, useEffect as useEffect20, useCallback as useCallback19, useRef as useRef22 } from "react";
2369
+ var PRESENCE_EVENTS = {
2370
+ JOIN: "presence:join",
2371
+ LEAVE: "presence:leave",
2372
+ HEARTBEAT: "presence:heartbeat",
2373
+ EDIT_START: "presence:edit_start",
2374
+ EDIT_STOP: "presence:edit_stop"
2375
+ };
2376
+ function usePresence(instanceId, options = {}) {
2377
+ const {
2378
+ userId = "anonymous",
2379
+ userName = "Anonymous",
2380
+ wsUrl,
2381
+ enabled = true,
2382
+ heartbeatInterval = 15e3,
2383
+ staleTimeout = 45e3
2384
+ } = options;
2385
+ const channelName = `presence:${instanceId}`;
2386
+ const { publish, subscribe, connected } = useChannel(channelName, {
2387
+ wsUrl,
2388
+ enabled
2389
+ });
2390
+ const [viewers, setViewers] = useState19([]);
2391
+ const [editors, setEditors] = useState19([]);
2392
+ const viewersRef = useRef22(/* @__PURE__ */ new Map());
2393
+ const editorsRef = useRef22(/* @__PURE__ */ new Map());
2394
+ useEffect20(() => {
2395
+ if (!connected || !enabled) return;
2396
+ publish(PRESENCE_EVENTS.JOIN, { id: userId, name: userName, connectedAt: Date.now() });
2397
+ const hb = setInterval(() => {
2398
+ publish(PRESENCE_EVENTS.HEARTBEAT, { id: userId, name: userName });
2399
+ }, heartbeatInterval);
2400
+ return () => {
2401
+ clearInterval(hb);
2402
+ publish(PRESENCE_EVENTS.LEAVE, { id: userId });
2403
+ };
2404
+ }, [connected, enabled, userId, userName, heartbeatInterval, publish]);
2405
+ useEffect20(() => {
2406
+ if (!enabled) return;
2407
+ const cleanup = setInterval(() => {
2408
+ const now = Date.now();
2409
+ const stale = [];
2410
+ for (const [id, v] of viewersRef.current) {
2411
+ if (now - v.connectedAt > staleTimeout) stale.push(id);
2412
+ }
2413
+ if (stale.length > 0) {
2414
+ for (const id of stale) {
2415
+ viewersRef.current.delete(id);
2416
+ editorsRef.current.delete(id);
2417
+ }
2418
+ setViewers(Array.from(viewersRef.current.values()));
2419
+ setEditors(Array.from(editorsRef.current.values()));
2420
+ }
2421
+ }, staleTimeout / 3);
2422
+ return () => clearInterval(cleanup);
2423
+ }, [enabled, staleTimeout]);
2424
+ useEffect20(() => {
2425
+ if (!enabled) return;
2426
+ const unsubs = [];
2427
+ unsubs.push(subscribe(PRESENCE_EVENTS.JOIN, (data) => {
2428
+ if (data.id === userId) return;
2429
+ viewersRef.current.set(data.id, {
2430
+ id: data.id,
2431
+ name: data.name || "Anonymous",
2432
+ connectedAt: data.connectedAt || Date.now()
2433
+ });
2434
+ setViewers(Array.from(viewersRef.current.values()));
2435
+ }));
2436
+ unsubs.push(subscribe(PRESENCE_EVENTS.LEAVE, (data) => {
2437
+ viewersRef.current.delete(data.id);
2438
+ editorsRef.current.delete(data.id);
2439
+ setViewers(Array.from(viewersRef.current.values()));
2440
+ setEditors(Array.from(editorsRef.current.values()));
2441
+ }));
2442
+ unsubs.push(subscribe(PRESENCE_EVENTS.HEARTBEAT, (data) => {
2443
+ if (data.id === userId) return;
2444
+ const existing = viewersRef.current.get(data.id);
2445
+ if (existing) {
2446
+ existing.connectedAt = Date.now();
2447
+ } else {
2448
+ viewersRef.current.set(data.id, {
2449
+ id: data.id,
2450
+ name: data.name || "Anonymous",
2451
+ connectedAt: Date.now()
2452
+ });
2453
+ setViewers(Array.from(viewersRef.current.values()));
2454
+ }
2455
+ }));
2456
+ unsubs.push(subscribe(PRESENCE_EVENTS.EDIT_START, (data) => {
2457
+ if (data.id === userId) return;
2458
+ editorsRef.current.set(data.id, {
2459
+ id: data.id,
2460
+ name: data.name || "Anonymous",
2461
+ field: data.field,
2462
+ startedAt: Date.now()
2463
+ });
2464
+ setEditors(Array.from(editorsRef.current.values()));
2465
+ }));
2466
+ unsubs.push(subscribe(PRESENCE_EVENTS.EDIT_STOP, (data) => {
2467
+ editorsRef.current.delete(data.id);
2468
+ setEditors(Array.from(editorsRef.current.values()));
2469
+ }));
2470
+ return () => unsubs.forEach((fn) => fn());
2471
+ }, [enabled, userId, subscribe]);
2472
+ const startEditing = useCallback19((field2) => {
2473
+ publish(PRESENCE_EVENTS.EDIT_START, { id: userId, name: userName, field: field2 });
2474
+ }, [publish, userId, userName]);
2475
+ const stopEditing = useCallback19((_field) => {
2476
+ publish(PRESENCE_EVENTS.EDIT_STOP, { id: userId });
2477
+ }, [publish, userId]);
2478
+ const isEditing = useCallback19((field2) => {
2479
+ for (const editor of editorsRef.current.values()) {
2480
+ if (editor.field === field2 && editor.id !== userId) return true;
2481
+ }
2482
+ return false;
2483
+ }, [userId]);
2484
+ return {
2485
+ viewers,
2486
+ editors,
2487
+ viewerCount: viewers.length,
2488
+ isEditing,
2489
+ startEditing,
2490
+ stopEditing
2491
+ };
2492
+ }
2493
+
3387
2494
  // src/hooks/useMiddleware.ts
3388
- import { useState as useState19, useEffect as useEffect20, useRef as useRef22, useMemo as useMemo14 } from "react";
2495
+ import { useState as useState20, useEffect as useEffect21, useRef as useRef23, useMemo as useMemo15 } from "react";
3389
2496
  function requireAuth(loginPath = "/login") {
3390
2497
  return (ctx) => {
3391
2498
  if (!ctx.token) {
@@ -3457,24 +2564,24 @@ function useMiddleware(middlewares, options = {}) {
3457
2564
  watchPathname = true,
3458
2565
  onRedirect
3459
2566
  } = options;
3460
- const [ready, setReady] = useState19(false);
3461
- const [loading, setLoading] = useState19(true);
3462
- const [redirect, setRedirect] = useState19(null);
3463
- const [error, setError] = useState19(null);
3464
- const [data, setData] = useState19({});
3465
- const [runKey, setRunKey] = useState19(0);
3466
- const middlewaresRef = useRef22(middlewares);
2567
+ const [ready, setReady] = useState20(false);
2568
+ const [loading, setLoading] = useState20(true);
2569
+ const [redirect, setRedirect] = useState20(null);
2570
+ const [error, setError] = useState20(null);
2571
+ const [data, setData] = useState20({});
2572
+ const [runKey, setRunKey] = useState20(0);
2573
+ const middlewaresRef = useRef23(middlewares);
3467
2574
  middlewaresRef.current = middlewares;
3468
- const onRedirectRef = useRef22(onRedirect);
2575
+ const onRedirectRef = useRef23(onRedirect);
3469
2576
  onRedirectRef.current = onRedirect;
3470
- const [pathname, setPathname] = useState19(getPathname);
3471
- useEffect20(() => {
2577
+ const [pathname, setPathname] = useState20(getPathname);
2578
+ useEffect21(() => {
3472
2579
  if (!watchPathname) return;
3473
2580
  const handler = () => setPathname(getPathname());
3474
2581
  window.addEventListener("popstate", handler);
3475
2582
  return () => window.removeEventListener("popstate", handler);
3476
2583
  }, [watchPathname]);
3477
- useEffect20(() => {
2584
+ useEffect21(() => {
3478
2585
  if (!enabled) {
3479
2586
  setReady(true);
3480
2587
  setLoading(false);
@@ -3521,11 +2628,11 @@ function useMiddleware(middlewares, options = {}) {
3521
2628
  cancelled = true;
3522
2629
  };
3523
2630
  }, [enabled, pathname, runKey]);
3524
- const rerun = useMemo14(
2631
+ const rerun = useMemo15(
3525
2632
  () => () => setRunKey((k) => k + 1),
3526
2633
  []
3527
2634
  );
3528
- return useMemo14(
2635
+ return useMemo15(
3529
2636
  () => ({ ready, loading, redirect, error, data, rerun }),
3530
2637
  [ready, loading, redirect, error, data, rerun]
3531
2638
  );
@@ -3535,8 +2642,8 @@ function useMiddleware(middlewares, options = {}) {
3535
2642
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3536
2643
  import { jsx } from "react/jsx-runtime";
3537
2644
  var defaultQueryClient = new QueryClient();
3538
- function WorkflowProvider({ runtime, queryClient, children }) {
3539
- return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient ?? defaultQueryClient, children: /* @__PURE__ */ jsx(RuntimeContext.Provider, { value: runtime, children }) });
2645
+ function WorkflowProvider({ runtime: runtime2, queryClient, children }) {
2646
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient ?? defaultQueryClient, children: /* @__PURE__ */ jsx(RuntimeContext.Provider, { value: runtime2, children }) });
3540
2647
  }
3541
2648
 
3542
2649
  // src/local/LocalEngine.ts
@@ -3597,8 +2704,8 @@ var LocalWorkflowEngine = class {
3597
2704
  * Process all pending events from a transition result.
3598
2705
  * Emits locally and returns the events for P2P broadcast.
3599
2706
  */
3600
- processPendingEvents(instance) {
3601
- const events = instance._pendingEvents;
2707
+ processPendingEvents(instance2) {
2708
+ const events = instance2._pendingEvents;
3602
2709
  if (!events?.length) return [];
3603
2710
  for (const evt of events) {
3604
2711
  this.emitEvent(evt);
@@ -3641,18 +2748,18 @@ var LocalWorkflowEngine = class {
3641
2748
  };
3642
2749
  }
3643
2750
  /** Check if a transition can fire from the instance's current state */
3644
- canTransition(instance, transitionName) {
3645
- const def = this.definitions.get(instance.definitionSlug);
2751
+ canTransition(instance2, transitionName) {
2752
+ const def = this.definitions.get(instance2.definitionSlug);
3646
2753
  if (!def) return false;
3647
2754
  const transition2 = def.transitions.find((t) => t.name === transitionName);
3648
2755
  if (!transition2) return false;
3649
- return transition2.from.includes(instance.currentState);
2756
+ return transition2.from.includes(instance2.currentState);
3650
2757
  }
3651
2758
  /** Get all transitions available from the instance's current state */
3652
- getAvailableTransitions(instance) {
3653
- const def = this.definitions.get(instance.definitionSlug);
2759
+ getAvailableTransitions(instance2) {
2760
+ const def = this.definitions.get(instance2.definitionSlug);
3654
2761
  if (!def) return [];
3655
- return def.transitions.filter((t) => t.from.includes(instance.currentState)).map((t) => t.name);
2762
+ return def.transitions.filter((t) => t.from.includes(instance2.currentState)).map((t) => t.name);
3656
2763
  }
3657
2764
  /**
3658
2765
  * Apply a transition, returning a new WorkflowInstance (immutable).
@@ -3663,29 +2770,29 @@ var LocalWorkflowEngine = class {
3663
2770
  * @returns New WorkflowInstance with updated state and version
3664
2771
  * @throws If transition is not valid from current state
3665
2772
  */
3666
- applyTransition(instance, transitionName, data) {
3667
- const def = this.definitions.get(instance.definitionSlug);
2773
+ applyTransition(instance2, transitionName, data) {
2774
+ const def = this.definitions.get(instance2.definitionSlug);
3668
2775
  if (!def) {
3669
- throw new Error(`Definition not found: ${instance.definitionSlug}`);
2776
+ throw new Error(`Definition not found: ${instance2.definitionSlug}`);
3670
2777
  }
3671
2778
  const transition2 = def.transitions.find((t) => t.name === transitionName);
3672
2779
  if (!transition2) {
3673
2780
  throw new Error(
3674
- `Transition "${transitionName}" not found in ${instance.definitionSlug}`
2781
+ `Transition "${transitionName}" not found in ${instance2.definitionSlug}`
3675
2782
  );
3676
2783
  }
3677
- if (!transition2.from.includes(instance.currentState)) {
2784
+ if (!transition2.from.includes(instance2.currentState)) {
3678
2785
  throw new Error(
3679
- `Transition "${transitionName}" cannot fire from state "${instance.currentState}" (allowed from: ${transition2.from.join(", ")})`
2786
+ `Transition "${transitionName}" cannot fire from state "${instance2.currentState}" (allowed from: ${transition2.from.join(", ")})`
3680
2787
  );
3681
2788
  }
3682
- const nextState = transition2.to ?? instance.currentState;
3683
- const fields = data ? { ...instance.fields, ...data } : { ...instance.fields };
2789
+ const nextState = transition2.to ?? instance2.currentState;
2790
+ const fields = data ? { ...instance2.fields, ...data } : { ...instance2.fields };
3684
2791
  let result = {
3685
- ...instance,
2792
+ ...instance2,
3686
2793
  currentState: nextState,
3687
2794
  fields,
3688
- version: instance.version + 1,
2795
+ version: instance2.version + 1,
3689
2796
  updatedAt: Date.now()
3690
2797
  };
3691
2798
  const targetStateDef = def.states.find((s) => s.name === nextState);
@@ -3758,14 +2865,14 @@ var LocalWorkflowEngine = class {
3758
2865
  * Apply a transition only if the incoming version is newer.
3759
2866
  * Used for P2P sync — skips stale transitions.
3760
2867
  */
3761
- applyRemoteTransition(instance, transitionName, data, remoteVersion) {
3762
- if (remoteVersion <= instance.version) {
2868
+ applyRemoteTransition(instance2, transitionName, data, remoteVersion) {
2869
+ if (remoteVersion <= instance2.version) {
3763
2870
  return null;
3764
2871
  }
3765
- if (!this.canTransition(instance, transitionName)) {
2872
+ if (!this.canTransition(instance2, transitionName)) {
3766
2873
  return null;
3767
2874
  }
3768
- const updated = this.applyTransition(instance, transitionName, data);
2875
+ const updated = this.applyTransition(instance2, transitionName, data);
3769
2876
  return { ...updated, version: remoteVersion };
3770
2877
  }
3771
2878
  };
@@ -4031,6 +3138,155 @@ function defineModel(def) {
4031
3138
  return def;
4032
3139
  }
4033
3140
 
3141
+ // src/config/orchestration-presets.ts
3142
+ var SOLO = {
3143
+ strategy: "solo",
3144
+ evaluation: { pure: "local" },
3145
+ scheduling: { coordinator: "any" },
3146
+ events: { evaluator: "any-subscriber" },
3147
+ errorHandling: { strategy: "manual" },
3148
+ conflicts: { default: "last-writer-wins", fields: {} },
3149
+ visibility: { roles: {}, players: {} },
3150
+ presence: { enabled: false, showEditing: false, showViewing: false },
3151
+ services: {},
3152
+ actionRouting: {}
3153
+ };
3154
+ var CLIENT_SERVER = {
3155
+ strategy: "client-server",
3156
+ evaluation: { pure: "local" },
3157
+ scheduling: { coordinator: "server" },
3158
+ events: { evaluator: "server" },
3159
+ errorHandling: { strategy: "rollback" },
3160
+ conflicts: { default: "last-writer-wins", fields: {} },
3161
+ visibility: { roles: {}, players: {} },
3162
+ presence: { enabled: false, showEditing: false, showViewing: false },
3163
+ services: {},
3164
+ actionRouting: {}
3165
+ };
3166
+ var MULTI_CLIENT = {
3167
+ strategy: "multi-client",
3168
+ evaluation: { pure: "local" },
3169
+ scheduling: { coordinator: "server" },
3170
+ events: { evaluator: "server" },
3171
+ errorHandling: { strategy: "compensate" },
3172
+ conflicts: { default: "last-writer-wins", fields: {} },
3173
+ visibility: { roles: {}, players: {} },
3174
+ presence: { enabled: true, showEditing: true, showViewing: true, conflictHighlight: true },
3175
+ services: {},
3176
+ actionRouting: {}
3177
+ };
3178
+ var SERVICE_MESH = {
3179
+ strategy: "service-mesh",
3180
+ evaluation: { pure: "local" },
3181
+ scheduling: { coordinator: "server" },
3182
+ events: { evaluator: "all" },
3183
+ errorHandling: { strategy: "saga" },
3184
+ conflicts: { default: "first-write-wins", fields: {} },
3185
+ visibility: { roles: {}, players: {} },
3186
+ presence: { enabled: false, showEditing: false, showViewing: false },
3187
+ services: {},
3188
+ actionRouting: {}
3189
+ };
3190
+ var PEER_TO_PEER = {
3191
+ strategy: "peer-to-peer",
3192
+ evaluation: { pure: "local" },
3193
+ scheduling: { coordinator: "any" },
3194
+ events: { evaluator: "any-subscriber" },
3195
+ errorHandling: { strategy: "compensate" },
3196
+ conflicts: { default: "crdt", fields: {} },
3197
+ visibility: { roles: {}, players: {} },
3198
+ presence: { enabled: true, showEditing: true, showViewing: true, conflictHighlight: false },
3199
+ services: {},
3200
+ actionRouting: {}
3201
+ };
3202
+ var HYBRID = {
3203
+ strategy: "hybrid",
3204
+ evaluation: { pure: "local" },
3205
+ scheduling: { coordinator: "server" },
3206
+ events: { evaluator: "server" },
3207
+ errorHandling: { strategy: "saga" },
3208
+ conflicts: { default: "last-writer-wins", fields: {} },
3209
+ visibility: { roles: {}, players: {} },
3210
+ presence: { enabled: true, showEditing: true, showViewing: false, conflictHighlight: false },
3211
+ services: {},
3212
+ actionRouting: {}
3213
+ };
3214
+ var HEADLESS = {
3215
+ strategy: "headless",
3216
+ evaluation: { pure: "local" },
3217
+ // expression engine runs server-local (native Rust, fastest)
3218
+ scheduling: { coordinator: "server" },
3219
+ // server manages cron/interval/timeout
3220
+ events: { evaluator: "server" },
3221
+ // server matches events, no clients involved
3222
+ errorHandling: { strategy: "compensate" },
3223
+ conflicts: { default: "first-write-wins", fields: {} },
3224
+ // no concurrent clients
3225
+ visibility: { roles: {}, players: {} },
3226
+ presence: { enabled: false, showEditing: false, showViewing: false, conflictHighlight: false },
3227
+ services: {},
3228
+ actionRouting: {}
3229
+ };
3230
+ var ORCHESTRATION_PRESETS = {
3231
+ "solo": SOLO,
3232
+ "client-server": CLIENT_SERVER,
3233
+ "multi-client": MULTI_CLIENT,
3234
+ "service-mesh": SERVICE_MESH,
3235
+ "peer-to-peer": PEER_TO_PEER,
3236
+ "hybrid": HYBRID,
3237
+ "headless": HEADLESS,
3238
+ "custom": CLIENT_SERVER
3239
+ // custom uses client-server as base
3240
+ };
3241
+ var DEFAULT_RESOLVED = {
3242
+ strategy: "client-server",
3243
+ evaluation: { pure: "local" },
3244
+ scheduling: { coordinator: "server" },
3245
+ events: { evaluator: "server" },
3246
+ errorHandling: { strategy: "rollback" },
3247
+ conflicts: { default: "last-writer-wins", fields: {} },
3248
+ visibility: { roles: {}, players: {} },
3249
+ presence: { enabled: false, showEditing: false, showViewing: false, conflictHighlight: false },
3250
+ services: {},
3251
+ actionRouting: {}
3252
+ };
3253
+ function resolveOrchestration(config) {
3254
+ if (!config) return { ...DEFAULT_RESOLVED };
3255
+ const strategy = config.strategy || "client-server";
3256
+ const preset = ORCHESTRATION_PRESETS[strategy] || CLIENT_SERVER;
3257
+ return {
3258
+ strategy,
3259
+ evaluation: {
3260
+ pure: config.evaluation?.pure ?? preset.evaluation?.pure ?? "local"
3261
+ },
3262
+ scheduling: {
3263
+ coordinator: config.scheduling?.coordinator ?? preset.scheduling?.coordinator ?? "server"
3264
+ },
3265
+ events: {
3266
+ evaluator: config.events?.evaluator ?? preset.events?.evaluator ?? "server"
3267
+ },
3268
+ errorHandling: {
3269
+ strategy: config.errorHandling?.strategy ?? preset.errorHandling?.strategy ?? "rollback"
3270
+ },
3271
+ conflicts: {
3272
+ default: config.conflicts?.default ?? preset.conflicts?.default ?? "last-writer-wins",
3273
+ fields: { ...preset.conflicts?.fields || {}, ...config.conflicts?.fields || {} }
3274
+ },
3275
+ visibility: {
3276
+ roles: { ...preset.visibility?.roles || {}, ...config.visibility?.roles || {} },
3277
+ players: { ...preset.visibility?.players || {}, ...config.visibility?.players || {} }
3278
+ },
3279
+ presence: {
3280
+ enabled: config.presence?.enabled ?? preset.presence?.enabled ?? false,
3281
+ showEditing: config.presence?.showEditing ?? preset.presence?.showEditing ?? false,
3282
+ showViewing: config.presence?.showViewing ?? preset.presence?.showViewing ?? false,
3283
+ conflictHighlight: config.presence?.conflictHighlight ?? preset.presence?.conflictHighlight ?? false
3284
+ },
3285
+ services: { ...preset.services || {}, ...config.services || {} },
3286
+ actionRouting: { ...preset.actionRouting || {}, ...config.actionRouting || {} }
3287
+ };
3288
+ }
3289
+
4034
3290
  // src/config/defineBlueprint.ts
4035
3291
  function defineBlueprint(config) {
4036
3292
  if (!config.slug) {
@@ -4144,13 +3400,13 @@ function inState(state2) {
4144
3400
  function notInState(state2) {
4145
3401
  return { type: "expression", expression: `current_state != "${state2}"` };
4146
3402
  }
4147
- function and2(...conditions) {
3403
+ function and(...conditions) {
4148
3404
  return { AND: conditions.map(normalize) };
4149
3405
  }
4150
- function or2(...conditions) {
3406
+ function or(...conditions) {
4151
3407
  return { OR: conditions.map(normalize) };
4152
3408
  }
4153
- function not2(condition) {
3409
+ function not(condition) {
4154
3410
  const c = normalize(condition);
4155
3411
  if (c.type === "expression" && c.expression) {
4156
3412
  return { type: "expression", expression: `NOT(${c.expression})` };
@@ -4195,7 +3451,7 @@ function refHasAnyRole(slug, lookupField, lookupValue, roles) {
4195
3451
  }
4196
3452
 
4197
3453
  // src/hooks/useModel.ts
4198
- import { useCallback as useCallback19, useRef as useRef23, useMemo as useMemo15 } from "react";
3454
+ import { useCallback as useCallback20, useRef as useRef24, useMemo as useMemo16 } from "react";
4199
3455
  function getDefaultFields(definition) {
4200
3456
  const defaults = {};
4201
3457
  for (const [key, field2] of Object.entries(definition.fields)) {
@@ -4250,18 +3506,18 @@ function useModel(definition, options = {}) {
4250
3506
  if (options.state) queryParams.state = options.state;
4251
3507
  const query = useQuery(slug, queryParams);
4252
3508
  const mutation = useMutation(slug);
4253
- const instance = query.data?.[0];
4254
- const instanceId = instance?.id ?? null;
4255
- const currentState = instance?.currentState ?? "";
4256
- const instanceFields = instance?.fields ?? null;
4257
- const defaultFields = useMemo15(() => getDefaultFields(definition), [definition]);
4258
- const fields = useMemo15(() => {
3509
+ const instance2 = query.data?.[0];
3510
+ const instanceId = instance2?.id ?? null;
3511
+ const currentState = instance2?.currentState ?? "";
3512
+ const instanceFields = instance2?.fields ?? null;
3513
+ const defaultFields = useMemo16(() => getDefaultFields(definition), [definition]);
3514
+ const fields = useMemo16(() => {
4259
3515
  if (!instanceFields) return defaultFields;
4260
3516
  return { ...defaultFields, ...instanceFields };
4261
3517
  }, [instanceFields, defaultFields]);
4262
- const instanceIdRef = useRef23(instanceId);
3518
+ const instanceIdRef = useRef24(instanceId);
4263
3519
  instanceIdRef.current = instanceId;
4264
- const trigger = useCallback19(async (name, input) => {
3520
+ const trigger = useCallback20(async (name, input) => {
4265
3521
  const id = instanceIdRef.current;
4266
3522
  if (!id) {
4267
3523
  throw new Error(`useModel(${slug}): No instance loaded. Cannot trigger '${name}'.`);
@@ -4269,12 +3525,12 @@ function useModel(definition, options = {}) {
4269
3525
  await mutation.transition(id, name, input);
4270
3526
  await query.refetch();
4271
3527
  }, [slug, mutation, query]);
4272
- const create = useCallback19(async (input) => {
3528
+ const create = useCallback20(async (input) => {
4273
3529
  const id = await mutation.create(input);
4274
3530
  await query.refetch();
4275
3531
  return id;
4276
3532
  }, [mutation, query]);
4277
- const update = useCallback19(async (fieldUpdates) => {
3533
+ const update = useCallback20(async (fieldUpdates) => {
4278
3534
  const id = instanceIdRef.current;
4279
3535
  if (!id) {
4280
3536
  throw new Error(`useModel(${slug}): No instance loaded. Cannot update.`);
@@ -4303,27 +3559,27 @@ function useCollection(definition, options = {}) {
4303
3559
  const slug = definition.slug;
4304
3560
  const query = useQuery(slug, options);
4305
3561
  const mutation = useMutation(slug);
4306
- const items = useMemo15(() => {
4307
- return (query.data || []).map((instance) => ({
4308
- id: instance.id,
4309
- fields: instance.fields ?? {},
4310
- state: instance.currentState ?? ""
3562
+ const items = useMemo16(() => {
3563
+ return (query.data || []).map((instance2) => ({
3564
+ id: instance2.id,
3565
+ fields: instance2.fields ?? {},
3566
+ state: instance2.currentState ?? ""
4311
3567
  }));
4312
3568
  }, [query.data]);
4313
- const trigger = useCallback19(async (instanceId, name, input) => {
3569
+ const trigger = useCallback20(async (instanceId, name, input) => {
4314
3570
  await mutation.transition(instanceId, name, input);
4315
3571
  await query.refetch();
4316
3572
  }, [mutation, query]);
4317
- const create = useCallback19(async (input) => {
3573
+ const create = useCallback20(async (input) => {
4318
3574
  const id = await mutation.create(input);
4319
3575
  await query.refetch();
4320
3576
  return id;
4321
3577
  }, [mutation, query]);
4322
- const update = useCallback19(async (instanceId, fieldUpdates) => {
3578
+ const update = useCallback20(async (instanceId, fieldUpdates) => {
4323
3579
  await mutation.update(instanceId, fieldUpdates);
4324
3580
  await query.refetch();
4325
3581
  }, [mutation, query]);
4326
- const remove = useCallback19(async (instanceId) => {
3582
+ const remove = useCallback20(async (instanceId) => {
4327
3583
  await mutation.remove(instanceId);
4328
3584
  await query.refetch();
4329
3585
  }, [mutation, query]);
@@ -4347,7 +3603,7 @@ function useCollection(definition, options = {}) {
4347
3603
  function stub(displayName) {
4348
3604
  const Component = () => {
4349
3605
  throw new Error(
4350
- `<${displayName}> is a compile-time stub from @mindmatrix/react/atoms. It should only appear in .workflow.tsx files processed by the compiler. At runtime, use the ComponentTreeRenderer which resolves "${displayName}" from the component registry.`
3606
+ `<${displayName}> is a compile-time stub from @mmapp/react/atoms. It should only appear in .workflow.tsx files processed by the compiler. At runtime, use the ComponentTreeRenderer which resolves "${displayName}" from the component registry.`
4351
3607
  );
4352
3608
  };
4353
3609
  Component.displayName = displayName;
@@ -4474,7 +3730,7 @@ function djb2Hash(str) {
4474
3730
  }
4475
3731
 
4476
3732
  // src/authoring.ts
4477
- function useState20(_defaultOrKey) {
3733
+ function useState21(_defaultOrKey) {
4478
3734
  return [void 0, () => {
4479
3735
  }];
4480
3736
  }
@@ -4485,10 +3741,10 @@ function defineWorkspace(config) {
4485
3741
  }
4486
3742
 
4487
3743
  // src/hooks/useModule.ts
4488
- import { useMemo as useMemo16 } from "react";
3744
+ import { useMemo as useMemo17 } from "react";
4489
3745
  function useModule(slug, config = {}, options = {}) {
4490
3746
  const { enabled = true } = options;
4491
- return useMemo16(() => ({
3747
+ return useMemo17(() => ({
4492
3748
  slug,
4493
3749
  config,
4494
3750
  isLoaded: enabled
@@ -4496,7 +3752,7 @@ function useModule(slug, config = {}, options = {}) {
4496
3752
  }
4497
3753
 
4498
3754
  // src/hooks/useModuleConfig.ts
4499
- import { useMemo as useMemo17 } from "react";
3755
+ import { useCallback as useCallback21, useMemo as useMemo18, useState as useState22 } from "react";
4500
3756
  var installedModulesStore = [];
4501
3757
  var configDefaultsStore = /* @__PURE__ */ new Map();
4502
3758
  function setInstalledModules(modules) {
@@ -4512,12 +3768,65 @@ function getInstalledModules() {
4512
3768
  return installedModulesStore;
4513
3769
  }
4514
3770
  function useModuleConfig(moduleSlug) {
4515
- return useMemo17(() => {
3771
+ return useMemo18(() => {
4516
3772
  const installed = getInstalledModule(moduleSlug);
4517
3773
  const defaults = configDefaultsStore.get(moduleSlug) ?? {};
4518
- return { ...defaults, ...installed?.config };
3774
+ const persisted = persistedConfigStore.get(moduleSlug) ?? {};
3775
+ return { ...defaults, ...persisted, ...installed?.config };
4519
3776
  }, [moduleSlug]);
4520
3777
  }
3778
+ var persistedConfigStore = /* @__PURE__ */ new Map();
3779
+ function setPersistedModuleConfig(moduleSlug, config) {
3780
+ persistedConfigStore.set(moduleSlug, config);
3781
+ }
3782
+ async function syncConfigDefaults(moduleSlug, defaults, definitionId) {
3783
+ const id = definitionId ?? activeDefinitionIdStore;
3784
+ if (!id) return;
3785
+ try {
3786
+ const moduleKey = `module_config.${moduleSlug}`;
3787
+ await updateDefinitionConfig({ [moduleKey]: defaults }, id);
3788
+ persistedConfigStore.set(moduleSlug, defaults);
3789
+ } catch (e) {
3790
+ console.warn(`[useModuleConfig] Failed to sync config for ${moduleSlug}:`, e);
3791
+ }
3792
+ }
3793
+ var activeDefinitionIdStore = null;
3794
+ var apiBaseUrlStore = "/api/v1/workflow";
3795
+ function setConfigContext(definitionId, apiBaseUrl) {
3796
+ activeDefinitionIdStore = definitionId;
3797
+ if (apiBaseUrl) apiBaseUrlStore = apiBaseUrl;
3798
+ }
3799
+ async function updateDefinitionConfig(values, definitionId) {
3800
+ const id = definitionId ?? activeDefinitionIdStore;
3801
+ if (!id) throw new Error("No active definition ID. Call setConfigContext() first.");
3802
+ const token = typeof localStorage !== "undefined" ? localStorage.getItem("auth_token") : null;
3803
+ const response = await fetch(`${apiBaseUrlStore}/definitions/${id}/config`, {
3804
+ method: "PATCH",
3805
+ headers: {
3806
+ "Content-Type": "application/json",
3807
+ ...token ? { Authorization: `Bearer ${token}` } : {}
3808
+ },
3809
+ body: JSON.stringify(values)
3810
+ });
3811
+ if (!response.ok) {
3812
+ const err = await response.json().catch(() => ({ message: response.statusText }));
3813
+ throw new Error(err.message || `Failed to update config: ${response.status}`);
3814
+ }
3815
+ return response.json();
3816
+ }
3817
+ function useModuleConfigWithMutation(moduleSlug) {
3818
+ const config = useModuleConfig(moduleSlug);
3819
+ const [isSaving, setIsSaving] = useState22(false);
3820
+ const updateConfig = useCallback21(async (values) => {
3821
+ setIsSaving(true);
3822
+ try {
3823
+ return await updateDefinitionConfig(values);
3824
+ } finally {
3825
+ setIsSaving(false);
3826
+ }
3827
+ }, []);
3828
+ return { config, updateConfig, isSaving };
3829
+ }
4521
3830
 
4522
3831
  // src/builders.ts
4523
3832
  function handlerToAction(handler, qualifier) {
@@ -6021,7 +5330,7 @@ function approval(config = {}) {
6021
5330
  }
6022
5331
  function escalation(config) {
6023
5332
  const {
6024
- timeout,
5333
+ timeout: timeout2,
6025
5334
  notifyRole = "admin",
6026
5335
  fromState = "pending_approval",
6027
5336
  escalatedState = "escalated"
@@ -6033,7 +5342,7 @@ function escalation(config) {
6033
5342
  });
6034
5343
  if (def.states[fromState]) {
6035
5344
  def.states[fromState].timeout = {
6036
- duration: timeout,
5345
+ duration: timeout2,
6037
5346
  fallback: { transition: "escalate" }
6038
5347
  };
6039
5348
  }
@@ -6052,8 +5361,8 @@ function escalation(config) {
6052
5361
  from: fromState,
6053
5362
  to: escalatedState,
6054
5363
  auto: true,
6055
- description: `Auto-escalate after ${timeout}`,
6056
- actions: [logEvent("escalated", { timeout })]
5364
+ description: `Auto-escalate after ${timeout2}`,
5365
+ actions: [logEvent("escalated", { timeout: timeout2 })]
6057
5366
  }
6058
5367
  });
6059
5368
  return def;
@@ -6711,7 +6020,14 @@ function describeModel(def) {
6711
6020
  }
6712
6021
 
6713
6022
  // src/hooks/usePlayer.ts
6714
- import { useCallback as useCallback20, useEffect as useEffect21, useMemo as useMemo18, useRef as useRef24, useState as useState21 } from "react";
6023
+ import { useCallback as useCallback22, useEffect as useEffect22, useMemo as useMemo19, useRef as useRef25, useState as useState23 } from "react";
6024
+ import {
6025
+ StateMachine as StateMachine2,
6026
+ EventBus as EventBus2,
6027
+ ActionDispatcher as ActionDispatcher2,
6028
+ createEvaluator as createEvaluator2,
6029
+ WEB_FAILURE_POLICIES as WEB_FAILURE_POLICIES2
6030
+ } from "@mmapp/player-core";
6715
6031
 
6716
6032
  // src/logger.ts
6717
6033
  var debugEnabled = false;
@@ -6751,18 +6067,18 @@ function computePlayerState(sm) {
6751
6067
  };
6752
6068
  }
6753
6069
  function usePlayer(config) {
6754
- const configRef = useRef24(config);
6070
+ const configRef = useRef25(config);
6755
6071
  configRef.current = config;
6756
- useEffect21(() => {
6072
+ useEffect22(() => {
6757
6073
  if (config.debug) setPlayerDebug(true);
6758
6074
  }, [config.debug]);
6759
- const evaluator = useMemo18(() => {
6760
- return createEvaluator({
6075
+ const evaluator = useMemo19(() => {
6076
+ return createEvaluator2({
6761
6077
  functions: config.functions ?? [],
6762
- failurePolicy: WEB_FAILURE_POLICIES.EVENT_REACTION
6078
+ failurePolicy: WEB_FAILURE_POLICIES2.EVENT_REACTION
6763
6079
  });
6764
6080
  }, [config.definition.id]);
6765
- const engine = useMemo18(() => {
6081
+ const engine = useMemo19(() => {
6766
6082
  const actionHandlers = /* @__PURE__ */ new Map();
6767
6083
  if (config.actionHandlers) {
6768
6084
  for (const [type, handler] of Object.entries(config.actionHandlers)) {
@@ -6790,14 +6106,14 @@ function usePlayer(config) {
6790
6106
  });
6791
6107
  }
6792
6108
  });
6793
- const sm2 = new StateMachine(
6109
+ const sm2 = new StateMachine2(
6794
6110
  config.definition,
6795
6111
  config.initialData ?? {},
6796
6112
  { evaluator, actionHandlers }
6797
6113
  );
6798
6114
  smRef = sm2;
6799
- const eventBus2 = new EventBus();
6800
- const dispatcher = new ActionDispatcher();
6115
+ const eventBus2 = new EventBus2();
6116
+ const dispatcher = new ActionDispatcher2();
6801
6117
  dispatcher.register("set_field", (cfg) => {
6802
6118
  if (smRef && typeof cfg.field === "string") {
6803
6119
  smRef.setField(cfg.field, cfg.value);
@@ -6816,8 +6132,8 @@ function usePlayer(config) {
6816
6132
  return { sm: sm2, eventBus: eventBus2, dispatcher };
6817
6133
  }, [config.definition.id, evaluator]);
6818
6134
  const { sm, eventBus } = engine;
6819
- const [playerState, setPlayerState] = useState21(() => computePlayerState(sm));
6820
- useEffect21(() => {
6135
+ const [playerState, setPlayerState] = useState23(() => computePlayerState(sm));
6136
+ useEffect22(() => {
6821
6137
  const stateDef = sm.getCurrentStateDefinition();
6822
6138
  if (!stateDef?.on_event?.length) return;
6823
6139
  const unsubs = [];
@@ -6881,7 +6197,7 @@ function usePlayer(config) {
6881
6197
  for (const unsub of unsubs) unsub();
6882
6198
  };
6883
6199
  }, [sm, eventBus, evaluator, engine.dispatcher, playerState.currentState]);
6884
- useEffect21(() => {
6200
+ useEffect22(() => {
6885
6201
  const unsub = sm.on((event) => {
6886
6202
  if (event.type === "transition" || event.type === "state_enter") {
6887
6203
  setPlayerState(computePlayerState(sm));
@@ -6897,7 +6213,7 @@ function usePlayer(config) {
6897
6213
  });
6898
6214
  return unsub;
6899
6215
  }, [sm]);
6900
- const transition2 = useCallback20(
6216
+ const transition2 = useCallback22(
6901
6217
  async (name, data) => {
6902
6218
  playerLog({
6903
6219
  level: "info",
@@ -6924,20 +6240,20 @@ function usePlayer(config) {
6924
6240
  },
6925
6241
  [sm]
6926
6242
  );
6927
- const setField2 = useCallback20(
6243
+ const setField2 = useCallback22(
6928
6244
  (field2, value) => {
6929
6245
  sm.setField(field2, value);
6930
6246
  setPlayerState(computePlayerState(sm));
6931
6247
  },
6932
6248
  [sm]
6933
6249
  );
6934
- const setMemory = useCallback20(
6250
+ const setMemory = useCallback22(
6935
6251
  (key, value) => {
6936
6252
  sm.setMemory(key, value);
6937
6253
  },
6938
6254
  [sm]
6939
6255
  );
6940
- const publishEvent = useCallback20(
6256
+ const publishEvent = useCallback22(
6941
6257
  (topic, payload) => {
6942
6258
  playerLog({
6943
6259
  level: "debug",
@@ -6963,11 +6279,11 @@ function usePlayer(config) {
6963
6279
  }
6964
6280
 
6965
6281
  // src/hooks/useDomainSubscription.ts
6966
- import { useEffect as useEffect22, useRef as useRef25 } from "react";
6282
+ import { useEffect as useEffect23, useRef as useRef26 } from "react";
6967
6283
  function useDomainSubscription(eventBus, transport, config) {
6968
- const configRef = useRef25(config);
6284
+ const configRef = useRef26(config);
6969
6285
  configRef.current = config;
6970
- useEffect22(() => {
6286
+ useEffect23(() => {
6971
6287
  if (!transport || config.enabled === false) return;
6972
6288
  const unsub = transport.subscribe(
6973
6289
  {
@@ -7020,11 +6336,11 @@ function useDomainSubscription(eventBus, transport, config) {
7020
6336
  }
7021
6337
 
7022
6338
  // src/hooks/useExperienceState.ts
7023
- import { useCallback as useCallback21, useRef as useRef26 } from "react";
6339
+ import { useCallback as useCallback23, useRef as useRef27 } from "react";
7024
6340
  function useExperienceState(player, selector) {
7025
- const selectorRef = useRef26(selector);
6341
+ const selectorRef = useRef27(selector);
7026
6342
  selectorRef.current = selector;
7027
- const getSnapshot = useCallback21(() => {
6343
+ const getSnapshot = useCallback23(() => {
7028
6344
  return selectorRef.current({
7029
6345
  currentState: player.currentState,
7030
6346
  stateData: player.stateData,
@@ -7040,20 +6356,20 @@ function useStateField(player, field2, defaultValue) {
7040
6356
  }
7041
6357
 
7042
6358
  // src/hooks/useComputed.ts
7043
- import { useMemo as useMemo19, useRef as useRef27 } from "react";
6359
+ import { useMemo as useMemo20, useRef as useRef28 } from "react";
7044
6360
  function useComputed(_name, compute, options) {
7045
6361
  const mode = options?.mode ?? "read-time";
7046
6362
  const deps = options?.deps ?? [];
7047
- const computeRef = useRef27(compute);
6363
+ const computeRef = useRef28(compute);
7048
6364
  computeRef.current = compute;
7049
6365
  if (mode === "read-time") {
7050
- return useMemo19(() => computeRef.current(), [
6366
+ return useMemo20(() => computeRef.current(), [
7051
6367
  // We intentionally depend on deps.join to recompute when tracked fields change
7052
6368
  // The actual dependency tracking happens at the compiler level
7053
6369
  deps.join(",")
7054
6370
  ]);
7055
6371
  }
7056
- return useMemo19(() => computeRef.current(), [deps.join(",")]);
6372
+ return useMemo20(() => computeRef.current(), [deps.join(",")]);
7057
6373
  }
7058
6374
  function useComputedWithMeta(name, compute, options) {
7059
6375
  const value = useComputed(name, compute, options);
@@ -7086,7 +6402,7 @@ function usePlayerContextSafe() {
7086
6402
  }
7087
6403
 
7088
6404
  // src/components/ExperienceWorkflowBridge.tsx
7089
- import { useMemo as useMemo20 } from "react";
6405
+ import { useMemo as useMemo21 } from "react";
7090
6406
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
7091
6407
  function ExperienceWorkflowBridgeInner({
7092
6408
  definition,
@@ -7104,7 +6420,7 @@ function ExperienceWorkflowBridgeInner({
7104
6420
  actionHandlers,
7105
6421
  debug
7106
6422
  });
7107
- const viewConfig = useMemo20(() => {
6423
+ const viewConfig = useMemo21(() => {
7108
6424
  if (!definition.state_views) return void 0;
7109
6425
  return definition.state_views[player.currentState];
7110
6426
  }, [definition.state_views, player.currentState]);
@@ -7460,7 +6776,7 @@ var BrowserPlayer = class {
7460
6776
  this.ensureInitialized();
7461
6777
  const id = crypto.randomUUID();
7462
6778
  const now = (/* @__PURE__ */ new Date()).toISOString();
7463
- const instance = {
6779
+ const instance2 = {
7464
6780
  id,
7465
6781
  definitionId: options.definitionId ?? definitionSlug,
7466
6782
  definitionSlug,
@@ -7472,15 +6788,15 @@ var BrowserPlayer = class {
7472
6788
  createdAt: now,
7473
6789
  updatedAt: now
7474
6790
  };
7475
- await this.putInstance(instance);
6791
+ await this.putInstance(instance2);
7476
6792
  this.log("info", `Instance created: ${id} (${definitionSlug})`);
7477
6793
  this.emit({
7478
6794
  type: "instance:created",
7479
6795
  instanceId: id,
7480
- data: { definitionSlug, currentState: instance.currentState },
6796
+ data: { definitionSlug, currentState: instance2.currentState },
7481
6797
  timestamp: Date.now()
7482
6798
  });
7483
- return instance;
6799
+ return instance2;
7484
6800
  }
7485
6801
  /** Get an instance by ID. */
7486
6802
  async getInstance(id) {
@@ -7489,13 +6805,13 @@ var BrowserPlayer = class {
7489
6805
  }
7490
6806
  /** Get the current state of an instance. */
7491
6807
  async getState(id) {
7492
- const instance = await this.getInstance(id);
7493
- if (!instance) return null;
6808
+ const instance2 = await this.getInstance(id);
6809
+ if (!instance2) return null;
7494
6810
  return {
7495
- currentState: instance.currentState,
7496
- status: instance.status,
7497
- stateData: instance.stateData,
7498
- lockVersion: instance.lockVersion
6811
+ currentState: instance2.currentState,
6812
+ status: instance2.status,
6813
+ stateData: instance2.stateData,
6814
+ lockVersion: instance2.lockVersion
7499
6815
  };
7500
6816
  }
7501
6817
  /**
@@ -7506,34 +6822,34 @@ var BrowserPlayer = class {
7506
6822
  */
7507
6823
  async transition(instanceId, transitionName, data = {}) {
7508
6824
  this.ensureInitialized();
7509
- const instance = await this.getInstanceFromDb(instanceId);
7510
- if (!instance) {
6825
+ const instance2 = await this.getInstanceFromDb(instanceId);
6826
+ if (!instance2) {
7511
6827
  return {
7512
6828
  success: false,
7513
6829
  instance: null,
7514
6830
  error: `Instance ${instanceId} not found`
7515
6831
  };
7516
6832
  }
7517
- if (instance.status !== "ACTIVE") {
6833
+ if (instance2.status !== "ACTIVE") {
7518
6834
  return {
7519
6835
  success: false,
7520
- instance,
7521
- error: `Instance is ${instance.status}, cannot transition`
6836
+ instance: instance2,
6837
+ error: `Instance is ${instance2.status}, cannot transition`
7522
6838
  };
7523
6839
  }
7524
6840
  try {
7525
- const newStateData = { ...instance.stateData, ...data };
7526
- const newLockVersion = instance.lockVersion + 1;
6841
+ const newStateData = { ...instance2.stateData, ...data };
6842
+ const newLockVersion = instance2.lockVersion + 1;
7527
6843
  if (this.wasm.execute_transition) {
7528
6844
  const request = {
7529
6845
  instance: {
7530
- id: instance.id,
7531
- definition_id: instance.definitionId,
7532
- current_state: instance.currentState,
7533
- status: instance.status,
6846
+ id: instance2.id,
6847
+ definition_id: instance2.definitionId,
6848
+ current_state: instance2.currentState,
6849
+ status: instance2.status,
7534
6850
  state_data: newStateData,
7535
- memory: instance.memory,
7536
- execution_lock_version: instance.lockVersion
6851
+ memory: instance2.memory,
6852
+ execution_lock_version: instance2.lockVersion
7537
6853
  },
7538
6854
  transition_name: transitionName,
7539
6855
  actor_id: this.peerId,
@@ -7542,26 +6858,26 @@ var BrowserPlayer = class {
7542
6858
  const resultJson = this.wasm.execute_transition(JSON.stringify(request));
7543
6859
  const result = JSON.parse(resultJson);
7544
6860
  if (result.success === false || result.error) {
7545
- return { success: false, instance, error: result.error ?? "Transition failed" };
6861
+ return { success: false, instance: instance2, error: result.error ?? "Transition failed" };
7546
6862
  }
7547
- instance.currentState = result.to_state ?? instance.currentState;
7548
- instance.status = result.status ?? instance.status;
7549
- instance.stateData = result.state_data ?? newStateData;
7550
- instance.memory = result.memory ?? instance.memory;
6863
+ instance2.currentState = result.to_state ?? instance2.currentState;
6864
+ instance2.status = result.status ?? instance2.status;
6865
+ instance2.stateData = result.state_data ?? newStateData;
6866
+ instance2.memory = result.memory ?? instance2.memory;
7551
6867
  } else {
7552
- instance.stateData = newStateData;
6868
+ instance2.stateData = newStateData;
7553
6869
  }
7554
- instance.lockVersion = newLockVersion;
7555
- instance.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
7556
- await this.putInstance(instance);
6870
+ instance2.lockVersion = newLockVersion;
6871
+ instance2.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
6872
+ await this.putInstance(instance2);
7557
6873
  this.log("info", `Transition: ${instanceId} ${transitionName}`);
7558
6874
  this.emit({
7559
6875
  type: "instance:transition",
7560
6876
  instanceId,
7561
6877
  data: {
7562
6878
  transitionName,
7563
- fromState: instance.currentState,
7564
- toState: instance.currentState,
6879
+ fromState: instance2.currentState,
6880
+ toState: instance2.currentState,
7565
6881
  lockVersion: newLockVersion
7566
6882
  },
7567
6883
  timestamp: Date.now()
@@ -7571,7 +6887,7 @@ var BrowserPlayer = class {
7571
6887
  type: "TransitionReplication",
7572
6888
  instance_id: instanceId,
7573
6889
  transition_name: transitionName,
7574
- state_data: instance.stateData,
6890
+ state_data: instance2.stateData,
7575
6891
  lock_version: newLockVersion
7576
6892
  });
7577
6893
  const envelope = this.wasm.sign_envelope(this.secretKeyHex, payload);
@@ -7581,11 +6897,11 @@ var BrowserPlayer = class {
7581
6897
  envelope
7582
6898
  }));
7583
6899
  }
7584
- return { success: true, instance };
6900
+ return { success: true, instance: instance2 };
7585
6901
  } catch (err) {
7586
6902
  const error = err instanceof Error ? err.message : String(err);
7587
6903
  this.log("error", `Transition failed: ${error}`);
7588
- return { success: false, instance, error };
6904
+ return { success: false, instance: instance2, error };
7589
6905
  }
7590
6906
  }
7591
6907
  // ─── Subscriptions ──────────────────────────────────────────────────
@@ -7665,12 +6981,12 @@ var BrowserPlayer = class {
7665
6981
  request.onerror = () => reject(request.error);
7666
6982
  });
7667
6983
  }
7668
- async putInstance(instance) {
6984
+ async putInstance(instance2) {
7669
6985
  if (!this.db) return;
7670
6986
  return new Promise((resolve, reject) => {
7671
6987
  const tx = this.db.transaction(INSTANCE_STORE_NAME, "readwrite");
7672
6988
  const store = tx.objectStore(INSTANCE_STORE_NAME);
7673
- store.put(instance);
6989
+ store.put(instance2);
7674
6990
  tx.oncomplete = () => resolve();
7675
6991
  tx.onerror = () => reject(tx.error);
7676
6992
  });
@@ -7817,9 +7133,381 @@ var BrowserPlayer = class {
7817
7133
  }
7818
7134
  }
7819
7135
  };
7136
+
7137
+ // src/middleware-def.ts
7138
+ function defineMiddleware(def) {
7139
+ if (process.env.NODE_ENV !== "production") {
7140
+ if (!def.name || typeof def.name !== "string") {
7141
+ throw new Error("defineMiddleware: name is required and must be a string");
7142
+ }
7143
+ if (!def.match) {
7144
+ throw new Error("defineMiddleware: match pattern is required");
7145
+ }
7146
+ const patterns = Array.isArray(def.match) ? def.match : [def.match];
7147
+ for (const p of patterns) {
7148
+ if (typeof p !== "string") {
7149
+ throw new Error(`defineMiddleware: match pattern must be a string, got ${typeof p}`);
7150
+ }
7151
+ }
7152
+ if (def.priority !== void 0 && typeof def.priority !== "number") {
7153
+ throw new Error("defineMiddleware: priority must be a number");
7154
+ }
7155
+ if (!def.before && !def.after && !def.around) {
7156
+ throw new Error("defineMiddleware: at least one of before, after, or around must be provided");
7157
+ }
7158
+ }
7159
+ return def;
7160
+ }
7161
+ function extendMiddleware(base, overrides) {
7162
+ let introduce;
7163
+ if (base.introduce || overrides.introduce) {
7164
+ introduce = {
7165
+ fields: { ...base.introduce?.fields, ...overrides.introduce?.fields },
7166
+ states: { ...base.introduce?.states, ...overrides.introduce?.states },
7167
+ transitions: { ...base.introduce?.transitions, ...overrides.introduce?.transitions }
7168
+ };
7169
+ if (introduce.fields && Object.keys(introduce.fields).length === 0) introduce.fields = void 0;
7170
+ if (introduce.states && Object.keys(introduce.states).length === 0) introduce.states = void 0;
7171
+ if (introduce.transitions && Object.keys(introduce.transitions).length === 0) introduce.transitions = void 0;
7172
+ }
7173
+ const merged = {
7174
+ ...base,
7175
+ ...overrides,
7176
+ // Config is merged (overrides win per-key)
7177
+ config: base.config || overrides.config ? { ...base.config, ...overrides.config } : void 0
7178
+ };
7179
+ if (introduce) {
7180
+ merged.introduce = introduce;
7181
+ }
7182
+ if (process.env.NODE_ENV !== "production") {
7183
+ if (!merged.name || typeof merged.name !== "string") {
7184
+ throw new Error("extendMiddleware: resulting middleware must have a name");
7185
+ }
7186
+ if (!merged.match) {
7187
+ throw new Error("extendMiddleware: resulting middleware must have a match pattern");
7188
+ }
7189
+ if (!merged.before && !merged.after && !merged.around) {
7190
+ throw new Error("extendMiddleware: resulting middleware must have at least one of before, after, or around");
7191
+ }
7192
+ }
7193
+ return merged;
7194
+ }
7195
+ function withAuth(opts) {
7196
+ const _redirectTo = opts?.redirectTo;
7197
+ return {
7198
+ name: "mm:auth",
7199
+ match: "*:*:transition.execute",
7200
+ priority: 90,
7201
+ before(ctx) {
7202
+ if (!ctx.actor.id) {
7203
+ ctx.block(_redirectTo ? `redirect:${_redirectTo}` : "Authentication required");
7204
+ }
7205
+ }
7206
+ };
7207
+ }
7208
+ function withAuditLog(opts) {
7209
+ const _level = opts?.level ?? "info";
7210
+ return {
7211
+ name: "mm:audit-log",
7212
+ match: "*:*:transition.execute",
7213
+ priority: 0,
7214
+ after(ctx) {
7215
+ ctx.modify({
7216
+ __audit: {
7217
+ level: _level,
7218
+ actor: ctx.actor.id,
7219
+ transition: ctx.transition?.name,
7220
+ from: ctx.transition?.from,
7221
+ to: ctx.transition?.to,
7222
+ timestamp: ctx.timestamp
7223
+ }
7224
+ });
7225
+ }
7226
+ };
7227
+ }
7228
+ function withRateLimit(opts) {
7229
+ const _max = opts?.maxPerMinute ?? 60;
7230
+ return {
7231
+ name: "mm:rate-limit",
7232
+ match: "*:*:transition.execute",
7233
+ priority: 80,
7234
+ config: {
7235
+ maxPerMinute: { type: "number", default: _max }
7236
+ },
7237
+ before(ctx) {
7238
+ const fields = ctx.instance.fields;
7239
+ const counter = fields.__rateCounter || 0;
7240
+ if (counter >= _max) {
7241
+ ctx.block(`Rate limit exceeded: ${_max} per minute`);
7242
+ }
7243
+ }
7244
+ };
7245
+ }
7246
+ function withValidation(opts) {
7247
+ const _rules = opts?.rules ?? [];
7248
+ return {
7249
+ name: "mm:validation",
7250
+ match: "*:*:field.change",
7251
+ priority: 70,
7252
+ config: {
7253
+ rules: { type: "json", default: _rules }
7254
+ },
7255
+ before(ctx) {
7256
+ if (!ctx.field) return;
7257
+ for (const rule of _rules) {
7258
+ if (rule.fields.includes(ctx.field.name)) {
7259
+ ctx.block(rule.message);
7260
+ }
7261
+ }
7262
+ }
7263
+ };
7264
+ }
7265
+ function withMetrics(opts) {
7266
+ const _endpoint = opts?.endpoint;
7267
+ return {
7268
+ name: "mm:metrics",
7269
+ match: "*:*:*",
7270
+ priority: 100,
7271
+ config: {
7272
+ endpoint: { type: "string", default: _endpoint }
7273
+ },
7274
+ async around(ctx, next) {
7275
+ const start = ctx.timestamp;
7276
+ await next();
7277
+ const duration = Date.now() - start;
7278
+ ctx.modify({
7279
+ __metrics: {
7280
+ duration,
7281
+ endpoint: _endpoint,
7282
+ actor: ctx.actor.id
7283
+ }
7284
+ });
7285
+ }
7286
+ };
7287
+ }
7288
+
7289
+ // src/actor.ts
7290
+ function compileTimeOnly(name) {
7291
+ throw new Error(
7292
+ `${name}() is a compile-time function and cannot be called at runtime. Use \`mmrc build\` to compile your workflow.`
7293
+ );
7294
+ }
7295
+ var DEFAULT_SUPERVISION = {
7296
+ strategy: "escalate"
7297
+ };
7298
+ var DEFAULT_MAILBOX = {
7299
+ capacity: 1e3,
7300
+ overflow: "error",
7301
+ priority: "fifo"
7302
+ };
7303
+ function configureActor(config) {
7304
+ void config;
7305
+ return {
7306
+ __actor: true,
7307
+ supervision: config.supervision ?? DEFAULT_SUPERVISION,
7308
+ mailbox: config.mailbox ?? DEFAULT_MAILBOX,
7309
+ hierarchy: config.hierarchy ?? {}
7310
+ };
7311
+ }
7312
+ function spawnActor(_slug, _options) {
7313
+ compileTimeOnly("spawnActor");
7314
+ }
7315
+ function sendMessage(_instanceId, _action, _payload) {
7316
+ compileTimeOnly("sendMessage");
7317
+ }
7318
+ function isActorConfig(value) {
7319
+ return typeof value === "object" && value !== null && value.__actor === true;
7320
+ }
7321
+
7322
+ // src/constraints.ts
7323
+ var BUILT_IN_CONSTRAINTS = /* @__PURE__ */ new Set([
7324
+ "every state is reachable",
7325
+ "no deadlocks",
7326
+ "no unreachable states",
7327
+ "deterministic guards",
7328
+ "terminates",
7329
+ "no guard overlaps",
7330
+ "all roles defined",
7331
+ "all fields validated"
7332
+ ]);
7333
+ function constraints(...rules) {
7334
+ if (process.env.NODE_ENV !== "production") {
7335
+ if (rules.length === 0) {
7336
+ throw new Error("constraints(): at least one constraint rule is required");
7337
+ }
7338
+ for (let i = 0; i < rules.length; i++) {
7339
+ const rule = rules[i];
7340
+ if (typeof rule !== "string" || rule.trim() === "") {
7341
+ throw new Error(
7342
+ `constraints(): rule at index ${i} must be a non-empty string, got ${typeof rule}`
7343
+ );
7344
+ }
7345
+ }
7346
+ }
7347
+ return {
7348
+ __constraints: true,
7349
+ rules: Object.freeze([...rules])
7350
+ };
7351
+ }
7352
+ function isConstraintDeclaration(value) {
7353
+ return typeof value === "object" && value !== null && value.__constraints === true && Array.isArray(value.rules);
7354
+ }
7355
+ function isBuiltInConstraint(rule) {
7356
+ return BUILT_IN_CONSTRAINTS.has(rule);
7357
+ }
7358
+
7359
+ // src/extend.ts
7360
+ function extend(base, options) {
7361
+ const _metadata = {
7362
+ __extend: true,
7363
+ base,
7364
+ options
7365
+ };
7366
+ throw new Error(
7367
+ `extend() is a compile-time declaration and cannot be called at runtime. Ensure your build pipeline includes the @mmapp/react-compiler Babel plugin or compile your workflow files with \`mmrc build\` before execution.
7368
+
7369
+ Base workflow: ${base?.name ?? "(anonymous)"}
7370
+ Derived slug: ${options.slug ?? "(not specified)"}`
7371
+ );
7372
+ return _metadata;
7373
+ }
7374
+
7375
+ // src/compose.ts
7376
+ function compose(workflow, ...mixins) {
7377
+ for (let i = 0; i < mixins.length; i++) {
7378
+ const mixin = mixins[i];
7379
+ if (!mixin || mixin.__mixin !== true) {
7380
+ throw new Error(
7381
+ `compose() argument ${i + 2} is not a valid WorkflowMixin. Each mixin must be created by a mixin factory (e.g. withAuditTrail(), withSoftDelete()). Received: ${typeof mixin === "object" ? JSON.stringify(mixin) : String(mixin)}`
7382
+ );
7383
+ }
7384
+ }
7385
+ const metadata = {
7386
+ __composed: true,
7387
+ workflow,
7388
+ mixins: Object.freeze([...mixins])
7389
+ };
7390
+ const composed = (async (...args) => {
7391
+ return workflow(...args);
7392
+ });
7393
+ Object.defineProperty(composed, "__composed", {
7394
+ value: metadata,
7395
+ writable: false,
7396
+ enumerable: false,
7397
+ configurable: false
7398
+ });
7399
+ Object.defineProperty(composed, "name", {
7400
+ value: `composed(${workflow.name || "anonymous"})`,
7401
+ writable: false,
7402
+ configurable: true
7403
+ });
7404
+ return composed;
7405
+ }
7406
+
7407
+ // src/imperative.ts
7408
+ function compileTimeOnly2(name) {
7409
+ throw new Error(
7410
+ `${name}() is a compile-time function and cannot be called at runtime. Use \`mmrc build\` to compile your workflow.`
7411
+ );
7412
+ }
7413
+ function compileTimeProxy(label) {
7414
+ return new Proxy(
7415
+ {},
7416
+ {
7417
+ get(_target, prop) {
7418
+ throw new Error(
7419
+ `Cannot access \`${label}.${String(prop)}\` at runtime. \`${label}\` is a compile-time constant. Use \`mmrc build\` to compile your workflow.`
7420
+ );
7421
+ }
7422
+ }
7423
+ );
7424
+ }
7425
+ function validate(_condition, _message, _severity) {
7426
+ compileTimeOnly2("validate");
7427
+ }
7428
+ function log(_event, _data) {
7429
+ compileTimeOnly2("log");
7430
+ }
7431
+ function notify2(_to, _message, _opts) {
7432
+ compileTimeOnly2("notify");
7433
+ }
7434
+ function emit(_event, _payload) {
7435
+ compileTimeOnly2("emit");
7436
+ }
7437
+ function requireRole2(..._roles) {
7438
+ compileTimeOnly2("requireRole");
7439
+ }
7440
+ function requireField(..._fields) {
7441
+ compileTimeOnly2("requireField");
7442
+ }
7443
+ function guard(_expression) {
7444
+ compileTimeOnly2("guard");
7445
+ }
7446
+ function every(_interval, _fn) {
7447
+ compileTimeOnly2("every");
7448
+ }
7449
+ function cron2(_expression, _fn) {
7450
+ compileTimeOnly2("cron");
7451
+ }
7452
+ function after(_delay, _fn) {
7453
+ compileTimeOnly2("after");
7454
+ }
7455
+ function on(_pattern, _handlerOrOpts) {
7456
+ compileTimeOnly2("on");
7457
+ }
7458
+ function timeout(_duration, _handler) {
7459
+ compileTimeOnly2("timeout");
7460
+ }
7461
+ function userAction(_name, _opts) {
7462
+ compileTimeOnly2("userAction");
7463
+ }
7464
+ function userChoice(_options) {
7465
+ compileTimeOnly2("userChoice");
7466
+ }
7467
+ function named(_name, _stateCall) {
7468
+ compileTimeOnly2("named");
7469
+ }
7470
+ function delay(_duration) {
7471
+ compileTimeOnly2("delay");
7472
+ }
7473
+ function allowTransition(_name, _opts) {
7474
+ compileTimeOnly2("allowTransition");
7475
+ }
7476
+ function restrict(_field, _opts) {
7477
+ compileTimeOnly2("restrict");
7478
+ }
7479
+ function visibleTo(..._roles) {
7480
+ compileTimeOnly2("visibleTo");
7481
+ }
7482
+ function editableBy(..._roles) {
7483
+ compileTimeOnly2("editableBy");
7484
+ }
7485
+ function editableIn(..._states) {
7486
+ compileTimeOnly2("editableIn");
7487
+ }
7488
+ function defineRoles(roles) {
7489
+ void roles;
7490
+ compileTimeOnly2("defineRoles");
7491
+ }
7492
+ function runtime(_target) {
7493
+ compileTimeOnly2("runtime");
7494
+ }
7495
+ function orchestration(config) {
7496
+ void config;
7497
+ compileTimeOnly2("orchestration");
7498
+ }
7499
+ function blueprint(_slug, _config) {
7500
+ compileTimeOnly2("blueprint");
7501
+ }
7502
+ function patch(_id, _overrides) {
7503
+ compileTimeOnly2("patch");
7504
+ }
7505
+ var actor = compileTimeProxy("actor");
7506
+ var instance = compileTimeProxy("instance");
7820
7507
  export {
7821
7508
  Accordion,
7822
7509
  AnimatedBox,
7510
+ BUILT_IN_CONSTRAINTS,
7823
7511
  Badge,
7824
7512
  Blueprint,
7825
7513
  BrowserPlayer,
@@ -7846,6 +7534,7 @@ export {
7846
7534
  Modal,
7847
7535
  ModelBuilder,
7848
7536
  NavLink,
7537
+ ORCHESTRATION_PRESETS,
7849
7538
  PlayerProvider,
7850
7539
  RoleGuard,
7851
7540
  Route,
@@ -7869,12 +7558,19 @@ export {
7869
7558
  WorkflowProvider,
7870
7559
  WorkflowRuntime,
7871
7560
  action,
7872
- and2 as and,
7561
+ actor,
7562
+ after,
7563
+ allowTransition,
7564
+ and,
7873
7565
  applyMixins,
7874
7566
  approval,
7875
7567
  assertModelValid,
7876
7568
  cedar,
7569
+ compose,
7570
+ computeVisibility,
7571
+ configureActor,
7877
7572
  connector,
7573
+ constraints,
7878
7574
  createActions,
7879
7575
  createCRUD,
7880
7576
  createLocalDataResolver,
@@ -7883,16 +7579,26 @@ export {
7883
7579
  cron,
7884
7580
  crud,
7885
7581
  defineBlueprint,
7582
+ blueprint as defineImperativeBlueprint,
7583
+ defineMiddleware,
7886
7584
  defineModel,
7887
7585
  defineModule,
7586
+ defineRoles,
7888
7587
  defineWorkspace,
7588
+ delay,
7889
7589
  deriveInstanceKey,
7890
7590
  deriveInstanceKeySync,
7891
7591
  describeModel,
7892
7592
  deviceAction,
7893
7593
  dmn,
7594
+ editableBy,
7595
+ editableIn,
7596
+ emit,
7894
7597
  escalation,
7598
+ every,
7895
7599
  expr,
7600
+ extend,
7601
+ extendMiddleware,
7896
7602
  field,
7897
7603
  fieldContains,
7898
7604
  fieldEquals,
@@ -7907,12 +7613,21 @@ export {
7907
7613
  getInstalledModule,
7908
7614
  getInstalledModules,
7909
7615
  graphql,
7616
+ guard,
7910
7617
  hasAnyRole,
7911
7618
  hasRole,
7619
+ cron2 as imperativeCron,
7620
+ log as imperativeLog,
7621
+ notify2 as imperativeNotify,
7622
+ requireRole2 as imperativeRequireRole,
7912
7623
  inState,
7913
7624
  inputEquals,
7914
7625
  inputRequired,
7626
+ instance,
7915
7627
  isActor,
7628
+ isActorConfig,
7629
+ isBuiltInConstraint,
7630
+ isConstraintDeclaration,
7916
7631
  isCreator,
7917
7632
  isOwner,
7918
7633
  isPlayerDebug,
@@ -7922,28 +7637,39 @@ export {
7922
7637
  loadExperienceWorkflow,
7923
7638
  logEvent,
7924
7639
  model,
7640
+ named,
7925
7641
  normalizeDefinition,
7926
- not2 as not,
7642
+ not,
7927
7643
  notInState,
7928
7644
  notify,
7929
- or2 as or,
7645
+ on,
7646
+ or,
7647
+ orchestration,
7648
+ patch,
7930
7649
  pipe,
7931
7650
  playerLog,
7932
7651
  prefetchData,
7933
7652
  refHasAnyRole,
7934
7653
  refHasRole,
7935
7654
  requireAuth,
7655
+ requireField,
7936
7656
  requireRole,
7657
+ resolveOrchestration,
7658
+ restrict,
7937
7659
  review,
7660
+ runtime,
7661
+ sendMessage,
7938
7662
  serverAction,
7939
7663
  setAuthResolver,
7940
7664
  setChannelTransport,
7665
+ setConfigContext,
7941
7666
  setExpressionLibraryResolver,
7942
7667
  setField,
7943
7668
  setFields,
7944
7669
  setInstalledModules,
7945
7670
  setModuleConfigDefaults,
7946
7671
  setMutationResolver,
7672
+ setPersistedModuleConfig,
7947
7673
  setPlayerDebug,
7948
7674
  setQueryResolver,
7949
7675
  setRealtimeQueryResolver,
@@ -7952,10 +7678,14 @@ export {
7952
7678
  setServerStateResolver,
7953
7679
  setViewResolver,
7954
7680
  spawn,
7681
+ spawnActor,
7955
7682
  sql,
7956
7683
  state,
7684
+ syncConfigDefaults,
7957
7685
  testModel,
7686
+ timeout,
7958
7687
  transition,
7688
+ updateDefinitionConfig,
7959
7689
  useAuth,
7960
7690
  useChannel,
7961
7691
  useCollection,
@@ -7973,6 +7703,7 @@ export {
7973
7703
  useModel,
7974
7704
  useModule,
7975
7705
  useModuleConfig,
7706
+ useModuleConfigWithMutation,
7976
7707
  useMutation,
7977
7708
  useNotification,
7978
7709
  useOnChange,
@@ -7985,6 +7716,7 @@ export {
7985
7716
  usePlayer,
7986
7717
  usePlayerContext,
7987
7718
  usePlayerContextSafe,
7719
+ usePresence,
7988
7720
  useQuery,
7989
7721
  useRealtimeQuery,
7990
7722
  useRole,
@@ -7997,20 +7729,30 @@ export {
7997
7729
  useToast,
7998
7730
  useTransition,
7999
7731
  useView,
7732
+ useVisibility,
8000
7733
  useWhileIn,
8001
7734
  useWorkflow,
8002
- useState20 as useWorkflowState,
7735
+ useState21 as useWorkflowState,
7736
+ userAction,
7737
+ userChoice,
7738
+ validate,
8003
7739
  validateExperienceWorkflow,
8004
7740
  validateModel,
7741
+ visibleTo,
8005
7742
  when,
7743
+ withAuditLog,
8006
7744
  withAuditTrail,
7745
+ withAuth,
7746
+ withMetrics,
8007
7747
  withOwnership,
8008
7748
  withPagination,
8009
7749
  withRBAC,
7750
+ withRateLimit,
8010
7751
  withSearch,
8011
7752
  withSlug,
8012
7753
  withSoftDelete,
8013
7754
  withTags,
8014
7755
  withTimestamps,
7756
+ withValidation,
8015
7757
  withVersioning
8016
7758
  };