@spearwolf/shadow-objects 0.32.0 → 0.34.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 (213) hide show
  1. package/CHANGELOG.md +333 -10
  2. package/README.md +100 -20
  3. package/bundle.js +5 -54
  4. package/package.json +7 -3
  5. package/src/ChangeTrailRefusedError.d.ts +27 -0
  6. package/src/ChangeTrailRefusedError.d.ts.map +1 -0
  7. package/src/ChangeTrailRefusedError.js +12 -0
  8. package/src/ChangeTrailRefusedError.js.map +7 -0
  9. package/src/EntityUuidInUseError.d.ts +19 -0
  10. package/src/EntityUuidInUseError.d.ts.map +1 -0
  11. package/src/EntityUuidInUseError.js +11 -0
  12. package/src/EntityUuidInUseError.js.map +7 -0
  13. package/src/WorkerTimeoutError.d.ts +25 -0
  14. package/src/WorkerTimeoutError.d.ts.map +1 -0
  15. package/src/WorkerTimeoutError.js +12 -0
  16. package/src/WorkerTimeoutError.js.map +7 -0
  17. package/src/bundle.d.ts +1 -1
  18. package/src/bundle.d.ts.map +1 -1
  19. package/src/bundle.js +1 -1
  20. package/src/bundle.js.map +2 -2
  21. package/src/constants.d.ts +9 -2
  22. package/src/constants.d.ts.map +1 -1
  23. package/src/constants.js +1 -1
  24. package/src/constants.js.map +2 -2
  25. package/src/create-worker.bundle.d.ts +1 -1
  26. package/src/create-worker.bundle.d.ts.map +1 -1
  27. package/src/create-worker.bundle.js.map +1 -1
  28. package/src/create-worker.d.ts +1 -1
  29. package/src/create-worker.d.ts.map +1 -1
  30. package/src/create-worker.js.map +1 -1
  31. package/src/elements/ShaeElement.d.ts +70 -2
  32. package/src/elements/ShaeElement.d.ts.map +1 -1
  33. package/src/elements/ShaeElement.js +129 -25
  34. package/src/elements/ShaeElement.js.map +3 -3
  35. package/src/elements/ShaeEntElement.d.ts +43 -5
  36. package/src/elements/ShaeEntElement.d.ts.map +1 -1
  37. package/src/elements/ShaeEntElement.js +399 -170
  38. package/src/elements/ShaeEntElement.js.map +2 -2
  39. package/src/elements/ShaeLifecycleElement.d.ts +71 -0
  40. package/src/elements/ShaeLifecycleElement.d.ts.map +1 -0
  41. package/src/elements/ShaeLifecycleElement.js +83 -0
  42. package/src/elements/ShaeLifecycleElement.js.map +7 -0
  43. package/src/elements/ShaePropElement.d.ts +57 -7
  44. package/src/elements/ShaePropElement.d.ts.map +1 -1
  45. package/src/elements/ShaePropElement.js +241 -220
  46. package/src/elements/ShaePropElement.js.map +2 -2
  47. package/src/elements/ShaeWorkerElement.d.ts +49 -5
  48. package/src/elements/ShaeWorkerElement.d.ts.map +1 -1
  49. package/src/elements/ShaeWorkerElement.js +230 -74
  50. package/src/elements/ShaeWorkerElement.js.map +2 -2
  51. package/src/elements/constants.d.ts +6 -0
  52. package/src/elements/constants.d.ts.map +1 -1
  53. package/src/elements/constants.js +12 -0
  54. package/src/elements/constants.js.map +2 -2
  55. package/src/elements/deferredTeardown.d.ts +24 -0
  56. package/src/elements/deferredTeardown.d.ts.map +1 -0
  57. package/src/elements/deferredTeardown.js +30 -0
  58. package/src/elements/deferredTeardown.js.map +7 -0
  59. package/src/elements/displayContentsRule.d.ts +25 -0
  60. package/src/elements/displayContentsRule.d.ts.map +1 -0
  61. package/src/elements/displayContentsRule.js +37 -0
  62. package/src/elements/displayContentsRule.js.map +7 -0
  63. package/src/elements/events.d.ts +10 -7
  64. package/src/elements/events.d.ts.map +1 -1
  65. package/src/elements/forwardCustomEvents.d.ts +19 -0
  66. package/src/elements/forwardCustomEvents.d.ts.map +1 -0
  67. package/src/elements/forwardCustomEvents.js +47 -0
  68. package/src/elements/forwardCustomEvents.js.map +7 -0
  69. package/src/elements/hostedSlots.d.ts +36 -0
  70. package/src/elements/hostedSlots.d.ts.map +1 -0
  71. package/src/elements/hostedSlots.js +118 -0
  72. package/src/elements/hostedSlots.js.map +7 -0
  73. package/src/elements/parentRemoval.d.ts +18 -0
  74. package/src/elements/parentRemoval.d.ts.map +1 -0
  75. package/src/elements/parentRemoval.js +60 -0
  76. package/src/elements/parentRemoval.js.map +7 -0
  77. package/src/elements/propValueConverters.d.ts +3 -0
  78. package/src/elements/propValueConverters.d.ts.map +1 -0
  79. package/src/elements/propValueConverters.js +54 -0
  80. package/src/elements/propValueConverters.js.map +7 -0
  81. package/src/elements/requestEntAncestor.d.ts +32 -0
  82. package/src/elements/requestEntAncestor.d.ts.map +1 -0
  83. package/src/elements/requestEntAncestor.js +16 -0
  84. package/src/elements/requestEntAncestor.js.map +7 -0
  85. package/src/elements.js.map +1 -1
  86. package/src/in-the-dark/Entity.d.ts +113 -3
  87. package/src/in-the-dark/Entity.d.ts.map +1 -1
  88. package/src/in-the-dark/Entity.js +292 -63
  89. package/src/in-the-dark/Entity.js.map +3 -3
  90. package/src/in-the-dark/Kernel.d.ts +81 -17
  91. package/src/in-the-dark/Kernel.d.ts.map +1 -1
  92. package/src/in-the-dark/Kernel.js +449 -392
  93. package/src/in-the-dark/Kernel.js.map +3 -3
  94. package/src/in-the-dark/Registry.d.ts +1 -1
  95. package/src/in-the-dark/Registry.d.ts.map +1 -1
  96. package/src/in-the-dark/Registry.js +99 -26
  97. package/src/in-the-dark/Registry.js.map +2 -2
  98. package/src/in-the-dark/ShadowObject.d.ts +1 -1
  99. package/src/in-the-dark/ShadowObject.d.ts.map +1 -1
  100. package/src/in-the-dark/ShadowObject.js +3 -2
  101. package/src/in-the-dark/ShadowObject.js.map +2 -2
  102. package/src/in-the-dark/ShadowObjectCreationScope.d.ts +126 -0
  103. package/src/in-the-dark/ShadowObjectCreationScope.d.ts.map +1 -0
  104. package/src/in-the-dark/ShadowObjectCreationScope.js +596 -0
  105. package/src/in-the-dark/ShadowObjectCreationScope.js.map +7 -0
  106. package/src/in-the-dark/SignalsPath.d.ts.map +1 -1
  107. package/src/in-the-dark/SignalsPath.js +2 -2
  108. package/src/in-the-dark/SignalsPath.js.map +2 -2
  109. package/src/in-the-dark/events.js.map +1 -1
  110. package/src/in-the-dark/importModule.d.ts +7 -0
  111. package/src/in-the-dark/importModule.d.ts.map +1 -1
  112. package/src/in-the-dark/importModule.js +8 -5
  113. package/src/in-the-dark/importModule.js.map +2 -2
  114. package/src/index.d.ts +7 -1
  115. package/src/index.d.ts.map +1 -1
  116. package/src/index.js +5 -1
  117. package/src/index.js.map +2 -2
  118. package/src/shadow-objects.d.ts +2 -0
  119. package/src/shadow-objects.d.ts.map +1 -1
  120. package/src/shadow-objects.js +2 -0
  121. package/src/shadow-objects.js.map +2 -2
  122. package/src/shadow-objects.worker.js +0 -1
  123. package/src/shadow-objects.worker.js.map +2 -2
  124. package/src/shae-ent.js.map +1 -1
  125. package/src/shae-prop.js +2 -2
  126. package/src/shae-prop.js.map +2 -2
  127. package/src/shae-worker.js.map +1 -1
  128. package/src/types.d.ts +39 -8
  129. package/src/types.d.ts.map +1 -1
  130. package/src/utils/ConsoleLogger.d.ts +45 -10
  131. package/src/utils/ConsoleLogger.d.ts.map +1 -1
  132. package/src/utils/ConsoleLogger.js +54 -28
  133. package/src/utils/ConsoleLogger.js.map +2 -2
  134. package/src/utils/FrameLoop.d.ts +42 -3
  135. package/src/utils/FrameLoop.d.ts.map +1 -1
  136. package/src/utils/FrameLoop.js +71 -12
  137. package/src/utils/FrameLoop.js.map +2 -2
  138. package/src/utils/MicrotaskCollector.d.ts +45 -0
  139. package/src/utils/MicrotaskCollector.d.ts.map +1 -0
  140. package/src/utils/MicrotaskCollector.js +33 -0
  141. package/src/utils/MicrotaskCollector.js.map +7 -0
  142. package/src/utils/MicrotaskGate.d.ts +17 -0
  143. package/src/utils/MicrotaskGate.d.ts.map +1 -0
  144. package/src/utils/MicrotaskGate.js +20 -0
  145. package/src/utils/MicrotaskGate.js.map +7 -0
  146. package/src/utils/array-utils.js.map +1 -1
  147. package/src/utils/attr-utils.d.ts +6 -0
  148. package/src/utils/attr-utils.d.ts.map +1 -1
  149. package/src/utils/attr-utils.js +4 -2
  150. package/src/utils/attr-utils.js.map +2 -2
  151. package/src/utils/constants.js.map +1 -1
  152. package/src/utils/generateUUID.d.ts +12 -1
  153. package/src/utils/generateUUID.d.ts.map +1 -1
  154. package/src/utils/generateUUID.js +31 -266
  155. package/src/utils/generateUUID.js.map +2 -2
  156. package/src/utils/props-utils.d.ts +3 -2
  157. package/src/utils/props-utils.d.ts.map +1 -1
  158. package/src/utils/props-utils.js +13 -24
  159. package/src/utils/props-utils.js.map +2 -2
  160. package/src/utils/runGuarded.d.ts +27 -0
  161. package/src/utils/runGuarded.d.ts.map +1 -0
  162. package/src/utils/runGuarded.js +11 -0
  163. package/src/utils/runGuarded.js.map +7 -0
  164. package/src/utils/toMaybe.d.ts.map +1 -1
  165. package/src/utils/toMaybe.js.map +1 -1
  166. package/src/utils/toNamespace.d.ts.map +1 -1
  167. package/src/utils/toNamespace.js.map +1 -1
  168. package/src/utils/toUrlString.d.ts +12 -0
  169. package/src/utils/toUrlString.d.ts.map +1 -1
  170. package/src/utils/toUrlString.js.map +2 -2
  171. package/src/utils/waitForMessageOfType.d.ts +16 -1
  172. package/src/utils/waitForMessageOfType.d.ts.map +1 -1
  173. package/src/utils/waitForMessageOfType.js +28 -3
  174. package/src/utils/waitForMessageOfType.js.map +2 -2
  175. package/src/view/ComponentChanges.d.ts +91 -1
  176. package/src/view/ComponentChanges.d.ts.map +1 -1
  177. package/src/view/ComponentChanges.js +253 -69
  178. package/src/view/ComponentChanges.js.map +2 -2
  179. package/src/view/ComponentContext.d.ts +239 -7
  180. package/src/view/ComponentContext.d.ts.map +1 -1
  181. package/src/view/ComponentContext.js +648 -115
  182. package/src/view/ComponentContext.js.map +2 -2
  183. package/src/view/ComponentMemory.d.ts +3 -3
  184. package/src/view/ComponentMemory.d.ts.map +1 -1
  185. package/src/view/ComponentMemory.js +3 -1
  186. package/src/view/ComponentMemory.js.map +2 -2
  187. package/src/view/IShadowObjectEnvProxy.d.ts +33 -1
  188. package/src/view/IShadowObjectEnvProxy.d.ts.map +1 -1
  189. package/src/view/LocalShadowObjectEnv.d.ts +2 -2
  190. package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
  191. package/src/view/LocalShadowObjectEnv.js +18 -11
  192. package/src/view/LocalShadowObjectEnv.js.map +2 -2
  193. package/src/view/RemoteWorkerEnv.d.ts +129 -3
  194. package/src/view/RemoteWorkerEnv.d.ts.map +1 -1
  195. package/src/view/RemoteWorkerEnv.js +290 -60
  196. package/src/view/RemoteWorkerEnv.js.map +2 -2
  197. package/src/view/ShadowEnv.d.ts +73 -2
  198. package/src/view/ShadowEnv.d.ts.map +1 -1
  199. package/src/view/ShadowEnv.js +301 -64
  200. package/src/view/ShadowEnv.js.map +2 -2
  201. package/src/view/ViewComponent.d.ts +93 -8
  202. package/src/view/ViewComponent.d.ts.map +1 -1
  203. package/src/view/ViewComponent.js +148 -28
  204. package/src/view/ViewComponent.js.map +2 -2
  205. package/src/view/cloneChangeTrail.js.map +2 -2
  206. package/src/worker/MessageRouter.d.ts +14 -0
  207. package/src/worker/MessageRouter.d.ts.map +1 -1
  208. package/src/worker/MessageRouter.js +80 -18
  209. package/src/worker/MessageRouter.js.map +2 -2
  210. package/src/worker/WorkerRuntime.d.ts +22 -1
  211. package/src/worker/WorkerRuntime.d.ts.map +1 -1
  212. package/src/worker/WorkerRuntime.js +60 -8
  213. package/src/worker/WorkerRuntime.js.map +2 -2
@@ -46,12 +46,33 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
46
46
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
47
47
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
48
48
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
49
- var _proxyReady_dec, _viewReady_dec, _comCtx, _shaObjEnvProxy, _syncScheduled, _syncAfterContextCreated, _syncWaitForConfirmation, _afterNextSync, _init, _viewReady, _proxyReady, _isDestroyed, _syncIfScheduled, _ShadowEnv_instances, syncNow_fn, onMessageToView_fn;
50
- import { emit, off, on, onceAsync, Priority, retain, retainClear } from "@spearwolf/eventize";
51
- import { createEffect, createSignal, destroyObjectSignals, findObjectSignalByName } from "@spearwolf/signalize";
49
+ var __privateWrapper = (obj, member, setter, getter) => ({
50
+ set _(value) {
51
+ __privateSet(obj, member, value, setter);
52
+ },
53
+ get _() {
54
+ return __privateGet(obj, member, getter);
55
+ }
56
+ });
57
+ var _proxyReady_dec, _viewReady_dec, _comCtx, _shaObjEnvProxy, _syncScheduled, _syncAfterContextCreated, _syncWaitForConfirmation, _nextSyncCycle, _logger, _init, _viewReady, _proxyReady, _isDestroyed, _contextEffect, _ShadowEnv_instances, ensureContextEffect_fn, releaseNamespace_fn, _proxyGeneration, _whenDestroyed, _rejectWhenDestroyed, destroyedSignal_fn, openSyncCycle_fn, _syncIfScheduled, syncNow_fn, commitSyncCycle_fn, announceContext_fn, endSyncCycle_fn, onMessageToView_fn, onProxyFailed_fn;
58
+ import { emitStrict, off, on, onceAsync, Priority, retain, retainClear } from "@spearwolf/eventize";
59
+ import {
60
+ createEffect,
61
+ createSignal,
62
+ destroyObjectSignals,
63
+ findObjectSignalByName,
64
+ hibernate
65
+ } from "@spearwolf/signalize";
52
66
  import { signal } from "@spearwolf/signalize/decorators";
67
+ import { ChangeTrailRefusedError } from "../ChangeTrailRefusedError.js";
53
68
  import { ConsoleLogger } from "../utils/ConsoleLogger.js";
54
69
  import { ComponentContext } from "./ComponentContext.js";
70
+ class ShadowEnvDestroyedError extends Error {
71
+ constructor(message = "the shadow environment has been destroyed") {
72
+ super(message);
73
+ this.name = "ShadowEnvDestroyedError";
74
+ }
75
+ }
55
76
  _viewReady_dec = [signal()], _proxyReady_dec = [signal()];
56
77
  const _ShadowEnv = class _ShadowEnv {
57
78
  constructor() {
@@ -61,14 +82,33 @@ const _ShadowEnv = class _ShadowEnv {
61
82
  __privateAdd(this, _syncScheduled, false);
62
83
  __privateAdd(this, _syncAfterContextCreated, false);
63
84
  __privateAdd(this, _syncWaitForConfirmation, false);
64
- __privateAdd(this, _afterNextSync);
65
- this.logger = new ConsoleLogger("ShadowEnv");
85
+ __privateAdd(this, _nextSyncCycle);
86
+ __privateAdd(this, _logger, new ConsoleLogger("ShadowEnv"));
87
+ /**
88
+ * The namespace of the {@link ComponentContext} this environment observes, and `undefined`
89
+ * while it observes none. The `view` setter writes it, so it carries the name
90
+ * {@link ShadowEnv.get} finds this environment under, unless another environment has since
91
+ * taken that namespace over; a `destroy()` leaves it on `undefined`.
92
+ */
66
93
  this.ns$ = createSignal();
67
94
  __privateAdd(this, _viewReady, __runInitializers(_init, 8, this, false)), __runInitializers(_init, 11, this);
68
95
  __privateAdd(this, _proxyReady, __runInitializers(_init, 12, this, false)), __runInitializers(_init, 15, this);
69
96
  __privateAdd(this, _isDestroyed, false);
97
+ __privateAdd(this, _contextEffect);
98
+ // Each assignment to `envProxy` opens a generation. A start that finishes outside the generation
99
+ // it belongs to speaks for a proxy this environment has already let go, and is discarded.
100
+ __privateAdd(this, _proxyGeneration, 0);
101
+ __privateAdd(this, _whenDestroyed);
102
+ __privateAdd(this, _rejectWhenDestroyed);
103
+ /**
104
+ * Resolves once the environment is ready.
105
+ *
106
+ * @throws {ShadowEnvDestroyedError} if the environment is destroyed before that happens
107
+ */
70
108
  this.ready = async () => {
71
- return this.isReady ? this : onceAsync(this, _ShadowEnv.ContextCreated);
109
+ if (__privateGet(this, _isDestroyed)) throw new ShadowEnvDestroyedError();
110
+ if (this.isReady) return this;
111
+ return Promise.race([onceAsync(this, _ShadowEnv.ContextCreated), __privateMethod(this, _ShadowEnv_instances, destroyedSignal_fn).call(this)]);
72
112
  };
73
113
  __privateAdd(this, _syncIfScheduled, () => {
74
114
  if (__privateGet(this, _syncScheduled)) {
@@ -77,27 +117,18 @@ const _ShadowEnv = class _ShadowEnv {
77
117
  });
78
118
  const self = this;
79
119
  retain(self, _ShadowEnv.ContextCreated);
80
- on(self, _ShadowEnv.ContextLost, Priority.AAA, () => {
120
+ on(self, _ShadowEnv.ContextLost, Priority.Critical, () => {
81
121
  retainClear(self, _ShadowEnv.ContextCreated);
82
122
  });
83
- createEffect(() => {
84
- if (this.viewReady && this.proxyReady) {
85
- this.view.reCreateChanges();
86
- emit(self, _ShadowEnv.ContextCreated, self);
87
- if (__privateGet(this, _syncAfterContextCreated)) {
88
- __privateSet(this, _syncAfterContextCreated, false);
89
- __privateMethod(this, _ShadowEnv_instances, syncNow_fn).call(this);
90
- }
91
- return () => {
92
- emit(self, _ShadowEnv.ContextLost, self);
93
- };
94
- }
95
- }, [findObjectSignalByName(this, "viewReady"), findObjectSignalByName(this, "proxyReady")]);
96
123
  }
97
124
  static get(ns) {
98
125
  if (ns == null) return void 0;
99
126
  return globalThis.__shadowEnvs?.get(ns);
100
127
  }
128
+ /** The logger this environment reports through. */
129
+ get logger() {
130
+ return __privateGet(this, _logger);
131
+ }
101
132
  get isDestroyed() {
102
133
  return __privateGet(this, _isDestroyed);
103
134
  }
@@ -106,23 +137,17 @@ const _ShadowEnv = class _ShadowEnv {
106
137
  }
107
138
  set view(ctx) {
108
139
  if (ctx !== __privateGet(this, _comCtx)) {
109
- if (__privateGet(this, _comCtx) && __privateGet(this, _comCtx).ns && globalThis.__shadowEnvs) {
110
- globalThis.__shadowEnvs.delete(__privateGet(this, _comCtx).ns);
111
- }
140
+ if (ctx) __privateMethod(this, _ShadowEnv_instances, ensureContextEffect_fn).call(this);
141
+ __privateMethod(this, _ShadowEnv_instances, releaseNamespace_fn).call(this, __privateGet(this, _comCtx)?.ns);
112
142
  __privateSet(this, _comCtx, ctx ?? void 0);
113
- if (__privateGet(this, _comCtx) && __privateGet(this, _comCtx).ns) {
143
+ if (__privateGet(this, _comCtx)?.ns) {
114
144
  globalThis.__shadowEnvs ??= /* @__PURE__ */ new Map();
115
145
  if (globalThis.__shadowEnvs.has(__privateGet(this, _comCtx).ns) && globalThis.__shadowEnvs.get(__privateGet(this, _comCtx).ns) !== this) {
116
- if (this.logger.isWarn) {
117
- this.logger.warn(
118
- "overwrite a namespace already in use",
119
- __privateGet(this, _comCtx).ns,
120
- globalThis.__shadowEnvs.get(__privateGet(this, _comCtx).ns)
121
- );
122
- }
146
+ this.logger.warn("overwrite a namespace already in use", __privateGet(this, _comCtx).ns, globalThis.__shadowEnvs.get(__privateGet(this, _comCtx).ns));
123
147
  }
124
148
  globalThis.__shadowEnvs.set(__privateGet(this, _comCtx).ns, this);
125
149
  }
150
+ this.ns$.set(__privateGet(this, _comCtx)?.ns);
126
151
  this.viewReady = Boolean(ctx);
127
152
  }
128
153
  }
@@ -131,18 +156,27 @@ const _ShadowEnv = class _ShadowEnv {
131
156
  }
132
157
  set envProxy(proxy) {
133
158
  if (proxy !== __privateGet(this, _shaObjEnvProxy)) {
159
+ if (proxy) __privateMethod(this, _ShadowEnv_instances, ensureContextEffect_fn).call(this);
134
160
  const prevProxy = __privateGet(this, _shaObjEnvProxy);
135
161
  __privateSet(this, _shaObjEnvProxy, proxy ?? void 0);
162
+ const generation = ++__privateWrapper(this, _proxyGeneration)._;
136
163
  if (__privateGet(this, _shaObjEnvProxy)) {
137
164
  __privateGet(this, _shaObjEnvProxy).onMessageToView = __privateMethod(this, _ShadowEnv_instances, onMessageToView_fn).bind(this);
165
+ __privateGet(this, _shaObjEnvProxy).onProxyFailed = __privateMethod(this, _ShadowEnv_instances, onProxyFailed_fn).bind(this);
138
166
  }
139
167
  if (prevProxy) {
140
168
  prevProxy.destroy();
169
+ prevProxy.onProxyFailed = void 0;
170
+ queueMicrotask(() => {
171
+ prevProxy.onMessageToView = void 0;
172
+ });
141
173
  }
142
174
  this.proxyReady = false;
143
175
  proxy?.start().then(() => {
176
+ if (generation !== __privateGet(this, _proxyGeneration)) return;
144
177
  this.proxyReady = true;
145
178
  }).catch((error) => {
179
+ if (generation !== __privateGet(this, _proxyGeneration)) return;
146
180
  this.logger.error("failed to start envProxy", error);
147
181
  this.proxyReady = false;
148
182
  });
@@ -151,7 +185,23 @@ const _ShadowEnv = class _ShadowEnv {
151
185
  get isReady() {
152
186
  return Boolean(__privateGet(this, _comCtx) && __privateGet(this, _shaObjEnvProxy) && this.proxyReady && !this.isDestroyed);
153
187
  }
188
+ /**
189
+ * Send the change trail without asking the Shadow Environment to confirm it --
190
+ * {@link ShadowEnv.syncWait} is the call that asks.
191
+ *
192
+ * What becomes of a refusal is then the proxy's decision, and the two shipped ones differ.
193
+ * `LocalShadowObjectEnv` runs the Kernel synchronously, inside the call the environment makes to
194
+ * the proxy -- one microtask after `sync()` returned, not inside the call to `sync()` itself --
195
+ * and rejects with what it threw, so a refusal reaches {@link ShadowEnv.SyncFailed} here as well,
196
+ * carrying its number.
197
+ * `RemoteWorkerEnv` sends no serial without a confirmation and gets no answer back, so a
198
+ * refusal stays in the worker: it is written to the console there, `SyncFailed` stays silent, and
199
+ * the whole trail is booked as applied.
200
+ *
201
+ * {@link ShadowEnv.syncWait} is the way both proxies answer on.
202
+ */
154
203
  sync() {
204
+ if (__privateGet(this, _isDestroyed)) return;
155
205
  if (!this.isReady) {
156
206
  __privateSet(this, _syncAfterContextCreated, true);
157
207
  return;
@@ -160,31 +210,63 @@ const _ShadowEnv = class _ShadowEnv {
160
210
  __privateSet(this, _syncScheduled, true);
161
211
  queueMicrotask(__privateGet(this, _syncIfScheduled));
162
212
  }
213
+ /**
214
+ * Like {@link ShadowEnv.sync}, but resolves with the change trail once the cycle completed.
215
+ *
216
+ * A cycle whose change trail the Shadow Environment could not apply rejects instead, with the
217
+ * reason the proxy gave. Where the Kernel itself refused the trail that reason is a
218
+ * {@link ChangeTrailRefusedError}: it names how many entries the Kernel applied, this side folds
219
+ * exactly those into its bookkeeping, and everything behind that line stays pending and goes out
220
+ * again with the next cycle. A trail whose cause of refusal stays put is refused every time, which
221
+ * is what {@link ShadowEnv.SyncFailed} is the place to act on.
222
+ *
223
+ * A reason that says nothing about how far the Kernel got -- a confirmation window that ran out,
224
+ * a proxy whose environment is gone -- counts the whole trail as applied, because a Shadow
225
+ * Environment that fell silent may well hold all of it. Then the trail is gone, and only a
226
+ * re-creation from the Component Memory brings it back. That re-creation belongs to a fresh
227
+ * proxy: an environment that still holds the entities refuses a creation for a uuid it already
228
+ * has. Handing {@link ShadowEnv.envProxy} a new proxy is therefore the way back -- the Shadow
229
+ * Environment calls {@link ComponentContext.reCreateChanges} itself once the new proxy is ready.
230
+ * Making that call is the consumer's decision, the same way recovering from a
231
+ * {@link ShadowEnv.ProxyFailed} is.
232
+ *
233
+ * Which cycle a caller gets is decided when the change trail is built. Everyone who arrives
234
+ * before that point waits on the same promise -- they all ride the same trail. From the build
235
+ * on the trail is fixed, and a call after it belongs to the next cycle, the one that carries
236
+ * the changes made since. That holds inside a listener of {@link ShadowEnv.AfterSync} or
237
+ * {@link ShadowEnv.SyncFailed} as well: the cycle it was told about is over, so the call opens
238
+ * the one behind it.
239
+ *
240
+ * @throws {ShadowEnvDestroyedError} if the environment is destroyed before the cycle completes
241
+ */
163
242
  syncWait() {
243
+ if (__privateGet(this, _isDestroyed)) return Promise.reject(new ShadowEnvDestroyedError());
164
244
  __privateSet(this, _syncWaitForConfirmation, true);
165
245
  this.sync();
166
- if (__privateGet(this, _afterNextSync)) return __privateGet(this, _afterNextSync);
167
- __privateSet(this, _afterNextSync, onceAsync(this, _ShadowEnv.AfterSync).then((changeTrail) => {
168
- __privateSet(this, _afterNextSync, void 0);
169
- return changeTrail;
170
- }));
171
- return __privateGet(this, _afterNextSync);
246
+ __privateGet(this, _nextSyncCycle) ?? __privateSet(this, _nextSyncCycle, __privateMethod(this, _ShadowEnv_instances, openSyncCycle_fn).call(this));
247
+ return __privateGet(this, _nextSyncCycle).promise;
172
248
  }
249
+ /**
250
+ * Tear the environment down: the proxy is destroyed, the namespace is released, all signals
251
+ * and listeners are removed, and every caller still waiting on {@link ShadowEnv.ready} or
252
+ * {@link ShadowEnv.syncWait} is rejected with a {@link ShadowEnvDestroyedError} instead of
253
+ * being left pending forever. Calling it more than once is a no-op.
254
+ */
173
255
  destroy() {
174
- const ns = __privateGet(this, _comCtx)?.ns;
175
- this.envProxy?.destroy();
256
+ var _a;
257
+ if (__privateGet(this, _isDestroyed)) return;
258
+ __privateSet(this, _isDestroyed, true);
259
+ __privateSet(this, _syncScheduled, false);
260
+ __privateSet(this, _syncAfterContextCreated, false);
261
+ __privateSet(this, _syncWaitForConfirmation, false);
176
262
  this.envProxy = void 0;
177
263
  this.view = void 0;
178
- if (ns) {
179
- if (globalThis.__shadowEnvs.has(ns)) {
180
- if (globalThis.__shadowEnvs.get(ns) === this) {
181
- globalThis.__shadowEnvs.delete(ns);
182
- }
183
- }
184
- }
264
+ (_a = __privateGet(this, _rejectWhenDestroyed)) == null ? void 0 : _a.call(this, new ShadowEnvDestroyedError());
265
+ __privateSet(this, _nextSyncCycle, void 0);
266
+ __privateGet(this, _contextEffect)?.destroy();
267
+ __privateSet(this, _contextEffect, void 0);
185
268
  destroyObjectSignals(this);
186
269
  off(this);
187
- __privateSet(this, _isDestroyed, true);
188
270
  Object.freeze(this);
189
271
  }
190
272
  };
@@ -194,43 +276,198 @@ _shaObjEnvProxy = new WeakMap();
194
276
  _syncScheduled = new WeakMap();
195
277
  _syncAfterContextCreated = new WeakMap();
196
278
  _syncWaitForConfirmation = new WeakMap();
197
- _afterNextSync = new WeakMap();
279
+ _nextSyncCycle = new WeakMap();
280
+ _logger = new WeakMap();
198
281
  _viewReady = new WeakMap();
199
282
  _proxyReady = new WeakMap();
200
283
  _isDestroyed = new WeakMap();
201
- _syncIfScheduled = new WeakMap();
284
+ _contextEffect = new WeakMap();
202
285
  _ShadowEnv_instances = new WeakSet();
286
+ /**
287
+ * Builds the effect that reports {@link ShadowEnv.ContextCreated} and {@link ShadowEnv.ContextLost}
288
+ * once, on the first half of the environment that arrives.
289
+ */
290
+ ensureContextEffect_fn = function() {
291
+ if (__privateGet(this, _isDestroyed) || __privateGet(this, _contextEffect) != null) return;
292
+ const self = this;
293
+ hibernate(() => {
294
+ __privateSet(this, _contextEffect, createEffect(() => {
295
+ if (this.viewReady && this.proxyReady) {
296
+ this.view.reCreateChanges();
297
+ __privateMethod(this, _ShadowEnv_instances, announceContext_fn).call(this, _ShadowEnv.ContextCreated, self);
298
+ if (__privateGet(this, _syncAfterContextCreated)) {
299
+ __privateSet(this, _syncAfterContextCreated, false);
300
+ __privateMethod(this, _ShadowEnv_instances, syncNow_fn).call(this);
301
+ }
302
+ return () => {
303
+ __privateMethod(this, _ShadowEnv_instances, announceContext_fn).call(this, _ShadowEnv.ContextLost, self);
304
+ };
305
+ }
306
+ }, [findObjectSignalByName(this, "viewReady"), findObjectSignalByName(this, "proxyReady")]));
307
+ });
308
+ };
309
+ /**
310
+ * Releases the namespace registration, but only while this environment holds it. A namespace
311
+ * carries one environment at a time, and an assignment that displaces another one leaves that
312
+ * other environment registered under nothing -- taking its entry along on the way out would
313
+ * make `ShadowEnv.get()` answer `undefined` for an environment that is very much alive.
314
+ */
315
+ releaseNamespace_fn = function(ns) {
316
+ if (!ns) return;
317
+ const shadowEnvs = globalThis.__shadowEnvs;
318
+ if (shadowEnvs?.get(ns) === this) {
319
+ shadowEnvs.delete(ns);
320
+ }
321
+ };
322
+ _proxyGeneration = new WeakMap();
323
+ _whenDestroyed = new WeakMap();
324
+ _rejectWhenDestroyed = new WeakMap();
325
+ /**
326
+ * A promise that rejects the moment this environment is destroyed.
327
+ *
328
+ * Every promise the public API hands out races against it. Without that race a caller
329
+ * would wait forever, because {@link ShadowEnv.destroy} tears down the very listeners
330
+ * those promises are built on.
331
+ */
332
+ destroyedSignal_fn = function() {
333
+ if (__privateGet(this, _whenDestroyed) == null) {
334
+ __privateSet(this, _whenDestroyed, new Promise((_, reject) => {
335
+ __privateSet(this, _rejectWhenDestroyed, reject);
336
+ }));
337
+ __privateGet(this, _whenDestroyed).catch(() => {
338
+ });
339
+ }
340
+ return __privateGet(this, _whenDestroyed);
341
+ };
342
+ /**
343
+ * The cycle settles this promise by hand rather than through `AfterSync` / `SyncFailed`. A
344
+ * subscription made here would stand in line behind the listeners the application registered
345
+ * during setup, and an eventize emit stops at the first listener that throws -- everything
346
+ * behind it, this promise included, would be left waiting forever. Settling by hand also
347
+ * spares the bookkeeping a subscription per call would need: a cycle produces one of the two
348
+ * events, and the subscriber of the other one would stay behind and pile up.
349
+ */
350
+ openSyncCycle_fn = function() {
351
+ let resolve;
352
+ let reject;
353
+ const outcome = new Promise((res, rej) => {
354
+ resolve = res;
355
+ reject = rej;
356
+ });
357
+ return { promise: Promise.race([outcome, __privateMethod(this, _ShadowEnv_instances, destroyedSignal_fn).call(this)]), resolve, reject };
358
+ };
359
+ _syncIfScheduled = new WeakMap();
203
360
  syncNow_fn = async function() {
204
361
  __privateSet(this, _syncScheduled, false);
205
- if (this.isReady) {
206
- const data = this.view.buildChangeTrails();
362
+ if (__privateGet(this, _isDestroyed)) return;
363
+ if (!this.isReady) {
364
+ __privateSet(this, _syncAfterContextCreated, true);
365
+ return;
366
+ }
367
+ const data = this.view.buildChangeTrails(false);
368
+ const cycle = __privateGet(this, _nextSyncCycle);
369
+ __privateSet(this, _nextSyncCycle, void 0);
370
+ const waitForConfirmation = __privateGet(this, _syncWaitForConfirmation);
371
+ __privateSet(this, _syncWaitForConfirmation, false);
372
+ try {
207
373
  if (data.length > 0) {
208
- try {
209
- const waitForConfirmation = __privateGet(this, _syncWaitForConfirmation);
210
- __privateSet(this, _syncWaitForConfirmation, false);
211
- await this.envProxy.applyChangeTrail(data, waitForConfirmation);
212
- } catch (error) {
213
- this.logger.error("failed to apply change trail", error);
214
- } finally {
215
- emit(this, _ShadowEnv.AfterSync, data);
216
- }
374
+ await this.envProxy.applyChangeTrail(data, waitForConfirmation);
217
375
  }
376
+ } catch (error) {
377
+ if (__privateGet(this, _isDestroyed)) return;
378
+ this.logger.error("failed to apply change trail", error);
379
+ __privateMethod(this, _ShadowEnv_instances, commitSyncCycle_fn).call(this, data, error);
380
+ __privateMethod(this, _ShadowEnv_instances, endSyncCycle_fn).call(this, data, cycle, { reason: error });
381
+ return;
218
382
  }
383
+ if (__privateGet(this, _isDestroyed)) return;
384
+ __privateMethod(this, _ShadowEnv_instances, commitSyncCycle_fn).call(this, data);
385
+ __privateMethod(this, _ShadowEnv_instances, endSyncCycle_fn).call(this, data, cycle);
219
386
  };
220
- onMessageToView_fn = function(event) {
221
- if (this.logger.isDebug) {
222
- this.logger.debug("onMessageToView", event.type, event.data);
387
+ /**
388
+ * Draws the line between what the Shadow Environment applied and what it still owes, and hands
389
+ * it to the view. Runs ahead of {@link ShadowEnv.#endSyncCycle} so that a `SyncFailed` listener
390
+ * and a waiting {@link ShadowEnv.syncWait} caller find bookkeeping that already holds.
391
+ *
392
+ * An empty change trail is settled as well: the build may have retired components even without
393
+ * writing an entry for any of them.
394
+ */
395
+ commitSyncCycle_fn = function(changeTrail, reason) {
396
+ const appliedCount = reason instanceof ChangeTrailRefusedError ? reason.appliedCount : changeTrail.length;
397
+ this.view?.commitChangeTrail(appliedCount, changeTrail);
398
+ };
399
+ /**
400
+ * Sends one of the two context events and keeps a listener that throws to itself.
401
+ *
402
+ * Both go out from inside the effect that watches `viewReady` and `proxyReady` -- `ContextLost`
403
+ * from its cleanup -- so a throw would leave through whatever signal write set that effect
404
+ * going, and reach code that has nothing to do with either event. `emitStrict()` serves every
405
+ * listener whatever the one before it did, and what they threw is reported here and travels no
406
+ * further.
407
+ */
408
+ announceContext_fn = function(eventName, self) {
409
+ try {
410
+ emitStrict(self, eventName, self);
411
+ } catch (error) {
412
+ this.logger.error(`a ${eventName} listener threw`, error);
413
+ }
414
+ };
415
+ /**
416
+ * Ends a synchronization cycle in exactly one of its two outcomes. A cycle the Shadow
417
+ * Environment applied resolves {@link ShadowEnv.syncWait} and emits {@link ShadowEnv.AfterSync};
418
+ * a cycle whose change trail it refused rejects and emits {@link ShadowEnv.SyncFailed}. Only a
419
+ * listener that can tell the two apart can react to either, so no cycle ever sends both.
420
+ *
421
+ * The waiting caller is settled before the event goes out, and the emit is the last thing that
422
+ * happens: a settlement that travelled as a listener of its own would sit behind whatever the
423
+ * application registered during setup, and this method is the wrong place to make a promise
424
+ * depend on the order consumers subscribe in. The dispatch is `emitStrict()`, so every listener
425
+ * hears about the cycle whatever the one before it did, and what they threw arrives here
426
+ * afterwards -- one of them unchanged, several as an `AggregateError` in dispatch order. It ends
427
+ * here as well: `#syncNow()` runs unawaited, and an error escaping it becomes an unhandled
428
+ * rejection rather than a report anybody reads.
429
+ *
430
+ * Which cycle is being ended arrives as an argument: the caller carries it from the moment its
431
+ * change trail was built, so a cycle that is still in flight cannot be settled by the one behind it.
432
+ */
433
+ endSyncCycle_fn = function(changeTrail, cycle, failure) {
434
+ try {
435
+ if (failure) {
436
+ cycle?.reject(failure.reason);
437
+ emitStrict(this, _ShadowEnv.SyncFailed, failure.reason, changeTrail, this);
438
+ } else {
439
+ cycle?.resolve(changeTrail);
440
+ emitStrict(this, _ShadowEnv.AfterSync, changeTrail);
441
+ }
442
+ } catch (error) {
443
+ this.logger.error("a sync cycle listener threw", error);
223
444
  }
445
+ };
446
+ onMessageToView_fn = function(event) {
447
+ this.logger.debug("onMessageToView", event.type, event.data);
224
448
  this.view?.dispatchMessage(event.uuid, event.type, event.data, event.traverseChildren);
225
449
  };
450
+ onProxyFailed_fn = function(reason) {
451
+ if (__privateGet(this, _isDestroyed)) return;
452
+ this.logger.error("the environment proxy failed", reason);
453
+ ++__privateWrapper(this, _proxyGeneration)._;
454
+ try {
455
+ emitStrict(this, _ShadowEnv.ProxyFailed, reason, this);
456
+ } finally {
457
+ this.proxyReady = false;
458
+ }
459
+ };
226
460
  __decorateElement(_init, 4, "viewReady", _viewReady_dec, _ShadowEnv, _viewReady);
227
461
  __decorateElement(_init, 4, "proxyReady", _proxyReady_dec, _ShadowEnv, _proxyReady);
228
462
  __decoratorMetadata(_init, _ShadowEnv);
229
463
  _ShadowEnv.AfterSync = "afterSync";
464
+ _ShadowEnv.SyncFailed = "syncFailed";
230
465
  _ShadowEnv.ContextLost = "contextLost";
231
466
  _ShadowEnv.ContextCreated = "contextCreated";
467
+ _ShadowEnv.ProxyFailed = "proxyFailed";
232
468
  let ShadowEnv = _ShadowEnv;
233
469
  export {
234
- ShadowEnv
470
+ ShadowEnv,
471
+ ShadowEnvDestroyedError
235
472
  };
236
473
  //# sourceMappingURL=ShadowEnv.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/view/ShadowEnv.ts"],
4
- "sourcesContent": ["import {emit, off, on, onceAsync, Priority, retain, retainClear} from '@spearwolf/eventize';\nimport {createEffect, createSignal, destroyObjectSignals, findObjectSignalByName} from '@spearwolf/signalize';\nimport {signal} from '@spearwolf/signalize/decorators';\nimport type {MessageToViewEvent} from '../shadow-objects.js';\nimport type {ChangeTrailType, NamespaceType} from '../types.js';\nimport {ConsoleLogger} from '../utils/ConsoleLogger.js';\nimport {ComponentContext} from './ComponentContext.js';\nimport type {IShadowObjectEnvProxy} from './IShadowObjectEnvProxy.js';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __shadowEnvs: Map<NamespaceType, ShadowEnv> | undefined;\n}\n\nexport class ShadowEnv {\n static AfterSync = 'afterSync';\n static ContextLost = 'contextLost';\n static ContextCreated = 'contextCreated';\n\n static get(ns: NamespaceType): ShadowEnv | undefined {\n if (ns == null) return undefined;\n return globalThis.__shadowEnvs?.get(ns);\n }\n\n #comCtx?: ComponentContext;\n #shaObjEnvProxy?: IShadowObjectEnvProxy;\n #syncScheduled = false;\n #syncAfterContextCreated = false;\n #syncWaitForConfirmation = false;\n #afterNextSync?: Promise<ChangeTrailType>;\n\n readonly logger = new ConsoleLogger('ShadowEnv');\n\n readonly ns$ = createSignal<NamespaceType | undefined>();\n\n @signal() accessor viewReady = false;\n @signal() accessor proxyReady = false;\n\n #isDestroyed = false;\n\n get isDestroyed() {\n return this.#isDestroyed;\n }\n\n constructor() {\n const self = this as ShadowEnv;\n retain(self, ShadowEnv.ContextCreated);\n\n on(self, ShadowEnv.ContextLost, Priority.AAA, () => {\n retainClear(self, ShadowEnv.ContextCreated);\n });\n\n createEffect(() => {\n if (this.viewReady && this.proxyReady) {\n this.view!.reCreateChanges();\n emit(self, ShadowEnv.ContextCreated, self);\n if (this.#syncAfterContextCreated) {\n this.#syncAfterContextCreated = false;\n this.#syncNow();\n }\n return () => {\n emit(self, ShadowEnv.ContextLost, self);\n };\n }\n }, [findObjectSignalByName(this, 'viewReady'), findObjectSignalByName(this, 'proxyReady')]);\n }\n\n get view(): ComponentContext | undefined {\n return this.#comCtx;\n }\n\n set view(ctx: ComponentContext | null | undefined) {\n if (ctx !== this.#comCtx) {\n if (this.#comCtx && this.#comCtx.ns && globalThis.__shadowEnvs) {\n globalThis.__shadowEnvs.delete(this.#comCtx.ns);\n }\n\n this.#comCtx = ctx ?? undefined;\n\n if (this.#comCtx && this.#comCtx.ns) {\n globalThis.__shadowEnvs ??= new Map();\n if (globalThis.__shadowEnvs.has(this.#comCtx.ns) && globalThis.__shadowEnvs.get(this.#comCtx.ns) !== this) {\n if (this.logger.isWarn) {\n this.logger.warn(\n 'overwrite a namespace already in use',\n this.#comCtx.ns,\n globalThis.__shadowEnvs.get(this.#comCtx.ns),\n );\n }\n }\n globalThis.__shadowEnvs.set(this.#comCtx.ns, this);\n }\n\n this.viewReady = Boolean(ctx);\n }\n }\n\n get envProxy(): IShadowObjectEnvProxy | undefined {\n return this.#shaObjEnvProxy;\n }\n\n set envProxy(proxy: IShadowObjectEnvProxy | null | undefined) {\n if (proxy !== this.#shaObjEnvProxy) {\n const prevProxy = this.#shaObjEnvProxy;\n this.#shaObjEnvProxy = proxy ?? undefined;\n\n if (this.#shaObjEnvProxy) {\n this.#shaObjEnvProxy.onMessageToView = this.#onMessageToView.bind(this);\n }\n\n if (prevProxy) {\n prevProxy.destroy();\n }\n\n this.proxyReady = false;\n\n proxy\n ?.start()\n .then(() => {\n this.proxyReady = true;\n })\n .catch((error) => {\n this.logger.error('failed to start envProxy', error);\n this.proxyReady = false;\n });\n }\n }\n\n get isReady(): boolean {\n return Boolean(this.#comCtx && this.#shaObjEnvProxy && this.proxyReady && !this.isDestroyed);\n }\n\n readonly ready = async (): Promise<ShadowEnv> => {\n return this.isReady ? this : onceAsync(this as ShadowEnv, ShadowEnv.ContextCreated);\n };\n\n sync(): void {\n if (!this.isReady) {\n this.#syncAfterContextCreated = true;\n return;\n }\n if (this.#syncScheduled) return;\n this.#syncScheduled = true;\n queueMicrotask(this.#syncIfScheduled);\n }\n\n syncWait(): Promise<ChangeTrailType> {\n this.#syncWaitForConfirmation = true;\n this.sync();\n if (this.#afterNextSync) return this.#afterNextSync;\n this.#afterNextSync = onceAsync<ChangeTrailType>(this as ShadowEnv, ShadowEnv.AfterSync).then((changeTrail) => {\n this.#afterNextSync = undefined;\n return changeTrail;\n });\n return this.#afterNextSync;\n }\n\n destroy() {\n const ns = this.#comCtx?.ns;\n\n this.envProxy?.destroy();\n this.envProxy = undefined;\n this.view = undefined;\n\n if (ns) {\n if (globalThis.__shadowEnvs.has(ns)) {\n if (globalThis.__shadowEnvs.get(ns) === this) {\n globalThis.__shadowEnvs.delete(ns);\n }\n }\n }\n\n destroyObjectSignals(this);\n off(this);\n\n this.#isDestroyed = true;\n Object.freeze(this);\n }\n\n #syncIfScheduled = () => {\n if (this.#syncScheduled) {\n this.#syncNow();\n }\n };\n\n async #syncNow() {\n this.#syncScheduled = false;\n if (this.isReady) {\n const data = this.view!.buildChangeTrails();\n if (data.length > 0) {\n try {\n const waitForConfirmation = this.#syncWaitForConfirmation;\n this.#syncWaitForConfirmation = false;\n await this.envProxy!.applyChangeTrail(data, waitForConfirmation);\n } catch (error) {\n this.logger.error('failed to apply change trail', error);\n } finally {\n emit(this as ShadowEnv, ShadowEnv.AfterSync, data);\n }\n }\n }\n }\n\n #onMessageToView(event: Omit<MessageToViewEvent, 'transferables'>) {\n if (this.logger.isDebug) {\n this.logger.debug('onMessageToView', event.type, event.data);\n }\n this.view?.dispatchMessage(event.uuid, event.type, event.data, event.traverseChildren);\n }\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {emitStrict, off, on, onceAsync, Priority, retain, retainClear} from '@spearwolf/eventize';\nimport {\n createEffect,\n createSignal,\n destroyObjectSignals,\n type Effect,\n findObjectSignalByName,\n hibernate,\n} from '@spearwolf/signalize';\nimport {signal} from '@spearwolf/signalize/decorators';\nimport {ChangeTrailRefusedError} from '../ChangeTrailRefusedError.js';\nimport type {MessageToViewEvent} from '../shadow-objects.js';\nimport type {ChangeTrailType, NamespaceType} from '../types.js';\nimport {ConsoleLogger} from '../utils/ConsoleLogger.js';\nimport {ComponentContext} from './ComponentContext.js';\nimport type {IShadowObjectEnvProxy} from './IShadowObjectEnvProxy.js';\n\ndeclare global {\n var __shadowEnvs: Map<NamespaceType, ShadowEnv> | undefined;\n}\n\n/**\n * The reason every pending {@link ShadowEnv.ready} and {@link ShadowEnv.syncWait} promise\n * is rejected with when the environment is destroyed.\n */\nexport class ShadowEnvDestroyedError extends Error {\n constructor(message = 'the shadow environment has been destroyed') {\n super(message);\n this.name = 'ShadowEnvDestroyedError';\n }\n}\n\n/**\n * The settlement of one synchronization cycle: the promise `syncWait()` hands out, and the pair\n * that settles it. A cycle takes its own settlement with it the moment its change trail is\n * built, which is what lets two cycles be in flight at once without settling each other's\n * callers.\n */\ntype SyncCycle = {\n promise: Promise<ChangeTrailType>;\n resolve: (changeTrail: ChangeTrailType) => void;\n reject: (reason: unknown) => void;\n};\n\nexport class ShadowEnv {\n static AfterSync = 'afterSync';\n static SyncFailed = 'syncFailed';\n static ContextLost = 'contextLost';\n static ContextCreated = 'contextCreated';\n static ProxyFailed = 'proxyFailed';\n\n static get(ns: NamespaceType): ShadowEnv | undefined {\n if (ns == null) return undefined;\n return globalThis.__shadowEnvs?.get(ns);\n }\n\n #comCtx?: ComponentContext | undefined;\n #shaObjEnvProxy?: IShadowObjectEnvProxy | undefined;\n #syncScheduled = false;\n #syncAfterContextCreated = false;\n #syncWaitForConfirmation = false;\n #nextSyncCycle?: SyncCycle | undefined;\n\n readonly #logger = new ConsoleLogger('ShadowEnv');\n\n /** The logger this environment reports through. */\n get logger(): ConsoleLogger {\n return this.#logger;\n }\n\n /**\n * The namespace of the {@link ComponentContext} this environment observes, and `undefined`\n * while it observes none. The `view` setter writes it, so it carries the name\n * {@link ShadowEnv.get} finds this environment under, unless another environment has since\n * taken that namespace over; a `destroy()` leaves it on `undefined`.\n */\n readonly ns$ = createSignal<NamespaceType | undefined>();\n\n @signal() accessor viewReady = false;\n @signal() accessor proxyReady = false;\n\n #isDestroyed = false;\n\n get isDestroyed() {\n return this.#isDestroyed;\n }\n\n constructor() {\n const self = this as ShadowEnv;\n retain(self, ShadowEnv.ContextCreated);\n\n on(self, ShadowEnv.ContextLost, Priority.Critical, () => {\n retainClear(self, ShadowEnv.ContextCreated);\n });\n\n // the effect that reports the context comes with the first `view` or `envProxy` this\n // environment is given: an effect stands in a module-wide queue until it is destroyed, and an\n // environment that never receives either half must stay collectable\n }\n\n #contextEffect?: Effect | undefined;\n\n /**\n * Builds the effect that reports {@link ShadowEnv.ContextCreated} and {@link ShadowEnv.ContextLost}\n * once, on the first half of the environment that arrives.\n */\n #ensureContextEffect(): void {\n if (this.#isDestroyed || this.#contextEffect != null) return;\n\n const self = this as ShadowEnv;\n\n // `hibernate()` clears the effect stack for the duration, and that is not optional here. Both\n // setters below are public API and are called from application code that may well sit inside a\n // `createEffect()` -- `<shae-worker>` is one such caller: it assigns `view` from inside an\n // `ns$.onChange()` callback. An effect built while a foreign effect is running becomes that\n // effect's child and dies at its next run, taking the context reports with it. The three custom\n // elements shield their `connectedCallback` the same way.\n //\n // One observable side effect comes with it: a `batch()` the caller has open is pushed through\n // before this returns, so the effects it was holding back run at this point. The writes the\n // setter makes afterwards go back into that batch and wait for it to close, the way they would\n // without any of this.\n hibernate(() => {\n this.#contextEffect = createEffect(() => {\n if (this.viewReady && this.proxyReady) {\n // Both halves being ready is what this reacts to, and either half can be the one that\n // arrived last. A fresh proxy under the standing view is the case the recovery is written\n // for: it holds none of the uuids, and the re-created trail goes through. A view that is\n // taken off and hung back on -- `env.view = undefined; env.view = ctx`, and `get(ns)`\n // hands back the very same context -- is the one that does not: its memory is still full,\n // the proxy that stayed still holds every uuid in it, and the trail is refused at its\n // first creation and stays refused. A context that is genuinely new carries an empty\n // memory and re-creates nothing at all. Whoever swaps the view of a live environment\n // tears the proxy down with it.\n this.view!.reCreateChanges();\n this.#announceContext(ShadowEnv.ContextCreated, self);\n if (this.#syncAfterContextCreated) {\n this.#syncAfterContextCreated = false;\n this.#syncNow();\n }\n return () => {\n this.#announceContext(ShadowEnv.ContextLost, self);\n };\n }\n // the two @signal accessors above create their signals during field initialization,\n // so both lookups resolve by the time a setter runs\n }, [findObjectSignalByName(this, 'viewReady')!, findObjectSignalByName(this, 'proxyReady')!]);\n });\n }\n\n get view(): ComponentContext | undefined {\n return this.#comCtx;\n }\n\n set view(ctx: ComponentContext | null | undefined) {\n if (ctx !== this.#comCtx) {\n if (ctx) this.#ensureContextEffect();\n\n this.#releaseNamespace(this.#comCtx?.ns);\n\n this.#comCtx = ctx ?? undefined;\n\n if (this.#comCtx?.ns) {\n globalThis.__shadowEnvs ??= new Map();\n if (globalThis.__shadowEnvs.has(this.#comCtx.ns) && globalThis.__shadowEnvs.get(this.#comCtx.ns) !== this) {\n this.logger.warn('overwrite a namespace already in use', this.#comCtx.ns, globalThis.__shadowEnvs.get(this.#comCtx.ns));\n }\n globalThis.__shadowEnvs.set(this.#comCtx.ns, this);\n }\n\n // the namespace this environment observes, published where the name promises it. `view` is\n // the only way one reaches this object -- `ComponentContext.ns` is assigned in its\n // constructor and never again -- and the write stands behind the registration above, so\n // whoever reacts to it finds `ShadowEnv.get()` already answering this environment. It needs\n // no truthiness guard of its own: `toNamespace()` turns an empty or whitespace-only string\n // into `GlobalNS`, so a context that exists has a namespace that registers.\n this.ns$.set(this.#comCtx?.ns);\n\n this.viewReady = Boolean(ctx);\n }\n }\n\n /**\n * Releases the namespace registration, but only while this environment holds it. A namespace\n * carries one environment at a time, and an assignment that displaces another one leaves that\n * other environment registered under nothing -- taking its entry along on the way out would\n * make `ShadowEnv.get()` answer `undefined` for an environment that is very much alive.\n */\n #releaseNamespace(ns: NamespaceType | undefined): void {\n // the same truthiness check the `view` setter above uses before it registers a namespace,\n // so release and registration recognize the same namespace as \"none\"\n if (!ns) return;\n const shadowEnvs = globalThis.__shadowEnvs;\n if (shadowEnvs?.get(ns) === this) {\n shadowEnvs.delete(ns);\n }\n }\n\n get envProxy(): IShadowObjectEnvProxy | undefined {\n return this.#shaObjEnvProxy;\n }\n\n // Each assignment to `envProxy` opens a generation. A start that finishes outside the generation\n // it belongs to speaks for a proxy this environment has already let go, and is discarded.\n #proxyGeneration = 0;\n\n set envProxy(proxy: IShadowObjectEnvProxy | null | undefined) {\n if (proxy !== this.#shaObjEnvProxy) {\n if (proxy) this.#ensureContextEffect();\n\n const prevProxy = this.#shaObjEnvProxy;\n this.#shaObjEnvProxy = proxy ?? undefined;\n\n const generation = ++this.#proxyGeneration;\n\n if (this.#shaObjEnvProxy) {\n this.#shaObjEnvProxy.onMessageToView = this.#onMessageToView.bind(this);\n this.#shaObjEnvProxy.onProxyFailed = this.#onProxyFailed.bind(this);\n }\n\n if (prevProxy) {\n prevProxy.destroy();\n\n // a proxy this environment has let go speaks for an environment that is gone; whatever\n // it makes of its own failure from here on is no longer this environment's business\n prevProxy.onProxyFailed = undefined;\n\n // one microtask later, not synchronously: a local environment hands a message an\n // `onDestroy` sends towards the view to a microtask queued while `destroy()` runs, and\n // that message is still addressed to this environment. The microtask queue is served in\n // the order it was filled, so every message the teardown queued runs ahead of this line\n // -- and the released proxy falls silent for everything after it\n queueMicrotask(() => {\n prevProxy.onMessageToView = undefined;\n });\n }\n\n this.proxyReady = false;\n\n // the catch stays behind the then: a listener of ContextCreated that throws is reported here,\n // and turning this into `then(onFulfilled, onRejected)` would let it escape as an unhandled rejection\n proxy\n ?.start()\n .then(() => {\n if (generation !== this.#proxyGeneration) return;\n this.proxyReady = true;\n })\n .catch((error) => {\n if (generation !== this.#proxyGeneration) return;\n this.logger.error('failed to start envProxy', error);\n this.proxyReady = false;\n });\n }\n }\n\n get isReady(): boolean {\n return Boolean(this.#comCtx && this.#shaObjEnvProxy && this.proxyReady && !this.isDestroyed);\n }\n\n #whenDestroyed?: Promise<never>;\n #rejectWhenDestroyed?: (error: Error) => void;\n\n /**\n * A promise that rejects the moment this environment is destroyed.\n *\n * Every promise the public API hands out races against it. Without that race a caller\n * would wait forever, because {@link ShadowEnv.destroy} tears down the very listeners\n * those promises are built on.\n */\n #destroyedSignal(): Promise<never> {\n if (this.#whenDestroyed == null) {\n this.#whenDestroyed = new Promise<never>((_, reject) => {\n this.#rejectWhenDestroyed = reject;\n });\n // the signal is rejected unconditionally, also when nobody happens to be racing against it\n this.#whenDestroyed.catch(() => {});\n }\n return this.#whenDestroyed;\n }\n\n /**\n * Resolves once the environment is ready.\n *\n * @throws {ShadowEnvDestroyedError} if the environment is destroyed before that happens\n */\n readonly ready = async (): Promise<ShadowEnv> => {\n if (this.#isDestroyed) throw new ShadowEnvDestroyedError();\n if (this.isReady) return this;\n return Promise.race([onceAsync<ShadowEnv>(this as ShadowEnv, ShadowEnv.ContextCreated), this.#destroyedSignal()]);\n };\n\n /**\n * Send the change trail without asking the Shadow Environment to confirm it --\n * {@link ShadowEnv.syncWait} is the call that asks.\n *\n * What becomes of a refusal is then the proxy's decision, and the two shipped ones differ.\n * `LocalShadowObjectEnv` runs the Kernel synchronously, inside the call the environment makes to\n * the proxy -- one microtask after `sync()` returned, not inside the call to `sync()` itself --\n * and rejects with what it threw, so a refusal reaches {@link ShadowEnv.SyncFailed} here as well,\n * carrying its number.\n * `RemoteWorkerEnv` sends no serial without a confirmation and gets no answer back, so a\n * refusal stays in the worker: it is written to the console there, `SyncFailed` stays silent, and\n * the whole trail is booked as applied.\n *\n * {@link ShadowEnv.syncWait} is the way both proxies answer on.\n */\n sync(): void {\n if (this.#isDestroyed) return;\n if (!this.isReady) {\n this.#syncAfterContextCreated = true;\n return;\n }\n if (this.#syncScheduled) return;\n this.#syncScheduled = true;\n queueMicrotask(this.#syncIfScheduled);\n }\n\n /**\n * Like {@link ShadowEnv.sync}, but resolves with the change trail once the cycle completed.\n *\n * A cycle whose change trail the Shadow Environment could not apply rejects instead, with the\n * reason the proxy gave. Where the Kernel itself refused the trail that reason is a\n * {@link ChangeTrailRefusedError}: it names how many entries the Kernel applied, this side folds\n * exactly those into its bookkeeping, and everything behind that line stays pending and goes out\n * again with the next cycle. A trail whose cause of refusal stays put is refused every time, which\n * is what {@link ShadowEnv.SyncFailed} is the place to act on.\n *\n * A reason that says nothing about how far the Kernel got -- a confirmation window that ran out,\n * a proxy whose environment is gone -- counts the whole trail as applied, because a Shadow\n * Environment that fell silent may well hold all of it. Then the trail is gone, and only a\n * re-creation from the Component Memory brings it back. That re-creation belongs to a fresh\n * proxy: an environment that still holds the entities refuses a creation for a uuid it already\n * has. Handing {@link ShadowEnv.envProxy} a new proxy is therefore the way back -- the Shadow\n * Environment calls {@link ComponentContext.reCreateChanges} itself once the new proxy is ready.\n * Making that call is the consumer's decision, the same way recovering from a\n * {@link ShadowEnv.ProxyFailed} is.\n *\n * Which cycle a caller gets is decided when the change trail is built. Everyone who arrives\n * before that point waits on the same promise -- they all ride the same trail. From the build\n * on the trail is fixed, and a call after it belongs to the next cycle, the one that carries\n * the changes made since. That holds inside a listener of {@link ShadowEnv.AfterSync} or\n * {@link ShadowEnv.SyncFailed} as well: the cycle it was told about is over, so the call opens\n * the one behind it.\n *\n * @throws {ShadowEnvDestroyedError} if the environment is destroyed before the cycle completes\n */\n syncWait(): Promise<ChangeTrailType> {\n if (this.#isDestroyed) return Promise.reject(new ShadowEnvDestroyedError());\n\n this.#syncWaitForConfirmation = true;\n this.sync();\n\n // Every caller that arrives before the change trail is built waits on the same promise: they\n // all ride the same trail. From the build on the trail is fixed, `#syncNow()` has taken this\n // cycle with it, and the next caller opens the one behind it -- the cycle that will carry the\n // change they are about to make.\n this.#nextSyncCycle ??= this.#openSyncCycle();\n\n return this.#nextSyncCycle.promise;\n }\n\n /**\n * The cycle settles this promise by hand rather than through `AfterSync` / `SyncFailed`. A\n * subscription made here would stand in line behind the listeners the application registered\n * during setup, and an eventize emit stops at the first listener that throws -- everything\n * behind it, this promise included, would be left waiting forever. Settling by hand also\n * spares the bookkeeping a subscription per call would need: a cycle produces one of the two\n * events, and the subscriber of the other one would stay behind and pile up.\n */\n #openSyncCycle(): SyncCycle {\n let resolve!: (changeTrail: ChangeTrailType) => void;\n let reject!: (reason: unknown) => void;\n\n const outcome = new Promise<ChangeTrailType>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n // the race is what settles a caller whose environment is destroyed before the cycle ends:\n // `destroy()` tears down the very listeners any other route would depend on\n return {promise: Promise.race([outcome, this.#destroyedSignal()]), resolve, reject};\n }\n\n /**\n * Tear the environment down: the proxy is destroyed, the namespace is released, all signals\n * and listeners are removed, and every caller still waiting on {@link ShadowEnv.ready} or\n * {@link ShadowEnv.syncWait} is rejected with a {@link ShadowEnvDestroyedError} instead of\n * being left pending forever. Calling it more than once is a no-op.\n */\n destroy() {\n if (this.#isDestroyed) return;\n\n // set first: isReady must report false for everything that runs below\n this.#isDestroyed = true;\n\n this.#syncScheduled = false;\n this.#syncAfterContextCreated = false;\n this.#syncWaitForConfirmation = false;\n\n // the `envProxy` setter destroys the previous proxy, so it must not be destroyed here as well\n this.envProxy = undefined;\n // the `view` setter releases the namespace registration on the way out, ownership-checked, and clears `ns$` with it\n this.view = undefined;\n\n // settle everyone still waiting before the listeners they depend on are removed\n this.#rejectWhenDestroyed?.(new ShadowEnvDestroyedError());\n this.#nextSyncCycle = undefined;\n\n // The effect is built here, so it is released here: its lifetime hangs on this class rather\n // than on what a reactivity library makes of an effect whose dependencies are taken away.\n // `ContextLost` goes out exactly once, from whichever of the two gets there first: the effect\n // rerun that `this.envProxy = undefined` triggers above, or -- while an open `batch()` parks\n // that drop of `proxyReady` -- the destroy on this line. A cleanup function belongs to the run\n // that returned it, and is spent by the one that runs it.\n this.#contextEffect?.destroy();\n this.#contextEffect = undefined;\n\n destroyObjectSignals(this);\n off(this);\n\n Object.freeze(this);\n }\n\n #syncIfScheduled = () => {\n if (this.#syncScheduled) {\n this.#syncNow();\n }\n };\n\n async #syncNow() {\n this.#syncScheduled = false;\n\n if (this.#isDestroyed) return;\n\n if (!this.isReady) {\n // the environment went away between scheduling and running this sync:\n // re-arm instead of dropping it, otherwise a pending syncWait() would never settle\n this.#syncAfterContextCreated = true;\n return;\n }\n\n const data = this.view!.buildChangeTrails(false);\n\n // The trail is fixed from here on, and with it the set of callers this cycle answers: it\n // leaves holding `#nextSyncCycle`, and a `syncWait()` from now on opens the cycle behind it.\n // The settlement travels in this frame rather than in a field, because two cycles can be in\n // flight at once -- `ComponentContext.buildChangeTrails()` says as much at its own end of this.\n const cycle = this.#nextSyncCycle;\n this.#nextSyncCycle = undefined;\n\n const waitForConfirmation = this.#syncWaitForConfirmation;\n this.#syncWaitForConfirmation = false;\n\n try {\n if (data.length > 0) {\n await this.envProxy!.applyChangeTrail(data, waitForConfirmation);\n }\n } catch (error) {\n // an environment that was torn down while its trail was in flight ends its cycle in silence:\n // destroy() has already rejected whoever waited on it and taken the listeners off, and a proxy\n // that refuses because it is being destroyed is not a failure anybody needs reported. The same\n // guard `#onProxyFailed()` carries at the neighbouring spot.\n if (this.#isDestroyed) return;\n\n // the log entry before anything else: what went wrong is on the record even if the report\n // of it runs into a listener that cannot cope\n this.logger.error('failed to apply change trail', error);\n this.#commitSyncCycle(data, error);\n this.#endSyncCycle(data, cycle, {reason: error});\n return;\n }\n\n if (this.#isDestroyed) return;\n\n // an empty change trail ends here as well -- nothing is sent, so nothing can be refused\n this.#commitSyncCycle(data);\n this.#endSyncCycle(data, cycle);\n }\n\n /**\n * Draws the line between what the Shadow Environment applied and what it still owes, and hands\n * it to the view. Runs ahead of {@link ShadowEnv.#endSyncCycle} so that a `SyncFailed` listener\n * and a waiting {@link ShadowEnv.syncWait} caller find bookkeeping that already holds.\n *\n * An empty change trail is settled as well: the build may have retired components even without\n * writing an entry for any of them.\n */\n #commitSyncCycle(changeTrail: ChangeTrailType, reason?: unknown): void {\n // A reason that does not say how far the Kernel got says nothing about the trail either: a\n // confirmation window that ran out leaves an environment that may well have applied every\n // entry, and a creation re-sent for an entity it already holds is refused -- a trail kept\n // pending on a guess would come back to that refusal cycle after cycle. The line moves only\n // where the Kernel itself named the count.\n const appliedCount = reason instanceof ChangeTrailRefusedError ? reason.appliedCount : changeTrail.length;\n\n // `?.` rather than `!`: the view can be taken off -- `env.view = undefined` -- between the\n // await above and this line\n this.view?.commitChangeTrail(appliedCount, changeTrail);\n }\n\n /**\n * Sends one of the two context events and keeps a listener that throws to itself.\n *\n * Both go out from inside the effect that watches `viewReady` and `proxyReady` -- `ContextLost`\n * from its cleanup -- so a throw would leave through whatever signal write set that effect\n * going, and reach code that has nothing to do with either event. `emitStrict()` serves every\n * listener whatever the one before it did, and what they threw is reported here and travels no\n * further.\n */\n #announceContext(eventName: string, self: ShadowEnv): void {\n try {\n emitStrict(self, eventName, self);\n } catch (error) {\n this.logger.error(`a ${eventName} listener threw`, error);\n }\n }\n\n /**\n * Ends a synchronization cycle in exactly one of its two outcomes. A cycle the Shadow\n * Environment applied resolves {@link ShadowEnv.syncWait} and emits {@link ShadowEnv.AfterSync};\n * a cycle whose change trail it refused rejects and emits {@link ShadowEnv.SyncFailed}. Only a\n * listener that can tell the two apart can react to either, so no cycle ever sends both.\n *\n * The waiting caller is settled before the event goes out, and the emit is the last thing that\n * happens: a settlement that travelled as a listener of its own would sit behind whatever the\n * application registered during setup, and this method is the wrong place to make a promise\n * depend on the order consumers subscribe in. The dispatch is `emitStrict()`, so every listener\n * hears about the cycle whatever the one before it did, and what they threw arrives here\n * afterwards -- one of them unchanged, several as an `AggregateError` in dispatch order. It ends\n * here as well: `#syncNow()` runs unawaited, and an error escaping it becomes an unhandled\n * rejection rather than a report anybody reads.\n *\n * Which cycle is being ended arrives as an argument: the caller carries it from the moment its\n * change trail was built, so a cycle that is still in flight cannot be settled by the one behind it.\n */\n #endSyncCycle(changeTrail: ChangeTrailType, cycle: SyncCycle | undefined, failure?: {reason: unknown}) {\n try {\n if (failure) {\n cycle?.reject(failure.reason);\n emitStrict(this as ShadowEnv, ShadowEnv.SyncFailed, failure.reason, changeTrail, this as ShadowEnv);\n } else {\n cycle?.resolve(changeTrail);\n emitStrict(this as ShadowEnv, ShadowEnv.AfterSync, changeTrail);\n }\n } catch (error) {\n this.logger.error('a sync cycle listener threw', error);\n }\n }\n\n #onMessageToView(event: Omit<MessageToViewEvent, 'transferables'>) {\n this.logger.debug('onMessageToView', event.type, event.data);\n this.view?.dispatchMessage(event.uuid, event.type, event.data, event.traverseChildren);\n }\n\n #onProxyFailed(reason: unknown) {\n // destroy() freezes this instance and destroys its signals; a proxy may report its failure afterwards\n if (this.#isDestroyed) return;\n\n this.logger.error('the environment proxy failed', reason);\n\n // the failure ends this proxy's turn the same way a reassignment would: a start of its own\n // that resolves afterwards must not report a lost environment as ready\n ++this.#proxyGeneration;\n\n try {\n // the reason before the consequence: ContextLost follows from dropping proxyReady.\n // `emitStrict()` so that one listener that cannot cope does not keep the rest from hearing\n // that the environment is gone; what it threw travels on to the proxy that reported the\n // failure, which is where this method has always put it.\n emitStrict(this as ShadowEnv, ShadowEnv.ProxyFailed, reason, this as ShadowEnv);\n } finally {\n // in the `finally`, because losing the environment is not up for debate:\n // a listener that throws must not leave `isReady` claiming otherwise\n this.proxyReady = false;\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }