@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,55 +0,0 @@
1
- import {
2
- registerMiddleware
3
- } from "./chunk-MEWPYTWC.js";
4
- import {
5
- logWarn
6
- } from "./chunk-KX32MU3I.js";
7
-
8
- // src/middleware/audit-middleware.ts
9
- async function invokeAuditHandler(handler, event) {
10
- try {
11
- await Promise.resolve(handler(event));
12
- } catch (err) {
13
- logWarn(
14
- "AuditMiddleware",
15
- `Handler error for ${event.action} ${event.entity}#${event.entityId}: ${err instanceof Error ? err.message : String(err)}`
16
- );
17
- }
18
- }
19
- function createAuditMiddleware(handler, options) {
20
- const saveMiddleware = async (ctx, next) => {
21
- await next();
22
- if (ctx.aborted) return;
23
- await invokeAuditHandler(handler, {
24
- action: ctx.isNew ? "create" : "update",
25
- entity: ctx.entity,
26
- entityId: ctx.id,
27
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
28
- url: ctx.url,
29
- fields: ctx.fields
30
- });
31
- };
32
- const deleteMiddleware = async (ctx, next) => {
33
- await next();
34
- if (ctx.aborted) return;
35
- await invokeAuditHandler(handler, {
36
- action: "delete",
37
- entity: ctx.entity,
38
- entityId: ctx.id,
39
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
40
- url: ctx.url,
41
- fields: {}
42
- });
43
- };
44
- const unregisterSave = registerMiddleware("form:afterSave", saveMiddleware, options);
45
- const unregisterDelete = registerMiddleware("form:afterDelete", deleteMiddleware, options);
46
- return () => {
47
- unregisterSave();
48
- unregisterDelete();
49
- };
50
- }
51
-
52
- export {
53
- createAuditMiddleware
54
- };
55
- //# sourceMappingURL=chunk-SQB4F3EF.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/middleware/audit-middleware.ts"],"sourcesContent":["/**\n * Audit middleware — standardized audit event creation for form mutations.\n *\n * Provides a typed `AuditEvent` and factory functions that hook into\n * `form:afterSave` and `form:afterDelete` to produce audit events for every\n * successful create, update, or delete operation.\n *\n * @example\n * ```ts\n * import { createAuditMiddleware } from \"@spring-systems/core/middleware\";\n *\n * // Send audit events to your backend:\n * const unregister = createAuditMiddleware(async (event) => {\n * await fetch(\"/api/audit\", {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify(event),\n * });\n * });\n *\n * // Or log to console during development:\n * createAuditMiddleware((event) => {\n * console.log(`[Audit] ${event.action} ${event.entity}#${event.entityId}`, event);\n * });\n * ```\n *\n * @module audit-middleware\n */\n\nimport { logWarn } from \"../logger/logger\";\nimport type { MiddlewareOptions } from \"./middleware-registry\";\nimport { registerMiddleware } from \"./middleware-registry\";\nimport type { FormDeleteContext, FormSaveContext, MiddlewareFn } from \"./middleware-types\";\n\nexport interface AuditEvent {\n /** Mutation type */\n action: \"create\" | \"update\" | \"delete\";\n /** Entity type name (e.g. \"partner\", \"user\") */\n entity: string;\n /** Entity record identifier */\n entityId: string;\n /** ISO 8601 timestamp of the event */\n timestamp: string;\n /** API endpoint URL used for the operation */\n url: string;\n /** Field values included in the save payload (empty object for deletes) */\n fields: Record<string, unknown>;\n}\n\nexport type AuditEventHandler = (event: AuditEvent) => void | Promise<void>;\n\nasync function invokeAuditHandler(handler: AuditEventHandler, event: AuditEvent): Promise<void> {\n try {\n await Promise.resolve(handler(event));\n } catch (err: unknown) {\n logWarn(\n \"AuditMiddleware\",\n `Handler error for ${event.action} ${event.entity}#${event.entityId}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\n/**\n * Create and register audit middleware that emits `AuditEvent` for every\n * successful form save (create or update) and delete operation.\n *\n * The middleware hooks into both `form:afterSave` and `form:afterDelete` slots.\n * Aborted operations are silently skipped.\n *\n * @param handler - Callback that receives the audit event. Can be sync or async.\n * Async errors are caught and logged to prevent audit failures\n * from breaking the operation flow.\n * @param options - Optional middleware options (e.g. `{ priority: 10 }`)\n * @returns An unregister function that removes both audit middleware registrations.\n */\nexport function createAuditMiddleware(\n handler: AuditEventHandler,\n options?: MiddlewareOptions,\n): () => void {\n const saveMiddleware: MiddlewareFn<FormSaveContext> = async (ctx, next) => {\n await next();\n\n if (ctx.aborted) return;\n\n await invokeAuditHandler(handler, {\n action: ctx.isNew ? \"create\" : \"update\",\n entity: ctx.entity,\n entityId: ctx.id,\n timestamp: new Date().toISOString(),\n url: ctx.url,\n fields: ctx.fields,\n });\n };\n\n const deleteMiddleware: MiddlewareFn<FormDeleteContext> = async (ctx, next) => {\n await next();\n\n if (ctx.aborted) return;\n\n await invokeAuditHandler(handler, {\n action: \"delete\",\n entity: ctx.entity,\n entityId: ctx.id,\n timestamp: new Date().toISOString(),\n url: ctx.url,\n fields: {},\n });\n };\n\n const unregisterSave = registerMiddleware(\"form:afterSave\", saveMiddleware, options);\n const unregisterDelete = registerMiddleware(\"form:afterDelete\", deleteMiddleware, options);\n\n return () => {\n unregisterSave();\n unregisterDelete();\n };\n}\n"],"mappings":";;;;;;;;AAmDA,eAAe,mBAAmB,SAA4B,OAAkC;AAC5F,MAAI;AACA,UAAM,QAAQ,QAAQ,QAAQ,KAAK,CAAC;AAAA,EACxC,SAAS,KAAc;AACnB;AAAA,MACI;AAAA,MACA,qBAAqB,MAAM,MAAM,IAAI,MAAM,MAAM,IAAI,MAAM,QAAQ,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC5H;AAAA,EACJ;AACJ;AAeO,SAAS,sBACZ,SACA,SACU;AACV,QAAM,iBAAgD,OAAO,KAAK,SAAS;AACvE,UAAM,KAAK;AAEX,QAAI,IAAI,QAAS;AAEjB,UAAM,mBAAmB,SAAS;AAAA,MAC9B,QAAQ,IAAI,QAAQ,WAAW;AAAA,MAC/B,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,KAAK,IAAI;AAAA,MACT,QAAQ,IAAI;AAAA,IAChB,CAAC;AAAA,EACL;AAEA,QAAM,mBAAoD,OAAO,KAAK,SAAS;AAC3E,UAAM,KAAK;AAEX,QAAI,IAAI,QAAS;AAEjB,UAAM,mBAAmB,SAAS;AAAA,MAC9B,QAAQ;AAAA,MACR,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,KAAK,IAAI;AAAA,MACT,QAAQ,CAAC;AAAA,IACb,CAAC;AAAA,EACL;AAEA,QAAM,iBAAiB,mBAAmB,kBAAkB,gBAAgB,OAAO;AACnF,QAAM,mBAAmB,mBAAmB,oBAAoB,kBAAkB,OAAO;AAEzF,SAAO,MAAM;AACT,mBAAe;AACf,qBAAiB;AAAA,EACrB;AACJ;","names":[]}
@@ -1,43 +0,0 @@
1
- // src/config/runtime-env-config.ts
2
- var RUNTIME_ENV_KEYS = ["IMAGE_TAG", "ENVIRONMENT", "BUILD_NUM", "BUILD_DATE"];
3
- var extraKeys = [];
4
- function registerRuntimeEnvKeys(...keys) {
5
- for (const key of keys) {
6
- if (!extraKeys.includes(key) && !RUNTIME_ENV_KEYS.includes(key)) {
7
- extraKeys.push(key);
8
- }
9
- }
10
- }
11
- function getRuntimeEnvKeys() {
12
- if (extraKeys.length === 0) return RUNTIME_ENV_KEYS;
13
- return [...RUNTIME_ENV_KEYS, ...extraKeys];
14
- }
15
- function clearRuntimeEnvKeys() {
16
- extraKeys.length = 0;
17
- }
18
- function getEnv() {
19
- if (typeof window === "undefined") {
20
- return {};
21
- }
22
- return window.__RUNTIME_ENV__ ?? {};
23
- }
24
- function getRuntimeVar(key) {
25
- const env = getEnv();
26
- const v = env[key];
27
- return typeof v === "string" ? v : "";
28
- }
29
- function getImageTag() {
30
- const v = getEnv().IMAGE_TAG;
31
- if (!v) return "";
32
- return v;
33
- }
34
-
35
- export {
36
- RUNTIME_ENV_KEYS,
37
- registerRuntimeEnvKeys,
38
- getRuntimeEnvKeys,
39
- clearRuntimeEnvKeys,
40
- getRuntimeVar,
41
- getImageTag
42
- };
43
- //# sourceMappingURL=chunk-UDT2RPX2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/runtime-env-config.ts"],"sourcesContent":["/**\n * Runtime environment variable keys injected on the client.\n * Values are read from `window.__RUNTIME_ENV__`.\n *\n * Consumers can register additional keys via `registerRuntimeEnvKeys()`.\n * @module runtime-env-config\n */\n\n/** Default framework runtime env keys. */\nexport const RUNTIME_ENV_KEYS = [\"IMAGE_TAG\", \"ENVIRONMENT\", \"BUILD_NUM\", \"BUILD_DATE\"] as const;\nexport type RuntimeEnvKey = (typeof RUNTIME_ENV_KEYS)[number];\nexport type RuntimeEnv = Partial<Record<string, string>>;\n\nconst extraKeys: string[] = [];\n\n/**\n * Register additional runtime environment keys.\n * Call this before runtime env payload is consumed by the app bootstrap.\n */\nexport function registerRuntimeEnvKeys(...keys: string[]): void {\n for (const key of keys) {\n if (!extraKeys.includes(key) && !(RUNTIME_ENV_KEYS as readonly string[]).includes(key)) {\n extraKeys.push(key);\n }\n }\n}\n\n/** Returns all registered runtime env keys (defaults + consumer-registered). */\nexport function getRuntimeEnvKeys(): readonly string[] {\n if (extraKeys.length === 0) return RUNTIME_ENV_KEYS;\n return [...RUNTIME_ENV_KEYS, ...extraKeys];\n}\n\n/** Clear consumer-registered runtime env keys. For testing only. */\nexport function clearRuntimeEnvKeys(): void {\n extraKeys.length = 0;\n}\n\ndeclare global {\n interface Window {\n __RUNTIME_ENV__?: RuntimeEnv;\n }\n}\n\nfunction getEnv(): RuntimeEnv {\n if (typeof window === \"undefined\") {\n return {};\n }\n return window.__RUNTIME_ENV__ ?? {};\n}\n\nexport function getRuntimeVar(key: string): string {\n const env = getEnv();\n const v = env[key];\n return typeof v === \"string\" ? v : \"\";\n}\n\nexport function getImageTag(): string {\n const v = getEnv().IMAGE_TAG;\n if (!v) return \"\";\n return v;\n}\n"],"mappings":";AASO,IAAM,mBAAmB,CAAC,aAAa,eAAe,aAAa,YAAY;AAItF,IAAM,YAAsB,CAAC;AAMtB,SAAS,0BAA0B,MAAsB;AAC5D,aAAW,OAAO,MAAM;AACpB,QAAI,CAAC,UAAU,SAAS,GAAG,KAAK,CAAE,iBAAuC,SAAS,GAAG,GAAG;AACpF,gBAAU,KAAK,GAAG;AAAA,IACtB;AAAA,EACJ;AACJ;AAGO,SAAS,oBAAuC;AACnD,MAAI,UAAU,WAAW,EAAG,QAAO;AACnC,SAAO,CAAC,GAAG,kBAAkB,GAAG,SAAS;AAC7C;AAGO,SAAS,sBAA4B;AACxC,YAAU,SAAS;AACvB;AAQA,SAAS,SAAqB;AAC1B,MAAI,OAAO,WAAW,aAAa;AAC/B,WAAO,CAAC;AAAA,EACZ;AACA,SAAO,OAAO,mBAAmB,CAAC;AACtC;AAEO,SAAS,cAAc,KAAqB;AAC/C,QAAM,MAAM,OAAO;AACnB,QAAM,IAAI,IAAI,GAAG;AACjB,SAAO,OAAO,MAAM,WAAW,IAAI;AACvC;AAEO,SAAS,cAAsB;AAClC,QAAM,IAAI,OAAO,EAAE;AACnB,MAAI,CAAC,EAAG,QAAO;AACf,SAAO;AACX;","names":[]}
@@ -1,17 +0,0 @@
1
- // src/config/constants.ts
2
- var emptyGuid = "00000000-0000-0000-0000-000000000000";
3
- var DIALOG_CONTENT_SELECTOR = ".spring-dialog-content";
4
- var DND_TOUCH_CONSTRAINT = { delay: 200, tolerance: 5 };
5
- var STORAGE_KEYS = {
6
- LANGUAGE: "language",
7
- COLOR_THEME: "colorTheme",
8
- DARK_MODE: "darkMode"
9
- };
10
-
11
- export {
12
- emptyGuid,
13
- DIALOG_CONTENT_SELECTOR,
14
- DND_TOUCH_CONSTRAINT,
15
- STORAGE_KEYS
16
- };
17
- //# sourceMappingURL=chunk-VRMVN2UM.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/constants.ts"],"sourcesContent":["/** Empty GUID for new records */\nexport const emptyGuid = \"00000000-0000-0000-0000-000000000000\";\n\n/** Generic interface for select options */\nexport interface CodeList {\n id_public: string;\n name: string;\n code?: string;\n version?: number;\n}\n\n/** Interface for persons (full_name) */\nexport interface CodeListFullName {\n id_public: string;\n full_name: string;\n first_name: string;\n last_name?: string;\n}\n\nexport interface CodeListNumber {\n id_public: number;\n name: string;\n}\n\nexport type Operator = \"=\" | \">\" | \">=\" | \"<\" | \"<=\" | \"!=\" | \"in\" | \"between\";\n\n/** CSS selector for an open dialog (detection in shortcut hooks) */\nexport const DIALOG_CONTENT_SELECTOR = \".spring-dialog-content\";\n\n/** DnD TouchSensor activation constraint (delay + tolerance) */\nexport const DND_TOUCH_CONSTRAINT = { delay: 200, tolerance: 5 } as const;\n\nexport const STORAGE_KEYS = {\n LANGUAGE: \"language\",\n COLOR_THEME: \"colorTheme\",\n DARK_MODE: \"darkMode\",\n} as const;\n\n/** Union type of all storage key values. */\nexport type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS];\n"],"mappings":";AACO,IAAM,YAAY;AA0BlB,IAAM,0BAA0B;AAGhC,IAAM,uBAAuB,EAAE,OAAO,KAAK,WAAW,EAAE;AAExD,IAAM,eAAe;AAAA,EACxB,UAAU;AAAA,EACV,aAAa;AAAA,EACb,WAAW;AACf;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/devtools/inspect.ts"],"sourcesContent":["/**\n * Lightweight dev-mode introspection utility for SpringInstance.\n * Zero production cost — all functions are no-ops when `__DEV__` is false.\n *\n * Usage in browser console: `window.__SPRING_INSPECT__()`\n *\n * @module devtools/inspect\n */\n\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport type { SpringInstance } from \"../instance/spring-instance\";\nimport { __DEV__ } from \"../utils/dev-warnings\";\n\ninterface InspectResult {\n id: string;\n state: string;\n config: {\n appName: string;\n defaultRoute: string;\n apiTimeoutMs: number | undefined;\n languages: number;\n };\n plugins: ReadonlyArray<{ name: string; version?: string }>;\n capabilities: Record<string, unknown>;\n middleware: string[];\n slots: string[];\n fieldTypes: string[];\n columnTypes: string[];\n validators: string[];\n adapters: {\n route: boolean;\n ui: boolean;\n http: boolean;\n telemetry: boolean;\n };\n auth: {\n authenticated: boolean;\n hasToken: boolean;\n };\n}\n\nfunction collectRegistryKeys(instance: SpringInstance, uiKey: symbol): string[] {\n const registry = instance.ui[uiKey];\n if (registry instanceof Map) return Array.from(registry.keys()) as string[];\n return [];\n}\n\n/**\n * Inspect the current SpringInstance state. Returns a structured summary\n * of all framework registrations, adapters, and configuration.\n *\n * Only works in dev mode — returns `undefined` in production.\n */\nexport function inspectInstance(instance?: SpringInstance): InspectResult | undefined {\n if (!__DEV__) return undefined;\n\n const inst = instance ?? tryGetSpringInstance();\n if (!inst) {\n console.warn(\"[SPRING DevTools] No SpringInstance found. Is SpringProvider mounted?\");\n return undefined;\n }\n\n const config = inst.core.config;\n const loadedPlugins = (inst.ui[Symbol.for(\"spring:loadedPlugins\")] ?? []) as ReadonlyArray<{ name: string; version?: string }>;\n const capabilities = (inst.ui[Symbol.for(\"spring:capabilities\")] ?? {}) as Record<string, unknown>;\n\n const middlewareSlots = Array.from(inst.core.middlewareRegistry.entries())\n .filter(([, list]) => list.length > 0)\n .map(([slot, list]) => `${slot} (${list.length})`);\n\n const result: InspectResult = {\n id: inst.id,\n state: inst.state,\n config: {\n appName: config.app.name,\n defaultRoute: config.app.defaultRoute,\n apiTimeoutMs: config.api?.timeoutMs,\n languages: config.i18n.languages.length,\n },\n plugins: loadedPlugins,\n capabilities,\n middleware: middlewareSlots,\n slots: collectRegistryKeys(inst, Symbol.for(\"spring:slotRegistry\")),\n fieldTypes: collectRegistryKeys(inst, Symbol.for(\"spring:fieldRendererRegistry\")),\n columnTypes: collectRegistryKeys(inst, Symbol.for(\"spring:columnRendererRegistry\")),\n validators: Array.from(inst.core.validatorRegistry.keys()),\n adapters: {\n route: !!inst.ui[Symbol.for(\"spring:routeAdapter\")],\n ui: !!inst.ui[Symbol.for(\"spring:uiAdapter\")],\n http: !!inst.ui[Symbol.for(\"spring:httpAdapter\")],\n telemetry: !!inst.ui[Symbol.for(\"spring:telemetryAdapter\")],\n },\n auth: {\n authenticated: inst.core.authenticated,\n hasToken: !!inst.api.authToken,\n },\n };\n\n console.info(`SPRING Instance: ${inst.id} [${inst.state}]`);\n console.info(\"App:\", config.app.name);\n console.info(\"Plugins:\", loadedPlugins.length > 0 ? loadedPlugins : \"(none)\");\n console.info(\"Middleware:\", middlewareSlots.length > 0 ? middlewareSlots : \"(none)\");\n console.info(\"Slots:\", result.slots.length > 0 ? result.slots : \"(none)\");\n console.info(\"Capabilities:\", Object.keys(capabilities).length > 0 ? capabilities : \"(none)\");\n console.info(\"Adapters:\", result.adapters);\n console.info(\"Auth:\", result.auth);\n\n return result;\n}\n\n// Register global shortcut for browser console\nif (__DEV__ && typeof window !== \"undefined\") {\n (window as unknown as Record<string, unknown>).__SPRING_INSPECT__ = inspectInstance;\n}\n"],"mappings":";;;;;;;AAyCA,SAAS,oBAAoB,UAA0B,OAAyB;AAC5E,QAAM,WAAW,SAAS,GAAG,KAAK;AAClC,MAAI,oBAAoB,IAAK,QAAO,MAAM,KAAK,SAAS,KAAK,CAAC;AAC9D,SAAO,CAAC;AACZ;AAQO,SAAS,gBAAgB,UAAsD;AAClF,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,OAAO,YAAY,qBAAqB;AAC9C,MAAI,CAAC,MAAM;AACP,YAAQ,KAAK,uEAAuE;AACpF,WAAO;AAAA,EACX;AAEA,QAAM,SAAS,KAAK,KAAK;AACzB,QAAM,gBAAiB,KAAK,GAAG,uBAAO,IAAI,sBAAsB,CAAC,KAAK,CAAC;AACvE,QAAM,eAAgB,KAAK,GAAG,uBAAO,IAAI,qBAAqB,CAAC,KAAK,CAAC;AAErE,QAAM,kBAAkB,MAAM,KAAK,KAAK,KAAK,mBAAmB,QAAQ,CAAC,EACpE,OAAO,CAAC,CAAC,EAAE,IAAI,MAAM,KAAK,SAAS,CAAC,EACpC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,GAAG,IAAI,KAAK,KAAK,MAAM,GAAG;AAErD,QAAM,SAAwB;AAAA,IAC1B,IAAI,KAAK;AAAA,IACT,OAAO,KAAK;AAAA,IACZ,QAAQ;AAAA,MACJ,SAAS,OAAO,IAAI;AAAA,MACpB,cAAc,OAAO,IAAI;AAAA,MACzB,cAAc,OAAO,KAAK;AAAA,MAC1B,WAAW,OAAO,KAAK,UAAU;AAAA,IACrC;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA,YAAY;AAAA,IACZ,OAAO,oBAAoB,MAAM,uBAAO,IAAI,qBAAqB,CAAC;AAAA,IAClE,YAAY,oBAAoB,MAAM,uBAAO,IAAI,8BAA8B,CAAC;AAAA,IAChF,aAAa,oBAAoB,MAAM,uBAAO,IAAI,+BAA+B,CAAC;AAAA,IAClF,YAAY,MAAM,KAAK,KAAK,KAAK,kBAAkB,KAAK,CAAC;AAAA,IACzD,UAAU;AAAA,MACN,OAAO,CAAC,CAAC,KAAK,GAAG,uBAAO,IAAI,qBAAqB,CAAC;AAAA,MAClD,IAAI,CAAC,CAAC,KAAK,GAAG,uBAAO,IAAI,kBAAkB,CAAC;AAAA,MAC5C,MAAM,CAAC,CAAC,KAAK,GAAG,uBAAO,IAAI,oBAAoB,CAAC;AAAA,MAChD,WAAW,CAAC,CAAC,KAAK,GAAG,uBAAO,IAAI,yBAAyB,CAAC;AAAA,IAC9D;AAAA,IACA,MAAM;AAAA,MACF,eAAe,KAAK,KAAK;AAAA,MACzB,UAAU,CAAC,CAAC,KAAK,IAAI;AAAA,IACzB;AAAA,EACJ;AAEA,UAAQ,KAAK,oBAAoB,KAAK,EAAE,KAAK,KAAK,KAAK,GAAG;AAC1D,UAAQ,KAAK,QAAQ,OAAO,IAAI,IAAI;AACpC,UAAQ,KAAK,YAAY,cAAc,SAAS,IAAI,gBAAgB,QAAQ;AAC5E,UAAQ,KAAK,eAAe,gBAAgB,SAAS,IAAI,kBAAkB,QAAQ;AACnF,UAAQ,KAAK,UAAU,OAAO,MAAM,SAAS,IAAI,OAAO,QAAQ,QAAQ;AACxE,UAAQ,KAAK,iBAAiB,OAAO,KAAK,YAAY,EAAE,SAAS,IAAI,eAAe,QAAQ;AAC5F,UAAQ,KAAK,aAAa,OAAO,QAAQ;AACzC,UAAQ,KAAK,SAAS,OAAO,IAAI;AAEjC,SAAO;AACX;AAGA,IAAI,WAAW,OAAO,WAAW,aAAa;AAC1C,EAAC,OAA8C,qBAAqB;AACxE;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @spring-systems/core\n// Core types, utilities, and configuration for Spring Systems SPRING.\n// Use sub-path imports for tree-shaking: @spring-systems/core/config, /utils, /types, etc.\n//\n// Convenience re-exports for the most commonly used APIs:\nexport {\n configureCapabilities,\n configureFramework,\n getCapabilities,\n getCapability,\n getFrameworkConfig,\n hasCapability,\n} from \"./config\";\nexport { eventBus } from \"./events/event-bus\";\nexport { getMiddlewareRunner, registerMiddleware } from \"./middleware\";\n\ndeclare const __VERSION__: string;\nexport const SPRING_CORE_VERSION: string = typeof __VERSION__ !== \"undefined\" ? __VERSION__ : \"0.0.0-dev\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBO,IAAM,sBAA8B,OAAqC,UAAc;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/testing/test-utils.ts"],"sourcesContent":["/**\n * Testing utilities for SPRING framework consumers and plugin authors.\n *\n * Provides factory functions to create isolated SpringInstances for tests\n * with pre-configured mocks and adapters.\n *\n * @example\n * ```ts\n * import { createTestInstance, mockAdapters } from \"@spring-systems/core/testing\";\n *\n * describe(\"my plugin\", () => {\n * let instance: SpringInstance;\n *\n * beforeEach(() => {\n * instance = createTestInstance({\n * config: { app: { name: \"Test\" } },\n * plugins: [myPlugin],\n * });\n * });\n *\n * afterEach(() => {\n * instance.dispose();\n * });\n *\n * it(\"registers middleware\", () => {\n * expect(getMiddlewareRunner(\"form:beforeSave\")).toBeDefined();\n * });\n * });\n * ```\n *\n * @module test-utils\n */\n\nimport {\n clearContentAdapter,\n clearHttpAdapter,\n clearLicenseAdapter,\n clearNotificationAdapter,\n clearTelemetryAdapter,\n} from \"../adapters\";\nimport { clearAuthState } from \"../auth/auth-handler\";\nimport { clearCapabilities } from \"../config/capabilities\";\nimport { clearFrameworkConfig } from \"../config/framework-config\";\nimport type { FrameworkConfigOverrides } from \"../config/framework-config-types\";\nimport { clearRuntimeEnvKeys } from \"../config/runtime-env-config\";\nimport { eventBus } from \"../events/event-bus\";\nimport { createSpringInstance } from \"../instance/create-instance\";\nimport { clearSpringInstance,setSpringInstance } from \"../instance/current-instance\";\nimport type { InstanceContentAdapter, InstanceLogAdapter,InstanceNotificationAdapter,SpringInstance } from \"../instance/spring-instance\";\nimport { clearLogAdapter, resetLogLevel } from \"../logger/logger\";\nimport { clearAllMiddleware } from \"../middleware/middleware-registry\";\nimport type { SpringPlugin } from \"../plugins/plugin\";\nimport { applyPlugins, disposePlugins } from \"../plugins/plugin\";\nimport type { SecurityLogData } from \"../utils/security-sanitize\";\nimport { clearValidators } from \"../validation/validations\";\n\nexport interface CreateTestInstanceOptions {\n /** Framework config overrides for this test instance */\n config?: FrameworkConfigOverrides;\n /** Plugins to apply to the test instance */\n plugins?: SpringPlugin[];\n /** Whether to set this as the global current instance (default: true) */\n setGlobal?: boolean;\n /** Custom content adapter (defaults to identity function) */\n contentAdapter?: InstanceContentAdapter;\n /** Custom notification adapter (defaults to no-op) */\n notificationAdapter?: InstanceNotificationAdapter;\n /** Custom log adapter (defaults to no-op) */\n logAdapter?: InstanceLogAdapter;\n}\n\n/**\n * Create an isolated SpringInstance for testing.\n * Automatically sets it as the global current instance (unless setGlobal: false).\n * Call `instance.dispose()` in afterEach to clean up.\n */\nexport function createTestInstance(options: CreateTestInstanceOptions = {}): SpringInstance {\n const instance = createSpringInstance(options.config);\n\n // Apply mock adapters\n if (options.contentAdapter) {\n instance.core.contentAdapter = options.contentAdapter;\n }\n if (options.notificationAdapter) {\n instance.core.notificationAdapter = options.notificationAdapter;\n }\n if (options.logAdapter) {\n instance.core.logAdapter = options.logAdapter;\n }\n\n // Set as global if requested\n if (options.setGlobal !== false) {\n setSpringInstance(instance);\n }\n\n // Apply plugins\n if (options.plugins && options.plugins.length > 0) {\n applyPlugins(instance, options.plugins);\n }\n\n // Augment dispose to also clear global and dispose plugins\n const originalDispose = instance.dispose.bind(instance);\n instance.dispose = () => {\n disposePlugins(instance);\n originalDispose();\n if (options.setGlobal !== false) {\n clearSpringInstance();\n }\n };\n\n return instance;\n}\n\n/** Pre-built mock adapters for testing */\nexport const mockAdapters = {\n /** Content adapter that returns the key itself (identity) */\n content: (): InstanceContentAdapter => ({\n getRes: (key: string) => key,\n }),\n\n /** Content adapter that returns a custom mapping */\n contentWithMessages: (messages: Record<string, string>): InstanceContentAdapter => ({\n getRes: (key: string) => messages[key] ?? `[${key}]`,\n }),\n\n /** Notification adapter that collects all notifications for assertions */\n notificationCollector: () => {\n const calls: Array<{ type: \"error\" | \"success\" | \"warning\" | \"info\"; msg: string }> = [];\n return {\n adapter: {\n error: (msg: string) => calls.push({ type: \"error\", msg }),\n success: (msg: string) => calls.push({ type: \"success\", msg }),\n warning: (msg: string) => calls.push({ type: \"warning\", msg }),\n info: (msg: string) => calls.push({ type: \"info\", msg }),\n } satisfies InstanceNotificationAdapter,\n calls,\n clear: () => { calls.length = 0; },\n };\n },\n\n /** Log adapter that collects all log entries for assertions */\n logCollector: () => {\n const errors: Array<{ context: string; error?: unknown }> = [];\n const warnings: Array<{ context: string; message?: string }> = [];\n const securityEvents: Array<{ event: unknown; data?: SecurityLogData }> = [];\n return {\n adapter: {\n onError: (ctx: string, err?: unknown) => errors.push({ context: ctx, error: err }),\n onWarn: (ctx: string, msg?: string) => warnings.push({ context: ctx, message: msg }),\n onSecurityEvent: (evt: unknown, data?: SecurityLogData) => securityEvents.push({ event: evt, data }),\n } satisfies InstanceLogAdapter,\n errors,\n warnings,\n securityEvents,\n };\n },\n\n /** Silent no-op adapters (suppress all output) */\n silent: {\n content: { getRes: (key: string) => key } satisfies InstanceContentAdapter,\n notification: {\n error: (_msg: string) => {},\n success: (_msg: string) => {},\n warning: (_msg: string) => {},\n info: (_msg: string) => {},\n } satisfies InstanceNotificationAdapter,\n log: {} satisfies InstanceLogAdapter,\n },\n} as const;\n\n/** Boundary cast for tests — replaces the `as unknown as X` pattern in a single place.\n * Usage: `castTo<FormStoreApi>({ getState: vi.fn() })` instead of `{ getState: vi.fn() } as unknown as FormStoreApi`\n */\nexport function castTo<T>(value: unknown): T {\n return value as T;\n}\n\n/** Runtime assertion that a value is defined. Returns the value with a non-nullable type.\n * Usage: `assertDefined(arr[0]).field` instead of `arr[0]!.field`\n */\nexport function assertDefined<T>(val: T | undefined | null, msg?: string): T {\n if (val === undefined || val === null) {\n throw new Error(msg ?? \"Expected value to be defined, but got \" + String(val));\n }\n return val;\n}\n\n/**\n * Resets singleton/fallback runtime state across core modules.\n * Useful in integration tests that run multiple app lifecycles in one process.\n */\nexport function resetCoreRuntimeState(): void {\n eventBus.clearAll();\n clearAllMiddleware();\n clearValidators();\n clearCapabilities();\n clearFrameworkConfig();\n clearRuntimeEnvKeys();\n\n clearAuthState();\n clearContentAdapter();\n clearNotificationAdapter();\n clearHttpAdapter();\n clearLicenseAdapter();\n clearTelemetryAdapter();\n clearLogAdapter();\n resetLogLevel();\n\n clearSpringInstance();\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/types/branded.ts","../../src/types/grid-types.ts","../../src/types/list-types.ts"],"sourcesContent":["/**\n * Branded types for nominal type safety.\n * Prevents accidental interchange of structurally identical string types.\n * @module branded\n */\n\ndeclare const __brand: unique symbol;\n\n/** Brands a base type `T` with a nominal tag `B`. */\nexport type Brand<T, B extends string> = T & { readonly [__brand]: B };\n\n/** A GUID / UUID string. */\nexport type Guid = Brand<string, \"Guid\">;\n\n/** A public entity identifier. */\nexport type IdPublic = Brand<string, \"IdPublic\">;\n\n/** A resource/translation key. */\nexport type ResourceKey = Brand<string, \"ResourceKey\">;\n\n/** An API route path. */\nexport type ApiRoute = Brand<string, \"ApiRoute\">;\n\n/** Cast a plain string to a Guid (boundary cast). */\nexport function toGuid(value: string): Guid {\n return value as Guid;\n}\n\n/** Cast a plain string to an IdPublic (boundary cast). */\nexport function toIdPublic(value: string): IdPublic {\n return value as IdPublic;\n}\n\n/** Cast a plain string to a ResourceKey (boundary cast). */\nexport function toResourceKey(value: string): ResourceKey {\n return value as ResourceKey;\n}\n\n/** Cast a plain string to an ApiRoute (boundary cast). */\nexport function toApiRoute(value: string): ApiRoute {\n return value as ApiRoute;\n}\n","/**\n * Shared types used by both List and TreeList grids.\n * Single source of truth — re-exported from lists.ts and treelists.ts.\n * @module grid-types\n */\n\nexport interface Permission {\n delete: boolean;\n insert: boolean;\n list: boolean;\n read: boolean;\n update: boolean;\n /** Allows projects to add custom permission fields (e.g., { export: true, approve: false }) */\n [key: string]: boolean;\n}\n\nexport type LogicOperator = \"and\" | \"or\";\n\n/** Node structure for tree-based filter. */\nexport interface FilterNode {\n field?: string;\n operator?: string;\n value?: string | number | boolean | null;\n logic?: LogicOperator;\n filters?: FilterNode[];\n negate?: boolean;\n}\n\n/** Simple key-value system filter (normalized into FilterNode by the engine). */\nexport interface SystemFilterRecord {\n [key: string]: string | number | boolean | Date | null | undefined;\n}\n\nexport type ColumnType = \"string\" | \"number\" | \"date\" | \"datetime\" | \"time\" | \"boolean\" | \"object\" | \"color\";\n\n/** Column layout for saving into user settings. */\nexport interface ColumnLayout {\n key: string;\n order: number;\n width?: number;\n show: boolean;\n}\n\nexport interface DefaultFilter {\n domain_name: string;\n id_public: string;\n is_default: boolean;\n json_data: string;\n name: string;\n user_setting_type_code: \"user\" | \"fixed\" | \"layout\";\n version: number;\n}\n\nexport interface SavedLayout {\n domain_name: string;\n id_public: string;\n is_default: boolean;\n json_data: string;\n name: string;\n user_setting_type_code: \"layout\";\n version: number;\n}\n\n/** Combined structure for json_data in user-settings — filter + layout in one JSON. */\nexport interface CombinedSettingData {\n user_filter?: FilterNode | null;\n layout?: ColumnLayout[];\n}\n\n/** Type guard for FilterNode — checks for tree-filter or leaf-filter shape. */\nexport function isFilterNode(val: unknown): val is FilterNode {\n if (typeof val !== \"object\" || val === null || Array.isArray(val)) return false;\n return (\"logic\" in val && \"filters\" in val) || (\"field\" in val && \"operator\" in val);\n}\n\n/** Type guard for CombinedSettingData — checks for user_filter or layout property. */\nexport function isCombinedSettingData(val: unknown): val is CombinedSettingData {\n if (typeof val !== \"object\" || val === null || Array.isArray(val)) return false;\n return \"user_filter\" in val || \"layout\" in val;\n}\n\n/** Type guard for Permission — checks for all 5 required CRUD boolean keys. */\nexport function isPermission(val: unknown): val is Permission {\n if (typeof val !== \"object\" || val === null || Array.isArray(val)) return false;\n const obj = val as Record<string, unknown>;\n return (\n typeof obj.read === \"boolean\" &&\n typeof obj.list === \"boolean\" &&\n typeof obj.delete === \"boolean\" &&\n typeof obj.insert === \"boolean\" &&\n typeof obj.update === \"boolean\"\n );\n}\n\n/** Type guard for ColumnLayout — checks for required key, order, show properties. */\nexport function isColumnLayout(val: unknown): val is ColumnLayout {\n if (typeof val !== \"object\" || val === null || Array.isArray(val)) return false;\n const obj = val as Record<string, unknown>;\n return typeof obj.key === \"string\" && typeof obj.order === \"number\" && typeof obj.show === \"boolean\";\n}\n","/**\n * List types — pure type definitions extracted from shared/lists/lists.ts.\n * @module list-types\n */\n\nimport type { FormStoreState } from \"./form-types\";\nimport type { Permission } from \"./grid-types\";\n\n/** Comparison operators used in format conditions (conditional formatting). */\nexport type FormatOperator = \"==\" | \"===\" | \"!=\" | \"!==\" | \">\" | \">=\" | \"<\" | \"<=\";\n\nexport interface FormatCondition {\n value?: string | number | boolean | null;\n background?: string;\n color?: string;\n column?: string;\n field: string;\n operator?: FormatOperator;\n className?: string;\n}\n\nexport const FormatType = {\n Badge: 1,\n Color: 2,\n Background: 3,\n RowBackground: 4,\n Icon: 5,\n Detail: 6,\n} as const;\nexport type FormatType = (typeof FormatType)[keyof typeof FormatType];\n\nexport interface Pagination {\n page?: number;\n per_page?: number;\n object_count: number;\n}\n\nexport interface ListResponse<T> {\n data: T[];\n message: string | null;\n pagination: Pagination;\n permissions?: Permission;\n format_conditions: FormatCondition[];\n params?: FormStoreState;\n}\n"],"mappings":";;;;;;;;;;;AAwBO,SAAS,OAAO,OAAqB;AACxC,SAAO;AACX;AAGO,SAAS,WAAW,OAAyB;AAChD,SAAO;AACX;AAGO,SAAS,cAAc,OAA4B;AACtD,SAAO;AACX;AAGO,SAAS,WAAW,OAAyB;AAChD,SAAO;AACX;;;AC6BO,SAAS,aAAa,KAAiC;AAC1D,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,EAAG,QAAO;AAC1E,SAAQ,WAAW,OAAO,aAAa,OAAS,WAAW,OAAO,cAAc;AACpF;AAGO,SAAS,sBAAsB,KAA0C;AAC5E,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,EAAG,QAAO;AAC1E,SAAO,iBAAiB,OAAO,YAAY;AAC/C;AAGO,SAAS,aAAa,KAAiC;AAC1D,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,EAAG,QAAO;AAC1E,QAAM,MAAM;AACZ,SACI,OAAO,IAAI,SAAS,aACpB,OAAO,IAAI,SAAS,aACpB,OAAO,IAAI,WAAW,aACtB,OAAO,IAAI,WAAW,aACtB,OAAO,IAAI,WAAW;AAE9B;AAGO,SAAS,eAAe,KAAmC;AAC9D,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,EAAG,QAAO;AAC1E,QAAM,MAAM;AACZ,SAAO,OAAO,IAAI,QAAQ,YAAY,OAAO,IAAI,UAAU,YAAY,OAAO,IAAI,SAAS;AAC/F;;;AC9EO,IAAM,aAAa;AAAA,EACtB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,MAAM;AAAA,EACN,QAAQ;AACZ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utils/a11y.ts","../../src/utils/color.ts","../../src/utils/data-utils.ts","../../src/utils/date.ts","../../src/utils/deprecation.ts","../../src/utils/filter-utils.ts","../../src/utils/format-utils.ts","../../src/utils/tree-utils.ts"],"sourcesContent":["interface KeyActivateEvent {\n key: string;\n preventDefault(): void;\n}\n\nexport function onKeyActivate<E extends KeyActivateEvent = KeyActivateEvent>(\n handler?: ((e: E) => void) | (() => void) | null,\n) {\n if (!handler) return undefined;\n return (e: E) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n (handler as (e: E) => void)(e);\n }\n };\n}\n\nexport function prefersReducedMotion(): boolean {\n if (typeof window === \"undefined\") return false;\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n","export function getBrightness(r: number, g: number, b: number): number {\n return (r * 299 + g * 587 + b * 114) / 1000;\n}\n\nexport function hexToRgb(hex: string): [number, number, number] {\n const bigint = parseInt(hex.slice(1), 16);\n const r = (bigint >> 16) & 255;\n const g = (bigint >> 8) & 255;\n const b = bigint & 255;\n return [r, g, b];\n}\n\nexport function rgbToHex(rgb: string): string {\n const match = rgb.match(/\\d+/g);\n if (!match) return \"#000000\";\n const result = match.map((x) => parseInt(x).toString(16).padStart(2, \"0\")).join(\"\");\n return `#${result}`;\n}\n\nexport function getContrastYIQ(hex: string): string {\n const [r, g, b] = hexToRgb(hex);\n const brightness = getBrightness(r, g, b);\n return brightness > 150 ? \"black\" : \"white\";\n}\n","import dayjs from \"dayjs\";\nimport customParseFormat from \"dayjs/plugin/customParseFormat\";\n\nimport { emptyGuid } from \"../config/constants\";\nimport { SpringValidationError } from \"../errors/errors\";\nimport type { FormDataValue, FormStoreState, Indexable, IndexedFormData } from \"../types/form-types\";\n\ndayjs.extend(customParseFormat);\n\nconst UNSAFE_MERGE_KEYS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\n\nexport function isValueNotEmpty(value: string | number | boolean | null | undefined | FormDataValue[]): boolean {\n return (\n value !== 0 &&\n value !== null &&\n value !== undefined &&\n value !== false &&\n value !== \"\" &&\n !(Array.isArray(value) && value.length === 0)\n );\n}\n\n/** Returns a deep copy of an object, removing unwanted references. */\nexport function deepCopy<T>(obj: T, hash?: WeakMap<WeakKey, unknown>): T {\n // Fast path: use native structuredClone on top-level calls (handles Date, RegExp, circular refs natively).\n // Falls back to manual implementation when structuredClone fails (e.g. objects containing functions).\n if (!hash && typeof structuredClone === \"function\") {\n try {\n return structuredClone(obj);\n } catch {\n // structuredClone cannot handle functions — fall through to manual copy\n }\n }\n\n const map = hash ?? new WeakMap();\n\n if (typeof obj === \"object\" && obj !== null && map.has(obj)) return map.get(obj) as T;\n\n if (obj instanceof Date) return new Date(obj.getTime()) as T;\n if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags) as T;\n if (obj === null || typeof obj !== \"object\") return obj;\n\n const result = (Array.isArray(obj) ? [] : {}) as Indexable;\n map.set(obj, result);\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n result[key] = deepCopy((obj as Indexable)[key], map);\n }\n }\n\n return result as T;\n}\n\n/**\n * Performs deep comparison of two objects.\n * Treats `null` and `\"\"` as equivalent — this is intentional because the backend\n * API returns `null` for empty fields while form inputs produce `\"\"`.\n */\nexport function deepEqual(a: FormDataValue | FormStoreState, b: FormDataValue | FormStoreState): boolean {\n if (a === b) return true;\n\n if ((a === null && b === \"\") || (a === \"\" && b === null)) return true;\n\n if (\n a == null ||\n b == null ||\n (typeof a !== \"object\" && typeof a !== \"function\") ||\n (typeof b !== \"object\" && typeof b !== \"function\")\n ) {\n return false;\n }\n\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n\n const objA = a as IndexedFormData;\n const objB = b as IndexedFormData;\n const keysA = Object.keys(objA);\n const keysB = Object.keys(objB);\n\n if (keysA.length !== keysB.length) {\n return false;\n }\n\n const keysBSet = new Set(keysB);\n for (const key of keysA) {\n if (!keysBSet.has(key) || !deepEqual(objA[key], objB[key])) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function deepMerge<T extends Indexable>(target: T, source: Partial<T>): T {\n const result = { ...target };\n Object.keys(source).forEach((key) => {\n if (UNSAFE_MERGE_KEYS.has(key)) {\n return;\n }\n const k = key as keyof T;\n if (source[k] && typeof source[k] === \"object\" && !Array.isArray(source[k])) {\n result[k] = deepMerge(\n (target[k] && typeof target[k] === \"object\" ? target[k] : {}) as T[keyof T] & Indexable,\n source[k] as Partial<T[keyof T] & Indexable>,\n ) as T[keyof T];\n } else {\n result[k] = source[k] as T[keyof T];\n }\n });\n return result;\n}\n\nexport function getValueByPath(obj: FormStoreState, path: string): FormDataValue {\n const keys = path.split(\".\");\n let current: FormDataValue | FormStoreState = obj;\n\n for (const key of keys) {\n if (current == null || typeof current !== \"object\" || current instanceof Date) {\n return undefined;\n }\n if (Array.isArray(current)) return undefined;\n current = (current as IndexedFormData)[key];\n }\n\n return current as FormDataValue;\n}\n\n/** Normalizes a string for comparison without diacritics, in lowercase */\nexport function normalizeString(str: string): string {\n return str\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLowerCase();\n}\n\nexport function generateGUID(): string {\n const cryptoApi = globalThis.crypto;\n if (cryptoApi && typeof cryptoApi.randomUUID === \"function\") {\n return cryptoApi.randomUUID();\n }\n\n if (cryptoApi && typeof cryptoApi.getRandomValues === \"function\") {\n const bytes = new Uint8Array(16);\n cryptoApi.getRandomValues(bytes);\n // RFC 4122 version 4 bits\n const b6 = bytes[6] ?? 0;\n const b8 = bytes[8] ?? 0;\n bytes[6] = (b6 & 0x0f) | 0x40;\n bytes[8] = (b8 & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n\n throw new SpringValidationError(\n \"generateGUID(): secure random source unavailable. Provide Web Crypto (crypto.randomUUID or crypto.getRandomValues).\",\n \"generateGUID\",\n );\n}\n\nexport function setDefaultStructure(\n data: { field?: string; type?: string }[],\n): Record<string, string | number | boolean | null | undefined> {\n const result: Record<string, string | number | boolean | null | undefined> = {\n id_public: emptyGuid,\n };\n\n const defaultValue = (type: string | undefined) => {\n switch (type) {\n case \"boolean\":\n return false;\n case \"string\":\n return \"\";\n case \"number\":\n return \"\";\n case \"object\":\n case \"date\":\n case \"datetime\":\n case \"time\":\n return null;\n default:\n return undefined;\n }\n };\n\n data.forEach((item: { field?: string; type?: string }) => {\n if (item.field) {\n result[item.field] = defaultValue(item.type);\n }\n });\n\n return result;\n}\n\nexport function parseJSONSafely(\n value: string | number | boolean | null | undefined | object,\n): string | number | boolean | null | undefined | object {\n if (typeof value === \"string\") {\n if (value.toLowerCase() === \"true\") {\n return true;\n } else if (value.toLowerCase() === \"false\") {\n return false;\n }\n\n try {\n return JSON.parse(value);\n } catch (_e: unknown) {\n return value;\n }\n }\n\n return value;\n}\n\nexport type ValueType = \"string\" | \"date\" | \"number\" | \"boolean\" | \"object\";\n\nexport function getValueType(value: string | number | boolean | null | undefined | object): ValueType {\n const v = parseJSONSafely(value);\n\n if (v === null || v === undefined) {\n return \"string\";\n }\n\n if (v instanceof Date) {\n return \"date\";\n }\n\n if (typeof v === \"string\") {\n const trimmed = v.trim();\n\n const looksLikeDate = /[0-9]/.test(trimmed) && /[-./]/.test(trimmed) && trimmed.length >= 6;\n\n if (looksLikeDate) {\n const formats = [\n \"D.M.YYYY\",\n \"DD.MM.YYYY\",\n \"D. M. YYYY\",\n \"DD. MM. YYYY\",\n \"DD.MM.YYYY HH:mm\",\n \"D.M.YYYY HH:mm\",\n \"DD.MM.YYYY H:mm\",\n \"D.M.YYYY H:mm\",\n \"YYYY-MM-DD\",\n \"YYYY-MM-DDTHH:mm:ss\",\n \"YYYY-MM-DDTHH:mm:ss.SSS\",\n \"YYYY-MM-DDTHH:mm:ssZ\",\n \"YYYY-MM-DDTHH:mm:ss.SSSZ\",\n ];\n\n if (dayjs(trimmed, formats as string[], true).isValid()) {\n return \"date\";\n }\n\n if (dayjs(trimmed).isValid() && /^\\d{4}-\\d{2}-\\d{2}/.test(trimmed)) {\n return \"date\";\n }\n }\n }\n\n if (Array.isArray(v)) {\n if (v.length === 0) {\n return \"object\";\n }\n return getValueType(v[0]);\n }\n\n const t = typeof v;\n\n if (t === \"number\") {\n return \"number\";\n }\n\n if (t === \"boolean\") {\n return \"boolean\";\n }\n\n if (t === \"object\") {\n return \"object\";\n }\n\n return \"string\";\n}\n","import dayjs from \"dayjs\";\n// Consumer must import their locale (e.g., import \"dayjs/locale/cs\") before using dateManager\nimport customParseFormat from \"dayjs/plugin/customParseFormat\";\nimport isBetweenPlugin from \"dayjs/plugin/isBetween\";\n\nimport { type DateFormatConfig, getFrameworkConfig } from \"../config/framework-config\";\n\ndayjs.extend(customParseFormat);\ndayjs.extend(isBetweenPlugin);\n\nlet activeLocale: string | null = null;\n\nfunction ensureLocale(): void {\n const locale = getFrameworkConfig().i18n.dayjsLocale;\n if (locale && locale !== activeLocale) {\n dayjs.locale(locale);\n activeLocale = locale;\n }\n}\n\n/**\n * Set the dayjs locale at runtime.\n * The locale package must be imported before calling this (e.g., `import \"dayjs/locale/en\"`).\n */\nexport function setDateLocale(locale: string): void {\n activeLocale = locale;\n dayjs.locale(locale);\n}\n\nfunction fmt(): DateFormatConfig {\n ensureLocale();\n return getFrameworkConfig().i18n.dateFormats;\n}\n\nexport const dateManager = {\n formatDateCustom(value: Date | null, format: string) {\n if (!value) {\n return \"\";\n } else {\n return dayjs(value).format(format);\n }\n },\n formatDate(value: Date | null) {\n if (!value) {\n return \"\";\n } else {\n return dayjs(value).format(fmt().date);\n }\n },\n formatDateTime(value: Date | null) {\n if (!value) {\n return \"\";\n } else {\n return dayjs(value).format(fmt().dateTime);\n }\n },\n formatTime(value: Date | null) {\n if (!value) {\n return \"\";\n } else {\n return dayjs(value).format(fmt().time);\n }\n },\n formatDateRange(dateFrom: Date, dateTo: Date, format = fmt().date) {\n const from = dayjs(dateFrom);\n const to = dayjs(dateTo);\n const dtFmt = fmt().dateTime;\n\n if (from.isSame(to, \"day\")) {\n if (format.includes(\"H\") || format.includes(\"h\")) {\n return `${from.format(dtFmt)}-${to.format(fmt().time)}`;\n } else if (format === fmt().time) {\n return `${from.format(fmt().time)}-${to.format(fmt().time)}`;\n }\n return from.format(format);\n }\n\n if (format.includes(\"H\") || format.includes(\"h\")) {\n return `${from.format(dtFmt)} - ${to.format(dtFmt)}`;\n } else if (format === fmt().time) {\n return `${from.format(fmt().time)} - ${to.format(fmt().time)}`;\n }\n\n return `${from.format(fmt().date)} - ${to.format(fmt().date)}`;\n },\n formatDateTimeWithSeconds(value: Date | null) {\n if (!value) {\n return \"\";\n } else {\n return dayjs(value).format(fmt().dateTimeSeconds);\n }\n },\n /** Formats a value as date with time, or time only if it is today */\n formatDateTimeShort(value: Date | null) {\n if (!value) {\n return \"\";\n } else if (dayjs(value).isSame(Date.now(), \"day\")) {\n return dayjs(value).format(fmt().time);\n } else {\n return this.formatDateTime(value);\n }\n },\n getAgeFromDate(value: Date) {\n return dayjs().diff(value, \"years\");\n },\n formatMonthName(value: Date, format: string) {\n return dayjs(value).format(format);\n },\n formatMonthNumber(value: Date) {\n return dayjs(value).month() + 1;\n },\n getPreviousMonth(date: Date, numberOfMonth: number) {\n return dayjs(date).subtract(numberOfMonth, \"months\").toDate();\n },\n setTimeFromString(date: Date, time: string, onlyMinutes?: boolean) {\n const setDate = dayjs(date).toDate();\n const split = time.split(\":\");\n if (!onlyMinutes) {\n setDate.setHours(Number(split[0] ?? 0));\n } else {\n setDate.setSeconds(0);\n }\n setDate.setMinutes(Number(split[1] ?? 0));\n return setDate;\n },\n formatDateString(value: string) {\n if (!value) {\n return null;\n } else {\n if (value.split(\"-\")[0]?.length === 4) {\n return dayjs(value).toDate();\n }\n if (value.split(\".\")[0]?.length === 4 || value.split(\"/\")[0]?.length === 4) {\n return dayjs(value, \"YYYY. M. D.\").toDate();\n }\n return dayjs(value, \"D. M. YYYY\").toDate();\n }\n },\n getDuration(date: Date | null, date2: Date | null, type: dayjs.ManipulateType) {\n if (!date || !date2) {\n return null;\n } else {\n const value = dayjs(date);\n const value2 = dayjs(date2);\n const result = value2.diff(value, type);\n return result;\n }\n },\n getStartOfDate(date: Date, unitOfTime: dayjs.OpUnitType) {\n return dayjs(date).startOf(unitOfTime).toDate();\n },\n getEndOfDay(date: Date) {\n return dayjs(date).endOf(\"day\").toDate();\n },\n getDateRange(date: Date, unitOfTime: dayjs.OpUnitType) {\n const startDate = dayjs(date).startOf(unitOfTime).toDate();\n const endDate = dayjs(date).endOf(unitOfTime).toDate();\n return { dateFrom: startDate, dateTo: endDate };\n },\n isDateInRange(startDate: Date, endDate: Date, dateToCheck: Date) {\n if (!endDate) {\n return dayjs(dateToCheck).isSame(startDate, \"day\");\n }\n return dayjs(dateToCheck).isBetween(startDate, endDate, null, \"[]\");\n },\n /** Adds a number of days (or other unit) to a date */\n add(value: Date, count: number, type?: dayjs.ManipulateType) {\n return dayjs(value)\n .add(count, type ? type : \"days\")\n .toDate();\n },\n substractDaysFromDate(numberOfDays: number, date: Date) {\n const result = dayjs(date).subtract(numberOfDays, \"days\").toDate();\n return result;\n },\n};\n","/**\n * Runtime deprecation warnings for the SPRING framework.\n * Warns once per session per deprecation to avoid console spam.\n * @module deprecation\n */\n\nconst warned = new Set<string>();\n\nexport function springDeprecate(name: string, alternative: string, removeVersion?: string): void {\n const key = `${name}:${alternative}`;\n if (warned.has(key)) return;\n warned.add(key);\n\n const versionNote = removeVersion ? ` It will be removed in v${removeVersion}.` : \"\";\n console.warn(`[SPRING Deprecation] \"${name}\" is deprecated. Use ${alternative} instead.${versionNote}`);\n}\n\n/** Clear all tracked deprecation warnings. Intended for testing. */\nexport function clearDeprecationWarnings(): void {\n warned.clear();\n}\n","import type { FilterFieldValue } from \"../types/form-types\";\nimport type { FilterNode } from \"../types/grid-types\";\nimport { getValueType } from \"./data-utils\";\n\nexport function parseFilter(value: string | number | boolean | Date | null | undefined | FilterFieldValue[] | object): string | boolean {\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (Array.isArray(value)) {\n return JSON.stringify(value);\n }\n\n if (typeof value === \"boolean\") {\n return value;\n }\n\n return value != null ? value.toString() : \"\";\n}\n\n/** Normalizes system filter — string/object to FilterNode. */\nexport function normalizeSystemFilter(\n input: Record<string, string | number | boolean | Date | null | undefined> | FilterNode | null | undefined\n): FilterNode | null {\n if (!input) return null;\n if (typeof input === \"object\" && input !== null && (\"logic\" in input || \"field\" in input)) {\n return input as FilterNode;\n }\n\n if (typeof input === \"object\" && input !== null) {\n const entries = Object.entries(input).filter(([k, v]) => k && v !== undefined && v !== null && v !== \"\");\n const filters: FilterNode[] = entries.map(([k, v]) => {\n const val = parseFilter(v);\n return {\n field: k,\n operator: \"eq\",\n value: val,\n };\n });\n\n if (filters.length === 0) {\n return null;\n }\n\n return {\n logic: \"and\",\n filters,\n };\n }\n\n return null;\n}\n\nexport function getFilterFieldType(\n fieldKey: string,\n defaultListFilter: Record<string, { type?: string }> | null | undefined,\n value: string | number | boolean | null | undefined | object\n): string {\n const fieldDef = defaultListFilter && defaultListFilter[fieldKey];\n\n if (fieldDef && typeof fieldDef.type === \"string\") {\n return fieldDef.type;\n }\n\n return getValueType(value);\n}\n","import sanitizeHtml from \"sanitize-html\";\n\nimport { getContentRes } from \"../adapters/content-adapter\";\nimport { getFrameworkConfig } from \"../config/framework-config\";\nimport type { FormStoreState } from \"../types/form-types\";\nimport type { ColumnType } from \"../types/grid-types\";\nimport { dateManager } from \"./date\";\n\ninterface FormatColumn<T> {\n field: string & keyof T;\n type: ColumnType;\n decimals?: number;\n textField?: string;\n}\n\n/** Strips all HTML tags from content */\nexport function sanitizeContent(content: string): string {\n if (!content) {\n return \"\";\n }\n const clean = sanitizeHtml(content, {\n allowedTags: [],\n allowedAttributes: {},\n });\n return clean;\n}\n\nconst editorAllowedTags = [\n \"p\", \"br\", \"div\", \"ul\", \"ol\", \"li\", \"b\", \"i\", \"em\", \"strong\", \"u\", \"s\",\n \"sub\", \"sup\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"span\", \"a\",\n \"table\", \"thead\", \"tbody\", \"tr\", \"th\", \"td\",\n];\nconst editorAllowedAttributes: sanitizeHtml.IOptions[\"allowedAttributes\"] = {\n a: [\"href\", \"title\", \"target\", \"rel\"],\n td: [\"colspan\", \"rowspan\"],\n th: [\"colspan\", \"rowspan\"],\n span: [\"style\"],\n};\nconst SAFE_TEXT_DECORATION_PATTERN = /^(?!.*(?:url|expression)\\s*\\()[a-z0-9#(),.%\\s-]{1,80}$/i;\nconst SAFE_LINK_TARGETS = new Set([\"_blank\", \"_self\", \"_parent\", \"_top\"]);\n\nfunction normalizeRelTokens(rel: string | undefined): string[] {\n if (!rel) return [];\n const seen = new Set<string>();\n const tokens: string[] = [];\n for (const raw of rel.split(/\\s+/)) {\n const token = raw.trim().toLowerCase();\n if (!token || token === \"opener\" || seen.has(token)) continue;\n seen.add(token);\n tokens.push(token);\n }\n return tokens;\n}\n\nconst editorTransformTags: sanitizeHtml.IOptions[\"transformTags\"] = {\n a: (tagName, attribs) => {\n const nextAttribs: Record<string, string> = { ...attribs };\n\n if (typeof nextAttribs.target === \"string\") {\n const normalizedTarget = nextAttribs.target.trim().toLowerCase();\n if (SAFE_LINK_TARGETS.has(normalizedTarget)) {\n nextAttribs.target = normalizedTarget;\n } else {\n delete nextAttribs.target;\n }\n }\n\n if (nextAttribs.target === \"_blank\") {\n const relTokens = normalizeRelTokens(nextAttribs.rel);\n if (!relTokens.includes(\"noopener\")) relTokens.push(\"noopener\");\n if (!relTokens.includes(\"noreferrer\")) relTokens.push(\"noreferrer\");\n nextAttribs.rel = relTokens.join(\" \");\n }\n\n return { tagName, attribs: nextAttribs };\n },\n};\n\nconst editorAllowedStyles: sanitizeHtml.IOptions[\"allowedStyles\"] = {\n span: {\n \"text-decoration\": [SAFE_TEXT_DECORATION_PATTERN],\n },\n};\n\n/** Sanitizes HTML output from WYSIWYG editor — allows formatting tags, removes scripts */\nexport function sanitizeEditorContent(content: string): string {\n if (!content) {\n return \"\";\n }\n return sanitizeHtml(content, {\n allowedTags: editorAllowedTags,\n allowedAttributes: editorAllowedAttributes,\n allowedStyles: editorAllowedStyles,\n transformTags: editorTransformTags,\n allowedSchemes: [\"http\", \"https\", \"mailto\"],\n });\n}\n\nexport function truncateString(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n } else if (maxLength < 3) {\n return value.slice(0, maxLength);\n } else {\n return value.slice(0, maxLength - 3) + \"...\";\n }\n}\n\nexport function toNumber(value: string | number, decimals?: number): string {\n const locale = getFrameworkConfig().i18n.numberLocale;\n return Number(value).toLocaleString(locale, {\n minimumFractionDigits: decimals ? decimals : 0,\n maximumFractionDigits: decimals ? decimals : 0,\n });\n}\n\nexport function setColumnBodyType<T extends FormStoreState>(item: T, obj: FormatColumn<T>): T[string & keyof T] | string | number | undefined {\n const key = obj.field;\n const rec = item;\n let result: T[string & keyof T] | string | number | undefined = rec[key];\n switch (obj.type) {\n case \"date\":\n result = dateManager.formatDate(rec[key] as Date | null);\n break;\n case \"datetime\":\n result = dateManager.formatDateTime(rec[key] as Date | null);\n break;\n case \"time\":\n result = dateManager.formatTime(rec[key] as Date | null);\n break;\n case \"boolean\":\n result = rec[key] ? getContentRes(\"admin-yes\") : getContentRes(\"admin-no\");\n break;\n case \"number\": {\n const numVal = rec[key] as string | number | undefined;\n result = numVal !== undefined ? (obj.decimals ? toNumber(numVal, obj.decimals) : numVal) : \"\";\n break;\n }\n case \"object\": {\n const objVal = rec[key] as { full_name?: string; name?: string; [k: string]: string | undefined } | null | undefined;\n result = objVal\n ? obj.textField\n ? objVal[obj.textField]\n : objVal.full_name || objVal.name || \"\"\n : \"\";\n break;\n }\n case \"string\":\n case \"color\":\n break;\n default: {\n const _exhaustive: never = obj.type;\n void _exhaustive;\n }\n }\n return result;\n}\n","/**\n * Shared utilities for tree structures (Tree and TreeList).\n * @module tree-utils\n */\n\nimport type { Indexable } from \"../types/form-types\";\n\nexport interface BaseTreeNode {\n id_public: string;\n childrenNodes?: BaseTreeNode[];\n}\n\n/** Safe access to node children — encapsulates dynamic property access + cast */\nexport function getChildren<T>(node: T, field: string): T[] | undefined {\n const val = (node as Indexable)[field];\n return Array.isArray(val) ? (val as T[]) : undefined;\n}\n\nexport function findNode<T extends BaseTreeNode>(\n nodes: T[],\n id: string,\n childrenField: string = \"childrenNodes\"\n): T | null {\n for (const node of nodes) {\n if (node.id_public === id) return node;\n const children = getChildren(node, childrenField);\n if (children && children.length > 0) {\n const found = findNode(children, id, childrenField);\n if (found) return found;\n }\n }\n return null;\n}\n\nexport function getAllIds<T extends BaseTreeNode>(nodes: T[], childrenField: string = \"childrenNodes\"): string[] {\n const ids: string[] = [];\n const collect = (items: T[]) => {\n for (const node of items) {\n ids.push(node.id_public);\n const children = getChildren(node, childrenField);\n if (children && children.length > 0) {\n collect(children);\n }\n }\n };\n collect(nodes);\n return ids;\n}\n\nexport function updateNode<T extends BaseTreeNode>(\n nodes: T[],\n id: string,\n updater: (node: T) => T,\n childrenField: string = \"childrenNodes\"\n): T[] {\n return nodes.map((node) => {\n if (node.id_public === id) {\n return updater(node);\n }\n const children = getChildren(node, childrenField);\n if (children && children.length > 0) {\n return {\n ...node,\n [childrenField]: updateNode(children, id, updater, childrenField),\n };\n }\n return node;\n });\n}\n\nexport function removeNode<T extends BaseTreeNode>(\n nodes: T[],\n id: string,\n childrenField: string = \"childrenNodes\"\n): T[] {\n return nodes\n .filter((node) => node.id_public !== id)\n .map((node) => {\n const children = getChildren(node, childrenField);\n if (children && children.length > 0) {\n return {\n ...node,\n [childrenField]: removeNode(children, id, childrenField),\n };\n }\n return node;\n });\n}\n\nexport function addNode<T extends BaseTreeNode>(\n nodes: T[],\n parentId: string | null,\n newNode: T,\n childrenField: string = \"childrenNodes\"\n): T[] {\n if (parentId === null) {\n return [...nodes, newNode];\n }\n\n return nodes.map((node) => {\n if (node.id_public === parentId) {\n const children = getChildren(node, childrenField) || [];\n return {\n ...node,\n [childrenField]: [...children, newNode],\n };\n }\n const children = getChildren(node, childrenField);\n if (children && children.length > 0) {\n return {\n ...node,\n [childrenField]: addNode(children, parentId, newNode, childrenField),\n };\n }\n return node;\n });\n}\n\nexport function findParentId<T extends BaseTreeNode>(\n nodes: T[],\n id: string,\n childrenField: string = \"childrenNodes\",\n parentId: string | null = null\n): string | null {\n for (const node of nodes) {\n if (node.id_public === id) {\n return parentId;\n }\n const children = getChildren(node, childrenField);\n if (children && children.length > 0) {\n const found = findParentId(children, id, childrenField, node.id_public);\n if (found !== null) return found;\n }\n }\n return null;\n}\n"],"mappings":"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","names":["dayjs","customParseFormat","dayjs","customParseFormat","children"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/validation/field-validators.ts"],"sourcesContent":["import { getContentRes } from \"../adapters/content-adapter\";\n\n/**\n * Validate a phone number string.\n *\n * Accepts:\n * - E.164 format: +1234567890 (7-15 digits after +)\n * - National formats: (123) 456-7890, 123-456-7890, 123.456.7890\n * - International with spaces/dashes: +420 123 456 789\n *\n * Rejects:\n * - Strings with fewer than 7 digits (too short to be valid)\n * - Strings with more than 15 digits (exceeds E.164 max)\n * - Strings that are all non-digit characters\n * - Strings with letters or invalid special characters\n */\nexport function isPhoneNumber(str: string): boolean {\n // Must contain only phone-valid characters: digits, +, (, ), -, ., space, /\n if (!/^[+]?[()/0-9. -]+$/.test(str)) return false;\n\n // Extract just the digits to validate length\n const digits = str.replace(/\\D/g, \"\");\n\n // E.164: min 7 digits, max 15 digits (ITU-T E.164)\n if (digits.length < 7 || digits.length > 15) return false;\n\n // Reject obviously invalid patterns:\n // - Leading + must be followed by digits (not more symbols)\n if (str.startsWith(\"+\") && !/^\\+\\d/.test(str)) return false;\n\n // - Multiple consecutive + signs\n if (/\\+.*\\+/.test(str)) return false;\n\n // - + sign not at the beginning\n if (!str.startsWith(\"+\") && str.includes(\"+\")) return false;\n\n return true;\n}\n\nexport function validatePhoneNumber(value: string, required: boolean = false): string {\n const input = typeof value === \"string\" ? value.trim() : \"\";\n\n if (required && input.length === 0) {\n return getContentRes(\"admin-fill-value\");\n }\n\n if (input.length === 0) {\n return \"\";\n }\n\n if (input.includes(\";\")) {\n const parts = input\n .split(\";\")\n .map((x) => x.trim())\n .filter((x) => x.length > 0);\n\n if (required && parts.length === 0) {\n return getContentRes(\"admin-fill-value\");\n }\n\n for (const part of parts) {\n if (!isPhoneNumber(part)) {\n return getContentRes(\"admin-invalid-phone-number-format\");\n }\n }\n\n return \"\";\n }\n\n if (!isPhoneNumber(input)) {\n return getContentRes(\"admin-invalid-phone-number-format\");\n }\n\n return \"\";\n}\n\n/**\n * Validate an email address string.\n *\n * Improvements over the previous regex:\n * - Supports + tags (user+tag@example.com) — already supported, kept\n * - Supports longer TLDs (.museum, .company, .international)\n * - Requires TLD to be at least 2 characters (rejects user@localhost-like)\n * - Local part: letters, digits, and . _ + - (no leading/trailing/consecutive dots)\n * - Domain: ASCII letters, digits, hyphens, dots (no leading/trailing hyphens per label)\n */\nexport function isEmailAddress(str: string): boolean {\n // Local part: alphanumeric, plus . _ + -\n // No leading/trailing dot, no consecutive dots\n // Domain: labels separated by dots, each label starts/ends with alphanum\n // TLD must be at least 2 chars (letters only)\n return /^[a-zA-Z0-9](?:[a-zA-Z0-9._+-]*[a-zA-Z0-9])?@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$/.test(\n str,\n );\n}\n\nexport function isMultipleEmailAddress(str: string): boolean {\n if (str == null) {\n return false;\n }\n const parts = str.split(/[,;\\s]+/).filter((p) => p.includes(\"@\"));\n return parts.length >= 2;\n}\n\nexport function validateEmailAddress(value: string, required: boolean = false): string {\n const input = typeof value === \"string\" ? value.trim() : \"\";\n\n if (required && input.length === 0) {\n return getContentRes(\"admin-fill-value\");\n }\n\n if (input.length === 0) {\n return \"\";\n }\n\n if (input.includes(\";\")) {\n const parts = input\n .split(\";\")\n .map((x) => x.trim())\n .filter((x) => x.length > 0);\n\n if (required && parts.length === 0) {\n return getContentRes(\"admin-fill-value\");\n }\n\n for (const part of parts) {\n if (isMultipleEmailAddress(part)) {\n return getContentRes(\"admin-email-contains-multiple-addresses\");\n }\n if (!isEmailAddress(part)) {\n return getContentRes(\"admin-invalid-email-format\");\n }\n }\n\n return \"\";\n }\n\n if (isMultipleEmailAddress(input)) {\n return getContentRes(\"admin-email-contains-multiple-addresses\");\n }\n if (!isEmailAddress(input)) {\n return getContentRes(\"admin-invalid-email-format\");\n }\n return \"\";\n}\n\nexport function isAbsoluteUrl(str: string): boolean {\n if (!str) return false;\n\n const s = String(str).trim();\n if (!s || /\\s/.test(s)) return false;\n\n try {\n const url = new URL(s);\n const protocolOk = url.protocol === \"http:\" || url.protocol === \"https:\";\n if (!protocolOk) return false;\n if (!url.hostname) return false;\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport function validateAbsoluteUrl(value: string, required: boolean = false): string {\n const input = typeof value === \"string\" ? value.trim() : \"\";\n\n if (required && input.length === 0) {\n return getContentRes(\"admin-fill-value\");\n }\n\n if (input.length === 0) {\n return \"\";\n }\n\n if (!isAbsoluteUrl(input)) {\n return getContentRes(\"admin-invalid-url-format\");\n }\n\n return \"\";\n}\n\n/** Minimum password strength requirements: 8+ characters, uppercase + lowercase + digit + special character */\nexport function validatePasswordStrength(value: string): string {\n if (!value) return getContentRes(\"admin-fill-value\");\n if (value.length < 8) return getContentRes(\"admin-password-min-length\");\n if (!/[A-Z]/.test(value)) return getContentRes(\"admin-password-uppercase\");\n if (!/[a-z]/.test(value)) return getContentRes(\"admin-password-lowercase\");\n if (!/[0-9]/.test(value)) return getContentRes(\"admin-password-digit\");\n if (!/[^A-Za-z0-9]/.test(value)) return getContentRes(\"admin-password-special-char\");\n return \"\";\n}\n"],"mappings":"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","names":[]}