@wirestate/lit 0.6.0 → 0.6.1

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 (98) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +245 -9
  3. package/cjs/development/index.js +774 -51
  4. package/cjs/development/index.js.map +1 -1
  5. package/cjs/production/index.js +1 -1
  6. package/cjs/production/index.js.map +1 -1
  7. package/esm/development/commands/on-command-controller.js +58 -0
  8. package/esm/development/commands/on-command-controller.js.map +1 -0
  9. package/esm/development/commands/on-command.js +45 -0
  10. package/esm/development/commands/on-command.js.map +1 -0
  11. package/esm/development/commands/use-on-command.js +31 -0
  12. package/esm/development/commands/use-on-command.js.map +1 -0
  13. package/esm/development/consumption/injection.js +40 -6
  14. package/esm/development/consumption/injection.js.map +1 -1
  15. package/esm/development/consumption/use-injection.js +38 -4
  16. package/esm/development/consumption/use-injection.js.map +1 -1
  17. package/esm/development/context/ioc-context.js +10 -0
  18. package/esm/development/context/ioc-context.js.map +1 -1
  19. package/esm/development/error/error-code.js +4 -0
  20. package/esm/development/error/error-code.js.map +1 -0
  21. package/esm/development/events/on-event-controller.js +66 -0
  22. package/esm/development/events/on-event-controller.js.map +1 -0
  23. package/esm/development/events/on-event.js +65 -0
  24. package/esm/development/events/on-event.js.map +1 -0
  25. package/esm/development/events/use-on-events.js +42 -0
  26. package/esm/development/events/use-on-events.js.map +1 -0
  27. package/esm/development/index.js +15 -3
  28. package/esm/development/index.js.map +1 -1
  29. package/esm/development/provision/injectables-provide.js +47 -0
  30. package/esm/development/provision/injectables-provide.js.map +1 -0
  31. package/esm/development/provision/injectables-provider-controller.js +123 -0
  32. package/esm/development/provision/injectables-provider-controller.js.map +1 -0
  33. package/esm/development/provision/ioc-provide.js +55 -0
  34. package/esm/development/provision/ioc-provide.js.map +1 -0
  35. package/esm/development/provision/ioc-provider-controller.js +72 -0
  36. package/esm/development/provision/ioc-provider-controller.js.map +1 -0
  37. package/esm/development/provision/use-injectables-provider.js +33 -0
  38. package/esm/development/provision/use-injectables-provider.js.map +1 -0
  39. package/esm/development/provision/use-ioc-provision.js +29 -0
  40. package/esm/development/provision/use-ioc-provision.js.map +1 -0
  41. package/esm/development/queries/on-query-controller.js +58 -0
  42. package/esm/development/queries/on-query-controller.js.map +1 -0
  43. package/esm/development/queries/on-query.js +45 -0
  44. package/esm/development/queries/on-query.js.map +1 -0
  45. package/esm/development/queries/use-on-query.js +31 -0
  46. package/esm/development/queries/use-on-query.js.map +1 -0
  47. package/esm/production/commands/on-command-controller.js +1 -0
  48. package/esm/production/commands/on-command-controller.js.map +1 -0
  49. package/esm/production/commands/on-command.js +1 -0
  50. package/esm/production/commands/on-command.js.map +1 -0
  51. package/esm/production/commands/use-on-command.js +1 -0
  52. package/esm/production/commands/use-on-command.js.map +1 -0
  53. package/esm/production/consumption/injection.js +1 -1
  54. package/esm/production/consumption/injection.js.map +1 -1
  55. package/esm/production/consumption/use-injection.js +1 -1
  56. package/esm/production/consumption/use-injection.js.map +1 -1
  57. package/esm/production/context/ioc-context.js.map +1 -1
  58. package/esm/production/error/error-code.js +1 -0
  59. package/esm/production/error/error-code.js.map +1 -0
  60. package/esm/production/events/on-event-controller.js +1 -0
  61. package/esm/production/events/on-event-controller.js.map +1 -0
  62. package/esm/production/events/on-event.js +1 -0
  63. package/esm/production/events/on-event.js.map +1 -0
  64. package/esm/production/events/use-on-events.js +1 -0
  65. package/esm/production/events/use-on-events.js.map +1 -0
  66. package/esm/production/index.js +1 -1
  67. package/esm/production/provision/injectables-provide.js +1 -0
  68. package/esm/production/provision/injectables-provide.js.map +1 -0
  69. package/esm/production/provision/injectables-provider-controller.js +1 -0
  70. package/esm/production/provision/injectables-provider-controller.js.map +1 -0
  71. package/esm/production/provision/ioc-provide.js +1 -0
  72. package/esm/production/provision/ioc-provide.js.map +1 -0
  73. package/esm/production/provision/ioc-provider-controller.js +1 -0
  74. package/esm/production/provision/ioc-provider-controller.js.map +1 -0
  75. package/esm/production/provision/use-injectables-provider.js +1 -0
  76. package/esm/production/provision/use-injectables-provider.js.map +1 -0
  77. package/esm/production/provision/use-ioc-provision.js +1 -0
  78. package/esm/production/provision/use-ioc-provision.js.map +1 -0
  79. package/esm/production/queries/on-query-controller.js +1 -0
  80. package/esm/production/queries/on-query-controller.js.map +1 -0
  81. package/esm/production/queries/on-query.js +1 -0
  82. package/esm/production/queries/on-query.js.map +1 -0
  83. package/esm/production/queries/use-on-query.js +1 -0
  84. package/esm/production/queries/use-on-query.js.map +1 -0
  85. package/index.d.ts +702 -28
  86. package/package.json +1 -1
  87. package/esm/development/provision/container-provider-controller.js +0 -41
  88. package/esm/development/provision/container-provider-controller.js.map +0 -1
  89. package/esm/development/provision/services-provider-controller.js +0 -63
  90. package/esm/development/provision/services-provider-controller.js.map +0 -1
  91. package/esm/development/provision/use-container-provision.js +0 -9
  92. package/esm/development/provision/use-container-provision.js.map +0 -1
  93. package/esm/production/provision/container-provider-controller.js +0 -1
  94. package/esm/production/provision/container-provider-controller.js.map +0 -1
  95. package/esm/production/provision/services-provider-controller.js +0 -1
  96. package/esm/production/provision/services-provider-controller.js.map +0 -1
  97. package/esm/production/provision/use-container-provision.js +0 -1
  98. package/esm/production/provision/use-container-provision.js.map +0 -1
@@ -2,14 +2,60 @@
2
2
 
3
3
  var context = require('@lit/context');
4
4
  var core = require('@wirestate/core');
5
+ var tslib = require('tslib');
5
6
 
7
+ /**
8
+ * Context key for the IoC container.
9
+ *
10
+ * @group context
11
+ */
6
12
  var IOC_CONTAINER_KEY = Symbol("ContainerContext");
13
+ /**
14
+ * Lit context for providing and consuming the IoC container.
15
+ *
16
+ * @group context
17
+ */
7
18
  var ContainerContext = context.createContext(IOC_CONTAINER_KEY);
8
19
 
9
- function injection(_a) {
10
- var injectionId = _a.injectionId,
11
- subscribe = _a.subscribe;
20
+ /**
21
+ * Decorator to inject a service from the IoC container into a Lit element property.
22
+ *
23
+ * @group consumption
24
+ *
25
+ * @param optionsOrInjectionId - injection options including the service identifier or the service identifier itself
26
+ * @returns injection decorator instance
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * class MyElement extends LitElement {
31
+ * @injection(MyService)
32
+ * private myService!: MyService;
33
+ *
34
+ * public render() {
35
+ * return html`<div>${this.myService.getName()}</div>`;
36
+ * }
37
+ * }
38
+ * ```
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * class MyElement extends LitElement {
43
+ * @injection({ injectionId: MyService, once: true })
44
+ * private myService!: MyService;
45
+ *
46
+ * public render() {
47
+ * return html`<div>${this.myService.getName()}</div>`;
48
+ * }
49
+ * }
50
+ * ```
51
+ */
52
+ function injection(optionsOrInjectionId) {
53
+ var options = typeof optionsOrInjectionId === "object" && optionsOrInjectionId !== null && "injectionId" in optionsOrInjectionId ? optionsOrInjectionId : {
54
+ injectionId: optionsOrInjectionId
55
+ };
12
56
  return function (protoOrTarget, nameOrContext) {
57
+ var injectionId = options.injectionId,
58
+ once = options.once;
13
59
  // Standard decorators branch.
14
60
  if (typeof nameOrContext === "object") {
15
61
  nameOrContext.addInitializer(function () {
@@ -19,7 +65,7 @@ function injection(_a) {
19
65
  callback: function (it) {
20
66
  protoOrTarget.set.call(_this, it.container.get(injectionId));
21
67
  },
22
- subscribe: subscribe
68
+ subscribe: !once
23
69
  });
24
70
  });
25
71
  } else {
@@ -28,20 +74,53 @@ function injection(_a) {
28
74
  new context.ContextConsumer(element, {
29
75
  context: ContainerContext,
30
76
  callback: function (it) {
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
77
  element[nameOrContext] = it.container.get(injectionId);
33
78
  },
34
- subscribe: subscribe
79
+ subscribe: !once
35
80
  });
36
81
  });
37
82
  }
38
83
  };
39
84
  }
40
85
 
41
- function useInjection(host, _a) {
42
- var once = _a.once,
43
- injectionId = _a.injectionId,
44
- value = _a.value;
86
+ /**
87
+ * Hook (controller) to inject a service from the IoC container in a Lit component.
88
+ *
89
+ * @group consumption
90
+ *
91
+ * @param host - the host element
92
+ * @param optionsOrInjectionId - injection options including the service identifier or the service identifier itself
93
+ * @returns injection descriptor object
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * class MyElement extends LitElement {
98
+ * private myService = useInjection(this, MyService);
99
+ *
100
+ * render() {
101
+ * return html`<div>${this.myService.value.getName()}</div>`;
102
+ * }
103
+ * }
104
+ * ```
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * class MyElement extends LitElement {
109
+ * private myService = useInjection(this, { injectionId: MyService, once: true });
110
+ *
111
+ * render() {
112
+ * return html`<div>${this.myService.value.getName()}</div>`;
113
+ * }
114
+ * }
115
+ * ```
116
+ */
117
+ function useInjection(host, optionsOrInjectionId) {
118
+ var options = typeof optionsOrInjectionId === "object" && optionsOrInjectionId !== null && "injectionId" in optionsOrInjectionId ? optionsOrInjectionId : {
119
+ injectionId: optionsOrInjectionId
120
+ };
121
+ var once = options.once,
122
+ injectionId = options.injectionId,
123
+ value = options.value;
45
124
  var current = {
46
125
  value: value,
47
126
  injectionId: injectionId
@@ -56,13 +135,427 @@ function useInjection(host, _a) {
56
135
  return current;
57
136
  }
58
137
 
59
- var ContainerProviderController = /** @class */function () {
60
- function ContainerProviderController(host, container) {
138
+ /**
139
+ * Reactive controller that registers a command handler on the {@link CommandBus} for the host element's lifetime.
140
+ *
141
+ * The handler is registered when the host connects and unregistered when it disconnects.
142
+ * When the IoC context is updated (container revision change), the handler is re-registered automatically.
143
+ *
144
+ * @group commands
145
+ */
146
+ var OnCommandController = /** @class */function () {
147
+ /**
148
+ * @param host - The host element.
149
+ * @param type - The command type to handle.
150
+ * @param handler - The command handler function.
151
+ */
152
+ function OnCommandController(host, type, handler) {
153
+ var _this = this;
154
+ this.bus = null;
155
+ this.unregister = null;
156
+ host.addController(this);
157
+ this.type = type;
158
+ this.handler = handler;
159
+ new context.ContextConsumer(host, {
160
+ context: ContainerContext,
161
+ subscribe: true,
162
+ callback: function (context) {
163
+ _this.bus = context.container.get(core.CommandBus);
164
+ if (host.isConnected) {
165
+ _this.reregister();
166
+ }
167
+ }
168
+ });
169
+ }
170
+ OnCommandController.prototype.hostConnected = function () {
171
+ this.reregister();
172
+ };
173
+ OnCommandController.prototype.hostDisconnected = function () {
174
+ this.cleanup();
175
+ };
176
+ OnCommandController.prototype.reregister = function () {
177
+ this.cleanup();
178
+ if (this.bus) {
179
+ this.unregister = this.bus.register(this.type, this.handler);
180
+ }
181
+ };
182
+ OnCommandController.prototype.cleanup = function () {
183
+ var _a;
184
+ (_a = this.unregister) === null || _a === void 0 ? void 0 : _a.call(this);
185
+ this.unregister = null;
186
+ };
187
+ return OnCommandController;
188
+ }();
189
+
190
+ /**
191
+ * Decorator that registers a Lit element method as a command handler for the given type.
192
+ *
193
+ * The handler is registered when the host element connects to the DOM and unregistered when it disconnects.
194
+ *
195
+ * @group commands
196
+ *
197
+ * @param type - the command type to handle
198
+ * @returns the decorator function.
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * class MyElement extends LitElement {
203
+ * @onCommand("SAVE")
204
+ * private handleSave(data: SomeData): void {
205
+ * // handle command
206
+ * }
207
+ * }
208
+ * ```
209
+ */
210
+ function onCommand(type) {
211
+ return function (protoOrTarget, nameOrContext) {
212
+ if (typeof nameOrContext === "object") {
213
+ // Standard decorators:
214
+ nameOrContext.addInitializer(function () {
215
+ var _this = this;
216
+ new OnCommandController(this, type, function (data) {
217
+ return _this[nameOrContext.name](data);
218
+ });
219
+ });
220
+ } else {
221
+ // Experimental legacy decorators:
222
+ protoOrTarget.constructor.addInitializer(function (element) {
223
+ new OnCommandController(element, type, function (data) {
224
+ return element[nameOrContext](data);
225
+ });
226
+ });
227
+ }
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Registers a command handler on the CommandBus for the host element's lifetime.
233
+ *
234
+ * @group commands
235
+ *
236
+ * @param host - the host element
237
+ * @param options - command handling options
238
+ * @param options.type - the command type to listen for
239
+ * @param options.handler - the command handler function
240
+ * @returns the command controller instance
241
+ *
242
+ * @example
243
+ * ```typescript
244
+ * class MyElement extends LitElement {
245
+ * private onSave = useOnCommand(this, {
246
+ * type: "SAVE",
247
+ * handler: (data) => console.log("Saving:", data),
248
+ * });
249
+ * }
250
+ * ```
251
+ */
252
+ function useOnCommand(host, _a) {
253
+ var type = _a.type,
254
+ handler = _a.handler;
255
+ return new OnCommandController(host, type, handler);
256
+ }
257
+
258
+ /**
259
+ * Controller that subscribes to events from the event bus.
260
+ *
261
+ * It automatically handles subscription and unsubscription based on the host element's lifecycle.
262
+ *
263
+ * @group events
264
+ */
265
+ var OnEventController = /** @class */function () {
266
+ /**
267
+ * @param host - the host element
268
+ * @param types - event types to listen for, if null, all events will be handled
269
+ * @param handler - the event handler function
270
+ */
271
+ function OnEventController(host, types, handler) {
272
+ var _this = this;
273
+ this.bus = null;
274
+ this.unsubscriber = null;
275
+ host.addController(this);
276
+ this.types = types;
277
+ this.handler = handler;
278
+ new context.ContextConsumer(host, {
279
+ context: ContainerContext,
280
+ subscribe: true,
281
+ callback: function (context) {
282
+ _this.bus = context.container.get(core.EventBus);
283
+ if (host.isConnected) {
284
+ _this.resubscribe();
285
+ }
286
+ }
287
+ });
288
+ }
289
+ OnEventController.prototype.hostConnected = function () {
290
+ this.resubscribe();
291
+ };
292
+ OnEventController.prototype.hostDisconnected = function () {
293
+ this.cleanup();
294
+ };
295
+ OnEventController.prototype.resubscribe = function () {
296
+ var _this = this;
297
+ this.cleanup();
298
+ if (this.bus) {
299
+ if (this.types === null) {
300
+ this.unsubscriber = this.bus.subscribe(this.handler);
301
+ } else {
302
+ this.unsubscriber = this.bus.subscribe(function (event) {
303
+ if (_this.types.includes(event.type)) {
304
+ _this.handler(event);
305
+ }
306
+ });
307
+ }
308
+ }
309
+ };
310
+ OnEventController.prototype.cleanup = function () {
311
+ var _a;
312
+ (_a = this.unsubscriber) === null || _a === void 0 ? void 0 : _a.call(this);
313
+ this.unsubscriber = null;
314
+ };
315
+ return OnEventController;
316
+ }();
317
+
318
+ /**
319
+ * Decorator to handle events from the event bus.
320
+ *
321
+ * @group events
322
+ *
323
+ * @param types - Event types to listen for. If omitted, all events will be handled.
324
+ * @returns The decorator function.
325
+ *
326
+ * @example
327
+ * ```typescript
328
+ * class MyElement extends LitElement {
329
+ * @onEvent()
330
+ * private onMyEvent(event: Event) {
331
+ * console.log('Event received:', event);
332
+ * }
333
+ * }
334
+ * ```
335
+ *
336
+ * @example
337
+ * ```typescript
338
+ * class MyElement extends LitElement {
339
+ * @onEvent('MY_EVENT_TYPE')
340
+ * private onMyEvent(event: MyEvent) {
341
+ * console.log('Event received:', event);
342
+ * }
343
+ * }
344
+ * ```
345
+ *
346
+ * @example
347
+ * ```typescript
348
+ * class MyElement extends LitElement {
349
+ * @onEvent(['MY_EVENT_TYPE_1', 'MY_EVENT_TYPE_2'])
350
+ * private onMyEvent(event: Event) {
351
+ * console.log('Event received:', event);
352
+ * }
353
+ * }
354
+ * ```
355
+ */
356
+ function onEvent(types) {
357
+ var normalized = types === undefined ? null : Array.isArray(types) ? tslib.__spreadArray([], types, true) : [types];
358
+ return function (protoOrTarget, nameOrContext) {
359
+ if (typeof nameOrContext === "object") {
360
+ // Standard decorators:
361
+ nameOrContext.addInitializer(function () {
362
+ var _this = this;
363
+ new OnEventController(this, normalized, function (event) {
364
+ return _this[nameOrContext.name](event);
365
+ });
366
+ });
367
+ } else {
368
+ // Experimental legacy decorators:
369
+ protoOrTarget.constructor.addInitializer(function (element) {
370
+ new OnEventController(element, normalized, function (event) {
371
+ return element[nameOrContext](event);
372
+ });
373
+ });
374
+ }
375
+ };
376
+ }
377
+
378
+ /**
379
+ * Hook (controller) to handle events from the event bus.
380
+ *
381
+ * @group events
382
+ *
383
+ * @param host - the host element
384
+ * @param options - event handling options
385
+ * @param options.handler - event handler function
386
+ * @param options.types - event types to listen for, if null or undefined, all events will be handled
387
+ * @returns events subscription controller
388
+ *
389
+ * @example
390
+ * ```typescript
391
+ * class MyElement extends LitElement {
392
+ * private eventHandler = useOnEvents(this, {
393
+ * handler: (event) => console.log(event),
394
+ * });
395
+ * }
396
+ * ```
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * class MyElement extends LitElement {
401
+ * private eventHandler = useOnEvents(this, {
402
+ * types: [MyEvent],
403
+ * handler: (event) => console.log(event),
404
+ * });
405
+ * }
406
+ * ```
407
+ */
408
+ function useOnEvents(host, _a) {
409
+ var types = _a.types,
410
+ handler = _a.handler;
411
+ var normalized = types ? Array.isArray(types) ? tslib.__spreadArray([], types, true) : [types] : null;
412
+ return new OnEventController(host, normalized, handler);
413
+ }
414
+
415
+ /**
416
+ * Reactive controller that registers a query handler on the {@link QueryBus} for the host element's lifetime.
417
+ *
418
+ * The handler is registered when the host connects and unregistered when it disconnects.
419
+ * When the IoC context is updated (container revision change), the handler is re-registered automatically.
420
+ *
421
+ * @group queries
422
+ */
423
+ var OnQueryController = /** @class */function () {
424
+ /**
425
+ * @param host - the host element
426
+ * @param type - the query type to handle
427
+ * @param handler - the query handler function
428
+ */
429
+ function OnQueryController(host, type, handler) {
430
+ var _this = this;
431
+ this.bus = null;
432
+ this.unregister = null;
433
+ host.addController(this);
434
+ this.type = type;
435
+ this.handler = handler;
436
+ new context.ContextConsumer(host, {
437
+ context: ContainerContext,
438
+ subscribe: true,
439
+ callback: function (context) {
440
+ _this.bus = context.container.get(core.QueryBus);
441
+ if (host.isConnected) {
442
+ _this.reregister();
443
+ }
444
+ }
445
+ });
446
+ }
447
+ OnQueryController.prototype.hostConnected = function () {
448
+ this.reregister();
449
+ };
450
+ OnQueryController.prototype.hostDisconnected = function () {
451
+ this.cleanup();
452
+ };
453
+ OnQueryController.prototype.reregister = function () {
454
+ this.cleanup();
455
+ if (this.bus) {
456
+ this.unregister = this.bus.register(this.type, this.handler);
457
+ }
458
+ };
459
+ OnQueryController.prototype.cleanup = function () {
460
+ var _a;
461
+ (_a = this.unregister) === null || _a === void 0 ? void 0 : _a.call(this);
462
+ this.unregister = null;
463
+ };
464
+ return OnQueryController;
465
+ }();
466
+
467
+ /**
468
+ * Decorator that registers a Lit element method as a query handler for the given type.
469
+ *
470
+ * The handler is registered when the host element connects to the DOM and unregistered when it disconnects.
471
+ *
472
+ * @group queries
473
+ *
474
+ * @param type - the query type to handle
475
+ * @returns the decorator function
476
+ *
477
+ * @example
478
+ * ```typescript
479
+ * class MyElement extends LitElement {
480
+ * @onQuery("GET_USER_NAME")
481
+ * public onGetUserName(data: QueryData) {
482
+ * return "Alice";
483
+ * }
484
+ * }
485
+ * ```
486
+ */
487
+ function onQuery(type) {
488
+ return function (protoOrTarget, nameOrContext) {
489
+ if (typeof nameOrContext === "object") {
490
+ // Standard decorators:
491
+ nameOrContext.addInitializer(function () {
492
+ var _this = this;
493
+ new OnQueryController(this, type, function (data) {
494
+ return _this[nameOrContext.name](data);
495
+ });
496
+ });
497
+ } else {
498
+ // Experimental legacy decorators:
499
+ protoOrTarget.constructor.addInitializer(function (element) {
500
+ new OnQueryController(element, type, function (data) {
501
+ return element[nameOrContext](data);
502
+ });
503
+ });
504
+ }
505
+ };
506
+ }
507
+
508
+ /**
509
+ * Registers a query handler on the {@link QueryBus} for the host element's lifetime.
510
+ *
511
+ * @group queries
512
+ *
513
+ * @param host - the host element
514
+ * @param options - query handling options
515
+ * @param options.type - the query type to handle
516
+ * @param options.handler - the query handler function
517
+ * @returns the query controller instance
518
+ *
519
+ * @example
520
+ * ```typescript
521
+ * class MyElement extends LitElement {
522
+ * private getUserController = useOnQuery(this, {
523
+ * type: "GET_USER",
524
+ * handler: (data) => ({ name: "Alice" }),
525
+ * });
526
+ * }
527
+ * ```
528
+ */
529
+ function useOnQuery(host, _a) {
530
+ var type = _a.type,
531
+ handler = _a.handler;
532
+ return new OnQueryController(host, type, handler);
533
+ }
534
+
535
+ /**
536
+ * Controller that provides an IoC container context to the host element and its children.
537
+ *
538
+ * It manages the lifecycle of the container and handles revision updates to notify consumers.
539
+ *
540
+ * @group provision
541
+ */
542
+ var IocProviderController = /** @class */function () {
543
+ /**
544
+ * @param host - the host element
545
+ * @param options - provisioning options
546
+ * @param options.container - optional existing container to use. If not provided, a new one will be created
547
+ * @param options.seed - optional seed data to apply to the container
548
+ */
549
+ function IocProviderController(host, _a) {
550
+ var _b = _a === void 0 ? {} : _a,
551
+ container = _b.container,
552
+ seed = _b.seed;
61
553
  var _this = this;
62
554
  this.host = host;
63
555
  this.revision = 1;
64
556
  this.host.addController(this);
65
557
  this.container = container !== null && container !== void 0 ? container : core.createIocContainer();
558
+ this.seed = seed;
66
559
  this.provider = new context.ContextProvider(host, {
67
560
  context: ContainerContext,
68
561
  initialValue: {
@@ -74,9 +567,23 @@ var ContainerProviderController = /** @class */function () {
74
567
  }
75
568
  });
76
569
  }
77
- ContainerProviderController.prototype.hostConnected = function () {};
78
- ContainerProviderController.prototype.hostDisconnected = function () {};
79
- ContainerProviderController.prototype.nextRevision = function () {
570
+ Object.defineProperty(IocProviderController.prototype, "value", {
571
+ /**
572
+ * @returns current {@link IocContext} value served to child consumers
573
+ */
574
+ get: function () {
575
+ return this.provider.value;
576
+ },
577
+ enumerable: false,
578
+ configurable: true
579
+ });
580
+ IocProviderController.prototype.hostConnected = function () {
581
+ if (this.seed) {
582
+ core.applySharedSeed(this.container, this.seed);
583
+ }
584
+ };
585
+ IocProviderController.prototype.hostDisconnected = function () {};
586
+ IocProviderController.prototype.nextRevision = function () {
80
587
  var _this = this;
81
588
  this.revision += 1;
82
589
  this.provider.setValue({
@@ -88,34 +595,148 @@ var ContainerProviderController = /** @class */function () {
88
595
  });
89
596
  return this.revision;
90
597
  };
91
- return ContainerProviderController;
598
+ return IocProviderController;
92
599
  }();
93
600
 
94
- var ServicesProviderController = /** @class */function () {
95
- function ServicesProviderController(host, options) {
601
+ /**
602
+ * Decorator to provide an IoC container to child components.
603
+ *
604
+ * @group provision
605
+ *
606
+ * @param options - provisioning options including container and seed data
607
+ * @param options.container - optional existing container to use, if not provided, a new one will be created
608
+ * @param options.seed - optional seed data to apply to the container
609
+ * @returns IOC provision controller instance
610
+ *
611
+ * @example
612
+ * ```typescript
613
+ * class MyRootElement extends LitElement {
614
+ * @iocProvide({ seed: { someData: 'value' } })
615
+ * private ioc!: IocProviderController;
616
+ * }
617
+ * ```
618
+ */
619
+ function iocProvide(_a) {
620
+ var _b = _a === void 0 ? {} : _a,
621
+ container = _b.container,
622
+ seed = _b.seed;
623
+ return function (protoOrTarget, nameOrContext) {
624
+ if (typeof nameOrContext === "object") {
625
+ // Standard decorators:
626
+ nameOrContext.addInitializer(function () {
627
+ protoOrTarget.set.call(this, new IocProviderController(this, {
628
+ container: container,
629
+ seed: seed
630
+ }));
631
+ });
632
+ } else {
633
+ var controller_1;
634
+ protoOrTarget.constructor.addInitializer(function (element) {
635
+ controller_1 = new IocProviderController(element, {
636
+ container: container,
637
+ seed: seed
638
+ });
639
+ });
640
+ return {
641
+ get: function () {
642
+ return controller_1;
643
+ },
644
+ set: function () {},
645
+ configurable: true,
646
+ enumerable: true
647
+ };
648
+ }
649
+ };
650
+ }
651
+
652
+ var ERROR_CODE_INVALID_ARGUMENTS = 2051;
653
+
654
+ /**
655
+ * Controller that binds a set of injectables to an IoC container when the host connects
656
+ * and unbinds them when the host disconnects.
657
+ *
658
+ * When no `into` context is provided, the controller uses the nearest {@link IocProviderController}
659
+ * ancestor via Lit context. Seeds are applied before entries so that `@Inject(SEEDS_TOKEN)`
660
+ * works during service activation.
661
+ *
662
+ * @group provision
663
+ *
664
+ * @example
665
+ * ```typescript
666
+ * class MyComponent extends LitElement {
667
+ * private services = new InjectablesProviderController(this, {
668
+ * entries: [AuthService, UserService],
669
+ * activate: [AuthService],
670
+ * seeds: [[AuthService, { role: "admin" }]],
671
+ * });
672
+ * }
673
+ * ```
674
+ */
675
+ var InjectablesProviderController = /** @class */function () {
676
+ /**
677
+ * @param host - the host element
678
+ * @param options - provisioning options
679
+ * @param options.entries - list of service entries to bind to the container
680
+ * @param options.into - target IoC context; if omitted, uses the nearest provider context
681
+ * @param options.activate - list of service identifiers to activate immediately after binding
682
+ * @param options.seeds - seed data applied before binding
683
+ */
684
+ function InjectablesProviderController(host, options) {
685
+ var _this = this;
686
+ var _a, _b, _c;
96
687
  this.host = host;
688
+ /**
689
+ * Tracks the context to which entries are currently bound, for correct cleanup on disconnect.
690
+ */
691
+ this.boundContext = null;
97
692
  this.host.addController(this);
98
693
  this.entries = options.entries;
99
- this.activate = options.activate;
100
- this.seeds = options.seeds;
101
- this.into = options.into;
102
- this.consumer = new context.ContextConsumer(host, {
103
- context: ContainerContext,
104
- subscribe: true,
105
- callback: function (it) {
106
- return;
107
- }
108
- });
694
+ this.activate = (_a = options.activate) !== null && _a !== void 0 ? _a : null;
695
+ this.seeds = (_b = options.seeds) !== null && _b !== void 0 ? _b : null;
696
+ this.into = (_c = options.into) !== null && _c !== void 0 ? _c : null;
697
+ if (!this.into) {
698
+ // subscribe: false — binding happens once per connect, not on every revision update.
699
+ this.consumer = new context.ContextConsumer(host, {
700
+ context: ContainerContext,
701
+ subscribe: false,
702
+ callback: function (context) {
703
+ if (!host.isConnected) {
704
+ return;
705
+ }
706
+ _this.bind(context);
707
+ }
708
+ });
709
+ }
109
710
  }
110
- ServicesProviderController.prototype.hostConnected = function () {
111
- var context = this.into ? typeof this.into === "function" ? this.into() : this.into : this.consumer.value;
112
- if (!context) {
113
- if (this.consumer["provided"] === false) {
114
- throw new Error("not provided");
711
+ InjectablesProviderController.prototype.hostConnected = function () {
712
+ var _a;
713
+ if (!this.into) {
714
+ // ContextConsumer with subscribe:false only invokes the user callback once (provided flag stays true
715
+ // after disconnect). On reconnect we fall back to the cached consumer.value so bind() still fires.
716
+ if ((_a = this.consumer) === null || _a === void 0 ? void 0 : _a.value) {
717
+ this.bind(this.consumer.value);
115
718
  }
116
- throw new Error("todo");
719
+ return;
720
+ }
721
+ var context = typeof this.into === "function" ? this.into() : this.into;
722
+ if (!context) {
723
+ throw new core.WirestateError(ERROR_CODE_INVALID_ARGUMENTS, "InjectablesProviderController: the 'into' option resolved to null or undefined. " + "Ensure the value or resolver function returns a valid IocContext.");
724
+ }
725
+ this.bind(context);
726
+ };
727
+ InjectablesProviderController.prototype.hostDisconnected = function () {
728
+ if (!this.boundContext) {
729
+ return;
730
+ }
731
+ this.unbind(this.boundContext);
732
+ };
733
+ InjectablesProviderController.prototype.bind = function (context) {
734
+ if (this.boundContext) {
735
+ // Re-binding without unbinding first would leave stale entries; unbind the previous context.
736
+ this.unbind(this.boundContext);
117
737
  }
118
- // Seed must be applied BEFORE binding so @Inject(INITIAL_STATE_TOKEN) works during activation.
738
+ this.boundContext = context;
739
+ // Seeds must be applied before binding so @Inject(SEEDS_TOKEN) resolves during activation.
119
740
  if (this.seeds) {
120
741
  core.applySeeds(context.container, this.seeds);
121
742
  }
@@ -125,38 +746,140 @@ var ServicesProviderController = /** @class */function () {
125
746
  }
126
747
  if (this.activate) {
127
748
  for (var _b = 0, _c = this.activate; _b < _c.length; _b++) {
128
- var eager = _c[_b];
129
- context.container.get(eager);
749
+ var token = _c[_b];
750
+ context.container.get(token);
130
751
  }
131
752
  }
132
753
  };
133
- ServicesProviderController.prototype.hostDisconnected = function () {
134
- var context = this.into ? typeof this.into === "function" ? this.into() : this.into : this.consumer.value;
135
- if (!context) {
136
- throw new Error("todo");
137
- }
754
+ InjectablesProviderController.prototype.unbind = function (context) {
138
755
  for (var _i = 0, _a = this.entries; _i < _a.length; _i++) {
139
756
  var entry = _a[_i];
140
757
  var token = core.getEntryToken(entry);
141
- context.container.unbind(token);
758
+ if (context.container.isBound(token)) {
759
+ context.container.unbind(token);
760
+ }
142
761
  }
143
- // Remove only this provider's targeted initial state entries.
144
762
  if (this.seeds) {
145
763
  core.unapplySeeds(context.container, this.seeds);
146
764
  }
765
+ this.boundContext = null;
147
766
  };
148
- return ServicesProviderController;
767
+ return InjectablesProviderController;
149
768
  }();
150
769
 
151
- function useContainerProvision(host, _a) {
152
- var container = _a.container;
153
- return new ContainerProviderController(host, container);
770
+ /**
771
+ * Decorator that binds a set of injectables to the nearest IoC container for the host element's lifetime.
772
+ *
773
+ * Entries are bound when the host connects and unbound when it disconnects.
774
+ * The decorated accessor or property holds the resulting {@link InjectablesProviderController} instance.
775
+ *
776
+ * @group provision
777
+ *
778
+ * @param options - provisioning options
779
+ * @returns injectables provider decorator instance
780
+ *
781
+ * @example
782
+ * ```typescript
783
+ * class MyComponent extends LitElement {
784
+ * @injectablesProvide({ entries: [AuthService, UserService], activate: [AuthService] })
785
+ * public services!: InjectablesProviderController<MyComponent>;
786
+ * }
787
+ * ```
788
+ */
789
+ function injectablesProvide(options) {
790
+ return function (protoOrTarget, nameOrContext) {
791
+ if (typeof nameOrContext === "object") {
792
+ // Standard decorators:
793
+ nameOrContext.addInitializer(function () {
794
+ protoOrTarget.set.call(this, new InjectablesProviderController(this, options));
795
+ });
796
+ } else {
797
+ var controller_1;
798
+ protoOrTarget.constructor.addInitializer(function (element) {
799
+ controller_1 = new InjectablesProviderController(element, options);
800
+ });
801
+ return {
802
+ get: function () {
803
+ return controller_1;
804
+ },
805
+ set: function () {},
806
+ configurable: true,
807
+ enumerable: true
808
+ };
809
+ }
810
+ };
811
+ }
812
+
813
+ /**
814
+ * Binds a set of injectables to the nearest IoC container for the host element's lifetime.
815
+ *
816
+ * Entries are bound when the host connects and unbound when it disconnects.
817
+ *
818
+ * @group provision
819
+ *
820
+ * @param host - the host element
821
+ * @param options - provisioning options
822
+ * @param options.entries - list of service entries to bind to the container
823
+ * @param options.into - target IoC context; if omitted, uses the nearest provider context
824
+ * @param options.activate - list of service identifiers to activate immediately after binding
825
+ * @param options.seeds - seed data applied before binding
826
+ * @returns the controller instance
827
+ *
828
+ * @example
829
+ * ```typescript
830
+ * class MyComponent extends LitElement {
831
+ * private services = useInjectablesProvider(this, {
832
+ * entries: [AuthService, UserService],
833
+ * activate: [AuthService],
834
+ * });
835
+ * }
836
+ * ```
837
+ */
838
+ function useInjectablesProvider(host, options) {
839
+ return new InjectablesProviderController(host, options);
840
+ }
841
+
842
+ /**
843
+ * Hook (controller) to provide an IoC container to the host element and its children.
844
+ *
845
+ * @group provision
846
+ *
847
+ * @param host - the host element
848
+ * @param options - provisioning options
849
+ * @param options.container - optional existing container to use
850
+ * @param options.seed - optional seed data to apply to the container
851
+ * @returns ioc provision controller instance
852
+ *
853
+ * @example
854
+ * ```typescript
855
+ * class MyRootElement extends LitElement {
856
+ * private ioc = useIocProvision(this, { seed: { initialData: '...' } });
857
+ * }
858
+ * ```
859
+ */
860
+ function useIocProvision(host, options) {
861
+ if (options === void 0) {
862
+ options = {};
863
+ }
864
+ return new IocProviderController(host, options);
154
865
  }
155
866
 
156
867
  exports.ContainerContext = ContainerContext;
157
- exports.ContainerProviderController = ContainerProviderController;
158
- exports.ServicesProviderController = ServicesProviderController;
868
+ exports.InjectablesProviderController = InjectablesProviderController;
869
+ exports.IocProviderController = IocProviderController;
870
+ exports.OnCommandController = OnCommandController;
871
+ exports.OnEventController = OnEventController;
872
+ exports.OnQueryController = OnQueryController;
873
+ exports.injectablesProvide = injectablesProvide;
159
874
  exports.injection = injection;
160
- exports.useContainerProvision = useContainerProvision;
875
+ exports.iocProvide = iocProvide;
876
+ exports.onCommand = onCommand;
877
+ exports.onEvent = onEvent;
878
+ exports.onQuery = onQuery;
879
+ exports.useInjectablesProvider = useInjectablesProvider;
161
880
  exports.useInjection = useInjection;
881
+ exports.useIocProvision = useIocProvision;
882
+ exports.useOnCommand = useOnCommand;
883
+ exports.useOnEvents = useOnEvents;
884
+ exports.useOnQuery = useOnQuery;
162
885
  //# sourceMappingURL=index.js.map