@mmapp/react 0.1.0-alpha.1 → 0.1.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -0
- package/dist/index.d.mts +1378 -94
- package/dist/index.d.ts +1378 -94
- package/dist/index.js +1094 -1309
- package/dist/index.mjs +1038 -1296
- package/package.json +4 -3
- package/package.json.backup +0 -41
- package/src/Blueprint.ts +0 -216
- package/src/__tests__/Blueprint.test.ts +0 -106
- package/src/__tests__/action-context.test.ts +0 -166
- package/src/__tests__/actionCreators.test.ts +0 -179
- package/src/__tests__/builders.test.ts +0 -336
- package/src/__tests__/defineBlueprint-composition.test.ts +0 -106
- package/src/__tests__/factories.test.ts +0 -229
- package/src/__tests__/loader.test.ts +0 -159
- package/src/__tests__/logger.test.ts +0 -70
- package/src/__tests__/type-inference.test.ts +0 -160
- package/src/__tests__/typed-transitions.test.ts +0 -126
- package/src/__tests__/useModuleConfig.test.ts +0 -61
- package/src/actionCreators.ts +0 -132
- package/src/actions.ts +0 -547
- package/src/atoms/index.ts +0 -600
- package/src/authoring.ts +0 -92
- package/src/browser-player.ts +0 -783
- package/src/builders.ts +0 -1342
- package/src/components/ExperienceWorkflowBridge.tsx +0 -123
- package/src/components/PlayerProvider.tsx +0 -43
- package/src/components/atoms/index.tsx +0 -269
- package/src/components/index.ts +0 -36
- package/src/conditions.ts +0 -692
- package/src/config/defineBlueprint.ts +0 -329
- package/src/config/defineModel.ts +0 -753
- package/src/config/defineWorkspace.ts +0 -24
- package/src/core/WorkflowRuntime.ts +0 -153
- package/src/factories.ts +0 -425
- package/src/grammar/index.ts +0 -173
- package/src/hooks/index.ts +0 -106
- package/src/hooks/useAuth.ts +0 -288
- package/src/hooks/useChannel.ts +0 -304
- package/src/hooks/useComputed.ts +0 -154
- package/src/hooks/useDomainSubscription.ts +0 -110
- package/src/hooks/useDuringAction.ts +0 -99
- package/src/hooks/useExperienceState.ts +0 -59
- package/src/hooks/useExpressionLibrary.ts +0 -129
- package/src/hooks/useForm.ts +0 -352
- package/src/hooks/useGeolocation.ts +0 -207
- package/src/hooks/useMapView.ts +0 -259
- package/src/hooks/useMiddleware.ts +0 -291
- package/src/hooks/useModel.ts +0 -363
- package/src/hooks/useModule.ts +0 -59
- package/src/hooks/useModuleConfig.ts +0 -61
- package/src/hooks/useMutation.ts +0 -237
- package/src/hooks/useNotification.ts +0 -151
- package/src/hooks/useOnChange.ts +0 -30
- package/src/hooks/useOnEnter.ts +0 -59
- package/src/hooks/useOnEvent.ts +0 -37
- package/src/hooks/useOnExit.ts +0 -27
- package/src/hooks/useOnTransition.ts +0 -30
- package/src/hooks/usePackage.ts +0 -128
- package/src/hooks/useParams.ts +0 -33
- package/src/hooks/usePlayer.ts +0 -308
- package/src/hooks/useQuery.ts +0 -184
- package/src/hooks/useRealtimeQuery.ts +0 -222
- package/src/hooks/useRole.ts +0 -191
- package/src/hooks/useRouteParams.ts +0 -100
- package/src/hooks/useRouter.ts +0 -347
- package/src/hooks/useServerAction.ts +0 -178
- package/src/hooks/useServerState.ts +0 -284
- package/src/hooks/useToast.ts +0 -164
- package/src/hooks/useTransition.ts +0 -39
- package/src/hooks/useView.ts +0 -102
- package/src/hooks/useWhileIn.ts +0 -48
- package/src/hooks/useWorkflow.ts +0 -63
- package/src/index.ts +0 -465
- package/src/loader/experience-workflow-loader.ts +0 -192
- package/src/loader/index.ts +0 -6
- package/src/local/LocalEngine.ts +0 -388
- package/src/local/LocalEngineAdapter.ts +0 -175
- package/src/local/LocalEngineContext.ts +0 -30
- package/src/logger.ts +0 -37
- package/src/mixins.ts +0 -1160
- package/src/providers/RuntimeContext.ts +0 -20
- package/src/providers/WorkflowProvider.tsx +0 -28
- package/src/routing/instance-key.ts +0 -107
- package/src/server/transition-context.ts +0 -172
- package/src/testing/index.ts +0 -9
- package/src/testing/useBlueprintTestRunner.ts +0 -91
- package/src/testing/useGraphAnalysis.ts +0 -18
- package/src/testing/useTestRunner.ts +0 -77
- package/src/testing.ts +0 -995
- package/src/types/workflow-inference.ts +0 -158
- package/src/types.ts +0 -114
- package/tsconfig.json +0 -27
- package/vitest.config.ts +0 -8
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
Accordion: () => Accordion,
|
|
34
34
|
AnimatedBox: () => AnimatedBox,
|
|
35
|
+
BUILT_IN_CONSTRAINTS: () => BUILT_IN_CONSTRAINTS,
|
|
35
36
|
Badge: () => Badge,
|
|
36
37
|
Blueprint: () => Blueprint,
|
|
37
38
|
BrowserPlayer: () => BrowserPlayer,
|
|
@@ -58,6 +59,7 @@ __export(index_exports, {
|
|
|
58
59
|
Modal: () => Modal,
|
|
59
60
|
ModelBuilder: () => ModelBuilder,
|
|
60
61
|
NavLink: () => NavLink,
|
|
62
|
+
ORCHESTRATION_PRESETS: () => ORCHESTRATION_PRESETS,
|
|
61
63
|
PlayerProvider: () => PlayerProvider,
|
|
62
64
|
RoleGuard: () => RoleGuard,
|
|
63
65
|
Route: () => Route,
|
|
@@ -81,12 +83,19 @@ __export(index_exports, {
|
|
|
81
83
|
WorkflowProvider: () => WorkflowProvider,
|
|
82
84
|
WorkflowRuntime: () => WorkflowRuntime,
|
|
83
85
|
action: () => action,
|
|
84
|
-
|
|
86
|
+
actor: () => actor,
|
|
87
|
+
after: () => after,
|
|
88
|
+
allowTransition: () => allowTransition,
|
|
89
|
+
and: () => and,
|
|
85
90
|
applyMixins: () => applyMixins,
|
|
86
91
|
approval: () => approval,
|
|
87
92
|
assertModelValid: () => assertModelValid,
|
|
88
93
|
cedar: () => cedar,
|
|
94
|
+
compose: () => compose,
|
|
95
|
+
computeVisibility: () => computeVisibility,
|
|
96
|
+
configureActor: () => configureActor,
|
|
89
97
|
connector: () => connector,
|
|
98
|
+
constraints: () => constraints,
|
|
90
99
|
createActions: () => createActions,
|
|
91
100
|
createCRUD: () => createCRUD,
|
|
92
101
|
createLocalDataResolver: () => createLocalDataResolver,
|
|
@@ -95,16 +104,26 @@ __export(index_exports, {
|
|
|
95
104
|
cron: () => cron,
|
|
96
105
|
crud: () => crud,
|
|
97
106
|
defineBlueprint: () => defineBlueprint,
|
|
107
|
+
defineImperativeBlueprint: () => blueprint,
|
|
108
|
+
defineMiddleware: () => defineMiddleware,
|
|
98
109
|
defineModel: () => defineModel,
|
|
99
110
|
defineModule: () => defineModule,
|
|
111
|
+
defineRoles: () => defineRoles,
|
|
100
112
|
defineWorkspace: () => defineWorkspace,
|
|
113
|
+
delay: () => delay,
|
|
101
114
|
deriveInstanceKey: () => deriveInstanceKey,
|
|
102
115
|
deriveInstanceKeySync: () => deriveInstanceKeySync,
|
|
103
116
|
describeModel: () => describeModel,
|
|
104
117
|
deviceAction: () => deviceAction,
|
|
105
118
|
dmn: () => dmn,
|
|
119
|
+
editableBy: () => editableBy,
|
|
120
|
+
editableIn: () => editableIn,
|
|
121
|
+
emit: () => emit,
|
|
106
122
|
escalation: () => escalation,
|
|
123
|
+
every: () => every,
|
|
107
124
|
expr: () => expr,
|
|
125
|
+
extend: () => extend,
|
|
126
|
+
extendMiddleware: () => extendMiddleware,
|
|
108
127
|
field: () => field,
|
|
109
128
|
fieldContains: () => fieldContains,
|
|
110
129
|
fieldEquals: () => fieldEquals,
|
|
@@ -119,12 +138,21 @@ __export(index_exports, {
|
|
|
119
138
|
getInstalledModule: () => getInstalledModule,
|
|
120
139
|
getInstalledModules: () => getInstalledModules,
|
|
121
140
|
graphql: () => graphql,
|
|
141
|
+
guard: () => guard,
|
|
122
142
|
hasAnyRole: () => hasAnyRole,
|
|
123
143
|
hasRole: () => hasRole,
|
|
144
|
+
imperativeCron: () => cron2,
|
|
145
|
+
imperativeLog: () => log,
|
|
146
|
+
imperativeNotify: () => notify2,
|
|
147
|
+
imperativeRequireRole: () => requireRole2,
|
|
124
148
|
inState: () => inState,
|
|
125
149
|
inputEquals: () => inputEquals,
|
|
126
150
|
inputRequired: () => inputRequired,
|
|
151
|
+
instance: () => instance,
|
|
127
152
|
isActor: () => isActor,
|
|
153
|
+
isActorConfig: () => isActorConfig,
|
|
154
|
+
isBuiltInConstraint: () => isBuiltInConstraint,
|
|
155
|
+
isConstraintDeclaration: () => isConstraintDeclaration,
|
|
128
156
|
isCreator: () => isCreator,
|
|
129
157
|
isOwner: () => isOwner,
|
|
130
158
|
isPlayerDebug: () => isPlayerDebug,
|
|
@@ -134,28 +162,39 @@ __export(index_exports, {
|
|
|
134
162
|
loadExperienceWorkflow: () => loadExperienceWorkflow,
|
|
135
163
|
logEvent: () => logEvent,
|
|
136
164
|
model: () => model,
|
|
165
|
+
named: () => named,
|
|
137
166
|
normalizeDefinition: () => normalizeDefinition,
|
|
138
|
-
not: () =>
|
|
167
|
+
not: () => not,
|
|
139
168
|
notInState: () => notInState,
|
|
140
169
|
notify: () => notify,
|
|
141
|
-
|
|
170
|
+
on: () => on,
|
|
171
|
+
or: () => or,
|
|
172
|
+
orchestration: () => orchestration,
|
|
173
|
+
patch: () => patch,
|
|
142
174
|
pipe: () => pipe,
|
|
143
175
|
playerLog: () => playerLog,
|
|
144
176
|
prefetchData: () => prefetchData,
|
|
145
177
|
refHasAnyRole: () => refHasAnyRole,
|
|
146
178
|
refHasRole: () => refHasRole,
|
|
147
179
|
requireAuth: () => requireAuth,
|
|
180
|
+
requireField: () => requireField,
|
|
148
181
|
requireRole: () => requireRole,
|
|
182
|
+
resolveOrchestration: () => resolveOrchestration,
|
|
183
|
+
restrict: () => restrict,
|
|
149
184
|
review: () => review,
|
|
185
|
+
runtime: () => runtime,
|
|
186
|
+
sendMessage: () => sendMessage,
|
|
150
187
|
serverAction: () => serverAction,
|
|
151
188
|
setAuthResolver: () => setAuthResolver,
|
|
152
189
|
setChannelTransport: () => setChannelTransport,
|
|
190
|
+
setConfigContext: () => setConfigContext,
|
|
153
191
|
setExpressionLibraryResolver: () => setExpressionLibraryResolver,
|
|
154
192
|
setField: () => setField,
|
|
155
193
|
setFields: () => setFields,
|
|
156
194
|
setInstalledModules: () => setInstalledModules,
|
|
157
195
|
setModuleConfigDefaults: () => setModuleConfigDefaults,
|
|
158
196
|
setMutationResolver: () => setMutationResolver,
|
|
197
|
+
setPersistedModuleConfig: () => setPersistedModuleConfig,
|
|
159
198
|
setPlayerDebug: () => setPlayerDebug,
|
|
160
199
|
setQueryResolver: () => setQueryResolver,
|
|
161
200
|
setRealtimeQueryResolver: () => setRealtimeQueryResolver,
|
|
@@ -164,10 +203,14 @@ __export(index_exports, {
|
|
|
164
203
|
setServerStateResolver: () => setServerStateResolver,
|
|
165
204
|
setViewResolver: () => setViewResolver,
|
|
166
205
|
spawn: () => spawn,
|
|
206
|
+
spawnActor: () => spawnActor,
|
|
167
207
|
sql: () => sql,
|
|
168
208
|
state: () => state,
|
|
209
|
+
syncConfigDefaults: () => syncConfigDefaults,
|
|
169
210
|
testModel: () => testModel,
|
|
211
|
+
timeout: () => timeout,
|
|
170
212
|
transition: () => transition,
|
|
213
|
+
updateDefinitionConfig: () => updateDefinitionConfig,
|
|
171
214
|
useAuth: () => useAuth,
|
|
172
215
|
useChannel: () => useChannel,
|
|
173
216
|
useCollection: () => useCollection,
|
|
@@ -185,6 +228,7 @@ __export(index_exports, {
|
|
|
185
228
|
useModel: () => useModel,
|
|
186
229
|
useModule: () => useModule,
|
|
187
230
|
useModuleConfig: () => useModuleConfig,
|
|
231
|
+
useModuleConfigWithMutation: () => useModuleConfigWithMutation,
|
|
188
232
|
useMutation: () => useMutation,
|
|
189
233
|
useNotification: () => useNotification,
|
|
190
234
|
useOnChange: () => useOnChange,
|
|
@@ -197,6 +241,7 @@ __export(index_exports, {
|
|
|
197
241
|
usePlayer: () => usePlayer,
|
|
198
242
|
usePlayerContext: () => usePlayerContext,
|
|
199
243
|
usePlayerContextSafe: () => usePlayerContextSafe,
|
|
244
|
+
usePresence: () => usePresence,
|
|
200
245
|
useQuery: () => useQuery,
|
|
201
246
|
useRealtimeQuery: () => useRealtimeQuery,
|
|
202
247
|
useRole: () => useRole,
|
|
@@ -209,1109 +254,37 @@ __export(index_exports, {
|
|
|
209
254
|
useToast: () => useToast,
|
|
210
255
|
useTransition: () => useTransition,
|
|
211
256
|
useView: () => useView,
|
|
257
|
+
useVisibility: () => useVisibility,
|
|
212
258
|
useWhileIn: () => useWhileIn,
|
|
213
259
|
useWorkflow: () => useWorkflow,
|
|
214
|
-
useWorkflowState: () =>
|
|
260
|
+
useWorkflowState: () => useState21,
|
|
261
|
+
userAction: () => userAction,
|
|
262
|
+
userChoice: () => userChoice,
|
|
263
|
+
validate: () => validate,
|
|
215
264
|
validateExperienceWorkflow: () => validateExperienceWorkflow,
|
|
216
265
|
validateModel: () => validateModel,
|
|
266
|
+
visibleTo: () => visibleTo,
|
|
217
267
|
when: () => when,
|
|
268
|
+
withAuditLog: () => withAuditLog,
|
|
218
269
|
withAuditTrail: () => withAuditTrail,
|
|
270
|
+
withAuth: () => withAuth,
|
|
271
|
+
withMetrics: () => withMetrics,
|
|
219
272
|
withOwnership: () => withOwnership,
|
|
220
273
|
withPagination: () => withPagination,
|
|
221
274
|
withRBAC: () => withRBAC,
|
|
275
|
+
withRateLimit: () => withRateLimit,
|
|
222
276
|
withSearch: () => withSearch,
|
|
223
277
|
withSlug: () => withSlug,
|
|
224
278
|
withSoftDelete: () => withSoftDelete,
|
|
225
279
|
withTags: () => withTags,
|
|
226
280
|
withTimestamps: () => withTimestamps,
|
|
281
|
+
withValidation: () => withValidation,
|
|
227
282
|
withVersioning: () => withVersioning
|
|
228
283
|
});
|
|
229
284
|
module.exports = __toCommonJS(index_exports);
|
|
230
285
|
|
|
231
|
-
// ../player-core/dist/index.mjs
|
|
232
|
-
var add = {
|
|
233
|
-
name: "add",
|
|
234
|
-
fn: (a, b) => Number(a) + Number(b),
|
|
235
|
-
arity: 2
|
|
236
|
-
};
|
|
237
|
-
var subtract = {
|
|
238
|
-
name: "subtract",
|
|
239
|
-
fn: (a, b) => Number(a) - Number(b),
|
|
240
|
-
arity: 2
|
|
241
|
-
};
|
|
242
|
-
var multiply = {
|
|
243
|
-
name: "multiply",
|
|
244
|
-
fn: (a, b) => Number(a) * Number(b),
|
|
245
|
-
arity: 2
|
|
246
|
-
};
|
|
247
|
-
var divide = {
|
|
248
|
-
name: "divide",
|
|
249
|
-
fn: (a, b) => {
|
|
250
|
-
const d = Number(b);
|
|
251
|
-
return d === 0 ? 0 : Number(a) / d;
|
|
252
|
-
},
|
|
253
|
-
arity: 2
|
|
254
|
-
};
|
|
255
|
-
var abs = {
|
|
256
|
-
name: "abs",
|
|
257
|
-
fn: (a) => Math.abs(Number(a)),
|
|
258
|
-
arity: 1
|
|
259
|
-
};
|
|
260
|
-
var round = {
|
|
261
|
-
name: "round",
|
|
262
|
-
fn: (a, decimals) => {
|
|
263
|
-
const d = decimals != null ? Number(decimals) : 0;
|
|
264
|
-
const factor = Math.pow(10, d);
|
|
265
|
-
return Math.round(Number(a) * factor) / factor;
|
|
266
|
-
},
|
|
267
|
-
arity: -1
|
|
268
|
-
};
|
|
269
|
-
var min = {
|
|
270
|
-
name: "min",
|
|
271
|
-
fn: (...args) => {
|
|
272
|
-
const nums = args.flat().map(Number).filter((n) => !isNaN(n));
|
|
273
|
-
return nums.length === 0 ? 0 : Math.min(...nums);
|
|
274
|
-
},
|
|
275
|
-
arity: -1
|
|
276
|
-
};
|
|
277
|
-
var max = {
|
|
278
|
-
name: "max",
|
|
279
|
-
fn: (...args) => {
|
|
280
|
-
const nums = args.flat().map(Number).filter((n) => !isNaN(n));
|
|
281
|
-
return nums.length === 0 ? 0 : Math.max(...nums);
|
|
282
|
-
},
|
|
283
|
-
arity: -1
|
|
284
|
-
};
|
|
285
|
-
var eq = {
|
|
286
|
-
name: "eq",
|
|
287
|
-
fn: (a, b) => a === b || String(a) === String(b),
|
|
288
|
-
arity: 2
|
|
289
|
-
};
|
|
290
|
-
var neq = {
|
|
291
|
-
name: "neq",
|
|
292
|
-
fn: (a, b) => a !== b && String(a) !== String(b),
|
|
293
|
-
arity: 2
|
|
294
|
-
};
|
|
295
|
-
var gt = {
|
|
296
|
-
name: "gt",
|
|
297
|
-
fn: (a, b) => Number(a) > Number(b),
|
|
298
|
-
arity: 2
|
|
299
|
-
};
|
|
300
|
-
var gte = {
|
|
301
|
-
name: "gte",
|
|
302
|
-
fn: (a, b) => Number(a) >= Number(b),
|
|
303
|
-
arity: 2
|
|
304
|
-
};
|
|
305
|
-
var lt = {
|
|
306
|
-
name: "lt",
|
|
307
|
-
fn: (a, b) => Number(a) < Number(b),
|
|
308
|
-
arity: 2
|
|
309
|
-
};
|
|
310
|
-
var lte = {
|
|
311
|
-
name: "lte",
|
|
312
|
-
fn: (a, b) => Number(a) <= Number(b),
|
|
313
|
-
arity: 2
|
|
314
|
-
};
|
|
315
|
-
var if_fn = {
|
|
316
|
-
name: "if",
|
|
317
|
-
fn: (cond, then, else_) => cond ? then : else_,
|
|
318
|
-
arity: 3
|
|
319
|
-
};
|
|
320
|
-
var and = {
|
|
321
|
-
name: "and",
|
|
322
|
-
fn: (...args) => args.every(Boolean),
|
|
323
|
-
arity: -1
|
|
324
|
-
};
|
|
325
|
-
var or = {
|
|
326
|
-
name: "or",
|
|
327
|
-
fn: (...args) => args.some(Boolean),
|
|
328
|
-
arity: -1
|
|
329
|
-
};
|
|
330
|
-
var not = {
|
|
331
|
-
name: "not",
|
|
332
|
-
fn: (a) => !a,
|
|
333
|
-
arity: 1
|
|
334
|
-
};
|
|
335
|
-
var coalesce = {
|
|
336
|
-
name: "coalesce",
|
|
337
|
-
fn: (...args) => {
|
|
338
|
-
for (const arg of args) {
|
|
339
|
-
if (arg != null) return arg;
|
|
340
|
-
}
|
|
341
|
-
return null;
|
|
342
|
-
},
|
|
343
|
-
arity: -1
|
|
344
|
-
};
|
|
345
|
-
var concat = {
|
|
346
|
-
name: "concat",
|
|
347
|
-
fn: (...args) => args.map(String).join(""),
|
|
348
|
-
arity: -1
|
|
349
|
-
};
|
|
350
|
-
var upper = {
|
|
351
|
-
name: "upper",
|
|
352
|
-
fn: (s) => String(s ?? "").toUpperCase(),
|
|
353
|
-
arity: 1
|
|
354
|
-
};
|
|
355
|
-
var lower = {
|
|
356
|
-
name: "lower",
|
|
357
|
-
fn: (s) => String(s ?? "").toLowerCase(),
|
|
358
|
-
arity: 1
|
|
359
|
-
};
|
|
360
|
-
var trim = {
|
|
361
|
-
name: "trim",
|
|
362
|
-
fn: (s) => String(s ?? "").trim(),
|
|
363
|
-
arity: 1
|
|
364
|
-
};
|
|
365
|
-
var format = {
|
|
366
|
-
name: "format",
|
|
367
|
-
fn: (template, ...args) => {
|
|
368
|
-
let result = String(template ?? "");
|
|
369
|
-
args.forEach((arg, i) => {
|
|
370
|
-
result = result.replace(`{${i}}`, String(arg ?? ""));
|
|
371
|
-
});
|
|
372
|
-
return result;
|
|
373
|
-
},
|
|
374
|
-
arity: -1
|
|
375
|
-
};
|
|
376
|
-
var length = {
|
|
377
|
-
name: "length",
|
|
378
|
-
fn: (v) => {
|
|
379
|
-
if (Array.isArray(v)) return v.length;
|
|
380
|
-
if (typeof v === "string") return v.length;
|
|
381
|
-
if (v && typeof v === "object") return Object.keys(v).length;
|
|
382
|
-
return 0;
|
|
383
|
-
},
|
|
384
|
-
arity: 1
|
|
385
|
-
};
|
|
386
|
-
var get = {
|
|
387
|
-
name: "get",
|
|
388
|
-
fn: (obj, path) => {
|
|
389
|
-
if (obj == null || typeof path !== "string") return void 0;
|
|
390
|
-
const parts = path.split(".");
|
|
391
|
-
let current = obj;
|
|
392
|
-
for (const part of parts) {
|
|
393
|
-
if (current == null || typeof current !== "object") return void 0;
|
|
394
|
-
current = current[part];
|
|
395
|
-
}
|
|
396
|
-
return current;
|
|
397
|
-
},
|
|
398
|
-
arity: 2
|
|
399
|
-
};
|
|
400
|
-
var includes = {
|
|
401
|
-
name: "includes",
|
|
402
|
-
fn: (collection, value) => {
|
|
403
|
-
if (Array.isArray(collection)) return collection.includes(value);
|
|
404
|
-
if (typeof collection === "string") return collection.includes(String(value));
|
|
405
|
-
return false;
|
|
406
|
-
},
|
|
407
|
-
arity: 2
|
|
408
|
-
};
|
|
409
|
-
var is_defined = {
|
|
410
|
-
name: "is_defined",
|
|
411
|
-
fn: (v) => v !== void 0 && v !== null,
|
|
412
|
-
arity: 1
|
|
413
|
-
};
|
|
414
|
-
var is_empty = {
|
|
415
|
-
name: "is_empty",
|
|
416
|
-
fn: (v) => {
|
|
417
|
-
if (v == null) return true;
|
|
418
|
-
if (typeof v === "string") return v.length === 0;
|
|
419
|
-
if (Array.isArray(v)) return v.length === 0;
|
|
420
|
-
if (typeof v === "object") return Object.keys(v).length === 0;
|
|
421
|
-
return false;
|
|
422
|
-
},
|
|
423
|
-
arity: 1
|
|
424
|
-
};
|
|
425
|
-
var is_null = {
|
|
426
|
-
name: "is_null",
|
|
427
|
-
fn: (v) => v === null || v === void 0,
|
|
428
|
-
arity: 1
|
|
429
|
-
};
|
|
430
|
-
var to_string = {
|
|
431
|
-
name: "to_string",
|
|
432
|
-
fn: (v) => {
|
|
433
|
-
if (v == null) return "";
|
|
434
|
-
if (typeof v === "object") return JSON.stringify(v);
|
|
435
|
-
return String(v);
|
|
436
|
-
},
|
|
437
|
-
arity: 1
|
|
438
|
-
};
|
|
439
|
-
var CORE_FUNCTIONS = [
|
|
440
|
-
// Math (8)
|
|
441
|
-
add,
|
|
442
|
-
subtract,
|
|
443
|
-
multiply,
|
|
444
|
-
divide,
|
|
445
|
-
abs,
|
|
446
|
-
round,
|
|
447
|
-
min,
|
|
448
|
-
max,
|
|
449
|
-
// Comparison (6)
|
|
450
|
-
eq,
|
|
451
|
-
neq,
|
|
452
|
-
gt,
|
|
453
|
-
gte,
|
|
454
|
-
lt,
|
|
455
|
-
lte,
|
|
456
|
-
// Logic (5)
|
|
457
|
-
if_fn,
|
|
458
|
-
and,
|
|
459
|
-
or,
|
|
460
|
-
not,
|
|
461
|
-
coalesce,
|
|
462
|
-
// String (6)
|
|
463
|
-
concat,
|
|
464
|
-
upper,
|
|
465
|
-
lower,
|
|
466
|
-
trim,
|
|
467
|
-
format,
|
|
468
|
-
length,
|
|
469
|
-
// Path (3)
|
|
470
|
-
get,
|
|
471
|
-
includes,
|
|
472
|
-
is_defined,
|
|
473
|
-
// Type (3)
|
|
474
|
-
is_empty,
|
|
475
|
-
is_null,
|
|
476
|
-
to_string
|
|
477
|
-
];
|
|
478
|
-
function buildFunctionMap(functions) {
|
|
479
|
-
const map = /* @__PURE__ */ new Map();
|
|
480
|
-
for (const fn of functions) {
|
|
481
|
-
map.set(fn.name, fn.fn);
|
|
482
|
-
}
|
|
483
|
-
return map;
|
|
484
|
-
}
|
|
485
|
-
var MAX_DEPTH = 50;
|
|
486
|
-
var Parser = class {
|
|
487
|
-
pos = 0;
|
|
488
|
-
depth = 0;
|
|
489
|
-
input;
|
|
490
|
-
constructor(input) {
|
|
491
|
-
this.input = input;
|
|
492
|
-
}
|
|
493
|
-
parse() {
|
|
494
|
-
this.skipWhitespace();
|
|
495
|
-
const node = this.parseExpression();
|
|
496
|
-
this.skipWhitespace();
|
|
497
|
-
if (this.pos < this.input.length) {
|
|
498
|
-
throw new Error(`Unexpected character at position ${this.pos}: '${this.input[this.pos]}'`);
|
|
499
|
-
}
|
|
500
|
-
return node;
|
|
501
|
-
}
|
|
502
|
-
guardDepth() {
|
|
503
|
-
if (++this.depth > MAX_DEPTH) {
|
|
504
|
-
throw new Error("Expression too deeply nested");
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
parseExpression() {
|
|
508
|
-
this.guardDepth();
|
|
509
|
-
try {
|
|
510
|
-
return this.parseTernary();
|
|
511
|
-
} finally {
|
|
512
|
-
this.depth--;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
parseTernary() {
|
|
516
|
-
let node = this.parseLogicalOr();
|
|
517
|
-
this.skipWhitespace();
|
|
518
|
-
if (this.peek() === "?") {
|
|
519
|
-
this.advance();
|
|
520
|
-
const consequent = this.parseExpression();
|
|
521
|
-
this.skipWhitespace();
|
|
522
|
-
this.expect(":");
|
|
523
|
-
const alternate = this.parseExpression();
|
|
524
|
-
node = { type: "ternary", condition: node, consequent, alternate };
|
|
525
|
-
}
|
|
526
|
-
return node;
|
|
527
|
-
}
|
|
528
|
-
parseLogicalOr() {
|
|
529
|
-
let left = this.parseLogicalAnd();
|
|
530
|
-
this.skipWhitespace();
|
|
531
|
-
while (this.match("||")) {
|
|
532
|
-
const right = this.parseLogicalAnd();
|
|
533
|
-
left = { type: "binary", operator: "||", left, right };
|
|
534
|
-
this.skipWhitespace();
|
|
535
|
-
}
|
|
536
|
-
return left;
|
|
537
|
-
}
|
|
538
|
-
parseLogicalAnd() {
|
|
539
|
-
let left = this.parseEquality();
|
|
540
|
-
this.skipWhitespace();
|
|
541
|
-
while (this.match("&&")) {
|
|
542
|
-
const right = this.parseEquality();
|
|
543
|
-
left = { type: "binary", operator: "&&", left, right };
|
|
544
|
-
this.skipWhitespace();
|
|
545
|
-
}
|
|
546
|
-
return left;
|
|
547
|
-
}
|
|
548
|
-
parseEquality() {
|
|
549
|
-
let left = this.parseComparison();
|
|
550
|
-
this.skipWhitespace();
|
|
551
|
-
while (true) {
|
|
552
|
-
if (this.match("==")) {
|
|
553
|
-
const right = this.parseComparison();
|
|
554
|
-
left = { type: "binary", operator: "==", left, right };
|
|
555
|
-
} else if (this.match("!=")) {
|
|
556
|
-
const right = this.parseComparison();
|
|
557
|
-
left = { type: "binary", operator: "!=", left, right };
|
|
558
|
-
} else {
|
|
559
|
-
break;
|
|
560
|
-
}
|
|
561
|
-
this.skipWhitespace();
|
|
562
|
-
}
|
|
563
|
-
return left;
|
|
564
|
-
}
|
|
565
|
-
parseComparison() {
|
|
566
|
-
let left = this.parseUnary();
|
|
567
|
-
this.skipWhitespace();
|
|
568
|
-
while (true) {
|
|
569
|
-
if (this.match(">=")) {
|
|
570
|
-
const right = this.parseUnary();
|
|
571
|
-
left = { type: "binary", operator: ">=", left, right };
|
|
572
|
-
} else if (this.match("<=")) {
|
|
573
|
-
const right = this.parseUnary();
|
|
574
|
-
left = { type: "binary", operator: "<=", left, right };
|
|
575
|
-
} else if (this.peek() === ">" && !this.lookAhead(">=")) {
|
|
576
|
-
this.advance();
|
|
577
|
-
const right = this.parseUnary();
|
|
578
|
-
left = { type: "binary", operator: ">", left, right };
|
|
579
|
-
} else if (this.peek() === "<" && !this.lookAhead("<=")) {
|
|
580
|
-
this.advance();
|
|
581
|
-
const right = this.parseUnary();
|
|
582
|
-
left = { type: "binary", operator: "<", left, right };
|
|
583
|
-
} else {
|
|
584
|
-
break;
|
|
585
|
-
}
|
|
586
|
-
this.skipWhitespace();
|
|
587
|
-
}
|
|
588
|
-
return left;
|
|
589
|
-
}
|
|
590
|
-
parseUnary() {
|
|
591
|
-
this.skipWhitespace();
|
|
592
|
-
if (this.peek() === "!") {
|
|
593
|
-
this.advance();
|
|
594
|
-
const operand = this.parseUnary();
|
|
595
|
-
return { type: "unary", operator: "!", operand };
|
|
596
|
-
}
|
|
597
|
-
if (this.peek() === "-") {
|
|
598
|
-
const nextChar = this.input[this.pos + 1];
|
|
599
|
-
if (nextChar !== void 0 && (nextChar >= "0" && nextChar <= "9" || nextChar === ".")) {
|
|
600
|
-
return this.parseCallChain();
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
return this.parseCallChain();
|
|
604
|
-
}
|
|
605
|
-
parseCallChain() {
|
|
606
|
-
let node = this.parsePrimary();
|
|
607
|
-
while (true) {
|
|
608
|
-
this.skipWhitespace();
|
|
609
|
-
if (this.peek() === "(") {
|
|
610
|
-
this.advance();
|
|
611
|
-
const args = this.parseArgList();
|
|
612
|
-
this.expect(")");
|
|
613
|
-
if (node.type === "identifier") {
|
|
614
|
-
node = { type: "call", name: node.name, args };
|
|
615
|
-
} else if (node.type === "path") {
|
|
616
|
-
const name = node.segments.join(".");
|
|
617
|
-
node = { type: "call", name, args };
|
|
618
|
-
} else if (node.type === "member") {
|
|
619
|
-
node = { type: "method_call", object: node.object, method: node.property, args };
|
|
620
|
-
} else {
|
|
621
|
-
throw new Error("Cannot call non-function");
|
|
622
|
-
}
|
|
623
|
-
} else if (this.peek() === ".") {
|
|
624
|
-
this.advance();
|
|
625
|
-
const prop = this.parseIdentifierName();
|
|
626
|
-
node = { type: "member", object: node, property: prop };
|
|
627
|
-
} else {
|
|
628
|
-
break;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return node;
|
|
632
|
-
}
|
|
633
|
-
parsePrimary() {
|
|
634
|
-
this.skipWhitespace();
|
|
635
|
-
const ch = this.peek();
|
|
636
|
-
if (ch === "(") {
|
|
637
|
-
this.advance();
|
|
638
|
-
const expr2 = this.parseExpression();
|
|
639
|
-
this.skipWhitespace();
|
|
640
|
-
this.expect(")");
|
|
641
|
-
return expr2;
|
|
642
|
-
}
|
|
643
|
-
if (ch === "'" || ch === '"') {
|
|
644
|
-
return this.parseString();
|
|
645
|
-
}
|
|
646
|
-
if (ch === "-" || ch >= "0" && ch <= "9") {
|
|
647
|
-
return this.parseNumber();
|
|
648
|
-
}
|
|
649
|
-
if (this.isIdentStart(ch)) {
|
|
650
|
-
return this.parseIdentifierOrPath();
|
|
651
|
-
}
|
|
652
|
-
throw new Error(
|
|
653
|
-
`Unexpected character at position ${this.pos}: '${ch || "EOF"}'`
|
|
654
|
-
);
|
|
655
|
-
}
|
|
656
|
-
parseString() {
|
|
657
|
-
const quote = this.advance();
|
|
658
|
-
let value = "";
|
|
659
|
-
while (this.pos < this.input.length && this.peek() !== quote) {
|
|
660
|
-
if (this.peek() === "\\") {
|
|
661
|
-
this.advance();
|
|
662
|
-
const esc = this.advance();
|
|
663
|
-
if (esc === "n") value += "\n";
|
|
664
|
-
else if (esc === "t") value += " ";
|
|
665
|
-
else if (esc === "r") value += "\r";
|
|
666
|
-
else value += esc;
|
|
667
|
-
} else {
|
|
668
|
-
value += this.advance();
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
if (this.pos >= this.input.length) {
|
|
672
|
-
throw new Error("Unterminated string literal");
|
|
673
|
-
}
|
|
674
|
-
this.advance();
|
|
675
|
-
return { type: "string", value };
|
|
676
|
-
}
|
|
677
|
-
parseNumber() {
|
|
678
|
-
let numStr = "";
|
|
679
|
-
if (this.peek() === "-") {
|
|
680
|
-
numStr += this.advance();
|
|
681
|
-
}
|
|
682
|
-
while (this.pos < this.input.length && (this.input[this.pos] >= "0" && this.input[this.pos] <= "9")) {
|
|
683
|
-
numStr += this.advance();
|
|
684
|
-
}
|
|
685
|
-
if (this.peek() === "." && this.pos + 1 < this.input.length && this.input[this.pos + 1] >= "0" && this.input[this.pos + 1] <= "9") {
|
|
686
|
-
numStr += this.advance();
|
|
687
|
-
while (this.pos < this.input.length && (this.input[this.pos] >= "0" && this.input[this.pos] <= "9")) {
|
|
688
|
-
numStr += this.advance();
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
return { type: "number", value: Number(numStr) };
|
|
692
|
-
}
|
|
693
|
-
parseIdentifierOrPath() {
|
|
694
|
-
const name = this.parseIdentifierName();
|
|
695
|
-
if (name === "true") return { type: "boolean", value: true };
|
|
696
|
-
if (name === "false") return { type: "boolean", value: false };
|
|
697
|
-
if (name === "null") return { type: "null" };
|
|
698
|
-
if (name === "undefined") return { type: "null" };
|
|
699
|
-
return { type: "identifier", name };
|
|
700
|
-
}
|
|
701
|
-
parseIdentifierName() {
|
|
702
|
-
let name = "";
|
|
703
|
-
if (this.peek() === "$") name += this.advance();
|
|
704
|
-
while (this.pos < this.input.length && this.isIdentPart(this.input[this.pos])) {
|
|
705
|
-
name += this.advance();
|
|
706
|
-
}
|
|
707
|
-
if (!name) {
|
|
708
|
-
throw new Error(`Expected identifier at position ${this.pos}`);
|
|
709
|
-
}
|
|
710
|
-
return name;
|
|
711
|
-
}
|
|
712
|
-
parseArgList() {
|
|
713
|
-
this.skipWhitespace();
|
|
714
|
-
if (this.peek() === ")") return [];
|
|
715
|
-
const args = [];
|
|
716
|
-
args.push(this.parseExpression());
|
|
717
|
-
this.skipWhitespace();
|
|
718
|
-
while (this.peek() === ",") {
|
|
719
|
-
this.advance();
|
|
720
|
-
args.push(this.parseExpression());
|
|
721
|
-
this.skipWhitespace();
|
|
722
|
-
}
|
|
723
|
-
return args;
|
|
724
|
-
}
|
|
725
|
-
// Character utilities
|
|
726
|
-
peek() {
|
|
727
|
-
return this.input[this.pos] ?? "";
|
|
728
|
-
}
|
|
729
|
-
advance() {
|
|
730
|
-
return this.input[this.pos++] ?? "";
|
|
731
|
-
}
|
|
732
|
-
match(str) {
|
|
733
|
-
if (this.input.startsWith(str, this.pos)) {
|
|
734
|
-
this.pos += str.length;
|
|
735
|
-
return true;
|
|
736
|
-
}
|
|
737
|
-
return false;
|
|
738
|
-
}
|
|
739
|
-
lookAhead(str) {
|
|
740
|
-
return this.input.startsWith(str, this.pos);
|
|
741
|
-
}
|
|
742
|
-
expect(ch) {
|
|
743
|
-
this.skipWhitespace();
|
|
744
|
-
if (this.peek() !== ch) {
|
|
745
|
-
throw new Error(`Expected '${ch}' at position ${this.pos}, got '${this.peek() || "EOF"}'`);
|
|
746
|
-
}
|
|
747
|
-
this.advance();
|
|
748
|
-
}
|
|
749
|
-
skipWhitespace() {
|
|
750
|
-
while (this.pos < this.input.length && " \n\r".includes(this.input[this.pos])) {
|
|
751
|
-
this.pos++;
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
isIdentStart(ch) {
|
|
755
|
-
return ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch === "_" || ch === "$";
|
|
756
|
-
}
|
|
757
|
-
isIdentPart(ch) {
|
|
758
|
-
return this.isIdentStart(ch) || ch >= "0" && ch <= "9";
|
|
759
|
-
}
|
|
760
|
-
};
|
|
761
|
-
function evaluateAST(node, context, fnMap) {
|
|
762
|
-
switch (node.type) {
|
|
763
|
-
case "number":
|
|
764
|
-
return node.value;
|
|
765
|
-
case "string":
|
|
766
|
-
return node.value;
|
|
767
|
-
case "boolean":
|
|
768
|
-
return node.value;
|
|
769
|
-
case "null":
|
|
770
|
-
return null;
|
|
771
|
-
case "identifier":
|
|
772
|
-
return resolvePath(node.name, context);
|
|
773
|
-
case "path":
|
|
774
|
-
return resolvePath(node.segments.join("."), context);
|
|
775
|
-
case "member": {
|
|
776
|
-
const obj = evaluateAST(node.object, context, fnMap);
|
|
777
|
-
if (obj == null || typeof obj !== "object") return void 0;
|
|
778
|
-
return obj[node.property];
|
|
779
|
-
}
|
|
780
|
-
case "call": {
|
|
781
|
-
const fn = fnMap.get(node.name);
|
|
782
|
-
if (!fn) return void 0;
|
|
783
|
-
const args = node.args.map((a) => evaluateAST(a, context, fnMap));
|
|
784
|
-
return fn(...args);
|
|
785
|
-
}
|
|
786
|
-
case "method_call": {
|
|
787
|
-
const obj = evaluateAST(node.object, context, fnMap);
|
|
788
|
-
if (obj != null && typeof obj === "object") {
|
|
789
|
-
const method = obj[node.method];
|
|
790
|
-
if (typeof method === "function") {
|
|
791
|
-
const args = node.args.map((a) => evaluateAST(a, context, fnMap));
|
|
792
|
-
return method.apply(obj, args);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
return void 0;
|
|
796
|
-
}
|
|
797
|
-
case "unary": {
|
|
798
|
-
const operand = evaluateAST(node.operand, context, fnMap);
|
|
799
|
-
return !operand;
|
|
800
|
-
}
|
|
801
|
-
case "binary": {
|
|
802
|
-
if (node.operator === "&&") {
|
|
803
|
-
const left2 = evaluateAST(node.left, context, fnMap);
|
|
804
|
-
if (!left2) return left2;
|
|
805
|
-
return evaluateAST(node.right, context, fnMap);
|
|
806
|
-
}
|
|
807
|
-
if (node.operator === "||") {
|
|
808
|
-
const left2 = evaluateAST(node.left, context, fnMap);
|
|
809
|
-
if (left2) return left2;
|
|
810
|
-
return evaluateAST(node.right, context, fnMap);
|
|
811
|
-
}
|
|
812
|
-
const left = evaluateAST(node.left, context, fnMap);
|
|
813
|
-
const right = evaluateAST(node.right, context, fnMap);
|
|
814
|
-
switch (node.operator) {
|
|
815
|
-
// eslint-disable-next-line eqeqeq
|
|
816
|
-
case "==":
|
|
817
|
-
return left == right;
|
|
818
|
-
// eslint-disable-next-line eqeqeq
|
|
819
|
-
case "!=":
|
|
820
|
-
return left != right;
|
|
821
|
-
case ">":
|
|
822
|
-
return Number(left) > Number(right);
|
|
823
|
-
case "<":
|
|
824
|
-
return Number(left) < Number(right);
|
|
825
|
-
case ">=":
|
|
826
|
-
return Number(left) >= Number(right);
|
|
827
|
-
case "<=":
|
|
828
|
-
return Number(left) <= Number(right);
|
|
829
|
-
default:
|
|
830
|
-
return void 0;
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
case "ternary": {
|
|
834
|
-
const condition = evaluateAST(node.condition, context, fnMap);
|
|
835
|
-
return condition ? evaluateAST(node.consequent, context, fnMap) : evaluateAST(node.alternate, context, fnMap);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
var MAX_CACHE = 500;
|
|
840
|
-
var astCache = /* @__PURE__ */ new Map();
|
|
841
|
-
function evictIfNeeded() {
|
|
842
|
-
if (astCache.size > MAX_CACHE) {
|
|
843
|
-
const keys = Array.from(astCache.keys());
|
|
844
|
-
const evictCount = Math.floor(MAX_CACHE * 0.25);
|
|
845
|
-
for (let i = 0; i < evictCount; i++) {
|
|
846
|
-
astCache.delete(keys[i]);
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
function parseAndCache(expr2) {
|
|
851
|
-
const cached = astCache.get(expr2);
|
|
852
|
-
if (cached) return cached;
|
|
853
|
-
const parser = new Parser(expr2);
|
|
854
|
-
const ast = parser.parse();
|
|
855
|
-
astCache.set(expr2, ast);
|
|
856
|
-
evictIfNeeded();
|
|
857
|
-
return ast;
|
|
858
|
-
}
|
|
859
|
-
var TEMPLATE_RE = /\{\{(.+?)\}\}/g;
|
|
860
|
-
function resolvePath(path, context) {
|
|
861
|
-
const parts = path.split(".");
|
|
862
|
-
let current = context;
|
|
863
|
-
for (const part of parts) {
|
|
864
|
-
if (current == null || typeof current !== "object") return void 0;
|
|
865
|
-
current = current[part];
|
|
866
|
-
}
|
|
867
|
-
return current;
|
|
868
|
-
}
|
|
869
|
-
function evaluateExpression(expr2, context, fnMap) {
|
|
870
|
-
const trimmed = expr2.trim();
|
|
871
|
-
if (trimmed === "true") return true;
|
|
872
|
-
if (trimmed === "false") return false;
|
|
873
|
-
if (trimmed === "null") return null;
|
|
874
|
-
if (trimmed === "undefined") return void 0;
|
|
875
|
-
const num = Number(trimmed);
|
|
876
|
-
if (!isNaN(num) && trimmed !== "") return num;
|
|
877
|
-
if (trimmed.startsWith("'") && trimmed.endsWith("'") || trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
878
|
-
return trimmed.slice(1, -1);
|
|
879
|
-
}
|
|
880
|
-
if (/^[a-zA-Z_$][\w$.]*$/.test(trimmed)) {
|
|
881
|
-
return resolvePath(trimmed, context);
|
|
882
|
-
}
|
|
883
|
-
const ast = parseAndCache(trimmed);
|
|
884
|
-
return evaluateAST(ast, context, fnMap);
|
|
885
|
-
}
|
|
886
|
-
var WEB_FAILURE_POLICIES = {
|
|
887
|
-
VIEW_BINDING: {
|
|
888
|
-
on_error: "return_fallback",
|
|
889
|
-
fallback_value: "",
|
|
890
|
-
log_level: "warn"
|
|
891
|
-
},
|
|
892
|
-
EVENT_REACTION: {
|
|
893
|
-
on_error: "log_and_skip",
|
|
894
|
-
fallback_value: void 0,
|
|
895
|
-
log_level: "error"
|
|
896
|
-
},
|
|
897
|
-
DURING_ACTION: {
|
|
898
|
-
on_error: "log_and_skip",
|
|
899
|
-
fallback_value: void 0,
|
|
900
|
-
log_level: "error"
|
|
901
|
-
},
|
|
902
|
-
CONDITIONAL_VISIBILITY: {
|
|
903
|
-
on_error: "return_fallback",
|
|
904
|
-
fallback_value: true,
|
|
905
|
-
// Show by default if condition fails
|
|
906
|
-
log_level: "warn"
|
|
907
|
-
}
|
|
908
|
-
};
|
|
909
|
-
function createEvaluator(config) {
|
|
910
|
-
const allFunctions = [...CORE_FUNCTIONS, ...config.functions];
|
|
911
|
-
const fnMap = buildFunctionMap(allFunctions);
|
|
912
|
-
const policy = config.failurePolicy;
|
|
913
|
-
function handleError(expr2, error) {
|
|
914
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
915
|
-
if (policy.log_level === "error") {
|
|
916
|
-
console.error(`[player-core] Expression error: "${expr2}" \u2014 ${message}`);
|
|
917
|
-
} else if (policy.log_level === "warn") {
|
|
918
|
-
console.warn(`[player-core] Expression error: "${expr2}" \u2014 ${message}`);
|
|
919
|
-
}
|
|
920
|
-
switch (policy.on_error) {
|
|
921
|
-
case "throw":
|
|
922
|
-
throw error;
|
|
923
|
-
case "return_fallback":
|
|
924
|
-
return { value: policy.fallback_value, status: "fallback", error: message };
|
|
925
|
-
case "log_and_skip":
|
|
926
|
-
default:
|
|
927
|
-
return { value: policy.fallback_value, status: "error", error: message };
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
return {
|
|
931
|
-
evaluate(expression, context) {
|
|
932
|
-
try {
|
|
933
|
-
const value = evaluateExpression(expression, context, fnMap);
|
|
934
|
-
return { value, status: "ok" };
|
|
935
|
-
} catch (error) {
|
|
936
|
-
return handleError(expression, error);
|
|
937
|
-
}
|
|
938
|
-
},
|
|
939
|
-
evaluateTemplate(template, context) {
|
|
940
|
-
try {
|
|
941
|
-
if (!template.includes("{{")) {
|
|
942
|
-
return { value: template, status: "ok" };
|
|
943
|
-
}
|
|
944
|
-
const result = template.replace(TEMPLATE_RE, (_match, expr2) => {
|
|
945
|
-
const value = evaluateExpression(expr2, context, fnMap);
|
|
946
|
-
return value != null ? String(value) : "";
|
|
947
|
-
});
|
|
948
|
-
return { value: result, status: "ok" };
|
|
949
|
-
} catch (error) {
|
|
950
|
-
return handleError(template, error);
|
|
951
|
-
}
|
|
952
|
-
},
|
|
953
|
-
validate(expression) {
|
|
954
|
-
const errors = [];
|
|
955
|
-
try {
|
|
956
|
-
parseAndCache(expression);
|
|
957
|
-
} catch (e) {
|
|
958
|
-
errors.push(e instanceof Error ? e.message : String(e));
|
|
959
|
-
}
|
|
960
|
-
return { valid: errors.length === 0, errors };
|
|
961
|
-
}
|
|
962
|
-
};
|
|
963
|
-
}
|
|
964
|
-
var MAX_AUTO_CHAIN = 10;
|
|
965
|
-
var StateMachine = class {
|
|
966
|
-
evaluator;
|
|
967
|
-
actionHandlers;
|
|
968
|
-
listeners = /* @__PURE__ */ new Set();
|
|
969
|
-
instance;
|
|
970
|
-
constructor(definition, initialData = {}, config) {
|
|
971
|
-
this.evaluator = config.evaluator;
|
|
972
|
-
this.actionHandlers = config.actionHandlers ?? /* @__PURE__ */ new Map();
|
|
973
|
-
const startState = definition.states.find((s) => s.type === "START");
|
|
974
|
-
if (!startState) {
|
|
975
|
-
throw new Error(`No START state found in definition ${definition.slug}`);
|
|
976
|
-
}
|
|
977
|
-
this.instance = {
|
|
978
|
-
definition,
|
|
979
|
-
current_state: startState.name,
|
|
980
|
-
state_data: { ...initialData },
|
|
981
|
-
memory: {},
|
|
982
|
-
status: "ACTIVE"
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
/** Get the current instance snapshot (immutable copy) */
|
|
986
|
-
getSnapshot() {
|
|
987
|
-
return { ...this.instance, state_data: { ...this.instance.state_data }, memory: { ...this.instance.memory } };
|
|
988
|
-
}
|
|
989
|
-
/** Get current state name */
|
|
990
|
-
get currentState() {
|
|
991
|
-
return this.instance.current_state;
|
|
992
|
-
}
|
|
993
|
-
/** Get current state_data */
|
|
994
|
-
get stateData() {
|
|
995
|
-
return this.instance.state_data;
|
|
996
|
-
}
|
|
997
|
-
/** Get current status */
|
|
998
|
-
get status() {
|
|
999
|
-
return this.instance.status;
|
|
1000
|
-
}
|
|
1001
|
-
/** Subscribe to state machine events */
|
|
1002
|
-
on(listener) {
|
|
1003
|
-
this.listeners.add(listener);
|
|
1004
|
-
return () => this.listeners.delete(listener);
|
|
1005
|
-
}
|
|
1006
|
-
/** Register an action handler */
|
|
1007
|
-
registerAction(type, handler) {
|
|
1008
|
-
this.actionHandlers.set(type, handler);
|
|
1009
|
-
}
|
|
1010
|
-
/** Execute a named transition */
|
|
1011
|
-
async transition(transitionName, data) {
|
|
1012
|
-
if (this.instance.status !== "ACTIVE") {
|
|
1013
|
-
return {
|
|
1014
|
-
success: false,
|
|
1015
|
-
from_state: this.instance.current_state,
|
|
1016
|
-
to_state: this.instance.current_state,
|
|
1017
|
-
actions_executed: [],
|
|
1018
|
-
error: `Cannot transition: instance status is ${this.instance.status}`
|
|
1019
|
-
};
|
|
1020
|
-
}
|
|
1021
|
-
const transition2 = this.instance.definition.transitions.find(
|
|
1022
|
-
(t) => t.name === transitionName && t.from.includes(this.instance.current_state)
|
|
1023
|
-
);
|
|
1024
|
-
if (!transition2) {
|
|
1025
|
-
return {
|
|
1026
|
-
success: false,
|
|
1027
|
-
from_state: this.instance.current_state,
|
|
1028
|
-
to_state: this.instance.current_state,
|
|
1029
|
-
actions_executed: [],
|
|
1030
|
-
error: `Transition "${transitionName}" not valid from state "${this.instance.current_state}"`
|
|
1031
|
-
};
|
|
1032
|
-
}
|
|
1033
|
-
if (data) {
|
|
1034
|
-
this.instance.state_data = { ...this.instance.state_data, ...data };
|
|
1035
|
-
}
|
|
1036
|
-
if (transition2.conditions && transition2.conditions.length > 0) {
|
|
1037
|
-
const ctx = this.buildContext();
|
|
1038
|
-
for (const condition of transition2.conditions) {
|
|
1039
|
-
const result2 = this.evaluator.evaluate(condition, ctx);
|
|
1040
|
-
if (!result2.value) {
|
|
1041
|
-
return {
|
|
1042
|
-
success: false,
|
|
1043
|
-
from_state: this.instance.current_state,
|
|
1044
|
-
to_state: this.instance.current_state,
|
|
1045
|
-
actions_executed: [],
|
|
1046
|
-
error: `Transition condition not met: ${condition}`
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
const result = await this.executeTransition(transition2);
|
|
1052
|
-
if (result.success) {
|
|
1053
|
-
await this.drainAutoTransitions();
|
|
1054
|
-
}
|
|
1055
|
-
return result;
|
|
1056
|
-
}
|
|
1057
|
-
/** Update state_data directly (for on_event set_field actions) */
|
|
1058
|
-
setField(field2, value) {
|
|
1059
|
-
this.instance.state_data = { ...this.instance.state_data, [field2]: value };
|
|
1060
|
-
}
|
|
1061
|
-
/** Update memory */
|
|
1062
|
-
setMemory(key, value) {
|
|
1063
|
-
this.instance.memory = { ...this.instance.memory, [key]: value };
|
|
1064
|
-
}
|
|
1065
|
-
/** Get available transitions from the current state */
|
|
1066
|
-
getAvailableTransitions() {
|
|
1067
|
-
return this.instance.definition.transitions.filter(
|
|
1068
|
-
(t) => t.from.includes(this.instance.current_state) && !t.auto
|
|
1069
|
-
);
|
|
1070
|
-
}
|
|
1071
|
-
/** Get the current state definition */
|
|
1072
|
-
getCurrentStateDefinition() {
|
|
1073
|
-
return this.instance.definition.states.find((s) => s.name === this.instance.current_state);
|
|
1074
|
-
}
|
|
1075
|
-
// ===========================================================================
|
|
1076
|
-
// Private implementation
|
|
1077
|
-
// ===========================================================================
|
|
1078
|
-
async executeTransition(transition2) {
|
|
1079
|
-
const fromState = this.instance.current_state;
|
|
1080
|
-
const allActionsExecuted = [];
|
|
1081
|
-
const fromStateDef = this.getCurrentStateDefinition();
|
|
1082
|
-
if (fromStateDef?.on_exit) {
|
|
1083
|
-
await this.executeActions(fromStateDef.on_exit, allActionsExecuted);
|
|
1084
|
-
}
|
|
1085
|
-
this.emit({
|
|
1086
|
-
type: "state_exit",
|
|
1087
|
-
instance_id: this.instance.definition.id,
|
|
1088
|
-
from_state: fromState
|
|
1089
|
-
});
|
|
1090
|
-
if (transition2.actions) {
|
|
1091
|
-
await this.executeActions(transition2.actions, allActionsExecuted);
|
|
1092
|
-
}
|
|
1093
|
-
this.instance.current_state = transition2.to;
|
|
1094
|
-
const toStateDef = this.instance.definition.states.find((s) => s.name === transition2.to);
|
|
1095
|
-
if (toStateDef?.type === "END") {
|
|
1096
|
-
this.instance.status = "COMPLETED";
|
|
1097
|
-
} else if (toStateDef?.type === "CANCELLED") {
|
|
1098
|
-
this.instance.status = "CANCELLED";
|
|
1099
|
-
}
|
|
1100
|
-
this.emit({
|
|
1101
|
-
type: "state_enter",
|
|
1102
|
-
instance_id: this.instance.definition.id,
|
|
1103
|
-
to_state: transition2.to
|
|
1104
|
-
});
|
|
1105
|
-
if (toStateDef?.on_enter) {
|
|
1106
|
-
await this.executeActions(toStateDef.on_enter, allActionsExecuted);
|
|
1107
|
-
}
|
|
1108
|
-
this.emit({
|
|
1109
|
-
type: "transition",
|
|
1110
|
-
instance_id: this.instance.definition.id,
|
|
1111
|
-
from_state: fromState,
|
|
1112
|
-
to_state: transition2.to
|
|
1113
|
-
});
|
|
1114
|
-
return {
|
|
1115
|
-
success: true,
|
|
1116
|
-
from_state: fromState,
|
|
1117
|
-
to_state: transition2.to,
|
|
1118
|
-
actions_executed: allActionsExecuted
|
|
1119
|
-
};
|
|
1120
|
-
}
|
|
1121
|
-
async drainAutoTransitions() {
|
|
1122
|
-
for (let depth = 0; depth < MAX_AUTO_CHAIN; depth++) {
|
|
1123
|
-
if (this.instance.status !== "ACTIVE") break;
|
|
1124
|
-
const autoTransition = this.findMatchingAutoTransition();
|
|
1125
|
-
if (!autoTransition) break;
|
|
1126
|
-
const result = await this.executeTransition(autoTransition);
|
|
1127
|
-
if (!result.success) break;
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
findMatchingAutoTransition() {
|
|
1131
|
-
const candidates = this.instance.definition.transitions.filter(
|
|
1132
|
-
(t) => t.auto && t.from.includes(this.instance.current_state)
|
|
1133
|
-
);
|
|
1134
|
-
const ctx = this.buildContext();
|
|
1135
|
-
for (const candidate of candidates) {
|
|
1136
|
-
if (!candidate.conditions || candidate.conditions.length === 0) {
|
|
1137
|
-
return candidate;
|
|
1138
|
-
}
|
|
1139
|
-
const allMet = candidate.conditions.every((condition) => {
|
|
1140
|
-
const result = this.evaluator.evaluate(condition, ctx);
|
|
1141
|
-
return result.value === true;
|
|
1142
|
-
});
|
|
1143
|
-
if (allMet) return candidate;
|
|
1144
|
-
}
|
|
1145
|
-
return null;
|
|
1146
|
-
}
|
|
1147
|
-
async executeActions(actions, collector) {
|
|
1148
|
-
const ctx = this.buildContext();
|
|
1149
|
-
for (const action2 of actions) {
|
|
1150
|
-
if (action2.condition) {
|
|
1151
|
-
const condResult = this.evaluator.evaluate(action2.condition, ctx);
|
|
1152
|
-
if (!condResult.value) continue;
|
|
1153
|
-
}
|
|
1154
|
-
const handler = this.actionHandlers.get(action2.type);
|
|
1155
|
-
if (handler) {
|
|
1156
|
-
try {
|
|
1157
|
-
await handler(action2, ctx);
|
|
1158
|
-
collector.push(action2);
|
|
1159
|
-
this.emit({
|
|
1160
|
-
type: "action_executed",
|
|
1161
|
-
instance_id: this.instance.definition.id,
|
|
1162
|
-
action: action2
|
|
1163
|
-
});
|
|
1164
|
-
} catch (error) {
|
|
1165
|
-
this.emit({
|
|
1166
|
-
type: "error",
|
|
1167
|
-
instance_id: this.instance.definition.id,
|
|
1168
|
-
action: action2,
|
|
1169
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1170
|
-
});
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
buildContext() {
|
|
1176
|
-
return {
|
|
1177
|
-
state_data: this.instance.state_data,
|
|
1178
|
-
memory: this.instance.memory,
|
|
1179
|
-
current_state: this.instance.current_state,
|
|
1180
|
-
status: this.instance.status,
|
|
1181
|
-
// Spread state_data for direct field access (e.g., "title" instead of "state_data.title")
|
|
1182
|
-
...this.instance.state_data
|
|
1183
|
-
};
|
|
1184
|
-
}
|
|
1185
|
-
emit(event) {
|
|
1186
|
-
for (const listener of this.listeners) {
|
|
1187
|
-
try {
|
|
1188
|
-
listener(event);
|
|
1189
|
-
} catch {
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
};
|
|
1194
|
-
var patternCache = /* @__PURE__ */ new Map();
|
|
1195
|
-
var MAX_CACHE2 = 200;
|
|
1196
|
-
function compilePattern(pattern) {
|
|
1197
|
-
const cached = patternCache.get(pattern);
|
|
1198
|
-
if (cached) return cached;
|
|
1199
|
-
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<DOUBLESTAR>>").replace(/\*/g, "[^:.]+").replace(/<<DOUBLESTAR>>/g, ".*");
|
|
1200
|
-
const regex = new RegExp(`^${escaped}$`);
|
|
1201
|
-
if (patternCache.size >= MAX_CACHE2) {
|
|
1202
|
-
const firstKey = patternCache.keys().next().value;
|
|
1203
|
-
if (firstKey) patternCache.delete(firstKey);
|
|
1204
|
-
}
|
|
1205
|
-
patternCache.set(pattern, regex);
|
|
1206
|
-
return regex;
|
|
1207
|
-
}
|
|
1208
|
-
function matchTopic(pattern, topic) {
|
|
1209
|
-
return pattern.test(topic);
|
|
1210
|
-
}
|
|
1211
|
-
var EventBus = class {
|
|
1212
|
-
subscriptions = [];
|
|
1213
|
-
/**
|
|
1214
|
-
* Subscribe to events matching a glob pattern.
|
|
1215
|
-
* Returns an unsubscribe function.
|
|
1216
|
-
*/
|
|
1217
|
-
subscribe(pattern, handler) {
|
|
1218
|
-
const regex = compilePattern(pattern);
|
|
1219
|
-
const subscription = { pattern, regex, handler };
|
|
1220
|
-
this.subscriptions.push(subscription);
|
|
1221
|
-
return () => {
|
|
1222
|
-
const idx = this.subscriptions.indexOf(subscription);
|
|
1223
|
-
if (idx !== -1) this.subscriptions.splice(idx, 1);
|
|
1224
|
-
};
|
|
1225
|
-
}
|
|
1226
|
-
/**
|
|
1227
|
-
* Publish an event. All matching subscriptions fire (async).
|
|
1228
|
-
* Errors in handlers are caught and logged, never propagated.
|
|
1229
|
-
*/
|
|
1230
|
-
async publish(topic, payload = {}) {
|
|
1231
|
-
const event = { topic, payload };
|
|
1232
|
-
for (const sub of this.subscriptions) {
|
|
1233
|
-
if (matchTopic(sub.regex, topic)) {
|
|
1234
|
-
try {
|
|
1235
|
-
await sub.handler(event);
|
|
1236
|
-
} catch (error) {
|
|
1237
|
-
console.warn(
|
|
1238
|
-
`[player-core] Event handler error for pattern "${sub.pattern}" on topic "${topic}":`,
|
|
1239
|
-
error
|
|
1240
|
-
);
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
/**
|
|
1246
|
-
* Publish synchronously (fire-and-forget).
|
|
1247
|
-
* Useful when you don't need to await handler completion.
|
|
1248
|
-
*/
|
|
1249
|
-
emit(topic, payload = {}) {
|
|
1250
|
-
void this.publish(topic, payload);
|
|
1251
|
-
}
|
|
1252
|
-
/** Get count of active subscriptions */
|
|
1253
|
-
get size() {
|
|
1254
|
-
return this.subscriptions.length;
|
|
1255
|
-
}
|
|
1256
|
-
/** Remove all subscriptions */
|
|
1257
|
-
clear() {
|
|
1258
|
-
this.subscriptions.length = 0;
|
|
1259
|
-
}
|
|
1260
|
-
};
|
|
1261
|
-
var ActionDispatcher = class {
|
|
1262
|
-
handlers = /* @__PURE__ */ new Map();
|
|
1263
|
-
/** Register a handler for an action type */
|
|
1264
|
-
register(type, handler) {
|
|
1265
|
-
this.handlers.set(type, handler);
|
|
1266
|
-
}
|
|
1267
|
-
/** Unregister a handler */
|
|
1268
|
-
unregister(type) {
|
|
1269
|
-
this.handlers.delete(type);
|
|
1270
|
-
}
|
|
1271
|
-
/** Check if a handler is registered for the given type */
|
|
1272
|
-
has(type) {
|
|
1273
|
-
return this.handlers.has(type);
|
|
1274
|
-
}
|
|
1275
|
-
/**
|
|
1276
|
-
* Execute a list of actions sequentially.
|
|
1277
|
-
* Each action's condition is evaluated first (if present).
|
|
1278
|
-
* Missing handlers are skipped with a warning.
|
|
1279
|
-
*/
|
|
1280
|
-
async execute(actions, context, evaluator) {
|
|
1281
|
-
const results = [];
|
|
1282
|
-
for (const action2 of actions) {
|
|
1283
|
-
if (action2.condition && evaluator) {
|
|
1284
|
-
const condResult = evaluator.evaluate(action2.condition, context);
|
|
1285
|
-
if (!condResult.value) continue;
|
|
1286
|
-
}
|
|
1287
|
-
const handler = this.handlers.get(action2.type);
|
|
1288
|
-
if (!handler) {
|
|
1289
|
-
console.warn(`[player-core] No handler registered for action type "${action2.type}"`);
|
|
1290
|
-
results.push({ type: action2.type, success: false, error: `No handler for "${action2.type}"` });
|
|
1291
|
-
continue;
|
|
1292
|
-
}
|
|
1293
|
-
try {
|
|
1294
|
-
await handler(action2.config, context);
|
|
1295
|
-
results.push({ type: action2.type, success: true });
|
|
1296
|
-
} catch (error) {
|
|
1297
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1298
|
-
console.warn(`[player-core] Action "${action2.type}" failed: ${message}`);
|
|
1299
|
-
results.push({ type: action2.type, success: false, error: message });
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
return results;
|
|
1303
|
-
}
|
|
1304
|
-
/** Get count of registered handlers */
|
|
1305
|
-
get size() {
|
|
1306
|
-
return this.handlers.size;
|
|
1307
|
-
}
|
|
1308
|
-
/** Remove all handlers */
|
|
1309
|
-
clear() {
|
|
1310
|
-
this.handlers.clear();
|
|
1311
|
-
}
|
|
1312
|
-
};
|
|
1313
|
-
|
|
1314
286
|
// src/core/WorkflowRuntime.ts
|
|
287
|
+
var import_player_core = require("@mmapp/player-core");
|
|
1315
288
|
var WorkflowRuntime = class {
|
|
1316
289
|
sm;
|
|
1317
290
|
eventBus;
|
|
@@ -1319,9 +292,9 @@ var WorkflowRuntime = class {
|
|
|
1319
292
|
evaluator;
|
|
1320
293
|
listeners = /* @__PURE__ */ new Set();
|
|
1321
294
|
constructor(config) {
|
|
1322
|
-
this.evaluator = createEvaluator({
|
|
295
|
+
this.evaluator = (0, import_player_core.createEvaluator)({
|
|
1323
296
|
functions: [],
|
|
1324
|
-
failurePolicy: WEB_FAILURE_POLICIES.EVENT_REACTION
|
|
297
|
+
failurePolicy: import_player_core.WEB_FAILURE_POLICIES.EVENT_REACTION
|
|
1325
298
|
});
|
|
1326
299
|
const actionHandlers = /* @__PURE__ */ new Map();
|
|
1327
300
|
if (config.actionHandlers) {
|
|
@@ -1343,14 +316,14 @@ var WorkflowRuntime = class {
|
|
|
1343
316
|
smRef.setMemory(action2.config.key, action2.config.value);
|
|
1344
317
|
}
|
|
1345
318
|
});
|
|
1346
|
-
this.sm = new StateMachine(
|
|
319
|
+
this.sm = new import_player_core.StateMachine(
|
|
1347
320
|
config.definition,
|
|
1348
321
|
config.initialData ?? {},
|
|
1349
322
|
{ evaluator: this.evaluator, actionHandlers }
|
|
1350
323
|
);
|
|
1351
324
|
smRef = this.sm;
|
|
1352
|
-
this.eventBus = new EventBus();
|
|
1353
|
-
this.dispatcher = new ActionDispatcher();
|
|
325
|
+
this.eventBus = new import_player_core.EventBus();
|
|
326
|
+
this.dispatcher = new import_player_core.ActionDispatcher();
|
|
1354
327
|
this.dispatcher.register("set_field", (cfg) => {
|
|
1355
328
|
if (smRef && typeof cfg.field === "string") {
|
|
1356
329
|
smRef.setField(cfg.field, cfg.value);
|
|
@@ -1410,24 +383,24 @@ var import_react2 = require("react");
|
|
|
1410
383
|
var import_react = require("react");
|
|
1411
384
|
var RuntimeContext = (0, import_react.createContext)(null);
|
|
1412
385
|
function useRuntimeContext() {
|
|
1413
|
-
const
|
|
1414
|
-
if (!
|
|
386
|
+
const runtime2 = (0, import_react.useContext)(RuntimeContext);
|
|
387
|
+
if (!runtime2) {
|
|
1415
388
|
throw new Error(
|
|
1416
389
|
"useRuntimeContext must be used within a WorkflowProvider or RuntimeContext.Provider"
|
|
1417
390
|
);
|
|
1418
391
|
}
|
|
1419
|
-
return
|
|
392
|
+
return runtime2;
|
|
1420
393
|
}
|
|
1421
394
|
|
|
1422
395
|
// src/hooks/useOnEnter.ts
|
|
1423
396
|
function useOnEnter(stateName, effect) {
|
|
1424
|
-
const
|
|
397
|
+
const runtime2 = useRuntimeContext();
|
|
1425
398
|
const effectRef = (0, import_react2.useRef)(effect);
|
|
1426
399
|
effectRef.current = effect;
|
|
1427
400
|
const cleanupRef = (0, import_react2.useRef)(null);
|
|
1428
401
|
const states = Array.isArray(stateName) ? stateName : [stateName];
|
|
1429
402
|
(0, import_react2.useEffect)(() => {
|
|
1430
|
-
if (states.includes(
|
|
403
|
+
if (states.includes(runtime2.sm.currentState)) {
|
|
1431
404
|
const result = effectRef.current();
|
|
1432
405
|
if (result instanceof Promise) {
|
|
1433
406
|
result.then((cleanup) => {
|
|
@@ -1437,7 +410,7 @@ function useOnEnter(stateName, effect) {
|
|
|
1437
410
|
cleanupRef.current = result;
|
|
1438
411
|
}
|
|
1439
412
|
}
|
|
1440
|
-
const unsub =
|
|
413
|
+
const unsub = runtime2.sm.on((event) => {
|
|
1441
414
|
if (event.type === "state_enter" && event.to_state && states.includes(event.to_state)) {
|
|
1442
415
|
cleanupRef.current?.();
|
|
1443
416
|
const result = effectRef.current();
|
|
@@ -1458,34 +431,34 @@ function useOnEnter(stateName, effect) {
|
|
|
1458
431
|
unsub();
|
|
1459
432
|
cleanupRef.current?.();
|
|
1460
433
|
};
|
|
1461
|
-
}, [
|
|
434
|
+
}, [runtime2, ...states]);
|
|
1462
435
|
}
|
|
1463
436
|
|
|
1464
437
|
// src/hooks/useOnExit.ts
|
|
1465
438
|
var import_react3 = require("react");
|
|
1466
439
|
function useOnExit(stateName, effect) {
|
|
1467
|
-
const
|
|
440
|
+
const runtime2 = useRuntimeContext();
|
|
1468
441
|
const effectRef = (0, import_react3.useRef)(effect);
|
|
1469
442
|
effectRef.current = effect;
|
|
1470
443
|
const states = Array.isArray(stateName) ? stateName : [stateName];
|
|
1471
444
|
(0, import_react3.useEffect)(() => {
|
|
1472
|
-
const unsub =
|
|
445
|
+
const unsub = runtime2.sm.on((event) => {
|
|
1473
446
|
if (event.type === "state_exit" && event.from_state && states.includes(event.from_state)) {
|
|
1474
447
|
effectRef.current();
|
|
1475
448
|
}
|
|
1476
449
|
});
|
|
1477
450
|
return unsub;
|
|
1478
|
-
}, [
|
|
451
|
+
}, [runtime2, ...states]);
|
|
1479
452
|
}
|
|
1480
453
|
|
|
1481
454
|
// src/hooks/useOnTransition.ts
|
|
1482
455
|
var import_react4 = require("react");
|
|
1483
456
|
function useOnTransition(effect) {
|
|
1484
|
-
const
|
|
457
|
+
const runtime2 = useRuntimeContext();
|
|
1485
458
|
const effectRef = (0, import_react4.useRef)(effect);
|
|
1486
459
|
effectRef.current = effect;
|
|
1487
460
|
(0, import_react4.useEffect)(() => {
|
|
1488
|
-
const unsub =
|
|
461
|
+
const unsub = runtime2.sm.on((event) => {
|
|
1489
462
|
if (event.type === "transition") {
|
|
1490
463
|
effectRef.current({
|
|
1491
464
|
from: event.from_state,
|
|
@@ -1494,33 +467,33 @@ function useOnTransition(effect) {
|
|
|
1494
467
|
}
|
|
1495
468
|
});
|
|
1496
469
|
return unsub;
|
|
1497
|
-
}, [
|
|
470
|
+
}, [runtime2]);
|
|
1498
471
|
}
|
|
1499
472
|
|
|
1500
473
|
// src/hooks/useOnEvent.ts
|
|
1501
474
|
var import_react5 = require("react");
|
|
1502
475
|
function useOnEvent(pattern, handler, options) {
|
|
1503
|
-
const
|
|
476
|
+
const runtime2 = useRuntimeContext();
|
|
1504
477
|
const handlerRef = (0, import_react5.useRef)(handler);
|
|
1505
478
|
handlerRef.current = handler;
|
|
1506
479
|
(0, import_react5.useEffect)(() => {
|
|
1507
|
-
const unsub =
|
|
1508
|
-
if (options?.while &&
|
|
480
|
+
const unsub = runtime2.eventBus.subscribe(pattern, (event) => {
|
|
481
|
+
if (options?.while && runtime2.sm.currentState !== options.while) return;
|
|
1509
482
|
handlerRef.current(event);
|
|
1510
483
|
});
|
|
1511
484
|
return unsub;
|
|
1512
|
-
}, [
|
|
485
|
+
}, [runtime2, pattern, options?.while]);
|
|
1513
486
|
}
|
|
1514
487
|
|
|
1515
488
|
// src/hooks/useOnChange.ts
|
|
1516
489
|
var import_react6 = require("react");
|
|
1517
490
|
function useOnChange(field2, handler) {
|
|
1518
|
-
const
|
|
491
|
+
const runtime2 = useRuntimeContext();
|
|
1519
492
|
const handlerRef = (0, import_react6.useRef)(handler);
|
|
1520
493
|
handlerRef.current = handler;
|
|
1521
|
-
const prevRef = (0, import_react6.useRef)(
|
|
494
|
+
const prevRef = (0, import_react6.useRef)(runtime2.sm.stateData[field2]);
|
|
1522
495
|
(0, import_react6.useEffect)(() => {
|
|
1523
|
-
const unsub =
|
|
496
|
+
const unsub = runtime2.subscribe((snap) => {
|
|
1524
497
|
const newVal = snap.stateData[field2];
|
|
1525
498
|
if (newVal !== prevRef.current) {
|
|
1526
499
|
handlerRef.current(newVal, prevRef.current);
|
|
@@ -1528,13 +501,13 @@ function useOnChange(field2, handler) {
|
|
|
1528
501
|
}
|
|
1529
502
|
});
|
|
1530
503
|
return unsub;
|
|
1531
|
-
}, [
|
|
504
|
+
}, [runtime2, field2]);
|
|
1532
505
|
}
|
|
1533
506
|
|
|
1534
507
|
// src/hooks/useWhileIn.ts
|
|
1535
508
|
var import_react7 = require("react");
|
|
1536
509
|
function useWhileIn(stateName, intervalMs, effect) {
|
|
1537
|
-
const
|
|
510
|
+
const runtime2 = useRuntimeContext();
|
|
1538
511
|
const effectRef = (0, import_react7.useRef)(effect);
|
|
1539
512
|
effectRef.current = effect;
|
|
1540
513
|
(0, import_react7.useEffect)(() => {
|
|
@@ -1549,8 +522,8 @@ function useWhileIn(stateName, intervalMs, effect) {
|
|
|
1549
522
|
timer = null;
|
|
1550
523
|
}
|
|
1551
524
|
}
|
|
1552
|
-
if (
|
|
1553
|
-
const unsub =
|
|
525
|
+
if (runtime2.sm.currentState === stateName) startInterval();
|
|
526
|
+
const unsub = runtime2.sm.on((event) => {
|
|
1554
527
|
if (event.type === "state_enter" && event.to_state === stateName) startInterval();
|
|
1555
528
|
if (event.type === "state_exit" && event.from_state === stateName) stopInterval();
|
|
1556
529
|
});
|
|
@@ -1558,13 +531,13 @@ function useWhileIn(stateName, intervalMs, effect) {
|
|
|
1558
531
|
unsub();
|
|
1559
532
|
stopInterval();
|
|
1560
533
|
};
|
|
1561
|
-
}, [
|
|
534
|
+
}, [runtime2, stateName, intervalMs]);
|
|
1562
535
|
}
|
|
1563
536
|
|
|
1564
537
|
// src/hooks/useDuringAction.ts
|
|
1565
538
|
var import_react8 = require("react");
|
|
1566
539
|
function useDuringAction(config) {
|
|
1567
|
-
const
|
|
540
|
+
const runtime2 = useRuntimeContext();
|
|
1568
541
|
const actionRef = (0, import_react8.useRef)(config.action);
|
|
1569
542
|
actionRef.current = config.action;
|
|
1570
543
|
const states = Array.isArray(config.state) ? config.state : [config.state];
|
|
@@ -1602,10 +575,10 @@ function useDuringAction(config) {
|
|
|
1602
575
|
timer = null;
|
|
1603
576
|
}
|
|
1604
577
|
}
|
|
1605
|
-
if (states.includes(
|
|
578
|
+
if (states.includes(runtime2.sm.currentState)) {
|
|
1606
579
|
startAction();
|
|
1607
580
|
}
|
|
1608
|
-
const unsub =
|
|
581
|
+
const unsub = runtime2.sm.on((event) => {
|
|
1609
582
|
if (event.type === "state_enter" && event.to_state && states.includes(event.to_state)) {
|
|
1610
583
|
startAction();
|
|
1611
584
|
}
|
|
@@ -1617,7 +590,7 @@ function useDuringAction(config) {
|
|
|
1617
590
|
unsub();
|
|
1618
591
|
stopAction();
|
|
1619
592
|
};
|
|
1620
|
-
}, [
|
|
593
|
+
}, [runtime2, intervalMs, immediate, enabled, ...states]);
|
|
1621
594
|
}
|
|
1622
595
|
|
|
1623
596
|
// src/hooks/useQuery.ts
|
|
@@ -2110,29 +1083,29 @@ function useServerState(instanceId, options = {}) {
|
|
|
2110
1083
|
// src/hooks/useWorkflow.ts
|
|
2111
1084
|
var import_react15 = require("react");
|
|
2112
1085
|
function useWorkflow(definition, options) {
|
|
2113
|
-
const
|
|
1086
|
+
const runtime2 = (0, import_react15.useMemo)(() => new WorkflowRuntime({
|
|
2114
1087
|
definition,
|
|
2115
1088
|
initialData: options?.initialData,
|
|
2116
1089
|
actionHandlers: options?.actionHandlers
|
|
2117
1090
|
}), [definition.id]);
|
|
2118
|
-
const [snapshot, setSnapshot] = (0, import_react15.useState)(() =>
|
|
1091
|
+
const [snapshot, setSnapshot] = (0, import_react15.useState)(() => runtime2.getSnapshot());
|
|
2119
1092
|
(0, import_react15.useEffect)(() => {
|
|
2120
|
-
const unsub =
|
|
1093
|
+
const unsub = runtime2.subscribe(setSnapshot);
|
|
2121
1094
|
return unsub;
|
|
2122
|
-
}, [
|
|
1095
|
+
}, [runtime2]);
|
|
2123
1096
|
const transition2 = (0, import_react15.useCallback)(async (name, data) => {
|
|
2124
|
-
const result = await
|
|
1097
|
+
const result = await runtime2.transition(name, data);
|
|
2125
1098
|
options?.onTransition?.(result);
|
|
2126
1099
|
return result;
|
|
2127
|
-
}, [
|
|
1100
|
+
}, [runtime2, options?.onTransition]);
|
|
2128
1101
|
const handle = {
|
|
2129
1102
|
slug: definition.slug,
|
|
2130
1103
|
...snapshot,
|
|
2131
1104
|
transition: transition2,
|
|
2132
|
-
setField:
|
|
2133
|
-
setMemory:
|
|
2134
|
-
publishEvent:
|
|
2135
|
-
runtime
|
|
1105
|
+
setField: runtime2.setField.bind(runtime2),
|
|
1106
|
+
setMemory: runtime2.setMemory.bind(runtime2),
|
|
1107
|
+
publishEvent: runtime2.publishEvent.bind(runtime2),
|
|
1108
|
+
runtime: runtime2
|
|
2136
1109
|
};
|
|
2137
1110
|
return handle;
|
|
2138
1111
|
}
|
|
@@ -2140,17 +1113,17 @@ function useWorkflow(definition, options) {
|
|
|
2140
1113
|
// src/hooks/useTransition.ts
|
|
2141
1114
|
var import_react16 = require("react");
|
|
2142
1115
|
function useTransition(transitionName, _config) {
|
|
2143
|
-
const
|
|
1116
|
+
const runtime2 = useRuntimeContext();
|
|
2144
1117
|
const [pending, setPending] = (0, import_react16.useState)(false);
|
|
2145
|
-
const available =
|
|
1118
|
+
const available = runtime2.sm.getAvailableTransitions().some((t) => t.name === transitionName);
|
|
2146
1119
|
const fire = (0, import_react16.useCallback)(async (data) => {
|
|
2147
1120
|
setPending(true);
|
|
2148
1121
|
try {
|
|
2149
|
-
return await
|
|
1122
|
+
return await runtime2.transition(transitionName, data);
|
|
2150
1123
|
} finally {
|
|
2151
1124
|
setPending(false);
|
|
2152
1125
|
}
|
|
2153
|
-
}, [
|
|
1126
|
+
}, [runtime2, transitionName]);
|
|
2154
1127
|
const handle = { fire, available, pending };
|
|
2155
1128
|
return handle;
|
|
2156
1129
|
}
|
|
@@ -2162,12 +1135,12 @@ function setRoleHierarchy(hierarchy) {
|
|
|
2162
1135
|
_globalHierarchy = hierarchy;
|
|
2163
1136
|
}
|
|
2164
1137
|
function useRole(roleName, options = {}) {
|
|
2165
|
-
const
|
|
1138
|
+
const runtime2 = useRuntimeContext();
|
|
2166
1139
|
const hierarchy = options.hierarchy ?? _globalHierarchy ?? [];
|
|
2167
1140
|
const inheritPermissions = options.inheritPermissions ?? true;
|
|
2168
1141
|
const result = (0, import_react17.useMemo)(() => {
|
|
2169
|
-
const snapshot =
|
|
2170
|
-
const definition =
|
|
1142
|
+
const snapshot = runtime2.getSnapshot();
|
|
1143
|
+
const definition = runtime2.config?.definition;
|
|
2171
1144
|
const userRoles = snapshot.stateData?._userRoles ?? snapshot.stateData?.user_roles ?? [];
|
|
2172
1145
|
let hasRole2 = userRoles.includes(roleName);
|
|
2173
1146
|
if (!hasRole2 && hierarchy.length > 0) {
|
|
@@ -2215,7 +1188,7 @@ function useRole(roleName, options = {}) {
|
|
|
2215
1188
|
}
|
|
2216
1189
|
}
|
|
2217
1190
|
return { hasRole: hasRole2, permissions, roles: userRoles, highestRole };
|
|
2218
|
-
}, [
|
|
1191
|
+
}, [runtime2, roleName, hierarchy, inheritPermissions]);
|
|
2219
1192
|
const isAbove = (0, import_react17.useCallback)(
|
|
2220
1193
|
(role) => {
|
|
2221
1194
|
if (hierarchy.length === 0) return false;
|
|
@@ -2266,21 +1239,21 @@ function useRole(roleName, options = {}) {
|
|
|
2266
1239
|
// src/hooks/useParams.ts
|
|
2267
1240
|
var import_react18 = require("react");
|
|
2268
1241
|
function useParams() {
|
|
2269
|
-
const
|
|
1242
|
+
const runtime2 = useRuntimeContext();
|
|
2270
1243
|
return (0, import_react18.useMemo)(() => {
|
|
2271
|
-
const snapshot =
|
|
1244
|
+
const snapshot = runtime2.getSnapshot();
|
|
2272
1245
|
const params = snapshot.stateData?._params ?? snapshot.memory?._callParams ?? {};
|
|
2273
1246
|
return params;
|
|
2274
|
-
}, [
|
|
1247
|
+
}, [runtime2]);
|
|
2275
1248
|
}
|
|
2276
1249
|
|
|
2277
1250
|
// src/hooks/usePackage.ts
|
|
2278
1251
|
var import_react19 = require("react");
|
|
2279
1252
|
function usePackage(packageSlug) {
|
|
2280
|
-
const
|
|
1253
|
+
const runtime2 = useRuntimeContext();
|
|
2281
1254
|
return (0, import_react19.useMemo)(() => {
|
|
2282
|
-
const snapshot =
|
|
2283
|
-
const definition =
|
|
1255
|
+
const snapshot = runtime2.getSnapshot();
|
|
1256
|
+
const definition = runtime2.config?.definition;
|
|
2284
1257
|
const childDefs = definition?.child_definitions ?? [];
|
|
2285
1258
|
const metadata = definition?.metadata ?? {};
|
|
2286
1259
|
if (definition?.slug === packageSlug && definition?.category === "blueprint") {
|
|
@@ -2343,7 +1316,7 @@ function usePackage(packageSlug) {
|
|
|
2343
1316
|
isResolved: false,
|
|
2344
1317
|
dependencySlugs: []
|
|
2345
1318
|
};
|
|
2346
|
-
}, [
|
|
1319
|
+
}, [runtime2, packageSlug]);
|
|
2347
1320
|
}
|
|
2348
1321
|
|
|
2349
1322
|
// src/hooks/useRouter.ts
|
|
@@ -2469,16 +1442,16 @@ function useRouter(options = {}) {
|
|
|
2469
1442
|
};
|
|
2470
1443
|
setIsNavigating(true);
|
|
2471
1444
|
try {
|
|
2472
|
-
for (const
|
|
2473
|
-
const allowed = await
|
|
1445
|
+
for (const guard2 of guardsRef.current) {
|
|
1446
|
+
const allowed = await guard2(to, location);
|
|
2474
1447
|
if (!allowed) {
|
|
2475
1448
|
onRejectRef.current?.(to);
|
|
2476
1449
|
return false;
|
|
2477
1450
|
}
|
|
2478
1451
|
}
|
|
2479
1452
|
if (found?.route?.guards) {
|
|
2480
|
-
for (const
|
|
2481
|
-
const allowed = await
|
|
1453
|
+
for (const guard2 of found.route.guards) {
|
|
1454
|
+
const allowed = await guard2(to, location);
|
|
2482
1455
|
if (!allowed) {
|
|
2483
1456
|
if (found.route.redirectOnFail) {
|
|
2484
1457
|
const fullRedirect = basePathRef.current + found.route.redirectOnFail;
|
|
@@ -2904,7 +1877,7 @@ function useGeolocation(options = {}) {
|
|
|
2904
1877
|
const {
|
|
2905
1878
|
enableHighAccuracy = false,
|
|
2906
1879
|
maximumAge = 0,
|
|
2907
|
-
timeout = 1e4,
|
|
1880
|
+
timeout: timeout2 = 1e4,
|
|
2908
1881
|
watch = false,
|
|
2909
1882
|
enabled = true
|
|
2910
1883
|
} = options;
|
|
@@ -2915,8 +1888,8 @@ function useGeolocation(options = {}) {
|
|
|
2915
1888
|
const watchIdRef = (0, import_react24.useRef)(null);
|
|
2916
1889
|
const supported = typeof navigator !== "undefined" && "geolocation" in navigator;
|
|
2917
1890
|
const positionOptions = (0, import_react24.useMemo)(
|
|
2918
|
-
() => ({ enableHighAccuracy, maximumAge, timeout }),
|
|
2919
|
-
[enableHighAccuracy, maximumAge,
|
|
1891
|
+
() => ({ enableHighAccuracy, maximumAge, timeout: timeout2 }),
|
|
1892
|
+
[enableHighAccuracy, maximumAge, timeout2]
|
|
2920
1893
|
);
|
|
2921
1894
|
const handleSuccess = (0, import_react24.useCallback)((pos) => {
|
|
2922
1895
|
setPosition({
|
|
@@ -3276,7 +2249,7 @@ var import_react27 = require("react");
|
|
|
3276
2249
|
function useForm(config) {
|
|
3277
2250
|
const {
|
|
3278
2251
|
initialValues,
|
|
3279
|
-
validate,
|
|
2252
|
+
validate: validate2,
|
|
3280
2253
|
fieldValidators,
|
|
3281
2254
|
onSubmit,
|
|
3282
2255
|
onError,
|
|
@@ -3289,8 +2262,8 @@ function useForm(config) {
|
|
|
3289
2262
|
const [isSubmitting, setIsSubmitting] = (0, import_react27.useState)(false);
|
|
3290
2263
|
const [submitCount, setSubmitCount] = (0, import_react27.useState)(0);
|
|
3291
2264
|
const initialRef = (0, import_react27.useRef)(initialValues);
|
|
3292
|
-
const validateRef = (0, import_react27.useRef)(
|
|
3293
|
-
validateRef.current =
|
|
2265
|
+
const validateRef = (0, import_react27.useRef)(validate2);
|
|
2266
|
+
validateRef.current = validate2;
|
|
3294
2267
|
const fieldValidatorsRef = (0, import_react27.useRef)(fieldValidators);
|
|
3295
2268
|
fieldValidatorsRef.current = fieldValidators;
|
|
3296
2269
|
const onSubmitRef = (0, import_react27.useRef)(onSubmit);
|
|
@@ -3507,7 +2480,7 @@ function useNotification() {
|
|
|
3507
2480
|
setPermission(result);
|
|
3508
2481
|
return result;
|
|
3509
2482
|
}, [supported]);
|
|
3510
|
-
const
|
|
2483
|
+
const notify3 = (0, import_react28.useCallback)(
|
|
3511
2484
|
(title, options = {}) => {
|
|
3512
2485
|
if (!supported || permission !== "granted") return null;
|
|
3513
2486
|
const {
|
|
@@ -3540,8 +2513,8 @@ function useNotification() {
|
|
|
3540
2513
|
[supported, permission]
|
|
3541
2514
|
);
|
|
3542
2515
|
return (0, import_react28.useMemo)(
|
|
3543
|
-
() => ({ permission, supported, requestPermission, notify:
|
|
3544
|
-
[permission, supported, requestPermission,
|
|
2516
|
+
() => ({ permission, supported, requestPermission, notify: notify3 }),
|
|
2517
|
+
[permission, supported, requestPermission, notify3]
|
|
3545
2518
|
);
|
|
3546
2519
|
}
|
|
3547
2520
|
|
|
@@ -3558,12 +2531,12 @@ function notifyListeners() {
|
|
|
3558
2531
|
}
|
|
3559
2532
|
function addToast(config) {
|
|
3560
2533
|
const id = `toast-${++_nextId}`;
|
|
3561
|
-
const
|
|
2534
|
+
const instance2 = {
|
|
3562
2535
|
...config,
|
|
3563
2536
|
id,
|
|
3564
2537
|
createdAt: Date.now()
|
|
3565
2538
|
};
|
|
3566
|
-
_toasts = [..._toasts,
|
|
2539
|
+
_toasts = [..._toasts, instance2];
|
|
3567
2540
|
const duration = config.duration ?? 5e3;
|
|
3568
2541
|
if (duration > 0) {
|
|
3569
2542
|
const timer = setTimeout(() => {
|
|
@@ -3614,8 +2587,191 @@ function useToast() {
|
|
|
3614
2587
|
);
|
|
3615
2588
|
}
|
|
3616
2589
|
|
|
3617
|
-
// src/hooks/
|
|
2590
|
+
// src/hooks/useVisibility.ts
|
|
3618
2591
|
var import_react30 = require("react");
|
|
2592
|
+
function useVisibility(model2, role, playerType) {
|
|
2593
|
+
return (0, import_react30.useMemo)(() => {
|
|
2594
|
+
return computeVisibility(model2, role, playerType);
|
|
2595
|
+
}, [model2, role, playerType]);
|
|
2596
|
+
}
|
|
2597
|
+
function computeVisibility(model2, role, playerType) {
|
|
2598
|
+
const allFields = Object.keys(model2.fields || {});
|
|
2599
|
+
const allStates = Object.keys(model2.states || {});
|
|
2600
|
+
const vis = model2.orchestration?.visibility;
|
|
2601
|
+
if (!vis) {
|
|
2602
|
+
return makeResult(allFields, allStates);
|
|
2603
|
+
}
|
|
2604
|
+
let roleFields;
|
|
2605
|
+
let roleStates;
|
|
2606
|
+
let playerFields;
|
|
2607
|
+
if (role && vis.roles && vis.roles[role]) {
|
|
2608
|
+
const rv = vis.roles[role];
|
|
2609
|
+
roleFields = rv.fields === "*" ? "*" : [...rv.fields];
|
|
2610
|
+
roleStates = rv.states === "*" ? "*" : rv.states ? [...rv.states] : "*";
|
|
2611
|
+
}
|
|
2612
|
+
if (playerType && vis.players && vis.players[playerType]) {
|
|
2613
|
+
const pv = vis.players[playerType];
|
|
2614
|
+
playerFields = pv.fields === "*" ? "*" : [...pv.fields];
|
|
2615
|
+
}
|
|
2616
|
+
if (roleFields === void 0 && playerFields === void 0) {
|
|
2617
|
+
return makeResult(allFields, allStates);
|
|
2618
|
+
}
|
|
2619
|
+
let resolvedFields;
|
|
2620
|
+
if (roleFields === "*" && playerFields === "*") {
|
|
2621
|
+
resolvedFields = allFields;
|
|
2622
|
+
} else if (roleFields === "*") {
|
|
2623
|
+
resolvedFields = playerFields === void 0 ? allFields : playerFields;
|
|
2624
|
+
} else if (playerFields === "*") {
|
|
2625
|
+
resolvedFields = roleFields === void 0 ? allFields : roleFields;
|
|
2626
|
+
} else if (roleFields !== void 0 && playerFields !== void 0) {
|
|
2627
|
+
const roleSet = new Set(roleFields);
|
|
2628
|
+
resolvedFields = playerFields.filter((f) => roleSet.has(f));
|
|
2629
|
+
} else {
|
|
2630
|
+
resolvedFields = roleFields || playerFields || allFields;
|
|
2631
|
+
}
|
|
2632
|
+
const resolvedStates = roleStates === "*" || roleStates === void 0 ? allStates : roleStates;
|
|
2633
|
+
return makeResult(resolvedFields, resolvedStates);
|
|
2634
|
+
}
|
|
2635
|
+
function makeResult(fields, states) {
|
|
2636
|
+
const fieldSet = new Set(fields);
|
|
2637
|
+
const stateSet = new Set(states);
|
|
2638
|
+
return {
|
|
2639
|
+
visibleFields: fields,
|
|
2640
|
+
visibleStates: states,
|
|
2641
|
+
canSeeField: (f) => fieldSet.has(f),
|
|
2642
|
+
canSeeState: (s) => stateSet.has(s)
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
// src/hooks/usePresence.ts
|
|
2647
|
+
var import_react31 = require("react");
|
|
2648
|
+
var PRESENCE_EVENTS = {
|
|
2649
|
+
JOIN: "presence:join",
|
|
2650
|
+
LEAVE: "presence:leave",
|
|
2651
|
+
HEARTBEAT: "presence:heartbeat",
|
|
2652
|
+
EDIT_START: "presence:edit_start",
|
|
2653
|
+
EDIT_STOP: "presence:edit_stop"
|
|
2654
|
+
};
|
|
2655
|
+
function usePresence(instanceId, options = {}) {
|
|
2656
|
+
const {
|
|
2657
|
+
userId = "anonymous",
|
|
2658
|
+
userName = "Anonymous",
|
|
2659
|
+
wsUrl,
|
|
2660
|
+
enabled = true,
|
|
2661
|
+
heartbeatInterval = 15e3,
|
|
2662
|
+
staleTimeout = 45e3
|
|
2663
|
+
} = options;
|
|
2664
|
+
const channelName = `presence:${instanceId}`;
|
|
2665
|
+
const { publish, subscribe, connected } = useChannel(channelName, {
|
|
2666
|
+
wsUrl,
|
|
2667
|
+
enabled
|
|
2668
|
+
});
|
|
2669
|
+
const [viewers, setViewers] = (0, import_react31.useState)([]);
|
|
2670
|
+
const [editors, setEditors] = (0, import_react31.useState)([]);
|
|
2671
|
+
const viewersRef = (0, import_react31.useRef)(/* @__PURE__ */ new Map());
|
|
2672
|
+
const editorsRef = (0, import_react31.useRef)(/* @__PURE__ */ new Map());
|
|
2673
|
+
(0, import_react31.useEffect)(() => {
|
|
2674
|
+
if (!connected || !enabled) return;
|
|
2675
|
+
publish(PRESENCE_EVENTS.JOIN, { id: userId, name: userName, connectedAt: Date.now() });
|
|
2676
|
+
const hb = setInterval(() => {
|
|
2677
|
+
publish(PRESENCE_EVENTS.HEARTBEAT, { id: userId, name: userName });
|
|
2678
|
+
}, heartbeatInterval);
|
|
2679
|
+
return () => {
|
|
2680
|
+
clearInterval(hb);
|
|
2681
|
+
publish(PRESENCE_EVENTS.LEAVE, { id: userId });
|
|
2682
|
+
};
|
|
2683
|
+
}, [connected, enabled, userId, userName, heartbeatInterval, publish]);
|
|
2684
|
+
(0, import_react31.useEffect)(() => {
|
|
2685
|
+
if (!enabled) return;
|
|
2686
|
+
const cleanup = setInterval(() => {
|
|
2687
|
+
const now = Date.now();
|
|
2688
|
+
const stale = [];
|
|
2689
|
+
for (const [id, v] of viewersRef.current) {
|
|
2690
|
+
if (now - v.connectedAt > staleTimeout) stale.push(id);
|
|
2691
|
+
}
|
|
2692
|
+
if (stale.length > 0) {
|
|
2693
|
+
for (const id of stale) {
|
|
2694
|
+
viewersRef.current.delete(id);
|
|
2695
|
+
editorsRef.current.delete(id);
|
|
2696
|
+
}
|
|
2697
|
+
setViewers(Array.from(viewersRef.current.values()));
|
|
2698
|
+
setEditors(Array.from(editorsRef.current.values()));
|
|
2699
|
+
}
|
|
2700
|
+
}, staleTimeout / 3);
|
|
2701
|
+
return () => clearInterval(cleanup);
|
|
2702
|
+
}, [enabled, staleTimeout]);
|
|
2703
|
+
(0, import_react31.useEffect)(() => {
|
|
2704
|
+
if (!enabled) return;
|
|
2705
|
+
const unsubs = [];
|
|
2706
|
+
unsubs.push(subscribe(PRESENCE_EVENTS.JOIN, (data) => {
|
|
2707
|
+
if (data.id === userId) return;
|
|
2708
|
+
viewersRef.current.set(data.id, {
|
|
2709
|
+
id: data.id,
|
|
2710
|
+
name: data.name || "Anonymous",
|
|
2711
|
+
connectedAt: data.connectedAt || Date.now()
|
|
2712
|
+
});
|
|
2713
|
+
setViewers(Array.from(viewersRef.current.values()));
|
|
2714
|
+
}));
|
|
2715
|
+
unsubs.push(subscribe(PRESENCE_EVENTS.LEAVE, (data) => {
|
|
2716
|
+
viewersRef.current.delete(data.id);
|
|
2717
|
+
editorsRef.current.delete(data.id);
|
|
2718
|
+
setViewers(Array.from(viewersRef.current.values()));
|
|
2719
|
+
setEditors(Array.from(editorsRef.current.values()));
|
|
2720
|
+
}));
|
|
2721
|
+
unsubs.push(subscribe(PRESENCE_EVENTS.HEARTBEAT, (data) => {
|
|
2722
|
+
if (data.id === userId) return;
|
|
2723
|
+
const existing = viewersRef.current.get(data.id);
|
|
2724
|
+
if (existing) {
|
|
2725
|
+
existing.connectedAt = Date.now();
|
|
2726
|
+
} else {
|
|
2727
|
+
viewersRef.current.set(data.id, {
|
|
2728
|
+
id: data.id,
|
|
2729
|
+
name: data.name || "Anonymous",
|
|
2730
|
+
connectedAt: Date.now()
|
|
2731
|
+
});
|
|
2732
|
+
setViewers(Array.from(viewersRef.current.values()));
|
|
2733
|
+
}
|
|
2734
|
+
}));
|
|
2735
|
+
unsubs.push(subscribe(PRESENCE_EVENTS.EDIT_START, (data) => {
|
|
2736
|
+
if (data.id === userId) return;
|
|
2737
|
+
editorsRef.current.set(data.id, {
|
|
2738
|
+
id: data.id,
|
|
2739
|
+
name: data.name || "Anonymous",
|
|
2740
|
+
field: data.field,
|
|
2741
|
+
startedAt: Date.now()
|
|
2742
|
+
});
|
|
2743
|
+
setEditors(Array.from(editorsRef.current.values()));
|
|
2744
|
+
}));
|
|
2745
|
+
unsubs.push(subscribe(PRESENCE_EVENTS.EDIT_STOP, (data) => {
|
|
2746
|
+
editorsRef.current.delete(data.id);
|
|
2747
|
+
setEditors(Array.from(editorsRef.current.values()));
|
|
2748
|
+
}));
|
|
2749
|
+
return () => unsubs.forEach((fn) => fn());
|
|
2750
|
+
}, [enabled, userId, subscribe]);
|
|
2751
|
+
const startEditing = (0, import_react31.useCallback)((field2) => {
|
|
2752
|
+
publish(PRESENCE_EVENTS.EDIT_START, { id: userId, name: userName, field: field2 });
|
|
2753
|
+
}, [publish, userId, userName]);
|
|
2754
|
+
const stopEditing = (0, import_react31.useCallback)((_field) => {
|
|
2755
|
+
publish(PRESENCE_EVENTS.EDIT_STOP, { id: userId });
|
|
2756
|
+
}, [publish, userId]);
|
|
2757
|
+
const isEditing = (0, import_react31.useCallback)((field2) => {
|
|
2758
|
+
for (const editor of editorsRef.current.values()) {
|
|
2759
|
+
if (editor.field === field2 && editor.id !== userId) return true;
|
|
2760
|
+
}
|
|
2761
|
+
return false;
|
|
2762
|
+
}, [userId]);
|
|
2763
|
+
return {
|
|
2764
|
+
viewers,
|
|
2765
|
+
editors,
|
|
2766
|
+
viewerCount: viewers.length,
|
|
2767
|
+
isEditing,
|
|
2768
|
+
startEditing,
|
|
2769
|
+
stopEditing
|
|
2770
|
+
};
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2773
|
+
// src/hooks/useMiddleware.ts
|
|
2774
|
+
var import_react32 = require("react");
|
|
3619
2775
|
function requireAuth(loginPath = "/login") {
|
|
3620
2776
|
return (ctx) => {
|
|
3621
2777
|
if (!ctx.token) {
|
|
@@ -3687,24 +2843,24 @@ function useMiddleware(middlewares, options = {}) {
|
|
|
3687
2843
|
watchPathname = true,
|
|
3688
2844
|
onRedirect
|
|
3689
2845
|
} = options;
|
|
3690
|
-
const [ready, setReady] = (0,
|
|
3691
|
-
const [loading, setLoading] = (0,
|
|
3692
|
-
const [redirect, setRedirect] = (0,
|
|
3693
|
-
const [error, setError] = (0,
|
|
3694
|
-
const [data, setData] = (0,
|
|
3695
|
-
const [runKey, setRunKey] = (0,
|
|
3696
|
-
const middlewaresRef = (0,
|
|
2846
|
+
const [ready, setReady] = (0, import_react32.useState)(false);
|
|
2847
|
+
const [loading, setLoading] = (0, import_react32.useState)(true);
|
|
2848
|
+
const [redirect, setRedirect] = (0, import_react32.useState)(null);
|
|
2849
|
+
const [error, setError] = (0, import_react32.useState)(null);
|
|
2850
|
+
const [data, setData] = (0, import_react32.useState)({});
|
|
2851
|
+
const [runKey, setRunKey] = (0, import_react32.useState)(0);
|
|
2852
|
+
const middlewaresRef = (0, import_react32.useRef)(middlewares);
|
|
3697
2853
|
middlewaresRef.current = middlewares;
|
|
3698
|
-
const onRedirectRef = (0,
|
|
2854
|
+
const onRedirectRef = (0, import_react32.useRef)(onRedirect);
|
|
3699
2855
|
onRedirectRef.current = onRedirect;
|
|
3700
|
-
const [pathname, setPathname] = (0,
|
|
3701
|
-
(0,
|
|
2856
|
+
const [pathname, setPathname] = (0, import_react32.useState)(getPathname);
|
|
2857
|
+
(0, import_react32.useEffect)(() => {
|
|
3702
2858
|
if (!watchPathname) return;
|
|
3703
2859
|
const handler = () => setPathname(getPathname());
|
|
3704
2860
|
window.addEventListener("popstate", handler);
|
|
3705
2861
|
return () => window.removeEventListener("popstate", handler);
|
|
3706
2862
|
}, [watchPathname]);
|
|
3707
|
-
(0,
|
|
2863
|
+
(0, import_react32.useEffect)(() => {
|
|
3708
2864
|
if (!enabled) {
|
|
3709
2865
|
setReady(true);
|
|
3710
2866
|
setLoading(false);
|
|
@@ -3751,11 +2907,11 @@ function useMiddleware(middlewares, options = {}) {
|
|
|
3751
2907
|
cancelled = true;
|
|
3752
2908
|
};
|
|
3753
2909
|
}, [enabled, pathname, runKey]);
|
|
3754
|
-
const rerun = (0,
|
|
2910
|
+
const rerun = (0, import_react32.useMemo)(
|
|
3755
2911
|
() => () => setRunKey((k) => k + 1),
|
|
3756
2912
|
[]
|
|
3757
2913
|
);
|
|
3758
|
-
return (0,
|
|
2914
|
+
return (0, import_react32.useMemo)(
|
|
3759
2915
|
() => ({ ready, loading, redirect, error, data, rerun }),
|
|
3760
2916
|
[ready, loading, redirect, error, data, rerun]
|
|
3761
2917
|
);
|
|
@@ -3765,8 +2921,8 @@ function useMiddleware(middlewares, options = {}) {
|
|
|
3765
2921
|
var import_react_query = require("@tanstack/react-query");
|
|
3766
2922
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
3767
2923
|
var defaultQueryClient = new import_react_query.QueryClient();
|
|
3768
|
-
function WorkflowProvider({ runtime, queryClient, children }) {
|
|
3769
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query.QueryClientProvider, { client: queryClient ?? defaultQueryClient, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RuntimeContext.Provider, { value:
|
|
2924
|
+
function WorkflowProvider({ runtime: runtime2, queryClient, children }) {
|
|
2925
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query.QueryClientProvider, { client: queryClient ?? defaultQueryClient, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RuntimeContext.Provider, { value: runtime2, children }) });
|
|
3770
2926
|
}
|
|
3771
2927
|
|
|
3772
2928
|
// src/local/LocalEngine.ts
|
|
@@ -3827,8 +2983,8 @@ var LocalWorkflowEngine = class {
|
|
|
3827
2983
|
* Process all pending events from a transition result.
|
|
3828
2984
|
* Emits locally and returns the events for P2P broadcast.
|
|
3829
2985
|
*/
|
|
3830
|
-
processPendingEvents(
|
|
3831
|
-
const events =
|
|
2986
|
+
processPendingEvents(instance2) {
|
|
2987
|
+
const events = instance2._pendingEvents;
|
|
3832
2988
|
if (!events?.length) return [];
|
|
3833
2989
|
for (const evt of events) {
|
|
3834
2990
|
this.emitEvent(evt);
|
|
@@ -3871,18 +3027,18 @@ var LocalWorkflowEngine = class {
|
|
|
3871
3027
|
};
|
|
3872
3028
|
}
|
|
3873
3029
|
/** Check if a transition can fire from the instance's current state */
|
|
3874
|
-
canTransition(
|
|
3875
|
-
const def = this.definitions.get(
|
|
3030
|
+
canTransition(instance2, transitionName) {
|
|
3031
|
+
const def = this.definitions.get(instance2.definitionSlug);
|
|
3876
3032
|
if (!def) return false;
|
|
3877
3033
|
const transition2 = def.transitions.find((t) => t.name === transitionName);
|
|
3878
3034
|
if (!transition2) return false;
|
|
3879
|
-
return transition2.from.includes(
|
|
3035
|
+
return transition2.from.includes(instance2.currentState);
|
|
3880
3036
|
}
|
|
3881
3037
|
/** Get all transitions available from the instance's current state */
|
|
3882
|
-
getAvailableTransitions(
|
|
3883
|
-
const def = this.definitions.get(
|
|
3038
|
+
getAvailableTransitions(instance2) {
|
|
3039
|
+
const def = this.definitions.get(instance2.definitionSlug);
|
|
3884
3040
|
if (!def) return [];
|
|
3885
|
-
return def.transitions.filter((t) => t.from.includes(
|
|
3041
|
+
return def.transitions.filter((t) => t.from.includes(instance2.currentState)).map((t) => t.name);
|
|
3886
3042
|
}
|
|
3887
3043
|
/**
|
|
3888
3044
|
* Apply a transition, returning a new WorkflowInstance (immutable).
|
|
@@ -3893,29 +3049,29 @@ var LocalWorkflowEngine = class {
|
|
|
3893
3049
|
* @returns New WorkflowInstance with updated state and version
|
|
3894
3050
|
* @throws If transition is not valid from current state
|
|
3895
3051
|
*/
|
|
3896
|
-
applyTransition(
|
|
3897
|
-
const def = this.definitions.get(
|
|
3052
|
+
applyTransition(instance2, transitionName, data) {
|
|
3053
|
+
const def = this.definitions.get(instance2.definitionSlug);
|
|
3898
3054
|
if (!def) {
|
|
3899
|
-
throw new Error(`Definition not found: ${
|
|
3055
|
+
throw new Error(`Definition not found: ${instance2.definitionSlug}`);
|
|
3900
3056
|
}
|
|
3901
3057
|
const transition2 = def.transitions.find((t) => t.name === transitionName);
|
|
3902
3058
|
if (!transition2) {
|
|
3903
3059
|
throw new Error(
|
|
3904
|
-
`Transition "${transitionName}" not found in ${
|
|
3060
|
+
`Transition "${transitionName}" not found in ${instance2.definitionSlug}`
|
|
3905
3061
|
);
|
|
3906
3062
|
}
|
|
3907
|
-
if (!transition2.from.includes(
|
|
3063
|
+
if (!transition2.from.includes(instance2.currentState)) {
|
|
3908
3064
|
throw new Error(
|
|
3909
|
-
`Transition "${transitionName}" cannot fire from state "${
|
|
3065
|
+
`Transition "${transitionName}" cannot fire from state "${instance2.currentState}" (allowed from: ${transition2.from.join(", ")})`
|
|
3910
3066
|
);
|
|
3911
3067
|
}
|
|
3912
|
-
const nextState = transition2.to ??
|
|
3913
|
-
const fields = data ? { ...
|
|
3068
|
+
const nextState = transition2.to ?? instance2.currentState;
|
|
3069
|
+
const fields = data ? { ...instance2.fields, ...data } : { ...instance2.fields };
|
|
3914
3070
|
let result = {
|
|
3915
|
-
...
|
|
3071
|
+
...instance2,
|
|
3916
3072
|
currentState: nextState,
|
|
3917
3073
|
fields,
|
|
3918
|
-
version:
|
|
3074
|
+
version: instance2.version + 1,
|
|
3919
3075
|
updatedAt: Date.now()
|
|
3920
3076
|
};
|
|
3921
3077
|
const targetStateDef = def.states.find((s) => s.name === nextState);
|
|
@@ -3988,23 +3144,23 @@ var LocalWorkflowEngine = class {
|
|
|
3988
3144
|
* Apply a transition only if the incoming version is newer.
|
|
3989
3145
|
* Used for P2P sync — skips stale transitions.
|
|
3990
3146
|
*/
|
|
3991
|
-
applyRemoteTransition(
|
|
3992
|
-
if (remoteVersion <=
|
|
3147
|
+
applyRemoteTransition(instance2, transitionName, data, remoteVersion) {
|
|
3148
|
+
if (remoteVersion <= instance2.version) {
|
|
3993
3149
|
return null;
|
|
3994
3150
|
}
|
|
3995
|
-
if (!this.canTransition(
|
|
3151
|
+
if (!this.canTransition(instance2, transitionName)) {
|
|
3996
3152
|
return null;
|
|
3997
3153
|
}
|
|
3998
|
-
const updated = this.applyTransition(
|
|
3154
|
+
const updated = this.applyTransition(instance2, transitionName, data);
|
|
3999
3155
|
return { ...updated, version: remoteVersion };
|
|
4000
3156
|
}
|
|
4001
3157
|
};
|
|
4002
3158
|
|
|
4003
3159
|
// src/local/LocalEngineContext.ts
|
|
4004
|
-
var
|
|
4005
|
-
var LocalEngineContext = (0,
|
|
3160
|
+
var import_react33 = require("react");
|
|
3161
|
+
var LocalEngineContext = (0, import_react33.createContext)(null);
|
|
4006
3162
|
function useLocalEngine() {
|
|
4007
|
-
return (0,
|
|
3163
|
+
return (0, import_react33.useContext)(LocalEngineContext);
|
|
4008
3164
|
}
|
|
4009
3165
|
var LocalEngineProvider = LocalEngineContext.Provider;
|
|
4010
3166
|
|
|
@@ -4261,6 +3417,155 @@ function defineModel(def) {
|
|
|
4261
3417
|
return def;
|
|
4262
3418
|
}
|
|
4263
3419
|
|
|
3420
|
+
// src/config/orchestration-presets.ts
|
|
3421
|
+
var SOLO = {
|
|
3422
|
+
strategy: "solo",
|
|
3423
|
+
evaluation: { pure: "local" },
|
|
3424
|
+
scheduling: { coordinator: "any" },
|
|
3425
|
+
events: { evaluator: "any-subscriber" },
|
|
3426
|
+
errorHandling: { strategy: "manual" },
|
|
3427
|
+
conflicts: { default: "last-writer-wins", fields: {} },
|
|
3428
|
+
visibility: { roles: {}, players: {} },
|
|
3429
|
+
presence: { enabled: false, showEditing: false, showViewing: false },
|
|
3430
|
+
services: {},
|
|
3431
|
+
actionRouting: {}
|
|
3432
|
+
};
|
|
3433
|
+
var CLIENT_SERVER = {
|
|
3434
|
+
strategy: "client-server",
|
|
3435
|
+
evaluation: { pure: "local" },
|
|
3436
|
+
scheduling: { coordinator: "server" },
|
|
3437
|
+
events: { evaluator: "server" },
|
|
3438
|
+
errorHandling: { strategy: "rollback" },
|
|
3439
|
+
conflicts: { default: "last-writer-wins", fields: {} },
|
|
3440
|
+
visibility: { roles: {}, players: {} },
|
|
3441
|
+
presence: { enabled: false, showEditing: false, showViewing: false },
|
|
3442
|
+
services: {},
|
|
3443
|
+
actionRouting: {}
|
|
3444
|
+
};
|
|
3445
|
+
var MULTI_CLIENT = {
|
|
3446
|
+
strategy: "multi-client",
|
|
3447
|
+
evaluation: { pure: "local" },
|
|
3448
|
+
scheduling: { coordinator: "server" },
|
|
3449
|
+
events: { evaluator: "server" },
|
|
3450
|
+
errorHandling: { strategy: "compensate" },
|
|
3451
|
+
conflicts: { default: "last-writer-wins", fields: {} },
|
|
3452
|
+
visibility: { roles: {}, players: {} },
|
|
3453
|
+
presence: { enabled: true, showEditing: true, showViewing: true, conflictHighlight: true },
|
|
3454
|
+
services: {},
|
|
3455
|
+
actionRouting: {}
|
|
3456
|
+
};
|
|
3457
|
+
var SERVICE_MESH = {
|
|
3458
|
+
strategy: "service-mesh",
|
|
3459
|
+
evaluation: { pure: "local" },
|
|
3460
|
+
scheduling: { coordinator: "server" },
|
|
3461
|
+
events: { evaluator: "all" },
|
|
3462
|
+
errorHandling: { strategy: "saga" },
|
|
3463
|
+
conflicts: { default: "first-write-wins", fields: {} },
|
|
3464
|
+
visibility: { roles: {}, players: {} },
|
|
3465
|
+
presence: { enabled: false, showEditing: false, showViewing: false },
|
|
3466
|
+
services: {},
|
|
3467
|
+
actionRouting: {}
|
|
3468
|
+
};
|
|
3469
|
+
var PEER_TO_PEER = {
|
|
3470
|
+
strategy: "peer-to-peer",
|
|
3471
|
+
evaluation: { pure: "local" },
|
|
3472
|
+
scheduling: { coordinator: "any" },
|
|
3473
|
+
events: { evaluator: "any-subscriber" },
|
|
3474
|
+
errorHandling: { strategy: "compensate" },
|
|
3475
|
+
conflicts: { default: "crdt", fields: {} },
|
|
3476
|
+
visibility: { roles: {}, players: {} },
|
|
3477
|
+
presence: { enabled: true, showEditing: true, showViewing: true, conflictHighlight: false },
|
|
3478
|
+
services: {},
|
|
3479
|
+
actionRouting: {}
|
|
3480
|
+
};
|
|
3481
|
+
var HYBRID = {
|
|
3482
|
+
strategy: "hybrid",
|
|
3483
|
+
evaluation: { pure: "local" },
|
|
3484
|
+
scheduling: { coordinator: "server" },
|
|
3485
|
+
events: { evaluator: "server" },
|
|
3486
|
+
errorHandling: { strategy: "saga" },
|
|
3487
|
+
conflicts: { default: "last-writer-wins", fields: {} },
|
|
3488
|
+
visibility: { roles: {}, players: {} },
|
|
3489
|
+
presence: { enabled: true, showEditing: true, showViewing: false, conflictHighlight: false },
|
|
3490
|
+
services: {},
|
|
3491
|
+
actionRouting: {}
|
|
3492
|
+
};
|
|
3493
|
+
var HEADLESS = {
|
|
3494
|
+
strategy: "headless",
|
|
3495
|
+
evaluation: { pure: "local" },
|
|
3496
|
+
// expression engine runs server-local (native Rust, fastest)
|
|
3497
|
+
scheduling: { coordinator: "server" },
|
|
3498
|
+
// server manages cron/interval/timeout
|
|
3499
|
+
events: { evaluator: "server" },
|
|
3500
|
+
// server matches events, no clients involved
|
|
3501
|
+
errorHandling: { strategy: "compensate" },
|
|
3502
|
+
conflicts: { default: "first-write-wins", fields: {} },
|
|
3503
|
+
// no concurrent clients
|
|
3504
|
+
visibility: { roles: {}, players: {} },
|
|
3505
|
+
presence: { enabled: false, showEditing: false, showViewing: false, conflictHighlight: false },
|
|
3506
|
+
services: {},
|
|
3507
|
+
actionRouting: {}
|
|
3508
|
+
};
|
|
3509
|
+
var ORCHESTRATION_PRESETS = {
|
|
3510
|
+
"solo": SOLO,
|
|
3511
|
+
"client-server": CLIENT_SERVER,
|
|
3512
|
+
"multi-client": MULTI_CLIENT,
|
|
3513
|
+
"service-mesh": SERVICE_MESH,
|
|
3514
|
+
"peer-to-peer": PEER_TO_PEER,
|
|
3515
|
+
"hybrid": HYBRID,
|
|
3516
|
+
"headless": HEADLESS,
|
|
3517
|
+
"custom": CLIENT_SERVER
|
|
3518
|
+
// custom uses client-server as base
|
|
3519
|
+
};
|
|
3520
|
+
var DEFAULT_RESOLVED = {
|
|
3521
|
+
strategy: "client-server",
|
|
3522
|
+
evaluation: { pure: "local" },
|
|
3523
|
+
scheduling: { coordinator: "server" },
|
|
3524
|
+
events: { evaluator: "server" },
|
|
3525
|
+
errorHandling: { strategy: "rollback" },
|
|
3526
|
+
conflicts: { default: "last-writer-wins", fields: {} },
|
|
3527
|
+
visibility: { roles: {}, players: {} },
|
|
3528
|
+
presence: { enabled: false, showEditing: false, showViewing: false, conflictHighlight: false },
|
|
3529
|
+
services: {},
|
|
3530
|
+
actionRouting: {}
|
|
3531
|
+
};
|
|
3532
|
+
function resolveOrchestration(config) {
|
|
3533
|
+
if (!config) return { ...DEFAULT_RESOLVED };
|
|
3534
|
+
const strategy = config.strategy || "client-server";
|
|
3535
|
+
const preset = ORCHESTRATION_PRESETS[strategy] || CLIENT_SERVER;
|
|
3536
|
+
return {
|
|
3537
|
+
strategy,
|
|
3538
|
+
evaluation: {
|
|
3539
|
+
pure: config.evaluation?.pure ?? preset.evaluation?.pure ?? "local"
|
|
3540
|
+
},
|
|
3541
|
+
scheduling: {
|
|
3542
|
+
coordinator: config.scheduling?.coordinator ?? preset.scheduling?.coordinator ?? "server"
|
|
3543
|
+
},
|
|
3544
|
+
events: {
|
|
3545
|
+
evaluator: config.events?.evaluator ?? preset.events?.evaluator ?? "server"
|
|
3546
|
+
},
|
|
3547
|
+
errorHandling: {
|
|
3548
|
+
strategy: config.errorHandling?.strategy ?? preset.errorHandling?.strategy ?? "rollback"
|
|
3549
|
+
},
|
|
3550
|
+
conflicts: {
|
|
3551
|
+
default: config.conflicts?.default ?? preset.conflicts?.default ?? "last-writer-wins",
|
|
3552
|
+
fields: { ...preset.conflicts?.fields || {}, ...config.conflicts?.fields || {} }
|
|
3553
|
+
},
|
|
3554
|
+
visibility: {
|
|
3555
|
+
roles: { ...preset.visibility?.roles || {}, ...config.visibility?.roles || {} },
|
|
3556
|
+
players: { ...preset.visibility?.players || {}, ...config.visibility?.players || {} }
|
|
3557
|
+
},
|
|
3558
|
+
presence: {
|
|
3559
|
+
enabled: config.presence?.enabled ?? preset.presence?.enabled ?? false,
|
|
3560
|
+
showEditing: config.presence?.showEditing ?? preset.presence?.showEditing ?? false,
|
|
3561
|
+
showViewing: config.presence?.showViewing ?? preset.presence?.showViewing ?? false,
|
|
3562
|
+
conflictHighlight: config.presence?.conflictHighlight ?? preset.presence?.conflictHighlight ?? false
|
|
3563
|
+
},
|
|
3564
|
+
services: { ...preset.services || {}, ...config.services || {} },
|
|
3565
|
+
actionRouting: { ...preset.actionRouting || {}, ...config.actionRouting || {} }
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
|
|
4264
3569
|
// src/config/defineBlueprint.ts
|
|
4265
3570
|
function defineBlueprint(config) {
|
|
4266
3571
|
if (!config.slug) {
|
|
@@ -4374,13 +3679,13 @@ function inState(state2) {
|
|
|
4374
3679
|
function notInState(state2) {
|
|
4375
3680
|
return { type: "expression", expression: `current_state != "${state2}"` };
|
|
4376
3681
|
}
|
|
4377
|
-
function
|
|
3682
|
+
function and(...conditions) {
|
|
4378
3683
|
return { AND: conditions.map(normalize) };
|
|
4379
3684
|
}
|
|
4380
|
-
function
|
|
3685
|
+
function or(...conditions) {
|
|
4381
3686
|
return { OR: conditions.map(normalize) };
|
|
4382
3687
|
}
|
|
4383
|
-
function
|
|
3688
|
+
function not(condition) {
|
|
4384
3689
|
const c = normalize(condition);
|
|
4385
3690
|
if (c.type === "expression" && c.expression) {
|
|
4386
3691
|
return { type: "expression", expression: `NOT(${c.expression})` };
|
|
@@ -4425,7 +3730,7 @@ function refHasAnyRole(slug, lookupField, lookupValue, roles) {
|
|
|
4425
3730
|
}
|
|
4426
3731
|
|
|
4427
3732
|
// src/hooks/useModel.ts
|
|
4428
|
-
var
|
|
3733
|
+
var import_react34 = require("react");
|
|
4429
3734
|
function getDefaultFields(definition) {
|
|
4430
3735
|
const defaults = {};
|
|
4431
3736
|
for (const [key, field2] of Object.entries(definition.fields)) {
|
|
@@ -4480,18 +3785,18 @@ function useModel(definition, options = {}) {
|
|
|
4480
3785
|
if (options.state) queryParams.state = options.state;
|
|
4481
3786
|
const query = useQuery(slug, queryParams);
|
|
4482
3787
|
const mutation = useMutation(slug);
|
|
4483
|
-
const
|
|
4484
|
-
const instanceId =
|
|
4485
|
-
const currentState =
|
|
4486
|
-
const instanceFields =
|
|
4487
|
-
const defaultFields = (0,
|
|
4488
|
-
const fields = (0,
|
|
3788
|
+
const instance2 = query.data?.[0];
|
|
3789
|
+
const instanceId = instance2?.id ?? null;
|
|
3790
|
+
const currentState = instance2?.currentState ?? "";
|
|
3791
|
+
const instanceFields = instance2?.fields ?? null;
|
|
3792
|
+
const defaultFields = (0, import_react34.useMemo)(() => getDefaultFields(definition), [definition]);
|
|
3793
|
+
const fields = (0, import_react34.useMemo)(() => {
|
|
4489
3794
|
if (!instanceFields) return defaultFields;
|
|
4490
3795
|
return { ...defaultFields, ...instanceFields };
|
|
4491
3796
|
}, [instanceFields, defaultFields]);
|
|
4492
|
-
const instanceIdRef = (0,
|
|
3797
|
+
const instanceIdRef = (0, import_react34.useRef)(instanceId);
|
|
4493
3798
|
instanceIdRef.current = instanceId;
|
|
4494
|
-
const trigger = (0,
|
|
3799
|
+
const trigger = (0, import_react34.useCallback)(async (name, input) => {
|
|
4495
3800
|
const id = instanceIdRef.current;
|
|
4496
3801
|
if (!id) {
|
|
4497
3802
|
throw new Error(`useModel(${slug}): No instance loaded. Cannot trigger '${name}'.`);
|
|
@@ -4499,12 +3804,12 @@ function useModel(definition, options = {}) {
|
|
|
4499
3804
|
await mutation.transition(id, name, input);
|
|
4500
3805
|
await query.refetch();
|
|
4501
3806
|
}, [slug, mutation, query]);
|
|
4502
|
-
const create = (0,
|
|
3807
|
+
const create = (0, import_react34.useCallback)(async (input) => {
|
|
4503
3808
|
const id = await mutation.create(input);
|
|
4504
3809
|
await query.refetch();
|
|
4505
3810
|
return id;
|
|
4506
3811
|
}, [mutation, query]);
|
|
4507
|
-
const update = (0,
|
|
3812
|
+
const update = (0, import_react34.useCallback)(async (fieldUpdates) => {
|
|
4508
3813
|
const id = instanceIdRef.current;
|
|
4509
3814
|
if (!id) {
|
|
4510
3815
|
throw new Error(`useModel(${slug}): No instance loaded. Cannot update.`);
|
|
@@ -4533,27 +3838,27 @@ function useCollection(definition, options = {}) {
|
|
|
4533
3838
|
const slug = definition.slug;
|
|
4534
3839
|
const query = useQuery(slug, options);
|
|
4535
3840
|
const mutation = useMutation(slug);
|
|
4536
|
-
const items = (0,
|
|
4537
|
-
return (query.data || []).map((
|
|
4538
|
-
id:
|
|
4539
|
-
fields:
|
|
4540
|
-
state:
|
|
3841
|
+
const items = (0, import_react34.useMemo)(() => {
|
|
3842
|
+
return (query.data || []).map((instance2) => ({
|
|
3843
|
+
id: instance2.id,
|
|
3844
|
+
fields: instance2.fields ?? {},
|
|
3845
|
+
state: instance2.currentState ?? ""
|
|
4541
3846
|
}));
|
|
4542
3847
|
}, [query.data]);
|
|
4543
|
-
const trigger = (0,
|
|
3848
|
+
const trigger = (0, import_react34.useCallback)(async (instanceId, name, input) => {
|
|
4544
3849
|
await mutation.transition(instanceId, name, input);
|
|
4545
3850
|
await query.refetch();
|
|
4546
3851
|
}, [mutation, query]);
|
|
4547
|
-
const create = (0,
|
|
3852
|
+
const create = (0, import_react34.useCallback)(async (input) => {
|
|
4548
3853
|
const id = await mutation.create(input);
|
|
4549
3854
|
await query.refetch();
|
|
4550
3855
|
return id;
|
|
4551
3856
|
}, [mutation, query]);
|
|
4552
|
-
const update = (0,
|
|
3857
|
+
const update = (0, import_react34.useCallback)(async (instanceId, fieldUpdates) => {
|
|
4553
3858
|
await mutation.update(instanceId, fieldUpdates);
|
|
4554
3859
|
await query.refetch();
|
|
4555
3860
|
}, [mutation, query]);
|
|
4556
|
-
const remove = (0,
|
|
3861
|
+
const remove = (0, import_react34.useCallback)(async (instanceId) => {
|
|
4557
3862
|
await mutation.remove(instanceId);
|
|
4558
3863
|
await query.refetch();
|
|
4559
3864
|
}, [mutation, query]);
|
|
@@ -4577,7 +3882,7 @@ function useCollection(definition, options = {}) {
|
|
|
4577
3882
|
function stub(displayName) {
|
|
4578
3883
|
const Component = () => {
|
|
4579
3884
|
throw new Error(
|
|
4580
|
-
`<${displayName}> is a compile-time stub from @
|
|
3885
|
+
`<${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.`
|
|
4581
3886
|
);
|
|
4582
3887
|
};
|
|
4583
3888
|
Component.displayName = displayName;
|
|
@@ -4704,7 +4009,7 @@ function djb2Hash(str) {
|
|
|
4704
4009
|
}
|
|
4705
4010
|
|
|
4706
4011
|
// src/authoring.ts
|
|
4707
|
-
function
|
|
4012
|
+
function useState21(_defaultOrKey) {
|
|
4708
4013
|
return [void 0, () => {
|
|
4709
4014
|
}];
|
|
4710
4015
|
}
|
|
@@ -4715,10 +4020,10 @@ function defineWorkspace(config) {
|
|
|
4715
4020
|
}
|
|
4716
4021
|
|
|
4717
4022
|
// src/hooks/useModule.ts
|
|
4718
|
-
var
|
|
4023
|
+
var import_react35 = require("react");
|
|
4719
4024
|
function useModule(slug, config = {}, options = {}) {
|
|
4720
4025
|
const { enabled = true } = options;
|
|
4721
|
-
return (0,
|
|
4026
|
+
return (0, import_react35.useMemo)(() => ({
|
|
4722
4027
|
slug,
|
|
4723
4028
|
config,
|
|
4724
4029
|
isLoaded: enabled
|
|
@@ -4726,7 +4031,7 @@ function useModule(slug, config = {}, options = {}) {
|
|
|
4726
4031
|
}
|
|
4727
4032
|
|
|
4728
4033
|
// src/hooks/useModuleConfig.ts
|
|
4729
|
-
var
|
|
4034
|
+
var import_react36 = require("react");
|
|
4730
4035
|
var installedModulesStore = [];
|
|
4731
4036
|
var configDefaultsStore = /* @__PURE__ */ new Map();
|
|
4732
4037
|
function setInstalledModules(modules) {
|
|
@@ -4742,12 +4047,65 @@ function getInstalledModules() {
|
|
|
4742
4047
|
return installedModulesStore;
|
|
4743
4048
|
}
|
|
4744
4049
|
function useModuleConfig(moduleSlug) {
|
|
4745
|
-
return (0,
|
|
4050
|
+
return (0, import_react36.useMemo)(() => {
|
|
4746
4051
|
const installed = getInstalledModule(moduleSlug);
|
|
4747
4052
|
const defaults = configDefaultsStore.get(moduleSlug) ?? {};
|
|
4748
|
-
|
|
4053
|
+
const persisted = persistedConfigStore.get(moduleSlug) ?? {};
|
|
4054
|
+
return { ...defaults, ...persisted, ...installed?.config };
|
|
4749
4055
|
}, [moduleSlug]);
|
|
4750
4056
|
}
|
|
4057
|
+
var persistedConfigStore = /* @__PURE__ */ new Map();
|
|
4058
|
+
function setPersistedModuleConfig(moduleSlug, config) {
|
|
4059
|
+
persistedConfigStore.set(moduleSlug, config);
|
|
4060
|
+
}
|
|
4061
|
+
async function syncConfigDefaults(moduleSlug, defaults, definitionId) {
|
|
4062
|
+
const id = definitionId ?? activeDefinitionIdStore;
|
|
4063
|
+
if (!id) return;
|
|
4064
|
+
try {
|
|
4065
|
+
const moduleKey = `module_config.${moduleSlug}`;
|
|
4066
|
+
await updateDefinitionConfig({ [moduleKey]: defaults }, id);
|
|
4067
|
+
persistedConfigStore.set(moduleSlug, defaults);
|
|
4068
|
+
} catch (e) {
|
|
4069
|
+
console.warn(`[useModuleConfig] Failed to sync config for ${moduleSlug}:`, e);
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
var activeDefinitionIdStore = null;
|
|
4073
|
+
var apiBaseUrlStore = "/api/v1/workflow";
|
|
4074
|
+
function setConfigContext(definitionId, apiBaseUrl) {
|
|
4075
|
+
activeDefinitionIdStore = definitionId;
|
|
4076
|
+
if (apiBaseUrl) apiBaseUrlStore = apiBaseUrl;
|
|
4077
|
+
}
|
|
4078
|
+
async function updateDefinitionConfig(values, definitionId) {
|
|
4079
|
+
const id = definitionId ?? activeDefinitionIdStore;
|
|
4080
|
+
if (!id) throw new Error("No active definition ID. Call setConfigContext() first.");
|
|
4081
|
+
const token = typeof localStorage !== "undefined" ? localStorage.getItem("auth_token") : null;
|
|
4082
|
+
const response = await fetch(`${apiBaseUrlStore}/definitions/${id}/config`, {
|
|
4083
|
+
method: "PATCH",
|
|
4084
|
+
headers: {
|
|
4085
|
+
"Content-Type": "application/json",
|
|
4086
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
4087
|
+
},
|
|
4088
|
+
body: JSON.stringify(values)
|
|
4089
|
+
});
|
|
4090
|
+
if (!response.ok) {
|
|
4091
|
+
const err = await response.json().catch(() => ({ message: response.statusText }));
|
|
4092
|
+
throw new Error(err.message || `Failed to update config: ${response.status}`);
|
|
4093
|
+
}
|
|
4094
|
+
return response.json();
|
|
4095
|
+
}
|
|
4096
|
+
function useModuleConfigWithMutation(moduleSlug) {
|
|
4097
|
+
const config = useModuleConfig(moduleSlug);
|
|
4098
|
+
const [isSaving, setIsSaving] = (0, import_react36.useState)(false);
|
|
4099
|
+
const updateConfig = (0, import_react36.useCallback)(async (values) => {
|
|
4100
|
+
setIsSaving(true);
|
|
4101
|
+
try {
|
|
4102
|
+
return await updateDefinitionConfig(values);
|
|
4103
|
+
} finally {
|
|
4104
|
+
setIsSaving(false);
|
|
4105
|
+
}
|
|
4106
|
+
}, []);
|
|
4107
|
+
return { config, updateConfig, isSaving };
|
|
4108
|
+
}
|
|
4751
4109
|
|
|
4752
4110
|
// src/builders.ts
|
|
4753
4111
|
function handlerToAction(handler, qualifier) {
|
|
@@ -6251,7 +5609,7 @@ function approval(config = {}) {
|
|
|
6251
5609
|
}
|
|
6252
5610
|
function escalation(config) {
|
|
6253
5611
|
const {
|
|
6254
|
-
timeout,
|
|
5612
|
+
timeout: timeout2,
|
|
6255
5613
|
notifyRole = "admin",
|
|
6256
5614
|
fromState = "pending_approval",
|
|
6257
5615
|
escalatedState = "escalated"
|
|
@@ -6263,7 +5621,7 @@ function escalation(config) {
|
|
|
6263
5621
|
});
|
|
6264
5622
|
if (def.states[fromState]) {
|
|
6265
5623
|
def.states[fromState].timeout = {
|
|
6266
|
-
duration:
|
|
5624
|
+
duration: timeout2,
|
|
6267
5625
|
fallback: { transition: "escalate" }
|
|
6268
5626
|
};
|
|
6269
5627
|
}
|
|
@@ -6282,8 +5640,8 @@ function escalation(config) {
|
|
|
6282
5640
|
from: fromState,
|
|
6283
5641
|
to: escalatedState,
|
|
6284
5642
|
auto: true,
|
|
6285
|
-
description: `Auto-escalate after ${
|
|
6286
|
-
actions: [logEvent("escalated", { timeout })]
|
|
5643
|
+
description: `Auto-escalate after ${timeout2}`,
|
|
5644
|
+
actions: [logEvent("escalated", { timeout: timeout2 })]
|
|
6287
5645
|
}
|
|
6288
5646
|
});
|
|
6289
5647
|
return def;
|
|
@@ -6941,7 +6299,8 @@ function describeModel(def) {
|
|
|
6941
6299
|
}
|
|
6942
6300
|
|
|
6943
6301
|
// src/hooks/usePlayer.ts
|
|
6944
|
-
var
|
|
6302
|
+
var import_react37 = require("react");
|
|
6303
|
+
var import_player_core2 = require("@mmapp/player-core");
|
|
6945
6304
|
|
|
6946
6305
|
// src/logger.ts
|
|
6947
6306
|
var debugEnabled = false;
|
|
@@ -6981,18 +6340,18 @@ function computePlayerState(sm) {
|
|
|
6981
6340
|
};
|
|
6982
6341
|
}
|
|
6983
6342
|
function usePlayer(config) {
|
|
6984
|
-
const configRef = (0,
|
|
6343
|
+
const configRef = (0, import_react37.useRef)(config);
|
|
6985
6344
|
configRef.current = config;
|
|
6986
|
-
(0,
|
|
6345
|
+
(0, import_react37.useEffect)(() => {
|
|
6987
6346
|
if (config.debug) setPlayerDebug(true);
|
|
6988
6347
|
}, [config.debug]);
|
|
6989
|
-
const evaluator = (0,
|
|
6990
|
-
return createEvaluator({
|
|
6348
|
+
const evaluator = (0, import_react37.useMemo)(() => {
|
|
6349
|
+
return (0, import_player_core2.createEvaluator)({
|
|
6991
6350
|
functions: config.functions ?? [],
|
|
6992
|
-
failurePolicy: WEB_FAILURE_POLICIES.EVENT_REACTION
|
|
6351
|
+
failurePolicy: import_player_core2.WEB_FAILURE_POLICIES.EVENT_REACTION
|
|
6993
6352
|
});
|
|
6994
6353
|
}, [config.definition.id]);
|
|
6995
|
-
const engine = (0,
|
|
6354
|
+
const engine = (0, import_react37.useMemo)(() => {
|
|
6996
6355
|
const actionHandlers = /* @__PURE__ */ new Map();
|
|
6997
6356
|
if (config.actionHandlers) {
|
|
6998
6357
|
for (const [type, handler] of Object.entries(config.actionHandlers)) {
|
|
@@ -7020,14 +6379,14 @@ function usePlayer(config) {
|
|
|
7020
6379
|
});
|
|
7021
6380
|
}
|
|
7022
6381
|
});
|
|
7023
|
-
const sm2 = new StateMachine(
|
|
6382
|
+
const sm2 = new import_player_core2.StateMachine(
|
|
7024
6383
|
config.definition,
|
|
7025
6384
|
config.initialData ?? {},
|
|
7026
6385
|
{ evaluator, actionHandlers }
|
|
7027
6386
|
);
|
|
7028
6387
|
smRef = sm2;
|
|
7029
|
-
const eventBus2 = new EventBus();
|
|
7030
|
-
const dispatcher = new ActionDispatcher();
|
|
6388
|
+
const eventBus2 = new import_player_core2.EventBus();
|
|
6389
|
+
const dispatcher = new import_player_core2.ActionDispatcher();
|
|
7031
6390
|
dispatcher.register("set_field", (cfg) => {
|
|
7032
6391
|
if (smRef && typeof cfg.field === "string") {
|
|
7033
6392
|
smRef.setField(cfg.field, cfg.value);
|
|
@@ -7046,8 +6405,8 @@ function usePlayer(config) {
|
|
|
7046
6405
|
return { sm: sm2, eventBus: eventBus2, dispatcher };
|
|
7047
6406
|
}, [config.definition.id, evaluator]);
|
|
7048
6407
|
const { sm, eventBus } = engine;
|
|
7049
|
-
const [playerState, setPlayerState] = (0,
|
|
7050
|
-
(0,
|
|
6408
|
+
const [playerState, setPlayerState] = (0, import_react37.useState)(() => computePlayerState(sm));
|
|
6409
|
+
(0, import_react37.useEffect)(() => {
|
|
7051
6410
|
const stateDef = sm.getCurrentStateDefinition();
|
|
7052
6411
|
if (!stateDef?.on_event?.length) return;
|
|
7053
6412
|
const unsubs = [];
|
|
@@ -7111,7 +6470,7 @@ function usePlayer(config) {
|
|
|
7111
6470
|
for (const unsub of unsubs) unsub();
|
|
7112
6471
|
};
|
|
7113
6472
|
}, [sm, eventBus, evaluator, engine.dispatcher, playerState.currentState]);
|
|
7114
|
-
(0,
|
|
6473
|
+
(0, import_react37.useEffect)(() => {
|
|
7115
6474
|
const unsub = sm.on((event) => {
|
|
7116
6475
|
if (event.type === "transition" || event.type === "state_enter") {
|
|
7117
6476
|
setPlayerState(computePlayerState(sm));
|
|
@@ -7127,7 +6486,7 @@ function usePlayer(config) {
|
|
|
7127
6486
|
});
|
|
7128
6487
|
return unsub;
|
|
7129
6488
|
}, [sm]);
|
|
7130
|
-
const transition2 = (0,
|
|
6489
|
+
const transition2 = (0, import_react37.useCallback)(
|
|
7131
6490
|
async (name, data) => {
|
|
7132
6491
|
playerLog({
|
|
7133
6492
|
level: "info",
|
|
@@ -7154,20 +6513,20 @@ function usePlayer(config) {
|
|
|
7154
6513
|
},
|
|
7155
6514
|
[sm]
|
|
7156
6515
|
);
|
|
7157
|
-
const setField2 = (0,
|
|
6516
|
+
const setField2 = (0, import_react37.useCallback)(
|
|
7158
6517
|
(field2, value) => {
|
|
7159
6518
|
sm.setField(field2, value);
|
|
7160
6519
|
setPlayerState(computePlayerState(sm));
|
|
7161
6520
|
},
|
|
7162
6521
|
[sm]
|
|
7163
6522
|
);
|
|
7164
|
-
const setMemory = (0,
|
|
6523
|
+
const setMemory = (0, import_react37.useCallback)(
|
|
7165
6524
|
(key, value) => {
|
|
7166
6525
|
sm.setMemory(key, value);
|
|
7167
6526
|
},
|
|
7168
6527
|
[sm]
|
|
7169
6528
|
);
|
|
7170
|
-
const publishEvent = (0,
|
|
6529
|
+
const publishEvent = (0, import_react37.useCallback)(
|
|
7171
6530
|
(topic, payload) => {
|
|
7172
6531
|
playerLog({
|
|
7173
6532
|
level: "debug",
|
|
@@ -7193,11 +6552,11 @@ function usePlayer(config) {
|
|
|
7193
6552
|
}
|
|
7194
6553
|
|
|
7195
6554
|
// src/hooks/useDomainSubscription.ts
|
|
7196
|
-
var
|
|
6555
|
+
var import_react38 = require("react");
|
|
7197
6556
|
function useDomainSubscription(eventBus, transport, config) {
|
|
7198
|
-
const configRef = (0,
|
|
6557
|
+
const configRef = (0, import_react38.useRef)(config);
|
|
7199
6558
|
configRef.current = config;
|
|
7200
|
-
(0,
|
|
6559
|
+
(0, import_react38.useEffect)(() => {
|
|
7201
6560
|
if (!transport || config.enabled === false) return;
|
|
7202
6561
|
const unsub = transport.subscribe(
|
|
7203
6562
|
{
|
|
@@ -7250,11 +6609,11 @@ function useDomainSubscription(eventBus, transport, config) {
|
|
|
7250
6609
|
}
|
|
7251
6610
|
|
|
7252
6611
|
// src/hooks/useExperienceState.ts
|
|
7253
|
-
var
|
|
6612
|
+
var import_react39 = require("react");
|
|
7254
6613
|
function useExperienceState(player, selector) {
|
|
7255
|
-
const selectorRef = (0,
|
|
6614
|
+
const selectorRef = (0, import_react39.useRef)(selector);
|
|
7256
6615
|
selectorRef.current = selector;
|
|
7257
|
-
const getSnapshot = (0,
|
|
6616
|
+
const getSnapshot = (0, import_react39.useCallback)(() => {
|
|
7258
6617
|
return selectorRef.current({
|
|
7259
6618
|
currentState: player.currentState,
|
|
7260
6619
|
stateData: player.stateData,
|
|
@@ -7270,20 +6629,20 @@ function useStateField(player, field2, defaultValue) {
|
|
|
7270
6629
|
}
|
|
7271
6630
|
|
|
7272
6631
|
// src/hooks/useComputed.ts
|
|
7273
|
-
var
|
|
6632
|
+
var import_react40 = require("react");
|
|
7274
6633
|
function useComputed(_name, compute, options) {
|
|
7275
6634
|
const mode = options?.mode ?? "read-time";
|
|
7276
6635
|
const deps = options?.deps ?? [];
|
|
7277
|
-
const computeRef = (0,
|
|
6636
|
+
const computeRef = (0, import_react40.useRef)(compute);
|
|
7278
6637
|
computeRef.current = compute;
|
|
7279
6638
|
if (mode === "read-time") {
|
|
7280
|
-
return (0,
|
|
6639
|
+
return (0, import_react40.useMemo)(() => computeRef.current(), [
|
|
7281
6640
|
// We intentionally depend on deps.join to recompute when tracked fields change
|
|
7282
6641
|
// The actual dependency tracking happens at the compiler level
|
|
7283
6642
|
deps.join(",")
|
|
7284
6643
|
]);
|
|
7285
6644
|
}
|
|
7286
|
-
return (0,
|
|
6645
|
+
return (0, import_react40.useMemo)(() => computeRef.current(), [deps.join(",")]);
|
|
7287
6646
|
}
|
|
7288
6647
|
function useComputedWithMeta(name, compute, options) {
|
|
7289
6648
|
const value = useComputed(name, compute, options);
|
|
@@ -7298,25 +6657,25 @@ function useComputedWithMeta(name, compute, options) {
|
|
|
7298
6657
|
}
|
|
7299
6658
|
|
|
7300
6659
|
// src/components/PlayerProvider.tsx
|
|
7301
|
-
var
|
|
6660
|
+
var import_react41 = require("react");
|
|
7302
6661
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
7303
|
-
var PlayerContext = (0,
|
|
6662
|
+
var PlayerContext = (0, import_react41.createContext)(null);
|
|
7304
6663
|
function PlayerProvider({ player, children }) {
|
|
7305
6664
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PlayerContext.Provider, { value: player, children });
|
|
7306
6665
|
}
|
|
7307
6666
|
function usePlayerContext() {
|
|
7308
|
-
const ctx = (0,
|
|
6667
|
+
const ctx = (0, import_react41.useContext)(PlayerContext);
|
|
7309
6668
|
if (!ctx) {
|
|
7310
6669
|
throw new Error("usePlayerContext must be used within a <PlayerProvider>");
|
|
7311
6670
|
}
|
|
7312
6671
|
return ctx;
|
|
7313
6672
|
}
|
|
7314
6673
|
function usePlayerContextSafe() {
|
|
7315
|
-
return (0,
|
|
6674
|
+
return (0, import_react41.useContext)(PlayerContext);
|
|
7316
6675
|
}
|
|
7317
6676
|
|
|
7318
6677
|
// src/components/ExperienceWorkflowBridge.tsx
|
|
7319
|
-
var
|
|
6678
|
+
var import_react42 = require("react");
|
|
7320
6679
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
7321
6680
|
function ExperienceWorkflowBridgeInner({
|
|
7322
6681
|
definition,
|
|
@@ -7334,7 +6693,7 @@ function ExperienceWorkflowBridgeInner({
|
|
|
7334
6693
|
actionHandlers,
|
|
7335
6694
|
debug
|
|
7336
6695
|
});
|
|
7337
|
-
const viewConfig = (0,
|
|
6696
|
+
const viewConfig = (0, import_react42.useMemo)(() => {
|
|
7338
6697
|
if (!definition.state_views) return void 0;
|
|
7339
6698
|
return definition.state_views[player.currentState];
|
|
7340
6699
|
}, [definition.state_views, player.currentState]);
|
|
@@ -7369,7 +6728,7 @@ function ExperienceWorkflowBridge(props) {
|
|
|
7369
6728
|
}
|
|
7370
6729
|
|
|
7371
6730
|
// src/components/atoms/index.tsx
|
|
7372
|
-
var
|
|
6731
|
+
var import_react43 = __toESM(require("react"));
|
|
7373
6732
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
7374
6733
|
|
|
7375
6734
|
// src/loader/experience-workflow-loader.ts
|
|
@@ -7690,7 +7049,7 @@ var BrowserPlayer = class {
|
|
|
7690
7049
|
this.ensureInitialized();
|
|
7691
7050
|
const id = crypto.randomUUID();
|
|
7692
7051
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7693
|
-
const
|
|
7052
|
+
const instance2 = {
|
|
7694
7053
|
id,
|
|
7695
7054
|
definitionId: options.definitionId ?? definitionSlug,
|
|
7696
7055
|
definitionSlug,
|
|
@@ -7702,15 +7061,15 @@ var BrowserPlayer = class {
|
|
|
7702
7061
|
createdAt: now,
|
|
7703
7062
|
updatedAt: now
|
|
7704
7063
|
};
|
|
7705
|
-
await this.putInstance(
|
|
7064
|
+
await this.putInstance(instance2);
|
|
7706
7065
|
this.log("info", `Instance created: ${id} (${definitionSlug})`);
|
|
7707
7066
|
this.emit({
|
|
7708
7067
|
type: "instance:created",
|
|
7709
7068
|
instanceId: id,
|
|
7710
|
-
data: { definitionSlug, currentState:
|
|
7069
|
+
data: { definitionSlug, currentState: instance2.currentState },
|
|
7711
7070
|
timestamp: Date.now()
|
|
7712
7071
|
});
|
|
7713
|
-
return
|
|
7072
|
+
return instance2;
|
|
7714
7073
|
}
|
|
7715
7074
|
/** Get an instance by ID. */
|
|
7716
7075
|
async getInstance(id) {
|
|
@@ -7719,13 +7078,13 @@ var BrowserPlayer = class {
|
|
|
7719
7078
|
}
|
|
7720
7079
|
/** Get the current state of an instance. */
|
|
7721
7080
|
async getState(id) {
|
|
7722
|
-
const
|
|
7723
|
-
if (!
|
|
7081
|
+
const instance2 = await this.getInstance(id);
|
|
7082
|
+
if (!instance2) return null;
|
|
7724
7083
|
return {
|
|
7725
|
-
currentState:
|
|
7726
|
-
status:
|
|
7727
|
-
stateData:
|
|
7728
|
-
lockVersion:
|
|
7084
|
+
currentState: instance2.currentState,
|
|
7085
|
+
status: instance2.status,
|
|
7086
|
+
stateData: instance2.stateData,
|
|
7087
|
+
lockVersion: instance2.lockVersion
|
|
7729
7088
|
};
|
|
7730
7089
|
}
|
|
7731
7090
|
/**
|
|
@@ -7736,34 +7095,34 @@ var BrowserPlayer = class {
|
|
|
7736
7095
|
*/
|
|
7737
7096
|
async transition(instanceId, transitionName, data = {}) {
|
|
7738
7097
|
this.ensureInitialized();
|
|
7739
|
-
const
|
|
7740
|
-
if (!
|
|
7098
|
+
const instance2 = await this.getInstanceFromDb(instanceId);
|
|
7099
|
+
if (!instance2) {
|
|
7741
7100
|
return {
|
|
7742
7101
|
success: false,
|
|
7743
7102
|
instance: null,
|
|
7744
7103
|
error: `Instance ${instanceId} not found`
|
|
7745
7104
|
};
|
|
7746
7105
|
}
|
|
7747
|
-
if (
|
|
7106
|
+
if (instance2.status !== "ACTIVE") {
|
|
7748
7107
|
return {
|
|
7749
7108
|
success: false,
|
|
7750
|
-
instance,
|
|
7751
|
-
error: `Instance is ${
|
|
7109
|
+
instance: instance2,
|
|
7110
|
+
error: `Instance is ${instance2.status}, cannot transition`
|
|
7752
7111
|
};
|
|
7753
7112
|
}
|
|
7754
7113
|
try {
|
|
7755
|
-
const newStateData = { ...
|
|
7756
|
-
const newLockVersion =
|
|
7114
|
+
const newStateData = { ...instance2.stateData, ...data };
|
|
7115
|
+
const newLockVersion = instance2.lockVersion + 1;
|
|
7757
7116
|
if (this.wasm.execute_transition) {
|
|
7758
7117
|
const request = {
|
|
7759
7118
|
instance: {
|
|
7760
|
-
id:
|
|
7761
|
-
definition_id:
|
|
7762
|
-
current_state:
|
|
7763
|
-
status:
|
|
7119
|
+
id: instance2.id,
|
|
7120
|
+
definition_id: instance2.definitionId,
|
|
7121
|
+
current_state: instance2.currentState,
|
|
7122
|
+
status: instance2.status,
|
|
7764
7123
|
state_data: newStateData,
|
|
7765
|
-
memory:
|
|
7766
|
-
execution_lock_version:
|
|
7124
|
+
memory: instance2.memory,
|
|
7125
|
+
execution_lock_version: instance2.lockVersion
|
|
7767
7126
|
},
|
|
7768
7127
|
transition_name: transitionName,
|
|
7769
7128
|
actor_id: this.peerId,
|
|
@@ -7772,26 +7131,26 @@ var BrowserPlayer = class {
|
|
|
7772
7131
|
const resultJson = this.wasm.execute_transition(JSON.stringify(request));
|
|
7773
7132
|
const result = JSON.parse(resultJson);
|
|
7774
7133
|
if (result.success === false || result.error) {
|
|
7775
|
-
return { success: false, instance, error: result.error ?? "Transition failed" };
|
|
7134
|
+
return { success: false, instance: instance2, error: result.error ?? "Transition failed" };
|
|
7776
7135
|
}
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7136
|
+
instance2.currentState = result.to_state ?? instance2.currentState;
|
|
7137
|
+
instance2.status = result.status ?? instance2.status;
|
|
7138
|
+
instance2.stateData = result.state_data ?? newStateData;
|
|
7139
|
+
instance2.memory = result.memory ?? instance2.memory;
|
|
7781
7140
|
} else {
|
|
7782
|
-
|
|
7141
|
+
instance2.stateData = newStateData;
|
|
7783
7142
|
}
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
await this.putInstance(
|
|
7143
|
+
instance2.lockVersion = newLockVersion;
|
|
7144
|
+
instance2.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7145
|
+
await this.putInstance(instance2);
|
|
7787
7146
|
this.log("info", `Transition: ${instanceId} ${transitionName}`);
|
|
7788
7147
|
this.emit({
|
|
7789
7148
|
type: "instance:transition",
|
|
7790
7149
|
instanceId,
|
|
7791
7150
|
data: {
|
|
7792
7151
|
transitionName,
|
|
7793
|
-
fromState:
|
|
7794
|
-
toState:
|
|
7152
|
+
fromState: instance2.currentState,
|
|
7153
|
+
toState: instance2.currentState,
|
|
7795
7154
|
lockVersion: newLockVersion
|
|
7796
7155
|
},
|
|
7797
7156
|
timestamp: Date.now()
|
|
@@ -7801,7 +7160,7 @@ var BrowserPlayer = class {
|
|
|
7801
7160
|
type: "TransitionReplication",
|
|
7802
7161
|
instance_id: instanceId,
|
|
7803
7162
|
transition_name: transitionName,
|
|
7804
|
-
state_data:
|
|
7163
|
+
state_data: instance2.stateData,
|
|
7805
7164
|
lock_version: newLockVersion
|
|
7806
7165
|
});
|
|
7807
7166
|
const envelope = this.wasm.sign_envelope(this.secretKeyHex, payload);
|
|
@@ -7811,11 +7170,11 @@ var BrowserPlayer = class {
|
|
|
7811
7170
|
envelope
|
|
7812
7171
|
}));
|
|
7813
7172
|
}
|
|
7814
|
-
return { success: true, instance };
|
|
7173
|
+
return { success: true, instance: instance2 };
|
|
7815
7174
|
} catch (err) {
|
|
7816
7175
|
const error = err instanceof Error ? err.message : String(err);
|
|
7817
7176
|
this.log("error", `Transition failed: ${error}`);
|
|
7818
|
-
return { success: false, instance, error };
|
|
7177
|
+
return { success: false, instance: instance2, error };
|
|
7819
7178
|
}
|
|
7820
7179
|
}
|
|
7821
7180
|
// ─── Subscriptions ──────────────────────────────────────────────────
|
|
@@ -7895,12 +7254,12 @@ var BrowserPlayer = class {
|
|
|
7895
7254
|
request.onerror = () => reject(request.error);
|
|
7896
7255
|
});
|
|
7897
7256
|
}
|
|
7898
|
-
async putInstance(
|
|
7257
|
+
async putInstance(instance2) {
|
|
7899
7258
|
if (!this.db) return;
|
|
7900
7259
|
return new Promise((resolve, reject) => {
|
|
7901
7260
|
const tx = this.db.transaction(INSTANCE_STORE_NAME, "readwrite");
|
|
7902
7261
|
const store = tx.objectStore(INSTANCE_STORE_NAME);
|
|
7903
|
-
store.put(
|
|
7262
|
+
store.put(instance2);
|
|
7904
7263
|
tx.oncomplete = () => resolve();
|
|
7905
7264
|
tx.onerror = () => reject(tx.error);
|
|
7906
7265
|
});
|
|
@@ -8047,10 +7406,382 @@ var BrowserPlayer = class {
|
|
|
8047
7406
|
}
|
|
8048
7407
|
}
|
|
8049
7408
|
};
|
|
7409
|
+
|
|
7410
|
+
// src/middleware-def.ts
|
|
7411
|
+
function defineMiddleware(def) {
|
|
7412
|
+
if (process.env.NODE_ENV !== "production") {
|
|
7413
|
+
if (!def.name || typeof def.name !== "string") {
|
|
7414
|
+
throw new Error("defineMiddleware: name is required and must be a string");
|
|
7415
|
+
}
|
|
7416
|
+
if (!def.match) {
|
|
7417
|
+
throw new Error("defineMiddleware: match pattern is required");
|
|
7418
|
+
}
|
|
7419
|
+
const patterns = Array.isArray(def.match) ? def.match : [def.match];
|
|
7420
|
+
for (const p of patterns) {
|
|
7421
|
+
if (typeof p !== "string") {
|
|
7422
|
+
throw new Error(`defineMiddleware: match pattern must be a string, got ${typeof p}`);
|
|
7423
|
+
}
|
|
7424
|
+
}
|
|
7425
|
+
if (def.priority !== void 0 && typeof def.priority !== "number") {
|
|
7426
|
+
throw new Error("defineMiddleware: priority must be a number");
|
|
7427
|
+
}
|
|
7428
|
+
if (!def.before && !def.after && !def.around) {
|
|
7429
|
+
throw new Error("defineMiddleware: at least one of before, after, or around must be provided");
|
|
7430
|
+
}
|
|
7431
|
+
}
|
|
7432
|
+
return def;
|
|
7433
|
+
}
|
|
7434
|
+
function extendMiddleware(base, overrides) {
|
|
7435
|
+
let introduce;
|
|
7436
|
+
if (base.introduce || overrides.introduce) {
|
|
7437
|
+
introduce = {
|
|
7438
|
+
fields: { ...base.introduce?.fields, ...overrides.introduce?.fields },
|
|
7439
|
+
states: { ...base.introduce?.states, ...overrides.introduce?.states },
|
|
7440
|
+
transitions: { ...base.introduce?.transitions, ...overrides.introduce?.transitions }
|
|
7441
|
+
};
|
|
7442
|
+
if (introduce.fields && Object.keys(introduce.fields).length === 0) introduce.fields = void 0;
|
|
7443
|
+
if (introduce.states && Object.keys(introduce.states).length === 0) introduce.states = void 0;
|
|
7444
|
+
if (introduce.transitions && Object.keys(introduce.transitions).length === 0) introduce.transitions = void 0;
|
|
7445
|
+
}
|
|
7446
|
+
const merged = {
|
|
7447
|
+
...base,
|
|
7448
|
+
...overrides,
|
|
7449
|
+
// Config is merged (overrides win per-key)
|
|
7450
|
+
config: base.config || overrides.config ? { ...base.config, ...overrides.config } : void 0
|
|
7451
|
+
};
|
|
7452
|
+
if (introduce) {
|
|
7453
|
+
merged.introduce = introduce;
|
|
7454
|
+
}
|
|
7455
|
+
if (process.env.NODE_ENV !== "production") {
|
|
7456
|
+
if (!merged.name || typeof merged.name !== "string") {
|
|
7457
|
+
throw new Error("extendMiddleware: resulting middleware must have a name");
|
|
7458
|
+
}
|
|
7459
|
+
if (!merged.match) {
|
|
7460
|
+
throw new Error("extendMiddleware: resulting middleware must have a match pattern");
|
|
7461
|
+
}
|
|
7462
|
+
if (!merged.before && !merged.after && !merged.around) {
|
|
7463
|
+
throw new Error("extendMiddleware: resulting middleware must have at least one of before, after, or around");
|
|
7464
|
+
}
|
|
7465
|
+
}
|
|
7466
|
+
return merged;
|
|
7467
|
+
}
|
|
7468
|
+
function withAuth(opts) {
|
|
7469
|
+
const _redirectTo = opts?.redirectTo;
|
|
7470
|
+
return {
|
|
7471
|
+
name: "mm:auth",
|
|
7472
|
+
match: "*:*:transition.execute",
|
|
7473
|
+
priority: 90,
|
|
7474
|
+
before(ctx) {
|
|
7475
|
+
if (!ctx.actor.id) {
|
|
7476
|
+
ctx.block(_redirectTo ? `redirect:${_redirectTo}` : "Authentication required");
|
|
7477
|
+
}
|
|
7478
|
+
}
|
|
7479
|
+
};
|
|
7480
|
+
}
|
|
7481
|
+
function withAuditLog(opts) {
|
|
7482
|
+
const _level = opts?.level ?? "info";
|
|
7483
|
+
return {
|
|
7484
|
+
name: "mm:audit-log",
|
|
7485
|
+
match: "*:*:transition.execute",
|
|
7486
|
+
priority: 0,
|
|
7487
|
+
after(ctx) {
|
|
7488
|
+
ctx.modify({
|
|
7489
|
+
__audit: {
|
|
7490
|
+
level: _level,
|
|
7491
|
+
actor: ctx.actor.id,
|
|
7492
|
+
transition: ctx.transition?.name,
|
|
7493
|
+
from: ctx.transition?.from,
|
|
7494
|
+
to: ctx.transition?.to,
|
|
7495
|
+
timestamp: ctx.timestamp
|
|
7496
|
+
}
|
|
7497
|
+
});
|
|
7498
|
+
}
|
|
7499
|
+
};
|
|
7500
|
+
}
|
|
7501
|
+
function withRateLimit(opts) {
|
|
7502
|
+
const _max = opts?.maxPerMinute ?? 60;
|
|
7503
|
+
return {
|
|
7504
|
+
name: "mm:rate-limit",
|
|
7505
|
+
match: "*:*:transition.execute",
|
|
7506
|
+
priority: 80,
|
|
7507
|
+
config: {
|
|
7508
|
+
maxPerMinute: { type: "number", default: _max }
|
|
7509
|
+
},
|
|
7510
|
+
before(ctx) {
|
|
7511
|
+
const fields = ctx.instance.fields;
|
|
7512
|
+
const counter = fields.__rateCounter || 0;
|
|
7513
|
+
if (counter >= _max) {
|
|
7514
|
+
ctx.block(`Rate limit exceeded: ${_max} per minute`);
|
|
7515
|
+
}
|
|
7516
|
+
}
|
|
7517
|
+
};
|
|
7518
|
+
}
|
|
7519
|
+
function withValidation(opts) {
|
|
7520
|
+
const _rules = opts?.rules ?? [];
|
|
7521
|
+
return {
|
|
7522
|
+
name: "mm:validation",
|
|
7523
|
+
match: "*:*:field.change",
|
|
7524
|
+
priority: 70,
|
|
7525
|
+
config: {
|
|
7526
|
+
rules: { type: "json", default: _rules }
|
|
7527
|
+
},
|
|
7528
|
+
before(ctx) {
|
|
7529
|
+
if (!ctx.field) return;
|
|
7530
|
+
for (const rule of _rules) {
|
|
7531
|
+
if (rule.fields.includes(ctx.field.name)) {
|
|
7532
|
+
ctx.block(rule.message);
|
|
7533
|
+
}
|
|
7534
|
+
}
|
|
7535
|
+
}
|
|
7536
|
+
};
|
|
7537
|
+
}
|
|
7538
|
+
function withMetrics(opts) {
|
|
7539
|
+
const _endpoint = opts?.endpoint;
|
|
7540
|
+
return {
|
|
7541
|
+
name: "mm:metrics",
|
|
7542
|
+
match: "*:*:*",
|
|
7543
|
+
priority: 100,
|
|
7544
|
+
config: {
|
|
7545
|
+
endpoint: { type: "string", default: _endpoint }
|
|
7546
|
+
},
|
|
7547
|
+
async around(ctx, next) {
|
|
7548
|
+
const start = ctx.timestamp;
|
|
7549
|
+
await next();
|
|
7550
|
+
const duration = Date.now() - start;
|
|
7551
|
+
ctx.modify({
|
|
7552
|
+
__metrics: {
|
|
7553
|
+
duration,
|
|
7554
|
+
endpoint: _endpoint,
|
|
7555
|
+
actor: ctx.actor.id
|
|
7556
|
+
}
|
|
7557
|
+
});
|
|
7558
|
+
}
|
|
7559
|
+
};
|
|
7560
|
+
}
|
|
7561
|
+
|
|
7562
|
+
// src/actor.ts
|
|
7563
|
+
function compileTimeOnly(name) {
|
|
7564
|
+
throw new Error(
|
|
7565
|
+
`${name}() is a compile-time function and cannot be called at runtime. Use \`mmrc build\` to compile your workflow.`
|
|
7566
|
+
);
|
|
7567
|
+
}
|
|
7568
|
+
var DEFAULT_SUPERVISION = {
|
|
7569
|
+
strategy: "escalate"
|
|
7570
|
+
};
|
|
7571
|
+
var DEFAULT_MAILBOX = {
|
|
7572
|
+
capacity: 1e3,
|
|
7573
|
+
overflow: "error",
|
|
7574
|
+
priority: "fifo"
|
|
7575
|
+
};
|
|
7576
|
+
function configureActor(config) {
|
|
7577
|
+
void config;
|
|
7578
|
+
return {
|
|
7579
|
+
__actor: true,
|
|
7580
|
+
supervision: config.supervision ?? DEFAULT_SUPERVISION,
|
|
7581
|
+
mailbox: config.mailbox ?? DEFAULT_MAILBOX,
|
|
7582
|
+
hierarchy: config.hierarchy ?? {}
|
|
7583
|
+
};
|
|
7584
|
+
}
|
|
7585
|
+
function spawnActor(_slug, _options) {
|
|
7586
|
+
compileTimeOnly("spawnActor");
|
|
7587
|
+
}
|
|
7588
|
+
function sendMessage(_instanceId, _action, _payload) {
|
|
7589
|
+
compileTimeOnly("sendMessage");
|
|
7590
|
+
}
|
|
7591
|
+
function isActorConfig(value) {
|
|
7592
|
+
return typeof value === "object" && value !== null && value.__actor === true;
|
|
7593
|
+
}
|
|
7594
|
+
|
|
7595
|
+
// src/constraints.ts
|
|
7596
|
+
var BUILT_IN_CONSTRAINTS = /* @__PURE__ */ new Set([
|
|
7597
|
+
"every state is reachable",
|
|
7598
|
+
"no deadlocks",
|
|
7599
|
+
"no unreachable states",
|
|
7600
|
+
"deterministic guards",
|
|
7601
|
+
"terminates",
|
|
7602
|
+
"no guard overlaps",
|
|
7603
|
+
"all roles defined",
|
|
7604
|
+
"all fields validated"
|
|
7605
|
+
]);
|
|
7606
|
+
function constraints(...rules) {
|
|
7607
|
+
if (process.env.NODE_ENV !== "production") {
|
|
7608
|
+
if (rules.length === 0) {
|
|
7609
|
+
throw new Error("constraints(): at least one constraint rule is required");
|
|
7610
|
+
}
|
|
7611
|
+
for (let i = 0; i < rules.length; i++) {
|
|
7612
|
+
const rule = rules[i];
|
|
7613
|
+
if (typeof rule !== "string" || rule.trim() === "") {
|
|
7614
|
+
throw new Error(
|
|
7615
|
+
`constraints(): rule at index ${i} must be a non-empty string, got ${typeof rule}`
|
|
7616
|
+
);
|
|
7617
|
+
}
|
|
7618
|
+
}
|
|
7619
|
+
}
|
|
7620
|
+
return {
|
|
7621
|
+
__constraints: true,
|
|
7622
|
+
rules: Object.freeze([...rules])
|
|
7623
|
+
};
|
|
7624
|
+
}
|
|
7625
|
+
function isConstraintDeclaration(value) {
|
|
7626
|
+
return typeof value === "object" && value !== null && value.__constraints === true && Array.isArray(value.rules);
|
|
7627
|
+
}
|
|
7628
|
+
function isBuiltInConstraint(rule) {
|
|
7629
|
+
return BUILT_IN_CONSTRAINTS.has(rule);
|
|
7630
|
+
}
|
|
7631
|
+
|
|
7632
|
+
// src/extend.ts
|
|
7633
|
+
function extend(base, options) {
|
|
7634
|
+
const _metadata = {
|
|
7635
|
+
__extend: true,
|
|
7636
|
+
base,
|
|
7637
|
+
options
|
|
7638
|
+
};
|
|
7639
|
+
throw new Error(
|
|
7640
|
+
`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.
|
|
7641
|
+
|
|
7642
|
+
Base workflow: ${base?.name ?? "(anonymous)"}
|
|
7643
|
+
Derived slug: ${options.slug ?? "(not specified)"}`
|
|
7644
|
+
);
|
|
7645
|
+
return _metadata;
|
|
7646
|
+
}
|
|
7647
|
+
|
|
7648
|
+
// src/compose.ts
|
|
7649
|
+
function compose(workflow, ...mixins) {
|
|
7650
|
+
for (let i = 0; i < mixins.length; i++) {
|
|
7651
|
+
const mixin = mixins[i];
|
|
7652
|
+
if (!mixin || mixin.__mixin !== true) {
|
|
7653
|
+
throw new Error(
|
|
7654
|
+
`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)}`
|
|
7655
|
+
);
|
|
7656
|
+
}
|
|
7657
|
+
}
|
|
7658
|
+
const metadata = {
|
|
7659
|
+
__composed: true,
|
|
7660
|
+
workflow,
|
|
7661
|
+
mixins: Object.freeze([...mixins])
|
|
7662
|
+
};
|
|
7663
|
+
const composed = (async (...args) => {
|
|
7664
|
+
return workflow(...args);
|
|
7665
|
+
});
|
|
7666
|
+
Object.defineProperty(composed, "__composed", {
|
|
7667
|
+
value: metadata,
|
|
7668
|
+
writable: false,
|
|
7669
|
+
enumerable: false,
|
|
7670
|
+
configurable: false
|
|
7671
|
+
});
|
|
7672
|
+
Object.defineProperty(composed, "name", {
|
|
7673
|
+
value: `composed(${workflow.name || "anonymous"})`,
|
|
7674
|
+
writable: false,
|
|
7675
|
+
configurable: true
|
|
7676
|
+
});
|
|
7677
|
+
return composed;
|
|
7678
|
+
}
|
|
7679
|
+
|
|
7680
|
+
// src/imperative.ts
|
|
7681
|
+
function compileTimeOnly2(name) {
|
|
7682
|
+
throw new Error(
|
|
7683
|
+
`${name}() is a compile-time function and cannot be called at runtime. Use \`mmrc build\` to compile your workflow.`
|
|
7684
|
+
);
|
|
7685
|
+
}
|
|
7686
|
+
function compileTimeProxy(label) {
|
|
7687
|
+
return new Proxy(
|
|
7688
|
+
{},
|
|
7689
|
+
{
|
|
7690
|
+
get(_target, prop) {
|
|
7691
|
+
throw new Error(
|
|
7692
|
+
`Cannot access \`${label}.${String(prop)}\` at runtime. \`${label}\` is a compile-time constant. Use \`mmrc build\` to compile your workflow.`
|
|
7693
|
+
);
|
|
7694
|
+
}
|
|
7695
|
+
}
|
|
7696
|
+
);
|
|
7697
|
+
}
|
|
7698
|
+
function validate(_condition, _message, _severity) {
|
|
7699
|
+
compileTimeOnly2("validate");
|
|
7700
|
+
}
|
|
7701
|
+
function log(_event, _data) {
|
|
7702
|
+
compileTimeOnly2("log");
|
|
7703
|
+
}
|
|
7704
|
+
function notify2(_to, _message, _opts) {
|
|
7705
|
+
compileTimeOnly2("notify");
|
|
7706
|
+
}
|
|
7707
|
+
function emit(_event, _payload) {
|
|
7708
|
+
compileTimeOnly2("emit");
|
|
7709
|
+
}
|
|
7710
|
+
function requireRole2(..._roles) {
|
|
7711
|
+
compileTimeOnly2("requireRole");
|
|
7712
|
+
}
|
|
7713
|
+
function requireField(..._fields) {
|
|
7714
|
+
compileTimeOnly2("requireField");
|
|
7715
|
+
}
|
|
7716
|
+
function guard(_expression) {
|
|
7717
|
+
compileTimeOnly2("guard");
|
|
7718
|
+
}
|
|
7719
|
+
function every(_interval, _fn) {
|
|
7720
|
+
compileTimeOnly2("every");
|
|
7721
|
+
}
|
|
7722
|
+
function cron2(_expression, _fn) {
|
|
7723
|
+
compileTimeOnly2("cron");
|
|
7724
|
+
}
|
|
7725
|
+
function after(_delay, _fn) {
|
|
7726
|
+
compileTimeOnly2("after");
|
|
7727
|
+
}
|
|
7728
|
+
function on(_pattern, _handlerOrOpts) {
|
|
7729
|
+
compileTimeOnly2("on");
|
|
7730
|
+
}
|
|
7731
|
+
function timeout(_duration, _handler) {
|
|
7732
|
+
compileTimeOnly2("timeout");
|
|
7733
|
+
}
|
|
7734
|
+
function userAction(_name, _opts) {
|
|
7735
|
+
compileTimeOnly2("userAction");
|
|
7736
|
+
}
|
|
7737
|
+
function userChoice(_options) {
|
|
7738
|
+
compileTimeOnly2("userChoice");
|
|
7739
|
+
}
|
|
7740
|
+
function named(_name, _stateCall) {
|
|
7741
|
+
compileTimeOnly2("named");
|
|
7742
|
+
}
|
|
7743
|
+
function delay(_duration) {
|
|
7744
|
+
compileTimeOnly2("delay");
|
|
7745
|
+
}
|
|
7746
|
+
function allowTransition(_name, _opts) {
|
|
7747
|
+
compileTimeOnly2("allowTransition");
|
|
7748
|
+
}
|
|
7749
|
+
function restrict(_field, _opts) {
|
|
7750
|
+
compileTimeOnly2("restrict");
|
|
7751
|
+
}
|
|
7752
|
+
function visibleTo(..._roles) {
|
|
7753
|
+
compileTimeOnly2("visibleTo");
|
|
7754
|
+
}
|
|
7755
|
+
function editableBy(..._roles) {
|
|
7756
|
+
compileTimeOnly2("editableBy");
|
|
7757
|
+
}
|
|
7758
|
+
function editableIn(..._states) {
|
|
7759
|
+
compileTimeOnly2("editableIn");
|
|
7760
|
+
}
|
|
7761
|
+
function defineRoles(roles) {
|
|
7762
|
+
void roles;
|
|
7763
|
+
compileTimeOnly2("defineRoles");
|
|
7764
|
+
}
|
|
7765
|
+
function runtime(_target) {
|
|
7766
|
+
compileTimeOnly2("runtime");
|
|
7767
|
+
}
|
|
7768
|
+
function orchestration(config) {
|
|
7769
|
+
void config;
|
|
7770
|
+
compileTimeOnly2("orchestration");
|
|
7771
|
+
}
|
|
7772
|
+
function blueprint(_slug, _config) {
|
|
7773
|
+
compileTimeOnly2("blueprint");
|
|
7774
|
+
}
|
|
7775
|
+
function patch(_id, _overrides) {
|
|
7776
|
+
compileTimeOnly2("patch");
|
|
7777
|
+
}
|
|
7778
|
+
var actor = compileTimeProxy("actor");
|
|
7779
|
+
var instance = compileTimeProxy("instance");
|
|
8050
7780
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8051
7781
|
0 && (module.exports = {
|
|
8052
7782
|
Accordion,
|
|
8053
7783
|
AnimatedBox,
|
|
7784
|
+
BUILT_IN_CONSTRAINTS,
|
|
8054
7785
|
Badge,
|
|
8055
7786
|
Blueprint,
|
|
8056
7787
|
BrowserPlayer,
|
|
@@ -8077,6 +7808,7 @@ var BrowserPlayer = class {
|
|
|
8077
7808
|
Modal,
|
|
8078
7809
|
ModelBuilder,
|
|
8079
7810
|
NavLink,
|
|
7811
|
+
ORCHESTRATION_PRESETS,
|
|
8080
7812
|
PlayerProvider,
|
|
8081
7813
|
RoleGuard,
|
|
8082
7814
|
Route,
|
|
@@ -8100,12 +7832,19 @@ var BrowserPlayer = class {
|
|
|
8100
7832
|
WorkflowProvider,
|
|
8101
7833
|
WorkflowRuntime,
|
|
8102
7834
|
action,
|
|
7835
|
+
actor,
|
|
7836
|
+
after,
|
|
7837
|
+
allowTransition,
|
|
8103
7838
|
and,
|
|
8104
7839
|
applyMixins,
|
|
8105
7840
|
approval,
|
|
8106
7841
|
assertModelValid,
|
|
8107
7842
|
cedar,
|
|
7843
|
+
compose,
|
|
7844
|
+
computeVisibility,
|
|
7845
|
+
configureActor,
|
|
8108
7846
|
connector,
|
|
7847
|
+
constraints,
|
|
8109
7848
|
createActions,
|
|
8110
7849
|
createCRUD,
|
|
8111
7850
|
createLocalDataResolver,
|
|
@@ -8114,16 +7853,26 @@ var BrowserPlayer = class {
|
|
|
8114
7853
|
cron,
|
|
8115
7854
|
crud,
|
|
8116
7855
|
defineBlueprint,
|
|
7856
|
+
defineImperativeBlueprint,
|
|
7857
|
+
defineMiddleware,
|
|
8117
7858
|
defineModel,
|
|
8118
7859
|
defineModule,
|
|
7860
|
+
defineRoles,
|
|
8119
7861
|
defineWorkspace,
|
|
7862
|
+
delay,
|
|
8120
7863
|
deriveInstanceKey,
|
|
8121
7864
|
deriveInstanceKeySync,
|
|
8122
7865
|
describeModel,
|
|
8123
7866
|
deviceAction,
|
|
8124
7867
|
dmn,
|
|
7868
|
+
editableBy,
|
|
7869
|
+
editableIn,
|
|
7870
|
+
emit,
|
|
8125
7871
|
escalation,
|
|
7872
|
+
every,
|
|
8126
7873
|
expr,
|
|
7874
|
+
extend,
|
|
7875
|
+
extendMiddleware,
|
|
8127
7876
|
field,
|
|
8128
7877
|
fieldContains,
|
|
8129
7878
|
fieldEquals,
|
|
@@ -8138,12 +7887,21 @@ var BrowserPlayer = class {
|
|
|
8138
7887
|
getInstalledModule,
|
|
8139
7888
|
getInstalledModules,
|
|
8140
7889
|
graphql,
|
|
7890
|
+
guard,
|
|
8141
7891
|
hasAnyRole,
|
|
8142
7892
|
hasRole,
|
|
7893
|
+
imperativeCron,
|
|
7894
|
+
imperativeLog,
|
|
7895
|
+
imperativeNotify,
|
|
7896
|
+
imperativeRequireRole,
|
|
8143
7897
|
inState,
|
|
8144
7898
|
inputEquals,
|
|
8145
7899
|
inputRequired,
|
|
7900
|
+
instance,
|
|
8146
7901
|
isActor,
|
|
7902
|
+
isActorConfig,
|
|
7903
|
+
isBuiltInConstraint,
|
|
7904
|
+
isConstraintDeclaration,
|
|
8147
7905
|
isCreator,
|
|
8148
7906
|
isOwner,
|
|
8149
7907
|
isPlayerDebug,
|
|
@@ -8153,28 +7911,39 @@ var BrowserPlayer = class {
|
|
|
8153
7911
|
loadExperienceWorkflow,
|
|
8154
7912
|
logEvent,
|
|
8155
7913
|
model,
|
|
7914
|
+
named,
|
|
8156
7915
|
normalizeDefinition,
|
|
8157
7916
|
not,
|
|
8158
7917
|
notInState,
|
|
8159
7918
|
notify,
|
|
7919
|
+
on,
|
|
8160
7920
|
or,
|
|
7921
|
+
orchestration,
|
|
7922
|
+
patch,
|
|
8161
7923
|
pipe,
|
|
8162
7924
|
playerLog,
|
|
8163
7925
|
prefetchData,
|
|
8164
7926
|
refHasAnyRole,
|
|
8165
7927
|
refHasRole,
|
|
8166
7928
|
requireAuth,
|
|
7929
|
+
requireField,
|
|
8167
7930
|
requireRole,
|
|
7931
|
+
resolveOrchestration,
|
|
7932
|
+
restrict,
|
|
8168
7933
|
review,
|
|
7934
|
+
runtime,
|
|
7935
|
+
sendMessage,
|
|
8169
7936
|
serverAction,
|
|
8170
7937
|
setAuthResolver,
|
|
8171
7938
|
setChannelTransport,
|
|
7939
|
+
setConfigContext,
|
|
8172
7940
|
setExpressionLibraryResolver,
|
|
8173
7941
|
setField,
|
|
8174
7942
|
setFields,
|
|
8175
7943
|
setInstalledModules,
|
|
8176
7944
|
setModuleConfigDefaults,
|
|
8177
7945
|
setMutationResolver,
|
|
7946
|
+
setPersistedModuleConfig,
|
|
8178
7947
|
setPlayerDebug,
|
|
8179
7948
|
setQueryResolver,
|
|
8180
7949
|
setRealtimeQueryResolver,
|
|
@@ -8183,10 +7952,14 @@ var BrowserPlayer = class {
|
|
|
8183
7952
|
setServerStateResolver,
|
|
8184
7953
|
setViewResolver,
|
|
8185
7954
|
spawn,
|
|
7955
|
+
spawnActor,
|
|
8186
7956
|
sql,
|
|
8187
7957
|
state,
|
|
7958
|
+
syncConfigDefaults,
|
|
8188
7959
|
testModel,
|
|
7960
|
+
timeout,
|
|
8189
7961
|
transition,
|
|
7962
|
+
updateDefinitionConfig,
|
|
8190
7963
|
useAuth,
|
|
8191
7964
|
useChannel,
|
|
8192
7965
|
useCollection,
|
|
@@ -8204,6 +7977,7 @@ var BrowserPlayer = class {
|
|
|
8204
7977
|
useModel,
|
|
8205
7978
|
useModule,
|
|
8206
7979
|
useModuleConfig,
|
|
7980
|
+
useModuleConfigWithMutation,
|
|
8207
7981
|
useMutation,
|
|
8208
7982
|
useNotification,
|
|
8209
7983
|
useOnChange,
|
|
@@ -8216,6 +7990,7 @@ var BrowserPlayer = class {
|
|
|
8216
7990
|
usePlayer,
|
|
8217
7991
|
usePlayerContext,
|
|
8218
7992
|
usePlayerContextSafe,
|
|
7993
|
+
usePresence,
|
|
8219
7994
|
useQuery,
|
|
8220
7995
|
useRealtimeQuery,
|
|
8221
7996
|
useRole,
|
|
@@ -8228,20 +8003,30 @@ var BrowserPlayer = class {
|
|
|
8228
8003
|
useToast,
|
|
8229
8004
|
useTransition,
|
|
8230
8005
|
useView,
|
|
8006
|
+
useVisibility,
|
|
8231
8007
|
useWhileIn,
|
|
8232
8008
|
useWorkflow,
|
|
8233
8009
|
useWorkflowState,
|
|
8010
|
+
userAction,
|
|
8011
|
+
userChoice,
|
|
8012
|
+
validate,
|
|
8234
8013
|
validateExperienceWorkflow,
|
|
8235
8014
|
validateModel,
|
|
8015
|
+
visibleTo,
|
|
8236
8016
|
when,
|
|
8017
|
+
withAuditLog,
|
|
8237
8018
|
withAuditTrail,
|
|
8019
|
+
withAuth,
|
|
8020
|
+
withMetrics,
|
|
8238
8021
|
withOwnership,
|
|
8239
8022
|
withPagination,
|
|
8240
8023
|
withRBAC,
|
|
8024
|
+
withRateLimit,
|
|
8241
8025
|
withSearch,
|
|
8242
8026
|
withSlug,
|
|
8243
8027
|
withSoftDelete,
|
|
8244
8028
|
withTags,
|
|
8245
8029
|
withTimestamps,
|
|
8030
|
+
withValidation,
|
|
8246
8031
|
withVersioning
|
|
8247
8032
|
});
|