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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +112 -0
  2. package/dist/index.d.mts +1378 -94
  3. package/dist/index.d.ts +1378 -94
  4. package/dist/index.js +1094 -1309
  5. package/dist/index.mjs +1038 -1296
  6. package/package.json +4 -3
  7. package/package.json.backup +0 -41
  8. package/src/Blueprint.ts +0 -216
  9. package/src/__tests__/Blueprint.test.ts +0 -106
  10. package/src/__tests__/action-context.test.ts +0 -166
  11. package/src/__tests__/actionCreators.test.ts +0 -179
  12. package/src/__tests__/builders.test.ts +0 -336
  13. package/src/__tests__/defineBlueprint-composition.test.ts +0 -106
  14. package/src/__tests__/factories.test.ts +0 -229
  15. package/src/__tests__/loader.test.ts +0 -159
  16. package/src/__tests__/logger.test.ts +0 -70
  17. package/src/__tests__/type-inference.test.ts +0 -160
  18. package/src/__tests__/typed-transitions.test.ts +0 -126
  19. package/src/__tests__/useModuleConfig.test.ts +0 -61
  20. package/src/actionCreators.ts +0 -132
  21. package/src/actions.ts +0 -547
  22. package/src/atoms/index.ts +0 -600
  23. package/src/authoring.ts +0 -92
  24. package/src/browser-player.ts +0 -783
  25. package/src/builders.ts +0 -1342
  26. package/src/components/ExperienceWorkflowBridge.tsx +0 -123
  27. package/src/components/PlayerProvider.tsx +0 -43
  28. package/src/components/atoms/index.tsx +0 -269
  29. package/src/components/index.ts +0 -36
  30. package/src/conditions.ts +0 -692
  31. package/src/config/defineBlueprint.ts +0 -329
  32. package/src/config/defineModel.ts +0 -753
  33. package/src/config/defineWorkspace.ts +0 -24
  34. package/src/core/WorkflowRuntime.ts +0 -153
  35. package/src/factories.ts +0 -425
  36. package/src/grammar/index.ts +0 -173
  37. package/src/hooks/index.ts +0 -106
  38. package/src/hooks/useAuth.ts +0 -288
  39. package/src/hooks/useChannel.ts +0 -304
  40. package/src/hooks/useComputed.ts +0 -154
  41. package/src/hooks/useDomainSubscription.ts +0 -110
  42. package/src/hooks/useDuringAction.ts +0 -99
  43. package/src/hooks/useExperienceState.ts +0 -59
  44. package/src/hooks/useExpressionLibrary.ts +0 -129
  45. package/src/hooks/useForm.ts +0 -352
  46. package/src/hooks/useGeolocation.ts +0 -207
  47. package/src/hooks/useMapView.ts +0 -259
  48. package/src/hooks/useMiddleware.ts +0 -291
  49. package/src/hooks/useModel.ts +0 -363
  50. package/src/hooks/useModule.ts +0 -59
  51. package/src/hooks/useModuleConfig.ts +0 -61
  52. package/src/hooks/useMutation.ts +0 -237
  53. package/src/hooks/useNotification.ts +0 -151
  54. package/src/hooks/useOnChange.ts +0 -30
  55. package/src/hooks/useOnEnter.ts +0 -59
  56. package/src/hooks/useOnEvent.ts +0 -37
  57. package/src/hooks/useOnExit.ts +0 -27
  58. package/src/hooks/useOnTransition.ts +0 -30
  59. package/src/hooks/usePackage.ts +0 -128
  60. package/src/hooks/useParams.ts +0 -33
  61. package/src/hooks/usePlayer.ts +0 -308
  62. package/src/hooks/useQuery.ts +0 -184
  63. package/src/hooks/useRealtimeQuery.ts +0 -222
  64. package/src/hooks/useRole.ts +0 -191
  65. package/src/hooks/useRouteParams.ts +0 -100
  66. package/src/hooks/useRouter.ts +0 -347
  67. package/src/hooks/useServerAction.ts +0 -178
  68. package/src/hooks/useServerState.ts +0 -284
  69. package/src/hooks/useToast.ts +0 -164
  70. package/src/hooks/useTransition.ts +0 -39
  71. package/src/hooks/useView.ts +0 -102
  72. package/src/hooks/useWhileIn.ts +0 -48
  73. package/src/hooks/useWorkflow.ts +0 -63
  74. package/src/index.ts +0 -465
  75. package/src/loader/experience-workflow-loader.ts +0 -192
  76. package/src/loader/index.ts +0 -6
  77. package/src/local/LocalEngine.ts +0 -388
  78. package/src/local/LocalEngineAdapter.ts +0 -175
  79. package/src/local/LocalEngineContext.ts +0 -30
  80. package/src/logger.ts +0 -37
  81. package/src/mixins.ts +0 -1160
  82. package/src/providers/RuntimeContext.ts +0 -20
  83. package/src/providers/WorkflowProvider.tsx +0 -28
  84. package/src/routing/instance-key.ts +0 -107
  85. package/src/server/transition-context.ts +0 -172
  86. package/src/testing/index.ts +0 -9
  87. package/src/testing/useBlueprintTestRunner.ts +0 -91
  88. package/src/testing/useGraphAnalysis.ts +0 -18
  89. package/src/testing/useTestRunner.ts +0 -77
  90. package/src/testing.ts +0 -995
  91. package/src/types/workflow-inference.ts +0 -158
  92. package/src/types.ts +0 -114
  93. package/tsconfig.json +0 -27
  94. package/vitest.config.ts +0 -8
@@ -1,388 +0,0 @@
1
- /**
2
- * LocalWorkflowEngine — Browser-side workflow state machine
3
- *
4
- * Lightweight, pure-function engine that runs workflow definitions locally.
5
- * Used by blueprint-specific bridges to drive state via workflow transitions
6
- * instead of React dispatch actions.
7
- *
8
- * - Immutable: applyTransition returns a new WorkflowInstance
9
- * - Lamport versioning: monotonic counter for ordering transitions across peers
10
- * - No side effects: safe to call in React render path
11
- */
12
-
13
- // ============================================================================
14
- // TYPES — Subset of mm-engine WorkflowDefinition relevant to frontend
15
- // ============================================================================
16
-
17
- export interface WorkflowState {
18
- name: string;
19
- state_type: 'START' | 'REGULAR' | 'END';
20
- description?: string;
21
- }
22
-
23
- export interface WorkflowTransition {
24
- name: string;
25
- /** States this transition can fire from. */
26
- from: string[];
27
- /** Target state, or null for self-loop (stays in current state). */
28
- to: string | null;
29
- description?: string;
30
- required_fields?: string[];
31
- }
32
-
33
- export interface WorkflowFieldDef {
34
- name: string;
35
- field_type: string;
36
- default_value?: unknown;
37
- [key: string]: unknown;
38
- }
39
-
40
- export interface WorkflowDefinition {
41
- id: string;
42
- slug: string;
43
- name: string;
44
- version: string;
45
- description?: string;
46
- states: WorkflowState[];
47
- transitions: WorkflowTransition[];
48
- fields: WorkflowFieldDef[];
49
- state_data?: Record<string, unknown>;
50
- [key: string]: unknown;
51
- }
52
-
53
- // ============================================================================
54
- // WORKFLOW INSTANCE — Runtime state of a single workflow
55
- // ============================================================================
56
-
57
- export interface WorkflowInstance {
58
- /** Unique instance ID */
59
- id: string;
60
- /** Slug of the definition this instance was created from */
61
- definitionSlug: string;
62
- /** Current state name */
63
- currentState: string;
64
- /** Field values (mutable data carried by this instance) */
65
- fields: Record<string, unknown>;
66
- /** Lamport version counter — incremented on every transition */
67
- version: number;
68
- /** Timestamp of last transition (ms since epoch) */
69
- updatedAt: number;
70
- }
71
-
72
- // ============================================================================
73
- // WORKFLOW EVENT — emitted by on_enter / transition actions
74
- // ============================================================================
75
-
76
- export interface WorkflowEvent {
77
- event: string;
78
- instanceId: string;
79
- definitionSlug: string;
80
- }
81
-
82
- /** Extended instance type carrying pending events from on_enter actions */
83
- export interface WorkflowInstanceWithEvents extends WorkflowInstance {
84
- _pendingEvents?: WorkflowEvent[];
85
- }
86
-
87
- // ============================================================================
88
- // ENGINE
89
- // ============================================================================
90
-
91
- /** Callback type for event subscriptions */
92
- export type WorkflowEventHandler = (event: WorkflowEvent) => void;
93
-
94
- export class LocalWorkflowEngine {
95
- private definitions = new Map<string, WorkflowDefinition>();
96
- private eventSubscriptions = new Map<string, Set<WorkflowEventHandler>>();
97
-
98
- /** Register a workflow definition by slug */
99
- registerDefinition(def: WorkflowDefinition): void {
100
- this.definitions.set(def.slug, def);
101
- }
102
-
103
- /** Get a registered definition */
104
- getDefinition(slug: string): WorkflowDefinition | undefined {
105
- return this.definitions.get(slug);
106
- }
107
-
108
- /** Get all registered definitions */
109
- getAllDefinitions(): WorkflowDefinition[] {
110
- return Array.from(this.definitions.values());
111
- }
112
-
113
- /** Check if a definition is registered */
114
- hasDefinition(slug: string): boolean {
115
- return this.definitions.has(slug);
116
- }
117
-
118
- /**
119
- * Subscribe to a workflow event by name.
120
- * Returns an unsubscribe function.
121
- */
122
- onEvent(eventName: string, handler: WorkflowEventHandler): () => void {
123
- let handlers = this.eventSubscriptions.get(eventName);
124
- if (!handlers) {
125
- handlers = new Set();
126
- this.eventSubscriptions.set(eventName, handlers);
127
- }
128
- handlers.add(handler);
129
- return () => {
130
- handlers!.delete(handler);
131
- if (handlers!.size === 0) {
132
- this.eventSubscriptions.delete(eventName);
133
- }
134
- };
135
- }
136
-
137
- /**
138
- * Emit a workflow event to all local subscribers.
139
- * Called after applyTransition when _pendingEvents are present.
140
- */
141
- emitEvent(event: WorkflowEvent): void {
142
- const handlers = this.eventSubscriptions.get(event.event);
143
- if (handlers) {
144
- for (const handler of handlers) {
145
- try {
146
- handler(event);
147
- } catch (err) {
148
- console.error(`[WorkflowEngine] Event handler error for "${event.event}":`, err);
149
- }
150
- }
151
- }
152
- }
153
-
154
- /**
155
- * Process all pending events from a transition result.
156
- * Emits locally and returns the events for P2P broadcast.
157
- */
158
- processPendingEvents(instance: WorkflowInstance): WorkflowEvent[] {
159
- const events = (instance as WorkflowInstanceWithEvents)._pendingEvents;
160
- if (!events?.length) return [];
161
- for (const evt of events) {
162
- this.emitEvent(evt);
163
- }
164
- return events;
165
- }
166
-
167
- /** Create a new workflow instance from a definition */
168
- createInstance(
169
- slug: string,
170
- id: string,
171
- initialFields?: Record<string, unknown>
172
- ): WorkflowInstance {
173
- const def = this.definitions.get(slug);
174
- if (!def) {
175
- throw new Error(`WorkflowDefinition not found: ${slug}`);
176
- }
177
-
178
- // Find the START state (support both state_type and type field naming)
179
- const startState = def.states.find(
180
- (s) => s.state_type === 'START' || (s as unknown as Record<string, unknown>).type === 'START',
181
- );
182
- if (!startState) {
183
- throw new Error(`No START state in definition: ${slug}`);
184
- }
185
-
186
- // Build default field values from definition
187
- const fields: Record<string, unknown> = {};
188
- for (const fieldDef of def.fields) {
189
- fields[fieldDef.name] = fieldDef.default_value ?? null;
190
- }
191
-
192
- // Merge state_data defaults
193
- if (def.state_data) {
194
- for (const [key, value] of Object.entries(def.state_data)) {
195
- if (!(key in fields)) {
196
- fields[key] = value;
197
- }
198
- }
199
- }
200
-
201
- // Override with caller-provided initial values
202
- if (initialFields) {
203
- Object.assign(fields, initialFields);
204
- }
205
-
206
- return {
207
- id,
208
- definitionSlug: slug,
209
- currentState: startState.name,
210
- fields,
211
- version: 0,
212
- updatedAt: Date.now(),
213
- };
214
- }
215
-
216
- /** Check if a transition can fire from the instance's current state */
217
- canTransition(instance: WorkflowInstance, transitionName: string): boolean {
218
- const def = this.definitions.get(instance.definitionSlug);
219
- if (!def) return false;
220
-
221
- const transition = def.transitions.find((t) => t.name === transitionName);
222
- if (!transition) return false;
223
-
224
- return transition.from.includes(instance.currentState);
225
- }
226
-
227
- /** Get all transitions available from the instance's current state */
228
- getAvailableTransitions(instance: WorkflowInstance): string[] {
229
- const def = this.definitions.get(instance.definitionSlug);
230
- if (!def) return [];
231
-
232
- return def.transitions
233
- .filter((t) => t.from.includes(instance.currentState))
234
- .map((t) => t.name);
235
- }
236
-
237
- /**
238
- * Apply a transition, returning a new WorkflowInstance (immutable).
239
- *
240
- * @param instance - Current instance state
241
- * @param transitionName - Name of the transition to apply
242
- * @param data - Optional field updates to merge into instance fields
243
- * @returns New WorkflowInstance with updated state and version
244
- * @throws If transition is not valid from current state
245
- */
246
- applyTransition(
247
- instance: WorkflowInstance,
248
- transitionName: string,
249
- data?: Record<string, unknown>
250
- ): WorkflowInstance {
251
- const def = this.definitions.get(instance.definitionSlug);
252
- if (!def) {
253
- throw new Error(`Definition not found: ${instance.definitionSlug}`);
254
- }
255
-
256
- const transition = def.transitions.find((t) => t.name === transitionName);
257
- if (!transition) {
258
- throw new Error(
259
- `Transition "${transitionName}" not found in ${instance.definitionSlug}`
260
- );
261
- }
262
-
263
- if (!transition.from.includes(instance.currentState)) {
264
- throw new Error(
265
- `Transition "${transitionName}" cannot fire from state "${instance.currentState}" ` +
266
- `(allowed from: ${transition.from.join(', ')})`
267
- );
268
- }
269
-
270
- // Determine target state: null means self-loop (stay in current state)
271
- const nextState = transition.to ?? instance.currentState;
272
-
273
- // Merge field updates
274
- const fields = data
275
- ? { ...instance.fields, ...data }
276
- : { ...instance.fields };
277
-
278
- let result: WorkflowInstance = {
279
- ...instance,
280
- currentState: nextState,
281
- fields,
282
- version: instance.version + 1,
283
- updatedAt: Date.now(),
284
- };
285
-
286
- // Execute on_enter actions for the target state
287
- const targetStateDef = def.states.find((s) => s.name === nextState);
288
- if (targetStateDef) {
289
- const onEnter = (targetStateDef as unknown as Record<string, unknown>).on_enter as
290
- | Array<{ action_type: string; config?: Record<string, unknown> }>
291
- | undefined;
292
-
293
- if (onEnter) {
294
- const pendingEvents: WorkflowEvent[] = [];
295
-
296
- for (const action of onEnter) {
297
- if (action.action_type === 'emit_event' && action.config) {
298
- pendingEvents.push({
299
- event: action.config.event as string,
300
- instanceId: result.id,
301
- definitionSlug: result.definitionSlug,
302
- });
303
- }
304
- if (action.action_type === 'set_field' && action.config) {
305
- const field = action.config.field as string;
306
- const expression = action.config.expression as string;
307
- if (field && expression) {
308
- if (expression.startsWith('$.transition_data.') && data) {
309
- const key = expression.replace('$.transition_data.', '');
310
- result = {
311
- ...result,
312
- fields: { ...result.fields, [field]: data[key] },
313
- };
314
- }
315
- }
316
- }
317
- }
318
-
319
- if (pendingEvents.length > 0) {
320
- (result as WorkflowInstanceWithEvents)._pendingEvents = pendingEvents;
321
- }
322
- }
323
- }
324
-
325
- // Execute transition-level actions (e.g., set_field, emit_event)
326
- const transitionActions = (transition as unknown as Record<string, unknown>).actions as
327
- | Array<{ action_type: string; config?: Record<string, unknown> }>
328
- | undefined;
329
-
330
- if (transitionActions) {
331
- for (const action of transitionActions) {
332
- if (action.action_type === 'set_field' && action.config) {
333
- const field = action.config.field as string;
334
- const expression = action.config.expression as string;
335
- if (field && expression) {
336
- if (expression.startsWith('$.transition_data.') && data) {
337
- const key = expression.replace('$.transition_data.', '');
338
- result = {
339
- ...result,
340
- fields: { ...result.fields, [field]: data[key] },
341
- };
342
- } else if (expression === 'now()') {
343
- result = {
344
- ...result,
345
- fields: { ...result.fields, [field]: new Date().toISOString() },
346
- };
347
- }
348
- }
349
- }
350
- if (action.action_type === 'emit_event' && action.config) {
351
- const events = (result as WorkflowInstanceWithEvents)._pendingEvents || [];
352
- events.push({
353
- event: action.config.event as string,
354
- instanceId: result.id,
355
- definitionSlug: result.definitionSlug,
356
- });
357
- (result as WorkflowInstanceWithEvents)._pendingEvents = events;
358
- }
359
- }
360
- }
361
-
362
- return result;
363
- }
364
-
365
- /**
366
- * Apply a transition only if the incoming version is newer.
367
- * Used for P2P sync — skips stale transitions.
368
- */
369
- applyRemoteTransition(
370
- instance: WorkflowInstance,
371
- transitionName: string,
372
- data: Record<string, unknown> | undefined,
373
- remoteVersion: number
374
- ): WorkflowInstance | null {
375
- // Skip stale transitions
376
- if (remoteVersion <= instance.version) {
377
- return null;
378
- }
379
-
380
- if (!this.canTransition(instance, transitionName)) {
381
- return null;
382
- }
383
-
384
- const updated = this.applyTransition(instance, transitionName, data);
385
- // Use the remote version to stay in sync
386
- return { ...updated, version: remoteVersion };
387
- }
388
- }
@@ -1,175 +0,0 @@
1
- /**
2
- * LocalEngineDataSourceAdapter — Adapter for querying LocalWorkflowEngine
3
- * from within ComponentTreeRenderer context.
4
- *
5
- * Provides the same interface as backend API queries but reads from the
6
- * local workflow engine instead. Fully generic — no workflow-specific concepts.
7
- */
8
-
9
- import type { LocalWorkflowEngine, WorkflowInstance } from './LocalEngine';
10
- import type { LocalEngineStore } from './LocalEngineContext';
11
-
12
- export interface WorkflowDataSource {
13
- type: 'workflow';
14
- slug?: string;
15
- query?: 'latest' | 'list';
16
- filters?: Record<string, unknown>;
17
- filter?: Record<string, unknown>;
18
- }
19
-
20
- export interface DataSource {
21
- type: string;
22
- }
23
-
24
- export interface DataSourceResult {
25
- instance?: unknown;
26
- instances?: unknown[];
27
- loading: boolean;
28
- error: Error | null;
29
- }
30
-
31
- export interface InstanceData {
32
- id: string;
33
- current_state: string;
34
- state_data?: Record<string, unknown>;
35
- /** Alias for state_data — compiled views reference $item.fields.x */
36
- fields?: Record<string, unknown>;
37
- created_at?: string;
38
- updated_at?: string;
39
- }
40
-
41
- export type LocalDataResolver = (source: DataSource, localState: Record<string, unknown>) => DataSourceResult | null;
42
-
43
- export interface LocalEngineAdapter {
44
- query(dataSource: WorkflowDataSource, localState: Record<string, unknown>): DataSourceResult;
45
- }
46
-
47
- /**
48
- * Convert a WorkflowInstance to InstanceData for CTR consumption.
49
- */
50
- function instanceToData(inst: WorkflowInstance): InstanceData {
51
- const fieldsCopy = { ...inst.fields };
52
- return {
53
- id: inst.id,
54
- current_state: inst.currentState,
55
- state_data: fieldsCopy,
56
- // Alias: compiled views reference $item.fields.x instead of $item.state_data.x
57
- fields: fieldsCopy,
58
- created_at: inst.fields.created_at as string | undefined,
59
- updated_at: inst.fields.updated_at as string | undefined,
60
- };
61
- }
62
-
63
- /**
64
- * Create an adapter that queries a LocalWorkflowEngine.
65
- * Supports list queries with filter expressions.
66
- */
67
- export function createLocalEngineAdapter(
68
- _engine: LocalWorkflowEngine,
69
- store: LocalEngineStore,
70
- ): LocalEngineAdapter {
71
- return {
72
- query(dataSource: WorkflowDataSource, localState: Record<string, unknown>): DataSourceResult {
73
- const { slug, query, filters, filter: staticFilter } = dataSource;
74
-
75
- if (!slug) {
76
- return { loading: false, error: new Error('LocalEngineAdapter: slug is required') };
77
- }
78
-
79
- // Handle app instance
80
- if (store.app && store.app.definitionSlug === slug) {
81
- return {
82
- instance: instanceToData(store.app),
83
- loading: false,
84
- error: null,
85
- };
86
- }
87
-
88
- // Look up the instance map for this slug
89
- const instanceMap = store.instances?.get(slug);
90
- if (!instanceMap || typeof instanceMap.values !== 'function') {
91
- return { instances: [], loading: false, error: null };
92
- }
93
-
94
- // Convert map values to InstanceData array
95
- let instances = Array.from(instanceMap.values()).map(instanceToData);
96
-
97
- // Apply filters (merge static + dynamic)
98
- const allFilters = { ...staticFilter, ...filters };
99
- if (allFilters && Object.keys(allFilters).length > 0) {
100
- instances = instances.filter((inst) => {
101
- for (const [key, valueExpr] of Object.entries(allFilters)) {
102
- let expectedValue: unknown;
103
-
104
- // Resolve bind expressions like { bind: '$local.some_field_id' }
105
- if (typeof valueExpr === 'object' && valueExpr !== null && 'bind' in valueExpr) {
106
- const bindExpr = (valueExpr as { bind: string }).bind;
107
- if (bindExpr.startsWith('$local.')) {
108
- const localKey = bindExpr.slice(7);
109
- expectedValue = localState[localKey];
110
- } else if (bindExpr.startsWith('$item.')) {
111
- // For slot contributions, $item is the parent instance
112
- // This is handled by the slot resolver, not here
113
- continue;
114
- } else {
115
- expectedValue = bindExpr;
116
- }
117
- } else {
118
- expectedValue = valueExpr;
119
- }
120
-
121
- // Compare field value (look in state_data)
122
- const actualValue = inst.state_data?.[key];
123
- if (actualValue !== expectedValue) {
124
- return false;
125
- }
126
- }
127
- return true;
128
- });
129
- }
130
-
131
- // For 'latest', return single instance
132
- if (query === 'latest') {
133
- return {
134
- instance: instances[0],
135
- instances: undefined,
136
- loading: false,
137
- error: null,
138
- };
139
- }
140
-
141
- // For 'list', return array
142
- return {
143
- instances,
144
- loading: false,
145
- error: null,
146
- };
147
- },
148
- };
149
- }
150
-
151
- /**
152
- * Create a LocalDataResolver function compatible with useExperienceData.
153
- * Returns non-null DataSourceResult for slugs handled by the local engine,
154
- * null for everything else (falls through to server API).
155
- */
156
- export function createLocalDataResolver(
157
- engine: LocalWorkflowEngine,
158
- store: LocalEngineStore,
159
- ): LocalDataResolver {
160
- const adapter = createLocalEngineAdapter(engine, store);
161
-
162
- return (source: DataSource, localState: Record<string, unknown>): DataSourceResult | null => {
163
- // Only handle workflow dataSources
164
- if (source.type !== 'workflow') return null;
165
- const wfSource = source as WorkflowDataSource;
166
- if (!wfSource.slug) return null;
167
-
168
- // Check if this slug is served by the local engine
169
- if (store.app?.definitionSlug === wfSource.slug || store.instances?.has(wfSource.slug)) {
170
- return adapter.query(wfSource, localState);
171
- }
172
-
173
- return null;
174
- };
175
- }
@@ -1,30 +0,0 @@
1
- /**
2
- * LocalEngineContext — Provides local workflow engine to ComponentTreeRenderer
3
- *
4
- * Used for P2P features where workflow instances are stored
5
- * locally instead of on the server. Fully generic — no workflow-specific concepts.
6
- */
7
-
8
- import { createContext, useContext } from 'react';
9
- import type { LocalWorkflowEngine, WorkflowInstance } from './LocalEngine';
10
-
11
- export interface LocalEngineStore {
12
- app?: WorkflowInstance;
13
- /** Generic slug-keyed instance maps: slug → (id → instance) */
14
- instances: Map<string, Map<string, WorkflowInstance>>;
15
- }
16
-
17
- export interface LocalEngineContextValue {
18
- engine: LocalWorkflowEngine;
19
- store: LocalEngineStore;
20
- /** Generic action dispatch — blueprint-specific actions keyed by name */
21
- actions?: Record<string, (data?: unknown) => void>;
22
- }
23
-
24
- const LocalEngineContext = createContext<LocalEngineContextValue | null>(null);
25
-
26
- export function useLocalEngine(): LocalEngineContextValue | null {
27
- return useContext(LocalEngineContext);
28
- }
29
-
30
- export const LocalEngineProvider = LocalEngineContext.Provider;
package/src/logger.ts DELETED
@@ -1,37 +0,0 @@
1
- /**
2
- * Player Logger — structured console.warn logging for event matching and action dispatch.
3
- */
4
-
5
- import type { PlayerLogEntry } from './types';
6
-
7
- let debugEnabled = false;
8
-
9
- export function setPlayerDebug(enabled: boolean): void {
10
- debugEnabled = enabled;
11
- }
12
-
13
- export function isPlayerDebug(): boolean {
14
- return debugEnabled;
15
- }
16
-
17
- export function playerLog(entry: Omit<PlayerLogEntry, 'timestamp'>): void {
18
- if (!debugEnabled && entry.level === 'debug') return;
19
-
20
- const prefix = `[player-web:${entry.category}]`;
21
- const msg = `${prefix} ${entry.message}`;
22
-
23
- switch (entry.level) {
24
- case 'error':
25
- console.error(msg, entry.data ?? '');
26
- break;
27
- case 'warn':
28
- console.warn(msg, entry.data ?? '');
29
- break;
30
- case 'info':
31
- console.info(msg, entry.data ?? '');
32
- break;
33
- case 'debug':
34
- console.debug(msg, entry.data ?? '');
35
- break;
36
- }
37
- }