actly 1.1.0 → 1.2.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 (130) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +262 -232
  3. package/dist/core/act.cjs +505 -39
  4. package/dist/core/act.d.ts +81 -10
  5. package/dist/core/act.d.ts.map +1 -1
  6. package/dist/core/act.js +504 -40
  7. package/dist/core/act.js.map +1 -1
  8. package/dist/core/executor.cjs +21 -9
  9. package/dist/core/executor.d.ts +31 -6
  10. package/dist/core/executor.d.ts.map +1 -1
  11. package/dist/core/executor.js +21 -9
  12. package/dist/core/executor.js.map +1 -1
  13. package/dist/core/health.cjs +34 -0
  14. package/dist/core/health.d.ts +18 -0
  15. package/dist/core/health.d.ts.map +1 -0
  16. package/dist/core/health.js +28 -0
  17. package/dist/core/health.js.map +1 -0
  18. package/dist/core/shutdown.cjs +60 -0
  19. package/dist/core/shutdown.d.ts +8 -0
  20. package/dist/core/shutdown.d.ts.map +1 -0
  21. package/dist/core/shutdown.js +56 -0
  22. package/dist/core/shutdown.js.map +1 -0
  23. package/dist/core/tenant.cjs +71 -0
  24. package/dist/core/tenant.d.ts +29 -0
  25. package/dist/core/tenant.d.ts.map +1 -0
  26. package/dist/core/tenant.js +68 -0
  27. package/dist/core/tenant.js.map +1 -0
  28. package/dist/errors.cjs +182 -0
  29. package/dist/errors.d.ts +151 -0
  30. package/dist/errors.d.ts.map +1 -0
  31. package/dist/errors.js +171 -0
  32. package/dist/errors.js.map +1 -0
  33. package/dist/index.cjs +56 -6
  34. package/dist/index.d.ts +22 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +24 -4
  37. package/dist/index.js.map +1 -1
  38. package/dist/observability.cjs +45 -0
  39. package/dist/observability.d.ts +145 -0
  40. package/dist/observability.d.ts.map +1 -0
  41. package/dist/observability.js +43 -0
  42. package/dist/observability.js.map +1 -0
  43. package/dist/policies/bulkhead.cjs +97 -0
  44. package/dist/policies/bulkhead.d.ts +3 -0
  45. package/dist/policies/bulkhead.d.ts.map +1 -0
  46. package/dist/policies/bulkhead.js +95 -0
  47. package/dist/policies/bulkhead.js.map +1 -0
  48. package/dist/policies/cache.cjs +223 -22
  49. package/dist/policies/cache.d.ts +42 -7
  50. package/dist/policies/cache.d.ts.map +1 -1
  51. package/dist/policies/cache.js +223 -22
  52. package/dist/policies/cache.js.map +1 -1
  53. package/dist/policies/circuitBreaker.cjs +85 -0
  54. package/dist/policies/circuitBreaker.d.ts +3 -0
  55. package/dist/policies/circuitBreaker.d.ts.map +1 -0
  56. package/dist/policies/circuitBreaker.js +83 -0
  57. package/dist/policies/circuitBreaker.js.map +1 -0
  58. package/dist/policies/dedupe.cjs +98 -21
  59. package/dist/policies/dedupe.d.ts +20 -13
  60. package/dist/policies/dedupe.d.ts.map +1 -1
  61. package/dist/policies/dedupe.js +98 -21
  62. package/dist/policies/dedupe.js.map +1 -1
  63. package/dist/policies/rateLimit.cjs +35 -0
  64. package/dist/policies/rateLimit.d.ts +3 -0
  65. package/dist/policies/rateLimit.d.ts.map +1 -0
  66. package/dist/policies/rateLimit.js +33 -0
  67. package/dist/policies/rateLimit.js.map +1 -0
  68. package/dist/policies/retry.cjs +103 -26
  69. package/dist/policies/retry.d.ts +25 -2
  70. package/dist/policies/retry.d.ts.map +1 -1
  71. package/dist/policies/retry.js +103 -26
  72. package/dist/policies/retry.js.map +1 -1
  73. package/dist/policies/timeout.cjs +78 -36
  74. package/dist/policies/timeout.d.ts +7 -18
  75. package/dist/policies/timeout.d.ts.map +1 -1
  76. package/dist/policies/timeout.js +84 -31
  77. package/dist/policies/timeout.js.map +1 -1
  78. package/dist/state/store.cjs +9 -2
  79. package/dist/state/store.d.ts +9 -0
  80. package/dist/state/store.d.ts.map +1 -1
  81. package/dist/state/store.js +9 -2
  82. package/dist/state/store.js.map +1 -1
  83. package/dist/stores/base.cjs +4 -4
  84. package/dist/stores/base.d.ts +32 -56
  85. package/dist/stores/base.d.ts.map +1 -1
  86. package/dist/stores/base.js +4 -4
  87. package/dist/stores/base.js.map +1 -1
  88. package/dist/stores/memory.cjs +161 -39
  89. package/dist/stores/memory.d.ts +64 -24
  90. package/dist/stores/memory.d.ts.map +1 -1
  91. package/dist/stores/memory.js +160 -39
  92. package/dist/stores/memory.js.map +1 -1
  93. package/dist/types/index.d.ts +315 -37
  94. package/dist/types/index.d.ts.map +1 -1
  95. package/dist/utils/abort.cjs +212 -0
  96. package/dist/utils/abort.d.ts +79 -0
  97. package/dist/utils/abort.d.ts.map +1 -0
  98. package/dist/utils/abort.js +206 -0
  99. package/dist/utils/abort.js.map +1 -0
  100. package/dist/utils/abortPool.cjs +26 -0
  101. package/dist/utils/abortPool.d.ts +4 -0
  102. package/dist/utils/abortPool.d.ts.map +1 -0
  103. package/dist/utils/abortPool.js +22 -0
  104. package/dist/utils/abortPool.js.map +1 -0
  105. package/dist/utils/backoff.cjs +54 -0
  106. package/dist/utils/backoff.d.ts +14 -0
  107. package/dist/utils/backoff.d.ts.map +1 -0
  108. package/dist/utils/backoff.js +52 -0
  109. package/dist/utils/backoff.js.map +1 -0
  110. package/dist/utils/key.cjs +77 -0
  111. package/dist/utils/key.d.ts +29 -0
  112. package/dist/utils/key.d.ts.map +1 -0
  113. package/dist/utils/key.js +75 -0
  114. package/dist/utils/key.js.map +1 -0
  115. package/dist/utils/limits.cjs +40 -0
  116. package/dist/utils/limits.d.ts +39 -0
  117. package/dist/utils/limits.d.ts.map +1 -0
  118. package/dist/utils/limits.js +38 -0
  119. package/dist/utils/limits.js.map +1 -0
  120. package/dist/utils/sanitize.cjs +29 -0
  121. package/dist/utils/sanitize.d.ts +3 -0
  122. package/dist/utils/sanitize.d.ts.map +1 -0
  123. package/dist/utils/sanitize.js +26 -0
  124. package/dist/utils/sanitize.js.map +1 -0
  125. package/dist/utils/validate.cjs +153 -0
  126. package/dist/utils/validate.d.ts +26 -0
  127. package/dist/utils/validate.d.ts.map +1 -0
  128. package/dist/utils/validate.js +141 -0
  129. package/dist/utils/validate.js.map +1 -0
  130. package/package.json +20 -37
@@ -3,22 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.REQUIRES_SYNC_STORE = void 0;
4
4
  exports.execute = execute;
5
5
  const base_js_1 = require("../stores/base.js");
6
- // Symbol stamped onto PolicyApplier functions by dedupePolicy.
7
- // Lets execute() detect a dedupe policy without importing the policy module
8
- // (which would create a circular dep) or doing fragile name-sniffing.
6
+ /**
7
+ * Symbol stamped onto `PolicyApplier` functions by `dedupePolicy`.
8
+ *
9
+ * Lets `execute()` detect a dedupe policy without importing the policy
10
+ * module (which would create a circular dep) or doing fragile name-sniffing.
11
+ */
9
12
  exports.REQUIRES_SYNC_STORE = Symbol('actly.requiresSyncStore');
10
13
  /**
11
14
  * Pure execution engine.
12
15
  *
13
- * This file imports nothing from /policies.
14
- * It operates on PolicyApplier<T> — a type alias defined in /types.
15
- * Policy implementations live in /policies and are wired in core/act.ts.
16
+ * This file imports nothing from `/policies`. It operates on `PolicyApplier<T>`
17
+ * — a type alias defined in `/types`. Policy implementations live in
18
+ * `/policies` and are wired in `core/act.ts`.
19
+ *
20
+ * # Public API
21
+ *
22
+ * Exported so consumers can build custom policy chains with explicit stores
23
+ * (e.g. for SSR request isolation or multi-tenant scenarios where the
24
+ * module-level default store is wrong).
16
25
  */
17
26
  async function execute(input) {
18
27
  // Guard: if any policy in the chain requires a sync store, the provided
19
28
  // store must be synchronous. An async store + dedupePolicy is a silent
20
- // correctness failure, not just a performance issue catch it here rather
21
- // than letting it produce subtly wrong dedupe behaviour at runtime.
29
+ // correctness failure catch it here rather than letting it produce
30
+ // subtly wrong dedupe behaviour at runtime.
22
31
  const needsSync = input.policies.some(p => p[exports.REQUIRES_SYNC_STORE]);
23
32
  if (needsSync && !(0, base_js_1.isSyncStore)(input.store)) {
24
33
  throw new Error('Actly: dedupePolicy requires a SyncStateStore (store._sync === true). ' +
@@ -29,9 +38,12 @@ async function execute(input) {
29
38
  key: input.key,
30
39
  store: input.store,
31
40
  meta: input.meta,
41
+ // Thread observability through. Policies read this lazily.
42
+ observability: input.observability,
32
43
  };
33
44
  // Build the call chain from inside out.
34
45
  // reduceRight ensures policies[0] becomes the outermost wrapper (runs first).
35
46
  const wrapped = input.policies.reduceRight((inner, applyPolicy) => applyPolicy(inner, ctx), input.fn);
36
- return wrapped();
47
+ // Call the outermost wrapper with the root signal.
48
+ return wrapped(input.signal);
37
49
  }
@@ -1,13 +1,19 @@
1
- import type { ActFn, PolicyApplier, AnyStateStore, RunMeta } from '../types/index.js';
1
+ import type { ActFn, PolicyApplier, AnyStateStore, RunMeta, ObservabilityContext } from '../types/index.js';
2
+ /**
3
+ * Symbol stamped onto `PolicyApplier` functions by `dedupePolicy`.
4
+ *
5
+ * Lets `execute()` detect a dedupe policy without importing the policy
6
+ * module (which would create a circular dep) or doing fragile name-sniffing.
7
+ */
2
8
  export declare const REQUIRES_SYNC_STORE: unique symbol;
3
9
  export interface ExecutorInput<T> {
4
10
  key: string;
5
11
  fn: ActFn<T>;
6
12
  /**
7
13
  * Policies ordered outermost -> innermost.
8
- * policies[0] intercepts first; policies[last] is closest to fn.
14
+ * `policies[0]` intercepts first; `policies[last]` is closest to `fn`.
9
15
  *
10
- * Canonical order: [totalTimeout, cache, dedupe, retry, timeout]
16
+ * Canonical order: `[totalTimeout, cache, dedupe, retry, timeout]`
11
17
  * totalTimeout -> hard wall-clock budget over the entire operation
12
18
  * cache -> a hit skips everything below it
13
19
  * dedupe -> collapses concurrent callers before retry fires
@@ -17,13 +23,32 @@ export interface ExecutorInput<T> {
17
23
  policies: ReadonlyArray<PolicyApplier<T>>;
18
24
  store: AnyStateStore;
19
25
  meta: RunMeta;
26
+ /**
27
+ * Root AbortSignal for the operation. Propagated inward through the
28
+ * policy chain: each policy receives it as the `signal` argument to
29
+ * its wrapped `ActFn`. The outermost policy may layer its own signal
30
+ * (e.g. `totalTimeoutPolicy` arms a timer) and pass the composite
31
+ * inward.
32
+ */
33
+ signal: AbortSignal;
34
+ /**
35
+ * Observability context. When present, policies emit events
36
+ * via the hooks. When absent (the common case), zero overhead.
37
+ */
38
+ observability?: ObservabilityContext;
20
39
  }
21
40
  /**
22
41
  * Pure execution engine.
23
42
  *
24
- * This file imports nothing from /policies.
25
- * It operates on PolicyApplier<T> — a type alias defined in /types.
26
- * Policy implementations live in /policies and are wired in core/act.ts.
43
+ * This file imports nothing from `/policies`. It operates on `PolicyApplier<T>`
44
+ * — a type alias defined in `/types`. Policy implementations live in
45
+ * `/policies` and are wired in `core/act.ts`.
46
+ *
47
+ * # Public API
48
+ *
49
+ * Exported so consumers can build custom policy chains with explicit stores
50
+ * (e.g. for SSR request isolation or multi-tenant scenarios where the
51
+ * module-level default store is wrong).
27
52
  */
28
53
  export declare function execute<T>(input: ExecutorInput<T>): Promise<T>;
29
54
  //# sourceMappingURL=executor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,aAAa,EAEb,aAAa,EACb,OAAO,EACR,MAAM,mBAAmB,CAAA;AAM1B,eAAO,MAAM,mBAAmB,eAAoC,CAAA;AAEpE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,GAAG,EAAO,MAAM,CAAA;IAChB,EAAE,EAAQ,KAAK,CAAC,CAAC,CAAC,CAAA;IAClB;;;;;;;;;;OAUG;IACH,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACzC,KAAK,EAAK,aAAa,CAAA;IACvB,IAAI,EAAM,OAAO,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA8BpE"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,aAAa,EAEb,aAAa,EACb,OAAO,EACP,oBAAoB,EACrB,MAAM,mBAAmB,CAAA;AAG1B;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,eAAoC,CAAA;AAEpE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,GAAG,EAAO,MAAM,CAAA;IAChB,EAAE,EAAQ,KAAK,CAAC,CAAC,CAAC,CAAA;IAClB;;;;;;;;;;OAUG;IACH,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACzC,KAAK,EAAK,aAAa,CAAA;IACvB,IAAI,EAAM,OAAO,CAAA;IACjB;;;;;;OAMG;IACH,MAAM,EAAI,WAAW,CAAA;IACrB;;;OAGG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAA;CACrC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAiCpE"}
@@ -1,20 +1,29 @@
1
1
  import { isSyncStore } from '../stores/base.js';
2
- // Symbol stamped onto PolicyApplier functions by dedupePolicy.
3
- // Lets execute() detect a dedupe policy without importing the policy module
4
- // (which would create a circular dep) or doing fragile name-sniffing.
2
+ /**
3
+ * Symbol stamped onto `PolicyApplier` functions by `dedupePolicy`.
4
+ *
5
+ * Lets `execute()` detect a dedupe policy without importing the policy
6
+ * module (which would create a circular dep) or doing fragile name-sniffing.
7
+ */
5
8
  export const REQUIRES_SYNC_STORE = Symbol('actly.requiresSyncStore');
6
9
  /**
7
10
  * Pure execution engine.
8
11
  *
9
- * This file imports nothing from /policies.
10
- * It operates on PolicyApplier<T> — a type alias defined in /types.
11
- * Policy implementations live in /policies and are wired in core/act.ts.
12
+ * This file imports nothing from `/policies`. It operates on `PolicyApplier<T>`
13
+ * — a type alias defined in `/types`. Policy implementations live in
14
+ * `/policies` and are wired in `core/act.ts`.
15
+ *
16
+ * # Public API
17
+ *
18
+ * Exported so consumers can build custom policy chains with explicit stores
19
+ * (e.g. for SSR request isolation or multi-tenant scenarios where the
20
+ * module-level default store is wrong).
12
21
  */
13
22
  export async function execute(input) {
14
23
  // Guard: if any policy in the chain requires a sync store, the provided
15
24
  // store must be synchronous. An async store + dedupePolicy is a silent
16
- // correctness failure, not just a performance issue catch it here rather
17
- // than letting it produce subtly wrong dedupe behaviour at runtime.
25
+ // correctness failure catch it here rather than letting it produce
26
+ // subtly wrong dedupe behaviour at runtime.
18
27
  const needsSync = input.policies.some(p => p[REQUIRES_SYNC_STORE]);
19
28
  if (needsSync && !isSyncStore(input.store)) {
20
29
  throw new Error('Actly: dedupePolicy requires a SyncStateStore (store._sync === true). ' +
@@ -25,10 +34,13 @@ export async function execute(input) {
25
34
  key: input.key,
26
35
  store: input.store,
27
36
  meta: input.meta,
37
+ // Thread observability through. Policies read this lazily.
38
+ observability: input.observability,
28
39
  };
29
40
  // Build the call chain from inside out.
30
41
  // reduceRight ensures policies[0] becomes the outermost wrapper (runs first).
31
42
  const wrapped = input.policies.reduceRight((inner, applyPolicy) => applyPolicy(inner, ctx), input.fn);
32
- return wrapped();
43
+ // Call the outermost wrapper with the root signal.
44
+ return wrapped(input.signal);
33
45
  }
34
46
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,+DAA+D;AAC/D,4EAA4E;AAC5E,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAA;AAqBpE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAI,KAAuB;IACtD,wEAAwE;IACxE,uEAAuE;IACvE,2EAA2E;IAC3E,oEAAoE;IACpE,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,CAAE,CAA4D,CAAC,mBAAmB,CAAC,CACxF,CAAA;IACD,IAAI,SAAS,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,wEAAwE;YACxE,uDAAuD;YACvD,kEAAkE,CACnE,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAkB;QACzB,GAAG,EAAI,KAAK,CAAC,GAAG;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAG,KAAK,CAAC,IAAI;KAClB,CAAA;IAED,wCAAwC;IACxC,8EAA8E;IAC9E,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CACxC,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,EAC/C,KAAK,CAAC,EAAE,CACT,CAAA;IAED,OAAO,OAAO,EAAE,CAAA;AAClB,CAAC"}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAA;AAkCpE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAI,KAAuB;IACtD,wEAAwE;IACxE,uEAAuE;IACvE,qEAAqE;IACrE,4CAA4C;IAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,CAAE,CAA4D,CAAC,mBAAmB,CAAC,CACxF,CAAA;IACD,IAAI,SAAS,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,wEAAwE;YACxE,uDAAuD;YACvD,kEAAkE,CACnE,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAkB;QACzB,GAAG,EAAI,KAAK,CAAC,GAAG;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAG,KAAK,CAAC,IAAI;QACjB,2DAA2D;QAC3D,aAAa,EAAE,KAAK,CAAC,aAAa;KACnC,CAAA;IAED,wCAAwC;IACxC,8EAA8E;IAC9E,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CACxC,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,EAC/C,KAAK,CAAC,EAAE,CACT,CAAA;IAED,mDAAmD;IACnD,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;AAC9B,CAAC"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerInflight = registerInflight;
4
+ exports.unregisterInflight = unregisterInflight;
5
+ exports.recordError = recordError;
6
+ exports.recordSuccess = recordSuccess;
7
+ exports.createHealthCheck = createHealthCheck;
8
+ let globalInflight = 0;
9
+ let startTime = Date.now();
10
+ let globalLastError;
11
+ let globalLastSuccessAt;
12
+ function registerInflight(_scope) {
13
+ globalInflight++;
14
+ }
15
+ function unregisterInflight(_scope) {
16
+ globalInflight = Math.max(0, globalInflight - 1);
17
+ }
18
+ function recordError(_scope, code, message) {
19
+ globalLastError = { code, message, timestamp: Date.now() };
20
+ }
21
+ function recordSuccess(_scope) {
22
+ globalLastSuccessAt = Date.now();
23
+ }
24
+ function createHealthCheck(store) {
25
+ return () => {
26
+ return {
27
+ storeSize: store.size(),
28
+ pendingInflight: globalInflight,
29
+ uptimeMs: Date.now() - startTime,
30
+ lastError: globalLastError,
31
+ lastSuccessAt: globalLastSuccessAt,
32
+ };
33
+ };
34
+ }
@@ -0,0 +1,18 @@
1
+ import type { InMemoryStore } from '../stores/memory.js';
2
+ export interface HealthStatus {
3
+ storeSize: number;
4
+ pendingInflight: number;
5
+ uptimeMs: number;
6
+ lastError?: {
7
+ code: string;
8
+ message: string;
9
+ timestamp: number;
10
+ };
11
+ lastSuccessAt?: number;
12
+ }
13
+ export declare function registerInflight(_scope: string): void;
14
+ export declare function unregisterInflight(_scope: string): void;
15
+ export declare function recordError(_scope: string, code: string, message: string): void;
16
+ export declare function recordSuccess(_scope: string): void;
17
+ export declare function createHealthCheck(store: InMemoryStore): () => HealthStatus;
18
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAChE,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAOD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAErD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/E;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,YAAY,CAU1E"}
@@ -0,0 +1,28 @@
1
+ let globalInflight = 0;
2
+ let startTime = Date.now();
3
+ let globalLastError;
4
+ let globalLastSuccessAt;
5
+ export function registerInflight(_scope) {
6
+ globalInflight++;
7
+ }
8
+ export function unregisterInflight(_scope) {
9
+ globalInflight = Math.max(0, globalInflight - 1);
10
+ }
11
+ export function recordError(_scope, code, message) {
12
+ globalLastError = { code, message, timestamp: Date.now() };
13
+ }
14
+ export function recordSuccess(_scope) {
15
+ globalLastSuccessAt = Date.now();
16
+ }
17
+ export function createHealthCheck(store) {
18
+ return () => {
19
+ return {
20
+ storeSize: store.size(),
21
+ pendingInflight: globalInflight,
22
+ uptimeMs: Date.now() - startTime,
23
+ lastError: globalLastError,
24
+ lastSuccessAt: globalLastSuccessAt,
25
+ };
26
+ };
27
+ }
28
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"AAUA,IAAI,cAAc,GAAG,CAAC,CAAA;AACtB,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;AAC1B,IAAI,eAAiF,CAAA;AACrF,IAAI,mBAAuC,CAAA;AAE3C,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,cAAc,EAAE,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,IAAY,EAAE,OAAe;IACvE,eAAe,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;AAC5D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,mBAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAoB;IACpD,OAAO,GAAG,EAAE;QACV,OAAO;YACL,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE;YACvB,eAAe,EAAE,cAAc;YAC/B,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,SAAS,EAAE,eAAe;YAC1B,aAAa,EAAE,mBAAmB;SACnC,CAAA;IACH,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerDrainable = registerDrainable;
4
+ exports.unregisterDrainable = unregisterDrainable;
5
+ exports.drain = drain;
6
+ const drainStates = new Map();
7
+ function getState(scope) {
8
+ let s = drainStates.get(scope);
9
+ if (!s) {
10
+ s = { inflight: 0, resolvers: [] };
11
+ drainStates.set(scope, s);
12
+ }
13
+ return s;
14
+ }
15
+ function registerDrainable(scope = 'default') {
16
+ getState(scope).inflight++;
17
+ }
18
+ function unregisterDrainable(scope = 'default') {
19
+ const s = getState(scope);
20
+ s.inflight = Math.max(0, s.inflight - 1);
21
+ if (s.inflight === 0) {
22
+ for (const r of s.resolvers)
23
+ r();
24
+ s.resolvers = [];
25
+ }
26
+ }
27
+ /**
28
+ * Wait for all in-flight act() calls in this scope to settle.
29
+ * Returns true if all settled within timeoutMs, false if timed out.
30
+ */
31
+ async function drain(timeoutMs, scope = 'default') {
32
+ const s = getState(scope);
33
+ if (s.inflight === 0)
34
+ return true;
35
+ return new Promise((resolve) => {
36
+ let resolved = false;
37
+ const resolver = () => {
38
+ if (resolved)
39
+ return;
40
+ resolved = true;
41
+ clearTimeout(timer);
42
+ // Remove this resolver from the array
43
+ const idx = s.resolvers.indexOf(resolver);
44
+ if (idx >= 0)
45
+ s.resolvers.splice(idx, 1);
46
+ resolve(true);
47
+ };
48
+ const timer = setTimeout(() => {
49
+ if (resolved)
50
+ return;
51
+ resolved = true;
52
+ // Remove this resolver from the array on timeout
53
+ const idx = s.resolvers.indexOf(resolver);
54
+ if (idx >= 0)
55
+ s.resolvers.splice(idx, 1);
56
+ resolve(false);
57
+ }, timeoutMs);
58
+ s.resolvers.push(resolver);
59
+ });
60
+ }
@@ -0,0 +1,8 @@
1
+ export declare function registerDrainable(scope?: string): void;
2
+ export declare function unregisterDrainable(scope?: string): void;
3
+ /**
4
+ * Wait for all in-flight act() calls in this scope to settle.
5
+ * Returns true if all settled within timeoutMs, false if timed out.
6
+ */
7
+ export declare function drain(timeoutMs: number, scope?: string): Promise<boolean>;
8
+ //# sourceMappingURL=shutdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/core/shutdown.ts"],"names":[],"mappings":"AAaA,wBAAgB,iBAAiB,CAAC,KAAK,SAAY,GAAG,IAAI,CAEzD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,SAAY,GAAG,IAAI,CAO3D;AAED;;;GAGG;AACH,wBAAsB,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,SAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BlF"}
@@ -0,0 +1,56 @@
1
+ const drainStates = new Map();
2
+ function getState(scope) {
3
+ let s = drainStates.get(scope);
4
+ if (!s) {
5
+ s = { inflight: 0, resolvers: [] };
6
+ drainStates.set(scope, s);
7
+ }
8
+ return s;
9
+ }
10
+ export function registerDrainable(scope = 'default') {
11
+ getState(scope).inflight++;
12
+ }
13
+ export function unregisterDrainable(scope = 'default') {
14
+ const s = getState(scope);
15
+ s.inflight = Math.max(0, s.inflight - 1);
16
+ if (s.inflight === 0) {
17
+ for (const r of s.resolvers)
18
+ r();
19
+ s.resolvers = [];
20
+ }
21
+ }
22
+ /**
23
+ * Wait for all in-flight act() calls in this scope to settle.
24
+ * Returns true if all settled within timeoutMs, false if timed out.
25
+ */
26
+ export async function drain(timeoutMs, scope = 'default') {
27
+ const s = getState(scope);
28
+ if (s.inflight === 0)
29
+ return true;
30
+ return new Promise((resolve) => {
31
+ let resolved = false;
32
+ const resolver = () => {
33
+ if (resolved)
34
+ return;
35
+ resolved = true;
36
+ clearTimeout(timer);
37
+ // Remove this resolver from the array
38
+ const idx = s.resolvers.indexOf(resolver);
39
+ if (idx >= 0)
40
+ s.resolvers.splice(idx, 1);
41
+ resolve(true);
42
+ };
43
+ const timer = setTimeout(() => {
44
+ if (resolved)
45
+ return;
46
+ resolved = true;
47
+ // Remove this resolver from the array on timeout
48
+ const idx = s.resolvers.indexOf(resolver);
49
+ if (idx >= 0)
50
+ s.resolvers.splice(idx, 1);
51
+ resolve(false);
52
+ }, timeoutMs);
53
+ s.resolvers.push(resolver);
54
+ });
55
+ }
56
+ //# sourceMappingURL=shutdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../src/core/shutdown.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG,IAAI,GAAG,EAA8D,CAAA;AAEzF,SAAS,QAAQ,CAAC,KAAa;IAC7B,IAAI,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC9B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;QAClC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC3B,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAK,GAAG,SAAS;IACjD,QAAQ,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAA;AAC5B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAK,GAAG,SAAS;IACnD,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAA;IACxC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS;YAAE,CAAC,EAAE,CAAA;QAChC,CAAC,CAAC,SAAS,GAAG,EAAE,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,SAAiB,EAAE,KAAK,GAAG,SAAS;IAC9D,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEjC,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACtC,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,IAAI,QAAQ;gBAAE,OAAM;YACpB,QAAQ,GAAG,IAAI,CAAA;YACf,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,sCAAsC;YACtC,MAAM,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;YACzC,IAAI,GAAG,IAAI,CAAC;gBAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;YACxC,OAAO,CAAC,IAAI,CAAC,CAAA;QACf,CAAC,CAAA;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,QAAQ;gBAAE,OAAM;YACpB,QAAQ,GAAG,IAAI,CAAA;YACf,iDAAiD;YACjD,MAAM,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;YACzC,IAAI,GAAG,IAAI,CAAC;gBAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;YACxC,OAAO,CAAC,KAAK,CAAC,CAAA;QAChB,CAAC,EAAE,SAAS,CAAC,CAAA;QAEb,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTenantStore = createTenantStore;
4
+ exports.createAsyncTenantStore = createAsyncTenantStore;
5
+ const memory_js_1 = require("../stores/memory.js");
6
+ const act_js_1 = require("./act.js");
7
+ const limits_js_1 = require("../utils/limits.js");
8
+ /**
9
+ * Manages per-tenant stores for multi-tenant isolation.
10
+ * Each tenant gets its own InMemoryStore — cache/dedupe entries
11
+ * cannot leak across tenants.
12
+ */
13
+ function createTenantStore(options = {}) {
14
+ const maxSize = options.maxSize ?? limits_js_1.LIMITS.DEFAULT_STORE_MAX_SIZE;
15
+ const autoCleanup = options.autoCleanup ?? true;
16
+ const cleanupIntervalMs = options.cleanupIntervalMs ?? 60_000;
17
+ const tenants = new Map();
18
+ return {
19
+ get(tenantId) {
20
+ let entry = tenants.get(tenantId);
21
+ if (!entry) {
22
+ const store = new memory_js_1.InMemoryStore({ maxSize, autoCleanup, cleanupIntervalMs });
23
+ const scoped = (0, act_js_1.withStore)(store);
24
+ entry = { store, scoped };
25
+ tenants.set(tenantId, entry);
26
+ }
27
+ return entry.scoped;
28
+ },
29
+ evict(tenantId) {
30
+ const entry = tenants.get(tenantId);
31
+ if (entry) {
32
+ entry.store.destroy();
33
+ tenants.delete(tenantId);
34
+ }
35
+ },
36
+ size() {
37
+ return tenants.size;
38
+ },
39
+ destroy() {
40
+ for (const [, entry] of tenants) {
41
+ entry.store.destroy();
42
+ }
43
+ tenants.clear();
44
+ },
45
+ };
46
+ }
47
+ /**
48
+ * Async tenant manager for async stores (Redis, DynamoDB, etc).
49
+ * Each tenant gets its own store instance with prefixed keys.
50
+ */
51
+ function createAsyncTenantStore(storeFactory) {
52
+ const tenants = new Map();
53
+ return {
54
+ get(tenantId) {
55
+ let entry = tenants.get(tenantId);
56
+ if (!entry) {
57
+ const store = storeFactory(tenantId);
58
+ const scoped = (0, act_js_1.withStore)(store);
59
+ entry = { store, scoped };
60
+ tenants.set(tenantId, entry);
61
+ }
62
+ return entry.scoped;
63
+ },
64
+ evict(tenantId) {
65
+ tenants.delete(tenantId);
66
+ },
67
+ size() {
68
+ return tenants.size;
69
+ },
70
+ };
71
+ }
@@ -0,0 +1,29 @@
1
+ import type { ScopedActSync, ScopedActAsync } from './act.js';
2
+ import type { AsyncStateStore } from '../stores/base.js';
3
+ export interface TenantStoreOptions {
4
+ maxSize?: number;
5
+ autoCleanup?: boolean;
6
+ cleanupIntervalMs?: number;
7
+ }
8
+ export interface TenantManager {
9
+ get(tenantId: string): ScopedActSync | ScopedActAsync;
10
+ evict(tenantId: string): void;
11
+ size(): number;
12
+ destroy(): void;
13
+ }
14
+ /**
15
+ * Manages per-tenant stores for multi-tenant isolation.
16
+ * Each tenant gets its own InMemoryStore — cache/dedupe entries
17
+ * cannot leak across tenants.
18
+ */
19
+ export declare function createTenantStore(options?: TenantStoreOptions): TenantManager;
20
+ /**
21
+ * Async tenant manager for async stores (Redis, DynamoDB, etc).
22
+ * Each tenant gets its own store instance with prefixed keys.
23
+ */
24
+ export declare function createAsyncTenantStore(storeFactory: (tenantId: string) => AsyncStateStore): {
25
+ get: (tenantId: string) => ScopedActAsync;
26
+ evict: (tenantId: string) => void;
27
+ size: () => number;
28
+ };
29
+ //# sourceMappingURL=tenant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/core/tenant.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE7D,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAGxE,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,CAAA;IACrD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,IAAI,IAAI,MAAM,CAAA;IACd,OAAO,IAAI,IAAI,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,aAAa,CAsCjF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,eAAe,GAClD;IACD,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,cAAc,CAAA;IACzC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,IAAI,EAAE,MAAM,MAAM,CAAA;CACnB,CAuBA"}
@@ -0,0 +1,68 @@
1
+ import { InMemoryStore } from '../stores/memory.js';
2
+ import { withStore } from './act.js';
3
+ import { LIMITS } from '../utils/limits.js';
4
+ /**
5
+ * Manages per-tenant stores for multi-tenant isolation.
6
+ * Each tenant gets its own InMemoryStore — cache/dedupe entries
7
+ * cannot leak across tenants.
8
+ */
9
+ export function createTenantStore(options = {}) {
10
+ const maxSize = options.maxSize ?? LIMITS.DEFAULT_STORE_MAX_SIZE;
11
+ const autoCleanup = options.autoCleanup ?? true;
12
+ const cleanupIntervalMs = options.cleanupIntervalMs ?? 60_000;
13
+ const tenants = new Map();
14
+ return {
15
+ get(tenantId) {
16
+ let entry = tenants.get(tenantId);
17
+ if (!entry) {
18
+ const store = new InMemoryStore({ maxSize, autoCleanup, cleanupIntervalMs });
19
+ const scoped = withStore(store);
20
+ entry = { store, scoped };
21
+ tenants.set(tenantId, entry);
22
+ }
23
+ return entry.scoped;
24
+ },
25
+ evict(tenantId) {
26
+ const entry = tenants.get(tenantId);
27
+ if (entry) {
28
+ entry.store.destroy();
29
+ tenants.delete(tenantId);
30
+ }
31
+ },
32
+ size() {
33
+ return tenants.size;
34
+ },
35
+ destroy() {
36
+ for (const [, entry] of tenants) {
37
+ entry.store.destroy();
38
+ }
39
+ tenants.clear();
40
+ },
41
+ };
42
+ }
43
+ /**
44
+ * Async tenant manager for async stores (Redis, DynamoDB, etc).
45
+ * Each tenant gets its own store instance with prefixed keys.
46
+ */
47
+ export function createAsyncTenantStore(storeFactory) {
48
+ const tenants = new Map();
49
+ return {
50
+ get(tenantId) {
51
+ let entry = tenants.get(tenantId);
52
+ if (!entry) {
53
+ const store = storeFactory(tenantId);
54
+ const scoped = withStore(store);
55
+ entry = { store, scoped };
56
+ tenants.set(tenantId, entry);
57
+ }
58
+ return entry.scoped;
59
+ },
60
+ evict(tenantId) {
61
+ tenants.delete(tenantId);
62
+ },
63
+ size() {
64
+ return tenants.size;
65
+ },
66
+ };
67
+ }
68
+ //# sourceMappingURL=tenant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/core/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAIpC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAe3C;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAA8B,EAAE;IAChE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,sBAAsB,CAAA;IAChE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,IAAI,CAAA;IAC/C,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,IAAI,MAAM,CAAA;IAE7D,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2D,CAAA;IAElF,OAAO;QACL,GAAG,CAAC,QAAgB;YAClB,IAAI,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACjC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC,CAAA;gBAC5E,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAkB,CAAA;gBAChD,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;gBACzB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAC9B,CAAC;YACD,OAAO,KAAK,CAAC,MAAM,CAAA;QACrB,CAAC;QAED,KAAK,CAAC,QAAgB;YACpB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACnC,IAAI,KAAK,EAAE,CAAC;gBACV,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;gBACrB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;YAC1B,CAAC;QACH,CAAC;QAED,IAAI;YACF,OAAO,OAAO,CAAC,IAAI,CAAA;QACrB,CAAC;QAED,OAAO;YACL,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;gBAChC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;YACvB,CAAC;YACD,OAAO,CAAC,KAAK,EAAE,CAAA;QACjB,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,YAAmD;IAMnD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8D,CAAA;IAErF,OAAO;QACL,GAAG,CAAC,QAAgB;YAClB,IAAI,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACjC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;gBACpC,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAmB,CAAA;gBACjD,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;gBACzB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAC9B,CAAC;YACD,OAAO,KAAK,CAAC,MAAM,CAAA;QACrB,CAAC;QAED,KAAK,CAAC,QAAgB;YACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAC1B,CAAC;QAED,IAAI;YACF,OAAO,OAAO,CAAC,IAAI,CAAA;QACrB,CAAC;KACF,CAAA;AACH,CAAC"}