@omerdlw/base-framework 1.0.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/dist/atoms/index.js +1 -103
  2. package/dist/atoms/index.js.map +1 -1
  3. package/dist/chunk-3BUP64Q6.js +105 -0
  4. package/dist/chunk-3BUP64Q6.js.map +1 -0
  5. package/dist/chunk-3MSK4XGK.js +9888 -0
  6. package/dist/chunk-3MSK4XGK.js.map +1 -0
  7. package/dist/chunk-4GMQKD6F.js +353 -0
  8. package/dist/chunk-4GMQKD6F.js.map +1 -0
  9. package/dist/chunk-65ZB4QTQ.js +888 -0
  10. package/dist/chunk-65ZB4QTQ.js.map +1 -0
  11. package/dist/chunk-6SG7V77J.js +577 -0
  12. package/dist/chunk-6SG7V77J.js.map +1 -0
  13. package/dist/chunk-7HQMXTNP.js +419 -0
  14. package/dist/chunk-7HQMXTNP.js.map +1 -0
  15. package/dist/chunk-7TAVYJ3A.js +371 -0
  16. package/dist/chunk-7TAVYJ3A.js.map +1 -0
  17. package/dist/chunk-AQ4BNXA2.js +349 -0
  18. package/dist/chunk-AQ4BNXA2.js.map +1 -0
  19. package/dist/chunk-CGHZSSFR.js +2166 -0
  20. package/dist/chunk-CGHZSSFR.js.map +1 -0
  21. package/dist/chunk-DGCQWQLZ.js +61 -0
  22. package/dist/chunk-DGCQWQLZ.js.map +1 -0
  23. package/dist/chunk-FIMPHODX.js +67 -0
  24. package/dist/chunk-FIMPHODX.js.map +1 -0
  25. package/dist/chunk-GF7TUX5I.js +1889 -0
  26. package/dist/chunk-GF7TUX5I.js.map +1 -0
  27. package/dist/chunk-JELG4JLT.js +454 -0
  28. package/dist/chunk-JELG4JLT.js.map +1 -0
  29. package/dist/chunk-K676GL7Z.js +51 -0
  30. package/dist/chunk-K676GL7Z.js.map +1 -0
  31. package/dist/chunk-KKQT46TP.js +26 -0
  32. package/dist/chunk-KKQT46TP.js.map +1 -0
  33. package/dist/chunk-QI3ALLIB.js +38 -0
  34. package/dist/chunk-QI3ALLIB.js.map +1 -0
  35. package/dist/chunk-QXR55VVS.js +1139 -0
  36. package/dist/chunk-QXR55VVS.js.map +1 -0
  37. package/dist/chunk-R2YGFJDJ.js +408 -0
  38. package/dist/chunk-R2YGFJDJ.js.map +1 -0
  39. package/dist/chunk-RFZQWLC5.js +27 -0
  40. package/dist/chunk-RFZQWLC5.js.map +1 -0
  41. package/dist/chunk-SYAVGTOX.js +521 -0
  42. package/dist/chunk-SYAVGTOX.js.map +1 -0
  43. package/dist/chunk-TV3WEF5G.js +784 -0
  44. package/dist/chunk-TV3WEF5G.js.map +1 -0
  45. package/dist/chunk-XASQT4CQ.js +280 -0
  46. package/dist/chunk-XASQT4CQ.js.map +1 -0
  47. package/dist/error/index.js +5 -682
  48. package/dist/error/index.js.map +1 -1
  49. package/dist/error/reporter.d.ts.map +1 -1
  50. package/dist/error/theme.d.ts +1 -1
  51. package/dist/error/theme.d.ts.map +1 -1
  52. package/dist/events.js +1 -7
  53. package/dist/events.js.map +1 -1
  54. package/dist/hooks/index.js +1 -358
  55. package/dist/hooks/index.js.map +1 -1
  56. package/dist/hooks/use-global-event.d.ts +1 -1
  57. package/dist/index.js +18 -20029
  58. package/dist/index.js.map +1 -1
  59. package/dist/kernel/index.js +2 -2035
  60. package/dist/kernel/index.js.map +1 -1
  61. package/dist/kernel/types.d.ts +1 -1
  62. package/dist/modules/ambient/analyze.d.ts +46 -0
  63. package/dist/modules/ambient/analyze.d.ts.map +1 -0
  64. package/dist/modules/ambient/constants.d.ts +1 -5
  65. package/dist/modules/ambient/constants.d.ts.map +1 -1
  66. package/dist/modules/ambient/context.d.ts.map +1 -1
  67. package/dist/modules/ambient/dom.d.ts +11 -12
  68. package/dist/modules/ambient/dom.d.ts.map +1 -1
  69. package/dist/modules/ambient/extractor.d.ts +10 -10
  70. package/dist/modules/ambient/extractor.d.ts.map +1 -1
  71. package/dist/modules/ambient/hooks.d.ts +1 -1
  72. package/dist/modules/ambient/hooks.d.ts.map +1 -1
  73. package/dist/modules/ambient/index.d.ts +6 -4
  74. package/dist/modules/ambient/index.d.ts.map +1 -1
  75. package/dist/modules/ambient/index.js +7 -762
  76. package/dist/modules/ambient/index.js.map +1 -1
  77. package/dist/modules/ambient/module.d.ts +1 -1
  78. package/dist/modules/ambient/module.d.ts.map +1 -1
  79. package/dist/modules/ambient/oklab.d.ts +36 -0
  80. package/dist/modules/ambient/oklab.d.ts.map +1 -0
  81. package/dist/modules/ambient/pipeline.d.ts +28 -0
  82. package/dist/modules/ambient/pipeline.d.ts.map +1 -0
  83. package/dist/modules/ambient/quantize.d.ts +22 -0
  84. package/dist/modules/ambient/quantize.d.ts.map +1 -0
  85. package/dist/modules/ambient/server/address.d.ts +8 -0
  86. package/dist/modules/ambient/server/address.d.ts.map +1 -0
  87. package/dist/modules/ambient/server/index.d.ts +53 -0
  88. package/dist/modules/ambient/server/index.d.ts.map +1 -0
  89. package/dist/modules/ambient/server/index.js +221 -0
  90. package/dist/modules/ambient/server/index.js.map +1 -0
  91. package/dist/modules/ambient/settings.d.ts +19 -0
  92. package/dist/modules/ambient/settings.d.ts.map +1 -0
  93. package/dist/modules/ambient/types.d.ts +105 -9
  94. package/dist/modules/ambient/types.d.ts.map +1 -1
  95. package/dist/modules/ambient/worker/index.d.ts +15 -0
  96. package/dist/modules/ambient/worker/index.d.ts.map +1 -0
  97. package/dist/modules/ambient/worker/index.js +114 -0
  98. package/dist/modules/ambient/worker/index.js.map +1 -0
  99. package/dist/modules/background/constants.d.ts +2 -2
  100. package/dist/modules/background/constants.d.ts.map +1 -1
  101. package/dist/modules/background/hooks.d.ts +1 -1
  102. package/dist/modules/background/index.js +6 -3078
  103. package/dist/modules/background/index.js.map +1 -1
  104. package/dist/modules/background/motion.d.ts +9 -7
  105. package/dist/modules/background/motion.d.ts.map +1 -1
  106. package/dist/modules/background/overlay.d.ts +3 -8
  107. package/dist/modules/background/overlay.d.ts.map +1 -1
  108. package/dist/modules/background/types.d.ts +16 -2
  109. package/dist/modules/background/types.d.ts.map +1 -1
  110. package/dist/modules/context-menu/constants.d.ts +2 -2
  111. package/dist/modules/context-menu/constants.d.ts.map +1 -1
  112. package/dist/modules/context-menu/hooks.d.ts +1 -1
  113. package/dist/modules/context-menu/index.js +10 -1896
  114. package/dist/modules/context-menu/index.js.map +1 -1
  115. package/dist/modules/context-menu/motion.d.ts +1 -8
  116. package/dist/modules/context-menu/motion.d.ts.map +1 -1
  117. package/dist/modules/context-menu/overlay.d.ts.map +1 -1
  118. package/dist/modules/context-menu/types.d.ts +16 -2
  119. package/dist/modules/context-menu/types.d.ts.map +1 -1
  120. package/dist/modules/controls/constants.d.ts +1 -1
  121. package/dist/modules/controls/constants.d.ts.map +1 -1
  122. package/dist/modules/controls/entries.d.ts +1 -1
  123. package/dist/modules/controls/hooks.d.ts +1 -1
  124. package/dist/modules/controls/index.js +4 -1110
  125. package/dist/modules/controls/index.js.map +1 -1
  126. package/dist/modules/controls/overlay.d.ts +1 -1
  127. package/dist/modules/controls/types.d.ts +2 -2
  128. package/dist/modules/dock/cards.d.ts +708 -24
  129. package/dist/modules/dock/cards.d.ts.map +1 -1
  130. package/dist/modules/dock/constants.d.ts +2 -2
  131. package/dist/modules/dock/constants.d.ts.map +1 -1
  132. package/dist/modules/dock/helpers.d.ts +2 -2
  133. package/dist/modules/dock/hooks.d.ts +2 -2
  134. package/dist/modules/dock/index.d.ts +1 -1
  135. package/dist/modules/dock/index.d.ts.map +1 -1
  136. package/dist/modules/dock/index.js +9 -12132
  137. package/dist/modules/dock/index.js.map +1 -1
  138. package/dist/modules/dock/module.d.ts +1 -1
  139. package/dist/modules/dock/motion.d.ts +41 -915
  140. package/dist/modules/dock/motion.d.ts.map +1 -1
  141. package/dist/modules/dock/overlay.d.ts.map +1 -1
  142. package/dist/modules/dock/runtime/dock.d.ts +1 -23
  143. package/dist/modules/dock/runtime/dock.d.ts.map +1 -1
  144. package/dist/modules/dock/styles.d.ts +4 -4
  145. package/dist/modules/dock/surface/hooks.d.ts +5 -20
  146. package/dist/modules/dock/surface/hooks.d.ts.map +1 -1
  147. package/dist/modules/dock/surface/machine.d.ts +4 -3
  148. package/dist/modules/dock/surface/machine.d.ts.map +1 -1
  149. package/dist/modules/dock/surface/stack.d.ts.map +1 -1
  150. package/dist/modules/dock/types.d.ts +158 -3
  151. package/dist/modules/dock/types.d.ts.map +1 -1
  152. package/dist/modules/index.js +16 -17883
  153. package/dist/modules/index.js.map +1 -1
  154. package/dist/modules/loading/constants.d.ts +1 -1
  155. package/dist/modules/loading/constants.d.ts.map +1 -1
  156. package/dist/modules/loading/context.d.ts +1 -1
  157. package/dist/modules/loading/hooks.d.ts +1 -1
  158. package/dist/modules/loading/index.js +5 -1153
  159. package/dist/modules/loading/index.js.map +1 -1
  160. package/dist/modules/loading/types.d.ts +2 -2
  161. package/dist/modules/media/context.d.ts +1 -1
  162. package/dist/modules/media/index.js +3 -570
  163. package/dist/modules/media/index.js.map +1 -1
  164. package/dist/modules/media/types.d.ts +2 -2
  165. package/dist/modules/modal/constants.d.ts +2 -2
  166. package/dist/modules/modal/constants.d.ts.map +1 -1
  167. package/dist/modules/modal/context.d.ts +1 -1
  168. package/dist/modules/modal/hooks.d.ts +3 -3
  169. package/dist/modules/modal/index.js +8 -2355
  170. package/dist/modules/modal/index.js.map +1 -1
  171. package/dist/modules/modal/motion.d.ts +3 -8
  172. package/dist/modules/modal/motion.d.ts.map +1 -1
  173. package/dist/modules/modal/overlay.d.ts.map +1 -1
  174. package/dist/modules/modal/types.d.ts +21 -0
  175. package/dist/modules/modal/types.d.ts.map +1 -1
  176. package/dist/modules/notification/constants.d.ts +2 -2
  177. package/dist/modules/notification/constants.d.ts.map +1 -1
  178. package/dist/modules/notification/context.d.ts +1 -1
  179. package/dist/modules/notification/hooks.d.ts +1 -1
  180. package/dist/modules/notification/index.js +4 -828
  181. package/dist/modules/notification/index.js.map +1 -1
  182. package/dist/modules/notification/motion.d.ts +1 -7
  183. package/dist/modules/notification/motion.d.ts.map +1 -1
  184. package/dist/modules/notification/overlay.d.ts.map +1 -1
  185. package/dist/modules/notification/types.d.ts +9 -1
  186. package/dist/modules/notification/types.d.ts.map +1 -1
  187. package/dist/overlay-TZ6L52A5.js +9 -0
  188. package/dist/overlay-TZ6L52A5.js.map +1 -0
  189. package/dist/provider.d.ts +1 -1
  190. package/dist/provider.d.ts.map +1 -1
  191. package/dist/provider.js +6 -1968
  192. package/dist/provider.js.map +1 -1
  193. package/dist/result.js +2 -63
  194. package/dist/result.js.map +1 -1
  195. package/dist/theme.d.ts +45 -8
  196. package/dist/theme.d.ts.map +1 -1
  197. package/dist/theme.js +3 -41
  198. package/dist/theme.js.map +1 -1
  199. package/dist/tokens/index.d.ts +1 -0
  200. package/dist/tokens/index.d.ts.map +1 -1
  201. package/dist/tokens/index.js +126 -155
  202. package/dist/tokens/index.js.map +1 -1
  203. package/dist/tokens/motion-config.d.ts +44 -0
  204. package/dist/tokens/motion-config.d.ts.map +1 -0
  205. package/dist/tokens/motion.d.ts +23 -174
  206. package/dist/tokens/motion.d.ts.map +1 -1
  207. package/dist/utils/index.js +4 -82
  208. package/dist/utils/index.js.map +1 -1
  209. package/dist/utils/report.d.ts.map +1 -1
  210. package/docs/README.md +1 -0
  211. package/docs/architecture-and-rules.md +4 -3
  212. package/docs/core-engine.md +7 -10
  213. package/docs/getting-started.md +4 -2
  214. package/docs/modules/ambient.md +194 -80
  215. package/docs/modules/background.md +3 -3
  216. package/docs/modules/context-menu.md +2 -2
  217. package/docs/modules/dock.md +8 -5
  218. package/docs/modules/modal.md +2 -2
  219. package/docs/modules/notification.md +2 -2
  220. package/docs/theming.md +81 -9
  221. package/package.json +22 -5
  222. package/templates/AGENTS.md +1 -1
  223. package/templates/motion/background.ts +17 -0
  224. package/templates/motion/context-menu.ts +63 -0
  225. package/templates/motion/dock.ts +327 -0
  226. package/templates/motion/modal.ts +79 -0
  227. package/templates/motion/notification.ts +27 -0
  228. package/templates/motion/tokens.ts +47 -0
  229. package/templates/tsconfig.json +7 -0
  230. package/dist/modules/ambient/color.d.ts +0 -21
  231. package/dist/modules/ambient/color.d.ts.map +0 -1
@@ -1,2038 +1,5 @@
1
1
  "use client";
2
- import { createContext, useState, useMemo, useCallback, useSyncExternalStore, use, useId, useRef, useEffect, createElement, Fragment as Fragment$1, useLayoutEffect, isValidElement, cloneElement, Children } from 'react';
3
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { usePathname } from 'next/navigation';
5
-
6
- // src/kernel/constants.ts
7
- var DEFAULT_SOURCE = "dynamic";
8
- var REGISTRY_SOURCES = Object.freeze({
9
- STATIC: "static",
10
- DYNAMIC: "dynamic",
11
- USER: "user"
12
- });
13
- var REGISTRY_LIFECYCLES = Object.freeze({
14
- IMMEDIATE: "immediate",
15
- GRACEFUL: "graceful",
16
- PERSISTENT: "persistent",
17
- ROUTE: "route"
18
- });
19
- var REGISTRY_VALIDATION_MODES = Object.freeze({
20
- WARN: "warn",
21
- STRICT: "strict"
22
- });
23
- var REGISTRY_METADATA_KEYS = Object.freeze([
24
- "cleanup",
25
- "cleanupDelayMs",
26
- "instanceId",
27
- "lifecycle",
28
- "priority",
29
- "source",
30
- "scope",
31
- "validation"
32
- ]);
33
- var REGISTRY_SOURCE_PRIORITY = Object.freeze({
34
- [REGISTRY_SOURCES.STATIC]: 100,
35
- [REGISTRY_SOURCES.DYNAMIC]: 200,
36
- [REGISTRY_SOURCES.USER]: 300
37
- });
38
- var REGISTRY_SOURCE_RANK = Object.freeze({
39
- [REGISTRY_SOURCES.STATIC]: 10,
40
- [REGISTRY_SOURCES.DYNAMIC]: 20,
41
- [REGISTRY_SOURCES.USER]: 30
42
- });
43
- var REGISTRY_LIFECYCLE_VALUES = new Set(
44
- Object.values(REGISTRY_LIFECYCLES)
45
- );
46
- var REGISTRY_METADATA_KEY_SET = new Set(
47
- REGISTRY_METADATA_KEYS
48
- );
49
- var REGISTRY_SCOPE_KINDS = Object.freeze({
50
- APP: "app",
51
- SESSION: "session",
52
- ROUTE: "route",
53
- INSTANCE: "instance",
54
- WORKSPACE: "workspace"
55
- });
56
- var DEFAULT_REGISTRY_SCOPE = REGISTRY_SCOPE_KINDS.APP;
57
- function getOrCreateGlobalContext(name, defaultValue) {
58
- const sym = /* @__PURE__ */ Symbol.for(`@omerdlw/base-framework/context/${name}`);
59
- const store = globalThis;
60
- if (!store[sym]) {
61
- store[sym] = createContext(defaultValue);
62
- }
63
- return store[sym];
64
- }
65
-
66
- // src/utils/string.ts
67
- function trimToNull(value) {
68
- if (value === null || value === void 0) return null;
69
- const trimmed = String(value).trim();
70
- return trimmed.length > 0 ? trimmed : null;
71
- }
72
-
73
- // src/utils/dom.ts
74
- var isBrowser = typeof window !== "undefined";
75
-
76
- // src/utils/object.ts
77
- function isObject(value) {
78
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
79
- }
80
- function isPlainObject(value) {
81
- if (!isObject(value)) return false;
82
- const proto = Object.getPrototypeOf(value);
83
- return proto === Object.prototype || proto === null;
84
- }
85
- function shallowEqual(a, b) {
86
- if (Object.is(a, b)) return true;
87
- if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
88
- return false;
89
- }
90
- const keysA = Object.keys(a);
91
- const keysB = Object.keys(b);
92
- if (keysA.length !== keysB.length) return false;
93
- for (const key of keysA) {
94
- if (!Object.prototype.hasOwnProperty.call(b, key) || !Object.is(
95
- a[key],
96
- b[key]
97
- )) {
98
- return false;
99
- }
100
- }
101
- return true;
102
- }
103
- function report(scope, error, level = "error") {
104
- if (process.env.NODE_ENV === "production" && typeof window !== "undefined") {
105
- return;
106
- }
107
- console[level](`[${scope}]`, error);
108
- }
109
-
110
- // src/utils/store.ts
111
- function freezeStoreSnapshot(state) {
112
- if (process.env.NODE_ENV === "production" || !state || typeof state !== "object") {
113
- return state;
114
- }
115
- const seen = /* @__PURE__ */ new WeakSet();
116
- const freeze = (value) => {
117
- if (seen.has(value) || Object.isFrozen(value)) return;
118
- seen.add(value);
119
- const prototype = Object.getPrototypeOf(value);
120
- if (Array.isArray(value) || prototype === Object.prototype || prototype === null) {
121
- for (const key of Reflect.ownKeys(value)) {
122
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
123
- if (descriptor && "value" in descriptor && descriptor.value !== null) {
124
- if (typeof descriptor.value === "object") freeze(descriptor.value);
125
- }
126
- }
127
- }
128
- Object.freeze(value);
129
- };
130
- freeze(state);
131
- return state;
132
- }
133
- function createStore(initialState, { freezeSnapshots = true } = {}) {
134
- const listeners = /* @__PURE__ */ new Set();
135
- const prepare = freezeSnapshots ? freezeStoreSnapshot : (state) => state;
136
- let snapshot = prepare(initialState);
137
- const publish = (nextStateOrUpdater) => {
138
- const nextState = typeof nextStateOrUpdater === "function" ? nextStateOrUpdater(snapshot) : nextStateOrUpdater;
139
- if (Object.is(snapshot, nextState)) return false;
140
- snapshot = prepare(nextState);
141
- for (const listener of listeners) {
142
- try {
143
- listener();
144
- } catch (error) {
145
- report("CoreStore subscriber", error, "warn");
146
- }
147
- }
148
- return true;
149
- };
150
- const setState = (updater) => {
151
- if (typeof updater === "function") {
152
- return publish(updater);
153
- }
154
- if (snapshot && typeof snapshot === "object" && updater && typeof updater === "object") {
155
- return publish({ ...snapshot, ...updater });
156
- }
157
- return publish(updater);
158
- };
159
- return Object.freeze({
160
- getSnapshot() {
161
- return snapshot;
162
- },
163
- publish,
164
- setState,
165
- subscribe(listener) {
166
- if (typeof listener !== "function") return () => {
167
- };
168
- listeners.add(listener);
169
- return () => listeners.delete(listener);
170
- }
171
- });
172
- }
173
-
174
- // src/kernel/utils.ts
175
- function hasOwnProperty(target, key) {
176
- return Object.prototype.hasOwnProperty.call(target, key);
177
- }
178
- function parseFiniteNumber(value) {
179
- const parsed = Number(value);
180
- return Number.isFinite(parsed) ? parsed : null;
181
- }
182
- function getValidString(value, fallback = null) {
183
- return trimToNull(value) ?? fallback;
184
- }
185
- function resolveInstanceId(value) {
186
- return isObject(value) && typeof value.instanceId === "string" ? value.instanceId : null;
187
- }
188
- function getSourceRank(source) {
189
- return REGISTRY_SOURCE_RANK[source] ?? 0;
190
- }
191
- function resolveRegisterInput(sourceOrOptions, optionsArg) {
192
- if (typeof sourceOrOptions === "string") {
193
- return {
194
- source: sourceOrOptions,
195
- options: isObject(optionsArg) ? optionsArg : {}
196
- };
197
- }
198
- if (isObject(sourceOrOptions)) {
199
- return {
200
- source: typeof sourceOrOptions.source === "string" ? sourceOrOptions.source : DEFAULT_SOURCE,
201
- options: sourceOrOptions
202
- };
203
- }
204
- return {
205
- source: DEFAULT_SOURCE,
206
- options: isObject(optionsArg) ? optionsArg : {}
207
- };
208
- }
209
- function resolveScope(options) {
210
- return typeof options?.scope === "string" && options.scope.trim() ? options.scope.trim() : DEFAULT_REGISTRY_SCOPE;
211
- }
212
- function resolveUnregisterInput(sourceOrOptions) {
213
- if (typeof sourceOrOptions === "string") {
214
- return { instanceId: null, scope: null, source: sourceOrOptions };
215
- }
216
- if (isObject(sourceOrOptions)) {
217
- return {
218
- instanceId: resolveInstanceId(sourceOrOptions),
219
- scope: typeof sourceOrOptions.scope === "string" && sourceOrOptions.scope.trim() ? sourceOrOptions.scope.trim() : null,
220
- source: typeof sourceOrOptions.source === "string" ? sourceOrOptions.source : DEFAULT_SOURCE
221
- };
222
- }
223
- return { instanceId: null, scope: null, source: DEFAULT_SOURCE };
224
- }
225
- function mergeModuleConfigs(base, patch) {
226
- const source = base;
227
- const changes = patch;
228
- const result = { ...source };
229
- Object.keys(changes).forEach((key) => {
230
- const baseVal = source[key];
231
- const patchVal = changes[key];
232
- if (baseVal && typeof baseVal === "object" && !Array.isArray(baseVal) && patchVal && typeof patchVal === "object" && !Array.isArray(patchVal)) {
233
- result[key] = { ...baseVal, ...patchVal };
234
- } else {
235
- result[key] = patchVal;
236
- }
237
- });
238
- return result;
239
- }
240
-
241
- // src/kernel/schema.ts
242
- function resolveLifecycle(metadata, fallback) {
243
- const lifecycle = metadata?.lifecycle ?? metadata?.cleanup;
244
- return lifecycle && REGISTRY_LIFECYCLE_VALUES.has(lifecycle) ? lifecycle : fallback;
245
- }
246
- function validateRegistryMetadata(metadata) {
247
- if (metadata === void 0 || metadata === null)
248
- return { issues: [], valid: true };
249
- if (!isObject(metadata))
250
- return { issues: ["registry metadata must be an object"], valid: false };
251
- const issues = [];
252
- Object.keys(metadata).forEach((key) => {
253
- if (!REGISTRY_METADATA_KEY_SET.has(key))
254
- issues.push(`unknown registry metadata field: ${key}`);
255
- });
256
- if (metadata.source !== void 0 && !getValidString(metadata.source))
257
- issues.push("source must be a non-empty string");
258
- if (metadata.instanceId !== void 0 && !getValidString(metadata.instanceId))
259
- issues.push("instanceId must be a non-empty string");
260
- if (metadata.scope !== void 0 && !getValidString(metadata.scope))
261
- issues.push("scope must be a non-empty string");
262
- if (metadata.priority !== void 0 && parseFiniteNumber(metadata.priority) === null)
263
- issues.push("priority must be a finite number");
264
- if (metadata.cleanupDelayMs !== void 0) {
265
- const delay = parseFiniteNumber(metadata.cleanupDelayMs);
266
- if (delay === null || delay < 0)
267
- issues.push("cleanupDelayMs must be a non-negative finite number");
268
- }
269
- const lifecycle = metadata.lifecycle ?? metadata.cleanup;
270
- if (lifecycle !== void 0 && !REGISTRY_LIFECYCLE_VALUES.has(String(lifecycle))) {
271
- issues.push(
272
- `lifecycle must be one of: ${[...REGISTRY_LIFECYCLE_VALUES].join(", ")}`
273
- );
274
- }
275
- if (metadata.validation !== void 0 && !Object.values(REGISTRY_VALIDATION_MODES).includes(
276
- metadata.validation
277
- )) {
278
- issues.push(
279
- `validation must be one of: ${Object.values(REGISTRY_VALIDATION_MODES).join(", ")}`
280
- );
281
- }
282
- return { issues, valid: issues.length === 0 };
283
- }
284
- function validateRegistryKey(type, key, definitions) {
285
- const definition = definitions.get(type);
286
- const issues = [];
287
- if (!definition) issues.push(`unknown registry type: ${String(type)}`);
288
- if (!getValidString(key))
289
- return {
290
- issues: [...issues, "key must be a non-empty string"],
291
- valid: false
292
- };
293
- const normalizedKey = String(key).trim();
294
- if (definition?.keyPolicy === "singleton") {
295
- const expectedKey = definition.singletonKey;
296
- if (expectedKey && normalizedKey !== expectedKey)
297
- issues.push(`${type} key must be ${expectedKey}`);
298
- } else if (definition?.keyPolicy === "path") {
299
- if (!normalizedKey.startsWith("/"))
300
- issues.push(`${type} key must be an absolute path`);
301
- } else if (definition?.keyPolicy === "route") {
302
- if (!normalizedKey.startsWith("/") && !definition.reservedKeys?.includes(normalizedKey)) {
303
- issues.push(`${type} key must be a route path or a reserved route key`);
304
- }
305
- }
306
- return { issues, valid: issues.length === 0 };
307
- }
308
- function validateRegistryValue(type, key, value, definitions) {
309
- const definition = definitions.get(type);
310
- const issues = [...validateRegistryKey(type, key, definitions).issues];
311
- const valueKind = definition?.valueKind ?? "object";
312
- if (definition && valueKind === "object" && !isPlainObject(value)) {
313
- issues.push(`${type} values must be plain objects`);
314
- }
315
- if (definition && valueKind === "component" && typeof value !== "function" && !isPlainObject(value)) {
316
- issues.push(
317
- `${type} values must be component functions or component objects`
318
- );
319
- }
320
- const validation = definition?.validate?.(value);
321
- if (validation && !validation.valid && Array.isArray(validation.issues)) {
322
- issues.push(...validation.issues);
323
- }
324
- return { issues, valid: issues.length === 0 };
325
- }
326
- function normalizeRegistryMetadata(metadata, {
327
- defaultCleanupDelayMs = null,
328
- defaultLifecycle = null,
329
- defaultSource = DEFAULT_SOURCE
330
- } = {}) {
331
- const registryMeta = isObject(metadata) ? metadata : {};
332
- const normalizedDefaultDelay = parseFiniteNumber(defaultCleanupDelayMs);
333
- const fallbackCleanupDelayMs = normalizedDefaultDelay !== null && normalizedDefaultDelay >= 0 ? normalizedDefaultDelay : null;
334
- const fallbackLifecycle = defaultLifecycle && REGISTRY_LIFECYCLE_VALUES.has(defaultLifecycle) ? defaultLifecycle : null;
335
- const source = getValidString(registryMeta.source) || getValidString(defaultSource, DEFAULT_SOURCE) || DEFAULT_SOURCE;
336
- const scope = getValidString(registryMeta.scope);
337
- const priority = parseFiniteNumber(registryMeta.priority);
338
- const lifecycle = resolveLifecycle(registryMeta, fallbackLifecycle);
339
- const validation = isValidationMode(registryMeta.validation) ? registryMeta.validation : null;
340
- const cleanupDelayCandidate = parseFiniteNumber(registryMeta.cleanupDelayMs);
341
- let cleanupDelayMs = cleanupDelayCandidate !== null && cleanupDelayCandidate >= 0 ? cleanupDelayCandidate : fallbackCleanupDelayMs;
342
- if (lifecycle === REGISTRY_LIFECYCLES.IMMEDIATE) {
343
- cleanupDelayMs = 0;
344
- } else if ((lifecycle === REGISTRY_LIFECYCLES.GRACEFUL || lifecycle === REGISTRY_LIFECYCLES.ROUTE) && cleanupDelayMs === null) {
345
- cleanupDelayMs = fallbackCleanupDelayMs;
346
- }
347
- return {
348
- cleanupDelayMs,
349
- lifecycle,
350
- priority,
351
- registerOptions: {
352
- ...priority !== null && { priority },
353
- ...validation === REGISTRY_VALIDATION_MODES.STRICT && { validation },
354
- ...scope && { scope }
355
- },
356
- source,
357
- ...scope && { scope },
358
- ...validation && { validation }
359
- };
360
- }
361
- function isValidationMode(value) {
362
- return Object.values(REGISTRY_VALIDATION_MODES).includes(value);
363
- }
364
- function pickRegistryMetadata(options) {
365
- if (!isObject(options)) return {};
366
- return Object.fromEntries(
367
- REGISTRY_METADATA_KEYS.filter((key) => options[key] !== void 0).map(
368
- (key) => [key, options[key]]
369
- )
370
- );
371
- }
372
-
373
- // src/kernel/operations.ts
374
- function createInitialRegistriesFor(definitions) {
375
- return Object.fromEntries(
376
- Array.from(definitions.keys(), (type) => [type, {}])
377
- );
378
- }
379
- function buildSourceRecord({
380
- source,
381
- value,
382
- instanceId = null,
383
- priority,
384
- timestamp,
385
- sequence,
386
- scope = DEFAULT_REGISTRY_SCOPE
387
- }) {
388
- return {
389
- updatedAt: timestamp,
390
- sequence: Number.isFinite(sequence) ? sequence : timestamp,
391
- instanceId: typeof instanceId === "string" ? instanceId : null,
392
- priority,
393
- value,
394
- source,
395
- scope
396
- };
397
- }
398
- function createRecordKey(source, instanceId = null, scope = DEFAULT_REGISTRY_SCOPE) {
399
- if (scope === DEFAULT_REGISTRY_SCOPE) {
400
- if (typeof instanceId === "string" && instanceId.length > 0) {
401
- return `instance:${JSON.stringify([source, instanceId])}`;
402
- }
403
- return `source:${JSON.stringify(source)}`;
404
- }
405
- if (typeof instanceId === "string" && instanceId.length > 0) {
406
- return `instance:${JSON.stringify([scope, source, instanceId])}`;
407
- }
408
- return `source:${JSON.stringify([scope, source])}`;
409
- }
410
- function getSourceRecords(entry, source, scope = null) {
411
- if (!entry) return [];
412
- return Object.entries(entry).map(([recordKey, rawRecord]) => ({
413
- recordKey,
414
- record: toSourceRecord(rawRecord, recordKey)
415
- })).filter(
416
- ({ record }) => record?.source === source && (scope === null || record.scope === scope)
417
- );
418
- }
419
- function getSourceRecord(entry, source, instanceId = null, scope = DEFAULT_REGISTRY_SCOPE) {
420
- const recordKey = createRecordKey(source, instanceId, scope);
421
- return toSourceRecord(entry?.[recordKey], source);
422
- }
423
- function resolveRecordPriority(options, source) {
424
- if (isObject(options) && hasOwnProperty(options, "priority")) {
425
- const parsedPriority = Number(options.priority);
426
- if (Number.isFinite(parsedPriority)) return parsedPriority;
427
- }
428
- return REGISTRY_SOURCE_PRIORITY[source] ?? 0;
429
- }
430
- function toSourceRecord(rawValue, source = DEFAULT_SOURCE) {
431
- if (rawValue === void 0) return null;
432
- const rawRecord = rawValue;
433
- const isWrappedRecord = isObject(rawValue) && hasOwnProperty(rawRecord, "value") && hasOwnProperty(rawRecord, "updatedAt") && hasOwnProperty(rawRecord, "priority") && hasOwnProperty(rawRecord, "source");
434
- if (isWrappedRecord) {
435
- const parsedPriority = Number(rawRecord.priority);
436
- return {
437
- updatedAt: Number(rawRecord.updatedAt) || 0,
438
- sequence: Number(rawRecord.sequence) || Number(rawRecord.updatedAt) || 0,
439
- instanceId: typeof rawRecord.instanceId === "string" ? rawRecord.instanceId : null,
440
- priority: Number.isFinite(parsedPriority) ? parsedPriority : REGISTRY_SOURCE_PRIORITY[source] ?? 0,
441
- source: typeof rawRecord.source === "string" ? rawRecord.source : source,
442
- scope: typeof rawRecord.scope === "string" ? rawRecord.scope : DEFAULT_REGISTRY_SCOPE,
443
- value: rawRecord.value
444
- };
445
- }
446
- return {
447
- updatedAt: 0,
448
- sequence: 0,
449
- instanceId: null,
450
- priority: REGISTRY_SOURCE_PRIORITY[source] ?? 0,
451
- source,
452
- scope: DEFAULT_REGISTRY_SCOPE,
453
- value: rawValue
454
- };
455
- }
456
- function compareRecords(a, b) {
457
- if (a.priority !== b.priority) return a.priority - b.priority;
458
- const rankDiff = getSourceRank(a.source) - getSourceRank(b.source);
459
- if (rankDiff !== 0) return rankDiff;
460
- return (a.sequence ?? a.updatedAt) - (b.sequence ?? b.updatedAt);
461
- }
462
- function recordsHaveSameValue(prevRecord, nextRecord) {
463
- if (Object.is(prevRecord?.value, nextRecord?.value)) return true;
464
- if (isObject(prevRecord?.value) && isObject(nextRecord?.value)) {
465
- return shallowEqual(prevRecord.value, nextRecord.value);
466
- }
467
- return false;
468
- }
469
- function hasRecordChanged(prevRecord, nextRecord) {
470
- if (!prevRecord) return true;
471
- return prevRecord.priority !== nextRecord.priority || prevRecord.source !== nextRecord.source || prevRecord.instanceId !== nextRecord.instanceId || prevRecord.scope !== nextRecord.scope || !recordsHaveSameValue(prevRecord, nextRecord);
472
- }
473
- function hasAnySourceRecord(entry) {
474
- return Object.values(entry || {}).some(
475
- (rawRecord) => rawRecord !== void 0
476
- );
477
- }
478
- function setSourceRecord(state, type, key, source, record) {
479
- const typeRegistry = state[type] || {};
480
- const currentEntry = typeRegistry[key] || {};
481
- const recordKey = createRecordKey(source, record.instanceId, record.scope);
482
- const prevRecord = toSourceRecord(currentEntry[recordKey], source);
483
- if (!hasRecordChanged(prevRecord, record)) {
484
- return state;
485
- }
486
- return {
487
- ...state,
488
- [type]: {
489
- ...typeRegistry,
490
- [key]: {
491
- ...currentEntry,
492
- [recordKey]: record
493
- }
494
- }
495
- };
496
- }
497
- function removeSourceRecord(state, type, key, source, instanceId = null, scope = null) {
498
- const typeRegistry = state[type];
499
- const currentEntry = typeRegistry?.[key];
500
- if (!typeRegistry || !currentEntry) return state;
501
- let activeRecords = [];
502
- if (typeof instanceId === "string" && instanceId.length > 0 && scope !== null) {
503
- const safeScope = scope || DEFAULT_REGISTRY_SCOPE;
504
- const recordKey = createRecordKey(source, instanceId, safeScope);
505
- const record = getSourceRecord(currentEntry, source, instanceId, safeScope);
506
- if (record) activeRecords.push({ recordKey, record });
507
- } else {
508
- activeRecords = getSourceRecords(currentEntry, source, scope).filter(({ record }) => !instanceId || record?.instanceId === instanceId).filter(
509
- (entry) => Boolean(entry.record)
510
- );
511
- }
512
- if (activeRecords.length === 0) return state;
513
- const nextEntry = { ...currentEntry };
514
- activeRecords.forEach(({ recordKey }) => {
515
- delete nextEntry[recordKey];
516
- });
517
- if (!hasAnySourceRecord(nextEntry)) {
518
- const nextTypeRegistry = { ...typeRegistry };
519
- delete nextTypeRegistry[key];
520
- return { ...state, [type]: nextTypeRegistry };
521
- }
522
- return {
523
- ...state,
524
- [type]: { ...typeRegistry, [key]: nextEntry }
525
- };
526
- }
527
- function resolveEntryValueFor(definitions, type, entry, scope = null) {
528
- if (!entry) return void 0;
529
- const activeRecords = Object.entries(entry).map(([source, rawRecord]) => toSourceRecord(rawRecord, source)).filter(
530
- (record) => record !== null && (scope === null || record.scope === scope)
531
- );
532
- if (activeRecords.length === 0) return void 0;
533
- const merge = definitions.get(type)?.merge;
534
- if (merge) {
535
- const sortedRecords = [...activeRecords].sort(compareRecords);
536
- const mergeCandidate = sortedRecords.every(
537
- (record) => isObject(record.value)
538
- );
539
- if (mergeCandidate) {
540
- const values = sortedRecords.map(
541
- (record) => record.value
542
- );
543
- return merge(values);
544
- }
545
- return sortedRecords[sortedRecords.length - 1].value;
546
- }
547
- return activeRecords.reduce(
548
- (winner, current) => compareRecords(current, winner) > 0 ? current : winner
549
- ).value;
550
- }
551
- function createResolverCacheFor(definitions) {
552
- const entryCache = /* @__PURE__ */ new WeakMap();
553
- return (type, entry, scope = null) => {
554
- if (!entry || typeof entry !== "object") {
555
- return resolveEntryValueFor(definitions, type, entry, scope);
556
- }
557
- let typeCache = entryCache.get(entry);
558
- if (!typeCache) {
559
- typeCache = /* @__PURE__ */ new Map();
560
- entryCache.set(entry, typeCache);
561
- }
562
- const cacheKey = scope || "default";
563
- if (typeCache.has(cacheKey)) return typeCache.get(cacheKey);
564
- const value = resolveEntryValueFor(definitions, type, entry, scope);
565
- typeCache.set(cacheKey, value);
566
- return value;
567
- };
568
- }
569
- function createRegisterOperation(type, key, item, sourceOrOptions, optionsArg, timestamp, sequence = timestamp) {
570
- const { source, options } = resolveRegisterInput(sourceOrOptions, optionsArg);
571
- const instanceId = resolveInstanceId(options);
572
- const scope = resolveScope(options);
573
- return {
574
- kind: "register",
575
- validation: options.validation,
576
- source,
577
- scope,
578
- record: buildSourceRecord({
579
- source,
580
- value: item,
581
- instanceId,
582
- priority: resolveRecordPriority(options, source),
583
- scope,
584
- timestamp,
585
- sequence
586
- }),
587
- instanceId,
588
- type,
589
- key: typeof key === "string" ? key.trim() : key
590
- };
591
- }
592
- function createUnregisterOperation(type, key, sourceOrOptions) {
593
- const { scope, source, instanceId } = resolveUnregisterInput(sourceOrOptions);
594
- return {
595
- kind: "unregister",
596
- instanceId,
597
- scope,
598
- source,
599
- type,
600
- key: typeof key === "string" ? key.trim() : key
601
- };
602
- }
603
- function isValidRegistryTargetFor(definitions, type, key) {
604
- return validateRegistryKey(type, key, definitions).valid;
605
- }
606
- function applyOperationFor(definitions, state, operation) {
607
- if (!isValidRegistryTargetFor(definitions, operation?.type, operation?.key))
608
- return state;
609
- if (operation.kind === "register") {
610
- return setSourceRecord(
611
- state,
612
- operation.type,
613
- operation.key,
614
- operation.source,
615
- operation.record
616
- );
617
- }
618
- if (operation.kind === "unregister") {
619
- return removeSourceRecord(
620
- state,
621
- operation.type,
622
- operation.key,
623
- operation.source,
624
- operation.instanceId,
625
- operation.scope
626
- );
627
- }
628
- return state;
629
- }
630
- function hasOperationEffectFor(definitions, state, operation) {
631
- if (!isValidRegistryTargetFor(definitions, operation?.type, operation?.key))
632
- return false;
633
- if (operation.kind === "register") {
634
- const currentRecord = getSourceRecord(
635
- state[operation.type]?.[operation.key],
636
- operation.source,
637
- operation.instanceId,
638
- operation.scope
639
- );
640
- return hasRecordChanged(currentRecord, operation.record);
641
- }
642
- if (operation.kind === "unregister") {
643
- const entry = state[operation.type]?.[operation.key];
644
- if (typeof operation.instanceId === "string" && operation.instanceId.length > 0) {
645
- return operation.scope === null ? getSourceRecords(entry, operation.source).some(
646
- ({ record }) => record?.instanceId === operation.instanceId
647
- ) : Boolean(
648
- getSourceRecord(
649
- entry,
650
- operation.source,
651
- operation.instanceId,
652
- operation.scope
653
- )
654
- );
655
- }
656
- return getSourceRecords(entry, operation.source, operation.scope).length > 0;
657
- }
658
- return false;
659
- }
660
- function resolveEffectiveOperationsFor(definitions, state, operations) {
661
- const effectiveOperations = [];
662
- let nextState = state;
663
- operations.forEach((operation) => {
664
- if (!hasOperationEffectFor(definitions, nextState, operation)) return;
665
- effectiveOperations.push(operation);
666
- nextState = applyOperationFor(definitions, nextState, operation);
667
- });
668
- return { effectiveOperations, nextState };
669
- }
670
- function createRegistryOperations(definitions) {
671
- return Object.freeze({
672
- applyOperation: (state, operation) => applyOperationFor(definitions, state, operation),
673
- createInitialRegistries: () => createInitialRegistriesFor(definitions),
674
- createResolverCache: () => createResolverCacheFor(definitions),
675
- hasOperationEffect: (state, operation) => hasOperationEffectFor(definitions, state, operation),
676
- isRegistryType: (type) => definitions.get(type) !== void 0,
677
- isValidRegistryTarget: (type, key) => isValidRegistryTargetFor(definitions, type, key),
678
- resolveEffectiveOperations: (state, operations) => resolveEffectiveOperationsFor(definitions, state, operations),
679
- resolveEntryValue: (type, entry, scope = null) => resolveEntryValueFor(definitions, type, entry, scope)
680
- });
681
- }
682
- function useRequiredContext(context, hookName, providerName) {
683
- const value = use(context);
684
- if (value === null) {
685
- throw new Error(`${hookName} must be used within ${providerName}`);
686
- }
687
- return value;
688
- }
689
- function useStore(store, selector = (state) => state, isEqual = Object.is) {
690
- const cacheRef = useRef({
691
- isEqual: null,
692
- selected: void 0,
693
- selector: null,
694
- snapshot: null
695
- });
696
- const getSelectedSnapshot = useCallback(() => {
697
- const snapshot = store.getSnapshot();
698
- const cache = cacheRef.current;
699
- if (cache.snapshot === snapshot && cache.selector === selector && cache.isEqual === isEqual) {
700
- return cache.selected;
701
- }
702
- const selected = selector(snapshot);
703
- if (cache.snapshot !== null && cache.isEqual === isEqual && isEqual(cache.selected, selected)) {
704
- cache.snapshot = snapshot;
705
- cache.selector = selector;
706
- return cache.selected;
707
- }
708
- cacheRef.current = {
709
- isEqual,
710
- selected,
711
- selector,
712
- snapshot
713
- };
714
- return selected;
715
- }, [isEqual, selector, store]);
716
- return useSyncExternalStore(
717
- store.subscribe,
718
- getSelectedSnapshot,
719
- getSelectedSnapshot
720
- );
721
- }
722
- var useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
723
-
724
- // src/kernel/runtime.ts
725
- function createRegistryTransaction(store, metadata = {}) {
726
- const operations = [];
727
- let status = "open";
728
- const traceId = metadata.traceId || `tx-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
729
- const ensureOpen = () => status === "open";
730
- const mergeOptions = (options) => {
731
- const baseOpts = options && typeof options === "object" ? options : {};
732
- const needsSource = metadata.source && !baseOpts.source;
733
- const needsScope = metadata.scope && !baseOpts.scope;
734
- if (!needsSource && !needsScope) return baseOpts;
735
- return {
736
- ...baseOpts,
737
- ...needsSource ? { source: metadata.source } : {},
738
- ...needsScope ? { scope: metadata.scope } : {}
739
- };
740
- };
741
- const register = (type, key, value, sourceOrOptions, optionsArg) => {
742
- if (!ensureOpen()) return { index: -1, status, traceId };
743
- const options = typeof sourceOrOptions === "string" ? mergeOptions({ ...optionsArg || {}, source: sourceOrOptions }) : mergeOptions(sourceOrOptions);
744
- operations.push({ key, item: value, options, type });
745
- return { index: operations.length - 1, status: "queued", traceId };
746
- };
747
- const unregister = (type, key, sourceOrOptions) => {
748
- if (!ensureOpen()) return { index: -1, status, traceId };
749
- const options = mergeOptions(
750
- typeof sourceOrOptions === "string" ? { source: sourceOrOptions } : sourceOrOptions
751
- );
752
- operations.push({ key, options, type, unregister: true });
753
- return { index: operations.length - 1, status: "queued", traceId };
754
- };
755
- const rollback = (_reason = "manual") => {
756
- if (!ensureOpen()) return { index: -1, status, traceId };
757
- status = "rolled-back";
758
- operations.length = 0;
759
- return { index: -1, status, traceId };
760
- };
761
- const commit = () => {
762
- if (!ensureOpen()) return { status, traceId };
763
- status = "committed";
764
- const result = store.batch((queue) => {
765
- operations.forEach((op) => {
766
- if (op.unregister) queue.unregister(op.type, op.key, op.options);
767
- else queue.register(op.type, op.key, op.item, op.options);
768
- });
769
- });
770
- const applied = typeof result === "number" && Number.isFinite(result) ? result : 0;
771
- return { applied, queued: operations.length, status, traceId };
772
- };
773
- const run = (executor) => {
774
- if (typeof executor !== "function") {
775
- rollback("invalid-executor");
776
- return { status, traceId };
777
- }
778
- try {
779
- executor({ register, unregister });
780
- return commit();
781
- } catch (error) {
782
- rollback(error instanceof Error ? error.message : String(error));
783
- throw error;
784
- }
785
- };
786
- return {
787
- commit,
788
- get operations() {
789
- return operations.slice();
790
- },
791
- register,
792
- rollback,
793
- run,
794
- get status() {
795
- return status;
796
- },
797
- traceId,
798
- unregister
799
- };
800
- }
801
-
802
- // src/kernel/store.ts
803
- var NO_DEFINITIONS = /* @__PURE__ */ new Map();
804
- function createNoopHandle(status = "rejected", reason = "unknown") {
805
- const handle = Object.assign(() => false, {
806
- active: false,
807
- dispose: () => false,
808
- instanceId: null,
809
- key: "",
810
- priority: 0,
811
- reason,
812
- source: "",
813
- status,
814
- type: "",
815
- update: () => handle,
816
- updatedAt: 0,
817
- validation: "warn"
818
- });
819
- return handle;
820
- }
821
- var NOOP_HANDLE = createNoopHandle();
822
- function isNoopHandle(handle) {
823
- return handle === NOOP_HANDLE || handle?.status === "rejected" || handle?.status === "ignored";
824
- }
825
- function cloneRegistryValue(value, seen = /* @__PURE__ */ new WeakMap()) {
826
- if (value === null || typeof value !== "object" || isValidElement(value)) {
827
- return value;
828
- }
829
- const prototype = Object.getPrototypeOf(value);
830
- const isPlainObject2 = !Array.isArray(value) && (prototype === Object.prototype || prototype === null);
831
- if (!Array.isArray(value) && !isPlainObject2) return value;
832
- if (seen.has(value)) return seen.get(value);
833
- const source = value;
834
- const clone = Array.isArray(value) ? [] : {};
835
- seen.set(value, clone);
836
- for (const key in source) {
837
- if (Object.prototype.hasOwnProperty.call(source, key)) {
838
- clone[key] = cloneRegistryValue(source[key], seen);
839
- }
840
- }
841
- return clone;
842
- }
843
- function normalizeInitialEntries(entries) {
844
- return (Array.isArray(entries) ? entries : []).filter(
845
- (entry) => entry?.type && entry?.items && typeof entry.items === "object"
846
- );
847
- }
848
- function createInitialState(ops, definitions, entries) {
849
- const normalizedEntries = normalizeInitialEntries(entries);
850
- if (normalizedEntries.length === 0) return ops.createInitialRegistries();
851
- const timestamp = Date.now();
852
- let sequence = 0;
853
- let state = ops.createInitialRegistries();
854
- normalizedEntries.forEach((entry) => {
855
- const source = entry.source || REGISTRY_SOURCES.STATIC;
856
- const options = {
857
- ...entry.options || {},
858
- instanceId: entry.instanceId || entry.options?.instanceId || "registry-initial"
859
- };
860
- Object.entries(entry.items).forEach(([key, value]) => {
861
- const validation = validateRegistration(
862
- definitions,
863
- entry.type,
864
- key,
865
- value,
866
- source,
867
- options
868
- );
869
- if (!validation.valid) return;
870
- const operation = createRegisterOperation(
871
- entry.type,
872
- key,
873
- cloneRegistryValue(value),
874
- source,
875
- options,
876
- timestamp,
877
- ++sequence
878
- );
879
- if (ops.hasOperationEffect(state, operation)) {
880
- state = ops.applyOperation(state, operation);
881
- }
882
- });
883
- });
884
- return state;
885
- }
886
- function notifyListeners(listeners) {
887
- if (!listeners) return;
888
- for (const listener of listeners) {
889
- try {
890
- listener();
891
- } catch (error) {
892
- report("Registry listener", error);
893
- }
894
- }
895
- }
896
- function getOrCreateKeyListeners(listenersByType, type, key) {
897
- let listeners = listenersByType.get(type);
898
- if (!listeners) {
899
- listeners = /* @__PURE__ */ new Map();
900
- listenersByType.set(type, listeners);
901
- }
902
- let keyListeners = listeners.get(key);
903
- if (!keyListeners) {
904
- keyListeners = /* @__PURE__ */ new Set();
905
- listeners.set(key, keyListeners);
906
- }
907
- return keyListeners;
908
- }
909
- function resolveRegistrationOptions(sourceOrOptions, optionsArg) {
910
- if (sourceOrOptions && typeof sourceOrOptions === "object")
911
- return sourceOrOptions;
912
- return optionsArg && typeof optionsArg === "object" ? optionsArg : {};
913
- }
914
- function validateRegistration(definitions, type, key, value, sourceOrOptions, optionsArg) {
915
- const options = resolveRegistrationOptions(sourceOrOptions, optionsArg);
916
- const metadataValidation = validateRegistryMetadata(options);
917
- const isStrict = options.validation === REGISTRY_VALIDATION_MODES.STRICT;
918
- if (!metadataValidation.valid && isStrict) {
919
- return {
920
- issues: metadataValidation.issues,
921
- reason: "invalid-metadata",
922
- valid: false
923
- };
924
- }
925
- const validation = validateRegistryValue(type, key, value, definitions);
926
- if (validation.valid) return { valid: true };
927
- if (!isStrict) {
928
- report(`Registry ${type} "${key}" is invalid`, validation.issues, "warn");
929
- }
930
- return {
931
- issues: validation.issues,
932
- reason: "invalid-value",
933
- valid: !isStrict
934
- };
935
- }
936
- function createRegistrationHandle(store, operation) {
937
- let disposed = false;
938
- const dispose = (reason = "manual") => {
939
- if (disposed) return false;
940
- disposed = true;
941
- return store.dispose(operation, reason);
942
- };
943
- const handle = ((reason) => dispose(reason));
944
- handle.dispose = dispose;
945
- handle.update = (value, options = {}) => {
946
- if (disposed || !store.isCurrent(operation)) return NOOP_HANDLE;
947
- const nextHandle = store.register(
948
- operation.type,
949
- operation.key,
950
- value,
951
- operation.source,
952
- {
953
- ...typeof options === "object" ? options : {},
954
- instanceId: operation.instanceId,
955
- priority: operation.record.priority,
956
- ...operation.scope ? { scope: operation.scope } : {},
957
- ...operation.validation ? { validation: operation.validation } : {}
958
- }
959
- );
960
- if (isNoopHandle(nextHandle)) return handle;
961
- disposed = true;
962
- return nextHandle;
963
- };
964
- Object.defineProperties(handle, {
965
- active: {
966
- enumerable: true,
967
- get: () => !disposed && store.isCurrent(operation)
968
- },
969
- instanceId: { enumerable: true, value: operation.instanceId },
970
- key: { enumerable: true, value: operation.key },
971
- priority: { enumerable: true, value: operation.record.priority },
972
- source: { enumerable: true, value: operation.source },
973
- status: {
974
- enumerable: true,
975
- get: () => disposed ? "disposed" : store.isCurrent(operation) ? "active" : "superseded"
976
- },
977
- type: { enumerable: true, value: operation.type },
978
- updatedAt: { enumerable: true, value: operation.record.updatedAt },
979
- validation: { enumerable: true, value: operation.validation || "warn" }
980
- });
981
- return handle;
982
- }
983
- function prepareRegisterOperation(ops, definitions, type, key, item, sourceOrOptions, optionsArg, timestamp, sequence) {
984
- if (!ops.isValidRegistryTarget(type, key)) {
985
- return { rejected: createNoopHandle("rejected", "invalid-target") };
986
- }
987
- const validation = validateRegistration(
988
- definitions,
989
- type,
990
- key,
991
- item,
992
- sourceOrOptions,
993
- optionsArg
994
- );
995
- if (!validation.valid) {
996
- return { rejected: createNoopHandle("rejected", validation.reason) };
997
- }
998
- return {
999
- operation: createRegisterOperation(
1000
- type,
1001
- key,
1002
- cloneRegistryValue(item),
1003
- sourceOrOptions,
1004
- optionsArg,
1005
- timestamp,
1006
- sequence
1007
- )
1008
- };
1009
- }
1010
- function createRegistryStore(initialEntries = [], definitions = NO_DEFINITIONS) {
1011
- const ops = createRegistryOperations(definitions);
1012
- let registries = createInitialState(ops, definitions, initialEntries);
1013
- let sequence = normalizeInitialEntries(initialEntries).reduce(
1014
- (count, entry) => count + Object.keys(entry.items).length,
1015
- 0
1016
- );
1017
- const listenersByType = /* @__PURE__ */ new Map();
1018
- const entrySnapshots = /* @__PURE__ */ new Map();
1019
- const valueSnapshots = /* @__PURE__ */ new Map();
1020
- const resolveCachedValue = ops.createResolverCache();
1021
- const subscribe = (type, key, listener) => {
1022
- const keyListeners = getOrCreateKeyListeners(
1023
- listenersByType,
1024
- type,
1025
- key ?? null
1026
- );
1027
- keyListeners.add(listener);
1028
- return () => {
1029
- keyListeners.delete(listener);
1030
- if (keyListeners.size > 0) return;
1031
- const listeners = listenersByType.get(type);
1032
- if (listeners) {
1033
- listeners.delete(key ?? null);
1034
- if (listeners.size === 0) listenersByType.delete(type);
1035
- }
1036
- };
1037
- };
1038
- const commit = (nextState, operations = []) => {
1039
- if (registries === nextState) return;
1040
- const previousState = registries;
1041
- registries = nextState;
1042
- const changedKeysByType = /* @__PURE__ */ new Map();
1043
- for (const operation of operations) {
1044
- if (!ops.isValidRegistryTarget(operation?.type, operation?.key)) continue;
1045
- let keys = changedKeysByType.get(operation.type);
1046
- if (!keys) {
1047
- keys = /* @__PURE__ */ new Set();
1048
- changedKeysByType.set(operation.type, keys);
1049
- }
1050
- keys.add(operation.key);
1051
- }
1052
- for (const [type, changedKeys] of changedKeysByType) {
1053
- const previousRegistry = previousState[type] || {};
1054
- const nextRegistry = nextState[type] || {};
1055
- const typeListeners = listenersByType.get(type);
1056
- let typeChanged = false;
1057
- if (!typeListeners) continue;
1058
- for (const key of changedKeys) {
1059
- if (previousRegistry[key] === nextRegistry[key]) continue;
1060
- typeChanged = true;
1061
- notifyListeners(typeListeners.get(key));
1062
- }
1063
- if (typeChanged) {
1064
- notifyListeners(typeListeners.get(null));
1065
- }
1066
- }
1067
- };
1068
- const isCurrent = (operation) => {
1069
- const entry = registries[operation.type]?.[operation.key];
1070
- const recordKey = createRecordKey(
1071
- operation.source,
1072
- operation.instanceId,
1073
- operation.scope
1074
- );
1075
- return entry?.[recordKey] === operation.record;
1076
- };
1077
- const dispose = (operation, _reason = "manual") => {
1078
- if (!isCurrent(operation)) return false;
1079
- const unregisterOperation = createUnregisterOperation(
1080
- operation.type,
1081
- operation.key,
1082
- {
1083
- source: operation.source,
1084
- instanceId: operation.instanceId,
1085
- scope: operation.scope
1086
- }
1087
- );
1088
- if (!ops.hasOperationEffect(registries, unregisterOperation)) return false;
1089
- commit(ops.applyOperation(registries, unregisterOperation), [
1090
- unregisterOperation
1091
- ]);
1092
- return true;
1093
- };
1094
- const register = (type, key, item, sourceOrOptions = DEFAULT_SOURCE, optionsArg = {}) => {
1095
- const prepared = prepareRegisterOperation(
1096
- ops,
1097
- definitions,
1098
- type,
1099
- key,
1100
- item,
1101
- sourceOrOptions,
1102
- optionsArg,
1103
- Date.now(),
1104
- ++sequence
1105
- );
1106
- if ("rejected" in prepared) return prepared.rejected;
1107
- const { operation } = prepared;
1108
- if (!ops.hasOperationEffect(registries, operation)) {
1109
- return createNoopHandle("ignored", "unchanged");
1110
- }
1111
- commit(ops.applyOperation(registries, operation), [operation]);
1112
- return createRegistrationHandle(store, operation);
1113
- };
1114
- const unregister = (type, key, sourceOrOptions = DEFAULT_SOURCE) => {
1115
- if (!ops.isValidRegistryTarget(type, key)) return;
1116
- const operation = createUnregisterOperation(type, key, sourceOrOptions);
1117
- if (!ops.hasOperationEffect(registries, operation)) return;
1118
- commit(ops.applyOperation(registries, operation), [operation]);
1119
- };
1120
- const batch = (executor) => {
1121
- if (typeof executor !== "function") return 0;
1122
- const timestamp = Date.now();
1123
- const operations = [];
1124
- const queue = {
1125
- register: (type, key, item, sourceOrOptions = DEFAULT_SOURCE, optionsArg = {}) => {
1126
- const prepared = prepareRegisterOperation(
1127
- ops,
1128
- definitions,
1129
- type,
1130
- key,
1131
- item,
1132
- sourceOrOptions,
1133
- optionsArg,
1134
- timestamp,
1135
- ++sequence
1136
- );
1137
- if ("rejected" in prepared) return prepared.rejected;
1138
- operations.push(prepared.operation);
1139
- return createRegistrationHandle(store, prepared.operation);
1140
- },
1141
- unregister: (type, key, sourceOrOptions = DEFAULT_SOURCE) => {
1142
- if (!ops.isValidRegistryTarget(type, key)) return;
1143
- operations.push(createUnregisterOperation(type, key, sourceOrOptions));
1144
- }
1145
- };
1146
- executor(queue);
1147
- if (operations.length === 0) return 0;
1148
- const { effectiveOperations, nextState } = ops.resolveEffectiveOperations(
1149
- registries,
1150
- operations
1151
- );
1152
- if (effectiveOperations.length === 0) return 0;
1153
- commit(nextState, effectiveOperations);
1154
- return effectiveOperations.length;
1155
- };
1156
- const getSnapshot = (type, key, scope = null) => {
1157
- const entry = registries[type]?.[key];
1158
- let snapshots = valueSnapshots.get(type);
1159
- if (!snapshots) {
1160
- snapshots = /* @__PURE__ */ new Map();
1161
- valueSnapshots.set(type, snapshots);
1162
- }
1163
- const cacheKey = scope === null ? key : `${scope}\0${key}`;
1164
- if (entry === void 0) {
1165
- snapshots.delete(cacheKey);
1166
- return void 0;
1167
- }
1168
- const cached = snapshots.get(cacheKey);
1169
- if (cached && cached.entry === entry) return cached.value;
1170
- const value = resolveCachedValue(type, entry, scope);
1171
- snapshots.set(cacheKey, { entry, value });
1172
- return value;
1173
- };
1174
- const getEntriesSnapshot = (type, scope = null) => {
1175
- const typeRegistry = registries[type] || {};
1176
- const cacheKey = `${type}::${scope ?? "null"}`;
1177
- const cached = entrySnapshots.get(cacheKey);
1178
- if (cached?.typeRegistry === typeRegistry) return cached.value;
1179
- const resolved = {};
1180
- for (const key in typeRegistry) {
1181
- if (Object.prototype.hasOwnProperty.call(typeRegistry, key)) {
1182
- const value = resolveCachedValue(type, typeRegistry[key], scope);
1183
- if (value !== void 0) resolved[key] = value;
1184
- }
1185
- }
1186
- const finalValue = Object.freeze(resolved);
1187
- entrySnapshots.set(cacheKey, { typeRegistry, value: finalValue });
1188
- return finalValue;
1189
- };
1190
- const store = {
1191
- batch,
1192
- dispose,
1193
- getEntriesSnapshot,
1194
- getSnapshot,
1195
- isCurrent,
1196
- register,
1197
- subscribe,
1198
- transaction: (executor, metadata = {}) => createRegistryTransaction(store, metadata).run(executor),
1199
- unregister
1200
- };
1201
- return store;
1202
- }
1203
- var RegistryContext = getOrCreateGlobalContext(
1204
- "RegistryContext",
1205
- null
1206
- );
1207
- function RegistryProvider({
1208
- children,
1209
- definitions,
1210
- initialEntries = []
1211
- }) {
1212
- const [store] = useState(
1213
- () => createRegistryStore(initialEntries, definitions)
1214
- );
1215
- const contextValue = useMemo(
1216
- () => ({
1217
- actions: {
1218
- batch: store.batch,
1219
- register: store.register,
1220
- transaction: store.transaction,
1221
- unregister: store.unregister
1222
- },
1223
- subscription: {
1224
- getEntriesSnapshot: store.getEntriesSnapshot,
1225
- getSnapshot: store.getSnapshot,
1226
- subscribe: store.subscribe
1227
- }
1228
- }),
1229
- [store]
1230
- );
1231
- return /* @__PURE__ */ jsx(RegistryContext, { value: contextValue, children });
1232
- }
1233
- function useRegistryActions() {
1234
- return useRequiredContext(
1235
- RegistryContext,
1236
- "useRegistryActions",
1237
- "RegistryProvider"
1238
- ).actions;
1239
- }
1240
- function useRegistrySubscription() {
1241
- return useRequiredContext(
1242
- RegistryContext,
1243
- "useRegistrySubscription",
1244
- "RegistryProvider"
1245
- ).subscription;
1246
- }
1247
- function useRegistryValue(type, key) {
1248
- const { getSnapshot, subscribe } = useRegistrySubscription();
1249
- const subscribeToKey = useCallback(
1250
- (listener) => subscribe(type, key, listener),
1251
- [key, subscribe, type]
1252
- );
1253
- const getValue = useCallback(
1254
- () => getSnapshot(type, key),
1255
- [getSnapshot, key, type]
1256
- );
1257
- return useSyncExternalStore(subscribeToKey, getValue, getValue);
1258
- }
1259
- function useRegistryEntries(type) {
1260
- const { getEntriesSnapshot, subscribe } = useRegistrySubscription();
1261
- const subscribeToType = useCallback(
1262
- (listener) => subscribe(type, null, listener),
1263
- [subscribe, type]
1264
- );
1265
- const getEntries = useCallback(
1266
- () => getEntriesSnapshot(type),
1267
- [getEntriesSnapshot, type]
1268
- );
1269
- return useSyncExternalStore(subscribeToType, getEntries, getEntries);
1270
- }
1271
- var EMPTY_MODULES = Object.freeze([]);
1272
- var PassthroughBoundary = ({ children }) => children;
1273
- var ModuleHostContext = getOrCreateGlobalContext("ModuleHostContext", null);
1274
- function selectModuleSlice(coreModule, config) {
1275
- const slice = coreModule.page?.select ? coreModule.page.select(config) : config[coreModule.id];
1276
- return slice ?? null;
1277
- }
1278
- function createModulePayload(modules, config, metadata = {}) {
1279
- const payload = {};
1280
- let hasSlices = false;
1281
- for (const coreModule of modules) {
1282
- if (!coreModule.page?.entries) continue;
1283
- const slice = selectModuleSlice(coreModule, config);
1284
- if (slice === null) continue;
1285
- payload[coreModule.id] = slice;
1286
- hasSlices = true;
1287
- }
1288
- if (!hasSlices) return null;
1289
- return {
1290
- ...payload,
1291
- registry: {
1292
- ...metadata,
1293
- ...isObject(config.registry) ? config.registry : {}
1294
- }
1295
- };
1296
- }
1297
- var MODULE_ID_PATTERN = /^[a-z][a-zA-Z0-9]*$/;
1298
- function sortModules(modules) {
1299
- const byId = /* @__PURE__ */ new Map();
1300
- for (const coreModule of modules) {
1301
- if (!MODULE_ID_PATTERN.test(coreModule.id)) {
1302
- throw new Error(
1303
- `[Core] Invalid module id "${coreModule.id}": use a camelCase name such as "contextMenu".`
1304
- );
1305
- }
1306
- if (byId.has(coreModule.id)) {
1307
- throw new Error(`[Core] Module "${coreModule.id}" is installed twice.`);
1308
- }
1309
- byId.set(coreModule.id, coreModule);
1310
- }
1311
- const sorted = [];
1312
- const state = /* @__PURE__ */ new Map();
1313
- const visit = (coreModule, path) => {
1314
- const current = state.get(coreModule.id);
1315
- if (current === "done") return;
1316
- if (current === "visiting") {
1317
- throw new Error(
1318
- `[Core] Module dependency cycle: ${[...path, coreModule.id].join(" -> ")}`
1319
- );
1320
- }
1321
- state.set(coreModule.id, "visiting");
1322
- for (const id of coreModule.uses ?? []) {
1323
- const dependency = byId.get(id);
1324
- if (dependency) visit(dependency, [...path, coreModule.id]);
1325
- }
1326
- state.set(coreModule.id, "done");
1327
- sorted.push(coreModule);
1328
- };
1329
- modules.forEach((coreModule) => visit(coreModule, []));
1330
- return sorted;
1331
- }
1332
- function createModuleRegistryDefinitions(modules) {
1333
- const definitions = /* @__PURE__ */ new Map();
1334
- for (const coreModule of modules) {
1335
- if (coreModule.registry)
1336
- definitions.set(coreModule.id, coreModule.registry);
1337
- }
1338
- return definitions;
1339
- }
1340
- function useInstalledModules() {
1341
- return use(ModuleHostContext)?.modules ?? EMPTY_MODULES;
1342
- }
1343
-
1344
- // src/kernel/handlers.ts
1345
- function isPersistentLifecycle(lifecycle) {
1346
- return lifecycle === REGISTRY_LIFECYCLES.PERSISTENT;
1347
- }
1348
- function runRegistrationBatch(context, executor) {
1349
- return typeof context.batch === "function" ? context.batch(executor) : executor(context);
1350
- }
1351
- function createEntryCleanupKey(type, key, source, instanceId, scope) {
1352
- return JSON.stringify([
1353
- "entry",
1354
- type,
1355
- key,
1356
- scope ?? null,
1357
- source,
1358
- instanceId
1359
- ]);
1360
- }
1361
- function getCleanupScope(context) {
1362
- return context?.cleanupScope || /* @__PURE__ */ new Map();
1363
- }
1364
- function clearCleanupTimer(scope, cleanupKey) {
1365
- const lifecycle = scope.get(cleanupKey);
1366
- if (!lifecycle) return;
1367
- lifecycle.cancelled = true;
1368
- if (lifecycle.timerId !== null) clearTimeout(lifecycle.timerId);
1369
- scope.delete(cleanupKey);
1370
- }
1371
- function scheduleCleanup(scope, cleanupKey, callback, delayMs) {
1372
- clearCleanupTimer(scope, cleanupKey);
1373
- const lifecycle = {
1374
- cancelled: false,
1375
- timerId: null
1376
- };
1377
- lifecycle.timerId = setTimeout(() => {
1378
- if (lifecycle.cancelled || scope.get(cleanupKey) !== lifecycle) return;
1379
- scope.delete(cleanupKey);
1380
- callback();
1381
- }, delayMs);
1382
- scope.set(cleanupKey, lifecycle);
1383
- }
1384
- function collectModuleRegistrations(coreModule, slice, pageMetadata, context) {
1385
- const definition = coreModule.registry;
1386
- const toEntries = coreModule.page?.entries;
1387
- if (!definition || !toEntries || slice == null || slice === false) return [];
1388
- const type = coreModule.id;
1389
- const items = Array.isArray(slice) ? slice : [slice];
1390
- const registrations = [];
1391
- for (const item of items) {
1392
- if (item == null || item === false) continue;
1393
- const itemMetadata = isObject(item) && isObject(item.registry) ? item.registry : {};
1394
- const metadata = { ...pageMetadata, ...itemMetadata };
1395
- if (metadata.validation === "strict" && !validateRegistryMetadata(metadata).valid) {
1396
- continue;
1397
- }
1398
- const payload = isObject(item) ? Object.fromEntries(
1399
- Object.entries(item).filter(([key]) => key !== "registry")
1400
- ) : item;
1401
- const { cleanupDelayMs, lifecycle, registerOptions, scope, source } = normalizeRegistryMetadata(metadata, {
1402
- defaultCleanupDelayMs: definition.cleanupDelayMs ?? null,
1403
- defaultLifecycle: definition.lifecycle,
1404
- defaultSource: DEFAULT_SOURCE
1405
- });
1406
- for (const { key, value } of toEntries(payload, context) ?? []) {
1407
- const validation = definition.validate?.(value);
1408
- if (validation && !validation.valid) {
1409
- report(`Registry ${type} config is invalid`, validation.issues, "warn");
1410
- continue;
1411
- }
1412
- registrations.push({
1413
- cleanupDelayMs,
1414
- cleanupKey: createEntryCleanupKey(
1415
- type,
1416
- key,
1417
- source,
1418
- context.instanceId,
1419
- scope
1420
- ),
1421
- key,
1422
- lifecycle,
1423
- registerOptions,
1424
- scope,
1425
- source,
1426
- type,
1427
- value
1428
- });
1429
- }
1430
- }
1431
- return registrations;
1432
- }
1433
- var NO_CLEANUP = () => {
1434
- };
1435
- function applyRegistryConfig(config, context) {
1436
- const modules = context.modules ?? [];
1437
- if (!config || modules.length === 0) return NO_CLEANUP;
1438
- const pageMetadata = isObject(config.registry) ? config.registry : {};
1439
- const slices = config;
1440
- const registrations = modules.flatMap((coreModule) => {
1441
- try {
1442
- return collectModuleRegistrations(
1443
- coreModule,
1444
- slices[coreModule.id],
1445
- pageMetadata,
1446
- context
1447
- );
1448
- } catch (error) {
1449
- report(`Registry apply (${coreModule.id})`, error);
1450
- return [];
1451
- }
1452
- });
1453
- if (registrations.length === 0) return NO_CLEANUP;
1454
- const cleanupScope = getCleanupScope(context);
1455
- const owner = (registration) => ({
1456
- instanceId: context.instanceId,
1457
- scope: registration.scope,
1458
- source: registration.source
1459
- });
1460
- runRegistrationBatch(context, (queue) => {
1461
- registrations.forEach(
1462
- ({ cleanupKey, key, registerOptions, source, type, value }) => {
1463
- clearCleanupTimer(cleanupScope, cleanupKey);
1464
- queue.register(type, key, value, source, registerOptions);
1465
- }
1466
- );
1467
- });
1468
- return () => {
1469
- const immediate = [];
1470
- registrations.forEach((registration) => {
1471
- if (isPersistentLifecycle(registration.lifecycle)) return;
1472
- const { cleanupDelayMs, cleanupKey, key, type } = registration;
1473
- if (typeof cleanupDelayMs === "number" && cleanupDelayMs > 0) {
1474
- scheduleCleanup(
1475
- cleanupScope,
1476
- cleanupKey,
1477
- () => context.unregister(type, key, owner(registration)),
1478
- cleanupDelayMs
1479
- );
1480
- } else {
1481
- immediate.push(registration);
1482
- }
1483
- });
1484
- if (immediate.length === 0) return;
1485
- runRegistrationBatch(context, (queue) => {
1486
- immediate.forEach(
1487
- (registration) => queue.unregister(
1488
- registration.type,
1489
- registration.key,
1490
- owner(registration)
1491
- )
1492
- );
1493
- });
1494
- };
1495
- }
1496
-
1497
- // src/kernel/hooks.ts
1498
- function withInstanceId(instanceId, sourceOrOptions, optionsArg) {
1499
- if (typeof sourceOrOptions === "string") {
1500
- return {
1501
- optionsArg: { ...isObject(optionsArg) ? optionsArg : {}, instanceId },
1502
- sourceOrOptions
1503
- };
1504
- }
1505
- if (isObject(sourceOrOptions)) {
1506
- return {
1507
- optionsArg,
1508
- sourceOrOptions: { ...sourceOrOptions, instanceId }
1509
- };
1510
- }
1511
- return {
1512
- optionsArg: void 0,
1513
- sourceOrOptions: {
1514
- ...isObject(optionsArg) ? optionsArg : {},
1515
- instanceId
1516
- }
1517
- };
1518
- }
1519
- function withInstanceIdForUnregister(instanceId, sourceOrOptions) {
1520
- if (typeof sourceOrOptions === "string") {
1521
- return { instanceId, source: sourceOrOptions };
1522
- }
1523
- if (isObject(sourceOrOptions)) {
1524
- return { ...sourceOrOptions, instanceId };
1525
- }
1526
- return { instanceId };
1527
- }
1528
- function resolveRegisterArgsWithInstance(instanceId, sourceOrOptions, optionsArg) {
1529
- const input = withInstanceId(instanceId, sourceOrOptions, optionsArg);
1530
- return [input.sourceOrOptions, input.optionsArg];
1531
- }
1532
- function useShallowStable(value) {
1533
- const ref = useRef(value);
1534
- if (ref.current !== value && !shallowEqual(ref.current, value)) {
1535
- ref.current = value;
1536
- }
1537
- return ref.current;
1538
- }
1539
- var MAX_STABILIZATION_DEPTH = 64;
1540
- function createStableFunctionEntry(fn) {
1541
- const entry = {
1542
- current: fn,
1543
- stable(...args) {
1544
- return entry.current?.apply(this, args);
1545
- }
1546
- };
1547
- return entry;
1548
- }
1549
- function isDirectRegistryComponentPath(path, componentSlices) {
1550
- const match = /^config\.([^.[]+)\.[^.[]+$/.exec(path);
1551
- return Boolean(match && componentSlices.has(match[1]));
1552
- }
1553
- function isReactNodeLike(value) {
1554
- return value === null || value === void 0 || typeof value === "boolean" || typeof value === "string" || typeof value === "number" || isValidElement(value);
1555
- }
1556
- function isStabilizableObject(value) {
1557
- return typeof value === "object" && value !== null && !Array.isArray(value) && !isValidElement(value);
1558
- }
1559
- function hasSameObjectKeys(previousValue, nextValue) {
1560
- if (!isStabilizableObject(previousValue) || !isStabilizableObject(nextValue)) {
1561
- return false;
1562
- }
1563
- const previousKeys = Object.keys(previousValue);
1564
- const nextKeys = Object.keys(nextValue);
1565
- if (previousKeys.length !== nextKeys.length) return false;
1566
- return nextKeys.every(
1567
- (key) => Object.prototype.hasOwnProperty.call(previousValue, key)
1568
- );
1569
- }
1570
- function stabilizeRegistryValue(value, path, scope, previousValue, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
1571
- if (depth > MAX_STABILIZATION_DEPTH) return value;
1572
- if (typeof value === "function") {
1573
- const isComponent = value.name && /^[A-Z]/.test(value.name);
1574
- if (isComponent || isDirectRegistryComponentPath(path, scope.componentSlices)) {
1575
- return value;
1576
- }
1577
- scope.usedPaths.add(path);
1578
- let entry = scope.functionEntries.get(path);
1579
- if (!entry) {
1580
- entry = createStableFunctionEntry(value);
1581
- scope.functionEntries.set(path, entry);
1582
- } else {
1583
- entry.current = value;
1584
- }
1585
- return entry.stable;
1586
- }
1587
- if (value && typeof value === "object") {
1588
- if (seen.has(value)) return value;
1589
- seen.add(value);
1590
- }
1591
- if (isValidElement(value)) {
1592
- const nextProps = stabilizeRegistryValue(
1593
- value.props,
1594
- `${path}.props`,
1595
- scope,
1596
- isValidElement(previousValue) ? previousValue.props : void 0,
1597
- seen,
1598
- depth + 1
1599
- );
1600
- if (isValidElement(previousValue) && previousValue.type === value.type && previousValue.key === value.key && previousValue.props === nextProps) {
1601
- return previousValue;
1602
- }
1603
- return cloneElement(value, nextProps);
1604
- }
1605
- if (Array.isArray(value)) {
1606
- const nextValue = value.every(isReactNodeLike) ? Children.toArray(value) : value;
1607
- const previousArray = Array.isArray(previousValue) ? previousValue : null;
1608
- let hasChanged2 = !previousArray || previousArray.length !== nextValue.length;
1609
- const stabilizedValue2 = nextValue.map((item, index) => {
1610
- const nextItem = stabilizeRegistryValue(
1611
- item,
1612
- `${path}[${index}]`,
1613
- scope,
1614
- previousArray?.[index],
1615
- seen,
1616
- depth + 1
1617
- );
1618
- if (!previousArray || nextItem !== previousArray[index]) {
1619
- hasChanged2 = true;
1620
- }
1621
- return nextItem;
1622
- });
1623
- return !hasChanged2 ? previousArray : stabilizedValue2;
1624
- }
1625
- if (typeof value !== "object" || value === null) {
1626
- return value;
1627
- }
1628
- const source = value;
1629
- const previousRecord = previousValue;
1630
- const stabilizedValue = {};
1631
- const canReusePrevious = hasSameObjectKeys(previousValue, value);
1632
- let hasChanged = !canReusePrevious;
1633
- Object.keys(source).forEach((key) => {
1634
- const nextValue = stabilizeRegistryValue(
1635
- source[key],
1636
- `${path}.${key}`,
1637
- scope,
1638
- previousRecord?.[key],
1639
- seen,
1640
- depth + 1
1641
- );
1642
- stabilizedValue[key] = nextValue;
1643
- if (!canReusePrevious || nextValue !== previousRecord?.[key]) {
1644
- hasChanged = true;
1645
- }
1646
- });
1647
- return !hasChanged ? previousValue : stabilizedValue;
1648
- }
1649
- function useAppliedRegistryConfig(payload, context, componentSlices) {
1650
- const functionEntriesRef = useRef(/* @__PURE__ */ new Map());
1651
- const appliedRef = useRef(null);
1652
- useIsomorphicLayoutEffect(() => {
1653
- const previous = appliedRef.current;
1654
- if (previous && previous.payload === payload && previous.context === context) {
1655
- return;
1656
- }
1657
- const functionEntries = functionEntriesRef.current;
1658
- const usedPaths = /* @__PURE__ */ new Set();
1659
- const config = stabilizeRegistryValue(
1660
- payload,
1661
- "config",
1662
- { componentSlices, functionEntries, usedPaths },
1663
- previous?.config
1664
- );
1665
- functionEntries.forEach((_entry, path) => {
1666
- if (!usedPaths.has(path)) functionEntries.delete(path);
1667
- });
1668
- if (previous && previous.config === config && previous.context === context) {
1669
- previous.payload = payload;
1670
- return;
1671
- }
1672
- previous?.cleanup();
1673
- appliedRef.current = {
1674
- cleanup: applyRegistryConfig(config, context),
1675
- config,
1676
- context,
1677
- payload
1678
- };
1679
- });
1680
- useIsomorphicLayoutEffect(
1681
- () => () => {
1682
- appliedRef.current?.cleanup();
1683
- appliedRef.current = null;
1684
- },
1685
- []
1686
- );
1687
- }
1688
- function createRegistryApplyContext(actions, {
1689
- cleanupScope = /* @__PURE__ */ new Map(),
1690
- instanceId,
1691
- modules = [],
1692
- pathname
1693
- }) {
1694
- const stamp = (queue) => ({
1695
- register: (type, key, item, sourceOrOptions, optionsArg) => queue.register(
1696
- type,
1697
- key,
1698
- item,
1699
- ...resolveRegisterArgsWithInstance(
1700
- instanceId,
1701
- sourceOrOptions,
1702
- optionsArg
1703
- )
1704
- ),
1705
- unregister: (type, key, sourceOrOptions) => queue.unregister(
1706
- type,
1707
- key,
1708
- withInstanceIdForUnregister(instanceId, sourceOrOptions)
1709
- )
1710
- });
1711
- return {
1712
- ...stamp(actions),
1713
- batch: (executor) => typeof executor === "function" ? actions.batch((queue) => executor(stamp(queue))) : 0,
1714
- cleanupScope,
1715
- instanceId,
1716
- modules,
1717
- pathname
1718
- };
1719
- }
1720
- function useRegistry(config, metadata) {
1721
- const { batch, register, unregister } = useRegistryActions();
1722
- const pathname = usePathname();
1723
- const modules = useInstalledModules();
1724
- const instanceId = `registry-instance-${useId()}`;
1725
- const [cleanupScope] = useState(
1726
- () => /* @__PURE__ */ new Map()
1727
- );
1728
- const context = useMemo(
1729
- () => createRegistryApplyContext(
1730
- { batch, register, unregister },
1731
- {
1732
- cleanupScope,
1733
- instanceId,
1734
- modules,
1735
- pathname
1736
- }
1737
- ),
1738
- [batch, cleanupScope, instanceId, modules, pathname, register, unregister]
1739
- );
1740
- const payload = useMemo(
1741
- () => config ? createModulePayload(modules, config, metadata) : null,
1742
- [config, metadata, modules]
1743
- );
1744
- const componentSlices = useMemo(
1745
- () => new Set(
1746
- modules.filter(
1747
- (coreModule) => coreModule.registry?.valueKind === "component"
1748
- ).map((coreModule) => coreModule.id)
1749
- ),
1750
- [modules]
1751
- );
1752
- useAppliedRegistryConfig(payload, context, componentSlices);
1753
- }
1754
- var EMPTY_OBJECT = Object.freeze({});
1755
- function createPageControllerStore() {
1756
- const listeners = /* @__PURE__ */ new Set();
1757
- let stack = [];
1758
- const notify = () => {
1759
- listeners.forEach((listener) => {
1760
- try {
1761
- listener();
1762
- } catch (error) {
1763
- report("Page controller listener", error);
1764
- }
1765
- });
1766
- };
1767
- return {
1768
- getSnapshot() {
1769
- const top = stack[stack.length - 1];
1770
- return top?.controllerRef?.current || null;
1771
- },
1772
- notify,
1773
- register(id, controllerRef) {
1774
- stack = stack.filter((item) => item.id !== id);
1775
- stack.push({ controllerRef, id });
1776
- notify();
1777
- },
1778
- subscribe(listener) {
1779
- listeners.add(listener);
1780
- return () => {
1781
- listeners.delete(listener);
1782
- };
1783
- },
1784
- unregister(id) {
1785
- stack = stack.filter((item) => item.id !== id);
1786
- notify();
1787
- }
1788
- };
1789
- }
1790
- function createControllerScope() {
1791
- const listeners = /* @__PURE__ */ new Set();
1792
- let current = null;
1793
- const subscribe = (listener) => {
1794
- listeners.add(listener);
1795
- return () => {
1796
- listeners.delete(listener);
1797
- };
1798
- };
1799
- const getSnapshot = () => current;
1800
- function PageProvider({ children }) {
1801
- const controller = useSyncExternalStore(
1802
- subscribe,
1803
- getSnapshot,
1804
- getSnapshot
1805
- );
1806
- return /* @__PURE__ */ jsx(PageControllerContext, { value: controller, children });
1807
- }
1808
- return {
1809
- Provider: PageProvider,
1810
- publish(controller) {
1811
- if (current === controller) return;
1812
- current = controller;
1813
- listeners.forEach((listener) => listener());
1814
- }
1815
- };
1816
- }
1817
- var fallbackStandaloneStore = createPageControllerStore();
1818
- var noopHook = () => {
1819
- };
1820
- var PassthroughProvider = ({ children }) => children;
1821
- var PageControllerContext = getOrCreateGlobalContext(
1822
- "PageControllerContext",
1823
- null
1824
- );
1825
- var PageControllerStoreContext = getOrCreateGlobalContext(
1826
- "PageControllerStoreContext",
1827
- fallbackStandaloneStore
1828
- );
1829
- function PageControllerProvider({ children }) {
1830
- const [store] = useState(
1831
- () => createPageControllerStore()
1832
- );
1833
- return /* @__PURE__ */ jsx(PageControllerStoreContext, { value: store, children });
1834
- }
1835
- var emptySubscribe = () => () => {
1836
- };
1837
- var getNullSnapshot = () => null;
1838
- var FALLBACK_PAGE_CONTROLLER = Object.freeze({
1839
- Provider: PassthroughProvider,
1840
- config: EMPTY_OBJECT,
1841
- modules: Object.freeze({}),
1842
- reset: noopHook,
1843
- set: noopHook
1844
- });
1845
- function usePageController() {
1846
- const scopedContext = use(PageControllerContext);
1847
- const controllerStore = use(PageControllerStoreContext);
1848
- const storeSubscribe = scopedContext ? emptySubscribe : controllerStore.subscribe;
1849
- const storeSnapshot = scopedContext ? getNullSnapshot : controllerStore.getSnapshot;
1850
- const storeController = useSyncExternalStore(
1851
- storeSubscribe,
1852
- storeSnapshot,
1853
- getNullSnapshot
1854
- );
1855
- return scopedContext ?? storeController ?? FALLBACK_PAGE_CONTROLLER;
1856
- }
1857
- function usePage(pageConfig = EMPTY_OBJECT, options) {
1858
- const instanceId = useId();
1859
- const controllerStore = use(PageControllerStoreContext);
1860
- const modules = useInstalledModules();
1861
- const [overrides, setOverrides] = useState(EMPTY_OBJECT);
1862
- const set = useCallback((partial) => {
1863
- if (!partial || typeof partial !== "object") return;
1864
- setOverrides((prev) => mergeModuleConfigs(prev, partial));
1865
- }, []);
1866
- const reset = useCallback(() => {
1867
- setOverrides(EMPTY_OBJECT);
1868
- }, []);
1869
- const effectiveConfig = useMemo(() => {
1870
- const base = pageConfig || EMPTY_OBJECT;
1871
- if (Object.keys(overrides).length === 0) return base;
1872
- return mergeModuleConfigs(base, overrides);
1873
- }, [pageConfig, overrides]);
1874
- const moduleSlices = useMemo(
1875
- () => modules.map(
1876
- (coreModule) => selectModuleSlice(coreModule, effectiveConfig)
1877
- ),
1878
- [effectiveConfig, modules]
1879
- );
1880
- const registryMetadata = useMemo(
1881
- () => pickRegistryMetadata(options),
1882
- [options]
1883
- );
1884
- useRegistry(effectiveConfig, registryMetadata);
1885
- const pageApi = useMemo(() => ({ set }), [set]);
1886
- const moduleControllers = {};
1887
- for (let index = 0; index < modules.length; index += 1) {
1888
- const coreModule = modules[index];
1889
- if (coreModule.page?.use) {
1890
- moduleControllers[coreModule.id] = coreModule.page.use(
1891
- moduleSlices[index],
1892
- pageApi
1893
- );
1894
- }
1895
- }
1896
- const pageModules = useShallowStable(moduleControllers);
1897
- const [scope] = useState(createControllerScope);
1898
- const controller = useMemo(
1899
- () => ({
1900
- Provider: scope.Provider,
1901
- config: effectiveConfig,
1902
- modules: pageModules,
1903
- reset,
1904
- set
1905
- }),
1906
- [effectiveConfig, pageModules, reset, scope, set]
1907
- );
1908
- const controllerRef = useRef(controller);
1909
- useIsomorphicLayoutEffect(() => {
1910
- controllerRef.current = controller;
1911
- scope.publish(controller);
1912
- controllerStore.notify();
1913
- }, [controller, controllerStore, scope]);
1914
- useEffect(() => {
1915
- controllerStore.register(instanceId, controllerRef);
1916
- return () => {
1917
- controllerStore.unregister(instanceId);
1918
- };
1919
- }, [controllerStore, instanceId]);
1920
- return controller;
1921
- }
1922
- function defineModule(coreModule) {
1923
- return Object.freeze({ ...coreModule });
1924
- }
1925
- function warnMissingPeers(modules) {
1926
- const installed = new Set(modules.map((coreModule) => coreModule.id));
1927
- for (const { id, uses } of modules) {
1928
- const missing = (uses ?? []).filter((peer) => !installed.has(peer));
1929
- if (missing.length > 0) {
1930
- report(
1931
- `Module "${id}" runs without its optional peers`,
1932
- missing.join(", "),
1933
- "warn"
1934
- );
1935
- }
1936
- }
1937
- }
1938
- function createModuleHost(modules, Boundary) {
1939
- const sorted = sortModules(modules);
1940
- if (process.env.NODE_ENV !== "production") warnMissingPeers(sorted);
1941
- return {
1942
- Boundary,
1943
- byId: new Map(sorted.map((coreModule) => [coreModule.id, coreModule])),
1944
- definitions: createModuleRegistryDefinitions(sorted),
1945
- modules: Object.freeze(sorted)
1946
- };
1947
- }
1948
- function ModuleHost({
1949
- boundary = PassthroughBoundary,
1950
- children,
1951
- modules = EMPTY_MODULES,
1952
- registryEntries
1953
- }) {
1954
- const [host] = useState(() => createModuleHost(modules, boundary));
1955
- const { Boundary } = host;
1956
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
1957
- host.modules.map(
1958
- ({ Backdrop, id }) => Backdrop ? /* @__PURE__ */ jsx(Boundary, { name: id, children: /* @__PURE__ */ jsx(Backdrop, {}) }, id) : null
1959
- ),
1960
- children,
1961
- host.modules.map(
1962
- ({ Overlay, id }) => Overlay ? /* @__PURE__ */ jsx(Boundary, { name: id, children: /* @__PURE__ */ jsx(Overlay, {}) }, id) : null
1963
- )
1964
- ] });
1965
- const tree = host.modules.reduceRight(
1966
- (inner, { Provider }) => Provider ? /* @__PURE__ */ jsx(Provider, { children: inner }) : inner,
1967
- content
1968
- );
1969
- return /* @__PURE__ */ jsx(
1970
- RegistryProvider,
1971
- {
1972
- definitions: host.definitions,
1973
- initialEntries: registryEntries,
1974
- children: /* @__PURE__ */ jsx(ModuleHostContext, { value: host, children: /* @__PURE__ */ jsx(PageControllerProvider, { children: tree }) })
1975
- }
1976
- );
1977
- }
1978
- function useModule(id) {
1979
- const coreModule = use(ModuleHostContext)?.byId.get(id);
1980
- return coreModule?.context ? use(coreModule.context) ?? null : null;
1981
- }
1982
- function definePeer(id, inert) {
1983
- const useRuntime = () => useModule(id) ?? inert;
1984
- return {
1985
- useRuntime,
1986
- useActions: () => useRuntime().actions,
1987
- useState: (selector, isEqual) => useStore(
1988
- useRuntime().store,
1989
- selector,
1990
- isEqual
1991
- )
1992
- };
1993
- }
1994
- var NO_MODULE_STORE = createStore(void 0);
1995
- function useModuleState(id, selector, fallback, isEqual = Object.is) {
1996
- const runtime = useModule(id);
1997
- return useStore(
1998
- runtime?.store ?? NO_MODULE_STORE,
1999
- (state) => runtime ? selector(state) : fallback,
2000
- isEqual
2001
- );
2002
- }
2003
- function ModuleBoundary({
2004
- children,
2005
- name
2006
- }) {
2007
- const Boundary = use(ModuleHostContext)?.Boundary ?? PassthroughBoundary;
2008
- return createElement(Boundary, { name }, children);
2009
- }
2010
- function useIsModuleInstalled(id) {
2011
- return use(ModuleHostContext)?.byId.has(id) ?? false;
2012
- }
2013
-
2014
- // src/kernel/adapters.ts
2015
- function useModuleRegistration(id, value, options) {
2016
- const coreModule = useInstalledModules().find(
2017
- (candidate) => candidate.id === id
2018
- );
2019
- const config = coreModule && options?.enabled !== false && value != null ? { [id]: value } : null;
2020
- useRegistry(config, pickRegistryMetadata(options));
2021
- }
2022
- function Compose({ providers, children }) {
2023
- return providers.reduceRight(
2024
- (acc, entry) => {
2025
- if (Array.isArray(entry)) {
2026
- const [Component2, props] = entry;
2027
- return createElement(Component2, props, acc);
2028
- }
2029
- const Component = entry;
2030
- return createElement(Component, null, acc);
2031
- },
2032
- createElement(Fragment$1, null, children)
2033
- );
2034
- }
2035
-
2036
- export { Compose, ModuleBoundary, ModuleHost, PageControllerProvider, REGISTRY_SOURCES, RegistryProvider, applyRegistryConfig, createModuleRegistryDefinitions, createRegistryApplyContext, createRegistryOperations, createRegistryStore, defineModule, definePeer, getOrCreateGlobalContext, hasOwnProperty, sortModules, useIsModuleInstalled, useModule, useModuleRegistration, useModuleState, usePage, usePageController, useRegistryEntries, useRegistryValue };
2
+ export { Compose, ModuleBoundary, ModuleHost, PageControllerProvider, REGISTRY_SOURCES, RegistryProvider, applyRegistryConfig, createModuleRegistryDefinitions, createRegistryApplyContext, createRegistryOperations, createRegistryStore, defineModule, definePeer, getOrCreateGlobalContext, hasOwnProperty, sortModules, useIsModuleInstalled, useModule, useModuleRegistration, useModuleState, usePage, usePageController, useRegistryEntries, useRegistryValue } from '../chunk-GF7TUX5I.js';
3
+ import '../chunk-TV3WEF5G.js';
2037
4
  //# sourceMappingURL=index.js.map
2038
5
  //# sourceMappingURL=index.js.map