@spring-systems/core 0.8.6 → 0.8.9

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 (97) hide show
  1. package/dist/adapters/index.js +1 -56
  2. package/dist/auth/index.js +1 -19
  3. package/dist/chunk-3OMNT22N.js +1 -0
  4. package/dist/chunk-4KRUU6MS.js +1 -0
  5. package/dist/chunk-6J2VFOKL.js +1 -0
  6. package/dist/chunk-7P4BJDQR.js +1 -0
  7. package/dist/chunk-AMXSATFF.js +1 -0
  8. package/dist/chunk-BMIRKMVX.js +1 -0
  9. package/dist/chunk-EVDFSWPU.js +1 -0
  10. package/dist/chunk-F3VXVDPQ.js +1 -0
  11. package/dist/chunk-GSQE2NEY.js +1 -0
  12. package/dist/chunk-HUASNNWD.js +1 -0
  13. package/dist/chunk-ICKHSEIX.js +1 -0
  14. package/dist/chunk-JRHMAY5G.js +1 -0
  15. package/dist/chunk-MNLYYTGZ.js +7 -0
  16. package/dist/chunk-OOVZTF74.js +1 -0
  17. package/dist/chunk-PNDXLNCU.js +1 -0
  18. package/dist/chunk-R3XYEEGR.js +1 -0
  19. package/dist/chunk-RKLYBW3O.js +1 -0
  20. package/dist/chunk-RVQHSQYF.js +3 -0
  21. package/dist/chunk-UT6X6RQM.js +1 -0
  22. package/dist/chunk-Y6DB43IE.js +3 -0
  23. package/dist/chunk-YMSSF2ZU.js +1 -0
  24. package/dist/config/index.js +1 -109
  25. package/dist/devtools/index.js +1 -67
  26. package/dist/errors/index.js +1 -21
  27. package/dist/events/index.js +1 -12
  28. package/dist/i18n/index.js +1 -7
  29. package/dist/index.js +1 -42
  30. package/dist/instance/index.js +1 -37
  31. package/dist/logger/index.js +1 -27
  32. package/dist/middleware/index.js +1 -23
  33. package/dist/plugins/index.js +1 -16
  34. package/dist/testing/index.js +1 -171
  35. package/dist/types/index.js +1 -72
  36. package/dist/utils/index.d.ts +43 -1
  37. package/dist/utils/index.js +1 -772
  38. package/dist/validation/index.js +1 -147
  39. package/package.json +1 -1
  40. package/dist/adapters/index.js.map +0 -1
  41. package/dist/auth/index.js.map +0 -1
  42. package/dist/chunk-2PJWFA5S.js +0 -393
  43. package/dist/chunk-2PJWFA5S.js.map +0 -1
  44. package/dist/chunk-EFUBAQCV.js +0 -94
  45. package/dist/chunk-EFUBAQCV.js.map +0 -1
  46. package/dist/chunk-F2SIMWZ5.js +0 -173
  47. package/dist/chunk-F2SIMWZ5.js.map +0 -1
  48. package/dist/chunk-F7WUQJH7.js +0 -399
  49. package/dist/chunk-F7WUQJH7.js.map +0 -1
  50. package/dist/chunk-GON7Q32Q.js +0 -176
  51. package/dist/chunk-GON7Q32Q.js.map +0 -1
  52. package/dist/chunk-GXU75LQX.js +0 -182
  53. package/dist/chunk-GXU75LQX.js.map +0 -1
  54. package/dist/chunk-HFELOXDQ.js +0 -110
  55. package/dist/chunk-HFELOXDQ.js.map +0 -1
  56. package/dist/chunk-KX32MU3I.js +0 -190
  57. package/dist/chunk-KX32MU3I.js.map +0 -1
  58. package/dist/chunk-MEWPYTWC.js +0 -284
  59. package/dist/chunk-MEWPYTWC.js.map +0 -1
  60. package/dist/chunk-N2L4TUC4.js +0 -34
  61. package/dist/chunk-N2L4TUC4.js.map +0 -1
  62. package/dist/chunk-NQQIVCLX.js +0 -47
  63. package/dist/chunk-NQQIVCLX.js.map +0 -1
  64. package/dist/chunk-OSSX443T.js +0 -146
  65. package/dist/chunk-OSSX443T.js.map +0 -1
  66. package/dist/chunk-PT4DIYUK.js +0 -78
  67. package/dist/chunk-PT4DIYUK.js.map +0 -1
  68. package/dist/chunk-QAVWXARR.js +0 -51
  69. package/dist/chunk-QAVWXARR.js.map +0 -1
  70. package/dist/chunk-RRWKDFAB.js +0 -143
  71. package/dist/chunk-RRWKDFAB.js.map +0 -1
  72. package/dist/chunk-RUCXSQEY.js +0 -42
  73. package/dist/chunk-RUCXSQEY.js.map +0 -1
  74. package/dist/chunk-S6RPCN5H.js +0 -64
  75. package/dist/chunk-S6RPCN5H.js.map +0 -1
  76. package/dist/chunk-S7MKRNMI.js +0 -153
  77. package/dist/chunk-S7MKRNMI.js.map +0 -1
  78. package/dist/chunk-SQB4F3EF.js +0 -55
  79. package/dist/chunk-SQB4F3EF.js.map +0 -1
  80. package/dist/chunk-UDT2RPX2.js +0 -43
  81. package/dist/chunk-UDT2RPX2.js.map +0 -1
  82. package/dist/chunk-VRMVN2UM.js +0 -17
  83. package/dist/chunk-VRMVN2UM.js.map +0 -1
  84. package/dist/config/index.js.map +0 -1
  85. package/dist/devtools/index.js.map +0 -1
  86. package/dist/errors/index.js.map +0 -1
  87. package/dist/events/index.js.map +0 -1
  88. package/dist/i18n/index.js.map +0 -1
  89. package/dist/index.js.map +0 -1
  90. package/dist/instance/index.js.map +0 -1
  91. package/dist/logger/index.js.map +0 -1
  92. package/dist/middleware/index.js.map +0 -1
  93. package/dist/plugins/index.js.map +0 -1
  94. package/dist/testing/index.js.map +0 -1
  95. package/dist/types/index.js.map +0 -1
  96. package/dist/utils/index.js.map +0 -1
  97. package/dist/validation/index.js.map +0 -1
@@ -1,399 +0,0 @@
1
- import {
2
- registerFallbackMigration
3
- } from "./chunk-RUCXSQEY.js";
4
- import {
5
- __DEV__,
6
- tryGetSpringInstance
7
- } from "./chunk-EFUBAQCV.js";
8
- import {
9
- SpringConfigError
10
- } from "./chunk-PT4DIYUK.js";
11
-
12
- // src/config/framework-config.ts
13
- function deepFreeze(obj) {
14
- Object.freeze(obj);
15
- for (const value of Object.values(obj)) {
16
- if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
17
- deepFreeze(value);
18
- }
19
- }
20
- return obj;
21
- }
22
- var DEFAULT_FRAMEWORK_CONFIG = deepFreeze({
23
- app: {
24
- name: "App",
25
- defaultRoute: "/",
26
- htmlLang: "en",
27
- skipLinkText: "Skip to main content",
28
- supportEmail: "",
29
- logo: { src: "/images/logo.svg", alt: "Logo" }
30
- },
31
- auth: {
32
- sessionCookiePrefix: "app",
33
- publicAuthPaths: ["auth/login", "auth/forgot_password", "auth/change_password"],
34
- sessionExpiredCodes: ["session_expired", "token_expired", "invalid_token"],
35
- loginFormFieldPrefix: "app",
36
- allowInMemoryTokenStorage: false,
37
- loginPath: "auth/login",
38
- logoutPath: "auth/logout",
39
- infoPath: "auth/info",
40
- tokenResponseFields: { accessToken: "access_token", refreshToken: "refresh_token" },
41
- loginUsernameField: "username"
42
- },
43
- proxy: {
44
- corsAllowedHeaders: "Content-Type, Authorization, X-Requested-With, X-hash, Hash",
45
- maxProxyPathLength: 2048,
46
- safeHashPattern: /^[A-Za-z0-9._~-]{1,256}$/,
47
- blockedPathPrefixesInProd: []
48
- },
49
- csp: {
50
- thirdPartyScriptSources: [],
51
- thirdPartyConnectSources: [],
52
- thirdPartyImageSources: [],
53
- thirdPartyFrameSources: []
54
- },
55
- i18n: {
56
- languages: [],
57
- defaultLanguageCode: "en",
58
- numberLocale: "en-US",
59
- dayjsLocale: "en",
60
- dateFormats: {
61
- date: "YYYY-MM-DD",
62
- dateTime: "YYYY-MM-DD HH:mm",
63
- dateTimeSeconds: "YYYY-MM-DD HH:mm:ss",
64
- time: "HH:mm"
65
- }
66
- },
67
- theme: {},
68
- darkTheme: {},
69
- componentTokens: {},
70
- limits: {
71
- maxFileSize: 10 * 1024 * 1024,
72
- autocompleteDebounceMs: 300,
73
- maxOpenedTabs: 10,
74
- signalrIdleTimeoutMs: 6e4,
75
- signalrServerTimeoutMs: 3e4,
76
- signalrKeepAliveIntervalMs: 1e4,
77
- signalrReconnectDelaysMs: [0, 1e3, 2e3, 5e3, 1e4, 15e3],
78
- idleSessionTimeoutMs: 30 * 60 * 1e3
79
- },
80
- api: {
81
- listUrlPattern: "${route}/list",
82
- detailWithMetaPattern: "${route}/${id}",
83
- detailUrlPattern: "${route}/${id}",
84
- nullDateSentinel: "0001-01-01T00:00:00",
85
- timeoutMs: 3e4,
86
- retryMaxAttempts: 2,
87
- retryBaseDelayMs: 1e3,
88
- retryMaxTotalMs: 6e4,
89
- retryableStatusCodes: [502, 503, 429],
90
- defaultPageSize: 20,
91
- defaultThrowOnError: false,
92
- searchGetStrictShape: false
93
- },
94
- navigation: {
95
- items: []
96
- }
97
- });
98
- var fallbackConfig = DEFAULT_FRAMEWORK_CONFIG;
99
- var COOKIE_PREFIX_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
100
- var UNSAFE_MERGE_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
101
- var MAX_REASONABLE_FILE_SIZE = 500 * 1024 * 1024;
102
- function validateStringArrayField(value, fieldPath, errors) {
103
- if (!Array.isArray(value)) {
104
- errors.push(`${fieldPath}: must be an array of strings`);
105
- return;
106
- }
107
- for (let i = 0; i < value.length; i += 1) {
108
- const item = value[i];
109
- if (typeof item !== "string" || item.trim().length === 0) {
110
- errors.push(`${fieldPath}[${i}]: must be a non-empty string`);
111
- }
112
- }
113
- }
114
- function validateFrameworkConfig(cfg) {
115
- const errors = [];
116
- const warnings = [];
117
- const { i18n, auth, limits, app, proxy, csp } = cfg;
118
- if (typeof app !== "object" || app === null) {
119
- errors.push("app: must be an object");
120
- } else {
121
- if (!app.name || typeof app.name !== "string" || app.name.trim().length === 0) {
122
- errors.push("app.name: must be a non-empty string");
123
- }
124
- if (typeof app.defaultRoute !== "string") {
125
- errors.push("app.defaultRoute: must be a string");
126
- }
127
- }
128
- if (typeof auth !== "object" || auth === null) {
129
- errors.push("auth: must be an object");
130
- } else {
131
- if (!COOKIE_PREFIX_PATTERN.test(auth.sessionCookiePrefix)) {
132
- errors.push(
133
- `auth.sessionCookiePrefix: "${auth.sessionCookiePrefix}" is invalid \u2014 expected pattern [a-zA-Z][a-zA-Z0-9_-]*`
134
- );
135
- }
136
- if (!COOKIE_PREFIX_PATTERN.test(auth.loginFormFieldPrefix)) {
137
- errors.push(
138
- `auth.loginFormFieldPrefix: "${auth.loginFormFieldPrefix}" is invalid`
139
- );
140
- }
141
- validateStringArrayField(auth.publicAuthPaths, "auth.publicAuthPaths", errors);
142
- validateStringArrayField(auth.sessionExpiredCodes, "auth.sessionExpiredCodes", errors);
143
- if (auth.allowInMemoryTokenStorage !== void 0 && typeof auth.allowInMemoryTokenStorage !== "boolean") {
144
- errors.push("auth.allowInMemoryTokenStorage: must be a boolean");
145
- }
146
- }
147
- if (typeof i18n !== "object" || i18n === null) {
148
- errors.push("i18n: must be an object");
149
- } else {
150
- let hasLanguageEntryErrors = false;
151
- if (!Array.isArray(i18n.languages)) {
152
- errors.push("i18n.languages: must be an array");
153
- } else {
154
- if (i18n.languages.length === 0) {
155
- warnings.push("i18n.languages: empty \u2014 framework requires at least one language");
156
- }
157
- for (let i = 0; i < i18n.languages.length; i += 1) {
158
- const language = i18n.languages[i];
159
- if (typeof language !== "object" || language === null) {
160
- errors.push(`i18n.languages[${i}]: must be an object`);
161
- hasLanguageEntryErrors = true;
162
- continue;
163
- }
164
- const entry = language;
165
- if (typeof entry.id_public !== "string" || entry.id_public.trim().length === 0) {
166
- errors.push(`i18n.languages[${i}].id_public: must be a non-empty string`);
167
- hasLanguageEntryErrors = true;
168
- }
169
- if (typeof entry.name !== "string" || entry.name.trim().length === 0) {
170
- errors.push(`i18n.languages[${i}].name: must be a non-empty string`);
171
- hasLanguageEntryErrors = true;
172
- }
173
- if (entry.code !== void 0) {
174
- if (typeof entry.code !== "string" || entry.code.trim().length === 0) {
175
- errors.push(`i18n.languages[${i}].code: must be a non-empty string when provided`);
176
- hasLanguageEntryErrors = true;
177
- }
178
- }
179
- }
180
- if (!hasLanguageEntryErrors && i18n.languages.length > 0 && !i18n.languages.some(
181
- (l) => typeof l?.code === "string" && l.code === i18n.defaultLanguageCode
182
- )) {
183
- warnings.push(
184
- `i18n.defaultLanguageCode: "${i18n.defaultLanguageCode}" not in languages list`
185
- );
186
- }
187
- }
188
- if (typeof i18n.dateFormats !== "object" || i18n.dateFormats === null || Array.isArray(i18n.dateFormats)) {
189
- errors.push("i18n.dateFormats: must be an object with non-empty string values");
190
- } else {
191
- for (const [key, value] of Object.entries(i18n.dateFormats)) {
192
- if (!value || typeof value !== "string" || value.trim().length === 0) {
193
- errors.push(`i18n.dateFormats.${key}: must be a non-empty string`);
194
- }
195
- }
196
- }
197
- }
198
- if (typeof limits !== "object" || limits === null) {
199
- errors.push("limits: must be an object");
200
- } else {
201
- if (typeof limits.maxFileSize !== "number" || limits.maxFileSize <= 0 || limits.maxFileSize > MAX_REASONABLE_FILE_SIZE) {
202
- errors.push(`limits.maxFileSize: must be > 0 and <= 500MB, got ${limits.maxFileSize}`);
203
- }
204
- if (typeof limits.autocompleteDebounceMs !== "number" || limits.autocompleteDebounceMs < 0 || limits.autocompleteDebounceMs > 1e4) {
205
- errors.push(`limits.autocompleteDebounceMs: must be 0\u201310000, got ${limits.autocompleteDebounceMs}`);
206
- }
207
- if (limits.maxOpenedTabs !== void 0 && (typeof limits.maxOpenedTabs !== "number" || !Number.isInteger(limits.maxOpenedTabs) || limits.maxOpenedTabs < 1 || limits.maxOpenedTabs > 200)) {
208
- errors.push(`limits.maxOpenedTabs: must be an integer in range 1\u2013200, got ${limits.maxOpenedTabs}`);
209
- }
210
- if (typeof limits.signalrIdleTimeoutMs !== "number" || limits.signalrIdleTimeoutMs < 5e3) {
211
- errors.push(`limits.signalrIdleTimeoutMs: must be >= 5000, got ${limits.signalrIdleTimeoutMs}`);
212
- }
213
- if (typeof limits.signalrServerTimeoutMs !== "number" || limits.signalrServerTimeoutMs < 1e3) {
214
- errors.push(`limits.signalrServerTimeoutMs: must be >= 1000, got ${limits.signalrServerTimeoutMs}`);
215
- }
216
- if (typeof limits.signalrKeepAliveIntervalMs !== "number" || limits.signalrKeepAliveIntervalMs < 1e3) {
217
- errors.push(`limits.signalrKeepAliveIntervalMs: must be >= 1000, got ${limits.signalrKeepAliveIntervalMs}`);
218
- }
219
- if (!Array.isArray(limits.signalrReconnectDelaysMs) || limits.signalrReconnectDelaysMs.length === 0) {
220
- errors.push("limits.signalrReconnectDelaysMs: must be a non-empty array of numbers");
221
- }
222
- if (typeof limits.idleSessionTimeoutMs !== "number" || limits.idleSessionTimeoutMs < 6e4) {
223
- errors.push(`limits.idleSessionTimeoutMs: must be >= 60000 (1 minute), got ${limits.idleSessionTimeoutMs}`);
224
- }
225
- }
226
- if (typeof proxy !== "object" || proxy === null) {
227
- errors.push("proxy: must be an object");
228
- } else {
229
- if (typeof proxy.maxProxyPathLength !== "number" || proxy.maxProxyPathLength <= 0 || proxy.maxProxyPathLength > 65536) {
230
- errors.push(`proxy.maxProxyPathLength: must be 1\u201365536, got ${proxy.maxProxyPathLength}`);
231
- }
232
- }
233
- if (typeof csp !== "object" || csp === null) {
234
- errors.push("csp: must be an object");
235
- } else {
236
- for (const key of ["thirdPartyScriptSources", "thirdPartyConnectSources", "thirdPartyImageSources", "thirdPartyFrameSources"]) {
237
- validateStringArrayField(csp[key], `csp.${key}`, errors);
238
- if (Array.isArray(csp[key])) {
239
- for (const src of csp[key]) {
240
- if (typeof src === "string" && /[\s;,\r\n]/.test(src)) {
241
- warnings.push(`csp.${key}: "${src}" contains CSP injection characters and will be ignored at runtime`);
242
- }
243
- }
244
- }
245
- }
246
- }
247
- if (cfg.api) {
248
- if (cfg.api.requestAdapter !== void 0 && typeof cfg.api.requestAdapter !== "function") {
249
- errors.push("api.requestAdapter: must be a function");
250
- }
251
- if (cfg.api.defaultThrowOnError !== void 0 && typeof cfg.api.defaultThrowOnError !== "boolean") {
252
- errors.push("api.defaultThrowOnError: must be a boolean");
253
- }
254
- if (cfg.api.searchGetStrictShape !== void 0 && typeof cfg.api.searchGetStrictShape !== "boolean") {
255
- errors.push("api.searchGetStrictShape: must be a boolean");
256
- }
257
- }
258
- return { valid: errors.length === 0, errors, warnings };
259
- }
260
- function deepMergePlain(target, source) {
261
- const t = target;
262
- const s = source;
263
- const result = { ...t };
264
- for (const key of Object.keys(s)) {
265
- if (UNSAFE_MERGE_KEYS.has(key)) {
266
- continue;
267
- }
268
- const sourceVal = s[key];
269
- const targetVal = t[key];
270
- if (sourceVal !== null && sourceVal !== void 0 && typeof sourceVal === "object" && !Array.isArray(sourceVal) && !(sourceVal instanceof RegExp) && typeof targetVal === "object" && targetVal !== null && !Array.isArray(targetVal) && !(targetVal instanceof RegExp)) {
271
- result[key] = deepMergePlain(
272
- targetVal,
273
- sourceVal
274
- );
275
- } else if (sourceVal !== void 0) {
276
- result[key] = sourceVal;
277
- }
278
- }
279
- return result;
280
- }
281
- function cloneFrameworkValue(value) {
282
- if (Array.isArray(value)) {
283
- return value.map((item) => cloneFrameworkValue(item));
284
- }
285
- if (value instanceof RegExp) {
286
- return new RegExp(value.source, value.flags);
287
- }
288
- if (value !== null && typeof value === "object") {
289
- const source = value;
290
- const cloned = {};
291
- for (const [k, v] of Object.entries(source)) {
292
- cloned[k] = cloneFrameworkValue(v);
293
- }
294
- return cloned;
295
- }
296
- return value;
297
- }
298
- function cloneDefaultFrameworkConfig() {
299
- return cloneFrameworkValue(DEFAULT_FRAMEWORK_CONFIG);
300
- }
301
- function createFrameworkConfig(overrides) {
302
- const base = cloneDefaultFrameworkConfig();
303
- if (!overrides) return deepFreeze(base);
304
- const merged = deepMergePlain(base, overrides);
305
- return deepFreeze(merged);
306
- }
307
- function configureFramework(overrides) {
308
- const merged = createFrameworkConfig(overrides);
309
- const result = validateFrameworkConfig(merged);
310
- if (!result.valid) {
311
- throw new SpringConfigError(
312
- `Invalid configuration:
313
- - ${result.errors.join("\n - ")}`
314
- );
315
- }
316
- if (__DEV__ && result.warnings.length > 0) {
317
- for (const w of result.warnings) {
318
- console.warn("[FrameworkConfig] Warning:", w);
319
- }
320
- }
321
- const instance = tryGetSpringInstance();
322
- if (instance) {
323
- instance.core.config = merged;
324
- } else {
325
- fallbackConfig = merged;
326
- }
327
- }
328
- function getFrameworkConfig() {
329
- const instance = tryGetSpringInstance();
330
- return instance ? instance.core.config : fallbackConfig;
331
- }
332
- function clearFrameworkConfig() {
333
- const instance = tryGetSpringInstance();
334
- if (instance) {
335
- instance.core.config = DEFAULT_FRAMEWORK_CONFIG;
336
- }
337
- fallbackConfig = DEFAULT_FRAMEWORK_CONFIG;
338
- }
339
- function getMaxFileSize() {
340
- return getFrameworkConfig().limits.maxFileSize;
341
- }
342
- function getAutocompleteDebounceMs() {
343
- return getFrameworkConfig().limits.autocompleteDebounceMs;
344
- }
345
- function getSignalrIdleTimeoutMs() {
346
- return getFrameworkConfig().limits.signalrIdleTimeoutMs;
347
- }
348
- function getSignalrServerTimeoutMs() {
349
- return getFrameworkConfig().limits.signalrServerTimeoutMs;
350
- }
351
- function getSignalrKeepAliveIntervalMs() {
352
- return getFrameworkConfig().limits.signalrKeepAliveIntervalMs;
353
- }
354
- function getSignalrReconnectDelaysMs() {
355
- return getFrameworkConfig().limits.signalrReconnectDelaysMs;
356
- }
357
- function getIdleSessionTimeoutMs() {
358
- return getFrameworkConfig().limits.idleSessionTimeoutMs;
359
- }
360
- function getApiTimeoutMs() {
361
- return getFrameworkConfig().api?.timeoutMs ?? 3e4;
362
- }
363
- function getApiDefaultPageSize() {
364
- return getFrameworkConfig().api?.defaultPageSize ?? 20;
365
- }
366
- function getSessionCookieName(prefix) {
367
- return `${prefix}_session`;
368
- }
369
- function getSecureSessionCookieName(prefix) {
370
- return `__Host-${prefix}_session`;
371
- }
372
- function applyFallbackConfig(instance) {
373
- if (fallbackConfig !== DEFAULT_FRAMEWORK_CONFIG) {
374
- instance.core.config = fallbackConfig;
375
- }
376
- }
377
- registerFallbackMigration(applyFallbackConfig, 100);
378
-
379
- export {
380
- DEFAULT_FRAMEWORK_CONFIG,
381
- validateFrameworkConfig,
382
- createFrameworkConfig,
383
- configureFramework,
384
- getFrameworkConfig,
385
- clearFrameworkConfig,
386
- getMaxFileSize,
387
- getAutocompleteDebounceMs,
388
- getSignalrIdleTimeoutMs,
389
- getSignalrServerTimeoutMs,
390
- getSignalrKeepAliveIntervalMs,
391
- getSignalrReconnectDelaysMs,
392
- getIdleSessionTimeoutMs,
393
- getApiTimeoutMs,
394
- getApiDefaultPageSize,
395
- getSessionCookieName,
396
- getSecureSessionCookieName,
397
- applyFallbackConfig
398
- };
399
- //# sourceMappingURL=chunk-F7WUQJH7.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/framework-config.ts"],"sourcesContent":["/**\n * Centralized framework configuration.\n * Each project sets its own values via configureFramework().\n * The framework reads from getFrameworkConfig().\n * @module framework-config\n */\n\nimport { SpringConfigError } from \"../errors/errors\";\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\nimport { __DEV__ } from \"../utils/dev-warnings\";\n// Re-export types from the standalone types file (no circular dependency risk)\nexport type { DateFormatConfig, FrameworkConfig, FrameworkConfigOverrides } from \"./framework-config-types\";\nimport type { FrameworkConfig, FrameworkConfigOverrides } from \"./framework-config-types\";\n\n/** Deep-freezes an object at runtime. Returns Readonly<T> (top-level); runtime freeze is deeper than the type reflects. */\nfunction deepFreeze<T extends object>(obj: T): Readonly<T> {\n Object.freeze(obj);\n for (const value of Object.values(obj)) {\n if (value !== null && typeof value === \"object\" && !Object.isFrozen(value)) {\n deepFreeze(value);\n }\n }\n return obj;\n}\n\n/**\n * Default framework configuration. Exported as the single source of truth\n * for both configureFramework() and createSpringInstance().\n * Deep-frozen to prevent accidental mutation of shared defaults.\n */\nexport const DEFAULT_FRAMEWORK_CONFIG: FrameworkConfig = deepFreeze({\n app: {\n name: \"App\",\n defaultRoute: \"/\",\n htmlLang: \"en\",\n skipLinkText: \"Skip to main content\",\n supportEmail: \"\",\n logo: { src: \"/images/logo.svg\", alt: \"Logo\" },\n },\n auth: {\n sessionCookiePrefix: \"app\",\n publicAuthPaths: [\"auth/login\", \"auth/forgot_password\", \"auth/change_password\"],\n sessionExpiredCodes: [\"session_expired\", \"token_expired\", \"invalid_token\"],\n loginFormFieldPrefix: \"app\",\n allowInMemoryTokenStorage: false,\n loginPath: \"auth/login\",\n logoutPath: \"auth/logout\",\n infoPath: \"auth/info\",\n tokenResponseFields: { accessToken: \"access_token\", refreshToken: \"refresh_token\" },\n loginUsernameField: \"username\",\n },\n proxy: {\n corsAllowedHeaders: \"Content-Type, Authorization, X-Requested-With, X-hash, Hash\",\n maxProxyPathLength: 2048,\n safeHashPattern: /^[A-Za-z0-9._~-]{1,256}$/,\n blockedPathPrefixesInProd: [],\n },\n csp: {\n thirdPartyScriptSources: [],\n thirdPartyConnectSources: [],\n thirdPartyImageSources: [],\n thirdPartyFrameSources: [],\n },\n i18n: {\n languages: [],\n defaultLanguageCode: \"en\",\n numberLocale: \"en-US\",\n dayjsLocale: \"en\",\n dateFormats: {\n date: \"YYYY-MM-DD\",\n dateTime: \"YYYY-MM-DD HH:mm\",\n dateTimeSeconds: \"YYYY-MM-DD HH:mm:ss\",\n time: \"HH:mm\",\n },\n },\n theme: {},\n darkTheme: {},\n componentTokens: {},\n limits: {\n maxFileSize: 10 * 1024 * 1024,\n autocompleteDebounceMs: 300,\n maxOpenedTabs: 10,\n signalrIdleTimeoutMs: 60_000,\n signalrServerTimeoutMs: 30_000,\n signalrKeepAliveIntervalMs: 10_000,\n signalrReconnectDelaysMs: [0, 1000, 2000, 5000, 10000, 15000],\n idleSessionTimeoutMs: 30 * 60 * 1000,\n },\n api: {\n listUrlPattern: \"${route}/list\",\n detailWithMetaPattern: \"${route}/${id}\",\n detailUrlPattern: \"${route}/${id}\",\n nullDateSentinel: \"0001-01-01T00:00:00\",\n timeoutMs: 30_000,\n retryMaxAttempts: 2,\n retryBaseDelayMs: 1_000,\n retryMaxTotalMs: 60_000,\n retryableStatusCodes: [502, 503, 429],\n defaultPageSize: 20,\n defaultThrowOnError: false,\n searchGetStrictShape: false,\n },\n navigation: {\n items: [],\n },\n});\n\n// Fallback for code that runs before SpringInstance is created\nlet fallbackConfig: FrameworkConfig = DEFAULT_FRAMEWORK_CONFIG;\n\nconst COOKIE_PREFIX_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/;\nconst UNSAFE_MERGE_KEYS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\n\nconst MAX_REASONABLE_FILE_SIZE = 500 * 1024 * 1024; // 500 MB\n\nexport interface ConfigValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\nfunction validateStringArrayField(\n value: unknown,\n fieldPath: string,\n errors: string[],\n): void {\n if (!Array.isArray(value)) {\n errors.push(`${fieldPath}: must be an array of strings`);\n return;\n }\n\n for (let i = 0; i < value.length; i += 1) {\n const item = value[i];\n if (typeof item !== \"string\" || item.trim().length === 0) {\n errors.push(`${fieldPath}[${i}]: must be a non-empty string`);\n }\n }\n}\n\n/**\n * Validate a framework configuration and return structured results.\n * Also callable standalone for CI/testing: `validateFrameworkConfig(config)`.\n */\nexport function validateFrameworkConfig(cfg: FrameworkConfig): ConfigValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const { i18n, auth, limits, app, proxy, csp } = cfg;\n\n // --- Type guard checks (schema-like validation) ---\n if (typeof app !== \"object\" || app === null) {\n errors.push(\"app: must be an object\");\n } else {\n if (!app.name || typeof app.name !== \"string\" || app.name.trim().length === 0) {\n errors.push(\"app.name: must be a non-empty string\");\n }\n if (typeof app.defaultRoute !== \"string\") {\n errors.push(\"app.defaultRoute: must be a string\");\n }\n }\n\n if (typeof auth !== \"object\" || auth === null) {\n errors.push(\"auth: must be an object\");\n } else {\n if (!COOKIE_PREFIX_PATTERN.test(auth.sessionCookiePrefix)) {\n errors.push(\n `auth.sessionCookiePrefix: \"${auth.sessionCookiePrefix}\" is invalid — expected pattern [a-zA-Z][a-zA-Z0-9_-]*`,\n );\n }\n if (!COOKIE_PREFIX_PATTERN.test(auth.loginFormFieldPrefix)) {\n errors.push(\n `auth.loginFormFieldPrefix: \"${auth.loginFormFieldPrefix}\" is invalid`,\n );\n }\n validateStringArrayField(auth.publicAuthPaths, \"auth.publicAuthPaths\", errors);\n validateStringArrayField(auth.sessionExpiredCodes, \"auth.sessionExpiredCodes\", errors);\n if (\n auth.allowInMemoryTokenStorage !== undefined &&\n typeof auth.allowInMemoryTokenStorage !== \"boolean\"\n ) {\n errors.push(\"auth.allowInMemoryTokenStorage: must be a boolean\");\n }\n }\n\n // --- i18n ---\n if (typeof i18n !== \"object\" || i18n === null) {\n errors.push(\"i18n: must be an object\");\n } else {\n let hasLanguageEntryErrors = false;\n if (!Array.isArray(i18n.languages)) {\n errors.push(\"i18n.languages: must be an array\");\n } else {\n if (i18n.languages.length === 0) {\n warnings.push(\"i18n.languages: empty — framework requires at least one language\");\n }\n for (let i = 0; i < i18n.languages.length; i += 1) {\n const language = i18n.languages[i];\n if (typeof language !== \"object\" || language === null) {\n errors.push(`i18n.languages[${i}]: must be an object`);\n hasLanguageEntryErrors = true;\n continue;\n }\n const entry = language as Record<string, unknown>;\n if (typeof entry.id_public !== \"string\" || entry.id_public.trim().length === 0) {\n errors.push(`i18n.languages[${i}].id_public: must be a non-empty string`);\n hasLanguageEntryErrors = true;\n }\n if (typeof entry.name !== \"string\" || entry.name.trim().length === 0) {\n errors.push(`i18n.languages[${i}].name: must be a non-empty string`);\n hasLanguageEntryErrors = true;\n }\n if (entry.code !== undefined) {\n if (typeof entry.code !== \"string\" || entry.code.trim().length === 0) {\n errors.push(`i18n.languages[${i}].code: must be a non-empty string when provided`);\n hasLanguageEntryErrors = true;\n }\n }\n }\n\n if (\n !hasLanguageEntryErrors &&\n i18n.languages.length > 0 &&\n !i18n.languages.some(\n (l) => typeof l?.code === \"string\" && l.code === i18n.defaultLanguageCode,\n )\n ) {\n warnings.push(\n `i18n.defaultLanguageCode: \"${i18n.defaultLanguageCode}\" not in languages list`,\n );\n }\n }\n if (\n typeof i18n.dateFormats !== \"object\" ||\n i18n.dateFormats === null ||\n Array.isArray(i18n.dateFormats)\n ) {\n errors.push(\"i18n.dateFormats: must be an object with non-empty string values\");\n } else {\n for (const [key, value] of Object.entries(i18n.dateFormats)) {\n if (!value || typeof value !== \"string\" || value.trim().length === 0) {\n errors.push(`i18n.dateFormats.${key}: must be a non-empty string`);\n }\n }\n }\n }\n\n // --- Limits ---\n if (typeof limits !== \"object\" || limits === null) {\n errors.push(\"limits: must be an object\");\n } else {\n if (typeof limits.maxFileSize !== \"number\" || limits.maxFileSize <= 0 || limits.maxFileSize > MAX_REASONABLE_FILE_SIZE) {\n errors.push(`limits.maxFileSize: must be > 0 and <= 500MB, got ${limits.maxFileSize}`);\n }\n if (typeof limits.autocompleteDebounceMs !== \"number\" || limits.autocompleteDebounceMs < 0 || limits.autocompleteDebounceMs > 10000) {\n errors.push(`limits.autocompleteDebounceMs: must be 0–10000, got ${limits.autocompleteDebounceMs}`);\n }\n if (\n limits.maxOpenedTabs !== undefined &&\n (typeof limits.maxOpenedTabs !== \"number\" ||\n !Number.isInteger(limits.maxOpenedTabs) ||\n limits.maxOpenedTabs < 1 ||\n limits.maxOpenedTabs > 200)\n ) {\n errors.push(`limits.maxOpenedTabs: must be an integer in range 1–200, got ${limits.maxOpenedTabs}`);\n }\n if (typeof limits.signalrIdleTimeoutMs !== \"number\" || limits.signalrIdleTimeoutMs < 5000) {\n errors.push(`limits.signalrIdleTimeoutMs: must be >= 5000, got ${limits.signalrIdleTimeoutMs}`);\n }\n if (typeof limits.signalrServerTimeoutMs !== \"number\" || limits.signalrServerTimeoutMs < 1000) {\n errors.push(`limits.signalrServerTimeoutMs: must be >= 1000, got ${limits.signalrServerTimeoutMs}`);\n }\n if (typeof limits.signalrKeepAliveIntervalMs !== \"number\" || limits.signalrKeepAliveIntervalMs < 1000) {\n errors.push(`limits.signalrKeepAliveIntervalMs: must be >= 1000, got ${limits.signalrKeepAliveIntervalMs}`);\n }\n if (!Array.isArray(limits.signalrReconnectDelaysMs) || limits.signalrReconnectDelaysMs.length === 0) {\n errors.push(\"limits.signalrReconnectDelaysMs: must be a non-empty array of numbers\");\n }\n if (typeof limits.idleSessionTimeoutMs !== \"number\" || limits.idleSessionTimeoutMs < 60_000) {\n errors.push(`limits.idleSessionTimeoutMs: must be >= 60000 (1 minute), got ${limits.idleSessionTimeoutMs}`);\n }\n }\n\n // --- Proxy ---\n if (typeof proxy !== \"object\" || proxy === null) {\n errors.push(\"proxy: must be an object\");\n } else {\n if (typeof proxy.maxProxyPathLength !== \"number\" || proxy.maxProxyPathLength <= 0 || proxy.maxProxyPathLength > 65536) {\n errors.push(`proxy.maxProxyPathLength: must be 1–65536, got ${proxy.maxProxyPathLength}`);\n }\n }\n\n // --- CSP ---\n if (typeof csp !== \"object\" || csp === null) {\n errors.push(\"csp: must be an object\");\n } else {\n for (const key of [\"thirdPartyScriptSources\", \"thirdPartyConnectSources\", \"thirdPartyImageSources\", \"thirdPartyFrameSources\"] as const) {\n validateStringArrayField(csp[key], `csp.${key}`, errors);\n if (Array.isArray(csp[key])) {\n for (const src of csp[key]) {\n if (typeof src === \"string\" && /[\\s;,\\r\\n]/.test(src)) {\n warnings.push(`csp.${key}: \"${src}\" contains CSP injection characters and will be ignored at runtime`);\n }\n }\n }\n }\n }\n\n // --- API ---\n if (cfg.api) {\n if (cfg.api.requestAdapter !== undefined && typeof cfg.api.requestAdapter !== \"function\") {\n errors.push(\"api.requestAdapter: must be a function\");\n }\n if (\n cfg.api.defaultThrowOnError !== undefined &&\n typeof cfg.api.defaultThrowOnError !== \"boolean\"\n ) {\n errors.push(\"api.defaultThrowOnError: must be a boolean\");\n }\n if (\n cfg.api.searchGetStrictShape !== undefined &&\n typeof cfg.api.searchGetStrictShape !== \"boolean\"\n ) {\n errors.push(\"api.searchGetStrictShape: must be a boolean\");\n }\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n\n/**\n * Deep merge two plain objects. Arrays and RegExp are replaced, not concatenated.\n * Only merges own enumerable properties. Handles nested objects recursively.\n */\nfunction deepMergePlain(target: object, source: object): object {\n const t = target as Record<string, unknown>;\n const s = source as Record<string, unknown>;\n const result: Record<string, unknown> = { ...t };\n for (const key of Object.keys(s)) {\n if (UNSAFE_MERGE_KEYS.has(key)) {\n continue;\n }\n const sourceVal = s[key];\n const targetVal = t[key];\n if (\n sourceVal !== null &&\n sourceVal !== undefined &&\n typeof sourceVal === \"object\" &&\n !Array.isArray(sourceVal) &&\n !(sourceVal instanceof RegExp) &&\n typeof targetVal === \"object\" &&\n targetVal !== null &&\n !Array.isArray(targetVal) &&\n !(targetVal instanceof RegExp)\n ) {\n result[key] = deepMergePlain(\n targetVal as object,\n sourceVal as object,\n );\n } else if (sourceVal !== undefined) {\n result[key] = sourceVal;\n }\n }\n return result;\n}\n\nfunction cloneFrameworkValue<T>(value: T): T {\n if (Array.isArray(value)) {\n return value.map((item) => cloneFrameworkValue(item)) as T;\n }\n if (value instanceof RegExp) {\n return new RegExp(value.source, value.flags) as T;\n }\n if (value !== null && typeof value === \"object\") {\n const source = value as Record<string, unknown>;\n const cloned: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(source)) {\n cloned[k] = cloneFrameworkValue(v);\n }\n return cloned as T;\n }\n return value;\n}\n\nfunction cloneDefaultFrameworkConfig(): FrameworkConfig {\n return cloneFrameworkValue(DEFAULT_FRAMEWORK_CONFIG);\n}\n\nexport function createFrameworkConfig(overrides?: FrameworkConfigOverrides): FrameworkConfig {\n const base = cloneDefaultFrameworkConfig();\n if (!overrides) return deepFreeze(base) as FrameworkConfig;\n const merged = deepMergePlain(base, overrides) as FrameworkConfig;\n return deepFreeze(merged) as FrameworkConfig;\n}\n\nexport function configureFramework(overrides: FrameworkConfigOverrides): void {\n const merged = createFrameworkConfig(overrides);\n const result = validateFrameworkConfig(merged);\n\n // Critical validation errors always throw — both dev and production.\n // A misconfigured framework is not safe to run (bad cookie prefixes,\n // missing auth paths, etc.). Only warnings are dev-only.\n if (!result.valid) {\n throw new SpringConfigError(\n `Invalid configuration:\\n - ${result.errors.join(\"\\n - \")}`,\n );\n }\n\n // Warnings are surfaced only in dev mode (non-blocking issues)\n if (__DEV__ && result.warnings.length > 0) {\n for (const w of result.warnings) {\n // Using console.warn intentionally — logWarn depends on config, so importing it here would create a circular dependency\n console.warn(\"[FrameworkConfig] Warning:\", w);\n }\n }\n\n // Write to SpringInstance if available, otherwise to fallback\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.core.config = merged;\n } else {\n fallbackConfig = merged;\n }\n}\n\nexport function getFrameworkConfig(): FrameworkConfig {\n const instance = tryGetSpringInstance();\n return instance ? instance.core.config : fallbackConfig;\n}\n\n/**\n * Reset framework config to immutable defaults.\n * Intended for test/integration teardown.\n */\nexport function clearFrameworkConfig(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.core.config = DEFAULT_FRAMEWORK_CONFIG;\n }\n fallbackConfig = DEFAULT_FRAMEWORK_CONFIG;\n}\n\n/** Max file size for upload — reads from framework config limits.maxFileSize */\nexport function getMaxFileSize(): number {\n return getFrameworkConfig().limits.maxFileSize;\n}\n\n/** Debounce delay for autocomplete search — reads from framework config limits.autocompleteDebounceMs */\nexport function getAutocompleteDebounceMs(): number {\n return getFrameworkConfig().limits.autocompleteDebounceMs;\n}\n\n/** Idle timeout for SignalR hub disconnect — reads from framework config limits.signalrIdleTimeoutMs */\nexport function getSignalrIdleTimeoutMs(): number {\n return getFrameworkConfig().limits.signalrIdleTimeoutMs;\n}\n\n/** SignalR server timeout — reads from framework config limits.signalrServerTimeoutMs */\nexport function getSignalrServerTimeoutMs(): number {\n return getFrameworkConfig().limits.signalrServerTimeoutMs;\n}\n\n/** SignalR keep-alive interval — reads from framework config limits.signalrKeepAliveIntervalMs */\nexport function getSignalrKeepAliveIntervalMs(): number {\n return getFrameworkConfig().limits.signalrKeepAliveIntervalMs;\n}\n\n/** SignalR reconnect delay sequence — reads from framework config limits.signalrReconnectDelaysMs */\nexport function getSignalrReconnectDelaysMs(): readonly number[] {\n return getFrameworkConfig().limits.signalrReconnectDelaysMs;\n}\n\n/** Idle session timeout — reads from framework config limits.idleSessionTimeoutMs */\nexport function getIdleSessionTimeoutMs(): number {\n return getFrameworkConfig().limits.idleSessionTimeoutMs;\n}\n\n/** API request timeout — reads from framework config api.timeoutMs */\nexport function getApiTimeoutMs(): number {\n return getFrameworkConfig().api?.timeoutMs ?? 30_000;\n}\n\n/** Default list page size — reads from framework config api.defaultPageSize */\nexport function getApiDefaultPageSize(): number {\n return getFrameworkConfig().api?.defaultPageSize ?? 20;\n}\n\nexport function getSessionCookieName(prefix: string): string {\n return `${prefix}_session`;\n}\n\nexport function getSecureSessionCookieName(prefix: string): string {\n return `__Host-${prefix}_session`;\n}\n\n/**\n * Apply the fallback config to a SpringInstance.\n * Called by SpringProvider after instance creation to pick up early configureFramework() calls.\n */\nexport function applyFallbackConfig(instance: { core: { config: FrameworkConfig } }): void {\n if (fallbackConfig !== DEFAULT_FRAMEWORK_CONFIG) {\n instance.core.config = fallbackConfig;\n }\n}\n\n// Register config migration with high priority so config lands before other migrations.\nregisterFallbackMigration(applyFallbackConfig, 100);\n"],"mappings":"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","names":[]}
@@ -1,176 +0,0 @@
1
- import {
2
- registerFallbackMigration
3
- } from "./chunk-RUCXSQEY.js";
4
- import {
5
- tryGetSpringInstance
6
- } from "./chunk-EFUBAQCV.js";
7
- import {
8
- SpringAdapterError
9
- } from "./chunk-PT4DIYUK.js";
10
-
11
- // src/adapters/http-adapter.ts
12
- var noopAdapter = {
13
- async request() {
14
- throw new SpringAdapterError(
15
- "No HttpAdapter configured. Call setHttpAdapter() before making API requests.",
16
- "HttpAdapter"
17
- );
18
- },
19
- async get() {
20
- throw new SpringAdapterError(
21
- "No HttpAdapter configured. Call setHttpAdapter() before making API requests.",
22
- "HttpAdapter"
23
- );
24
- },
25
- async post() {
26
- throw new SpringAdapterError(
27
- "No HttpAdapter configured. Call setHttpAdapter() before making API requests.",
28
- "HttpAdapter"
29
- );
30
- },
31
- async put() {
32
- throw new SpringAdapterError(
33
- "No HttpAdapter configured. Call setHttpAdapter() before making API requests.",
34
- "HttpAdapter"
35
- );
36
- },
37
- async delete() {
38
- throw new SpringAdapterError(
39
- "No HttpAdapter configured. Call setHttpAdapter() before making API requests.",
40
- "HttpAdapter"
41
- );
42
- }
43
- };
44
- var fallbackAdapter = noopAdapter;
45
- var UI_KEY = /* @__PURE__ */ Symbol.for("spring:httpAdapter");
46
- registerFallbackMigration((instance) => {
47
- if (fallbackAdapter !== noopAdapter) {
48
- instance.ui[UI_KEY] = fallbackAdapter;
49
- }
50
- });
51
- function setHttpAdapter(adapter) {
52
- const instance = tryGetSpringInstance();
53
- if (instance) {
54
- instance.ui[UI_KEY] = adapter;
55
- } else {
56
- fallbackAdapter = adapter;
57
- }
58
- }
59
- function getHttpAdapter() {
60
- const instance = tryGetSpringInstance();
61
- if (instance) {
62
- return instance.ui[UI_KEY] ?? noopAdapter;
63
- }
64
- return fallbackAdapter;
65
- }
66
- function clearHttpAdapter() {
67
- const instance = tryGetSpringInstance();
68
- if (instance) {
69
- delete instance.ui[UI_KEY];
70
- }
71
- fallbackAdapter = noopAdapter;
72
- }
73
-
74
- // src/adapters/license-adapter.ts
75
- var defaultLicenseInfo = {
76
- tier: "community",
77
- features: []
78
- };
79
- var noopAdapter2 = {
80
- async validateLicense() {
81
- return { valid: false, tier: "community", message: "No license adapter configured" };
82
- },
83
- getLicenseInfo() {
84
- return defaultLicenseInfo;
85
- },
86
- isFeatureLicensed() {
87
- return false;
88
- }
89
- };
90
- var fallbackAdapter2 = noopAdapter2;
91
- var UI_KEY2 = /* @__PURE__ */ Symbol.for("spring:licenseAdapter");
92
- registerFallbackMigration((instance) => {
93
- if (fallbackAdapter2 !== noopAdapter2) {
94
- instance.ui[UI_KEY2] = fallbackAdapter2;
95
- }
96
- });
97
- function setLicenseAdapter(adapter) {
98
- const instance = tryGetSpringInstance();
99
- if (instance) {
100
- instance.ui[UI_KEY2] = adapter;
101
- } else {
102
- fallbackAdapter2 = adapter;
103
- }
104
- }
105
- function getLicenseAdapter() {
106
- const instance = tryGetSpringInstance();
107
- if (instance) {
108
- return instance.ui[UI_KEY2] ?? noopAdapter2;
109
- }
110
- return fallbackAdapter2;
111
- }
112
- function clearLicenseAdapter() {
113
- const instance = tryGetSpringInstance();
114
- if (instance) {
115
- delete instance.ui[UI_KEY2];
116
- }
117
- fallbackAdapter2 = noopAdapter2;
118
- }
119
- function validateLicense() {
120
- return getLicenseAdapter().validateLicense();
121
- }
122
- function isFeatureLicensed(feature) {
123
- return getLicenseAdapter().isFeatureLicensed(feature);
124
- }
125
- function getLicenseInfo() {
126
- return getLicenseAdapter().getLicenseInfo();
127
- }
128
-
129
- // src/adapters/notification-adapter.ts
130
- var fallback = {
131
- error: (msg) => console.error("[Notification]", msg),
132
- success: (msg) => console.info("[Notification]", msg),
133
- warning: (msg) => console.warn("[Notification]", msg),
134
- info: (msg) => console.info("[Notification]", msg)
135
- };
136
- var fallbackAdapter3 = fallback;
137
- registerFallbackMigration((instance) => {
138
- if (fallbackAdapter3 !== fallback) {
139
- instance.core.notificationAdapter = fallbackAdapter3;
140
- }
141
- });
142
- function setNotificationAdapter(a) {
143
- const instance = tryGetSpringInstance();
144
- if (instance) {
145
- instance.core.notificationAdapter = a;
146
- } else {
147
- fallbackAdapter3 = a;
148
- }
149
- }
150
- function getNotificationAdapter() {
151
- const instance = tryGetSpringInstance();
152
- return instance ? instance.core.notificationAdapter : fallbackAdapter3;
153
- }
154
- function clearNotificationAdapter() {
155
- const instance = tryGetSpringInstance();
156
- if (instance) {
157
- instance.core.notificationAdapter = fallback;
158
- }
159
- fallbackAdapter3 = fallback;
160
- }
161
-
162
- export {
163
- setHttpAdapter,
164
- getHttpAdapter,
165
- clearHttpAdapter,
166
- setLicenseAdapter,
167
- getLicenseAdapter,
168
- clearLicenseAdapter,
169
- validateLicense,
170
- isFeatureLicensed,
171
- getLicenseInfo,
172
- setNotificationAdapter,
173
- getNotificationAdapter,
174
- clearNotificationAdapter
175
- };
176
- //# sourceMappingURL=chunk-GON7Q32Q.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/http-adapter.ts","../src/adapters/license-adapter.ts","../src/adapters/notification-adapter.ts"],"sourcesContent":["/**\n * HTTP adapter — decouples the framework from any specific HTTP client (axios, fetch, etc.).\n *\n * Consumer applications provide their own HTTP implementation by setting a custom adapter.\n * The framework uses this adapter for all API communication (lists, forms, auth, etc.)\n *\n * @example\n * ```ts\n * import { setHttpAdapter } from \"@spring-systems/core/adapters\";\n *\n * setHttpAdapter({\n * async request(config) {\n * const resp = await fetch(config.url, {\n * method: config.method ?? \"GET\",\n * body: config.data ? JSON.stringify(config.data) : undefined,\n * headers: config.headers,\n * signal: config.signal,\n * });\n * return resp.json();\n * },\n * async get(url, config) {\n * return this.request({ ...config, url, method: \"GET\" });\n * },\n * async post(config) {\n * return this.request({ ...config, method: \"POST\" });\n * },\n * async put(config) {\n * return this.request({ ...config, method: \"PUT\" });\n * },\n * async delete(url, config) {\n * return this.request({ ...config, url, method: \"DELETE\" });\n * },\n * });\n * ```\n *\n * @module http-adapter\n */\n\nimport { SpringAdapterError } from \"../errors/errors\";\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\n\nexport interface HttpRequest {\n url: string;\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n data?: unknown;\n params?: Record<string, string>;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n /** Override the global timeout for this request (e.g. longer timeout for exports/uploads). */\n timeoutMs?: number;\n suppressToast?: boolean;\n suppressRedirect?: boolean;\n}\n\nexport interface HttpAdapter {\n request<TResponse>(config: HttpRequest): Promise<TResponse | undefined>;\n get<TResponse>(url: string, config?: Partial<HttpRequest>): Promise<TResponse | undefined>;\n post<TData, TResponse>(config: HttpRequest & { data: TData }): Promise<TResponse | undefined>;\n put<TData, TResponse>(config: HttpRequest & { data: TData }): Promise<TResponse | undefined>;\n delete<TResponse>(url: string, config?: Partial<HttpRequest>): Promise<TResponse | undefined>;\n}\n\n/**\n * Default adapter — throws at runtime so missing adapter is caught early.\n * Consumer apps must provide a real HTTP adapter before making API calls.\n */\nconst noopAdapter = {\n async request() {\n throw new SpringAdapterError(\n \"No HttpAdapter configured. Call setHttpAdapter() before making API requests.\",\n \"HttpAdapter\",\n );\n },\n async get() {\n throw new SpringAdapterError(\n \"No HttpAdapter configured. Call setHttpAdapter() before making API requests.\",\n \"HttpAdapter\",\n );\n },\n async post() {\n throw new SpringAdapterError(\n \"No HttpAdapter configured. Call setHttpAdapter() before making API requests.\",\n \"HttpAdapter\",\n );\n },\n async put() {\n throw new SpringAdapterError(\n \"No HttpAdapter configured. Call setHttpAdapter() before making API requests.\",\n \"HttpAdapter\",\n );\n },\n async delete() {\n throw new SpringAdapterError(\n \"No HttpAdapter configured. Call setHttpAdapter() before making API requests.\",\n \"HttpAdapter\",\n );\n },\n} satisfies HttpAdapter;\n\nlet fallbackAdapter: HttpAdapter = noopAdapter;\n\nconst UI_KEY = Symbol.for(\"spring:httpAdapter\");\n\n// Migrate fallback HTTP adapter to SpringInstance when SpringProvider mounts\nregisterFallbackMigration((instance) => {\n if (fallbackAdapter !== noopAdapter) {\n instance.ui[UI_KEY] = fallbackAdapter;\n }\n});\n\nexport function setHttpAdapter(adapter: HttpAdapter): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.ui[UI_KEY] = adapter;\n } else {\n fallbackAdapter = adapter;\n }\n}\n\nexport function getHttpAdapter(): HttpAdapter {\n const instance = tryGetSpringInstance();\n if (instance) {\n return (instance.ui[UI_KEY] as HttpAdapter) ?? noopAdapter;\n }\n return fallbackAdapter;\n}\n\n/**\n * Reset the HTTP adapter to the default noop adapter.\n * For testing only.\n */\nexport function clearHttpAdapter(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n delete instance.ui[UI_KEY];\n }\n fallbackAdapter = noopAdapter;\n}\n","/**\n * License adapter — provides a pluggable interface for enterprise license validation.\n *\n * Enterprise clients integrate with their license servers by providing a custom adapter.\n * The framework checks license status at key points (startup, feature gating, etc.)\n *\n * @example\n * ```ts\n * import { setLicenseAdapter } from \"@spring-systems/core/adapters\";\n *\n * setLicenseAdapter({\n * async validateLicense() {\n * const resp = await fetch(\"/api/license\");\n * const data = await resp.json();\n * return { valid: data.active, expiresAt: new Date(data.expiresAt), tier: data.tier };\n * },\n * getLicenseInfo() {\n * return cachedLicenseInfo;\n * },\n * isFeatureLicensed(feature) {\n * return cachedLicenseInfo.features.includes(feature);\n * },\n * });\n * ```\n *\n * @module license-adapter\n */\n\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\n\n/** Result of a license validation call */\nexport interface LicenseValidationResult {\n /** Whether the license is currently valid */\n valid: boolean;\n /** When the license expires (undefined = perpetual) */\n expiresAt?: Date;\n /** License tier identifier (e.g. \"community\", \"professional\", \"enterprise\") */\n tier?: string;\n /** Human-readable message (e.g. \"License expired\", \"Trial period\") */\n message?: string;\n}\n\n/** Cached license info (synchronous access) */\nexport interface LicenseInfo {\n /** License tier (e.g. \"standard\", \"professional\", \"enterprise\") */\n tier: string;\n /** List of licensed feature keys */\n features: string[];\n /** When the license expires */\n expiresAt?: Date;\n}\n\nexport interface LicenseAdapter {\n /**\n * Validate the license asynchronously (e.g. call a license server).\n * Called at application startup and periodically.\n */\n validateLicense(): Promise<LicenseValidationResult>;\n\n /**\n * Get cached license info synchronously.\n * Returns info from the last successful validation.\n */\n getLicenseInfo(): LicenseInfo;\n\n /**\n * Check if a specific feature is licensed.\n * Uses cached license info for synchronous access.\n */\n isFeatureLicensed(feature: string): boolean;\n}\n\nconst defaultLicenseInfo = {\n tier: \"community\",\n features: [],\n} satisfies LicenseInfo;\n\n/**\n * Default adapter — fail-closed: no features licensed, validation returns invalid.\n * Enterprise clients must provide a real adapter to unlock licensed features.\n * This ensures that a missing adapter never accidentally grants access.\n */\nconst noopAdapter = {\n async validateLicense() {\n return { valid: false, tier: \"community\", message: \"No license adapter configured\" };\n },\n getLicenseInfo() {\n return defaultLicenseInfo;\n },\n isFeatureLicensed() {\n return false;\n },\n} satisfies LicenseAdapter;\n\nlet fallbackAdapter: LicenseAdapter = noopAdapter;\n\nconst UI_KEY = Symbol.for(\"spring:licenseAdapter\");\n\n// Migrate fallback license adapter to SpringInstance when SpringProvider mounts\nregisterFallbackMigration((instance) => {\n if (fallbackAdapter !== noopAdapter) {\n instance.ui[UI_KEY] = fallbackAdapter;\n }\n});\n\nexport function setLicenseAdapter(adapter: LicenseAdapter): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.ui[UI_KEY] = adapter;\n } else {\n fallbackAdapter = adapter;\n }\n}\n\nexport function getLicenseAdapter(): LicenseAdapter {\n const instance = tryGetSpringInstance();\n if (instance) {\n return (instance.ui[UI_KEY] as LicenseAdapter) ?? noopAdapter;\n }\n return fallbackAdapter;\n}\n\n/**\n * Reset the license adapter to the default noop (fail-closed) adapter.\n * For testing only.\n */\nexport function clearLicenseAdapter(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n delete instance.ui[UI_KEY];\n }\n fallbackAdapter = noopAdapter;\n}\n\n/**\n * Convenience: validate the license via the configured adapter.\n */\nexport function validateLicense(): Promise<LicenseValidationResult> {\n return getLicenseAdapter().validateLicense();\n}\n\n/**\n * Convenience: check if a feature is licensed.\n */\nexport function isFeatureLicensed(feature: string): boolean {\n return getLicenseAdapter().isFeatureLicensed(feature);\n}\n\n/**\n * Convenience: get cached license info.\n */\nexport function getLicenseInfo(): LicenseInfo {\n return getLicenseAdapter().getLicenseInfo();\n}\n","/**\n * Notification adapter — decouples API/validation layers from the UI notification system (react-toastify).\n * Pattern matches setLogAdapter() in logger.ts.\n * @module notification-adapter\n */\n\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\n\nexport interface NotificationAdapter {\n error(msg: string): void;\n success(msg: string): void;\n warning(msg: string): void;\n info(msg: string): void;\n}\n\nconst fallback = {\n error: (msg) => console.error(\"[Notification]\", msg),\n success: (msg) => console.info(\"[Notification]\", msg),\n warning: (msg) => console.warn(\"[Notification]\", msg),\n info: (msg) => console.info(\"[Notification]\", msg),\n} satisfies NotificationAdapter;\n\nlet fallbackAdapter: NotificationAdapter = fallback;\n\n// Migrate fallback notification adapter to SpringInstance when SpringProvider mounts\nregisterFallbackMigration((instance) => {\n if (fallbackAdapter !== fallback) {\n instance.core.notificationAdapter = fallbackAdapter;\n }\n});\n\nexport function setNotificationAdapter(a: NotificationAdapter): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.core.notificationAdapter = a;\n } else {\n fallbackAdapter = a;\n }\n}\n\nexport function getNotificationAdapter(): NotificationAdapter {\n const instance = tryGetSpringInstance();\n return instance ? instance.core.notificationAdapter : fallbackAdapter;\n}\n\n/** Reset to default notification adapter. For testing/integration teardown only. */\nexport function clearNotificationAdapter(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.core.notificationAdapter = fallback;\n }\n fallbackAdapter = fallback;\n}\n"],"mappings":"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","names":["noopAdapter","fallbackAdapter","UI_KEY","fallbackAdapter"]}