@spring-systems/core 0.8.4 → 0.8.7

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 (109) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/dist/adapters/index.js +1 -56
  3. package/dist/auth/index.d.ts +2 -2
  4. package/dist/auth/index.js +1 -19
  5. package/dist/chunk-3OMNT22N.js +1 -0
  6. package/dist/chunk-4KRUU6MS.js +1 -0
  7. package/dist/chunk-6J2VFOKL.js +1 -0
  8. package/dist/chunk-7P4BJDQR.js +1 -0
  9. package/dist/chunk-AMXSATFF.js +1 -0
  10. package/dist/chunk-BMIRKMVX.js +1 -0
  11. package/dist/chunk-EVDFSWPU.js +1 -0
  12. package/dist/chunk-F3VXVDPQ.js +1 -0
  13. package/dist/chunk-GSQE2NEY.js +1 -0
  14. package/dist/chunk-HUASNNWD.js +1 -0
  15. package/dist/chunk-ICKHSEIX.js +1 -0
  16. package/dist/chunk-JRHMAY5G.js +1 -0
  17. package/dist/chunk-MNLYYTGZ.js +7 -0
  18. package/dist/chunk-OOVZTF74.js +1 -0
  19. package/dist/chunk-PNDXLNCU.js +1 -0
  20. package/dist/chunk-R3XYEEGR.js +1 -0
  21. package/dist/chunk-RKLYBW3O.js +1 -0
  22. package/dist/chunk-RVQHSQYF.js +3 -0
  23. package/dist/chunk-UT6X6RQM.js +1 -0
  24. package/dist/chunk-Y6DB43IE.js +3 -0
  25. package/dist/chunk-YMSSF2ZU.js +1 -0
  26. package/dist/config/index.d.ts +3 -3
  27. package/dist/config/index.js +1 -109
  28. package/dist/devtools/index.d.ts +2 -2
  29. package/dist/devtools/index.js +1 -67
  30. package/dist/errors/index.js +1 -21
  31. package/dist/events/index.js +1 -12
  32. package/dist/{framework-config-types-ClghA-zo.d.ts → framework-config-types-Cmy83YS6.d.ts} +4 -1
  33. package/dist/i18n/index.js +1 -7
  34. package/dist/index.d.ts +2 -2
  35. package/dist/index.js +1 -42
  36. package/dist/instance/index.d.ts +3 -3
  37. package/dist/instance/index.js +1 -37
  38. package/dist/logger/index.d.ts +2 -2
  39. package/dist/logger/index.js +1 -27
  40. package/dist/middleware/index.js +1 -23
  41. package/dist/plugins/index.d.ts +2 -2
  42. package/dist/plugins/index.js +1 -16
  43. package/dist/{runtime-env-config-Bs9HwewE.d.ts → runtime-env-config-B7vf3XX5.d.ts} +1 -1
  44. package/dist/{spring-instance-Bijjj8Mq.d.ts → spring-instance-CZk8Ju5T.d.ts} +1 -1
  45. package/dist/testing/index.d.ts +2 -2
  46. package/dist/testing/index.js +1 -171
  47. package/dist/types/index.js +1 -72
  48. package/dist/utils/index.d.ts +1 -0
  49. package/dist/utils/index.js +1 -772
  50. package/dist/validation/index.js +1 -147
  51. package/package.json +1 -1
  52. package/dist/adapters/index.js.map +0 -1
  53. package/dist/auth/index.js.map +0 -1
  54. package/dist/chunk-EFUBAQCV.js +0 -94
  55. package/dist/chunk-EFUBAQCV.js.map +0 -1
  56. package/dist/chunk-F2SIMWZ5.js +0 -173
  57. package/dist/chunk-F2SIMWZ5.js.map +0 -1
  58. package/dist/chunk-F7WUQJH7.js +0 -399
  59. package/dist/chunk-F7WUQJH7.js.map +0 -1
  60. package/dist/chunk-GON7Q32Q.js +0 -176
  61. package/dist/chunk-GON7Q32Q.js.map +0 -1
  62. package/dist/chunk-GXU75LQX.js +0 -182
  63. package/dist/chunk-GXU75LQX.js.map +0 -1
  64. package/dist/chunk-HFELOXDQ.js +0 -110
  65. package/dist/chunk-HFELOXDQ.js.map +0 -1
  66. package/dist/chunk-KX32MU3I.js +0 -190
  67. package/dist/chunk-KX32MU3I.js.map +0 -1
  68. package/dist/chunk-MEWPYTWC.js +0 -284
  69. package/dist/chunk-MEWPYTWC.js.map +0 -1
  70. package/dist/chunk-N2L4TUC4.js +0 -34
  71. package/dist/chunk-N2L4TUC4.js.map +0 -1
  72. package/dist/chunk-NQQIVCLX.js +0 -47
  73. package/dist/chunk-NQQIVCLX.js.map +0 -1
  74. package/dist/chunk-OSSX443T.js +0 -146
  75. package/dist/chunk-OSSX443T.js.map +0 -1
  76. package/dist/chunk-PT4DIYUK.js +0 -78
  77. package/dist/chunk-PT4DIYUK.js.map +0 -1
  78. package/dist/chunk-QAVWXARR.js +0 -51
  79. package/dist/chunk-QAVWXARR.js.map +0 -1
  80. package/dist/chunk-RRWKDFAB.js +0 -143
  81. package/dist/chunk-RRWKDFAB.js.map +0 -1
  82. package/dist/chunk-RUCXSQEY.js +0 -42
  83. package/dist/chunk-RUCXSQEY.js.map +0 -1
  84. package/dist/chunk-S6RPCN5H.js +0 -64
  85. package/dist/chunk-S6RPCN5H.js.map +0 -1
  86. package/dist/chunk-S7MKRNMI.js +0 -153
  87. package/dist/chunk-S7MKRNMI.js.map +0 -1
  88. package/dist/chunk-SQB4F3EF.js +0 -55
  89. package/dist/chunk-SQB4F3EF.js.map +0 -1
  90. package/dist/chunk-UDT2RPX2.js +0 -43
  91. package/dist/chunk-UDT2RPX2.js.map +0 -1
  92. package/dist/chunk-VRMVN2UM.js +0 -17
  93. package/dist/chunk-VRMVN2UM.js.map +0 -1
  94. package/dist/chunk-XGNQEGV7.js +0 -391
  95. package/dist/chunk-XGNQEGV7.js.map +0 -1
  96. package/dist/config/index.js.map +0 -1
  97. package/dist/devtools/index.js.map +0 -1
  98. package/dist/errors/index.js.map +0 -1
  99. package/dist/events/index.js.map +0 -1
  100. package/dist/i18n/index.js.map +0 -1
  101. package/dist/index.js.map +0 -1
  102. package/dist/instance/index.js.map +0 -1
  103. package/dist/logger/index.js.map +0 -1
  104. package/dist/middleware/index.js.map +0 -1
  105. package/dist/plugins/index.js.map +0 -1
  106. package/dist/testing/index.js.map +0 -1
  107. package/dist/types/index.js.map +0 -1
  108. package/dist/utils/index.js.map +0 -1
  109. package/dist/validation/index.js.map +0 -1
@@ -1,284 +0,0 @@
1
- import {
2
- registerFallbackMigration
3
- } from "./chunk-RUCXSQEY.js";
4
- import {
5
- devThrow,
6
- tryGetSpringInstance
7
- } from "./chunk-EFUBAQCV.js";
8
- import {
9
- SpringMiddlewareError
10
- } from "./chunk-PT4DIYUK.js";
11
-
12
- // src/middleware/middleware-runner.ts
13
- function composeMiddleware(middlewares, options) {
14
- const timeoutMs = options?.timeoutMs;
15
- return async (ctx) => {
16
- let index = -1;
17
- let timedOut = false;
18
- const timeoutController = timeoutMs != null && timeoutMs > 0 && typeof AbortController !== "undefined" ? new AbortController() : null;
19
- const restoreSignal = timeoutController ? attachTimeoutSignal(ctx, timeoutController.signal) : () => {
20
- };
21
- const createTimeoutError = () => new SpringMiddlewareError(
22
- `Middleware chain timed out after ${timeoutMs}ms`,
23
- "timeout"
24
- );
25
- async function dispatch(i) {
26
- if (timedOut) {
27
- throw createTimeoutError();
28
- }
29
- if (i <= index) {
30
- throw new SpringMiddlewareError("next() called multiple times in middleware.", "compose");
31
- }
32
- index = i;
33
- if (i >= middlewares.length) {
34
- return;
35
- }
36
- const fn = middlewares[i];
37
- if (!fn) return;
38
- await fn(ctx, () => dispatch(i + 1));
39
- }
40
- try {
41
- if (timeoutMs != null && timeoutMs > 0) {
42
- await raceWithTimeout(dispatch(0), timeoutMs, () => {
43
- timedOut = true;
44
- timeoutController?.abort();
45
- });
46
- } else {
47
- await dispatch(0);
48
- }
49
- } finally {
50
- restoreSignal();
51
- }
52
- };
53
- }
54
- function isAbortSignalLike(value) {
55
- if (!value || typeof value !== "object") return false;
56
- const candidate = value;
57
- return typeof candidate.aborted === "boolean" && typeof candidate.addEventListener === "function";
58
- }
59
- function canAssignSignal(target) {
60
- let current = target;
61
- while (current) {
62
- const descriptor = Object.getOwnPropertyDescriptor(current, "signal");
63
- if (!descriptor) {
64
- current = Object.getPrototypeOf(current);
65
- continue;
66
- }
67
- if ("set" in descriptor) {
68
- return typeof descriptor.set === "function";
69
- }
70
- return descriptor.writable === true;
71
- }
72
- return true;
73
- }
74
- function mergeAbortSignals(existing, timeoutSignal) {
75
- if (typeof AbortSignal !== "undefined" && typeof AbortSignal.any === "function") {
76
- return { signal: AbortSignal.any([existing, timeoutSignal]), cleanup: () => {
77
- } };
78
- }
79
- if (typeof AbortController === "undefined") {
80
- return { signal: timeoutSignal, cleanup: () => {
81
- } };
82
- }
83
- const controller = new AbortController();
84
- const abortCombined = () => {
85
- if (!controller.signal.aborted) {
86
- controller.abort();
87
- }
88
- };
89
- if (existing.aborted || timeoutSignal.aborted) {
90
- abortCombined();
91
- return { signal: controller.signal, cleanup: () => {
92
- } };
93
- }
94
- existing.addEventListener("abort", abortCombined, { once: true });
95
- timeoutSignal.addEventListener("abort", abortCombined, { once: true });
96
- return {
97
- signal: controller.signal,
98
- cleanup: () => {
99
- existing.removeEventListener("abort", abortCombined);
100
- timeoutSignal.removeEventListener("abort", abortCombined);
101
- }
102
- };
103
- }
104
- function attachTimeoutSignal(ctx, timeoutSignal) {
105
- if (!ctx || typeof ctx !== "object") {
106
- return () => {
107
- };
108
- }
109
- const target = ctx;
110
- if (!("signal" in target)) {
111
- return () => {
112
- };
113
- }
114
- const previous = target.signal;
115
- if (previous !== void 0 && !isAbortSignalLike(previous)) {
116
- return () => {
117
- };
118
- }
119
- let nextSignal = timeoutSignal;
120
- let cleanupMerged = () => {
121
- };
122
- if (isAbortSignalLike(previous) && previous !== timeoutSignal) {
123
- const merged = mergeAbortSignals(previous, timeoutSignal);
124
- nextSignal = merged.signal;
125
- cleanupMerged = merged.cleanup;
126
- }
127
- if (!canAssignSignal(target)) {
128
- return cleanupMerged;
129
- }
130
- try {
131
- target.signal = nextSignal;
132
- } catch {
133
- cleanupMerged();
134
- return () => {
135
- };
136
- }
137
- return () => {
138
- cleanupMerged();
139
- try {
140
- if (previous === void 0) {
141
- delete target.signal;
142
- } else {
143
- target.signal = previous;
144
- }
145
- } catch {
146
- }
147
- };
148
- }
149
- function raceWithTimeout(task, ms, onTimeout) {
150
- return new Promise((resolve, reject) => {
151
- let settled = false;
152
- const hasAbortTimeout = typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function";
153
- let signal;
154
- let fallbackTimer;
155
- function handleTimeout() {
156
- if (!settled) {
157
- settled = true;
158
- onTimeout();
159
- if (signal) {
160
- signal.removeEventListener("abort", handleTimeout);
161
- }
162
- reject(new SpringMiddlewareError(`Middleware chain timed out after ${ms}ms`, "timeout"));
163
- }
164
- }
165
- if (hasAbortTimeout) {
166
- signal = AbortSignal.timeout(ms);
167
- signal.addEventListener("abort", handleTimeout, { once: true });
168
- } else {
169
- fallbackTimer = setTimeout(handleTimeout, ms);
170
- }
171
- task.then(
172
- () => {
173
- if (!settled) {
174
- settled = true;
175
- if (fallbackTimer !== void 0) clearTimeout(fallbackTimer);
176
- if (signal) signal.removeEventListener("abort", handleTimeout);
177
- resolve();
178
- }
179
- },
180
- (err) => {
181
- if (!settled) {
182
- settled = true;
183
- if (fallbackTimer !== void 0) clearTimeout(fallbackTimer);
184
- if (signal) signal.removeEventListener("abort", handleTimeout);
185
- reject(err);
186
- }
187
- }
188
- );
189
- });
190
- }
191
-
192
- // src/middleware/middleware-registry.ts
193
- var fallbackRegistry = /* @__PURE__ */ new Map();
194
- registerFallbackMigration((instance) => {
195
- if (fallbackRegistry.size === 0) return;
196
- const target = instance.core.middlewareRegistry;
197
- for (const [slot, entries] of fallbackRegistry) {
198
- if (entries.length === 0) continue;
199
- const existing = target.get(slot);
200
- if (!existing) {
201
- target.set(slot, [...entries]);
202
- continue;
203
- }
204
- for (const entry of entries) {
205
- if (!existing.includes(entry)) {
206
- existing.push(entry);
207
- }
208
- }
209
- existing.sort((a, b) => b.priority - a.priority);
210
- }
211
- });
212
- function removeMiddlewareEntry(registry, slot, entry) {
213
- const current = registry.get(slot);
214
- if (!current) return;
215
- const idx = current.indexOf(entry);
216
- if (idx !== -1) current.splice(idx, 1);
217
- }
218
- function getRegistry() {
219
- const instance = tryGetSpringInstance();
220
- return instance ? instance.core.middlewareRegistry : fallbackRegistry;
221
- }
222
- function registerMiddleware(slot, middleware, options) {
223
- if (!slot || typeof slot !== "string") {
224
- devThrow("Middleware", "registerMiddleware(): slot must be a non-empty string");
225
- return () => {
226
- };
227
- }
228
- if (typeof middleware !== "function") {
229
- devThrow("Middleware", `registerMiddleware("${slot}"): middleware must be a function`);
230
- return () => {
231
- };
232
- }
233
- const priority = options?.priority ?? 0;
234
- const entry = { fn: middleware, priority };
235
- const registry = getRegistry();
236
- let list = registry.get(slot);
237
- if (!list) {
238
- list = [];
239
- registry.set(slot, list);
240
- }
241
- list.push(entry);
242
- list.sort((a, b) => b.priority - a.priority);
243
- return () => {
244
- const e = entry;
245
- removeMiddlewareEntry(registry, slot, e);
246
- if (registry !== fallbackRegistry) {
247
- removeMiddlewareEntry(fallbackRegistry, slot, e);
248
- }
249
- const instance = tryGetSpringInstance();
250
- if (instance) {
251
- removeMiddlewareEntry(
252
- instance.core.middlewareRegistry,
253
- slot,
254
- e
255
- );
256
- }
257
- };
258
- }
259
- function getMiddlewareRunner(slot) {
260
- const registry = getRegistry();
261
- const entries = registry.get(slot);
262
- if (!entries || entries.length === 0) {
263
- return async () => {
264
- };
265
- }
266
- return composeMiddleware(entries.map((e) => e.fn));
267
- }
268
- function getRegisteredMiddlewareSlots() {
269
- const registry = getRegistry();
270
- return Array.from(registry.entries()).filter(([, list]) => list.length > 0).map(([slot]) => slot);
271
- }
272
- function clearAllMiddleware() {
273
- const registry = getRegistry();
274
- registry.clear();
275
- }
276
-
277
- export {
278
- composeMiddleware,
279
- registerMiddleware,
280
- getMiddlewareRunner,
281
- getRegisteredMiddlewareSlots,
282
- clearAllMiddleware
283
- };
284
- //# sourceMappingURL=chunk-MEWPYTWC.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/middleware/middleware-runner.ts","../src/middleware/middleware-registry.ts"],"sourcesContent":["/**\n * Koa-style middleware composition.\n * Chains middleware functions with a `next()` pattern.\n * @module middleware-runner\n */\n\nimport { SpringMiddlewareError } from \"../errors/errors\";\nimport type { MiddlewareFn } from \"./middleware-types\";\n\nexport interface ComposeOptions {\n /**\n * Optional timeout in milliseconds for the entire middleware chain.\n * If the chain doesn't complete within this time, a SpringMiddlewareError is thrown.\n * When omitted, no timeout is applied (backward-compatible default).\n */\n timeoutMs?: number;\n}\n\n/**\n * Compose an array of middleware functions into a single function.\n * Each middleware receives a context and a `next` callback.\n * Calling `next()` invokes the next middleware in the chain.\n * Calling `next()` more than once throws an error.\n *\n * @param middlewares - Array of middleware functions to compose\n * @param options - Optional configuration (e.g. timeout)\n * @returns A function that runs the full middleware chain on a given context.\n */\nexport function composeMiddleware<TContext>(\n middlewares: ReadonlyArray<MiddlewareFn<TContext>>,\n options?: ComposeOptions,\n): (ctx: TContext) => Promise<void> {\n const timeoutMs = options?.timeoutMs;\n\n return async (ctx: TContext): Promise<void> => {\n let index = -1;\n let timedOut = false;\n const timeoutController =\n timeoutMs != null && timeoutMs > 0 && typeof AbortController !== \"undefined\"\n ? new AbortController()\n : null;\n const restoreSignal = timeoutController ? attachTimeoutSignal(ctx, timeoutController.signal) : () => {};\n\n const createTimeoutError = (): SpringMiddlewareError =>\n new SpringMiddlewareError(\n `Middleware chain timed out after ${timeoutMs}ms`,\n \"timeout\",\n );\n\n async function dispatch(i: number): Promise<void> {\n if (timedOut) {\n throw createTimeoutError();\n }\n if (i <= index) {\n throw new SpringMiddlewareError(\"next() called multiple times in middleware.\", \"compose\");\n }\n index = i;\n if (i >= middlewares.length) {\n return;\n }\n const fn = middlewares[i];\n if (!fn) return;\n await fn(ctx, () => dispatch(i + 1));\n }\n\n try {\n if (timeoutMs != null && timeoutMs > 0) {\n await raceWithTimeout(dispatch(0), timeoutMs, () => {\n timedOut = true;\n timeoutController?.abort();\n });\n } else {\n await dispatch(0);\n }\n } finally {\n restoreSignal();\n }\n };\n}\n\nfunction isAbortSignalLike(value: unknown): value is AbortSignal {\n if (!value || typeof value !== \"object\") return false;\n const candidate = value as { aborted?: unknown; addEventListener?: unknown };\n return typeof candidate.aborted === \"boolean\" && typeof candidate.addEventListener === \"function\";\n}\n\nfunction canAssignSignal(target: Record<string, unknown>): boolean {\n let current: object | null = target;\n while (current) {\n const descriptor = Object.getOwnPropertyDescriptor(current, \"signal\");\n if (!descriptor) {\n current = Object.getPrototypeOf(current);\n continue;\n }\n if (\"set\" in descriptor) {\n return typeof descriptor.set === \"function\";\n }\n return descriptor.writable === true;\n }\n return true;\n}\n\nfunction mergeAbortSignals(\n existing: AbortSignal,\n timeoutSignal: AbortSignal,\n): { signal: AbortSignal; cleanup: () => void } {\n if (typeof AbortSignal !== \"undefined\" && typeof AbortSignal.any === \"function\") {\n return { signal: AbortSignal.any([existing, timeoutSignal]), cleanup: () => {} };\n }\n\n if (typeof AbortController === \"undefined\") {\n return { signal: timeoutSignal, cleanup: () => {} };\n }\n\n const controller = new AbortController();\n const abortCombined = (): void => {\n if (!controller.signal.aborted) {\n controller.abort();\n }\n };\n\n if (existing.aborted || timeoutSignal.aborted) {\n abortCombined();\n return { signal: controller.signal, cleanup: () => {} };\n }\n\n existing.addEventListener(\"abort\", abortCombined, { once: true });\n timeoutSignal.addEventListener(\"abort\", abortCombined, { once: true });\n\n return {\n signal: controller.signal,\n cleanup: () => {\n existing.removeEventListener(\"abort\", abortCombined);\n timeoutSignal.removeEventListener(\"abort\", abortCombined);\n },\n };\n}\n\n/**\n * If the context exposes a `signal` field, attach timeout signal so middleware\n * can abort downstream fetch/IO operations cooperatively.\n */\nfunction attachTimeoutSignal<TContext>(ctx: TContext, timeoutSignal: AbortSignal): () => void {\n if (!ctx || typeof ctx !== \"object\") {\n return () => {};\n }\n\n const target = ctx as Record<string, unknown>;\n if (!(\"signal\" in target)) {\n return () => {};\n }\n\n const previous = target.signal;\n if (previous !== undefined && !isAbortSignalLike(previous)) {\n return () => {};\n }\n\n let nextSignal: AbortSignal = timeoutSignal;\n let cleanupMerged = () => {};\n if (\n isAbortSignalLike(previous) &&\n previous !== timeoutSignal\n ) {\n const merged = mergeAbortSignals(previous, timeoutSignal);\n nextSignal = merged.signal;\n cleanupMerged = merged.cleanup;\n }\n\n if (!canAssignSignal(target)) {\n return cleanupMerged;\n }\n\n try {\n target.signal = nextSignal;\n } catch {\n cleanupMerged();\n return () => {};\n }\n\n return () => {\n cleanupMerged();\n try {\n if (previous === undefined) {\n delete target.signal;\n } else {\n target.signal = previous;\n }\n } catch {\n // Ignore restore errors for read-only or sealed contexts.\n }\n };\n}\n\n/**\n * Race a promise against a timeout. Rejects with SpringMiddlewareError if the\n * timeout fires first. Uses AbortSignal.timeout where available, falling\n * back to setTimeout for older runtimes.\n */\nfunction raceWithTimeout(task: Promise<void>, ms: number, onTimeout: () => void): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n\n // Use AbortSignal.timeout if available (Node 18+, modern browsers)\n const hasAbortTimeout = typeof AbortSignal !== \"undefined\" && typeof AbortSignal.timeout === \"function\";\n let signal: AbortSignal | undefined;\n let fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\n function handleTimeout(): void {\n if (!settled) {\n settled = true;\n onTimeout();\n if (signal) {\n signal.removeEventListener(\"abort\", handleTimeout);\n }\n reject(new SpringMiddlewareError(`Middleware chain timed out after ${ms}ms`, \"timeout\"));\n }\n }\n\n if (hasAbortTimeout) {\n signal = AbortSignal.timeout(ms);\n signal.addEventListener(\"abort\", handleTimeout, { once: true });\n } else {\n fallbackTimer = setTimeout(handleTimeout, ms);\n }\n\n task.then(\n () => {\n if (!settled) {\n settled = true;\n if (fallbackTimer !== undefined) clearTimeout(fallbackTimer);\n if (signal) signal.removeEventListener(\"abort\", handleTimeout);\n resolve();\n }\n },\n (err: unknown) => {\n if (!settled) {\n settled = true;\n if (fallbackTimer !== undefined) clearTimeout(fallbackTimer);\n if (signal) signal.removeEventListener(\"abort\", handleTimeout);\n reject(err);\n }\n },\n );\n });\n}\n","/**\n * Middleware registry — manages middleware functions registered per slot.\n *\n * Type-safe: the context type is inferred from the slot name via MiddlewareSlotMap.\n * Custom slots added via declaration merging also get full type inference.\n *\n * @module middleware-registry\n */\n\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\nimport { devThrow } from \"../utils/dev-warnings\";\nimport { composeMiddleware } from \"./middleware-runner\";\nimport type { MiddlewareEntry, MiddlewareFn, MiddlewareSlot } from \"./middleware-types\";\n\nexport interface MiddlewareOptions {\n /** Higher priority middleware runs first. Default: 0 */\n priority?: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- heterogeneous registry stores middlewares for multiple context types by slot\nconst fallbackRegistry = new Map<MiddlewareSlot, MiddlewareEntry<any>[]>();\n\n// Migrate pre-mount middleware registrations to SpringInstance when it becomes available.\nregisterFallbackMigration((instance) => {\n if (fallbackRegistry.size === 0) return;\n\n const target = instance.core.middlewareRegistry;\n for (const [slot, entries] of fallbackRegistry) {\n if (entries.length === 0) continue;\n const existing = target.get(slot);\n if (!existing) {\n target.set(slot, [...entries]);\n continue;\n }\n for (const entry of entries) {\n if (!existing.includes(entry)) {\n existing.push(entry);\n }\n }\n existing.sort((a, b) => b.priority - a.priority);\n }\n});\n\nfunction removeMiddlewareEntry(\n registry: Map<MiddlewareSlot, MiddlewareEntry<unknown>[]>,\n slot: MiddlewareSlot,\n entry: MiddlewareEntry<unknown>,\n): void {\n const current = registry.get(slot);\n if (!current) return;\n const idx = current.indexOf(entry);\n if (idx !== -1) current.splice(idx, 1);\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- same rationale as fallbackRegistry; runtime slot dispatch preserves context typing at call sites\nfunction getRegistry(): Map<MiddlewareSlot, MiddlewareEntry<any>[]> {\n const instance = tryGetSpringInstance();\n return instance ? instance.core.middlewareRegistry : fallbackRegistry;\n}\n\n/**\n * Register a middleware function for a given slot.\n * The context type is automatically inferred from the slot name via MiddlewareSlotMap.\n *\n * @example\n * ```ts\n * // Context type is inferred as FormSaveContext\n * const unregister = registerMiddleware(\"form:beforeSave\", async (ctx, next) => {\n * console.log(\"Saving entity:\", ctx.entity);\n * await next();\n * });\n * unregister(); // Cleanup when no longer needed\n *\n * // With priority (higher = runs first):\n * registerMiddleware(\"form:beforeSave\", auditMiddleware, { priority: 10 });\n * ```\n *\n * @param slot - Middleware slot name (e.g. \"form:beforeSave\", \"api:beforeRequest\")\n * @param middleware - Koa-style middleware function receiving `(ctx, next)`\n * @param options - Optional settings; `priority` controls execution order (higher runs first, default 0)\n * @returns An unregister function that removes this middleware from the slot.\n */\nexport function registerMiddleware<TContext = unknown>(\n slot: MiddlewareSlot,\n middleware: MiddlewareFn<TContext>,\n options?: MiddlewareOptions,\n): () => void {\n if (!slot || typeof slot !== \"string\") {\n devThrow(\"Middleware\", \"registerMiddleware(): slot must be a non-empty string\");\n return () => {};\n }\n if (typeof middleware !== \"function\") {\n devThrow(\"Middleware\", `registerMiddleware(\"${slot}\"): middleware must be a function`);\n return () => {};\n }\n\n const priority = options?.priority ?? 0;\n const entry: MiddlewareEntry<TContext> = { fn: middleware, priority };\n\n const registry = getRegistry();\n let list = registry.get(slot);\n if (!list) {\n list = [];\n registry.set(slot, list);\n }\n list.push(entry);\n // Stable sort: higher priority first\n list.sort((a, b) => b.priority - a.priority);\n\n return () => {\n const e = entry as MiddlewareEntry<unknown>;\n removeMiddlewareEntry(registry as Map<MiddlewareSlot, MiddlewareEntry<unknown>[]>, slot, e);\n if (registry !== fallbackRegistry) {\n removeMiddlewareEntry(fallbackRegistry as Map<MiddlewareSlot, MiddlewareEntry<unknown>[]>, slot, e);\n }\n const instance = tryGetSpringInstance();\n if (instance) {\n removeMiddlewareEntry(\n instance.core.middlewareRegistry as Map<MiddlewareSlot, MiddlewareEntry<unknown>[]>,\n slot,\n e,\n );\n }\n };\n}\n\n/**\n * Get a composed runner for a given slot.\n * Returns a function that executes all registered middleware for that slot\n * in priority order (higher priority first) using the Koa-style `next()` pattern.\n *\n * If no middleware is registered for the slot, the returned function is a no-op.\n *\n * @param slot - Middleware slot name to compose a runner for\n * @returns An async function that runs all middleware for the slot on a given context.\n */\nexport function getMiddlewareRunner<TContext = unknown>(\n slot: MiddlewareSlot,\n): (ctx: TContext) => Promise<void> {\n const registry = getRegistry();\n const entries = registry.get(slot);\n if (!entries || entries.length === 0) {\n return async () => {};\n }\n return composeMiddleware<TContext>(entries.map((e) => e.fn as MiddlewareFn<TContext>));\n}\n\n/**\n * Get all slot names that have at least one middleware registered.\n * Useful for debugging and introspection.\n */\nexport function getRegisteredMiddlewareSlots(): MiddlewareSlot[] {\n const registry = getRegistry();\n return Array.from(registry.entries())\n .filter(([, list]) => list.length > 0)\n .map(([slot]) => slot);\n}\n\n/**\n * Remove all registered middleware. Intended for testing.\n */\nexport function clearAllMiddleware(): void {\n const registry = getRegistry();\n registry.clear();\n}\n"],"mappings":";;;;;;;;;;;;AA4BO,SAAS,kBACZ,aACA,SACgC;AAChC,QAAM,YAAY,SAAS;AAE3B,SAAO,OAAO,QAAiC;AAC3C,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,UAAM,oBACF,aAAa,QAAQ,YAAY,KAAK,OAAO,oBAAoB,cAC3D,IAAI,gBAAgB,IACpB;AACV,UAAM,gBAAgB,oBAAoB,oBAAoB,KAAK,kBAAkB,MAAM,IAAI,MAAM;AAAA,IAAC;AAEtG,UAAM,qBAAqB,MACvB,IAAI;AAAA,MACA,oCAAoC,SAAS;AAAA,MAC7C;AAAA,IACJ;AAEJ,mBAAe,SAAS,GAA0B;AAC9C,UAAI,UAAU;AACV,cAAM,mBAAmB;AAAA,MAC7B;AACA,UAAI,KAAK,OAAO;AACZ,cAAM,IAAI,sBAAsB,+CAA+C,SAAS;AAAA,MAC5F;AACA,cAAQ;AACR,UAAI,KAAK,YAAY,QAAQ;AACzB;AAAA,MACJ;AACA,YAAM,KAAK,YAAY,CAAC;AACxB,UAAI,CAAC,GAAI;AACT,YAAM,GAAG,KAAK,MAAM,SAAS,IAAI,CAAC,CAAC;AAAA,IACvC;AAEA,QAAI;AACA,UAAI,aAAa,QAAQ,YAAY,GAAG;AACpC,cAAM,gBAAgB,SAAS,CAAC,GAAG,WAAW,MAAM;AAChD,qBAAW;AACX,6BAAmB,MAAM;AAAA,QAC7B,CAAC;AAAA,MACL,OAAO;AACH,cAAM,SAAS,CAAC;AAAA,MACpB;AAAA,IACJ,UAAE;AACE,oBAAc;AAAA,IAClB;AAAA,EACJ;AACJ;AAEA,SAAS,kBAAkB,OAAsC;AAC7D,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,YAAY;AAClB,SAAO,OAAO,UAAU,YAAY,aAAa,OAAO,UAAU,qBAAqB;AAC3F;AAEA,SAAS,gBAAgB,QAA0C;AAC/D,MAAI,UAAyB;AAC7B,SAAO,SAAS;AACZ,UAAM,aAAa,OAAO,yBAAyB,SAAS,QAAQ;AACpE,QAAI,CAAC,YAAY;AACb,gBAAU,OAAO,eAAe,OAAO;AACvC;AAAA,IACJ;AACA,QAAI,SAAS,YAAY;AACrB,aAAO,OAAO,WAAW,QAAQ;AAAA,IACrC;AACA,WAAO,WAAW,aAAa;AAAA,EACnC;AACA,SAAO;AACX;AAEA,SAAS,kBACL,UACA,eAC4C;AAC5C,MAAI,OAAO,gBAAgB,eAAe,OAAO,YAAY,QAAQ,YAAY;AAC7E,WAAO,EAAE,QAAQ,YAAY,IAAI,CAAC,UAAU,aAAa,CAAC,GAAG,SAAS,MAAM;AAAA,IAAC,EAAE;AAAA,EACnF;AAEA,MAAI,OAAO,oBAAoB,aAAa;AACxC,WAAO,EAAE,QAAQ,eAAe,SAAS,MAAM;AAAA,IAAC,EAAE;AAAA,EACtD;AAEA,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,gBAAgB,MAAY;AAC9B,QAAI,CAAC,WAAW,OAAO,SAAS;AAC5B,iBAAW,MAAM;AAAA,IACrB;AAAA,EACJ;AAEA,MAAI,SAAS,WAAW,cAAc,SAAS;AAC3C,kBAAc;AACd,WAAO,EAAE,QAAQ,WAAW,QAAQ,SAAS,MAAM;AAAA,IAAC,EAAE;AAAA,EAC1D;AAEA,WAAS,iBAAiB,SAAS,eAAe,EAAE,MAAM,KAAK,CAAC;AAChE,gBAAc,iBAAiB,SAAS,eAAe,EAAE,MAAM,KAAK,CAAC;AAErE,SAAO;AAAA,IACH,QAAQ,WAAW;AAAA,IACnB,SAAS,MAAM;AACX,eAAS,oBAAoB,SAAS,aAAa;AACnD,oBAAc,oBAAoB,SAAS,aAAa;AAAA,IAC5D;AAAA,EACJ;AACJ;AAMA,SAAS,oBAA8B,KAAe,eAAwC;AAC1F,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACjC,WAAO,MAAM;AAAA,IAAC;AAAA,EAClB;AAEA,QAAM,SAAS;AACf,MAAI,EAAE,YAAY,SAAS;AACvB,WAAO,MAAM;AAAA,IAAC;AAAA,EAClB;AAEA,QAAM,WAAW,OAAO;AACxB,MAAI,aAAa,UAAa,CAAC,kBAAkB,QAAQ,GAAG;AACxD,WAAO,MAAM;AAAA,IAAC;AAAA,EAClB;AAEA,MAAI,aAA0B;AAC9B,MAAI,gBAAgB,MAAM;AAAA,EAAC;AAC3B,MACI,kBAAkB,QAAQ,KAC1B,aAAa,eACf;AACE,UAAM,SAAS,kBAAkB,UAAU,aAAa;AACxD,iBAAa,OAAO;AACpB,oBAAgB,OAAO;AAAA,EAC3B;AAEA,MAAI,CAAC,gBAAgB,MAAM,GAAG;AAC1B,WAAO;AAAA,EACX;AAEA,MAAI;AACA,WAAO,SAAS;AAAA,EACpB,QAAQ;AACJ,kBAAc;AACd,WAAO,MAAM;AAAA,IAAC;AAAA,EAClB;AAEA,SAAO,MAAM;AACT,kBAAc;AACd,QAAI;AACA,UAAI,aAAa,QAAW;AACxB,eAAO,OAAO;AAAA,MAClB,OAAO;AACH,eAAO,SAAS;AAAA,MACpB;AAAA,IACJ,QAAQ;AAAA,IAER;AAAA,EACJ;AACJ;AAOA,SAAS,gBAAgB,MAAqB,IAAY,WAAsC;AAC5F,SAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC1C,QAAI,UAAU;AAGd,UAAM,kBAAkB,OAAO,gBAAgB,eAAe,OAAO,YAAY,YAAY;AAC7F,QAAI;AACJ,QAAI;AAEJ,aAAS,gBAAsB;AAC3B,UAAI,CAAC,SAAS;AACV,kBAAU;AACV,kBAAU;AACV,YAAI,QAAQ;AACR,iBAAO,oBAAoB,SAAS,aAAa;AAAA,QACrD;AACA,eAAO,IAAI,sBAAsB,oCAAoC,EAAE,MAAM,SAAS,CAAC;AAAA,MAC3F;AAAA,IACJ;AAEA,QAAI,iBAAiB;AACjB,eAAS,YAAY,QAAQ,EAAE;AAC/B,aAAO,iBAAiB,SAAS,eAAe,EAAE,MAAM,KAAK,CAAC;AAAA,IAClE,OAAO;AACH,sBAAgB,WAAW,eAAe,EAAE;AAAA,IAChD;AAEA,SAAK;AAAA,MACD,MAAM;AACF,YAAI,CAAC,SAAS;AACV,oBAAU;AACV,cAAI,kBAAkB,OAAW,cAAa,aAAa;AAC3D,cAAI,OAAQ,QAAO,oBAAoB,SAAS,aAAa;AAC7D,kBAAQ;AAAA,QACZ;AAAA,MACJ;AAAA,MACA,CAAC,QAAiB;AACd,YAAI,CAAC,SAAS;AACV,oBAAU;AACV,cAAI,kBAAkB,OAAW,cAAa,aAAa;AAC3D,cAAI,OAAQ,QAAO,oBAAoB,SAAS,aAAa;AAC7D,iBAAO,GAAG;AAAA,QACd;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;;;AC/NA,IAAM,mBAAmB,oBAAI,IAA4C;AAGzE,0BAA0B,CAAC,aAAa;AACpC,MAAI,iBAAiB,SAAS,EAAG;AAEjC,QAAM,SAAS,SAAS,KAAK;AAC7B,aAAW,CAAC,MAAM,OAAO,KAAK,kBAAkB;AAC5C,QAAI,QAAQ,WAAW,EAAG;AAC1B,UAAM,WAAW,OAAO,IAAI,IAAI;AAChC,QAAI,CAAC,UAAU;AACX,aAAO,IAAI,MAAM,CAAC,GAAG,OAAO,CAAC;AAC7B;AAAA,IACJ;AACA,eAAW,SAAS,SAAS;AACzB,UAAI,CAAC,SAAS,SAAS,KAAK,GAAG;AAC3B,iBAAS,KAAK,KAAK;AAAA,MACvB;AAAA,IACJ;AACA,aAAS,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAAA,EACnD;AACJ,CAAC;AAED,SAAS,sBACL,UACA,MACA,OACI;AACJ,QAAM,UAAU,SAAS,IAAI,IAAI;AACjC,MAAI,CAAC,QAAS;AACd,QAAM,MAAM,QAAQ,QAAQ,KAAK;AACjC,MAAI,QAAQ,GAAI,SAAQ,OAAO,KAAK,CAAC;AACzC;AAGA,SAAS,cAA2D;AAChE,QAAM,WAAW,qBAAqB;AACtC,SAAO,WAAW,SAAS,KAAK,qBAAqB;AACzD;AAwBO,SAAS,mBACZ,MACA,YACA,SACU;AACV,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACnC,aAAS,cAAc,uDAAuD;AAC9E,WAAO,MAAM;AAAA,IAAC;AAAA,EAClB;AACA,MAAI,OAAO,eAAe,YAAY;AAClC,aAAS,cAAc,uBAAuB,IAAI,mCAAmC;AACrF,WAAO,MAAM;AAAA,IAAC;AAAA,EAClB;AAEA,QAAM,WAAW,SAAS,YAAY;AACtC,QAAM,QAAmC,EAAE,IAAI,YAAY,SAAS;AAEpE,QAAM,WAAW,YAAY;AAC7B,MAAI,OAAO,SAAS,IAAI,IAAI;AAC5B,MAAI,CAAC,MAAM;AACP,WAAO,CAAC;AACR,aAAS,IAAI,MAAM,IAAI;AAAA,EAC3B;AACA,OAAK,KAAK,KAAK;AAEf,OAAK,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAE3C,SAAO,MAAM;AACT,UAAM,IAAI;AACV,0BAAsB,UAA6D,MAAM,CAAC;AAC1F,QAAI,aAAa,kBAAkB;AAC/B,4BAAsB,kBAAqE,MAAM,CAAC;AAAA,IACtG;AACA,UAAM,WAAW,qBAAqB;AACtC,QAAI,UAAU;AACV;AAAA,QACI,SAAS,KAAK;AAAA,QACd;AAAA,QACA;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;AAYO,SAAS,oBACZ,MACgC;AAChC,QAAM,WAAW,YAAY;AAC7B,QAAM,UAAU,SAAS,IAAI,IAAI;AACjC,MAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AAClC,WAAO,YAAY;AAAA,IAAC;AAAA,EACxB;AACA,SAAO,kBAA4B,QAAQ,IAAI,CAAC,MAAM,EAAE,EAA4B,CAAC;AACzF;AAMO,SAAS,+BAAiD;AAC7D,QAAM,WAAW,YAAY;AAC7B,SAAO,MAAM,KAAK,SAAS,QAAQ,CAAC,EAC/B,OAAO,CAAC,CAAC,EAAE,IAAI,MAAM,KAAK,SAAS,CAAC,EACpC,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AAC7B;AAKO,SAAS,qBAA2B;AACvC,QAAM,WAAW,YAAY;AAC7B,WAAS,MAAM;AACnB;","names":[]}
@@ -1,34 +0,0 @@
1
- // src/i18n/default-messages.ts
2
- var DEFAULT_MESSAGES = {
3
- "admin-fill-value": "This field is required",
4
- "admin-invalid-phone-number-format": "Invalid phone number format",
5
- "admin-invalid-email-format": "Invalid email format",
6
- "admin-email-contains-multiple-addresses": "Field contains multiple email addresses",
7
- "admin-invalid-url-format": "Invalid URL format",
8
- "admin-password-min-length": "Password must be at least 8 characters",
9
- "admin-password-uppercase": "Password must contain an uppercase letter",
10
- "admin-password-lowercase": "Password must contain a lowercase letter",
11
- "admin-password-digit": "Password must contain a digit",
12
- "admin-password-special-char": "Password must contain a special character",
13
- "admin-yes": "Yes",
14
- "admin-no": "No",
15
- "admin-login-failed": "Login failed",
16
- "admin-session-expired": "Session expired. Please log in again.",
17
- "admin-fill-all-required-fields": "Please fill in all required fields",
18
- "admin-username": "Username",
19
- "admin-detail": "Detail",
20
- "admin-not-found": "Not found",
21
- "admin-unknown-error": "Unknown error",
22
- "admin-validation-error": "Validation error",
23
- "admin-sorted-ascending": "Sorted ascending",
24
- "admin-sorted-descending": "Sorted descending",
25
- "admin-sort-cleared": "Sort cleared",
26
- "admin-of": "of",
27
- "admin-rows-selected": "rows selected",
28
- "admin-tree": "Tree"
29
- };
30
-
31
- export {
32
- DEFAULT_MESSAGES
33
- };
34
- //# sourceMappingURL=chunk-N2L4TUC4.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/i18n/default-messages.ts"],"sourcesContent":["/**\n * Built-in default messages for framework UI strings.\n * These provide a working default so the framework operates out of the box\n * without requiring a ContentAdapter for basic validation messages.\n * Consumers can override via setContentAdapter() for full i18n.\n * @module default-messages\n */\n\nexport const DEFAULT_MESSAGES = {\n \"admin-fill-value\": \"This field is required\",\n \"admin-invalid-phone-number-format\": \"Invalid phone number format\",\n \"admin-invalid-email-format\": \"Invalid email format\",\n \"admin-email-contains-multiple-addresses\": \"Field contains multiple email addresses\",\n \"admin-invalid-url-format\": \"Invalid URL format\",\n \"admin-password-min-length\": \"Password must be at least 8 characters\",\n \"admin-password-uppercase\": \"Password must contain an uppercase letter\",\n \"admin-password-lowercase\": \"Password must contain a lowercase letter\",\n \"admin-password-digit\": \"Password must contain a digit\",\n \"admin-password-special-char\": \"Password must contain a special character\",\n \"admin-yes\": \"Yes\",\n \"admin-no\": \"No\",\n \"admin-login-failed\": \"Login failed\",\n \"admin-session-expired\": \"Session expired. Please log in again.\",\n \"admin-fill-all-required-fields\": \"Please fill in all required fields\",\n \"admin-username\": \"Username\",\n \"admin-detail\": \"Detail\",\n \"admin-not-found\": \"Not found\",\n \"admin-unknown-error\": \"Unknown error\",\n \"admin-validation-error\": \"Validation error\",\n \"admin-sorted-ascending\": \"Sorted ascending\",\n \"admin-sorted-descending\": \"Sorted descending\",\n \"admin-sort-cleared\": \"Sort cleared\",\n \"admin-of\": \"of\",\n \"admin-rows-selected\": \"rows selected\",\n \"admin-tree\": \"Tree\",\n} as const satisfies Record<string, string>;\n"],"mappings":";AAQO,IAAM,mBAAmB;AAAA,EAC5B,oBAAoB;AAAA,EACpB,qCAAqC;AAAA,EACrC,8BAA8B;AAAA,EAC9B,2CAA2C;AAAA,EAC3C,4BAA4B;AAAA,EAC5B,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA,EAC5B,4BAA4B;AAAA,EAC5B,wBAAwB;AAAA,EACxB,+BAA+B;AAAA,EAC/B,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,sBAAsB;AAAA,EACtB,yBAAyB;AAAA,EACzB,kCAAkC;AAAA,EAClC,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA,EAC3B,sBAAsB;AAAA,EACtB,YAAY;AAAA,EACZ,uBAAuB;AAAA,EACvB,cAAc;AAClB;","names":[]}
@@ -1,47 +0,0 @@
1
- import {
2
- DEFAULT_MESSAGES
3
- } from "./chunk-N2L4TUC4.js";
4
- import {
5
- registerFallbackMigration
6
- } from "./chunk-RUCXSQEY.js";
7
- import {
8
- tryGetSpringInstance
9
- } from "./chunk-EFUBAQCV.js";
10
-
11
- // src/adapters/content-adapter.ts
12
- var fallback = {
13
- getRes: (key) => DEFAULT_MESSAGES[key] ?? `[${key}]`
14
- };
15
- function setContentAdapter(adapter) {
16
- const instance = tryGetSpringInstance();
17
- if (instance) {
18
- instance.core.contentAdapter = adapter;
19
- } else {
20
- fallbackAdapter = adapter;
21
- }
22
- }
23
- var fallbackAdapter = fallback;
24
- registerFallbackMigration((instance) => {
25
- if (fallbackAdapter !== fallback) {
26
- instance.core.contentAdapter = fallbackAdapter;
27
- }
28
- });
29
- function getContentRes(key) {
30
- const instance = tryGetSpringInstance();
31
- const adapter = instance ? instance.core.contentAdapter : fallbackAdapter;
32
- return adapter.getRes(key);
33
- }
34
- function clearContentAdapter() {
35
- const instance = tryGetSpringInstance();
36
- if (instance) {
37
- instance.core.contentAdapter = fallback;
38
- }
39
- fallbackAdapter = fallback;
40
- }
41
-
42
- export {
43
- setContentAdapter,
44
- getContentRes,
45
- clearContentAdapter
46
- };
47
- //# sourceMappingURL=chunk-NQQIVCLX.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/content-adapter.ts"],"sourcesContent":["/**\n * Content adapter — decouples API/validation layers from the i18n system (contents store).\n * Pattern matches setLogAdapter() in logger.ts.\n * @module content-adapter\n */\n\nimport { DEFAULT_MESSAGES } from \"../i18n/default-messages\";\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\n\nexport interface ContentAdapter {\n getRes(key: string): string;\n}\n\nconst fallback = {\n getRes: (key) => (DEFAULT_MESSAGES as Record<string, string>)[key] ?? `[${key}]`,\n} satisfies ContentAdapter;\n\nexport function setContentAdapter(adapter: ContentAdapter): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.core.contentAdapter = adapter;\n } else {\n fallbackAdapter = adapter;\n }\n}\n\n// Fallback for code that runs before SpringInstance is created\nlet fallbackAdapter: ContentAdapter = fallback;\n\n// Migrate fallback content adapter to SpringInstance when SpringProvider mounts\nregisterFallbackMigration((instance) => {\n if (fallbackAdapter !== fallback) {\n instance.core.contentAdapter = fallbackAdapter;\n }\n});\n\n/** Returns translated content via the registered adapter. Replaces direct getRes() imports in core/api layers. */\nexport function getContentRes(key: string): string {\n const instance = tryGetSpringInstance();\n const adapter = instance ? instance.core.contentAdapter : fallbackAdapter;\n return adapter.getRes(key);\n}\n\n/** Reset to default content adapter. For testing/integration teardown only. */\nexport function clearContentAdapter(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.core.contentAdapter = fallback;\n }\n fallbackAdapter = fallback;\n}\n"],"mappings":";;;;;;;;;;;AAcA,IAAM,WAAW;AAAA,EACb,QAAQ,CAAC,QAAS,iBAA4C,GAAG,KAAK,IAAI,GAAG;AACjF;AAEO,SAAS,kBAAkB,SAA+B;AAC7D,QAAM,WAAW,qBAAqB;AACtC,MAAI,UAAU;AACV,aAAS,KAAK,iBAAiB;AAAA,EACnC,OAAO;AACH,sBAAkB;AAAA,EACtB;AACJ;AAGA,IAAI,kBAAkC;AAGtC,0BAA0B,CAAC,aAAa;AACpC,MAAI,oBAAoB,UAAU;AAC9B,aAAS,KAAK,iBAAiB;AAAA,EACnC;AACJ,CAAC;AAGM,SAAS,cAAc,KAAqB;AAC/C,QAAM,WAAW,qBAAqB;AACtC,QAAM,UAAU,WAAW,SAAS,KAAK,iBAAiB;AAC1D,SAAO,QAAQ,OAAO,GAAG;AAC7B;AAGO,SAAS,sBAA4B;AACxC,QAAM,WAAW,qBAAqB;AACtC,MAAI,UAAU;AACV,aAAS,KAAK,iBAAiB;AAAA,EACnC;AACA,oBAAkB;AACtB;","names":[]}
@@ -1,146 +0,0 @@
1
- import {
2
- getTelemetryAdapter
3
- } from "./chunk-S6RPCN5H.js";
4
- import {
5
- registerFallbackMigration
6
- } from "./chunk-RUCXSQEY.js";
7
- import {
8
- logError
9
- } from "./chunk-KX32MU3I.js";
10
- import {
11
- devThrow,
12
- devWarn,
13
- tryGetSpringInstance
14
- } from "./chunk-EFUBAQCV.js";
15
-
16
- // src/events/event-bus.ts
17
- function getListeners() {
18
- const instance = tryGetSpringInstance();
19
- if (instance) return instance.core.eventListeners;
20
- return fallbackListeners;
21
- }
22
- var fallbackListeners = /* @__PURE__ */ new Map();
23
- registerFallbackMigration((instance) => {
24
- if (fallbackListeners.size === 0) return;
25
- const target = instance.core.eventListeners;
26
- for (const [event, entries] of fallbackListeners) {
27
- if (entries.length === 0) continue;
28
- const existing = target.get(event);
29
- if (!existing) {
30
- target.set(event, [...entries]);
31
- } else {
32
- for (const entry of entries) {
33
- if (!existing.includes(entry)) {
34
- existing.push(entry);
35
- }
36
- }
37
- }
38
- }
39
- });
40
- var LEAK_THRESHOLD = 100;
41
- function removeHandlerEntry(listeners, event, entry) {
42
- const entries = listeners.get(event);
43
- if (!entries) return;
44
- const idx = entries.indexOf(entry);
45
- if (idx !== -1) entries.splice(idx, 1);
46
- }
47
- function addHandler(event, handler, once2) {
48
- if (typeof handler !== "function") {
49
- devThrow("EventBus", `on("${event}"): handler must be a function`);
50
- return () => {
51
- };
52
- }
53
- const listeners = getListeners();
54
- let entries = listeners.get(event);
55
- if (!entries) {
56
- entries = [];
57
- listeners.set(event, entries);
58
- }
59
- if (entries.length >= LEAK_THRESHOLD) {
60
- devWarn("EventBus", `Event "${event}" has ${entries.length}+ listeners \u2014 possible memory leak`);
61
- }
62
- const entry = { handler, once: once2 };
63
- entries.push(entry);
64
- return () => {
65
- removeHandlerEntry(listeners, event, entry);
66
- if (listeners !== fallbackListeners) {
67
- removeHandlerEntry(fallbackListeners, event, entry);
68
- }
69
- const instance = tryGetSpringInstance();
70
- if (instance) {
71
- removeHandlerEntry(instance.core.eventListeners, event, entry);
72
- }
73
- };
74
- }
75
- function on(event, handler) {
76
- return addHandler(event, handler, false);
77
- }
78
- function once(event, handler) {
79
- return addHandler(event, handler, true);
80
- }
81
- function emit(event, ...[payload]) {
82
- const listeners = getListeners();
83
- const entries = listeners.get(event);
84
- if (!entries || entries.length === 0) return;
85
- const snapshot = entries.slice();
86
- for (let i = 0; i < snapshot.length; i++) {
87
- const entry = snapshot[i];
88
- if (!entry) continue;
89
- try {
90
- const result = entry.handler(payload);
91
- if (result && typeof result.catch === "function") {
92
- result.catch((err) => {
93
- logError(`EventBus handler #${i} for "${event}" threw`, err);
94
- getTelemetryAdapter().trackError(err, { source: "EventBus", event });
95
- });
96
- }
97
- } catch (err) {
98
- logError(`EventBus handler #${i} for "${event}" threw`, err);
99
- getTelemetryAdapter().trackError(err, { source: "EventBus", event });
100
- }
101
- if (entry.once) {
102
- const liveIdx = entries.indexOf(entry);
103
- if (liveIdx !== -1) entries.splice(liveIdx, 1);
104
- }
105
- }
106
- }
107
- async function emitAsync(event, ...[payload]) {
108
- const listeners = getListeners();
109
- const entries = listeners.get(event);
110
- if (!entries || entries.length === 0) return;
111
- const snapshot = entries.slice();
112
- for (let i = 0; i < snapshot.length; i++) {
113
- const entry = snapshot[i];
114
- if (!entry) continue;
115
- try {
116
- await entry.handler(payload);
117
- } catch (err) {
118
- logError(`EventBus async handler #${i} for "${event}" threw`, err);
119
- getTelemetryAdapter().trackError(err, { source: "EventBus", event });
120
- }
121
- if (entry.once) {
122
- const liveIdx = entries.indexOf(entry);
123
- if (liveIdx !== -1) entries.splice(liveIdx, 1);
124
- }
125
- }
126
- }
127
- function clear() {
128
- const listeners = getListeners();
129
- listeners.clear();
130
- if (listeners !== fallbackListeners) {
131
- fallbackListeners.clear();
132
- }
133
- }
134
- function clearAll() {
135
- const instance = tryGetSpringInstance();
136
- if (instance) {
137
- instance.core.eventListeners.clear();
138
- }
139
- fallbackListeners.clear();
140
- }
141
- var eventBus = { on, once, emit, emitAsync, clear, clearAll };
142
-
143
- export {
144
- eventBus
145
- };
146
- //# sourceMappingURL=chunk-OSSX443T.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/events/event-bus.ts"],"sourcesContent":["/**\n * Typed event bus for framework-wide communication.\n * Handlers that throw are caught and logged — they never block other handlers.\n * @module event-bus\n */\n\nimport { getTelemetryAdapter } from \"../adapters/telemetry-adapter\";\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\nimport type { HandlerEntry } from \"../instance/spring-instance\";\nimport { logError } from \"../logger/logger\";\nimport { devThrow, devWarn } from \"../utils/dev-warnings\";\nimport type { FrameworkEventMap } from \"./event-types\";\n\ntype EventHandler<T> = (payload: T) => void | Promise<void>;\n\nfunction getListeners(): Map<string, HandlerEntry[]> {\n const instance = tryGetSpringInstance();\n if (instance) return instance.core.eventListeners;\n // Fallback for code that runs before SpringProvider mounts\n return fallbackListeners;\n}\n\nconst fallbackListeners = new Map<string, HandlerEntry[]>();\n\n// Migrate fallback event listeners to SpringInstance when SpringProvider mounts.\n// Listeners added before the instance exists would otherwise be silently lost.\nregisterFallbackMigration((instance) => {\n if (fallbackListeners.size === 0) return;\n\n const target = instance.core.eventListeners;\n for (const [event, entries] of fallbackListeners) {\n if (entries.length === 0) continue;\n const existing = target.get(event);\n if (!existing) {\n // No listeners on the instance yet for this event — move them all\n target.set(event, [...entries]);\n } else {\n // Merge: only add entries not already present on the target\n for (const entry of entries) {\n if (!existing.includes(entry)) {\n existing.push(entry);\n }\n }\n }\n }\n});\n\nconst LEAK_THRESHOLD = 100;\n\nfunction removeHandlerEntry(listeners: Map<string, HandlerEntry[]>, event: string, entry: HandlerEntry): void {\n const entries = listeners.get(event);\n if (!entries) return;\n const idx = entries.indexOf(entry);\n if (idx !== -1) entries.splice(idx, 1);\n}\n\nfunction addHandler(event: string, handler: EventHandler<unknown>, once: boolean): () => void {\n if (typeof handler !== \"function\") {\n devThrow(\"EventBus\", `on(\"${event}\"): handler must be a function`);\n return () => {};\n }\n\n const listeners = getListeners();\n let entries = listeners.get(event);\n if (!entries) {\n entries = [];\n listeners.set(event, entries);\n }\n if (entries.length >= LEAK_THRESHOLD) {\n devWarn(\"EventBus\", `Event \"${event}\" has ${entries.length}+ listeners — possible memory leak`);\n }\n\n const entry: HandlerEntry = { handler, once };\n entries.push(entry);\n\n return () => {\n removeHandlerEntry(listeners, event, entry);\n if (listeners !== fallbackListeners) {\n removeHandlerEntry(fallbackListeners, event, entry);\n }\n const instance = tryGetSpringInstance();\n if (instance) {\n removeHandlerEntry(instance.core.eventListeners, event, entry);\n }\n };\n}\n\n/**\n * Register a handler for an event. Returns an unsubscribe function.\n *\n * @param event - Event name from FrameworkEventMap (e.g. \"auth:logout\", \"form:saved\")\n * @param handler - Callback invoked with the event payload; may be sync or async\n * @returns An unsubscribe function that removes this handler.\n */\nfunction on<K extends keyof FrameworkEventMap>(event: K, handler: EventHandler<FrameworkEventMap[K]>): () => void {\n return addHandler(event as string, handler as EventHandler<unknown>, false);\n}\n\n/**\n * Register a one-time handler. Automatically removed after the first call.\n *\n * @param event - Event name from FrameworkEventMap\n * @param handler - Callback invoked once with the event payload, then auto-removed\n * @returns An unsubscribe function that removes this handler before it fires.\n */\nfunction once<K extends keyof FrameworkEventMap>(event: K, handler: EventHandler<FrameworkEventMap[K]>): () => void {\n return addHandler(event as string, handler as EventHandler<unknown>, true);\n}\n\n/**\n * Emit an event synchronously. Handlers are called in registration order.\n * Handler errors are caught and logged but do not stop other handlers.\n *\n * @param event - Event name to emit\n * @param payload - Event payload matching the type defined in FrameworkEventMap (omit for void events)\n */\nfunction emit<K extends keyof FrameworkEventMap>(\n event: K,\n ...[payload]: FrameworkEventMap[K] extends void ? [undefined?] : [FrameworkEventMap[K]]\n): void {\n const listeners = getListeners();\n const entries = listeners.get(event as string);\n if (!entries || entries.length === 0) return;\n\n // Snapshot so that unsubscribes during iteration don't skip handlers\n const snapshot = entries.slice();\n\n for (let i = 0; i < snapshot.length; i++) {\n const entry = snapshot[i];\n if (!entry) continue;\n try {\n const result = entry.handler(payload);\n // Catch rejections from async handlers passed to synchronous emit()\n if (result && typeof (result as Promise<void>).catch === \"function\") {\n (result as Promise<void>).catch((err) => {\n logError(`EventBus handler #${i} for \"${event as string}\" threw`, err);\n getTelemetryAdapter().trackError(err, { source: \"EventBus\", event: event as string });\n });\n }\n } catch (err) {\n logError(`EventBus handler #${i} for \"${event as string}\" threw`, err);\n getTelemetryAdapter().trackError(err, { source: \"EventBus\", event: event as string });\n }\n if (entry.once) {\n const liveIdx = entries.indexOf(entry);\n if (liveIdx !== -1) entries.splice(liveIdx, 1);\n }\n }\n}\n\n/**\n * Emit an event and await all handlers (including async ones).\n * Handler errors are caught and logged but do not stop other handlers.\n *\n * @param event - Event name to emit\n * @param payload - Event payload matching the type defined in FrameworkEventMap (omit for void events)\n * @returns Resolves when all handlers have completed.\n */\nasync function emitAsync<K extends keyof FrameworkEventMap>(\n event: K,\n ...[payload]: FrameworkEventMap[K] extends void ? [undefined?] : [FrameworkEventMap[K]]\n): Promise<void> {\n const listeners = getListeners();\n const entries = listeners.get(event as string);\n if (!entries || entries.length === 0) return;\n\n // Snapshot so that unsubscribes during iteration don't skip handlers\n const snapshot = entries.slice();\n\n for (let i = 0; i < snapshot.length; i++) {\n const entry = snapshot[i];\n if (!entry) continue;\n try {\n await entry.handler(payload);\n } catch (err) {\n logError(`EventBus async handler #${i} for \"${event as string}\" threw`, err);\n getTelemetryAdapter().trackError(err, { source: \"EventBus\", event: event as string });\n }\n if (entry.once) {\n const liveIdx = entries.indexOf(entry);\n if (liveIdx !== -1) entries.splice(liveIdx, 1);\n }\n }\n}\n\n/**\n * Remove all handlers for all events on both listener maps\n * (active instance map and fallback map).\n */\nfunction clear(): void {\n const listeners = getListeners();\n listeners.clear();\n if (listeners !== fallbackListeners) {\n fallbackListeners.clear();\n }\n}\n\n/**\n * Remove all event listeners from both the SpringInstance (if active)\n * and the fallback listener map. Useful for full teardown in tests\n * or when disposing the entire framework.\n */\nfunction clearAll(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.core.eventListeners.clear();\n }\n fallbackListeners.clear();\n}\n\n/** Singleton event bus facade — delegates to the current SpringInstance's event listeners */\nexport const eventBus = { on, once, emit, emitAsync, clear, clearAll };\n"],"mappings":"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","names":["once"]}