@repobit/dex-store-elements 1.7.3 → 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 (227) hide show
  1. package/CHANGELOG.md +5 -913
  2. package/README.md +9 -7
  3. package/dist/src/actions/action.adapter.d.ts +36 -0
  4. package/dist/src/actions/action.adapter.js +183 -0
  5. package/dist/src/actions/action.adapter.js.map +1 -0
  6. package/dist/src/actions/action.attributes.d.ts +15 -0
  7. package/dist/src/actions/action.attributes.js +137 -0
  8. package/dist/src/actions/action.attributes.js.map +1 -0
  9. package/dist/src/actions/action.registry.d.ts +4 -0
  10. package/dist/src/actions/action.registry.js +119 -0
  11. package/dist/src/actions/action.registry.js.map +1 -0
  12. package/dist/src/actions/index.d.ts +3 -2
  13. package/dist/src/actions/index.js +3 -80
  14. package/dist/src/actions/index.js.map +1 -1
  15. package/dist/src/compute/compute.expand.d.ts +70 -0
  16. package/dist/src/compute/compute.expand.js +319 -0
  17. package/dist/src/compute/compute.expand.js.map +1 -0
  18. package/dist/src/compute/compute.scan.d.ts +54 -0
  19. package/dist/src/compute/compute.scan.js +160 -0
  20. package/dist/src/compute/compute.scan.js.map +1 -0
  21. package/dist/src/compute/option-resolver.d.ts +31 -0
  22. package/dist/src/compute/option-resolver.js +147 -0
  23. package/dist/src/compute/option-resolver.js.map +1 -0
  24. package/dist/src/contexts/context.compute.d.ts +12 -0
  25. package/dist/src/contexts/context.compute.js +4 -0
  26. package/dist/src/contexts/context.compute.js.map +1 -0
  27. package/dist/src/contexts/context.scope.d.ts +139 -0
  28. package/dist/src/contexts/context.scope.js +48 -0
  29. package/dist/src/contexts/context.scope.js.map +1 -0
  30. package/dist/src/controllers/controller.action-resolve.d.ts +110 -0
  31. package/dist/src/controllers/controller.action-resolve.js +203 -0
  32. package/dist/src/controllers/controller.action-resolve.js.map +1 -0
  33. package/dist/src/controllers/controller.action-topology.d.ts +59 -0
  34. package/dist/src/controllers/controller.action-topology.js +130 -0
  35. package/dist/src/controllers/controller.action-topology.js.map +1 -0
  36. package/dist/src/controllers/controller.compute.d.ts +72 -0
  37. package/dist/src/controllers/controller.compute.js +110 -0
  38. package/dist/src/controllers/controller.compute.js.map +1 -0
  39. package/dist/src/controllers/controller.resolve.d.ts +78 -0
  40. package/dist/src/controllers/controller.resolve.js +205 -0
  41. package/dist/src/controllers/controller.resolve.js.map +1 -0
  42. package/dist/src/core/action-topology.d.ts +62 -0
  43. package/dist/src/core/action-topology.js +67 -0
  44. package/dist/src/core/action-topology.js.map +1 -0
  45. package/dist/src/core/actions.d.ts +64 -0
  46. package/dist/src/core/actions.js +47 -0
  47. package/dist/src/core/actions.js.map +1 -0
  48. package/dist/src/core/node.element.d.ts +179 -0
  49. package/dist/src/core/node.element.js +573 -0
  50. package/dist/src/core/node.element.js.map +1 -0
  51. package/dist/src/core/node.scope.d.ts +374 -0
  52. package/dist/src/core/node.scope.js +558 -0
  53. package/dist/src/core/node.scope.js.map +1 -0
  54. package/dist/src/core/option-update.d.ts +11 -0
  55. package/dist/src/core/option-update.js +59 -0
  56. package/dist/src/core/option-update.js.map +1 -0
  57. package/dist/src/dsl/compilers/array/compiler.js +13 -14
  58. package/dist/src/dsl/compilers/array/compiler.js.map +1 -1
  59. package/dist/src/dsl/compilers/boolean/compiler.d.ts +1 -1
  60. package/dist/src/dsl/compilers/boolean/compiler.js +14 -27
  61. package/dist/src/dsl/compilers/boolean/compiler.js.map +1 -1
  62. package/dist/src/dsl/compilers/enum/compiler.js +7 -10
  63. package/dist/src/dsl/compilers/enum/compiler.js.map +1 -1
  64. package/dist/src/dsl/compilers/index.d.ts +1 -1
  65. package/dist/src/dsl/compilers/index.js +5 -5
  66. package/dist/src/dsl/compilers/index.js.map +1 -1
  67. package/dist/src/dsl/utilty.d.ts +0 -4
  68. package/dist/src/dsl/utilty.js +3 -30
  69. package/dist/src/dsl/utilty.js.map +1 -1
  70. package/dist/src/eta/batch.d.ts +123 -0
  71. package/dist/src/eta/batch.js +162 -0
  72. package/dist/src/eta/batch.js.map +1 -0
  73. package/dist/src/eta/batcher.d.ts +184 -0
  74. package/dist/src/eta/batcher.js +335 -0
  75. package/dist/src/eta/batcher.js.map +1 -0
  76. package/dist/src/eta/cache.d.ts +36 -0
  77. package/dist/src/eta/cache.js +56 -0
  78. package/dist/src/eta/cache.js.map +1 -0
  79. package/dist/src/eta/controller.d.ts +608 -0
  80. package/dist/src/eta/controller.js +1036 -0
  81. package/dist/src/eta/controller.js.map +1 -0
  82. package/dist/src/eta/factory.d.ts +74 -0
  83. package/dist/src/eta/factory.js +121 -0
  84. package/dist/src/eta/factory.js.map +1 -0
  85. package/dist/src/eta/idle.d.ts +39 -0
  86. package/dist/src/eta/idle.js +52 -0
  87. package/dist/src/eta/idle.js.map +1 -0
  88. package/dist/src/eta/index.d.ts +52 -0
  89. package/dist/src/eta/index.js +13 -0
  90. package/dist/src/eta/index.js.map +1 -0
  91. package/dist/src/eta/observer.d.ts +263 -0
  92. package/dist/src/eta/observer.js +263 -0
  93. package/dist/src/eta/observer.js.map +1 -0
  94. package/dist/src/eta/operations.d.ts +41 -0
  95. package/dist/src/eta/operations.js +59 -0
  96. package/dist/src/eta/operations.js.map +1 -0
  97. package/dist/src/eta/source-registry.d.ts +198 -0
  98. package/dist/src/eta/source-registry.js +267 -0
  99. package/dist/src/eta/source-registry.js.map +1 -0
  100. package/dist/src/eta/template-index.d.ts +285 -0
  101. package/dist/src/eta/template-index.js +642 -0
  102. package/dist/src/eta/template-index.js.map +1 -0
  103. package/dist/src/eta/types.d.ts +529 -0
  104. package/dist/src/eta/types.js +2 -0
  105. package/dist/src/eta/types.js.map +1 -0
  106. package/dist/src/index.d.ts +21 -9
  107. package/dist/src/index.js +22 -11
  108. package/dist/src/index.js.map +1 -1
  109. package/dist/src/nodes/node.context.d.ts +5 -3
  110. package/dist/src/nodes/node.context.js +48 -3
  111. package/dist/src/nodes/node.context.js.map +1 -1
  112. package/dist/src/nodes/node.option.d.ts +11 -31
  113. package/dist/src/nodes/node.option.js +158 -222
  114. package/dist/src/nodes/node.option.js.map +1 -1
  115. package/dist/src/nodes/node.product.d.ts +7 -11
  116. package/dist/src/nodes/node.product.js +85 -64
  117. package/dist/src/nodes/node.product.js.map +1 -1
  118. package/dist/src/renders/attributes/buyLink.d.ts +2 -2
  119. package/dist/src/renders/attributes/buyLink.js +14 -11
  120. package/dist/src/renders/attributes/buyLink.js.map +1 -1
  121. package/dist/src/renders/attributes/devices.d.ts +2 -2
  122. package/dist/src/renders/attributes/devices.js +9 -19
  123. package/dist/src/renders/attributes/devices.js.map +1 -1
  124. package/dist/src/renders/attributes/discount.d.ts +2 -2
  125. package/dist/src/renders/attributes/discount.js +56 -44
  126. package/dist/src/renders/attributes/discount.js.map +1 -1
  127. package/dist/src/renders/attributes/hide.d.ts +2 -2
  128. package/dist/src/renders/attributes/hide.js +49 -14
  129. package/dist/src/renders/attributes/hide.js.map +1 -1
  130. package/dist/src/renders/attributes/index.d.ts +3 -3
  131. package/dist/src/renders/attributes/index.js +2 -4
  132. package/dist/src/renders/attributes/index.js.map +1 -1
  133. package/dist/src/renders/attributes/price.d.ts +2 -2
  134. package/dist/src/renders/attributes/price.js +30 -44
  135. package/dist/src/renders/attributes/price.js.map +1 -1
  136. package/dist/src/renders/attributes/subscription.d.ts +2 -2
  137. package/dist/src/renders/attributes/subscription.js +14 -20
  138. package/dist/src/renders/attributes/subscription.js.map +1 -1
  139. package/dist/src/renders/attributes/utilty.d.ts +2 -0
  140. package/dist/src/renders/attributes/utilty.js +17 -4
  141. package/dist/src/renders/attributes/utilty.js.map +1 -1
  142. package/dist/src/renders/context.d.ts +122 -10
  143. package/dist/src/renders/context.js +140 -80
  144. package/dist/src/renders/context.js.map +1 -1
  145. package/dist/src/renders/format.js +2 -2
  146. package/dist/src/renders/format.js.map +1 -1
  147. package/dist/src/renders/index.d.ts +6 -2
  148. package/dist/src/renders/index.js +67 -29
  149. package/dist/src/renders/index.js.map +1 -1
  150. package/dist/src/renders/observe.d.ts +1 -4
  151. package/dist/src/renders/observe.js +10 -24
  152. package/dist/src/renders/observe.js.map +1 -1
  153. package/dist/src/renders/render.wrapper.d.ts +37 -0
  154. package/dist/src/renders/render.wrapper.js +147 -0
  155. package/dist/src/renders/render.wrapper.js.map +1 -0
  156. package/dist/src/templating/eta.js +1 -4
  157. package/dist/src/templating/eta.js.map +1 -1
  158. package/package.json +4 -5
  159. package/dist/src/actions/action.button.d.ts +0 -2
  160. package/dist/src/actions/action.button.js +0 -8
  161. package/dist/src/actions/action.button.js.map +0 -1
  162. package/dist/src/actions/action.input.d.ts +0 -2
  163. package/dist/src/actions/action.input.js +0 -43
  164. package/dist/src/actions/action.input.js.map +0 -1
  165. package/dist/src/actions/action.select.d.ts +0 -2
  166. package/dist/src/actions/action.select.js +0 -14
  167. package/dist/src/actions/action.select.js.map +0 -1
  168. package/dist/src/actions/utilty.d.ts +0 -16
  169. package/dist/src/actions/utilty.js +0 -149
  170. package/dist/src/actions/utilty.js.map +0 -1
  171. package/dist/src/contexts/context.datalayer.d.ts +0 -9
  172. package/dist/src/contexts/context.datalayer.js +0 -3
  173. package/dist/src/contexts/context.datalayer.js.map +0 -1
  174. package/dist/src/contexts/context.derived.d.ts +0 -12
  175. package/dist/src/contexts/context.derived.js +0 -3
  176. package/dist/src/contexts/context.derived.js.map +0 -1
  177. package/dist/src/contexts/context.option.d.ts +0 -5
  178. package/dist/src/contexts/context.option.js +0 -3
  179. package/dist/src/contexts/context.option.js.map +0 -1
  180. package/dist/src/contexts/context.product.d.ts +0 -5
  181. package/dist/src/contexts/context.product.js +0 -3
  182. package/dist/src/contexts/context.product.js.map +0 -1
  183. package/dist/src/contexts/context.state.d.ts +0 -28
  184. package/dist/src/contexts/context.state.js +0 -3
  185. package/dist/src/contexts/context.state.js.map +0 -1
  186. package/dist/src/contexts/context.store.d.ts +0 -5
  187. package/dist/src/contexts/context.store.js +0 -3
  188. package/dist/src/contexts/context.store.js.map +0 -1
  189. package/dist/src/controllers/collect-controller.d.ts +0 -39
  190. package/dist/src/controllers/collect-controller.js +0 -161
  191. package/dist/src/controllers/collect-controller.js.map +0 -1
  192. package/dist/src/controllers/compute-controller.d.ts +0 -55
  193. package/dist/src/controllers/compute-controller.js +0 -350
  194. package/dist/src/controllers/compute-controller.js.map +0 -1
  195. package/dist/src/controllers/eta-renderer/eta-dom-renderer.d.ts +0 -25
  196. package/dist/src/controllers/eta-renderer/eta-dom-renderer.js +0 -192
  197. package/dist/src/controllers/eta-renderer/eta-dom-renderer.js.map +0 -1
  198. package/dist/src/controllers/eta-renderer/eta-mutation-observer.d.ts +0 -28
  199. package/dist/src/controllers/eta-renderer/eta-mutation-observer.js +0 -206
  200. package/dist/src/controllers/eta-renderer/eta-mutation-observer.js.map +0 -1
  201. package/dist/src/controllers/eta-renderer/eta-renderer.d.ts +0 -21
  202. package/dist/src/controllers/eta-renderer/eta-renderer.js +0 -77
  203. package/dist/src/controllers/eta-renderer/eta-renderer.js.map +0 -1
  204. package/dist/src/controllers/eta-renderer/eta-template-cache.d.ts +0 -24
  205. package/dist/src/controllers/eta-renderer/eta-template-cache.js +0 -61
  206. package/dist/src/controllers/eta-renderer/eta-template-cache.js.map +0 -1
  207. package/dist/src/controllers/eta-renderer/eta-types.d.ts +0 -11
  208. package/dist/src/controllers/eta-renderer/eta-types.js +0 -1
  209. package/dist/src/controllers/eta-renderer/eta-types.js.map +0 -1
  210. package/dist/src/controllers/eta-renderer/index.d.ts +0 -2
  211. package/dist/src/controllers/eta-renderer/index.js +0 -2
  212. package/dist/src/controllers/eta-renderer/index.js.map +0 -1
  213. package/dist/src/controllers/event-pipeline-controller.d.ts +0 -28
  214. package/dist/src/controllers/event-pipeline-controller.js +0 -72
  215. package/dist/src/controllers/event-pipeline-controller.js.map +0 -1
  216. package/dist/src/events/events.d.ts +0 -75
  217. package/dist/src/events/events.js +0 -78
  218. package/dist/src/events/events.js.map +0 -1
  219. package/dist/src/nodes/node.root.d.ts +0 -16
  220. package/dist/src/nodes/node.root.js +0 -49
  221. package/dist/src/nodes/node.root.js.map +0 -1
  222. package/dist/src/nodes/node.state.d.ts +0 -88
  223. package/dist/src/nodes/node.state.js +0 -330
  224. package/dist/src/nodes/node.state.js.map +0 -1
  225. package/dist/src/renders/utility.d.ts +0 -32
  226. package/dist/src/renders/utility.js +0 -191
  227. package/dist/src/renders/utility.js.map +0 -1
@@ -0,0 +1,110 @@
1
+ import type { ReactiveController } from 'lit';
2
+ import { type BdActionRequestDetail, type BdTransition } from '../core/actions.js';
3
+ import { type BdResolveContext, type BdResolveHookPhase, type BdResolveHost, type BdResolveStatus, type BdWorkKey, type MaybePromise } from './controller.resolve.js';
4
+ export type BdActionResolveTransitionSource = 'local' | 'parent';
5
+ export type BdActionResolveContext = Readonly<{
6
+ /**
7
+ * The transition passed to derive/resolve/commit.
8
+ *
9
+ * This is only set for a fresh transition. Once the controller marks a
10
+ * transition committed, the same transition is suppressed from future args.
11
+ */
12
+ transition?: BdTransition;
13
+ transitionSeq?: number;
14
+ transitionSource?: BdActionResolveTransitionSource;
15
+ freshTransition: boolean;
16
+ }>;
17
+ export interface BdActionResolveHost extends BdResolveHost, EventTarget {
18
+ }
19
+ export interface BdActionResolveOptions<TArgs extends readonly unknown[], TDerivedArgs extends readonly unknown[], TResult> {
20
+ name?: string;
21
+ workKey?: BdWorkKey;
22
+ /**
23
+ * Base node inputs. Keep this close to @lit/task naming.
24
+ *
25
+ * Examples:
26
+ * () => [this.parentScope, this.devices, this.subscription] as const
27
+ */
28
+ args: () => TArgs;
29
+ /**
30
+ * Optional downward transition source, usually parentScope.transition.
31
+ *
32
+ * Local bd-action-request events captured by this controller are considered
33
+ * alongside this transition, with the latest seq winning.
34
+ */
35
+ transition?: (args: TArgs) => BdTransition | undefined;
36
+ /**
37
+ * Converts base args + a fresh transition into the actual resolver args.
38
+ *
39
+ * This should be pure. It must not publish scope or mutate host props.
40
+ */
41
+ derive: (args: TArgs, context: BdActionResolveContext) => TDerivedArgs;
42
+ enabled?: (args: TDerivedArgs, context: BdActionResolveContext) => boolean;
43
+ argsEqual?: (oldArgs: TDerivedArgs, newArgs: TDerivedArgs) => boolean;
44
+ autoRun?: boolean | 'afterUpdate';
45
+ resolve: (args: TDerivedArgs, resolveContext: BdResolveContext, actionContext: BdActionResolveContext) => MaybePromise<TResult>;
46
+ commit?: (result: TResult, args: TDerivedArgs, resolveContext: BdResolveContext, actionContext: BdActionResolveContext) => MaybePromise<void>;
47
+ onPending?: (args: TDerivedArgs, resolveContext: BdResolveContext, actionContext: BdActionResolveContext) => MaybePromise<void>;
48
+ onDisabled?: (args: TDerivedArgs, resolveContext: BdResolveContext, actionContext: BdActionResolveContext) => MaybePromise<void>;
49
+ onComplete?: (result: TResult, args: TDerivedArgs, resolveContext: BdResolveContext, actionContext: BdActionResolveContext) => MaybePromise<void>;
50
+ onError?: (error: unknown, args: TDerivedArgs, resolveContext: BdResolveContext, actionContext: BdActionResolveContext) => MaybePromise<void>;
51
+ onHookError?: (error: unknown, phase: BdResolveHookPhase) => void;
52
+ abortOnDisconnect?: boolean;
53
+ /**
54
+ * If false, this controller only consumes transitions supplied by options.transition.
55
+ */
56
+ captureActions?: boolean;
57
+ createTransition?: (detail: BdActionRequestDetail, event: CustomEvent<BdActionRequestDetail>) => BdTransition;
58
+ /**
59
+ * Optional predicate consulted for every transition candidate (both
60
+ * local `bd-action-request` events and parent cascades).
61
+ *
62
+ * Return `false` to drop the candidate; the controller will not feed it
63
+ * into `derive` / `resolve` / `commit`. The host typically uses this to
64
+ * honour the `ignore-events` and `ignore-events-parent` attributes on
65
+ * `bd-*` provider elements.
66
+ */
67
+ filterTransition?: (candidate: TransitionCandidate) => boolean;
68
+ }
69
+ type TransitionCandidate = Readonly<{
70
+ transition: BdTransition;
71
+ source: BdActionResolveTransitionSource;
72
+ }>;
73
+ /**
74
+ * Node workflow controller for the common bd runtime pattern:
75
+ *
76
+ * base args + fresh transition -> derived resolver args
77
+ * enabled -> resolve -> commit
78
+ * mark transition committed only after successful commit
79
+ *
80
+ * It keeps raw DOM requests out of node code and keeps transition seq
81
+ * bookkeeping out of every concrete resolver.
82
+ */
83
+ export declare class BdActionResolveController<TArgs extends readonly unknown[], TDerivedArgs extends readonly unknown[], TResult> implements ReactiveController {
84
+ private readonly host;
85
+ private readonly options;
86
+ private readonly _resolver;
87
+ private _localTransition?;
88
+ private _lastCommittedTransitionSeq;
89
+ private _listening;
90
+ constructor(host: BdActionResolveHost, options: BdActionResolveOptions<TArgs, TDerivedArgs, TResult>);
91
+ hostConnected(): void;
92
+ hostDisconnected(): void;
93
+ get status(): BdResolveStatus;
94
+ get value(): TResult | undefined;
95
+ get error(): unknown;
96
+ get pending(): boolean;
97
+ get complete(): boolean;
98
+ get disabled(): boolean;
99
+ get failed(): boolean;
100
+ get localTransition(): BdTransition | undefined;
101
+ run(): Promise<TResult | undefined>;
102
+ abort(reason?: unknown): void;
103
+ private _args;
104
+ private _createActionContext;
105
+ private _selectTransitionCandidate;
106
+ private _argsEqual;
107
+ private _markTransitionCommitted;
108
+ private readonly _onActionRequest;
109
+ }
110
+ export {};
@@ -0,0 +1,203 @@
1
+ import { BD_ACTION_REQUEST_EVENT, createBdTransition, isBdActionRequestEvent } from '../core/actions.js';
2
+ import { BdResolveController } from './controller.resolve.js';
3
+ /**
4
+ * Node workflow controller for the common bd runtime pattern:
5
+ *
6
+ * base args + fresh transition -> derived resolver args
7
+ * enabled -> resolve -> commit
8
+ * mark transition committed only after successful commit
9
+ *
10
+ * It keeps raw DOM requests out of node code and keeps transition seq
11
+ * bookkeeping out of every concrete resolver.
12
+ */
13
+ export class BdActionResolveController {
14
+ constructor(host, options) {
15
+ this.host = host;
16
+ this.options = options;
17
+ this._lastCommittedTransitionSeq = 0;
18
+ this._listening = false;
19
+ this._onActionRequest = (event) => {
20
+ if (!isBdActionRequestEvent(event)) {
21
+ return;
22
+ }
23
+ event.preventDefault();
24
+ event.stopPropagation();
25
+ const transition = this.options.createTransition?.(event.detail, event) ??
26
+ createBdTransition(event.detail, event.target);
27
+ const filter = this.options.filterTransition;
28
+ if (filter &&
29
+ !filter({
30
+ transition,
31
+ source: 'local'
32
+ })) {
33
+ return;
34
+ }
35
+ this._localTransition = transition;
36
+ this.host.requestUpdate();
37
+ };
38
+ host.addController(this);
39
+ this._resolver = new BdResolveController(host, {
40
+ name: options.name,
41
+ workKey: options.workKey,
42
+ autoRun: options.autoRun,
43
+ abortOnDisconnect: options.abortOnDisconnect,
44
+ args: () => this._args(),
45
+ argsEqual: (oldArgs, newArgs) => this._argsEqual(oldArgs, newArgs),
46
+ enabled: ([args, context]) => options.enabled?.(args, context) ?? true,
47
+ resolve: ([args, actionContext], resolveContext) => options.resolve(args, resolveContext, actionContext),
48
+ commit: async (result, [args, actionContext], resolveContext) => {
49
+ const commitResult = options.commit?.(result, args, resolveContext, actionContext);
50
+ if (isPromiseLike(commitResult)) {
51
+ await commitResult;
52
+ }
53
+ this._markTransitionCommitted(actionContext);
54
+ },
55
+ onPending: ([args, actionContext], resolveContext) => options.onPending?.(args, resolveContext, actionContext),
56
+ onDisabled: ([args, actionContext], resolveContext) => options.onDisabled?.(args, resolveContext, actionContext),
57
+ onComplete: (result, [args, actionContext], resolveContext) => options.onComplete?.(result, args, resolveContext, actionContext),
58
+ onError: (error, [args, actionContext], resolveContext) => options.onError?.(error, args, resolveContext, actionContext),
59
+ onHookError: options.onHookError
60
+ });
61
+ }
62
+ hostConnected() {
63
+ if (this.options.captureActions === false) {
64
+ return;
65
+ }
66
+ if (this._listening) {
67
+ return;
68
+ }
69
+ this.host.addEventListener(BD_ACTION_REQUEST_EVENT, this._onActionRequest);
70
+ this._listening = true;
71
+ }
72
+ hostDisconnected() {
73
+ if (!this._listening) {
74
+ return;
75
+ }
76
+ this.host.removeEventListener(BD_ACTION_REQUEST_EVENT, this._onActionRequest);
77
+ this._listening = false;
78
+ }
79
+ get status() {
80
+ return this._resolver.status;
81
+ }
82
+ get value() {
83
+ return this._resolver.value;
84
+ }
85
+ get error() {
86
+ return this._resolver.error;
87
+ }
88
+ get pending() {
89
+ return this._resolver.pending;
90
+ }
91
+ get complete() {
92
+ return this._resolver.complete;
93
+ }
94
+ get disabled() {
95
+ return this._resolver.disabled;
96
+ }
97
+ get failed() {
98
+ return this._resolver.failed;
99
+ }
100
+ get localTransition() {
101
+ return this._localTransition;
102
+ }
103
+ run() {
104
+ return this._resolver.run();
105
+ }
106
+ abort(reason) {
107
+ this._localTransition = undefined;
108
+ this._resolver.abort(reason);
109
+ }
110
+ _args() {
111
+ const baseArgs = this.options.args();
112
+ const context = this._createActionContext(baseArgs);
113
+ const derivedArgs = this.options.derive(baseArgs, context);
114
+ return [
115
+ derivedArgs,
116
+ context
117
+ ];
118
+ }
119
+ _createActionContext(args) {
120
+ const candidate = this._selectTransitionCandidate(args);
121
+ if (!candidate ||
122
+ candidate.transition.seq <= this._lastCommittedTransitionSeq) {
123
+ return {
124
+ freshTransition: false
125
+ };
126
+ }
127
+ return {
128
+ transition: candidate.transition,
129
+ transitionSeq: candidate.transition.seq,
130
+ transitionSource: candidate.source,
131
+ freshTransition: true
132
+ };
133
+ }
134
+ _selectTransitionCandidate(args) {
135
+ const filter = this.options.filterTransition;
136
+ const localCandidate = this._localTransition
137
+ ? {
138
+ transition: this._localTransition,
139
+ source: 'local'
140
+ }
141
+ : undefined;
142
+ const parentTransition = this.options.transition?.(args);
143
+ const parentCandidate = parentTransition
144
+ ? {
145
+ transition: parentTransition,
146
+ source: 'parent'
147
+ }
148
+ : undefined;
149
+ const candidates = [];
150
+ if (localCandidate && (!filter || filter(localCandidate))) {
151
+ candidates.push(localCandidate);
152
+ }
153
+ if (parentCandidate && (!filter || filter(parentCandidate))) {
154
+ candidates.push(parentCandidate);
155
+ }
156
+ if (candidates.length === 0) {
157
+ return undefined;
158
+ }
159
+ return candidates.reduce((latest, current) => current.transition.seq >= latest.transition.seq ? current : latest);
160
+ }
161
+ _argsEqual(oldArgs, newArgs) {
162
+ const [oldDerivedArgs, oldContext] = oldArgs;
163
+ const [newDerivedArgs, newContext] = newArgs;
164
+ if (newContext.freshTransition &&
165
+ newContext.transitionSeq !== oldContext.transitionSeq) {
166
+ return false;
167
+ }
168
+ return (this.options.argsEqual?.(oldDerivedArgs, newDerivedArgs) ??
169
+ shallowArrayEqual(oldDerivedArgs, newDerivedArgs));
170
+ }
171
+ _markTransitionCommitted(context) {
172
+ const transition = context.transition;
173
+ if (!transition || !context.freshTransition) {
174
+ return;
175
+ }
176
+ this._lastCommittedTransitionSeq = Math.max(this._lastCommittedTransitionSeq, transition.seq);
177
+ if (this._localTransition === transition) {
178
+ this._localTransition = undefined;
179
+ }
180
+ this.host.requestUpdate();
181
+ }
182
+ }
183
+ function shallowArrayEqual(oldArgs, newArgs) {
184
+ if (oldArgs === newArgs) {
185
+ return true;
186
+ }
187
+ if (oldArgs.length !== newArgs.length) {
188
+ return false;
189
+ }
190
+ for (let index = 0; index < oldArgs.length; index += 1) {
191
+ if (!Object.is(oldArgs[index], newArgs[index])) {
192
+ return false;
193
+ }
194
+ }
195
+ return true;
196
+ }
197
+ function isPromiseLike(value) {
198
+ return (typeof value === 'object' &&
199
+ value !== null &&
200
+ 'then' in value &&
201
+ typeof value.then === 'function');
202
+ }
203
+ //# sourceMappingURL=controller.action-resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.action-resolve.js","sourceRoot":"","sources":["../../../src/controllers/controller.action-resolve.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\n\nimport {\n BD_ACTION_REQUEST_EVENT,\n createBdTransition,\n isBdActionRequestEvent,\n type BdActionRequestDetail,\n type BdTransition\n} from '@/core/actions.js';\nimport {\n BdResolveController,\n type BdResolveContext,\n type BdResolveHookPhase,\n type BdResolveHost,\n type BdResolveStatus,\n type BdWorkKey,\n type MaybePromise\n} from './controller.resolve.js';\n\nexport type BdActionResolveTransitionSource =\n | 'local'\n | 'parent';\n\nexport type BdActionResolveContext = Readonly<{\n /**\n * The transition passed to derive/resolve/commit.\n *\n * This is only set for a fresh transition. Once the controller marks a\n * transition committed, the same transition is suppressed from future args.\n */\n transition?: BdTransition;\n\n transitionSeq? : number;\n transitionSource?: BdActionResolveTransitionSource;\n freshTransition : boolean;\n}>;\n\nexport interface BdActionResolveHost extends BdResolveHost, EventTarget {}\n\nexport interface BdActionResolveOptions<\n TArgs extends readonly unknown[],\n TDerivedArgs extends readonly unknown[],\n TResult\n> {\n name? : string;\n workKey?: BdWorkKey;\n\n /**\n * Base node inputs. Keep this close to @lit/task naming.\n *\n * Examples:\n * () => [this.parentScope, this.devices, this.subscription] as const\n */\n args: () => TArgs;\n\n /**\n * Optional downward transition source, usually parentScope.transition.\n *\n * Local bd-action-request events captured by this controller are considered\n * alongside this transition, with the latest seq winning.\n */\n transition?: (args: TArgs) => BdTransition | undefined;\n\n /**\n * Converts base args + a fresh transition into the actual resolver args.\n *\n * This should be pure. It must not publish scope or mutate host props.\n */\n derive: (\n args: TArgs,\n context: BdActionResolveContext\n ) => TDerivedArgs;\n\n enabled?: (\n args: TDerivedArgs,\n context: BdActionResolveContext\n ) => boolean;\n\n argsEqual?: (\n oldArgs: TDerivedArgs,\n newArgs: TDerivedArgs\n ) => boolean;\n\n autoRun?: boolean | 'afterUpdate';\n\n resolve: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<TResult>;\n\n commit?: (\n result: TResult,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onPending?: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onDisabled?: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onComplete?: (\n result: TResult,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onError?: (\n error: unknown,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onHookError?: (\n error: unknown,\n phase: BdResolveHookPhase\n ) => void;\n\n abortOnDisconnect?: boolean;\n\n /**\n * If false, this controller only consumes transitions supplied by options.transition.\n */\n captureActions?: boolean;\n\n createTransition?: (\n detail: BdActionRequestDetail,\n event: CustomEvent<BdActionRequestDetail>\n ) => BdTransition;\n\n /**\n * Optional predicate consulted for every transition candidate (both\n * local `bd-action-request` events and parent cascades).\n *\n * Return `false` to drop the candidate; the controller will not feed it\n * into `derive` / `resolve` / `commit`. The host typically uses this to\n * honour the `ignore-events` and `ignore-events-parent` attributes on\n * `bd-*` provider elements.\n */\n filterTransition?: (\n candidate: TransitionCandidate\n ) => boolean;\n}\n\ntype BdActionResolveInternalArgs<\n TDerivedArgs extends readonly unknown[]\n> = readonly [\n args: TDerivedArgs,\n context: BdActionResolveContext\n];\n\ntype TransitionCandidate = Readonly<{\n transition: BdTransition;\n source : BdActionResolveTransitionSource;\n}>;\n\n/**\n * Node workflow controller for the common bd runtime pattern:\n *\n * base args + fresh transition -> derived resolver args\n * enabled -> resolve -> commit\n * mark transition committed only after successful commit\n *\n * It keeps raw DOM requests out of node code and keeps transition seq\n * bookkeeping out of every concrete resolver.\n */\nexport class BdActionResolveController<\n TArgs extends readonly unknown[],\n TDerivedArgs extends readonly unknown[],\n TResult\n> implements ReactiveController {\n private readonly _resolver: BdResolveController<\n BdActionResolveInternalArgs<TDerivedArgs>,\n TResult\n >;\n\n private _localTransition?: BdTransition;\n private _lastCommittedTransitionSeq = 0;\n private _listening = false;\n\n constructor(\n private readonly host: BdActionResolveHost,\n private readonly options:\n BdActionResolveOptions<TArgs, TDerivedArgs, TResult>\n ) {\n host.addController(this);\n\n this._resolver = new BdResolveController(host, {\n name : options.name,\n workKey : options.workKey,\n autoRun : options.autoRun,\n abortOnDisconnect: options.abortOnDisconnect,\n args : () => this._args(),\n argsEqual : (oldArgs, newArgs) =>\n this._argsEqual(\n oldArgs,\n newArgs\n ),\n enabled: ([args, context]) =>\n options.enabled?.(\n args,\n context\n ) ?? true,\n resolve: ([args, actionContext], resolveContext) =>\n options.resolve(\n args,\n resolveContext,\n actionContext\n ),\n commit: async (\n result,\n [args, actionContext],\n resolveContext\n ) => {\n const commitResult =\n options.commit?.(\n result,\n args,\n resolveContext,\n actionContext\n );\n\n if (isPromiseLike(commitResult)) {\n await commitResult;\n }\n\n this._markTransitionCommitted(actionContext);\n },\n onPending: ([args, actionContext], resolveContext) =>\n options.onPending?.(\n args,\n resolveContext,\n actionContext\n ),\n onDisabled: ([args, actionContext], resolveContext) =>\n options.onDisabled?.(\n args,\n resolveContext,\n actionContext\n ),\n onComplete: (\n result,\n [args, actionContext],\n resolveContext\n ) =>\n options.onComplete?.(\n result,\n args,\n resolveContext,\n actionContext\n ),\n onError: (\n error,\n [args, actionContext],\n resolveContext\n ) =>\n options.onError?.(\n error,\n args,\n resolveContext,\n actionContext\n ),\n onHookError: options.onHookError\n });\n }\n\n hostConnected(): void {\n if (this.options.captureActions === false) {\n return;\n }\n\n if (this._listening) {\n return;\n }\n\n this.host.addEventListener(\n BD_ACTION_REQUEST_EVENT,\n this._onActionRequest as EventListener\n );\n\n this._listening = true;\n }\n\n hostDisconnected(): void {\n if (!this._listening) {\n return;\n }\n\n this.host.removeEventListener(\n BD_ACTION_REQUEST_EVENT,\n this._onActionRequest as EventListener\n );\n\n this._listening = false;\n }\n\n get status(): BdResolveStatus {\n return this._resolver.status;\n }\n\n get value(): TResult | undefined {\n return this._resolver.value;\n }\n\n get error(): unknown {\n return this._resolver.error;\n }\n\n get pending(): boolean {\n return this._resolver.pending;\n }\n\n get complete(): boolean {\n return this._resolver.complete;\n }\n\n get disabled(): boolean {\n return this._resolver.disabled;\n }\n\n get failed(): boolean {\n return this._resolver.failed;\n }\n\n get localTransition(): BdTransition | undefined {\n return this._localTransition;\n }\n\n run(): Promise<TResult | undefined> {\n return this._resolver.run();\n }\n\n abort(reason?: unknown): void {\n this._localTransition = undefined;\n this._resolver.abort(reason);\n }\n\n private _args(): BdActionResolveInternalArgs<TDerivedArgs> {\n const baseArgs =\n this.options.args();\n\n const context =\n this._createActionContext(baseArgs);\n\n const derivedArgs =\n this.options.derive(\n baseArgs,\n context\n );\n\n return [\n derivedArgs,\n context\n ] as const;\n }\n\n private _createActionContext(\n args: TArgs\n ): BdActionResolveContext {\n const candidate =\n this._selectTransitionCandidate(args);\n\n if (\n !candidate ||\n candidate.transition.seq <= this._lastCommittedTransitionSeq\n ) {\n return {\n freshTransition: false\n };\n }\n\n return {\n transition : candidate.transition,\n transitionSeq : candidate.transition.seq,\n transitionSource: candidate.source,\n freshTransition : true\n };\n }\n\n private _selectTransitionCandidate(\n args: TArgs\n ): TransitionCandidate | undefined {\n const filter = this.options.filterTransition;\n\n const localCandidate =\n this._localTransition\n ? {\n transition: this._localTransition,\n source : 'local' as const\n }\n : undefined;\n\n const parentTransition =\n this.options.transition?.(args);\n\n const parentCandidate =\n parentTransition\n ? {\n transition: parentTransition,\n source : 'parent' as const\n }\n : undefined;\n\n const candidates: TransitionCandidate[] = [];\n\n if (localCandidate && (!filter || filter(localCandidate))) {\n candidates.push(localCandidate);\n }\n\n if (parentCandidate && (!filter || filter(parentCandidate))) {\n candidates.push(parentCandidate);\n }\n\n if (candidates.length === 0) {\n return undefined;\n }\n\n return candidates.reduce((latest, current) =>\n current.transition.seq >= latest.transition.seq ? current : latest\n );\n }\n\n private _argsEqual(\n oldArgs: BdActionResolveInternalArgs<TDerivedArgs>,\n newArgs: BdActionResolveInternalArgs<TDerivedArgs>\n ): boolean {\n const [oldDerivedArgs, oldContext] = oldArgs;\n const [newDerivedArgs, newContext] = newArgs;\n\n if (\n newContext.freshTransition &&\n newContext.transitionSeq !== oldContext.transitionSeq\n ) {\n return false;\n }\n\n return (\n this.options.argsEqual?.(\n oldDerivedArgs,\n newDerivedArgs\n ) ??\n shallowArrayEqual(\n oldDerivedArgs,\n newDerivedArgs\n )\n );\n }\n\n private _markTransitionCommitted(\n context: BdActionResolveContext\n ): void {\n const transition = context.transition;\n\n if (!transition || !context.freshTransition) {\n return;\n }\n\n this._lastCommittedTransitionSeq = Math.max(\n this._lastCommittedTransitionSeq,\n transition.seq\n );\n\n if (this._localTransition === transition) {\n this._localTransition = undefined;\n }\n\n this.host.requestUpdate();\n }\n\n private readonly _onActionRequest = (\n event: Event\n ): void => {\n if (!isBdActionRequestEvent(event)) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n const transition =\n this.options.createTransition?.(\n event.detail,\n event\n ) ??\n createBdTransition(\n event.detail,\n event.target\n );\n\n const filter = this.options.filterTransition;\n\n if (\n filter &&\n !filter({\n transition,\n source: 'local'\n })\n ) {\n return;\n }\n\n this._localTransition = transition;\n\n this.host.requestUpdate();\n };\n}\n\nfunction shallowArrayEqual(\n oldArgs: readonly unknown[],\n newArgs: readonly unknown[]\n): boolean {\n if (oldArgs === newArgs) {\n return true;\n }\n\n if (oldArgs.length !== newArgs.length) {\n return false;\n }\n\n for (let index = 0; index < oldArgs.length; index += 1) {\n if (!Object.is(\n oldArgs[index],\n newArgs[index]\n )) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isPromiseLike<T>(\n value: MaybePromise<T> | undefined\n): value is Promise<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function'\n );\n}\n"]}
@@ -0,0 +1,59 @@
1
+ import type { ReactiveController, ReactiveControllerHost } from 'lit';
2
+ import { type BdComputeScan } from '../compute/compute.scan.js';
3
+ import type { ProductOption } from '@repobit/dex-store';
4
+ export interface BdActionTopologyHost extends ReactiveControllerHost, EventTarget {
5
+ readonly topologyBoundary?: boolean;
6
+ }
7
+ /**
8
+ * Owns the set of native action elements that belong to a single bd node.
9
+ *
10
+ * Membership is fed incrementally by BdActionElementAdapter announcements, so
11
+ * no node ever rescans its DOM children. The nearest bd node catches
12
+ * bd-action-connect / bd-action-disconnect, exactly like bd-action-request, so
13
+ * an action's compute radius matches its runtime radius.
14
+ *
15
+ * Aggregation across the logical bd subtree is intentionally NOT done here. The
16
+ * owning element walks its bd children (which it has access to) and unions
17
+ * their local sets. This controller only owns local membership + a revision
18
+ * that already reflects descendant changes via the bubbling topology event.
19
+ */
20
+ export declare class BdActionTopologyController implements ReactiveController {
21
+ private readonly host;
22
+ private readonly _localScans;
23
+ private _localOptionSeed?;
24
+ private _revision;
25
+ private _listening;
26
+ constructor(host: BdActionTopologyHost);
27
+ /**
28
+ * Bumped whenever this node's local set changes OR any descendant bd node's
29
+ * set changes (the change event bubbles through here). Use this as a compute
30
+ * input so a node recomputes when anything in its subtree changes.
31
+ */
32
+ get revision(): number;
33
+ get localElements(): readonly HTMLElement[];
34
+ get localActionScans(): readonly BdComputeScan[];
35
+ get localOptionSeed(): ProductOption | undefined;
36
+ setLocalOptionSeed(option: ProductOption | undefined): void;
37
+ /**
38
+ * Signal that this node's logical subtree shape changed (a bd child node
39
+ * connected or disconnected) rather than an individual action element.
40
+ *
41
+ * Membership is recomputed lazily by the owning element, so this only needs
42
+ * to bump the revision and notify ancestors. The owning element calls this
43
+ * from its onBdChildConnected / onBdChildDisconnected hooks, which fire while
44
+ * this node is still connected even as a child subtree is torn down.
45
+ */
46
+ markSubtreeChanged(): void;
47
+ hostConnected(): void;
48
+ hostDisconnected(): void;
49
+ private readonly _onActionConnect;
50
+ private readonly _onActionDisconnect;
51
+ private readonly _onActionUpdate;
52
+ /**
53
+ * Fires on this node (target phase) and every ancestor (bubbling) for a
54
+ * single change. Each node bumps its own revision exactly once, which is why
55
+ * local changes also flow through here instead of bumping directly.
56
+ */
57
+ private readonly _onTopologyChanged;
58
+ private _emitChanged;
59
+ }
@@ -0,0 +1,130 @@
1
+ import { BD_ACTION_CONNECT_EVENT, BD_ACTION_DISCONNECT_EVENT, BD_ACTION_TOPOLOGY_CHANGED_EVENT, BD_ACTION_UPDATE_EVENT, dispatchBdActionTopologyChanged } from '../core/action-topology.js';
2
+ /**
3
+ * Owns the set of native action elements that belong to a single bd node.
4
+ *
5
+ * Membership is fed incrementally by BdActionElementAdapter announcements, so
6
+ * no node ever rescans its DOM children. The nearest bd node catches
7
+ * bd-action-connect / bd-action-disconnect, exactly like bd-action-request, so
8
+ * an action's compute radius matches its runtime radius.
9
+ *
10
+ * Aggregation across the logical bd subtree is intentionally NOT done here. The
11
+ * owning element walks its bd children (which it has access to) and unions
12
+ * their local sets. This controller only owns local membership + a revision
13
+ * that already reflects descendant changes via the bubbling topology event.
14
+ */
15
+ export class BdActionTopologyController {
16
+ constructor(host) {
17
+ this.host = host;
18
+ this._localScans = new Map();
19
+ this._revision = 0;
20
+ this._listening = false;
21
+ this._onActionConnect = (event) => {
22
+ /**
23
+ * Nearest bd node wins ownership; do not let outer nodes also claim it.
24
+ */
25
+ event.stopPropagation();
26
+ event.detail.claim(this.host);
27
+ this._localScans.set(event.detail.element, event.detail.scan);
28
+ this._emitChanged();
29
+ };
30
+ this._onActionDisconnect = (event) => {
31
+ event.stopPropagation();
32
+ if (!this._localScans.delete(event.detail.element)) {
33
+ return;
34
+ }
35
+ this._emitChanged();
36
+ };
37
+ this._onActionUpdate = (event) => {
38
+ event.stopPropagation();
39
+ if (!this._localScans.has(event.detail.element)) {
40
+ return;
41
+ }
42
+ const previous = this._localScans.get(event.detail.element);
43
+ if (previous &&
44
+ sameComputeScan(previous, event.detail.scan)) {
45
+ return;
46
+ }
47
+ this._localScans.set(event.detail.element, event.detail.scan);
48
+ this._emitChanged();
49
+ };
50
+ /**
51
+ * Fires on this node (target phase) and every ancestor (bubbling) for a
52
+ * single change. Each node bumps its own revision exactly once, which is why
53
+ * local changes also flow through here instead of bumping directly.
54
+ */
55
+ this._onTopologyChanged = (event) => {
56
+ this._revision++;
57
+ this.host.requestUpdate();
58
+ if (this.host.topologyBoundary === true) {
59
+ event.stopPropagation();
60
+ }
61
+ };
62
+ host.addController(this);
63
+ }
64
+ /**
65
+ * Bumped whenever this node's local set changes OR any descendant bd node's
66
+ * set changes (the change event bubbles through here). Use this as a compute
67
+ * input so a node recomputes when anything in its subtree changes.
68
+ */
69
+ get revision() {
70
+ return this._revision;
71
+ }
72
+ get localElements() {
73
+ return [...this._localScans.keys()];
74
+ }
75
+ get localActionScans() {
76
+ return [...this._localScans.values()];
77
+ }
78
+ get localOptionSeed() {
79
+ return this._localOptionSeed;
80
+ }
81
+ setLocalOptionSeed(option) {
82
+ if (Object.is(this._localOptionSeed, option)) {
83
+ return;
84
+ }
85
+ this._localOptionSeed = option;
86
+ this._emitChanged();
87
+ }
88
+ /**
89
+ * Signal that this node's logical subtree shape changed (a bd child node
90
+ * connected or disconnected) rather than an individual action element.
91
+ *
92
+ * Membership is recomputed lazily by the owning element, so this only needs
93
+ * to bump the revision and notify ancestors. The owning element calls this
94
+ * from its onBdChildConnected / onBdChildDisconnected hooks, which fire while
95
+ * this node is still connected even as a child subtree is torn down.
96
+ */
97
+ markSubtreeChanged() {
98
+ this._emitChanged();
99
+ }
100
+ hostConnected() {
101
+ if (this._listening) {
102
+ return;
103
+ }
104
+ this.host.addEventListener(BD_ACTION_CONNECT_EVENT, this._onActionConnect);
105
+ this.host.addEventListener(BD_ACTION_DISCONNECT_EVENT, this._onActionDisconnect);
106
+ this.host.addEventListener(BD_ACTION_UPDATE_EVENT, this._onActionUpdate);
107
+ this.host.addEventListener(BD_ACTION_TOPOLOGY_CHANGED_EVENT, this._onTopologyChanged);
108
+ this._listening = true;
109
+ }
110
+ hostDisconnected() {
111
+ if (!this._listening) {
112
+ return;
113
+ }
114
+ this.host.removeEventListener(BD_ACTION_CONNECT_EVENT, this._onActionConnect);
115
+ this.host.removeEventListener(BD_ACTION_DISCONNECT_EVENT, this._onActionDisconnect);
116
+ this.host.removeEventListener(BD_ACTION_UPDATE_EVENT, this._onActionUpdate);
117
+ this.host.removeEventListener(BD_ACTION_TOPOLOGY_CHANGED_EVENT, this._onTopologyChanged);
118
+ this._listening = false;
119
+ this._localScans.clear();
120
+ this._localOptionSeed = undefined;
121
+ }
122
+ _emitChanged() {
123
+ dispatchBdActionTopologyChanged(this.host);
124
+ }
125
+ }
126
+ function sameComputeScan(a, b) {
127
+ return (JSON.stringify(a.staticCommands) === JSON.stringify(b.staticCommands) &&
128
+ JSON.stringify(a.domains) === JSON.stringify(b.domains));
129
+ }
130
+ //# sourceMappingURL=controller.action-topology.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.action-topology.js","sourceRoot":"","sources":["../../../src/controllers/controller.action-topology.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ReactiveController,\n ReactiveControllerHost\n} from 'lit';\n\nimport {\n type BdComputeScan\n} from '@/compute/compute.scan.js';\nimport {\n BD_ACTION_CONNECT_EVENT,\n BD_ACTION_DISCONNECT_EVENT,\n BD_ACTION_TOPOLOGY_CHANGED_EVENT,\n BD_ACTION_UPDATE_EVENT,\n dispatchBdActionTopologyChanged,\n type BdActionConnectDetail,\n type BdActionDisconnectDetail,\n type BdActionUpdateDetail\n} from '@/core/action-topology.js';\nimport type { ProductOption } from '@repobit/dex-store';\n\nexport interface BdActionTopologyHost\n extends ReactiveControllerHost, EventTarget {\n readonly topologyBoundary?: boolean;\n}\n\n/**\n * Owns the set of native action elements that belong to a single bd node.\n *\n * Membership is fed incrementally by BdActionElementAdapter announcements, so\n * no node ever rescans its DOM children. The nearest bd node catches\n * bd-action-connect / bd-action-disconnect, exactly like bd-action-request, so\n * an action's compute radius matches its runtime radius.\n *\n * Aggregation across the logical bd subtree is intentionally NOT done here. The\n * owning element walks its bd children (which it has access to) and unions\n * their local sets. This controller only owns local membership + a revision\n * that already reflects descendant changes via the bubbling topology event.\n */\nexport class BdActionTopologyController implements ReactiveController {\n private readonly _localScans = new Map<HTMLElement, BdComputeScan>();\n private _localOptionSeed?: ProductOption;\n private _revision = 0;\n private _listening = false;\n\n constructor(\n private readonly host: BdActionTopologyHost\n ) {\n host.addController(this);\n }\n\n /**\n * Bumped whenever this node's local set changes OR any descendant bd node's\n * set changes (the change event bubbles through here). Use this as a compute\n * input so a node recomputes when anything in its subtree changes.\n */\n get revision(): number {\n return this._revision;\n }\n\n get localElements(): readonly HTMLElement[] {\n return [...this._localScans.keys()];\n }\n\n get localActionScans(): readonly BdComputeScan[] {\n return [...this._localScans.values()];\n }\n\n get localOptionSeed(): ProductOption | undefined {\n return this._localOptionSeed;\n }\n\n setLocalOptionSeed(\n option: ProductOption | undefined\n ): void {\n if (Object.is(\n this._localOptionSeed,\n option\n )) {\n return;\n }\n\n this._localOptionSeed = option;\n this._emitChanged();\n }\n\n /**\n * Signal that this node's logical subtree shape changed (a bd child node\n * connected or disconnected) rather than an individual action element.\n *\n * Membership is recomputed lazily by the owning element, so this only needs\n * to bump the revision and notify ancestors. The owning element calls this\n * from its onBdChildConnected / onBdChildDisconnected hooks, which fire while\n * this node is still connected even as a child subtree is torn down.\n */\n markSubtreeChanged(): void {\n this._emitChanged();\n }\n\n hostConnected(): void {\n if (this._listening) {\n return;\n }\n\n this.host.addEventListener(\n BD_ACTION_CONNECT_EVENT,\n this._onActionConnect as EventListener\n );\n\n this.host.addEventListener(\n BD_ACTION_DISCONNECT_EVENT,\n this._onActionDisconnect as EventListener\n );\n\n this.host.addEventListener(\n BD_ACTION_UPDATE_EVENT,\n this._onActionUpdate as EventListener\n );\n\n this.host.addEventListener(\n BD_ACTION_TOPOLOGY_CHANGED_EVENT,\n this._onTopologyChanged as EventListener\n );\n\n this._listening = true;\n }\n\n hostDisconnected(): void {\n if (!this._listening) {\n return;\n }\n\n this.host.removeEventListener(\n BD_ACTION_CONNECT_EVENT,\n this._onActionConnect as EventListener\n );\n\n this.host.removeEventListener(\n BD_ACTION_DISCONNECT_EVENT,\n this._onActionDisconnect as EventListener\n );\n\n this.host.removeEventListener(\n BD_ACTION_UPDATE_EVENT,\n this._onActionUpdate as EventListener\n );\n\n this.host.removeEventListener(\n BD_ACTION_TOPOLOGY_CHANGED_EVENT,\n this._onTopologyChanged as EventListener\n );\n\n this._listening = false;\n this._localScans.clear();\n this._localOptionSeed = undefined;\n }\n\n private readonly _onActionConnect = (\n event: CustomEvent<BdActionConnectDetail>\n ): void => {\n /**\n * Nearest bd node wins ownership; do not let outer nodes also claim it.\n */\n event.stopPropagation();\n\n event.detail.claim(this.host);\n this._localScans.set(\n event.detail.element,\n event.detail.scan\n );\n\n this._emitChanged();\n };\n\n private readonly _onActionDisconnect = (\n event: CustomEvent<BdActionDisconnectDetail>\n ): void => {\n event.stopPropagation();\n\n if (!this._localScans.delete(event.detail.element)) {\n return;\n }\n\n this._emitChanged();\n };\n\n private readonly _onActionUpdate = (\n event: CustomEvent<BdActionUpdateDetail>\n ): void => {\n event.stopPropagation();\n\n if (!this._localScans.has(event.detail.element)) {\n return;\n }\n\n const previous =\n this._localScans.get(event.detail.element);\n\n if (\n previous &&\n sameComputeScan(\n previous,\n event.detail.scan\n )\n ) {\n return;\n }\n\n this._localScans.set(\n event.detail.element,\n event.detail.scan\n );\n\n this._emitChanged();\n };\n\n /**\n * Fires on this node (target phase) and every ancestor (bubbling) for a\n * single change. Each node bumps its own revision exactly once, which is why\n * local changes also flow through here instead of bumping directly.\n */\n private readonly _onTopologyChanged = (\n event: Event\n ): void => {\n this._revision++;\n this.host.requestUpdate();\n\n if (this.host.topologyBoundary === true) {\n event.stopPropagation();\n }\n };\n\n private _emitChanged(): void {\n dispatchBdActionTopologyChanged(this.host);\n }\n}\n\nfunction sameComputeScan(\n a: BdComputeScan,\n b: BdComputeScan\n): boolean {\n return (\n JSON.stringify(a.staticCommands) === JSON.stringify(b.staticCommands) &&\n JSON.stringify(a.domains) === JSON.stringify(b.domains)\n );\n}\n"]}
@@ -0,0 +1,72 @@
1
+ import { type BdComputeResult } from '../compute/compute.expand.js';
2
+ import { type BdComputeScan } from '../compute/compute.scan.js';
3
+ import type { ProductOption, Store } from '@repobit/dex-store';
4
+ import type { ReactiveController } from 'lit';
5
+ import { type BdResolveHost } from './controller.resolve.js';
6
+ export declare const BD_COMPUTE_CHANGED_EVENT: "bd-compute-changed";
7
+ export type BdComputeChangedDetail = Readonly<{
8
+ result?: BdComputeResult;
9
+ }>;
10
+ declare global {
11
+ interface HTMLElementEventMap {
12
+ [BD_COMPUTE_CHANGED_EVENT]: CustomEvent<BdComputeChangedDetail>;
13
+ }
14
+ }
15
+ /**
16
+ * Host requirements for the compute controller. Any BdNodeElement satisfies
17
+ * this: it tracks local work, is an EventTarget, can query its own subtree, and
18
+ * exposes the incremental action topology.
19
+ */
20
+ export interface BdComputeHost extends BdResolveHost, EventTarget, ParentNode {
21
+ readonly actionTopologyRevision: number;
22
+ collectActionScans(): BdComputeScan[];
23
+ collectOptionSeeds(): ProductOption[];
24
+ }
25
+ export interface BdComputeOptions {
26
+ name?: string;
27
+ /**
28
+ * The store used to resolve products. Usually `() => this.scope?.store`.
29
+ */
30
+ store: () => Store | undefined;
31
+ /**
32
+ * Global/local compute switch. Disabled compute publishes an undefined result.
33
+ */
34
+ enabled?: () => boolean;
35
+ /**
36
+ * Extra change signal mixed into the task args. Defaults to the host's action
37
+ * topology revision, which already bumps on action and bd-subtree changes.
38
+ */
39
+ revision?: () => number;
40
+ /**
41
+ * Safety cap on the fixed-point search size.
42
+ */
43
+ maxScenarios?: number;
44
+ onResult?: (result: BdComputeResult | undefined) => void;
45
+ }
46
+ /**
47
+ * Dry-run min/max price compute over every product/option combination reachable
48
+ * from a bd node boundary.
49
+ *
50
+ * It never dispatches bd-action-request. It reads resolved option seeds and
51
+ * collected action declarations from topology, expands them against the same
52
+ * command shapes the runtime would honor, and reduces price. Reruns are driven
53
+ * by the store scope, the resolved seed set, and the action topology revision.
54
+ */
55
+ export declare class BdComputeController implements ReactiveController {
56
+ private readonly host;
57
+ private readonly options;
58
+ result?: BdComputeResult;
59
+ private readonly _resolver;
60
+ constructor(host: BdComputeHost, options: BdComputeOptions);
61
+ hostConnected(): void;
62
+ hostDisconnected(): void;
63
+ get pending(): boolean;
64
+ get complete(): boolean;
65
+ get failed(): boolean;
66
+ get error(): unknown;
67
+ run(): Promise<BdComputeResult | undefined>;
68
+ private _compute;
69
+ private _publish;
70
+ private _revision;
71
+ private _enabled;
72
+ }