joopjs 2.0.6 → 2.1.0

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 (140) hide show
  1. package/.claude/skills/observables.md +28 -0
  2. package/.claude/skills/setup.md +14 -3
  3. package/.cursor/rules/joopjs.mdc +4 -5
  4. package/.github/copilot-instructions.md +3 -1
  5. package/.windsurf/rules/joopjs.md +4 -0
  6. package/CHANGELOG.md +31 -2
  7. package/README.md +19 -7
  8. package/ai-rules/AGENTS.md +21 -0
  9. package/ai-rules/GEMINI.md +17 -3
  10. package/dist/ai/index.js +15 -3
  11. package/dist/ai/index.js.map +1 -1
  12. package/dist/ai/index.mjs +15 -3
  13. package/dist/ai/index.mjs.map +1 -1
  14. package/dist/analytics/index.js +10 -2
  15. package/dist/analytics/index.js.map +1 -1
  16. package/dist/analytics/index.mjs +10 -2
  17. package/dist/analytics/index.mjs.map +1 -1
  18. package/dist/angular/index.d.mts +98 -27
  19. package/dist/angular/index.d.ts +98 -27
  20. package/dist/angular/index.js +44 -0
  21. package/dist/angular/index.js.map +1 -1
  22. package/dist/angular/index.mjs +39 -1
  23. package/dist/angular/index.mjs.map +1 -1
  24. package/dist/api/index.js +15 -3
  25. package/dist/api/index.js.map +1 -1
  26. package/dist/api/index.mjs +15 -3
  27. package/dist/api/index.mjs.map +1 -1
  28. package/dist/auth/index.js +15 -3
  29. package/dist/auth/index.js.map +1 -1
  30. package/dist/auth/index.mjs +15 -3
  31. package/dist/auth/index.mjs.map +1 -1
  32. package/dist/banking/index.js +15 -3
  33. package/dist/banking/index.js.map +1 -1
  34. package/dist/banking/index.mjs +15 -3
  35. package/dist/banking/index.mjs.map +1 -1
  36. package/dist/cache/index.js +15 -3
  37. package/dist/cache/index.js.map +1 -1
  38. package/dist/cache/index.mjs +15 -3
  39. package/dist/cache/index.mjs.map +1 -1
  40. package/dist/{index-DFqEoX_l.d.ts → consent.service-CIHNtx9h.d.ts} +1 -2
  41. package/dist/{index-B_ksKpS1.d.mts → consent.service-DQ-JAEJx.d.mts} +1 -2
  42. package/dist/core/index.d.mts +34 -1
  43. package/dist/core/index.d.ts +34 -1
  44. package/dist/core/index.js +56 -5
  45. package/dist/core/index.js.map +1 -1
  46. package/dist/core/index.mjs +54 -6
  47. package/dist/core/index.mjs.map +1 -1
  48. package/dist/deeplink/index.js +15 -3
  49. package/dist/deeplink/index.js.map +1 -1
  50. package/dist/deeplink/index.mjs +15 -3
  51. package/dist/deeplink/index.mjs.map +1 -1
  52. package/dist/device/index.js +15 -3
  53. package/dist/device/index.js.map +1 -1
  54. package/dist/device/index.mjs +15 -3
  55. package/dist/device/index.mjs.map +1 -1
  56. package/dist/forms/index.js +15 -3
  57. package/dist/forms/index.js.map +1 -1
  58. package/dist/forms/index.mjs +15 -3
  59. package/dist/forms/index.mjs.map +1 -1
  60. package/dist/i18n/index.js +15 -3
  61. package/dist/i18n/index.js.map +1 -1
  62. package/dist/i18n/index.mjs +15 -3
  63. package/dist/i18n/index.mjs.map +1 -1
  64. package/dist/index.d.mts +2 -2
  65. package/dist/index.d.ts +2 -2
  66. package/dist/index.js +50 -8
  67. package/dist/index.js.map +1 -1
  68. package/dist/index.mjs +50 -8
  69. package/dist/index.mjs.map +1 -1
  70. package/dist/{joop-CA3DMeOO.d.ts → joop-Dim2yEKG.d.ts} +1 -1
  71. package/dist/{joop-Bx7Iwj5p.d.mts → joop-GkQw13f9.d.mts} +1 -1
  72. package/dist/native-bridge/index.js +10 -2
  73. package/dist/native-bridge/index.js.map +1 -1
  74. package/dist/native-bridge/index.mjs +10 -2
  75. package/dist/native-bridge/index.mjs.map +1 -1
  76. package/dist/network/index.js +15 -3
  77. package/dist/network/index.js.map +1 -1
  78. package/dist/network/index.mjs +15 -3
  79. package/dist/network/index.mjs.map +1 -1
  80. package/dist/observability/index.js +15 -3
  81. package/dist/observability/index.js.map +1 -1
  82. package/dist/observability/index.mjs +15 -3
  83. package/dist/observability/index.mjs.map +1 -1
  84. package/dist/pwa/index.js +15 -3
  85. package/dist/pwa/index.js.map +1 -1
  86. package/dist/pwa/index.mjs +15 -3
  87. package/dist/pwa/index.mjs.map +1 -1
  88. package/dist/react/index.d.mts +2 -2
  89. package/dist/react/index.d.ts +2 -2
  90. package/dist/react/index.js +15 -3
  91. package/dist/react/index.js.map +1 -1
  92. package/dist/react/index.mjs +15 -3
  93. package/dist/react/index.mjs.map +1 -1
  94. package/dist/router/index.js +15 -3
  95. package/dist/router/index.js.map +1 -1
  96. package/dist/router/index.mjs +15 -3
  97. package/dist/router/index.mjs.map +1 -1
  98. package/dist/security/index.js +15 -3
  99. package/dist/security/index.js.map +1 -1
  100. package/dist/security/index.mjs +15 -3
  101. package/dist/security/index.mjs.map +1 -1
  102. package/dist/session/index.js +15 -3
  103. package/dist/session/index.js.map +1 -1
  104. package/dist/session/index.mjs +15 -3
  105. package/dist/session/index.mjs.map +1 -1
  106. package/dist/state/index.js +15 -3
  107. package/dist/state/index.js.map +1 -1
  108. package/dist/state/index.mjs +15 -3
  109. package/dist/state/index.mjs.map +1 -1
  110. package/dist/storage/index.js +15 -3
  111. package/dist/storage/index.js.map +1 -1
  112. package/dist/storage/index.mjs +15 -3
  113. package/dist/storage/index.mjs.map +1 -1
  114. package/dist/sync/index.js +15 -3
  115. package/dist/sync/index.js.map +1 -1
  116. package/dist/sync/index.mjs +15 -3
  117. package/dist/sync/index.mjs.map +1 -1
  118. package/dist/theme/index.js +15 -3
  119. package/dist/theme/index.js.map +1 -1
  120. package/dist/theme/index.mjs +15 -3
  121. package/dist/theme/index.mjs.map +1 -1
  122. package/dist/ui/index.js +15 -3
  123. package/dist/ui/index.js.map +1 -1
  124. package/dist/ui/index.mjs +15 -3
  125. package/dist/ui/index.mjs.map +1 -1
  126. package/dist/utilities/index.js +46 -4
  127. package/dist/utilities/index.js.map +1 -1
  128. package/dist/utilities/index.mjs +46 -4
  129. package/dist/utilities/index.mjs.map +1 -1
  130. package/dist/vue/index.d.mts +2 -2
  131. package/dist/vue/index.d.ts +2 -2
  132. package/dist/vue/index.js +15 -3
  133. package/dist/vue/index.js.map +1 -1
  134. package/dist/vue/index.mjs +15 -3
  135. package/dist/vue/index.mjs.map +1 -1
  136. package/dist/workflow/index.js +15 -3
  137. package/dist/workflow/index.js.map +1 -1
  138. package/dist/workflow/index.mjs +15 -3
  139. package/dist/workflow/index.mjs.map +1 -1
  140. package/package.json +16 -2
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  // src/events/index.ts
4
+ var _onListenerError = (error) => {
5
+ console.error("[joopjs] a subject subscriber threw during emission:", error);
6
+ };
4
7
  var JoopSubject = class {
5
8
  _listeners = [];
6
9
  subscribe(listener) {
@@ -10,8 +13,13 @@ var JoopSubject = class {
10
13
  };
11
14
  }
12
15
  next(value) {
13
- for (const listener of this._listeners) {
14
- listener(value);
16
+ const listeners = this._listeners.slice();
17
+ for (const listener of listeners) {
18
+ try {
19
+ listener(value);
20
+ } catch (error) {
21
+ _onListenerError(error);
22
+ }
15
23
  }
16
24
  }
17
25
  asObservable() {
@@ -32,7 +40,11 @@ var JoopBehaviorSubject = class extends JoopSubject {
32
40
  super.next(value);
33
41
  }
34
42
  subscribe(listener) {
35
- listener(this._value);
43
+ try {
44
+ listener(this._value);
45
+ } catch (error) {
46
+ _onListenerError(error);
47
+ }
36
48
  return super.subscribe(listener);
37
49
  }
38
50
  asObservable() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/events/index.ts","../../src/workflow/state-machine.ts","../../src/workflow/workflow-engine.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export type Unsubscribe = () => void;\nexport type Listener<T> = (value: T) => void;\n\n/**\n * Lightweight pub/sub subject — emits to all current subscribers.\n * Replaces RxJS Subject without pulling in the full RxJS dependency.\n */\nexport class JoopSubject<T> {\n private _listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>): Unsubscribe {\n this._listeners.push(listener);\n return () => {\n this._listeners = this._listeners.filter(l => l !== listener);\n };\n }\n\n next(value: T): void {\n for (const listener of this._listeners) {\n listener(value);\n }\n }\n\n asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Stateful subject — replays the current value to any new subscriber immediately.\n * Replaces RxJS BehaviorSubject.\n */\nexport class JoopBehaviorSubject<T> extends JoopSubject<T> {\n private _value: T;\n\n constructor(initialValue: T) {\n super();\n this._value = initialValue;\n }\n\n getValue(): T {\n return this._value;\n }\n\n override next(value: T): void {\n this._value = value;\n super.next(value);\n }\n\n override subscribe(listener: Listener<T>): Unsubscribe {\n listener(this._value);\n return super.subscribe(listener);\n }\n\n override asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Read-only observable handle returned from asObservable().\n */\nexport class JoopObservable<T> {\n constructor(private _subscribeFn: (listener: Listener<T>) => Unsubscribe) {}\n\n subscribe(listener: Listener<T>): Unsubscribe {\n return this._subscribeFn(listener);\n }\n\n /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */\n getOnce(): T | undefined {\n let result: T | undefined;\n const unsub = this.subscribe(v => { result = v; });\n unsub();\n return result;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopTransition<S extends string, E extends string> {\n target: S;\n guard?: (context?: unknown) => boolean;\n action?: (context?: unknown) => void;\n}\n\nexport interface JoopStateConfig<S extends string, E extends string> {\n on?: Partial<Record<E, JoopTransition<S, E> | S>>;\n onEnter?: (context?: unknown) => void;\n onExit?: (context?: unknown) => void;\n type?: 'final' | 'normal';\n}\n\nexport interface JoopMachineConfig<S extends string, E extends string> {\n id?: string;\n initial: S;\n context?: unknown;\n states: Record<S, JoopStateConfig<S, E>>;\n}\n\nexport interface JoopStateTransition<S extends string, E extends string> {\n from: S;\n event: E;\n to: S;\n timestamp: number;\n}\n\nexport class JoopStateMachine<S extends string, E extends string> {\n private _state$: JoopBehaviorSubject<S>;\n private _transition$ = new JoopSubject<JoopStateTransition<S, E>>();\n private _cfg: JoopMachineConfig<S, E>;\n private _history: JoopStateTransition<S, E>[] = [];\n private _context: unknown;\n\n constructor(config: JoopMachineConfig<S, E>) {\n this._cfg = config;\n this._context = config.context;\n this._state$ = new JoopBehaviorSubject<S>(config.initial);\n this._cfg.states[config.initial]?.onEnter?.(this._context);\n }\n\n getState(): S { return this._state$.getValue(); }\n getContext(): unknown { return this._context; }\n state$() { return this._state$.asObservable(); }\n transition$() { return this._transition$.asObservable(); }\n history(): JoopStateTransition<S, E>[] { return [...this._history]; }\n\n matches(state: S): boolean { return this._state$.getValue() === state; }\n isFinal(): boolean { return this._cfg.states[this.getState()]?.type === 'final'; }\n\n /** Returns true if the event can be sent from current state */\n can(event: E): boolean {\n const cfg = this._cfg.states[this.getState()]?.on;\n if (!cfg || !(event in cfg)) return false;\n const t = this._resolveTransition(this.getState(), event);\n return t !== null;\n }\n\n /** Send an event; returns true if a transition occurred */\n send(event: E, context?: unknown): boolean {\n const from = this.getState();\n const stateCfg = this._cfg.states[from];\n if (!stateCfg?.on || !(event in stateCfg.on)) return false;\n\n const t = this._resolveTransition(from, event, context);\n if (!t) return false;\n\n const to = t.target;\n stateCfg.onExit?.(this._context);\n t.action?.(this._context);\n if (context !== undefined) this._context = context;\n\n const record: JoopStateTransition<S, E> = { from, event, to, timestamp: Date.now() };\n this._history.push(record);\n this._state$.next(to);\n this._transition$.next(record);\n\n this._cfg.states[to]?.onEnter?.(this._context);\n return true;\n }\n\n /** Update context without triggering a transition */\n setContext(ctx: unknown): void { this._context = ctx; }\n\n reset(): void {\n const initial = this._cfg.initial;\n this._state$.next(initial);\n this._history = [];\n this._cfg.states[initial]?.onEnter?.(this._context);\n }\n\n /** Export as Mermaid state diagram */\n toMermaid(): string {\n const lines = ['stateDiagram-v2'];\n lines.push(` [*] --> ${this._cfg.initial}`);\n for (const [state, cfg] of Object.entries(this._cfg.states) as Array<[S, JoopStateConfig<S,E>]>) {\n if (cfg.type === 'final') lines.push(` ${state} --> [*]`);\n if (cfg.on) {\n for (const [event, trans] of Object.entries(cfg.on)) {\n const target = typeof trans === 'string' ? trans : (trans as JoopTransition<S,E>).target;\n lines.push(` ${state} --> ${target} : ${event}`);\n }\n }\n }\n return lines.join('\\n');\n }\n\n private _resolveTransition(from: S, event: E, context?: unknown): JoopTransition<S, E> | null {\n const rawTrans = this._cfg.states[from]?.on?.[event];\n if (!rawTrans) return null;\n const t: JoopTransition<S, E> = typeof rawTrans === 'string' ? { target: rawTrans as S } : rawTrans;\n if (t.guard && !t.guard(context ?? this._context)) return null;\n return t;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopWorkflowStep {\n id: string;\n name?: string;\n after?: string[]; // step IDs this depends on\n execute: (context: unknown) => Promise<unknown>;\n compensate?: (context: unknown) => Promise<void>; // saga rollback\n timeout?: number;\n retries?: number;\n}\n\nexport interface JoopWorkflowDefinition {\n id: string;\n steps: JoopWorkflowStep[];\n}\n\nexport type JoopWorkflowRunStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled' | 'compensating';\n\nexport interface JoopWorkflowRun {\n runId: string;\n workflowId: string;\n status: JoopWorkflowRunStatus;\n input: unknown;\n outputs: Record<string, unknown>;\n errors: Record<string, string>;\n startedAt: number;\n completedAt?: number;\n}\n\nexport interface JoopWorkflowResult {\n runId: string;\n status: 'completed' | 'failed';\n outputs: Record<string, unknown>;\n errors: Record<string, string>;\n durationMs: number;\n}\n\nexport class JoopWorkflowEngine {\n private _definitions = new Map<string, JoopWorkflowDefinition>();\n private _runs = new Map<string, JoopWorkflowRun>();\n private _runStatus$ = new JoopSubject<JoopWorkflowRun>();\n private _cancellations = new Set<string>();\n\n define(workflow: JoopWorkflowDefinition): void { this._definitions.set(workflow.id, workflow); }\n undefine(id: string): void { this._definitions.delete(id); }\n\n async run(workflowId: string, input: unknown = null): Promise<JoopWorkflowResult> {\n const def = this._definitions.get(workflowId);\n if (!def) throw new Error(`JoopWorkflowEngine: unknown workflow '${workflowId}'`);\n\n const runId = `${workflowId}_${Date.now()}_${Math.floor(Math.random() * 1000)}`;\n const run: JoopWorkflowRun = {\n runId, workflowId, status: 'running',\n input, outputs: {}, errors: {}, startedAt: Date.now(),\n };\n this._runs.set(runId, run);\n this._emit(run);\n\n const completed = new Set<string>();\n const context = { input, outputs: run.outputs };\n\n // Build execution order respecting `after` dependencies\n const remaining = [...def.steps];\n const executedSteps: JoopWorkflowStep[] = [];\n\n while (remaining.length > 0) {\n if (this._cancellations.has(runId)) {\n run.status = 'cancelled'; this._emit(run); break;\n }\n\n // Find steps whose dependencies are all satisfied\n const ready = remaining.filter(s => (s.after ?? []).every(dep => completed.has(dep)));\n if (ready.length === 0 && remaining.length > 0) throw new Error(`Workflow deadlock in '${workflowId}': circular/missing dependencies`);\n\n // Run ready steps in parallel\n const results = await Promise.allSettled(ready.map(s => this._runStep(s, context, runId)));\n for (let i = 0; i < ready.length; i++) {\n const step = ready[i];\n const result = results[i];\n remaining.splice(remaining.indexOf(step), 1);\n if (result.status === 'fulfilled') {\n run.outputs[step.id] = result.value;\n (context as Record<string, unknown>).outputs = run.outputs;\n completed.add(step.id);\n executedSteps.push(step);\n } else {\n run.errors[step.id] = String(result.reason);\n run.status = 'failed';\n break;\n }\n }\n if (run.status === 'failed') break;\n }\n\n if (run.status === 'failed') {\n // Saga: compensate in reverse order\n run.status = 'compensating'; this._emit(run);\n for (const step of [...executedSteps].reverse()) {\n if (step.compensate) { try { await step.compensate(context); } catch { /* best effort */ } }\n }\n } else if (run.status === 'running') {\n run.status = 'completed';\n }\n\n run.completedAt = Date.now();\n this._emit(run);\n this._cancellations.delete(runId);\n\n return {\n runId,\n status: run.status === 'completed' ? 'completed' : 'failed',\n outputs: run.outputs,\n errors: run.errors,\n durationMs: run.completedAt - run.startedAt,\n };\n }\n\n cancel(runId: string): void { this._cancellations.add(runId); }\n\n status(runId: string): JoopWorkflowRun | undefined { return this._runs.get(runId); }\n history(): JoopWorkflowRun[] { return Array.from(this._runs.values()); }\n runStatus$() { return this._runStatus$.asObservable(); }\n\n private async _runStep(step: JoopWorkflowStep, context: unknown, runId: string): Promise<unknown> {\n const maxAttempts = (step.retries ?? 0) + 1;\n let lastErr: unknown;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (this._cancellations.has(runId)) throw new Error('Cancelled');\n try {\n const run = step.timeout\n ? await _withTimeout(step.execute(context), step.timeout, step.id)\n : await step.execute(context);\n return run;\n } catch (e) { lastErr = e; }\n }\n throw lastErr;\n }\n\n private _emit(run: JoopWorkflowRun): void { this._runStatus$.next({ ...run }); }\n}\n\nfunction _withTimeout<T>(promise: Promise<T>, ms: number, id: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`Step '${id}' timed out after ${ms}ms`)), ms);\n promise.then(v => { clearTimeout(timer); resolve(v); }, e => { clearTimeout(timer); reject(e); });\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/events/index.ts","../../src/workflow/state-machine.ts","../../src/workflow/workflow-engine.ts"],"names":[],"mappings":";;;AAQA,IAAI,gBAAA,GAA6C,CAAC,KAAA,KAAU;AAE1D,EAAA,OAAA,CAAQ,KAAA,CAAM,wDAAwD,KAAK,CAAA;AAC7E,CAAA;AAWO,IAAM,cAAN,MAAqB;AAAA,EAClB,aAA4B,EAAC;AAAA,EAErC,UAAU,QAAA,EAAoC;AAC5C,IAAA,IAAA,CAAK,UAAA,CAAW,KAAK,QAAQ,CAAA;AAC7B,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,aAAa,IAAA,CAAK,UAAA,CAAW,MAAA,CAAO,CAAA,CAAA,KAAK,MAAM,QAAQ,CAAA;AAAA,IAC9D,CAAA;AAAA,EACF;AAAA,EAEA,KAAK,KAAA,EAAgB;AAInB,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,UAAA,CAAW,KAAA,EAAM;AACxC,IAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,MAAA,IAAI;AACF,QAAA,QAAA,CAAS,KAAK,CAAA;AAAA,MAChB,SAAS,KAAA,EAAO;AACd,QAAA,gBAAA,CAAiB,KAAK,CAAA;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAA,GAAkC;AAChC,IAAA,OAAO,IAAI,cAAA,CAAkB,CAAA,QAAA,KAAY,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,EACnE;AACF,CAAA;AAMO,IAAM,mBAAA,GAAN,cAAqC,WAAA,CAAe;AAAA,EACjD,MAAA;AAAA,EAER,YAAY,YAAA,EAAiB;AAC3B,IAAA,KAAA,EAAM;AACN,IAAA,IAAA,CAAK,MAAA,GAAS,YAAA;AAAA,EAChB;AAAA,EAEA,QAAA,GAAc;AACZ,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA,EAES,KAAK,KAAA,EAAgB;AAC5B,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AACd,IAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,EAClB;AAAA,EAES,UAAU,QAAA,EAAoC;AACrD,IAAA,IAAI;AACF,MAAA,QAAA,CAAS,KAAK,MAAM,CAAA;AAAA,IACtB,SAAS,KAAA,EAAO;AACd,MAAA,gBAAA,CAAiB,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAO,KAAA,CAAM,UAAU,QAAQ,CAAA;AAAA,EACjC;AAAA,EAES,YAAA,GAAkC;AACzC,IAAA,OAAO,IAAI,cAAA,CAAkB,CAAA,QAAA,KAAY,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,EACnE;AACF,CAAA;AAKO,IAAM,iBAAN,MAAwB;AAAA,EAC7B,YAAoB,YAAA,EAAsD;AAAtD,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AAAA,EAAuD;AAAA,EAAvD,YAAA;AAAA,EAEpB,UAAU,QAAA,EAAoC;AAC5C,IAAA,OAAO,IAAA,CAAK,aAAa,QAAQ,CAAA;AAAA,EACnC;AAAA;AAAA,EAGA,OAAA,GAAyB;AACvB,IAAA,IAAI,MAAA;AACJ,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,SAAA,CAAU,CAAA,CAAA,KAAK;AAAE,MAAA,MAAA,GAAS,CAAA;AAAA,IAAG,CAAC,CAAA;AACjD,IAAA,KAAA,EAAM;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF,CAAA;;;AC1EO,IAAM,mBAAN,MAA2D;AAAA,EACxD,OAAA;AAAA,EACA,YAAA,GAAe,IAAI,WAAA,EAAuC;AAAA,EAC1D,IAAA;AAAA,EACA,WAAwC,EAAC;AAAA,EACzC,QAAA;AAAA,EAER,YAAY,MAAA,EAAiC;AAC3C,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AACZ,IAAA,IAAA,CAAK,WAAW,MAAA,CAAO,OAAA;AACvB,IAAA,IAAA,CAAK,OAAA,GAAU,IAAI,mBAAA,CAAuB,MAAA,CAAO,OAAO,CAAA;AACxD,IAAA,IAAA,CAAK,KAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,EAAG,OAAA,GAAU,KAAK,QAAQ,CAAA;AAAA,EAC3D;AAAA,EAEA,QAAA,GAAc;AAAE,IAAA,OAAO,IAAA,CAAK,QAAQ,QAAA,EAAS;AAAA,EAAG;AAAA,EAChD,UAAA,GAAsB;AAAE,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EAAU;AAAA,EAC9C,MAAA,GAAS;AAAE,IAAA,OAAO,IAAA,CAAK,QAAQ,YAAA,EAAa;AAAA,EAAG;AAAA,EAC/C,WAAA,GAAc;AAAE,IAAA,OAAO,IAAA,CAAK,aAAa,YAAA,EAAa;AAAA,EAAG;AAAA,EACzD,OAAA,GAAuC;AAAE,IAAA,OAAO,CAAC,GAAG,IAAA,CAAK,QAAQ,CAAA;AAAA,EAAG;AAAA,EAEpE,QAAQ,KAAA,EAAmB;AAAE,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,QAAA,EAAS,KAAM,KAAA;AAAA,EAAO;AAAA,EACvE,OAAA,GAAmB;AAAE,IAAA,OAAO,KAAK,IAAA,CAAK,MAAA,CAAO,KAAK,QAAA,EAAU,GAAG,IAAA,KAAS,OAAA;AAAA,EAAS;AAAA;AAAA,EAGjF,IAAI,KAAA,EAAmB;AACrB,IAAA,MAAM,MAAM,IAAA,CAAK,IAAA,CAAK,OAAO,IAAA,CAAK,QAAA,EAAU,CAAA,EAAG,EAAA;AAC/C,IAAA,IAAI,CAAC,GAAA,IAAO,EAAE,KAAA,IAAS,MAAM,OAAO,KAAA;AACpC,IAAA,MAAM,IAAI,IAAA,CAAK,kBAAA,CAAmB,IAAA,CAAK,QAAA,IAAY,KAAK,CAAA;AACxD,IAAA,OAAO,CAAA,KAAM,IAAA;AAAA,EACf;AAAA;AAAA,EAGA,IAAA,CAAK,OAAU,OAAA,EAA4B;AACzC,IAAA,MAAM,IAAA,GAAO,KAAK,QAAA,EAAS;AAC3B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA;AACtC,IAAA,IAAI,CAAC,QAAA,EAAU,EAAA,IAAM,EAAE,KAAA,IAAS,QAAA,CAAS,KAAK,OAAO,KAAA;AAErD,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,kBAAA,CAAmB,IAAA,EAAM,OAAO,OAAO,CAAA;AACtD,IAAA,IAAI,CAAC,GAAG,OAAO,KAAA;AAEf,IAAA,MAAM,KAAK,CAAA,CAAE,MAAA;AACb,IAAA,QAAA,CAAS,MAAA,GAAS,KAAK,QAAQ,CAAA;AAC/B,IAAA,CAAA,CAAE,MAAA,GAAS,KAAK,QAAQ,CAAA;AACxB,IAAA,IAAI,OAAA,KAAY,MAAA,EAAW,IAAA,CAAK,QAAA,GAAW,OAAA;AAE3C,IAAA,MAAM,MAAA,GAAoC,EAAE,IAAA,EAAM,KAAA,EAAO,IAAI,SAAA,EAAW,IAAA,CAAK,KAAI,EAAE;AACnF,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,MAAM,CAAA;AACzB,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,EAAE,CAAA;AACpB,IAAA,IAAA,CAAK,YAAA,CAAa,KAAK,MAAM,CAAA;AAE7B,IAAA,IAAA,CAAK,KAAK,MAAA,CAAO,EAAE,CAAA,EAAG,OAAA,GAAU,KAAK,QAAQ,CAAA;AAC7C,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA,EAGA,WAAW,GAAA,EAAoB;AAAE,IAAA,IAAA,CAAK,QAAA,GAAW,GAAA;AAAA,EAAK;AAAA,EAEtD,KAAA,GAAc;AACZ,IAAA,MAAM,OAAA,GAAU,KAAK,IAAA,CAAK,OAAA;AAC1B,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,OAAO,CAAA;AACzB,IAAA,IAAA,CAAK,WAAW,EAAC;AACjB,IAAA,IAAA,CAAK,KAAK,MAAA,CAAO,OAAO,CAAA,EAAG,OAAA,GAAU,KAAK,QAAQ,CAAA;AAAA,EACpD;AAAA;AAAA,EAGA,SAAA,GAAoB;AAClB,IAAA,MAAM,KAAA,GAAQ,CAAC,iBAAiB,CAAA;AAChC,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,UAAA,EAAa,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA,CAAE,CAAA;AAC3C,IAAA,KAAA,MAAW,CAAC,OAAO,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA,EAAuC;AAC/F,MAAA,IAAI,IAAI,IAAA,KAAS,OAAA,QAAe,IAAA,CAAK,CAAA,EAAA,EAAK,KAAK,CAAA,QAAA,CAAU,CAAA;AACzD,MAAA,IAAI,IAAI,EAAA,EAAI;AACV,QAAA,KAAA,MAAW,CAAC,OAAO,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA,EAAG;AACnD,UAAA,MAAM,MAAA,GAAS,OAAO,KAAA,KAAU,QAAA,GAAW,QAAS,KAAA,CAA8B,MAAA;AAClF,UAAA,KAAA,CAAM,KAAK,CAAA,EAAA,EAAK,KAAK,QAAQ,MAAM,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAA;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,EACxB;AAAA,EAEQ,kBAAA,CAAmB,IAAA,EAAS,KAAA,EAAU,OAAA,EAAgD;AAC5F,IAAA,MAAM,WAAW,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,CAAA,EAAG,KAAK,KAAK,CAAA;AACnD,IAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AACtB,IAAA,MAAM,IAA0B,OAAO,QAAA,KAAa,WAAW,EAAE,MAAA,EAAQ,UAAc,GAAI,QAAA;AAC3F,IAAA,IAAI,CAAA,CAAE,SAAS,CAAC,CAAA,CAAE,MAAM,OAAA,IAAW,IAAA,CAAK,QAAQ,CAAA,EAAG,OAAO,IAAA;AAC1D,IAAA,OAAO,CAAA;AAAA,EACT;AACF;;;AC9EO,IAAM,qBAAN,MAAyB;AAAA,EACtB,YAAA,uBAAmB,GAAA,EAAoC;AAAA,EACvD,KAAA,uBAAY,GAAA,EAA6B;AAAA,EACzC,WAAA,GAAc,IAAI,WAAA,EAA6B;AAAA,EAC/C,cAAA,uBAAqB,GAAA,EAAY;AAAA,EAEzC,OAAO,QAAA,EAAwC;AAAE,IAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,QAAQ,CAAA;AAAA,EAAG;AAAA,EAC/F,SAAS,EAAA,EAAkB;AAAE,IAAA,IAAA,CAAK,YAAA,CAAa,OAAO,EAAE,CAAA;AAAA,EAAG;AAAA,EAE3D,MAAM,GAAA,CAAI,UAAA,EAAoB,KAAA,GAAiB,IAAA,EAAmC;AAChF,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,UAAU,CAAA;AAC5C,IAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA,CAAM,CAAA,sCAAA,EAAyC,UAAU,CAAA,CAAA,CAAG,CAAA;AAEhF,IAAA,MAAM,KAAA,GAAQ,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,KAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAA,EAAO,GAAI,GAAI,CAAC,CAAA,CAAA;AAC7E,IAAA,MAAM,GAAA,GAAuB;AAAA,MAC3B,KAAA;AAAA,MAAO,UAAA;AAAA,MAAY,MAAA,EAAQ,SAAA;AAAA,MAC3B,KAAA;AAAA,MAAO,SAAS,EAAC;AAAA,MAAG,QAAQ,EAAC;AAAA,MAAG,SAAA,EAAW,KAAK,GAAA;AAAI,KACtD;AACA,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,KAAA,EAAO,GAAG,CAAA;AACzB,IAAA,IAAA,CAAK,MAAM,GAAG,CAAA;AAEd,IAAA,MAAM,SAAA,uBAAgB,GAAA,EAAY;AAClC,IAAA,MAAM,OAAA,GAAU,EAAE,KAAA,EAAO,OAAA,EAAS,IAAI,OAAA,EAAQ;AAG9C,IAAA,MAAM,SAAA,GAAY,CAAC,GAAG,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,MAAM,gBAAoC,EAAC;AAE3C,IAAA,OAAO,SAAA,CAAU,SAAS,CAAA,EAAG;AAC3B,MAAA,IAAI,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,KAAK,CAAA,EAAG;AAClC,QAAA,GAAA,CAAI,MAAA,GAAS,WAAA;AAAa,QAAA,IAAA,CAAK,MAAM,GAAG,CAAA;AAAG,QAAA;AAAA,MAC7C;AAGA,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,MAAA,CAAO,CAAA,CAAA,KAAA,CAAM,EAAE,KAAA,IAAS,EAAC,EAAG,KAAA,CAAM,CAAA,GAAA,KAAO,SAAA,CAAU,GAAA,CAAI,GAAG,CAAC,CAAC,CAAA;AACpF,MAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,SAAA,CAAU,MAAA,GAAS,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,UAAU,CAAA,gCAAA,CAAkC,CAAA;AAGrI,MAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,UAAA,CAAW,KAAA,CAAM,GAAA,CAAI,CAAA,CAAA,KAAK,IAAA,CAAK,QAAA,CAAS,CAAA,EAAG,OAAA,EAAS,KAAK,CAAC,CAAC,CAAA;AACzF,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,QAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AACpB,QAAA,MAAM,MAAA,GAAS,QAAQ,CAAC,CAAA;AACxB,QAAA,SAAA,CAAU,MAAA,CAAO,SAAA,CAAU,OAAA,CAAQ,IAAI,GAAG,CAAC,CAAA;AAC3C,QAAA,IAAI,MAAA,CAAO,WAAW,WAAA,EAAa;AACjC,UAAA,GAAA,CAAI,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,GAAI,MAAA,CAAO,KAAA;AAC9B,UAAC,OAAA,CAAoC,UAAU,GAAA,CAAI,OAAA;AACnD,UAAA,SAAA,CAAU,GAAA,CAAI,KAAK,EAAE,CAAA;AACrB,UAAA,aAAA,CAAc,KAAK,IAAI,CAAA;AAAA,QACzB,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,OAAO,IAAA,CAAK,EAAE,CAAA,GAAI,MAAA,CAAO,OAAO,MAAM,CAAA;AAC1C,UAAA,GAAA,CAAI,MAAA,GAAS,QAAA;AACb,UAAA;AAAA,QACF;AAAA,MACF;AACA,MAAA,IAAI,GAAA,CAAI,WAAW,QAAA,EAAU;AAAA,IAC/B;AAEA,IAAA,IAAI,GAAA,CAAI,WAAW,QAAA,EAAU;AAE3B,MAAA,GAAA,CAAI,MAAA,GAAS,cAAA;AAAgB,MAAA,IAAA,CAAK,MAAM,GAAG,CAAA;AAC3C,MAAA,KAAA,MAAW,QAAQ,CAAC,GAAG,aAAa,CAAA,CAAE,SAAQ,EAAG;AAC/C,QAAA,IAAI,KAAK,UAAA,EAAY;AAAE,UAAA,IAAI;AAAE,YAAA,MAAM,IAAA,CAAK,WAAW,OAAO,CAAA;AAAA,UAAG,CAAA,CAAA,MAAQ;AAAA,UAAoB;AAAA,QAAE;AAAA,MAC7F;AAAA,IACF,CAAA,MAAA,IAAW,GAAA,CAAI,MAAA,KAAW,SAAA,EAAW;AACnC,MAAA,GAAA,CAAI,MAAA,GAAS,WAAA;AAAA,IACf;AAEA,IAAA,GAAA,CAAI,WAAA,GAAc,KAAK,GAAA,EAAI;AAC3B,IAAA,IAAA,CAAK,MAAM,GAAG,CAAA;AACd,IAAA,IAAA,CAAK,cAAA,CAAe,OAAO,KAAK,CAAA;AAEhC,IAAA,OAAO;AAAA,MACL,KAAA;AAAA,MACA,MAAA,EAAQ,GAAA,CAAI,MAAA,KAAW,WAAA,GAAc,WAAA,GAAc,QAAA;AAAA,MACnD,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,QAAQ,GAAA,CAAI,MAAA;AAAA,MACZ,UAAA,EAAY,GAAA,CAAI,WAAA,GAAc,GAAA,CAAI;AAAA,KACpC;AAAA,EACF;AAAA,EAEA,OAAO,KAAA,EAAqB;AAAE,IAAA,IAAA,CAAK,cAAA,CAAe,IAAI,KAAK,CAAA;AAAA,EAAG;AAAA,EAE9D,OAAO,KAAA,EAA4C;AAAE,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,KAAK,CAAA;AAAA,EAAG;AAAA,EACnF,OAAA,GAA6B;AAAE,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AAAA,EAAG;AAAA,EACvE,UAAA,GAAa;AAAE,IAAA,OAAO,IAAA,CAAK,YAAY,YAAA,EAAa;AAAA,EAAG;AAAA,EAEvD,MAAc,QAAA,CAAS,IAAA,EAAwB,OAAA,EAAkB,KAAA,EAAiC;AAChG,IAAA,MAAM,WAAA,GAAA,CAAe,IAAA,CAAK,OAAA,IAAW,CAAA,IAAK,CAAA;AAC1C,IAAA,IAAI,OAAA;AACJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,GAAU,WAAA,EAAa,OAAA,EAAA,EAAW;AACtD,MAAA,IAAI,IAAA,CAAK,eAAe,GAAA,CAAI,KAAK,GAAG,MAAM,IAAI,MAAM,WAAW,CAAA;AAC/D,MAAA,IAAI;AACF,QAAA,MAAM,MAAM,IAAA,CAAK,OAAA,GACb,MAAM,YAAA,CAAa,KAAK,OAAA,CAAQ,OAAO,CAAA,EAAG,IAAA,CAAK,SAAS,IAAA,CAAK,EAAE,IAC/D,MAAM,IAAA,CAAK,QAAQ,OAAO,CAAA;AAC9B,QAAA,OAAO,GAAA;AAAA,MACT,SAAS,CAAA,EAAG;AAAE,QAAA,OAAA,GAAU,CAAA;AAAA,MAAG;AAAA,IAC7B;AACA,IAAA,MAAM,OAAA;AAAA,EACR;AAAA,EAEQ,MAAM,GAAA,EAA4B;AAAE,IAAA,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,EAAE,GAAG,KAAK,CAAA;AAAA,EAAG;AACjF;AAEA,SAAS,YAAA,CAAgB,OAAA,EAAqB,EAAA,EAAY,EAAA,EAAwB;AAChF,EAAA,OAAO,IAAI,OAAA,CAAW,CAAC,OAAA,EAAS,MAAA,KAAW;AACzC,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,MAAM,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,EAAE,CAAA,kBAAA,EAAqB,EAAE,CAAA,EAAA,CAAI,CAAC,GAAG,EAAE,CAAA;AAC5F,IAAA,OAAA,CAAQ,KAAK,CAAA,CAAA,KAAK;AAAE,MAAA,YAAA,CAAa,KAAK,CAAA;AAAG,MAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAAG,GAAG,CAAA,CAAA,KAAK;AAAE,MAAA,YAAA,CAAa,KAAK,CAAA;AAAG,MAAA,MAAA,CAAO,CAAC,CAAA;AAAA,IAAG,CAAC,CAAA;AAAA,EAClG,CAAC,CAAA;AACH","file":"index.js","sourcesContent":["export type Unsubscribe = () => void;\nexport type Listener<T> = (value: T) => void;\n\n/**\n * Reports a subscriber that threw during emission, without aborting delivery\n * to the remaining subscribers. Defaults to console.error; override to route\n * to your own logger (e.g. in a banking app where dropped events matter).\n */\nlet _onListenerError: (error: unknown) => void = (error) => {\n // eslint-disable-next-line no-console\n console.error('[joopjs] a subject subscriber threw during emission:', error);\n};\n\n/** Override how subscriber errors are reported during emission. */\nexport function setSubjectErrorHandler(handler: (error: unknown) => void): void {\n _onListenerError = handler;\n}\n\n/**\n * Lightweight pub/sub subject — emits to all current subscribers.\n * Replaces RxJS Subject without pulling in the full RxJS dependency.\n */\nexport class JoopSubject<T> {\n private _listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>): Unsubscribe {\n this._listeners.push(listener);\n return () => {\n this._listeners = this._listeners.filter(l => l !== listener);\n };\n }\n\n next(value: T): void {\n // Snapshot so a subscribe()/unsubscribe() triggered by a listener can't\n // disturb this emission, and isolate each listener so one that throws\n // doesn't deprive later subscribers of the value.\n const listeners = this._listeners.slice();\n for (const listener of listeners) {\n try {\n listener(value);\n } catch (error) {\n _onListenerError(error);\n }\n }\n }\n\n asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Stateful subject — replays the current value to any new subscriber immediately.\n * Replaces RxJS BehaviorSubject.\n */\nexport class JoopBehaviorSubject<T> extends JoopSubject<T> {\n private _value: T;\n\n constructor(initialValue: T) {\n super();\n this._value = initialValue;\n }\n\n getValue(): T {\n return this._value;\n }\n\n override next(value: T): void {\n this._value = value;\n super.next(value);\n }\n\n override subscribe(listener: Listener<T>): Unsubscribe {\n try {\n listener(this._value);\n } catch (error) {\n _onListenerError(error);\n }\n return super.subscribe(listener);\n }\n\n override asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Read-only observable handle returned from asObservable().\n */\nexport class JoopObservable<T> {\n constructor(private _subscribeFn: (listener: Listener<T>) => Unsubscribe) {}\n\n subscribe(listener: Listener<T>): Unsubscribe {\n return this._subscribeFn(listener);\n }\n\n /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */\n getOnce(): T | undefined {\n let result: T | undefined;\n const unsub = this.subscribe(v => { result = v; });\n unsub();\n return result;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopTransition<S extends string, E extends string> {\n target: S;\n guard?: (context?: unknown) => boolean;\n action?: (context?: unknown) => void;\n}\n\nexport interface JoopStateConfig<S extends string, E extends string> {\n on?: Partial<Record<E, JoopTransition<S, E> | S>>;\n onEnter?: (context?: unknown) => void;\n onExit?: (context?: unknown) => void;\n type?: 'final' | 'normal';\n}\n\nexport interface JoopMachineConfig<S extends string, E extends string> {\n id?: string;\n initial: S;\n context?: unknown;\n states: Record<S, JoopStateConfig<S, E>>;\n}\n\nexport interface JoopStateTransition<S extends string, E extends string> {\n from: S;\n event: E;\n to: S;\n timestamp: number;\n}\n\nexport class JoopStateMachine<S extends string, E extends string> {\n private _state$: JoopBehaviorSubject<S>;\n private _transition$ = new JoopSubject<JoopStateTransition<S, E>>();\n private _cfg: JoopMachineConfig<S, E>;\n private _history: JoopStateTransition<S, E>[] = [];\n private _context: unknown;\n\n constructor(config: JoopMachineConfig<S, E>) {\n this._cfg = config;\n this._context = config.context;\n this._state$ = new JoopBehaviorSubject<S>(config.initial);\n this._cfg.states[config.initial]?.onEnter?.(this._context);\n }\n\n getState(): S { return this._state$.getValue(); }\n getContext(): unknown { return this._context; }\n state$() { return this._state$.asObservable(); }\n transition$() { return this._transition$.asObservable(); }\n history(): JoopStateTransition<S, E>[] { return [...this._history]; }\n\n matches(state: S): boolean { return this._state$.getValue() === state; }\n isFinal(): boolean { return this._cfg.states[this.getState()]?.type === 'final'; }\n\n /** Returns true if the event can be sent from current state */\n can(event: E): boolean {\n const cfg = this._cfg.states[this.getState()]?.on;\n if (!cfg || !(event in cfg)) return false;\n const t = this._resolveTransition(this.getState(), event);\n return t !== null;\n }\n\n /** Send an event; returns true if a transition occurred */\n send(event: E, context?: unknown): boolean {\n const from = this.getState();\n const stateCfg = this._cfg.states[from];\n if (!stateCfg?.on || !(event in stateCfg.on)) return false;\n\n const t = this._resolveTransition(from, event, context);\n if (!t) return false;\n\n const to = t.target;\n stateCfg.onExit?.(this._context);\n t.action?.(this._context);\n if (context !== undefined) this._context = context;\n\n const record: JoopStateTransition<S, E> = { from, event, to, timestamp: Date.now() };\n this._history.push(record);\n this._state$.next(to);\n this._transition$.next(record);\n\n this._cfg.states[to]?.onEnter?.(this._context);\n return true;\n }\n\n /** Update context without triggering a transition */\n setContext(ctx: unknown): void { this._context = ctx; }\n\n reset(): void {\n const initial = this._cfg.initial;\n this._state$.next(initial);\n this._history = [];\n this._cfg.states[initial]?.onEnter?.(this._context);\n }\n\n /** Export as Mermaid state diagram */\n toMermaid(): string {\n const lines = ['stateDiagram-v2'];\n lines.push(` [*] --> ${this._cfg.initial}`);\n for (const [state, cfg] of Object.entries(this._cfg.states) as Array<[S, JoopStateConfig<S,E>]>) {\n if (cfg.type === 'final') lines.push(` ${state} --> [*]`);\n if (cfg.on) {\n for (const [event, trans] of Object.entries(cfg.on)) {\n const target = typeof trans === 'string' ? trans : (trans as JoopTransition<S,E>).target;\n lines.push(` ${state} --> ${target} : ${event}`);\n }\n }\n }\n return lines.join('\\n');\n }\n\n private _resolveTransition(from: S, event: E, context?: unknown): JoopTransition<S, E> | null {\n const rawTrans = this._cfg.states[from]?.on?.[event];\n if (!rawTrans) return null;\n const t: JoopTransition<S, E> = typeof rawTrans === 'string' ? { target: rawTrans as S } : rawTrans;\n if (t.guard && !t.guard(context ?? this._context)) return null;\n return t;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopWorkflowStep {\n id: string;\n name?: string;\n after?: string[]; // step IDs this depends on\n execute: (context: unknown) => Promise<unknown>;\n compensate?: (context: unknown) => Promise<void>; // saga rollback\n timeout?: number;\n retries?: number;\n}\n\nexport interface JoopWorkflowDefinition {\n id: string;\n steps: JoopWorkflowStep[];\n}\n\nexport type JoopWorkflowRunStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled' | 'compensating';\n\nexport interface JoopWorkflowRun {\n runId: string;\n workflowId: string;\n status: JoopWorkflowRunStatus;\n input: unknown;\n outputs: Record<string, unknown>;\n errors: Record<string, string>;\n startedAt: number;\n completedAt?: number;\n}\n\nexport interface JoopWorkflowResult {\n runId: string;\n status: 'completed' | 'failed';\n outputs: Record<string, unknown>;\n errors: Record<string, string>;\n durationMs: number;\n}\n\nexport class JoopWorkflowEngine {\n private _definitions = new Map<string, JoopWorkflowDefinition>();\n private _runs = new Map<string, JoopWorkflowRun>();\n private _runStatus$ = new JoopSubject<JoopWorkflowRun>();\n private _cancellations = new Set<string>();\n\n define(workflow: JoopWorkflowDefinition): void { this._definitions.set(workflow.id, workflow); }\n undefine(id: string): void { this._definitions.delete(id); }\n\n async run(workflowId: string, input: unknown = null): Promise<JoopWorkflowResult> {\n const def = this._definitions.get(workflowId);\n if (!def) throw new Error(`JoopWorkflowEngine: unknown workflow '${workflowId}'`);\n\n const runId = `${workflowId}_${Date.now()}_${Math.floor(Math.random() * 1000)}`;\n const run: JoopWorkflowRun = {\n runId, workflowId, status: 'running',\n input, outputs: {}, errors: {}, startedAt: Date.now(),\n };\n this._runs.set(runId, run);\n this._emit(run);\n\n const completed = new Set<string>();\n const context = { input, outputs: run.outputs };\n\n // Build execution order respecting `after` dependencies\n const remaining = [...def.steps];\n const executedSteps: JoopWorkflowStep[] = [];\n\n while (remaining.length > 0) {\n if (this._cancellations.has(runId)) {\n run.status = 'cancelled'; this._emit(run); break;\n }\n\n // Find steps whose dependencies are all satisfied\n const ready = remaining.filter(s => (s.after ?? []).every(dep => completed.has(dep)));\n if (ready.length === 0 && remaining.length > 0) throw new Error(`Workflow deadlock in '${workflowId}': circular/missing dependencies`);\n\n // Run ready steps in parallel\n const results = await Promise.allSettled(ready.map(s => this._runStep(s, context, runId)));\n for (let i = 0; i < ready.length; i++) {\n const step = ready[i];\n const result = results[i];\n remaining.splice(remaining.indexOf(step), 1);\n if (result.status === 'fulfilled') {\n run.outputs[step.id] = result.value;\n (context as Record<string, unknown>).outputs = run.outputs;\n completed.add(step.id);\n executedSteps.push(step);\n } else {\n run.errors[step.id] = String(result.reason);\n run.status = 'failed';\n break;\n }\n }\n if (run.status === 'failed') break;\n }\n\n if (run.status === 'failed') {\n // Saga: compensate in reverse order\n run.status = 'compensating'; this._emit(run);\n for (const step of [...executedSteps].reverse()) {\n if (step.compensate) { try { await step.compensate(context); } catch { /* best effort */ } }\n }\n } else if (run.status === 'running') {\n run.status = 'completed';\n }\n\n run.completedAt = Date.now();\n this._emit(run);\n this._cancellations.delete(runId);\n\n return {\n runId,\n status: run.status === 'completed' ? 'completed' : 'failed',\n outputs: run.outputs,\n errors: run.errors,\n durationMs: run.completedAt - run.startedAt,\n };\n }\n\n cancel(runId: string): void { this._cancellations.add(runId); }\n\n status(runId: string): JoopWorkflowRun | undefined { return this._runs.get(runId); }\n history(): JoopWorkflowRun[] { return Array.from(this._runs.values()); }\n runStatus$() { return this._runStatus$.asObservable(); }\n\n private async _runStep(step: JoopWorkflowStep, context: unknown, runId: string): Promise<unknown> {\n const maxAttempts = (step.retries ?? 0) + 1;\n let lastErr: unknown;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (this._cancellations.has(runId)) throw new Error('Cancelled');\n try {\n const run = step.timeout\n ? await _withTimeout(step.execute(context), step.timeout, step.id)\n : await step.execute(context);\n return run;\n } catch (e) { lastErr = e; }\n }\n throw lastErr;\n }\n\n private _emit(run: JoopWorkflowRun): void { this._runStatus$.next({ ...run }); }\n}\n\nfunction _withTimeout<T>(promise: Promise<T>, ms: number, id: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`Step '${id}' timed out after ${ms}ms`)), ms);\n promise.then(v => { clearTimeout(timer); resolve(v); }, e => { clearTimeout(timer); reject(e); });\n });\n}\n"]}
@@ -1,4 +1,7 @@
1
1
  // src/events/index.ts
2
+ var _onListenerError = (error) => {
3
+ console.error("[joopjs] a subject subscriber threw during emission:", error);
4
+ };
2
5
  var JoopSubject = class {
3
6
  _listeners = [];
4
7
  subscribe(listener) {
@@ -8,8 +11,13 @@ var JoopSubject = class {
8
11
  };
9
12
  }
10
13
  next(value) {
11
- for (const listener of this._listeners) {
12
- listener(value);
14
+ const listeners = this._listeners.slice();
15
+ for (const listener of listeners) {
16
+ try {
17
+ listener(value);
18
+ } catch (error) {
19
+ _onListenerError(error);
20
+ }
13
21
  }
14
22
  }
15
23
  asObservable() {
@@ -30,7 +38,11 @@ var JoopBehaviorSubject = class extends JoopSubject {
30
38
  super.next(value);
31
39
  }
32
40
  subscribe(listener) {
33
- listener(this._value);
41
+ try {
42
+ listener(this._value);
43
+ } catch (error) {
44
+ _onListenerError(error);
45
+ }
34
46
  return super.subscribe(listener);
35
47
  }
36
48
  asObservable() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/events/index.ts","../../src/workflow/state-machine.ts","../../src/workflow/workflow-engine.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["export type Unsubscribe = () => void;\nexport type Listener<T> = (value: T) => void;\n\n/**\n * Lightweight pub/sub subject — emits to all current subscribers.\n * Replaces RxJS Subject without pulling in the full RxJS dependency.\n */\nexport class JoopSubject<T> {\n private _listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>): Unsubscribe {\n this._listeners.push(listener);\n return () => {\n this._listeners = this._listeners.filter(l => l !== listener);\n };\n }\n\n next(value: T): void {\n for (const listener of this._listeners) {\n listener(value);\n }\n }\n\n asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Stateful subject — replays the current value to any new subscriber immediately.\n * Replaces RxJS BehaviorSubject.\n */\nexport class JoopBehaviorSubject<T> extends JoopSubject<T> {\n private _value: T;\n\n constructor(initialValue: T) {\n super();\n this._value = initialValue;\n }\n\n getValue(): T {\n return this._value;\n }\n\n override next(value: T): void {\n this._value = value;\n super.next(value);\n }\n\n override subscribe(listener: Listener<T>): Unsubscribe {\n listener(this._value);\n return super.subscribe(listener);\n }\n\n override asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Read-only observable handle returned from asObservable().\n */\nexport class JoopObservable<T> {\n constructor(private _subscribeFn: (listener: Listener<T>) => Unsubscribe) {}\n\n subscribe(listener: Listener<T>): Unsubscribe {\n return this._subscribeFn(listener);\n }\n\n /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */\n getOnce(): T | undefined {\n let result: T | undefined;\n const unsub = this.subscribe(v => { result = v; });\n unsub();\n return result;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopTransition<S extends string, E extends string> {\n target: S;\n guard?: (context?: unknown) => boolean;\n action?: (context?: unknown) => void;\n}\n\nexport interface JoopStateConfig<S extends string, E extends string> {\n on?: Partial<Record<E, JoopTransition<S, E> | S>>;\n onEnter?: (context?: unknown) => void;\n onExit?: (context?: unknown) => void;\n type?: 'final' | 'normal';\n}\n\nexport interface JoopMachineConfig<S extends string, E extends string> {\n id?: string;\n initial: S;\n context?: unknown;\n states: Record<S, JoopStateConfig<S, E>>;\n}\n\nexport interface JoopStateTransition<S extends string, E extends string> {\n from: S;\n event: E;\n to: S;\n timestamp: number;\n}\n\nexport class JoopStateMachine<S extends string, E extends string> {\n private _state$: JoopBehaviorSubject<S>;\n private _transition$ = new JoopSubject<JoopStateTransition<S, E>>();\n private _cfg: JoopMachineConfig<S, E>;\n private _history: JoopStateTransition<S, E>[] = [];\n private _context: unknown;\n\n constructor(config: JoopMachineConfig<S, E>) {\n this._cfg = config;\n this._context = config.context;\n this._state$ = new JoopBehaviorSubject<S>(config.initial);\n this._cfg.states[config.initial]?.onEnter?.(this._context);\n }\n\n getState(): S { return this._state$.getValue(); }\n getContext(): unknown { return this._context; }\n state$() { return this._state$.asObservable(); }\n transition$() { return this._transition$.asObservable(); }\n history(): JoopStateTransition<S, E>[] { return [...this._history]; }\n\n matches(state: S): boolean { return this._state$.getValue() === state; }\n isFinal(): boolean { return this._cfg.states[this.getState()]?.type === 'final'; }\n\n /** Returns true if the event can be sent from current state */\n can(event: E): boolean {\n const cfg = this._cfg.states[this.getState()]?.on;\n if (!cfg || !(event in cfg)) return false;\n const t = this._resolveTransition(this.getState(), event);\n return t !== null;\n }\n\n /** Send an event; returns true if a transition occurred */\n send(event: E, context?: unknown): boolean {\n const from = this.getState();\n const stateCfg = this._cfg.states[from];\n if (!stateCfg?.on || !(event in stateCfg.on)) return false;\n\n const t = this._resolveTransition(from, event, context);\n if (!t) return false;\n\n const to = t.target;\n stateCfg.onExit?.(this._context);\n t.action?.(this._context);\n if (context !== undefined) this._context = context;\n\n const record: JoopStateTransition<S, E> = { from, event, to, timestamp: Date.now() };\n this._history.push(record);\n this._state$.next(to);\n this._transition$.next(record);\n\n this._cfg.states[to]?.onEnter?.(this._context);\n return true;\n }\n\n /** Update context without triggering a transition */\n setContext(ctx: unknown): void { this._context = ctx; }\n\n reset(): void {\n const initial = this._cfg.initial;\n this._state$.next(initial);\n this._history = [];\n this._cfg.states[initial]?.onEnter?.(this._context);\n }\n\n /** Export as Mermaid state diagram */\n toMermaid(): string {\n const lines = ['stateDiagram-v2'];\n lines.push(` [*] --> ${this._cfg.initial}`);\n for (const [state, cfg] of Object.entries(this._cfg.states) as Array<[S, JoopStateConfig<S,E>]>) {\n if (cfg.type === 'final') lines.push(` ${state} --> [*]`);\n if (cfg.on) {\n for (const [event, trans] of Object.entries(cfg.on)) {\n const target = typeof trans === 'string' ? trans : (trans as JoopTransition<S,E>).target;\n lines.push(` ${state} --> ${target} : ${event}`);\n }\n }\n }\n return lines.join('\\n');\n }\n\n private _resolveTransition(from: S, event: E, context?: unknown): JoopTransition<S, E> | null {\n const rawTrans = this._cfg.states[from]?.on?.[event];\n if (!rawTrans) return null;\n const t: JoopTransition<S, E> = typeof rawTrans === 'string' ? { target: rawTrans as S } : rawTrans;\n if (t.guard && !t.guard(context ?? this._context)) return null;\n return t;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopWorkflowStep {\n id: string;\n name?: string;\n after?: string[]; // step IDs this depends on\n execute: (context: unknown) => Promise<unknown>;\n compensate?: (context: unknown) => Promise<void>; // saga rollback\n timeout?: number;\n retries?: number;\n}\n\nexport interface JoopWorkflowDefinition {\n id: string;\n steps: JoopWorkflowStep[];\n}\n\nexport type JoopWorkflowRunStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled' | 'compensating';\n\nexport interface JoopWorkflowRun {\n runId: string;\n workflowId: string;\n status: JoopWorkflowRunStatus;\n input: unknown;\n outputs: Record<string, unknown>;\n errors: Record<string, string>;\n startedAt: number;\n completedAt?: number;\n}\n\nexport interface JoopWorkflowResult {\n runId: string;\n status: 'completed' | 'failed';\n outputs: Record<string, unknown>;\n errors: Record<string, string>;\n durationMs: number;\n}\n\nexport class JoopWorkflowEngine {\n private _definitions = new Map<string, JoopWorkflowDefinition>();\n private _runs = new Map<string, JoopWorkflowRun>();\n private _runStatus$ = new JoopSubject<JoopWorkflowRun>();\n private _cancellations = new Set<string>();\n\n define(workflow: JoopWorkflowDefinition): void { this._definitions.set(workflow.id, workflow); }\n undefine(id: string): void { this._definitions.delete(id); }\n\n async run(workflowId: string, input: unknown = null): Promise<JoopWorkflowResult> {\n const def = this._definitions.get(workflowId);\n if (!def) throw new Error(`JoopWorkflowEngine: unknown workflow '${workflowId}'`);\n\n const runId = `${workflowId}_${Date.now()}_${Math.floor(Math.random() * 1000)}`;\n const run: JoopWorkflowRun = {\n runId, workflowId, status: 'running',\n input, outputs: {}, errors: {}, startedAt: Date.now(),\n };\n this._runs.set(runId, run);\n this._emit(run);\n\n const completed = new Set<string>();\n const context = { input, outputs: run.outputs };\n\n // Build execution order respecting `after` dependencies\n const remaining = [...def.steps];\n const executedSteps: JoopWorkflowStep[] = [];\n\n while (remaining.length > 0) {\n if (this._cancellations.has(runId)) {\n run.status = 'cancelled'; this._emit(run); break;\n }\n\n // Find steps whose dependencies are all satisfied\n const ready = remaining.filter(s => (s.after ?? []).every(dep => completed.has(dep)));\n if (ready.length === 0 && remaining.length > 0) throw new Error(`Workflow deadlock in '${workflowId}': circular/missing dependencies`);\n\n // Run ready steps in parallel\n const results = await Promise.allSettled(ready.map(s => this._runStep(s, context, runId)));\n for (let i = 0; i < ready.length; i++) {\n const step = ready[i];\n const result = results[i];\n remaining.splice(remaining.indexOf(step), 1);\n if (result.status === 'fulfilled') {\n run.outputs[step.id] = result.value;\n (context as Record<string, unknown>).outputs = run.outputs;\n completed.add(step.id);\n executedSteps.push(step);\n } else {\n run.errors[step.id] = String(result.reason);\n run.status = 'failed';\n break;\n }\n }\n if (run.status === 'failed') break;\n }\n\n if (run.status === 'failed') {\n // Saga: compensate in reverse order\n run.status = 'compensating'; this._emit(run);\n for (const step of [...executedSteps].reverse()) {\n if (step.compensate) { try { await step.compensate(context); } catch { /* best effort */ } }\n }\n } else if (run.status === 'running') {\n run.status = 'completed';\n }\n\n run.completedAt = Date.now();\n this._emit(run);\n this._cancellations.delete(runId);\n\n return {\n runId,\n status: run.status === 'completed' ? 'completed' : 'failed',\n outputs: run.outputs,\n errors: run.errors,\n durationMs: run.completedAt - run.startedAt,\n };\n }\n\n cancel(runId: string): void { this._cancellations.add(runId); }\n\n status(runId: string): JoopWorkflowRun | undefined { return this._runs.get(runId); }\n history(): JoopWorkflowRun[] { return Array.from(this._runs.values()); }\n runStatus$() { return this._runStatus$.asObservable(); }\n\n private async _runStep(step: JoopWorkflowStep, context: unknown, runId: string): Promise<unknown> {\n const maxAttempts = (step.retries ?? 0) + 1;\n let lastErr: unknown;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (this._cancellations.has(runId)) throw new Error('Cancelled');\n try {\n const run = step.timeout\n ? await _withTimeout(step.execute(context), step.timeout, step.id)\n : await step.execute(context);\n return run;\n } catch (e) { lastErr = e; }\n }\n throw lastErr;\n }\n\n private _emit(run: JoopWorkflowRun): void { this._runStatus$.next({ ...run }); }\n}\n\nfunction _withTimeout<T>(promise: Promise<T>, ms: number, id: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`Step '${id}' timed out after ${ms}ms`)), ms);\n promise.then(v => { clearTimeout(timer); resolve(v); }, e => { clearTimeout(timer); reject(e); });\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/events/index.ts","../../src/workflow/state-machine.ts","../../src/workflow/workflow-engine.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["export type Unsubscribe = () => void;\nexport type Listener<T> = (value: T) => void;\n\n/**\n * Reports a subscriber that threw during emission, without aborting delivery\n * to the remaining subscribers. Defaults to console.error; override to route\n * to your own logger (e.g. in a banking app where dropped events matter).\n */\nlet _onListenerError: (error: unknown) => void = (error) => {\n // eslint-disable-next-line no-console\n console.error('[joopjs] a subject subscriber threw during emission:', error);\n};\n\n/** Override how subscriber errors are reported during emission. */\nexport function setSubjectErrorHandler(handler: (error: unknown) => void): void {\n _onListenerError = handler;\n}\n\n/**\n * Lightweight pub/sub subject — emits to all current subscribers.\n * Replaces RxJS Subject without pulling in the full RxJS dependency.\n */\nexport class JoopSubject<T> {\n private _listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>): Unsubscribe {\n this._listeners.push(listener);\n return () => {\n this._listeners = this._listeners.filter(l => l !== listener);\n };\n }\n\n next(value: T): void {\n // Snapshot so a subscribe()/unsubscribe() triggered by a listener can't\n // disturb this emission, and isolate each listener so one that throws\n // doesn't deprive later subscribers of the value.\n const listeners = this._listeners.slice();\n for (const listener of listeners) {\n try {\n listener(value);\n } catch (error) {\n _onListenerError(error);\n }\n }\n }\n\n asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Stateful subject — replays the current value to any new subscriber immediately.\n * Replaces RxJS BehaviorSubject.\n */\nexport class JoopBehaviorSubject<T> extends JoopSubject<T> {\n private _value: T;\n\n constructor(initialValue: T) {\n super();\n this._value = initialValue;\n }\n\n getValue(): T {\n return this._value;\n }\n\n override next(value: T): void {\n this._value = value;\n super.next(value);\n }\n\n override subscribe(listener: Listener<T>): Unsubscribe {\n try {\n listener(this._value);\n } catch (error) {\n _onListenerError(error);\n }\n return super.subscribe(listener);\n }\n\n override asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Read-only observable handle returned from asObservable().\n */\nexport class JoopObservable<T> {\n constructor(private _subscribeFn: (listener: Listener<T>) => Unsubscribe) {}\n\n subscribe(listener: Listener<T>): Unsubscribe {\n return this._subscribeFn(listener);\n }\n\n /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */\n getOnce(): T | undefined {\n let result: T | undefined;\n const unsub = this.subscribe(v => { result = v; });\n unsub();\n return result;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopTransition<S extends string, E extends string> {\n target: S;\n guard?: (context?: unknown) => boolean;\n action?: (context?: unknown) => void;\n}\n\nexport interface JoopStateConfig<S extends string, E extends string> {\n on?: Partial<Record<E, JoopTransition<S, E> | S>>;\n onEnter?: (context?: unknown) => void;\n onExit?: (context?: unknown) => void;\n type?: 'final' | 'normal';\n}\n\nexport interface JoopMachineConfig<S extends string, E extends string> {\n id?: string;\n initial: S;\n context?: unknown;\n states: Record<S, JoopStateConfig<S, E>>;\n}\n\nexport interface JoopStateTransition<S extends string, E extends string> {\n from: S;\n event: E;\n to: S;\n timestamp: number;\n}\n\nexport class JoopStateMachine<S extends string, E extends string> {\n private _state$: JoopBehaviorSubject<S>;\n private _transition$ = new JoopSubject<JoopStateTransition<S, E>>();\n private _cfg: JoopMachineConfig<S, E>;\n private _history: JoopStateTransition<S, E>[] = [];\n private _context: unknown;\n\n constructor(config: JoopMachineConfig<S, E>) {\n this._cfg = config;\n this._context = config.context;\n this._state$ = new JoopBehaviorSubject<S>(config.initial);\n this._cfg.states[config.initial]?.onEnter?.(this._context);\n }\n\n getState(): S { return this._state$.getValue(); }\n getContext(): unknown { return this._context; }\n state$() { return this._state$.asObservable(); }\n transition$() { return this._transition$.asObservable(); }\n history(): JoopStateTransition<S, E>[] { return [...this._history]; }\n\n matches(state: S): boolean { return this._state$.getValue() === state; }\n isFinal(): boolean { return this._cfg.states[this.getState()]?.type === 'final'; }\n\n /** Returns true if the event can be sent from current state */\n can(event: E): boolean {\n const cfg = this._cfg.states[this.getState()]?.on;\n if (!cfg || !(event in cfg)) return false;\n const t = this._resolveTransition(this.getState(), event);\n return t !== null;\n }\n\n /** Send an event; returns true if a transition occurred */\n send(event: E, context?: unknown): boolean {\n const from = this.getState();\n const stateCfg = this._cfg.states[from];\n if (!stateCfg?.on || !(event in stateCfg.on)) return false;\n\n const t = this._resolveTransition(from, event, context);\n if (!t) return false;\n\n const to = t.target;\n stateCfg.onExit?.(this._context);\n t.action?.(this._context);\n if (context !== undefined) this._context = context;\n\n const record: JoopStateTransition<S, E> = { from, event, to, timestamp: Date.now() };\n this._history.push(record);\n this._state$.next(to);\n this._transition$.next(record);\n\n this._cfg.states[to]?.onEnter?.(this._context);\n return true;\n }\n\n /** Update context without triggering a transition */\n setContext(ctx: unknown): void { this._context = ctx; }\n\n reset(): void {\n const initial = this._cfg.initial;\n this._state$.next(initial);\n this._history = [];\n this._cfg.states[initial]?.onEnter?.(this._context);\n }\n\n /** Export as Mermaid state diagram */\n toMermaid(): string {\n const lines = ['stateDiagram-v2'];\n lines.push(` [*] --> ${this._cfg.initial}`);\n for (const [state, cfg] of Object.entries(this._cfg.states) as Array<[S, JoopStateConfig<S,E>]>) {\n if (cfg.type === 'final') lines.push(` ${state} --> [*]`);\n if (cfg.on) {\n for (const [event, trans] of Object.entries(cfg.on)) {\n const target = typeof trans === 'string' ? trans : (trans as JoopTransition<S,E>).target;\n lines.push(` ${state} --> ${target} : ${event}`);\n }\n }\n }\n return lines.join('\\n');\n }\n\n private _resolveTransition(from: S, event: E, context?: unknown): JoopTransition<S, E> | null {\n const rawTrans = this._cfg.states[from]?.on?.[event];\n if (!rawTrans) return null;\n const t: JoopTransition<S, E> = typeof rawTrans === 'string' ? { target: rawTrans as S } : rawTrans;\n if (t.guard && !t.guard(context ?? this._context)) return null;\n return t;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopWorkflowStep {\n id: string;\n name?: string;\n after?: string[]; // step IDs this depends on\n execute: (context: unknown) => Promise<unknown>;\n compensate?: (context: unknown) => Promise<void>; // saga rollback\n timeout?: number;\n retries?: number;\n}\n\nexport interface JoopWorkflowDefinition {\n id: string;\n steps: JoopWorkflowStep[];\n}\n\nexport type JoopWorkflowRunStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled' | 'compensating';\n\nexport interface JoopWorkflowRun {\n runId: string;\n workflowId: string;\n status: JoopWorkflowRunStatus;\n input: unknown;\n outputs: Record<string, unknown>;\n errors: Record<string, string>;\n startedAt: number;\n completedAt?: number;\n}\n\nexport interface JoopWorkflowResult {\n runId: string;\n status: 'completed' | 'failed';\n outputs: Record<string, unknown>;\n errors: Record<string, string>;\n durationMs: number;\n}\n\nexport class JoopWorkflowEngine {\n private _definitions = new Map<string, JoopWorkflowDefinition>();\n private _runs = new Map<string, JoopWorkflowRun>();\n private _runStatus$ = new JoopSubject<JoopWorkflowRun>();\n private _cancellations = new Set<string>();\n\n define(workflow: JoopWorkflowDefinition): void { this._definitions.set(workflow.id, workflow); }\n undefine(id: string): void { this._definitions.delete(id); }\n\n async run(workflowId: string, input: unknown = null): Promise<JoopWorkflowResult> {\n const def = this._definitions.get(workflowId);\n if (!def) throw new Error(`JoopWorkflowEngine: unknown workflow '${workflowId}'`);\n\n const runId = `${workflowId}_${Date.now()}_${Math.floor(Math.random() * 1000)}`;\n const run: JoopWorkflowRun = {\n runId, workflowId, status: 'running',\n input, outputs: {}, errors: {}, startedAt: Date.now(),\n };\n this._runs.set(runId, run);\n this._emit(run);\n\n const completed = new Set<string>();\n const context = { input, outputs: run.outputs };\n\n // Build execution order respecting `after` dependencies\n const remaining = [...def.steps];\n const executedSteps: JoopWorkflowStep[] = [];\n\n while (remaining.length > 0) {\n if (this._cancellations.has(runId)) {\n run.status = 'cancelled'; this._emit(run); break;\n }\n\n // Find steps whose dependencies are all satisfied\n const ready = remaining.filter(s => (s.after ?? []).every(dep => completed.has(dep)));\n if (ready.length === 0 && remaining.length > 0) throw new Error(`Workflow deadlock in '${workflowId}': circular/missing dependencies`);\n\n // Run ready steps in parallel\n const results = await Promise.allSettled(ready.map(s => this._runStep(s, context, runId)));\n for (let i = 0; i < ready.length; i++) {\n const step = ready[i];\n const result = results[i];\n remaining.splice(remaining.indexOf(step), 1);\n if (result.status === 'fulfilled') {\n run.outputs[step.id] = result.value;\n (context as Record<string, unknown>).outputs = run.outputs;\n completed.add(step.id);\n executedSteps.push(step);\n } else {\n run.errors[step.id] = String(result.reason);\n run.status = 'failed';\n break;\n }\n }\n if (run.status === 'failed') break;\n }\n\n if (run.status === 'failed') {\n // Saga: compensate in reverse order\n run.status = 'compensating'; this._emit(run);\n for (const step of [...executedSteps].reverse()) {\n if (step.compensate) { try { await step.compensate(context); } catch { /* best effort */ } }\n }\n } else if (run.status === 'running') {\n run.status = 'completed';\n }\n\n run.completedAt = Date.now();\n this._emit(run);\n this._cancellations.delete(runId);\n\n return {\n runId,\n status: run.status === 'completed' ? 'completed' : 'failed',\n outputs: run.outputs,\n errors: run.errors,\n durationMs: run.completedAt - run.startedAt,\n };\n }\n\n cancel(runId: string): void { this._cancellations.add(runId); }\n\n status(runId: string): JoopWorkflowRun | undefined { return this._runs.get(runId); }\n history(): JoopWorkflowRun[] { return Array.from(this._runs.values()); }\n runStatus$() { return this._runStatus$.asObservable(); }\n\n private async _runStep(step: JoopWorkflowStep, context: unknown, runId: string): Promise<unknown> {\n const maxAttempts = (step.retries ?? 0) + 1;\n let lastErr: unknown;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (this._cancellations.has(runId)) throw new Error('Cancelled');\n try {\n const run = step.timeout\n ? await _withTimeout(step.execute(context), step.timeout, step.id)\n : await step.execute(context);\n return run;\n } catch (e) { lastErr = e; }\n }\n throw lastErr;\n }\n\n private _emit(run: JoopWorkflowRun): void { this._runStatus$.next({ ...run }); }\n}\n\nfunction _withTimeout<T>(promise: Promise<T>, ms: number, id: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`Step '${id}' timed out after ${ms}ms`)), ms);\n promise.then(v => { clearTimeout(timer); resolve(v); }, e => { clearTimeout(timer); reject(e); });\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joopjs",
3
- "version": "2.0.6",
3
+ "version": "2.1.0",
4
4
  "description": "Framework-agnostic JavaScript SDK for enterprise web applications. Works with React, Angular, Vue, and any JavaScript project.",
5
5
  "keywords": [
6
6
  "sdk",
@@ -226,6 +226,7 @@
226
226
  "build": "tsup",
227
227
  "build:watch": "tsup --watch",
228
228
  "typecheck": "tsc --noEmit",
229
+ "check:boundary": "node scripts/check-core-boundary.mjs",
229
230
  "clean": "rimraf dist dist-playground",
230
231
  "test": "vitest run",
231
232
  "test:ui": "vitest --ui --open",
@@ -246,8 +247,10 @@
246
247
  "base64-arraybuffer": "^1.0.2"
247
248
  },
248
249
  "peerDependencies": {
249
- "react": ">=18.0.0",
250
+ "@angular/common": ">=17.0.0",
250
251
  "@angular/core": ">=17.0.0",
252
+ "@angular/router": ">=17.0.0",
253
+ "react": ">=18.0.0",
251
254
  "rxjs": ">=7.0.0",
252
255
  "vue": ">=3.0.0"
253
256
  },
@@ -255,9 +258,15 @@
255
258
  "react": {
256
259
  "optional": true
257
260
  },
261
+ "@angular/common": {
262
+ "optional": true
263
+ },
258
264
  "@angular/core": {
259
265
  "optional": true
260
266
  },
267
+ "@angular/router": {
268
+ "optional": true
269
+ },
261
270
  "rxjs": {
262
271
  "optional": true
263
272
  },
@@ -266,11 +275,16 @@
266
275
  }
267
276
  },
268
277
  "devDependencies": {
278
+ "@angular/common": "^17.3.12",
279
+ "@angular/compiler": "^17.3.12",
280
+ "@angular/core": "^17.3.12",
281
+ "@angular/router": "^17.3.12",
269
282
  "@vitest/coverage-v8": "^2.1.0",
270
283
  "@vitest/ui": "^2.1.0",
271
284
  "fake-indexeddb": "^6.2.5",
272
285
  "jsdom": "^29.1.1",
273
286
  "rimraf": "^5.0.0",
287
+ "rxjs": "^7.8.2",
274
288
  "tsup": "^8.3.0",
275
289
  "typescript": "^5.3.3",
276
290
  "vite": "^5.4.0",