@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,347 +0,0 @@
1
- /**
2
- * useRouter — Client-side routing with nested routes, dynamic params, and route guards.
3
- *
4
- * Provides Next.js-style routing within workflow applications.
5
- * Supports dynamic segments (/ride/:id), nested routes, query params,
6
- * and guard functions for auth/permission checks before navigation.
7
- *
8
- * Usage in .workflow.tsx:
9
- * const router = useRouter();
10
- * router.push('/rides/abc123');
11
- * router.push('/rides/abc123?tab=details');
12
- *
13
- * // With guard
14
- * const router = useRouter({
15
- * guards: [requireAuth, requireRole('driver')],
16
- * });
17
- */
18
-
19
- import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
20
-
21
- // =============================================================================
22
- // Types
23
- // =============================================================================
24
-
25
- /** Route definition for configuring application routes. */
26
- export interface RouteDefinition {
27
- /** URL path pattern (supports :param dynamic segments). */
28
- path: string;
29
- /** Route guard functions — must all return true to allow navigation. */
30
- guards?: RouteGuard[];
31
- /** Redirect path if guards fail. */
32
- redirectOnFail?: string;
33
- /** Nested child routes. */
34
- children?: RouteDefinition[];
35
- /** Metadata attached to the route. */
36
- meta?: Record<string, unknown>;
37
- }
38
-
39
- /** Guard function that determines if navigation is allowed. */
40
- export type RouteGuard = (to: RouteLocation, from: RouteLocation | null) => boolean | Promise<boolean>;
41
-
42
- /** Represents a parsed route location. */
43
- export interface RouteLocation {
44
- /** The full pathname (e.g., '/rides/abc123'). */
45
- pathname: string;
46
- /** Parsed dynamic params (e.g., { id: 'abc123' }). */
47
- params: Record<string, string>;
48
- /** Parsed query string params. */
49
- query: Record<string, string>;
50
- /** URL hash fragment (without #). */
51
- hash: string;
52
- /** The matched route definition, if any. */
53
- matched?: RouteDefinition;
54
- /** Route metadata from matched definition. */
55
- meta: Record<string, unknown>;
56
- }
57
-
58
- /** Options for configuring the router. */
59
- export interface RouterOptions {
60
- /** Route definitions for matching and guards. */
61
- routes?: RouteDefinition[];
62
- /** Global guards applied to every navigation. */
63
- guards?: RouteGuard[];
64
- /** Called when a guard blocks navigation. */
65
- onGuardReject?: (to: RouteLocation) => void;
66
- /** Base path prefix (e.g., '/app'). */
67
- basePath?: string;
68
- }
69
-
70
- /** Router handle returned by useRouter. */
71
- export interface RouterHandle {
72
- /** Current route location. */
73
- location: RouteLocation;
74
- /** Current pathname. */
75
- pathname: string;
76
- /** Current dynamic params. */
77
- params: Record<string, string>;
78
- /** Current query params. */
79
- query: Record<string, string>;
80
- /** Current hash. */
81
- hash: string;
82
- /** Navigate to a new path (pushState). */
83
- push: (path: string) => Promise<boolean>;
84
- /** Replace current path (replaceState). */
85
- replace: (path: string) => Promise<boolean>;
86
- /** Go back in history. */
87
- back: () => void;
88
- /** Go forward in history. */
89
- forward: () => void;
90
- /** Check if a path matches a pattern. */
91
- isActive: (pattern: string) => boolean;
92
- /** Whether a navigation is in progress (guards running). */
93
- isNavigating: boolean;
94
- }
95
-
96
- // =============================================================================
97
- // Internal helpers
98
- // =============================================================================
99
-
100
- /** Parse a URL path into segments. */
101
- function parsePath(fullPath: string, basePath: string): { pathname: string; query: Record<string, string>; hash: string } {
102
- let path = fullPath;
103
-
104
- // Strip base path prefix
105
- if (basePath && path.startsWith(basePath)) {
106
- path = path.slice(basePath.length) || '/';
107
- }
108
-
109
- // Extract hash
110
- const hashIdx = path.indexOf('#');
111
- let hash = '';
112
- if (hashIdx !== -1) {
113
- hash = path.slice(hashIdx + 1);
114
- path = path.slice(0, hashIdx);
115
- }
116
-
117
- // Extract query
118
- const queryIdx = path.indexOf('?');
119
- const query: Record<string, string> = {};
120
- if (queryIdx !== -1) {
121
- const qs = path.slice(queryIdx + 1);
122
- path = path.slice(0, queryIdx);
123
- for (const pair of qs.split('&')) {
124
- const eqIdx = pair.indexOf('=');
125
- if (eqIdx !== -1) {
126
- query[decodeURIComponent(pair.slice(0, eqIdx))] = decodeURIComponent(pair.slice(eqIdx + 1));
127
- } else if (pair) {
128
- query[decodeURIComponent(pair)] = '';
129
- }
130
- }
131
- }
132
-
133
- return { pathname: path || '/', query, hash };
134
- }
135
-
136
- /** Match a path against a route pattern, extracting dynamic params. */
137
- function matchRoute(
138
- pathname: string,
139
- pattern: string,
140
- ): { match: boolean; params: Record<string, string> } {
141
- const pathParts = pathname.split('/').filter(Boolean);
142
- const patternParts = pattern.split('/').filter(Boolean);
143
-
144
- // Wildcard catch-all
145
- if (patternParts[patternParts.length - 1] === '*') {
146
- const staticParts = patternParts.slice(0, -1);
147
- if (pathParts.length < staticParts.length) return { match: false, params: {} };
148
- const params: Record<string, string> = {};
149
- for (let i = 0; i < staticParts.length; i++) {
150
- const pp = staticParts[i];
151
- if (pp.startsWith(':')) {
152
- params[pp.slice(1)] = pathParts[i];
153
- } else if (pp !== pathParts[i]) {
154
- return { match: false, params: {} };
155
- }
156
- }
157
- params['*'] = pathParts.slice(staticParts.length).join('/');
158
- return { match: true, params };
159
- }
160
-
161
- if (pathParts.length !== patternParts.length) return { match: false, params: {} };
162
-
163
- const params: Record<string, string> = {};
164
- for (let i = 0; i < patternParts.length; i++) {
165
- const pp = patternParts[i];
166
- if (pp.startsWith(':')) {
167
- params[pp.slice(1)] = pathParts[i];
168
- } else if (pp !== pathParts[i]) {
169
- return { match: false, params: {} };
170
- }
171
- }
172
-
173
- return { match: true, params };
174
- }
175
-
176
- /** Find a matching route definition (supports nested routes). */
177
- function findRoute(
178
- pathname: string,
179
- routes: RouteDefinition[],
180
- parentPath: string = '',
181
- ): { route: RouteDefinition; params: Record<string, string> } | null {
182
- for (const route of routes) {
183
- const fullPattern = parentPath + route.path;
184
- const result = matchRoute(pathname, fullPattern);
185
-
186
- if (result.match) {
187
- return { route, params: result.params };
188
- }
189
-
190
- // Check children
191
- if (route.children) {
192
- const childResult = findRoute(pathname, route.children, fullPattern);
193
- if (childResult) return childResult;
194
- }
195
- }
196
-
197
- return null;
198
- }
199
-
200
- /** Build a RouteLocation from current browser state. */
201
- function buildLocation(basePath: string, routes: RouteDefinition[]): RouteLocation {
202
- const { pathname, query, hash } = parsePath(
203
- typeof window !== 'undefined' ? window.location.pathname + window.location.search + window.location.hash : '/',
204
- basePath,
205
- );
206
-
207
- const found = findRoute(pathname, routes);
208
-
209
- return {
210
- pathname,
211
- params: found?.params ?? {},
212
- query,
213
- hash,
214
- matched: found?.route,
215
- meta: found?.route?.meta ?? {},
216
- };
217
- }
218
-
219
- // =============================================================================
220
- // Hook
221
- // =============================================================================
222
-
223
- /**
224
- * Client-side router with nested routes, dynamic params, and guards.
225
- *
226
- * @param options - Router configuration (routes, guards, basePath).
227
- * @returns Router handle with navigation methods and current location.
228
- */
229
- export function useRouter(options: RouterOptions = {}): RouterHandle {
230
- const { routes = [], guards: globalGuards = [], onGuardReject, basePath = '' } = options;
231
-
232
- const routesRef = useRef(routes);
233
- routesRef.current = routes;
234
- const guardsRef = useRef(globalGuards);
235
- guardsRef.current = globalGuards;
236
- const onRejectRef = useRef(onGuardReject);
237
- onRejectRef.current = onGuardReject;
238
- const basePathRef = useRef(basePath);
239
- basePathRef.current = basePath;
240
-
241
- const [location, setLocation] = useState<RouteLocation>(() =>
242
- buildLocation(basePath, routes),
243
- );
244
- const [isNavigating, setIsNavigating] = useState(false);
245
-
246
- // Listen to popstate (back/forward)
247
- useEffect(() => {
248
- const handler = () => {
249
- setLocation(buildLocation(basePathRef.current, routesRef.current));
250
- };
251
- window.addEventListener('popstate', handler);
252
- return () => window.removeEventListener('popstate', handler);
253
- }, []);
254
-
255
- const navigate = useCallback(
256
- async (path: string, replace: boolean): Promise<boolean> => {
257
- const { pathname, query, hash } = parsePath(path, basePathRef.current);
258
- const found = findRoute(pathname, routesRef.current);
259
-
260
- const to: RouteLocation = {
261
- pathname,
262
- params: found?.params ?? {},
263
- query,
264
- hash,
265
- matched: found?.route,
266
- meta: found?.route?.meta ?? {},
267
- };
268
-
269
- // Run guards
270
- setIsNavigating(true);
271
- try {
272
- // Global guards
273
- for (const guard of guardsRef.current) {
274
- const allowed = await guard(to, location);
275
- if (!allowed) {
276
- onRejectRef.current?.(to);
277
- return false;
278
- }
279
- }
280
-
281
- // Route-specific guards
282
- if (found?.route?.guards) {
283
- for (const guard of found.route.guards) {
284
- const allowed = await guard(to, location);
285
- if (!allowed) {
286
- if (found.route.redirectOnFail) {
287
- const fullRedirect = basePathRef.current + found.route.redirectOnFail;
288
- window.history.pushState(null, '', fullRedirect);
289
- setLocation(buildLocation(basePathRef.current, routesRef.current));
290
- }
291
- onRejectRef.current?.(to);
292
- return false;
293
- }
294
- }
295
- }
296
-
297
- // Navigate
298
- const fullPath = basePathRef.current + path;
299
- if (replace) {
300
- window.history.replaceState(null, '', fullPath);
301
- } else {
302
- window.history.pushState(null, '', fullPath);
303
- }
304
- setLocation(to);
305
- return true;
306
- } finally {
307
- setIsNavigating(false);
308
- }
309
- },
310
- [location],
311
- );
312
-
313
- const push = useCallback((path: string) => navigate(path, false), [navigate]);
314
- const replace = useCallback((path: string) => navigate(path, true), [navigate]);
315
-
316
- const back = useCallback(() => {
317
- window.history.back();
318
- }, []);
319
-
320
- const forward = useCallback(() => {
321
- window.history.forward();
322
- }, []);
323
-
324
- const isActive = useCallback(
325
- (pattern: string) => {
326
- return matchRoute(location.pathname, pattern).match;
327
- },
328
- [location.pathname],
329
- );
330
-
331
- return useMemo(
332
- (): RouterHandle => ({
333
- location,
334
- pathname: location.pathname,
335
- params: location.params,
336
- query: location.query,
337
- hash: location.hash,
338
- push,
339
- replace,
340
- back,
341
- forward,
342
- isActive,
343
- isNavigating,
344
- }),
345
- [location, push, replace, back, forward, isActive, isNavigating],
346
- );
347
- }
@@ -1,178 +0,0 @@
1
- /**
2
- * useServerAction — invoke server-side workflow actions from .workflow.tsx.
3
- *
4
- * Registers a named action that POSTs to the Rust API for server-side execution.
5
- * Handles loading, error, and optimistic state.
6
- *
7
- * Usage in .workflow.tsx:
8
- * const approve = useServerAction('approve-order', {
9
- * instanceId: orderId,
10
- * onSuccess: () => refetch(),
11
- * });
12
- *
13
- * <Button onClick={() => approve.execute({ comment: 'Looks good' })}>
14
- * {approve.loading ? 'Approving...' : 'Approve'}
15
- * </Button>
16
- *
17
- * The compiler extracts this as a server action dependency in the IR.
18
- * At runtime, the hook POSTs to /api/v1/workflow/instances/{id}/actions/{name}.
19
- */
20
-
21
- import { useState, useCallback, useRef } from 'react';
22
-
23
- // =============================================================================
24
- // Types
25
- // =============================================================================
26
-
27
- export interface ServerActionOptions {
28
- /** The workflow instance ID to execute the action against. */
29
- instanceId: string;
30
- /** Optional definition ID — when present, uses the path-param endpoint. */
31
- definitionId?: string;
32
- /** Called after a successful action execution. */
33
- onSuccess?: (result: ServerActionResult) => void;
34
- /** Called after a failed action execution. */
35
- onError?: (error: Error) => void;
36
- }
37
-
38
- export interface ServerActionResult {
39
- success: boolean;
40
- action_id: string;
41
- action_type?: string;
42
- triggered_by?: string;
43
- data?: Record<string, unknown>;
44
- }
45
-
46
- export interface ServerActionHandle {
47
- /** Execute the server action with optional input payload. */
48
- execute: (input?: Record<string, unknown>) => Promise<ServerActionResult>;
49
- /** Whether the action is currently executing. */
50
- loading: boolean;
51
- /** Error from the last execution attempt. */
52
- error: Error | null;
53
- /** Result from the last successful execution. */
54
- result: ServerActionResult | null;
55
- /** Reset error and result state. */
56
- reset: () => void;
57
- }
58
-
59
- /**
60
- * Resolver interface — the runtime must provide an implementation.
61
- * Typically set by WorkflowProvider or a top-level setup call.
62
- */
63
- export interface ServerActionResolver {
64
- executeAction: (
65
- instanceId: string,
66
- actionName: string,
67
- input?: Record<string, unknown>,
68
- definitionId?: string,
69
- ) => Promise<ServerActionResult>;
70
- }
71
-
72
- // Global resolver (set by provider)
73
- let _globalServerActionResolver: ServerActionResolver | null = null;
74
-
75
- export function setServerActionResolver(resolver: ServerActionResolver | null): void {
76
- _globalServerActionResolver = resolver;
77
- }
78
-
79
- /**
80
- * Default resolver that POSTs to the Rust API.
81
- * Used when no custom resolver is configured.
82
- */
83
- function getDefaultResolver(): ServerActionResolver {
84
- return {
85
- async executeAction(instanceId, actionName, input, definitionId) {
86
- const token = typeof localStorage !== 'undefined'
87
- ? localStorage.getItem('auth_token')
88
- : null;
89
-
90
- // Use path-param endpoint when definitionId is provided
91
- const url = definitionId
92
- ? `/api/v1/workflow/server-actions/${encodeURIComponent(definitionId)}/${encodeURIComponent(actionName)}`
93
- : `/api/v1/workflow/instances/${encodeURIComponent(instanceId)}/actions/${encodeURIComponent(actionName)}`;
94
-
95
- const body = definitionId
96
- ? JSON.stringify({ instance_id: instanceId || undefined, payload: input })
97
- : input ? JSON.stringify(input) : undefined;
98
-
99
- const res = await fetch(url, {
100
- method: 'POST',
101
- headers: {
102
- 'Content-Type': 'application/json',
103
- ...(token ? { Authorization: `Bearer ${token}` } : {}),
104
- },
105
- body,
106
- });
107
-
108
- if (!res.ok) {
109
- const errBody = await res.json().catch(() => ({ message: res.statusText }));
110
- throw new Error(errBody.message || errBody.error || `Server action failed: ${res.status}`);
111
- }
112
-
113
- return res.json();
114
- },
115
- };
116
- }
117
-
118
- // =============================================================================
119
- // Hook
120
- // =============================================================================
121
-
122
- /**
123
- * Registers a server-side action and returns a callable handle.
124
- *
125
- * @param actionName - The action identifier (matches pending_actions or transition name).
126
- * @param options - Instance ID and optional callbacks.
127
- * @returns Handle with execute(), loading, error, and result.
128
- */
129
- export function useServerAction(
130
- actionName: string,
131
- options: ServerActionOptions,
132
- ): ServerActionHandle {
133
- const [loading, setLoading] = useState(false);
134
- const [error, setError] = useState<Error | null>(null);
135
- const [result, setResult] = useState<ServerActionResult | null>(null);
136
-
137
- const optionsRef = useRef(options);
138
- optionsRef.current = options;
139
-
140
- const execute = useCallback(
141
- async (input?: Record<string, unknown>): Promise<ServerActionResult> => {
142
- const resolver = _globalServerActionResolver || getDefaultResolver();
143
- const { instanceId, definitionId, onSuccess, onError } = optionsRef.current;
144
-
145
- try {
146
- setLoading(true);
147
- setError(null);
148
-
149
- const actionResult = await resolver.executeAction(instanceId, actionName, input, definitionId);
150
- setResult(actionResult);
151
- onSuccess?.(actionResult);
152
- return actionResult;
153
- } catch (err) {
154
- const e = err instanceof Error ? err : new Error(String(err));
155
- setError(e);
156
- onError?.(e);
157
- throw e;
158
- } finally {
159
- setLoading(false);
160
- }
161
- },
162
- [actionName],
163
- );
164
-
165
- const reset = useCallback(() => {
166
- setError(null);
167
- setResult(null);
168
- }, []);
169
-
170
- const handle: ServerActionHandle = {
171
- execute,
172
- loading,
173
- error,
174
- result,
175
- reset,
176
- };
177
- return handle;
178
- }