joopjs 2.0.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 (259) hide show
  1. package/CHANGELOG.md +678 -0
  2. package/README.md +583 -0
  3. package/dist/a11y.service-C-DQQfgO.d.mts +143 -0
  4. package/dist/a11y.service-CauEJrJe.d.ts +143 -0
  5. package/dist/adapters-B6slG6hQ.d.mts +84 -0
  6. package/dist/adapters-B6slG6hQ.d.ts +84 -0
  7. package/dist/aes.service-CkoupAww.d.mts +95 -0
  8. package/dist/aes.service-CkoupAww.d.ts +95 -0
  9. package/dist/ai/index.d.mts +99 -0
  10. package/dist/ai/index.d.ts +99 -0
  11. package/dist/ai/index.js +307 -0
  12. package/dist/ai/index.js.map +1 -0
  13. package/dist/ai/index.mjs +304 -0
  14. package/dist/ai/index.mjs.map +1 -0
  15. package/dist/analytics/index.d.mts +42 -0
  16. package/dist/analytics/index.d.ts +42 -0
  17. package/dist/analytics/index.js +139 -0
  18. package/dist/analytics/index.js.map +1 -0
  19. package/dist/analytics/index.mjs +136 -0
  20. package/dist/analytics/index.mjs.map +1 -0
  21. package/dist/angular/index.d.mts +148 -0
  22. package/dist/angular/index.d.ts +148 -0
  23. package/dist/angular/index.js +122 -0
  24. package/dist/angular/index.js.map +1 -0
  25. package/dist/angular/index.mjs +101 -0
  26. package/dist/angular/index.mjs.map +1 -0
  27. package/dist/api/index.d.mts +128 -0
  28. package/dist/api/index.d.ts +128 -0
  29. package/dist/api/index.js +1358 -0
  30. package/dist/api/index.js.map +1 -0
  31. package/dist/api/index.mjs +1332 -0
  32. package/dist/api/index.mjs.map +1 -0
  33. package/dist/auth/index.d.mts +105 -0
  34. package/dist/auth/index.d.ts +105 -0
  35. package/dist/auth/index.js +989 -0
  36. package/dist/auth/index.js.map +1 -0
  37. package/dist/auth/index.mjs +979 -0
  38. package/dist/auth/index.mjs.map +1 -0
  39. package/dist/auth.service-DNVB-L4U.d.mts +16 -0
  40. package/dist/auth.service-PjUUSUIt.d.ts +16 -0
  41. package/dist/banking/index.d.mts +1530 -0
  42. package/dist/banking/index.d.ts +1530 -0
  43. package/dist/banking/index.js +4739 -0
  44. package/dist/banking/index.js.map +1 -0
  45. package/dist/banking/index.mjs +4661 -0
  46. package/dist/banking/index.mjs.map +1 -0
  47. package/dist/cache/index.d.mts +40 -0
  48. package/dist/cache/index.d.ts +40 -0
  49. package/dist/cache/index.js +174 -0
  50. package/dist/cache/index.js.map +1 -0
  51. package/dist/cache/index.mjs +172 -0
  52. package/dist/cache/index.mjs.map +1 -0
  53. package/dist/client-profile.service-BuPeXVp5.d.mts +28 -0
  54. package/dist/client-profile.service-D5bRRYQp.d.ts +28 -0
  55. package/dist/config.models-Cqg04fAQ.d.mts +84 -0
  56. package/dist/config.models-Cqg04fAQ.d.ts +84 -0
  57. package/dist/config.service-CrCvI-JS.d.ts +31 -0
  58. package/dist/config.service-Cz4QQLlf.d.mts +31 -0
  59. package/dist/core/index.d.mts +4 -0
  60. package/dist/core/index.d.ts +4 -0
  61. package/dist/core/index.js +631 -0
  62. package/dist/core/index.js.map +1 -0
  63. package/dist/core/index.mjs +619 -0
  64. package/dist/core/index.mjs.map +1 -0
  65. package/dist/crypto-utils-DriNhLdx.d.mts +30 -0
  66. package/dist/crypto-utils-DriNhLdx.d.ts +30 -0
  67. package/dist/data-storage.service-DT6xaTxE.d.ts +51 -0
  68. package/dist/data-storage.service-LvhGRCmw.d.mts +51 -0
  69. package/dist/deeplink/index.d.mts +39 -0
  70. package/dist/deeplink/index.d.ts +39 -0
  71. package/dist/deeplink/index.js +268 -0
  72. package/dist/deeplink/index.js.map +1 -0
  73. package/dist/deeplink/index.mjs +265 -0
  74. package/dist/deeplink/index.mjs.map +1 -0
  75. package/dist/deeplink.service-Ctd5u243.d.mts +35 -0
  76. package/dist/deeplink.service-uUuTnY9_.d.ts +35 -0
  77. package/dist/dev/index.d.mts +20 -0
  78. package/dist/dev/index.d.ts +20 -0
  79. package/dist/dev/index.js +51 -0
  80. package/dist/dev/index.js.map +1 -0
  81. package/dist/dev/index.mjs +49 -0
  82. package/dist/dev/index.mjs.map +1 -0
  83. package/dist/device/index.d.mts +108 -0
  84. package/dist/device/index.d.ts +108 -0
  85. package/dist/device/index.js +960 -0
  86. package/dist/device/index.js.map +1 -0
  87. package/dist/device/index.mjs +951 -0
  88. package/dist/device/index.mjs.map +1 -0
  89. package/dist/differential-privacy-BcAv1G80.d.mts +210 -0
  90. package/dist/differential-privacy-C8mAUjZr.d.ts +210 -0
  91. package/dist/encryption/index.d.mts +75 -0
  92. package/dist/encryption/index.d.ts +75 -0
  93. package/dist/encryption/index.js +605 -0
  94. package/dist/encryption/index.js.map +1 -0
  95. package/dist/encryption/index.mjs +598 -0
  96. package/dist/encryption/index.mjs.map +1 -0
  97. package/dist/form-validator-3tkmzr_o.d.mts +72 -0
  98. package/dist/form-validator-3tkmzr_o.d.ts +72 -0
  99. package/dist/forms/index.d.mts +59 -0
  100. package/dist/forms/index.d.ts +59 -0
  101. package/dist/forms/index.js +446 -0
  102. package/dist/forms/index.js.map +1 -0
  103. package/dist/forms/index.mjs +442 -0
  104. package/dist/forms/index.mjs.map +1 -0
  105. package/dist/i18n/index.d.mts +37 -0
  106. package/dist/i18n/index.d.ts +37 -0
  107. package/dist/i18n/index.js +147 -0
  108. package/dist/i18n/index.js.map +1 -0
  109. package/dist/i18n/index.mjs +145 -0
  110. package/dist/i18n/index.mjs.map +1 -0
  111. package/dist/idempotency.service-_6LqhivP.d.mts +372 -0
  112. package/dist/idempotency.service-eOKoISRD.d.ts +372 -0
  113. package/dist/index-B_ksKpS1.d.mts +202 -0
  114. package/dist/index-CqDKWTUP.d.mts +28 -0
  115. package/dist/index-CqDKWTUP.d.ts +28 -0
  116. package/dist/index-DFqEoX_l.d.ts +202 -0
  117. package/dist/index-Dz0gOur2.d.mts +36 -0
  118. package/dist/index-Dz0gOur2.d.ts +36 -0
  119. package/dist/index.d.mts +1336 -0
  120. package/dist/index.d.ts +1336 -0
  121. package/dist/index.js +19464 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/index.mjs +19155 -0
  124. package/dist/index.mjs.map +1 -0
  125. package/dist/india/index.d.mts +75 -0
  126. package/dist/india/index.d.ts +75 -0
  127. package/dist/india/index.js +325 -0
  128. package/dist/india/index.js.map +1 -0
  129. package/dist/india/index.mjs +303 -0
  130. package/dist/india/index.mjs.map +1 -0
  131. package/dist/joop-Bx7Iwj5p.d.mts +155 -0
  132. package/dist/joop-CA3DMeOO.d.ts +155 -0
  133. package/dist/native-bridge/index.d.mts +27 -0
  134. package/dist/native-bridge/index.d.ts +27 -0
  135. package/dist/native-bridge/index.js +98 -0
  136. package/dist/native-bridge/index.js.map +1 -0
  137. package/dist/native-bridge/index.mjs +96 -0
  138. package/dist/native-bridge/index.mjs.map +1 -0
  139. package/dist/network/index.d.mts +85 -0
  140. package/dist/network/index.d.ts +85 -0
  141. package/dist/network/index.js +454 -0
  142. package/dist/network/index.js.map +1 -0
  143. package/dist/network/index.mjs +451 -0
  144. package/dist/network/index.mjs.map +1 -0
  145. package/dist/network-monitor-BIwPSXme.d.mts +179 -0
  146. package/dist/network-monitor-Bqp2hvZr.d.ts +179 -0
  147. package/dist/notification.service-Dm4fvfZf.d.mts +25 -0
  148. package/dist/notification.service-tEMKatWJ.d.ts +25 -0
  149. package/dist/observability/index.d.mts +179 -0
  150. package/dist/observability/index.d.ts +179 -0
  151. package/dist/observability/index.js +559 -0
  152. package/dist/observability/index.js.map +1 -0
  153. package/dist/observability/index.mjs +552 -0
  154. package/dist/observability/index.mjs.map +1 -0
  155. package/dist/oidc-client-DIJcClmB.d.mts +190 -0
  156. package/dist/oidc-client-DxhyE59t.d.ts +190 -0
  157. package/dist/platform/index.d.mts +73 -0
  158. package/dist/platform/index.d.ts +73 -0
  159. package/dist/platform/index.js +127 -0
  160. package/dist/platform/index.js.map +1 -0
  161. package/dist/platform/index.mjs +125 -0
  162. package/dist/platform/index.mjs.map +1 -0
  163. package/dist/pwa/index.d.mts +31 -0
  164. package/dist/pwa/index.d.ts +31 -0
  165. package/dist/pwa/index.js +247 -0
  166. package/dist/pwa/index.js.map +1 -0
  167. package/dist/pwa/index.mjs +244 -0
  168. package/dist/pwa/index.mjs.map +1 -0
  169. package/dist/react/index.d.mts +133 -0
  170. package/dist/react/index.d.ts +133 -0
  171. package/dist/react/index.js +632 -0
  172. package/dist/react/index.js.map +1 -0
  173. package/dist/react/index.mjs +630 -0
  174. package/dist/react/index.mjs.map +1 -0
  175. package/dist/router/index.d.mts +39 -0
  176. package/dist/router/index.d.ts +39 -0
  177. package/dist/router/index.js +168 -0
  178. package/dist/router/index.js.map +1 -0
  179. package/dist/router/index.mjs +166 -0
  180. package/dist/router/index.mjs.map +1 -0
  181. package/dist/security/index.d.mts +206 -0
  182. package/dist/security/index.d.ts +206 -0
  183. package/dist/security/index.js +1297 -0
  184. package/dist/security/index.js.map +1 -0
  185. package/dist/security/index.mjs +1285 -0
  186. package/dist/security/index.mjs.map +1 -0
  187. package/dist/session/index.d.mts +115 -0
  188. package/dist/session/index.d.ts +115 -0
  189. package/dist/session/index.js +297 -0
  190. package/dist/session/index.js.map +1 -0
  191. package/dist/session/index.mjs +292 -0
  192. package/dist/session/index.mjs.map +1 -0
  193. package/dist/state/index.d.mts +43 -0
  194. package/dist/state/index.d.ts +43 -0
  195. package/dist/state/index.js +156 -0
  196. package/dist/state/index.js.map +1 -0
  197. package/dist/state/index.mjs +152 -0
  198. package/dist/state/index.mjs.map +1 -0
  199. package/dist/statement-parser-BHQtXwCM.d.ts +260 -0
  200. package/dist/statement-parser-C2qNmb49.d.mts +260 -0
  201. package/dist/storage/index.d.mts +40 -0
  202. package/dist/storage/index.d.ts +40 -0
  203. package/dist/storage/index.js +256 -0
  204. package/dist/storage/index.js.map +1 -0
  205. package/dist/storage/index.mjs +252 -0
  206. package/dist/storage/index.mjs.map +1 -0
  207. package/dist/sync/index.d.mts +69 -0
  208. package/dist/sync/index.d.ts +69 -0
  209. package/dist/sync/index.js +330 -0
  210. package/dist/sync/index.js.map +1 -0
  211. package/dist/sync/index.mjs +323 -0
  212. package/dist/sync/index.mjs.map +1 -0
  213. package/dist/sync-engine-DCIMRG5s.d.ts +61 -0
  214. package/dist/sync-engine-DZqyKHkK.d.mts +61 -0
  215. package/dist/theme/index.d.mts +53 -0
  216. package/dist/theme/index.d.ts +53 -0
  217. package/dist/theme/index.js +169 -0
  218. package/dist/theme/index.js.map +1 -0
  219. package/dist/theme/index.mjs +167 -0
  220. package/dist/theme/index.mjs.map +1 -0
  221. package/dist/ui/index.d.mts +66 -0
  222. package/dist/ui/index.d.ts +66 -0
  223. package/dist/ui/index.js +811 -0
  224. package/dist/ui/index.js.map +1 -0
  225. package/dist/ui/index.mjs +803 -0
  226. package/dist/ui/index.mjs.map +1 -0
  227. package/dist/utilities/index.d.mts +199 -0
  228. package/dist/utilities/index.d.ts +199 -0
  229. package/dist/utilities/index.js +1991 -0
  230. package/dist/utilities/index.js.map +1 -0
  231. package/dist/utilities/index.mjs +1923 -0
  232. package/dist/utilities/index.mjs.map +1 -0
  233. package/dist/validation/index.d.mts +60 -0
  234. package/dist/validation/index.d.ts +60 -0
  235. package/dist/validation/index.js +460 -0
  236. package/dist/validation/index.js.map +1 -0
  237. package/dist/validation/index.mjs +455 -0
  238. package/dist/validation/index.mjs.map +1 -0
  239. package/dist/vue/index.d.mts +135 -0
  240. package/dist/vue/index.d.ts +135 -0
  241. package/dist/vue/index.js +621 -0
  242. package/dist/vue/index.js.map +1 -0
  243. package/dist/vue/index.mjs +619 -0
  244. package/dist/vue/index.mjs.map +1 -0
  245. package/dist/watermark.service-Detur5tq.d.ts +235 -0
  246. package/dist/watermark.service-QNegMeQZ.d.mts +235 -0
  247. package/dist/workers/index.d.mts +42 -0
  248. package/dist/workers/index.d.ts +42 -0
  249. package/dist/workers/index.js +359 -0
  250. package/dist/workers/index.js.map +1 -0
  251. package/dist/workers/index.mjs +356 -0
  252. package/dist/workers/index.mjs.map +1 -0
  253. package/dist/workflow/index.d.mts +99 -0
  254. package/dist/workflow/index.d.ts +99 -0
  255. package/dist/workflow/index.js +282 -0
  256. package/dist/workflow/index.js.map +1 -0
  257. package/dist/workflow/index.mjs +279 -0
  258. package/dist/workflow/index.mjs.map +1 -0
  259. package/package.json +226 -0
@@ -0,0 +1,282 @@
1
+ 'use strict';
2
+
3
+ // src/events/index.ts
4
+ var JoopSubject = class {
5
+ _listeners = [];
6
+ subscribe(listener) {
7
+ this._listeners.push(listener);
8
+ return () => {
9
+ this._listeners = this._listeners.filter((l) => l !== listener);
10
+ };
11
+ }
12
+ next(value) {
13
+ for (const listener of this._listeners) {
14
+ listener(value);
15
+ }
16
+ }
17
+ asObservable() {
18
+ return new JoopObservable((listener) => this.subscribe(listener));
19
+ }
20
+ };
21
+ var JoopBehaviorSubject = class extends JoopSubject {
22
+ _value;
23
+ constructor(initialValue) {
24
+ super();
25
+ this._value = initialValue;
26
+ }
27
+ getValue() {
28
+ return this._value;
29
+ }
30
+ next(value) {
31
+ this._value = value;
32
+ super.next(value);
33
+ }
34
+ subscribe(listener) {
35
+ listener(this._value);
36
+ return super.subscribe(listener);
37
+ }
38
+ asObservable() {
39
+ return new JoopObservable((listener) => this.subscribe(listener));
40
+ }
41
+ };
42
+ var JoopObservable = class {
43
+ constructor(_subscribeFn) {
44
+ this._subscribeFn = _subscribeFn;
45
+ }
46
+ _subscribeFn;
47
+ subscribe(listener) {
48
+ return this._subscribeFn(listener);
49
+ }
50
+ /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */
51
+ getOnce() {
52
+ let result;
53
+ const unsub = this.subscribe((v) => {
54
+ result = v;
55
+ });
56
+ unsub();
57
+ return result;
58
+ }
59
+ };
60
+
61
+ // src/workflow/state-machine.ts
62
+ var JoopStateMachine = class {
63
+ _state$;
64
+ _transition$ = new JoopSubject();
65
+ _cfg;
66
+ _history = [];
67
+ _context;
68
+ constructor(config) {
69
+ this._cfg = config;
70
+ this._context = config.context;
71
+ this._state$ = new JoopBehaviorSubject(config.initial);
72
+ this._cfg.states[config.initial]?.onEnter?.(this._context);
73
+ }
74
+ getState() {
75
+ return this._state$.getValue();
76
+ }
77
+ getContext() {
78
+ return this._context;
79
+ }
80
+ state$() {
81
+ return this._state$.asObservable();
82
+ }
83
+ transition$() {
84
+ return this._transition$.asObservable();
85
+ }
86
+ history() {
87
+ return [...this._history];
88
+ }
89
+ matches(state) {
90
+ return this._state$.getValue() === state;
91
+ }
92
+ isFinal() {
93
+ return this._cfg.states[this.getState()]?.type === "final";
94
+ }
95
+ /** Returns true if the event can be sent from current state */
96
+ can(event) {
97
+ const cfg = this._cfg.states[this.getState()]?.on;
98
+ if (!cfg || !(event in cfg)) return false;
99
+ const t = this._resolveTransition(this.getState(), event);
100
+ return t !== null;
101
+ }
102
+ /** Send an event; returns true if a transition occurred */
103
+ send(event, context) {
104
+ const from = this.getState();
105
+ const stateCfg = this._cfg.states[from];
106
+ if (!stateCfg?.on || !(event in stateCfg.on)) return false;
107
+ const t = this._resolveTransition(from, event, context);
108
+ if (!t) return false;
109
+ const to = t.target;
110
+ stateCfg.onExit?.(this._context);
111
+ t.action?.(this._context);
112
+ if (context !== void 0) this._context = context;
113
+ const record = { from, event, to, timestamp: Date.now() };
114
+ this._history.push(record);
115
+ this._state$.next(to);
116
+ this._transition$.next(record);
117
+ this._cfg.states[to]?.onEnter?.(this._context);
118
+ return true;
119
+ }
120
+ /** Update context without triggering a transition */
121
+ setContext(ctx) {
122
+ this._context = ctx;
123
+ }
124
+ reset() {
125
+ const initial = this._cfg.initial;
126
+ this._state$.next(initial);
127
+ this._history = [];
128
+ this._cfg.states[initial]?.onEnter?.(this._context);
129
+ }
130
+ /** Export as Mermaid state diagram */
131
+ toMermaid() {
132
+ const lines = ["stateDiagram-v2"];
133
+ lines.push(` [*] --> ${this._cfg.initial}`);
134
+ for (const [state, cfg] of Object.entries(this._cfg.states)) {
135
+ if (cfg.type === "final") lines.push(` ${state} --> [*]`);
136
+ if (cfg.on) {
137
+ for (const [event, trans] of Object.entries(cfg.on)) {
138
+ const target = typeof trans === "string" ? trans : trans.target;
139
+ lines.push(` ${state} --> ${target} : ${event}`);
140
+ }
141
+ }
142
+ }
143
+ return lines.join("\n");
144
+ }
145
+ _resolveTransition(from, event, context) {
146
+ const rawTrans = this._cfg.states[from]?.on?.[event];
147
+ if (!rawTrans) return null;
148
+ const t = typeof rawTrans === "string" ? { target: rawTrans } : rawTrans;
149
+ if (t.guard && !t.guard(context ?? this._context)) return null;
150
+ return t;
151
+ }
152
+ };
153
+
154
+ // src/workflow/workflow-engine.ts
155
+ var JoopWorkflowEngine = class {
156
+ _definitions = /* @__PURE__ */ new Map();
157
+ _runs = /* @__PURE__ */ new Map();
158
+ _runStatus$ = new JoopSubject();
159
+ _cancellations = /* @__PURE__ */ new Set();
160
+ define(workflow) {
161
+ this._definitions.set(workflow.id, workflow);
162
+ }
163
+ undefine(id) {
164
+ this._definitions.delete(id);
165
+ }
166
+ async run(workflowId, input = null) {
167
+ const def = this._definitions.get(workflowId);
168
+ if (!def) throw new Error(`JoopWorkflowEngine: unknown workflow '${workflowId}'`);
169
+ const runId = `${workflowId}_${Date.now()}_${Math.floor(Math.random() * 1e3)}`;
170
+ const run = {
171
+ runId,
172
+ workflowId,
173
+ status: "running",
174
+ input,
175
+ outputs: {},
176
+ errors: {},
177
+ startedAt: Date.now()
178
+ };
179
+ this._runs.set(runId, run);
180
+ this._emit(run);
181
+ const completed = /* @__PURE__ */ new Set();
182
+ const context = { input, outputs: run.outputs };
183
+ const remaining = [...def.steps];
184
+ const executedSteps = [];
185
+ while (remaining.length > 0) {
186
+ if (this._cancellations.has(runId)) {
187
+ run.status = "cancelled";
188
+ this._emit(run);
189
+ break;
190
+ }
191
+ const ready = remaining.filter((s) => (s.after ?? []).every((dep) => completed.has(dep)));
192
+ if (ready.length === 0 && remaining.length > 0) throw new Error(`Workflow deadlock in '${workflowId}': circular/missing dependencies`);
193
+ const results = await Promise.allSettled(ready.map((s) => this._runStep(s, context, runId)));
194
+ for (let i = 0; i < ready.length; i++) {
195
+ const step = ready[i];
196
+ const result = results[i];
197
+ remaining.splice(remaining.indexOf(step), 1);
198
+ if (result.status === "fulfilled") {
199
+ run.outputs[step.id] = result.value;
200
+ context.outputs = run.outputs;
201
+ completed.add(step.id);
202
+ executedSteps.push(step);
203
+ } else {
204
+ run.errors[step.id] = String(result.reason);
205
+ run.status = "failed";
206
+ break;
207
+ }
208
+ }
209
+ if (run.status === "failed") break;
210
+ }
211
+ if (run.status === "failed") {
212
+ run.status = "compensating";
213
+ this._emit(run);
214
+ for (const step of [...executedSteps].reverse()) {
215
+ if (step.compensate) {
216
+ try {
217
+ await step.compensate(context);
218
+ } catch {
219
+ }
220
+ }
221
+ }
222
+ } else if (run.status === "running") {
223
+ run.status = "completed";
224
+ }
225
+ run.completedAt = Date.now();
226
+ this._emit(run);
227
+ this._cancellations.delete(runId);
228
+ return {
229
+ runId,
230
+ status: run.status === "completed" ? "completed" : "failed",
231
+ outputs: run.outputs,
232
+ errors: run.errors,
233
+ durationMs: run.completedAt - run.startedAt
234
+ };
235
+ }
236
+ cancel(runId) {
237
+ this._cancellations.add(runId);
238
+ }
239
+ status(runId) {
240
+ return this._runs.get(runId);
241
+ }
242
+ history() {
243
+ return Array.from(this._runs.values());
244
+ }
245
+ runStatus$() {
246
+ return this._runStatus$.asObservable();
247
+ }
248
+ async _runStep(step, context, runId) {
249
+ const maxAttempts = (step.retries ?? 0) + 1;
250
+ let lastErr;
251
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
252
+ if (this._cancellations.has(runId)) throw new Error("Cancelled");
253
+ try {
254
+ const run = step.timeout ? await _withTimeout(step.execute(context), step.timeout, step.id) : await step.execute(context);
255
+ return run;
256
+ } catch (e) {
257
+ lastErr = e;
258
+ }
259
+ }
260
+ throw lastErr;
261
+ }
262
+ _emit(run) {
263
+ this._runStatus$.next({ ...run });
264
+ }
265
+ };
266
+ function _withTimeout(promise, ms, id) {
267
+ return new Promise((resolve, reject) => {
268
+ const timer = setTimeout(() => reject(new Error(`Step '${id}' timed out after ${ms}ms`)), ms);
269
+ promise.then((v) => {
270
+ clearTimeout(timer);
271
+ resolve(v);
272
+ }, (e) => {
273
+ clearTimeout(timer);
274
+ reject(e);
275
+ });
276
+ });
277
+ }
278
+
279
+ exports.JoopStateMachine = JoopStateMachine;
280
+ exports.JoopWorkflowEngine = JoopWorkflowEngine;
281
+ //# sourceMappingURL=index.js.map
282
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,279 @@
1
+ // src/events/index.ts
2
+ var JoopSubject = class {
3
+ _listeners = [];
4
+ subscribe(listener) {
5
+ this._listeners.push(listener);
6
+ return () => {
7
+ this._listeners = this._listeners.filter((l) => l !== listener);
8
+ };
9
+ }
10
+ next(value) {
11
+ for (const listener of this._listeners) {
12
+ listener(value);
13
+ }
14
+ }
15
+ asObservable() {
16
+ return new JoopObservable((listener) => this.subscribe(listener));
17
+ }
18
+ };
19
+ var JoopBehaviorSubject = class extends JoopSubject {
20
+ _value;
21
+ constructor(initialValue) {
22
+ super();
23
+ this._value = initialValue;
24
+ }
25
+ getValue() {
26
+ return this._value;
27
+ }
28
+ next(value) {
29
+ this._value = value;
30
+ super.next(value);
31
+ }
32
+ subscribe(listener) {
33
+ listener(this._value);
34
+ return super.subscribe(listener);
35
+ }
36
+ asObservable() {
37
+ return new JoopObservable((listener) => this.subscribe(listener));
38
+ }
39
+ };
40
+ var JoopObservable = class {
41
+ constructor(_subscribeFn) {
42
+ this._subscribeFn = _subscribeFn;
43
+ }
44
+ _subscribeFn;
45
+ subscribe(listener) {
46
+ return this._subscribeFn(listener);
47
+ }
48
+ /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */
49
+ getOnce() {
50
+ let result;
51
+ const unsub = this.subscribe((v) => {
52
+ result = v;
53
+ });
54
+ unsub();
55
+ return result;
56
+ }
57
+ };
58
+
59
+ // src/workflow/state-machine.ts
60
+ var JoopStateMachine = class {
61
+ _state$;
62
+ _transition$ = new JoopSubject();
63
+ _cfg;
64
+ _history = [];
65
+ _context;
66
+ constructor(config) {
67
+ this._cfg = config;
68
+ this._context = config.context;
69
+ this._state$ = new JoopBehaviorSubject(config.initial);
70
+ this._cfg.states[config.initial]?.onEnter?.(this._context);
71
+ }
72
+ getState() {
73
+ return this._state$.getValue();
74
+ }
75
+ getContext() {
76
+ return this._context;
77
+ }
78
+ state$() {
79
+ return this._state$.asObservable();
80
+ }
81
+ transition$() {
82
+ return this._transition$.asObservable();
83
+ }
84
+ history() {
85
+ return [...this._history];
86
+ }
87
+ matches(state) {
88
+ return this._state$.getValue() === state;
89
+ }
90
+ isFinal() {
91
+ return this._cfg.states[this.getState()]?.type === "final";
92
+ }
93
+ /** Returns true if the event can be sent from current state */
94
+ can(event) {
95
+ const cfg = this._cfg.states[this.getState()]?.on;
96
+ if (!cfg || !(event in cfg)) return false;
97
+ const t = this._resolveTransition(this.getState(), event);
98
+ return t !== null;
99
+ }
100
+ /** Send an event; returns true if a transition occurred */
101
+ send(event, context) {
102
+ const from = this.getState();
103
+ const stateCfg = this._cfg.states[from];
104
+ if (!stateCfg?.on || !(event in stateCfg.on)) return false;
105
+ const t = this._resolveTransition(from, event, context);
106
+ if (!t) return false;
107
+ const to = t.target;
108
+ stateCfg.onExit?.(this._context);
109
+ t.action?.(this._context);
110
+ if (context !== void 0) this._context = context;
111
+ const record = { from, event, to, timestamp: Date.now() };
112
+ this._history.push(record);
113
+ this._state$.next(to);
114
+ this._transition$.next(record);
115
+ this._cfg.states[to]?.onEnter?.(this._context);
116
+ return true;
117
+ }
118
+ /** Update context without triggering a transition */
119
+ setContext(ctx) {
120
+ this._context = ctx;
121
+ }
122
+ reset() {
123
+ const initial = this._cfg.initial;
124
+ this._state$.next(initial);
125
+ this._history = [];
126
+ this._cfg.states[initial]?.onEnter?.(this._context);
127
+ }
128
+ /** Export as Mermaid state diagram */
129
+ toMermaid() {
130
+ const lines = ["stateDiagram-v2"];
131
+ lines.push(` [*] --> ${this._cfg.initial}`);
132
+ for (const [state, cfg] of Object.entries(this._cfg.states)) {
133
+ if (cfg.type === "final") lines.push(` ${state} --> [*]`);
134
+ if (cfg.on) {
135
+ for (const [event, trans] of Object.entries(cfg.on)) {
136
+ const target = typeof trans === "string" ? trans : trans.target;
137
+ lines.push(` ${state} --> ${target} : ${event}`);
138
+ }
139
+ }
140
+ }
141
+ return lines.join("\n");
142
+ }
143
+ _resolveTransition(from, event, context) {
144
+ const rawTrans = this._cfg.states[from]?.on?.[event];
145
+ if (!rawTrans) return null;
146
+ const t = typeof rawTrans === "string" ? { target: rawTrans } : rawTrans;
147
+ if (t.guard && !t.guard(context ?? this._context)) return null;
148
+ return t;
149
+ }
150
+ };
151
+
152
+ // src/workflow/workflow-engine.ts
153
+ var JoopWorkflowEngine = class {
154
+ _definitions = /* @__PURE__ */ new Map();
155
+ _runs = /* @__PURE__ */ new Map();
156
+ _runStatus$ = new JoopSubject();
157
+ _cancellations = /* @__PURE__ */ new Set();
158
+ define(workflow) {
159
+ this._definitions.set(workflow.id, workflow);
160
+ }
161
+ undefine(id) {
162
+ this._definitions.delete(id);
163
+ }
164
+ async run(workflowId, input = null) {
165
+ const def = this._definitions.get(workflowId);
166
+ if (!def) throw new Error(`JoopWorkflowEngine: unknown workflow '${workflowId}'`);
167
+ const runId = `${workflowId}_${Date.now()}_${Math.floor(Math.random() * 1e3)}`;
168
+ const run = {
169
+ runId,
170
+ workflowId,
171
+ status: "running",
172
+ input,
173
+ outputs: {},
174
+ errors: {},
175
+ startedAt: Date.now()
176
+ };
177
+ this._runs.set(runId, run);
178
+ this._emit(run);
179
+ const completed = /* @__PURE__ */ new Set();
180
+ const context = { input, outputs: run.outputs };
181
+ const remaining = [...def.steps];
182
+ const executedSteps = [];
183
+ while (remaining.length > 0) {
184
+ if (this._cancellations.has(runId)) {
185
+ run.status = "cancelled";
186
+ this._emit(run);
187
+ break;
188
+ }
189
+ const ready = remaining.filter((s) => (s.after ?? []).every((dep) => completed.has(dep)));
190
+ if (ready.length === 0 && remaining.length > 0) throw new Error(`Workflow deadlock in '${workflowId}': circular/missing dependencies`);
191
+ const results = await Promise.allSettled(ready.map((s) => this._runStep(s, context, runId)));
192
+ for (let i = 0; i < ready.length; i++) {
193
+ const step = ready[i];
194
+ const result = results[i];
195
+ remaining.splice(remaining.indexOf(step), 1);
196
+ if (result.status === "fulfilled") {
197
+ run.outputs[step.id] = result.value;
198
+ context.outputs = run.outputs;
199
+ completed.add(step.id);
200
+ executedSteps.push(step);
201
+ } else {
202
+ run.errors[step.id] = String(result.reason);
203
+ run.status = "failed";
204
+ break;
205
+ }
206
+ }
207
+ if (run.status === "failed") break;
208
+ }
209
+ if (run.status === "failed") {
210
+ run.status = "compensating";
211
+ this._emit(run);
212
+ for (const step of [...executedSteps].reverse()) {
213
+ if (step.compensate) {
214
+ try {
215
+ await step.compensate(context);
216
+ } catch {
217
+ }
218
+ }
219
+ }
220
+ } else if (run.status === "running") {
221
+ run.status = "completed";
222
+ }
223
+ run.completedAt = Date.now();
224
+ this._emit(run);
225
+ this._cancellations.delete(runId);
226
+ return {
227
+ runId,
228
+ status: run.status === "completed" ? "completed" : "failed",
229
+ outputs: run.outputs,
230
+ errors: run.errors,
231
+ durationMs: run.completedAt - run.startedAt
232
+ };
233
+ }
234
+ cancel(runId) {
235
+ this._cancellations.add(runId);
236
+ }
237
+ status(runId) {
238
+ return this._runs.get(runId);
239
+ }
240
+ history() {
241
+ return Array.from(this._runs.values());
242
+ }
243
+ runStatus$() {
244
+ return this._runStatus$.asObservable();
245
+ }
246
+ async _runStep(step, context, runId) {
247
+ const maxAttempts = (step.retries ?? 0) + 1;
248
+ let lastErr;
249
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
250
+ if (this._cancellations.has(runId)) throw new Error("Cancelled");
251
+ try {
252
+ const run = step.timeout ? await _withTimeout(step.execute(context), step.timeout, step.id) : await step.execute(context);
253
+ return run;
254
+ } catch (e) {
255
+ lastErr = e;
256
+ }
257
+ }
258
+ throw lastErr;
259
+ }
260
+ _emit(run) {
261
+ this._runStatus$.next({ ...run });
262
+ }
263
+ };
264
+ function _withTimeout(promise, ms, id) {
265
+ return new Promise((resolve, reject) => {
266
+ const timer = setTimeout(() => reject(new Error(`Step '${id}' timed out after ${ms}ms`)), ms);
267
+ promise.then((v) => {
268
+ clearTimeout(timer);
269
+ resolve(v);
270
+ }, (e) => {
271
+ clearTimeout(timer);
272
+ reject(e);
273
+ });
274
+ });
275
+ }
276
+
277
+ export { JoopStateMachine, JoopWorkflowEngine };
278
+ //# sourceMappingURL=index.mjs.map
279
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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"]}