@spring-systems/core 0.8.4 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/dist/adapters/index.js +1 -56
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +1 -19
- package/dist/chunk-3OMNT22N.js +1 -0
- package/dist/chunk-4KRUU6MS.js +1 -0
- package/dist/chunk-6J2VFOKL.js +1 -0
- package/dist/chunk-7P4BJDQR.js +1 -0
- package/dist/chunk-AMXSATFF.js +1 -0
- package/dist/chunk-BMIRKMVX.js +1 -0
- package/dist/chunk-EVDFSWPU.js +1 -0
- package/dist/chunk-F3VXVDPQ.js +1 -0
- package/dist/chunk-GSQE2NEY.js +1 -0
- package/dist/chunk-HUASNNWD.js +1 -0
- package/dist/chunk-ICKHSEIX.js +1 -0
- package/dist/chunk-JRHMAY5G.js +1 -0
- package/dist/chunk-MNLYYTGZ.js +7 -0
- package/dist/chunk-OOVZTF74.js +1 -0
- package/dist/chunk-PNDXLNCU.js +1 -0
- package/dist/chunk-R3XYEEGR.js +1 -0
- package/dist/chunk-RKLYBW3O.js +1 -0
- package/dist/chunk-RVQHSQYF.js +3 -0
- package/dist/chunk-UT6X6RQM.js +1 -0
- package/dist/chunk-Y6DB43IE.js +3 -0
- package/dist/chunk-YMSSF2ZU.js +1 -0
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.js +1 -109
- package/dist/devtools/index.d.ts +2 -2
- package/dist/devtools/index.js +1 -67
- package/dist/errors/index.js +1 -21
- package/dist/events/index.js +1 -12
- package/dist/{framework-config-types-ClghA-zo.d.ts → framework-config-types-Cmy83YS6.d.ts} +4 -1
- package/dist/i18n/index.js +1 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -42
- package/dist/instance/index.d.ts +3 -3
- package/dist/instance/index.js +1 -37
- package/dist/logger/index.d.ts +2 -2
- package/dist/logger/index.js +1 -27
- package/dist/middleware/index.js +1 -23
- package/dist/plugins/index.d.ts +2 -2
- package/dist/plugins/index.js +1 -16
- package/dist/{runtime-env-config-Bs9HwewE.d.ts → runtime-env-config-B7vf3XX5.d.ts} +1 -1
- package/dist/{spring-instance-Bijjj8Mq.d.ts → spring-instance-CZk8Ju5T.d.ts} +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +1 -171
- package/dist/types/index.js +1 -72
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -772
- package/dist/validation/index.js +1 -147
- package/package.json +1 -1
- package/dist/adapters/index.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/chunk-EFUBAQCV.js +0 -94
- package/dist/chunk-EFUBAQCV.js.map +0 -1
- package/dist/chunk-F2SIMWZ5.js +0 -173
- package/dist/chunk-F2SIMWZ5.js.map +0 -1
- package/dist/chunk-F7WUQJH7.js +0 -399
- package/dist/chunk-F7WUQJH7.js.map +0 -1
- package/dist/chunk-GON7Q32Q.js +0 -176
- package/dist/chunk-GON7Q32Q.js.map +0 -1
- package/dist/chunk-GXU75LQX.js +0 -182
- package/dist/chunk-GXU75LQX.js.map +0 -1
- package/dist/chunk-HFELOXDQ.js +0 -110
- package/dist/chunk-HFELOXDQ.js.map +0 -1
- package/dist/chunk-KX32MU3I.js +0 -190
- package/dist/chunk-KX32MU3I.js.map +0 -1
- package/dist/chunk-MEWPYTWC.js +0 -284
- package/dist/chunk-MEWPYTWC.js.map +0 -1
- package/dist/chunk-N2L4TUC4.js +0 -34
- package/dist/chunk-N2L4TUC4.js.map +0 -1
- package/dist/chunk-NQQIVCLX.js +0 -47
- package/dist/chunk-NQQIVCLX.js.map +0 -1
- package/dist/chunk-OSSX443T.js +0 -146
- package/dist/chunk-OSSX443T.js.map +0 -1
- package/dist/chunk-PT4DIYUK.js +0 -78
- package/dist/chunk-PT4DIYUK.js.map +0 -1
- package/dist/chunk-QAVWXARR.js +0 -51
- package/dist/chunk-QAVWXARR.js.map +0 -1
- package/dist/chunk-RRWKDFAB.js +0 -143
- package/dist/chunk-RRWKDFAB.js.map +0 -1
- package/dist/chunk-RUCXSQEY.js +0 -42
- package/dist/chunk-RUCXSQEY.js.map +0 -1
- package/dist/chunk-S6RPCN5H.js +0 -64
- package/dist/chunk-S6RPCN5H.js.map +0 -1
- package/dist/chunk-S7MKRNMI.js +0 -153
- package/dist/chunk-S7MKRNMI.js.map +0 -1
- package/dist/chunk-SQB4F3EF.js +0 -55
- package/dist/chunk-SQB4F3EF.js.map +0 -1
- package/dist/chunk-UDT2RPX2.js +0 -43
- package/dist/chunk-UDT2RPX2.js.map +0 -1
- package/dist/chunk-VRMVN2UM.js +0 -17
- package/dist/chunk-VRMVN2UM.js.map +0 -1
- package/dist/chunk-XGNQEGV7.js +0 -391
- package/dist/chunk-XGNQEGV7.js.map +0 -1
- package/dist/config/index.js.map +0 -1
- package/dist/devtools/index.js.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/events/index.js.map +0 -1
- package/dist/i18n/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/instance/index.js.map +0 -1
- package/dist/logger/index.js.map +0 -1
- package/dist/middleware/index.js.map +0 -1
- package/dist/plugins/index.js.map +0 -1
- package/dist/testing/index.js.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/validation/index.js.map +0 -1
package/dist/chunk-PT4DIYUK.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// src/errors/errors.ts
|
|
2
|
-
var SpringError = class extends Error {
|
|
3
|
-
constructor(message, code) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.code = code;
|
|
6
|
-
this.name = "SpringError";
|
|
7
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
var SpringConfigError = class extends SpringError {
|
|
11
|
-
constructor(message) {
|
|
12
|
-
super(message, "CONFIG_ERROR");
|
|
13
|
-
this.name = "SpringConfigError";
|
|
14
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
var SpringValidationError = class extends SpringError {
|
|
18
|
-
constructor(message, field) {
|
|
19
|
-
super(message, "VALIDATION_ERROR");
|
|
20
|
-
this.field = field;
|
|
21
|
-
this.name = "SpringValidationError";
|
|
22
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
var SpringSlotError = class extends SpringError {
|
|
26
|
-
slotName;
|
|
27
|
-
constructor(slotName, message) {
|
|
28
|
-
super(`Slot "${slotName}": ${message}`, "SLOT_ERROR");
|
|
29
|
-
this.name = "SpringSlotError";
|
|
30
|
-
this.slotName = slotName;
|
|
31
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
var SpringApiError = class extends SpringError {
|
|
35
|
-
constructor(message, statusCode, endpoint, code = "API_ERROR") {
|
|
36
|
-
super(message, code);
|
|
37
|
-
this.statusCode = statusCode;
|
|
38
|
-
this.endpoint = endpoint;
|
|
39
|
-
this.name = "SpringApiError";
|
|
40
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
var SpringPluginError = class extends SpringError {
|
|
44
|
-
constructor(message, pluginName, code = "PLUGIN_ERROR") {
|
|
45
|
-
super(message, code);
|
|
46
|
-
this.pluginName = pluginName;
|
|
47
|
-
this.name = "SpringPluginError";
|
|
48
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
var SpringAdapterError = class extends SpringError {
|
|
52
|
-
constructor(message, adapterName, code = "ADAPTER_ERROR") {
|
|
53
|
-
super(message, code);
|
|
54
|
-
this.adapterName = adapterName;
|
|
55
|
-
this.name = "SpringAdapterError";
|
|
56
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
var SpringMiddlewareError = class extends SpringError {
|
|
60
|
-
constructor(message, slot, code = "MIDDLEWARE_ERROR") {
|
|
61
|
-
super(message, code);
|
|
62
|
-
this.slot = slot;
|
|
63
|
-
this.name = "SpringMiddlewareError";
|
|
64
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export {
|
|
69
|
-
SpringError,
|
|
70
|
-
SpringConfigError,
|
|
71
|
-
SpringValidationError,
|
|
72
|
-
SpringSlotError,
|
|
73
|
-
SpringApiError,
|
|
74
|
-
SpringPluginError,
|
|
75
|
-
SpringAdapterError,
|
|
76
|
-
SpringMiddlewareError
|
|
77
|
-
};
|
|
78
|
-
//# sourceMappingURL=chunk-PT4DIYUK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors/errors.ts"],"sourcesContent":["/**\n * Custom error classes for the SPRING framework.\n * Provides structured, typed errors for better error handling by consumers.\n * @module errors\n */\n\nexport class SpringError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = \"SpringError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SpringConfigError extends SpringError {\n constructor(message: string) {\n super(message, \"CONFIG_ERROR\");\n this.name = \"SpringConfigError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SpringValidationError extends SpringError {\n constructor(\n message: string,\n public readonly field?: string,\n ) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"SpringValidationError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SpringSlotError extends SpringError {\n public readonly slotName: string;\n\n constructor(slotName: string, message: string) {\n super(`Slot \"${slotName}\": ${message}`, \"SLOT_ERROR\");\n this.name = \"SpringSlotError\";\n this.slotName = slotName;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SpringApiError extends SpringError {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly endpoint: string,\n code = \"API_ERROR\" as const,\n ) {\n super(message, code);\n this.name = \"SpringApiError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SpringPluginError extends SpringError {\n constructor(\n message: string,\n public readonly pluginName: string,\n code = \"PLUGIN_ERROR\" as const,\n ) {\n super(message, code);\n this.name = \"SpringPluginError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SpringAdapterError extends SpringError {\n constructor(\n message: string,\n public readonly adapterName: string,\n code = \"ADAPTER_ERROR\" as const,\n ) {\n super(message, code);\n this.name = \"SpringAdapterError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SpringMiddlewareError extends SpringError {\n constructor(\n message: string,\n public readonly slot: string,\n code = \"MIDDLEWARE_ERROR\" as const,\n ) {\n super(message, code);\n this.name = \"SpringMiddlewareError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n"],"mappings":";AAMO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACnC,YACI,SACgB,MAClB;AACE,UAAM,OAAO;AAFG;AAGhB,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EACpD;AACJ;AAEO,IAAM,oBAAN,cAAgC,YAAY;AAAA,EAC/C,YAAY,SAAiB;AACzB,UAAM,SAAS,cAAc;AAC7B,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EACpD;AACJ;AAEO,IAAM,wBAAN,cAAoC,YAAY;AAAA,EACnD,YACI,SACgB,OAClB;AACE,UAAM,SAAS,kBAAkB;AAFjB;AAGhB,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EACpD;AACJ;AAEO,IAAM,kBAAN,cAA8B,YAAY;AAAA,EAC7B;AAAA,EAEhB,YAAY,UAAkB,SAAiB;AAC3C,UAAM,SAAS,QAAQ,MAAM,OAAO,IAAI,YAAY;AACpD,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EACpD;AACJ;AAEO,IAAM,iBAAN,cAA6B,YAAY;AAAA,EAC5C,YACI,SACgB,YACA,UAChB,OAAO,aACT;AACE,UAAM,SAAS,IAAI;AAJH;AACA;AAIhB,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EACpD;AACJ;AAEO,IAAM,oBAAN,cAAgC,YAAY;AAAA,EAC/C,YACI,SACgB,YAChB,OAAO,gBACT;AACE,UAAM,SAAS,IAAI;AAHH;AAIhB,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EACpD;AACJ;AAEO,IAAM,qBAAN,cAAiC,YAAY;AAAA,EAChD,YACI,SACgB,aAChB,OAAO,iBACT;AACE,UAAM,SAAS,IAAI;AAHH;AAIhB,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EACpD;AACJ;AAEO,IAAM,wBAAN,cAAoC,YAAY;AAAA,EACnD,YACI,SACgB,MAChB,OAAO,oBACT;AACE,UAAM,SAAS,IAAI;AAHH;AAIhB,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EACpD;AACJ;","names":[]}
|
package/dist/chunk-QAVWXARR.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
// src/types/form-types.ts
|
|
2
|
-
function getIdentifiableId(obj, key) {
|
|
3
|
-
if (typeof obj !== "object" || obj === null || Array.isArray(obj) || obj instanceof Date) return void 0;
|
|
4
|
-
const o = obj;
|
|
5
|
-
if (key) {
|
|
6
|
-
const val = o[key];
|
|
7
|
-
if (val !== void 0 && val !== null && (typeof val === "string" || typeof val === "number")) return val;
|
|
8
|
-
}
|
|
9
|
-
if (o.id_public !== void 0 && o.id_public !== null) return o.id_public;
|
|
10
|
-
if (o.id !== void 0 && o.id !== null) return o.id;
|
|
11
|
-
return void 0;
|
|
12
|
-
}
|
|
13
|
-
function storeBoundary(value) {
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
16
|
-
function toFormDataValue(value) {
|
|
17
|
-
return value;
|
|
18
|
-
}
|
|
19
|
-
function isFormFieldRuntime(val) {
|
|
20
|
-
return val !== null && typeof val === "object" && !Array.isArray(val) && !(val instanceof Date) && "value" in val && "title" in val;
|
|
21
|
-
}
|
|
22
|
-
function getField(state, key) {
|
|
23
|
-
if (!state) return void 0;
|
|
24
|
-
const val = state[key];
|
|
25
|
-
if (val && typeof val === "object" && !Array.isArray(val) && !(val instanceof Date)) {
|
|
26
|
-
return val;
|
|
27
|
-
}
|
|
28
|
-
return void 0;
|
|
29
|
-
}
|
|
30
|
-
function getSubState(state, key) {
|
|
31
|
-
if (!state) return void 0;
|
|
32
|
-
const val = state[key];
|
|
33
|
-
if (val && typeof val === "object" && !Array.isArray(val) && !(val instanceof Date)) {
|
|
34
|
-
return val;
|
|
35
|
-
}
|
|
36
|
-
return void 0;
|
|
37
|
-
}
|
|
38
|
-
function getStoreValue(state, key) {
|
|
39
|
-
return state[key];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export {
|
|
43
|
-
getIdentifiableId,
|
|
44
|
-
storeBoundary,
|
|
45
|
-
toFormDataValue,
|
|
46
|
-
isFormFieldRuntime,
|
|
47
|
-
getField,
|
|
48
|
-
getSubState,
|
|
49
|
-
getStoreValue
|
|
50
|
-
};
|
|
51
|
-
//# sourceMappingURL=chunk-QAVWXARR.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/form-types.ts"],"sourcesContent":["/**\n * Types for FormManager - runtime shapes of fields, details, and store API.\n * @module form-types\n */\n\nimport type { Permission } from \"./grid-types\";\n\n/** Concrete union type for form field values (JSON-like data from API) */\nexport type FormDataValue =\n | string\n | number\n | boolean\n | Date\n | null\n | undefined\n | FormDataValue[]\n | { [key: string]: FormDataValue };\n\n/**\n * Form field value — at runtime includes: string, number, boolean, Date, null, undefined,\n * arrays, plain objects (JSON data from API). TS interface limitation: cannot be expressed as a union\n * without losing compatibility with TS interfaces (they lack implicit index signatures).\n */\nexport type FormFieldValue = unknown;\n\n/** Zustand store state — top-level keys (detail, list, ...) */\nexport interface FormStoreState {\n [key: string]: FormFieldValue;\n}\n\n/** Indexable object with FormDataValue entries — concrete type for dynamic field access in utilities */\nexport interface IndexedFormData {\n [key: string]: FormDataValue;\n}\n\n/** Indexable object — concrete type for generic object traversal (deepCopy, tree access) */\nexport interface Indexable {\n [key: string]: FormDataValue;\n}\n\n/** Plain object of a collection item — with known meta keys */\nexport interface FormCollectionItem {\n __cid?: string;\n id_public?: string;\n [key: string]: FormDataValue;\n}\n\n/** Map of form fields — fieldName -> FormFieldRuntime */\nexport interface FormDetailFields {\n [key: string]: FormFieldRuntime;\n}\n\n/** Structure definition for a nested object/collection */\nexport interface FormStructureDef {\n [key: string]: FormFieldDefinitionRuntime;\n}\n\n/** Forward declaration for FormManagerImpl - avoids circular dependency */\nexport interface FormManagerRef {\n handleForm: <_T>(\n setState: (updater: (state: FormStoreState) => FormStoreState) => void,\n collectionKeys?: string[] | string,\n isFilter?: boolean,\n ) => FormCollectionActions;\n}\n\n/** Runtime shape of a field definition in structure (metadata without value) */\nexport interface FormFieldDefinitionRuntime {\n value?: FormDataValue;\n title?: string | ((item: FormCollectionItem) => string);\n resourceKey?: string;\n validation?: string | ((value: FormDataValue, structure: FormDetailFields) => string);\n required?: (structure: FormDetailFields) => boolean;\n skipValidation?: boolean;\n skipField?: boolean;\n help?: string;\n dataSource?: FormDataValue[];\n visible?: (structure: FormDetailFields) => boolean;\n disabled?: (structure: FormDetailFields) => boolean;\n onChange?: (value: FormDataValue, formManager: FormManagerRef) => void;\n [key: string]: FormFieldValue;\n}\n\n/** Core field identity and value. */\nexport interface FormFieldCore {\n value?: FormDataValue;\n items?: FormCollectionItem[];\n structure?: FormStructureDef;\n title?: string | ((item: FormCollectionItem) => string);\n resourceKey?: string;\n key?: string;\n help?: string;\n dataSource?: FormDataValue[];\n}\n\n/** Validation facet of a form field. */\nexport interface FormFieldValidation {\n validation?: string | ((value: FormDataValue, structure: FormDetailFields) => string);\n required?: (structure: FormDetailFields) => boolean;\n skipValidation?: boolean;\n skipField?: boolean;\n serverError?: string;\n forceDefault?: boolean;\n}\n\n/** Mutation methods for form fields. */\nexport interface FormFieldMutation {\n set?: (newValue: FormDataValue, index?: number, fieldName?: string) => void;\n add?: (parent: FormCollectionItem | null, defaultValue?: FormCollectionItem) => void;\n remove?: (item: FormCollectionItem) => void;\n}\n\n/** Lifecycle hooks for form fields (collection items, change events). */\nexport interface FormFieldLifecycle {\n onChange?: (value: FormDataValue, formManager: FormManagerRef) => void;\n onBeforeAdd?: (newItem: FormCollectionItem) => FormCollectionItem | undefined;\n onAfterAdd?: (addedItem: FormCollectionItem, allItems: FormCollectionItem[]) => void;\n onBeforeRemove?: (item: FormCollectionItem) => boolean | void;\n onAfterRemove?: (removedItem: FormCollectionItem) => void;\n}\n\n/** Visibility facet of a form field. */\nexport interface FormFieldVisibility {\n visible?: (structure: FormDetailFields) => boolean;\n disabled?: (structure: FormDetailFields) => boolean;\n}\n\n/** Runtime shape of a single form field — intersection of all facets. 100% backward-compatible. */\nexport interface FormFieldRuntime\n extends FormFieldCore, FormFieldValidation, FormFieldMutation, FormFieldLifecycle, FormFieldVisibility {\n [key: string]: FormFieldValue;\n}\n\nexport type FormChangedPath = string;\n\nexport interface FormChangesSnapshot {\n isChanged: boolean;\n changedPaths: FormChangedPath[];\n lastChangedPath?: FormChangedPath;\n}\n\nexport interface FormChangesApi {\n get(): FormChangesSnapshot;\n isChanged(path: FormChangedPath): boolean;\n markClean(): void;\n touch(path: FormChangedPath, previousValue: FormDataValue, currentValue: FormDataValue): void;\n setChanged(path: FormChangedPath, changed: boolean): void;\n exportBaseline?: () => FormStoreState;\n importBaseline?: (baseline: FormStoreState) => void;\n}\n\n/** Runtime state of the entire form detail - access to fields via string index, specific runtime keys */\nexport interface FormDetailRuntime extends FormStoreState {\n isEdited?: boolean;\n isValidated?: boolean;\n changes?: FormChangesApi;\n formManager?: FormManagerRef;\n form?: (collectionKeys?: string | string[]) => FormCollectionActions;\n}\n\n/** Minimal interface for createForm return value — Zustand store instance. */\nexport interface FormStoreInstance {\n getState: () => object;\n}\n\n/** Type for the Zustand-like store used by FormManager */\nexport interface FormStoreApi {\n getState: () => FormStoreState;\n setState: (updater: (s: FormStoreState) => FormStoreState) => void;\n getInitialState: () => FormStoreState;\n}\n\n/** Actions for manipulating collections in the form (add/remove/set) */\nexport interface FormCollectionActions {\n add: (parent: FormCollectionItem | null, newItem: FormCollectionItem) => void;\n remove: (itemToRemove: FormCollectionItem) => void;\n set: (newValue: FormFieldValue, key: string, item: FormCollectionItem) => void;\n}\n\n/** Non-generic version of FormManager for contexts where invariant M is not needed. */\nexport interface FormManagerBase {\n clearFields(): void;\n getFields(): (FormStoreState & { id_public?: string }) | null;\n setFields(value: FormStoreState, opts?: { markClean?: boolean }): void;\n get(key: string): FormFieldValue;\n set(key: string, value: FormFieldValue): void;\n getReadOnly(): boolean;\n setReadOnly(value: boolean): void;\n setIdPublic(value: string): void;\n validate(): boolean;\n save(\n url: string,\n fields: FormStoreState & { id_public?: string },\n validations?: boolean,\n ): Promise<FormStoreState | false>;\n load<T extends FormStoreState>(\n route: string,\n id_public?: string,\n detailData?: T,\n copyFrom?: string,\n ): Promise<T | undefined>;\n getPermissions(): Permission | undefined;\n setPermissions(permissions: Permission | undefined): void;\n transformDs(items: FormCollectionItem[], structure?: FormStructureDef): FormCollectionItem[];\n handleForm<_T>(\n setState: (updater: (state: FormStoreState) => FormStoreState) => void,\n collectionKeys?: string[] | string,\n isFilter?: boolean,\n ): FormCollectionActions;\n}\n\n/** Minimal interface for ListManager — covers .load() called from Detail/Context. */\nexport interface ListManagerLoadable {\n load(allowLoad?: boolean): Promise<object | null | undefined | void>;\n highlightRow(id_public: string): void;\n}\n\n/** Form readOnly state — minimal interface for the readOnly field in FormPageForm */\nexport interface ReadOnlyField {\n value?: boolean;\n set?: (newValue: boolean) => void;\n}\n\nexport interface Identifiable {\n id_public?: string | number;\n id?: string | number;\n [key: string]: FormFieldValue;\n}\n\n/** Extracts ID from an object — looks for `key`, `id_public`, `id` (in that order). */\nexport function getIdentifiableId(obj: unknown, key?: string): string | number | undefined {\n if (typeof obj !== \"object\" || obj === null || Array.isArray(obj) || obj instanceof Date) return undefined;\n const o = obj as Identifiable;\n if (key) {\n const val = o[key];\n if (val !== undefined && val !== null && (typeof val === \"string\" || typeof val === \"number\")) return val;\n }\n if (o.id_public !== undefined && o.id_public !== null) return o.id_public;\n if (o.id !== undefined && o.id !== null) return o.id;\n return undefined;\n}\n\n/** Zustand boundary cast — encapsulates `as unknown as T` for Store type invariance. */\nexport function storeBoundary<T>(value: FormFieldValue): T {\n return value as T;\n}\n\n/** Boundary function: narrows FormFieldValue (=unknown) to FormDataValue at the unknown→typed boundary. */\nexport function toFormDataValue(value: FormFieldValue): FormDataValue {\n return value as FormDataValue;\n}\n\n/** Type guard: checks if an unknown value is a FormFieldRuntime-like object (has `value` key and is not a Date/Array). */\nexport function isFormFieldRuntime(val: unknown): val is FormFieldRuntime {\n return (\n val !== null &&\n typeof val === \"object\" &&\n !Array.isArray(val) &&\n !(val instanceof Date) &&\n \"value\" in val &&\n \"title\" in val\n );\n}\n\n/** Typed accessor: returns FormFieldRuntime from FormStoreState[key] with a runtime type check. */\nexport function getField(state: FormStoreState | null | undefined, key: string): FormFieldRuntime | undefined {\n if (!state) return undefined;\n const val = state[key];\n if (val && typeof val === \"object\" && !Array.isArray(val) && !(val instanceof Date)) {\n return val as FormFieldRuntime;\n }\n return undefined;\n}\n\n/** Typed accessor: returns nested FormStoreState from FormStoreState[key] with a runtime check. */\nexport function getSubState(state: FormStoreState | null | undefined, key: string): FormStoreState | undefined {\n if (!state) return undefined;\n const val = state[key];\n if (val && typeof val === \"object\" && !Array.isArray(val) && !(val instanceof Date)) {\n return val as FormStoreState;\n }\n return undefined;\n}\n\n/** Typed accessor: returns a value from Zustand store state under the given key. */\nexport function getStoreValue<T>(state: object, key: string): T {\n return (state as FormStoreState)[key] as T;\n}\n\n/** Filter value in the TreeList/List filter system — includes lookup objects */\nexport type FilterFieldValue =\n | string\n | number\n | boolean\n | Date\n | null\n | undefined\n | { id_public?: string | number; value?: string | number; [key: string]: FilterFieldValue | undefined }\n | FilterFieldValue[];\n\n/** Shape of an error object from API/Axios */\nexport interface ApiErrorLike {\n code?: string;\n name?: string;\n message?: string;\n status?: number;\n data?: unknown;\n}\n\n/** Comparison function for the validation engine */\nexport type ComparisonFunction = (a: FormDataValue, b: FormDataValue) => boolean;\n\n/** Named validator function — registered via registerValidator, resolved at validation time. */\nexport type ValidatorFn = (value: FormDataValue, structure: FormDetailFields) => string;\n\nexport interface FormLifecycle<T = FormStoreState> {\n onBeforeLoad?: (id: string) => void | Promise<void>;\n onAfterLoad?: (data: FormStoreState) => void;\n onBeforeSave?: (fields: T) => T;\n onAfterSave?: (result: FormStoreState) => void;\n}\n"],"mappings":";AAsOO,SAAS,kBAAkB,KAAc,KAA2C;AACvF,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,KAAK,eAAe,KAAM,QAAO;AACjG,QAAM,IAAI;AACV,MAAI,KAAK;AACL,UAAM,MAAM,EAAE,GAAG;AACjB,QAAI,QAAQ,UAAa,QAAQ,SAAS,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAAW,QAAO;AAAA,EAC1G;AACA,MAAI,EAAE,cAAc,UAAa,EAAE,cAAc,KAAM,QAAO,EAAE;AAChE,MAAI,EAAE,OAAO,UAAa,EAAE,OAAO,KAAM,QAAO,EAAE;AAClD,SAAO;AACX;AAGO,SAAS,cAAiB,OAA0B;AACvD,SAAO;AACX;AAGO,SAAS,gBAAgB,OAAsC;AAClE,SAAO;AACX;AAGO,SAAS,mBAAmB,KAAuC;AACtE,SACI,QAAQ,QACR,OAAO,QAAQ,YACf,CAAC,MAAM,QAAQ,GAAG,KAClB,EAAE,eAAe,SACjB,WAAW,OACX,WAAW;AAEnB;AAGO,SAAS,SAAS,OAA0C,KAA2C;AAC1G,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,MAAM,GAAG;AACrB,MAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,KAAK,EAAE,eAAe,OAAO;AACjF,WAAO;AAAA,EACX;AACA,SAAO;AACX;AAGO,SAAS,YAAY,OAA0C,KAAyC;AAC3G,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,MAAM,GAAG;AACrB,MAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,KAAK,EAAE,eAAe,OAAO;AACjF,WAAO;AAAA,EACX;AACA,SAAO;AACX;AAGO,SAAS,cAAiB,OAAe,KAAgB;AAC5D,SAAQ,MAAyB,GAAG;AACxC;","names":[]}
|
package/dist/chunk-RRWKDFAB.js
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getField
|
|
3
|
-
} from "./chunk-QAVWXARR.js";
|
|
4
|
-
import {
|
|
5
|
-
getContentRes
|
|
6
|
-
} from "./chunk-NQQIVCLX.js";
|
|
7
|
-
import {
|
|
8
|
-
registerFallbackMigration
|
|
9
|
-
} from "./chunk-RUCXSQEY.js";
|
|
10
|
-
import {
|
|
11
|
-
logError
|
|
12
|
-
} from "./chunk-KX32MU3I.js";
|
|
13
|
-
import {
|
|
14
|
-
tryGetSpringInstance
|
|
15
|
-
} from "./chunk-EFUBAQCV.js";
|
|
16
|
-
|
|
17
|
-
// src/validation/validations.ts
|
|
18
|
-
var fallbackRegistry = /* @__PURE__ */ new Map();
|
|
19
|
-
registerFallbackMigration((instance) => {
|
|
20
|
-
if (fallbackRegistry.size === 0) return;
|
|
21
|
-
const target = instance.core.validatorRegistry;
|
|
22
|
-
for (const [name, validator] of fallbackRegistry) {
|
|
23
|
-
if (!target.has(name)) {
|
|
24
|
-
target.set(name, validator);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
function getRegistry() {
|
|
29
|
-
const instance = tryGetSpringInstance();
|
|
30
|
-
return instance ? instance.core.validatorRegistry : fallbackRegistry;
|
|
31
|
-
}
|
|
32
|
-
function registerValidator(name, fn) {
|
|
33
|
-
getRegistry().set(name, fn);
|
|
34
|
-
}
|
|
35
|
-
function getValidator(name) {
|
|
36
|
-
return getRegistry().get(name);
|
|
37
|
-
}
|
|
38
|
-
function getRegisteredValidators() {
|
|
39
|
-
return Array.from(getRegistry().keys());
|
|
40
|
-
}
|
|
41
|
-
function clearValidators() {
|
|
42
|
-
const instance = tryGetSpringInstance();
|
|
43
|
-
if (instance) {
|
|
44
|
-
instance.core.validatorRegistry.clear();
|
|
45
|
-
}
|
|
46
|
-
fallbackRegistry.clear();
|
|
47
|
-
}
|
|
48
|
-
var comparisonOps = {
|
|
49
|
-
"===": (a, b) => a === b,
|
|
50
|
-
"!==": (a, b) => a !== b,
|
|
51
|
-
">=": (a, b) => Number(a) >= Number(b),
|
|
52
|
-
"<=": (a, b) => Number(a) <= Number(b),
|
|
53
|
-
">": (a, b) => Number(a) > Number(b),
|
|
54
|
-
"<": (a, b) => Number(a) < Number(b)
|
|
55
|
-
};
|
|
56
|
-
function findOperatorOutsideQuotes(str) {
|
|
57
|
-
const ops = ["===", "!==", ">=", "<=", ">", "<"];
|
|
58
|
-
let inQuote = null;
|
|
59
|
-
let escaped = false;
|
|
60
|
-
for (let i = 0; i < str.length; i++) {
|
|
61
|
-
const ch = str[i];
|
|
62
|
-
if (escaped) {
|
|
63
|
-
escaped = false;
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (ch === "\\") {
|
|
67
|
-
escaped = true;
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
if (inQuote) {
|
|
71
|
-
if (ch === inQuote) inQuote = null;
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
if (ch === '"' || ch === "'") {
|
|
75
|
-
inQuote = ch;
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
for (const op of ops) {
|
|
79
|
-
if (str.startsWith(op, i)) {
|
|
80
|
-
return { op, index: i };
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
function parseValue(raw) {
|
|
87
|
-
const trimmed = raw.trim();
|
|
88
|
-
if (trimmed === "undefined") return void 0;
|
|
89
|
-
if (trimmed === "null") return null;
|
|
90
|
-
if (trimmed === "true") return true;
|
|
91
|
-
if (trimmed === "false") return false;
|
|
92
|
-
if (/^".*"$/.test(trimmed) || /^'.*'$/.test(trimmed)) return trimmed.slice(1, -1);
|
|
93
|
-
const num = Number(trimmed);
|
|
94
|
-
if (!isNaN(num) && trimmed !== "") return num;
|
|
95
|
-
return trimmed;
|
|
96
|
-
}
|
|
97
|
-
function resolveToken(token, structure) {
|
|
98
|
-
const trimmed = token.trim();
|
|
99
|
-
const fieldMatch = trimmed.match(/^\{(\w+)\}$/);
|
|
100
|
-
const fieldName = fieldMatch?.[1];
|
|
101
|
-
if (fieldName) {
|
|
102
|
-
const field = getField(structure, fieldName);
|
|
103
|
-
return field?.value ?? void 0;
|
|
104
|
-
}
|
|
105
|
-
return parseValue(trimmed);
|
|
106
|
-
}
|
|
107
|
-
function interpretValidation(structure, validationString) {
|
|
108
|
-
if (!structure || !validationString) return void 0;
|
|
109
|
-
try {
|
|
110
|
-
if (/&&|\|\|/.test(validationString)) {
|
|
111
|
-
logError(
|
|
112
|
-
"Validation.interpret",
|
|
113
|
-
`Compound expressions are not supported: "${validationString}". Use simple comparisons.`
|
|
114
|
-
);
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
const opInfo = findOperatorOutsideQuotes(validationString);
|
|
118
|
-
if (!opInfo) {
|
|
119
|
-
return resolveToken(validationString, structure);
|
|
120
|
-
}
|
|
121
|
-
const { op, index: opIndex } = opInfo;
|
|
122
|
-
const left = resolveToken(validationString.slice(0, opIndex), structure);
|
|
123
|
-
const right = resolveToken(validationString.slice(opIndex + op.length), structure);
|
|
124
|
-
const fn = op in comparisonOps ? comparisonOps[op] : void 0;
|
|
125
|
-
if (!fn) {
|
|
126
|
-
logError("Validation.interpret", `Unknown operator "${op}" in: "${validationString}"`);
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
return fn(left, right);
|
|
130
|
-
} catch (error) {
|
|
131
|
-
logError("Validation.interpret", error);
|
|
132
|
-
return getContentRes("admin-validation-error");
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export {
|
|
137
|
-
registerValidator,
|
|
138
|
-
getValidator,
|
|
139
|
-
getRegisteredValidators,
|
|
140
|
-
clearValidators,
|
|
141
|
-
interpretValidation
|
|
142
|
-
};
|
|
143
|
-
//# sourceMappingURL=chunk-RRWKDFAB.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/validation/validations.ts"],"sourcesContent":["import { getContentRes } from \"../adapters/content-adapter\";\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\nimport { logError } from \"../logger/logger\";\nimport type { ComparisonFunction, FormDataValue, FormDetailRuntime, ValidatorFn } from \"../types/form-types\";\nimport { getField } from \"../types/form-types\";\n\nexport type { ValidatorFn } from \"../types/form-types\";\n\n// Fallback for code that runs before SpringInstance is created\nconst fallbackRegistry = new Map<string, ValidatorFn>();\n\n// Migrate pre-mount validators so they remain available after instance initialization.\nregisterFallbackMigration((instance) => {\n if (fallbackRegistry.size === 0) return;\n\n const target = instance.core.validatorRegistry;\n for (const [name, validator] of fallbackRegistry) {\n if (!target.has(name)) {\n target.set(name, validator);\n }\n }\n});\n\nfunction getRegistry(): Map<string, ValidatorFn> {\n const instance = tryGetSpringInstance();\n return instance ? instance.core.validatorRegistry : fallbackRegistry;\n}\n\n/** Register a named validator (projects can add custom validators) */\nexport function registerValidator(name: string, fn: ValidatorFn): void {\n getRegistry().set(name, fn);\n}\n\n/** Get a registered validator by name */\nexport function getValidator(name: string): ValidatorFn | undefined {\n return getRegistry().get(name);\n}\n\n/** Get names of all registered validators. Useful for debugging and introspection. */\nexport function getRegisteredValidators(): string[] {\n return Array.from(getRegistry().keys());\n}\n\n/** Remove all registered validators from both instance and fallback stores. */\nexport function clearValidators(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.core.validatorRegistry.clear();\n }\n fallbackRegistry.clear();\n}\n\ntype ComparisonOperator = \"===\" | \"!==\" | \">=\" | \"<=\" | \">\" | \"<\";\n\nconst comparisonOps = {\n \"===\": (a, b) => a === b,\n \"!==\": (a, b) => a !== b,\n \">=\": (a, b) => Number(a) >= Number(b),\n \"<=\": (a, b) => Number(a) <= Number(b),\n \">\": (a, b) => Number(a) > Number(b),\n \"<\": (a, b) => Number(a) < Number(b),\n} satisfies Record<ComparisonOperator, ComparisonFunction>;\n\n/** Finds the first comparison operator outside quotes */\nfunction findOperatorOutsideQuotes(str: string): { op: string; index: number } | null {\n const ops = [\"===\", \"!==\", \">=\", \"<=\", \">\", \"<\"];\n let inQuote: string | null = null;\n let escaped = false;\n\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n\n if (escaped) {\n escaped = false;\n continue;\n }\n\n if (ch === \"\\\\\") {\n escaped = true;\n continue;\n }\n\n if (inQuote) {\n if (ch === inQuote) inQuote = null;\n continue;\n }\n\n if (ch === '\"' || ch === \"'\") {\n inQuote = ch;\n continue;\n }\n\n for (const op of ops) {\n if (str.startsWith(op, i)) {\n return { op, index: i };\n }\n }\n }\n\n return null;\n}\n\nfunction parseValue(raw: string) {\n const trimmed = raw.trim();\n if (trimmed === \"undefined\") return undefined;\n if (trimmed === \"null\") return null;\n if (trimmed === \"true\") return true;\n if (trimmed === \"false\") return false;\n if (/^\".*\"$/.test(trimmed) || /^'.*'$/.test(trimmed)) return trimmed.slice(1, -1);\n const num = Number(trimmed);\n if (!isNaN(num) && trimmed !== \"\") return num;\n return trimmed;\n}\n\n/**\n * Resolve a token in a validation expression.\n * Tokens are either field references `{fieldName}` or literal values.\n * Field values are returned directly (no string interpolation) to prevent injection.\n */\nfunction resolveToken(token: string, structure: FormDetailRuntime): FormDataValue {\n const trimmed = token.trim();\n // Field reference: {fieldName}\n const fieldMatch = trimmed.match(/^\\{(\\w+)\\}$/);\n const fieldName = fieldMatch?.[1];\n if (fieldName) {\n const field = getField(structure, fieldName);\n return field?.value ?? undefined;\n }\n return parseValue(trimmed);\n}\n\n/** Interprets dynamic validation from string — safe against injection. */\nexport function interpretValidation(structure: FormDetailRuntime, validationString: string) {\n if (!structure || !validationString) return undefined;\n try {\n if (/&&|\\|\\|/.test(validationString)) {\n logError(\n \"Validation.interpret\",\n `Compound expressions are not supported: \"${validationString}\". Use simple comparisons.`,\n );\n return false;\n }\n\n const opInfo = findOperatorOutsideQuotes(validationString);\n if (!opInfo) {\n // No operator — resolve as single token\n return resolveToken(validationString, structure);\n }\n\n const { op, index: opIndex } = opInfo;\n const left = resolveToken(validationString.slice(0, opIndex), structure);\n const right = resolveToken(validationString.slice(opIndex + op.length), structure);\n const fn = op in comparisonOps ? comparisonOps[op as ComparisonOperator] : undefined;\n if (!fn) {\n logError(\"Validation.interpret\", `Unknown operator \"${op}\" in: \"${validationString}\"`);\n return false;\n }\n return fn(left, right);\n } catch (error: unknown) {\n logError(\"Validation.interpret\", error);\n return getContentRes(\"admin-validation-error\");\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-RUCXSQEY.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
logError
|
|
3
|
-
} from "./chunk-KX32MU3I.js";
|
|
4
|
-
|
|
5
|
-
// src/instance/fallback-bridge.ts
|
|
6
|
-
function applyAllFallbacks(instance) {
|
|
7
|
-
const sorted = [...fallbackMigrations.values()].sort((a, b) => {
|
|
8
|
-
if (b.priority !== a.priority) return b.priority - a.priority;
|
|
9
|
-
return a.order - b.order;
|
|
10
|
-
});
|
|
11
|
-
for (const entry of sorted) {
|
|
12
|
-
try {
|
|
13
|
-
entry.migration(instance);
|
|
14
|
-
} catch (e) {
|
|
15
|
-
logError("FallbackBridge.migration", e);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
var fallbackMigrations = /* @__PURE__ */ new Map();
|
|
20
|
-
var registrationOrder = 0;
|
|
21
|
-
function registerFallbackMigration(migration, priority = 0) {
|
|
22
|
-
const existing = fallbackMigrations.get(migration);
|
|
23
|
-
if (existing) {
|
|
24
|
-
existing.priority = priority;
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
fallbackMigrations.set(migration, {
|
|
28
|
-
migration,
|
|
29
|
-
priority,
|
|
30
|
-
order: registrationOrder++
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
function clearFallbackMigrations() {
|
|
34
|
-
fallbackMigrations.clear();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export {
|
|
38
|
-
applyAllFallbacks,
|
|
39
|
-
registerFallbackMigration,
|
|
40
|
-
clearFallbackMigrations
|
|
41
|
-
};
|
|
42
|
-
//# sourceMappingURL=chunk-RUCXSQEY.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/instance/fallback-bridge.ts"],"sourcesContent":["/**\n * Centralized fallback bridge — migrates pre-mount state to a SpringInstance.\n *\n * Before SpringProvider mounts, various modules (config, adapters, event bus,\n * middleware) store state in module-level fallback variables. When SpringProvider\n * creates and sets the SpringInstance, this function migrates all fallback state\n * to the instance in a single call.\n *\n * This replaces the previous pattern where each module independently checked\n * tryGetSpringInstance() and maintained its own fallback state.\n *\n * @module fallback-bridge\n */\n\nimport { logError } from \"../logger/logger\";\nimport type { SpringInstance } from \"./spring-instance\";\n\n/**\n * Migrate all pre-mount fallback state into the given SpringInstance.\n * Called once by SpringProvider after instance creation.\n *\n * Modules register their fallback migration via registerFallbackMigration().\n * This allows packages (ui, api) to register their own migrations\n * without core needing to know about them.\n */\nexport function applyAllFallbacks(instance: SpringInstance): void {\n // Run all registered migrations from other modules in deterministic order.\n // Higher priority runs first; same priority preserves registration order.\n const sorted = [...fallbackMigrations.values()].sort((a, b) => {\n if (b.priority !== a.priority) return b.priority - a.priority;\n return a.order - b.order;\n });\n for (const entry of sorted) {\n try {\n entry.migration(instance);\n } catch (e) {\n logError(\"FallbackBridge.migration\", e);\n }\n }\n}\n\ntype FallbackMigration = (instance: SpringInstance) => void;\ninterface FallbackMigrationEntry {\n migration: FallbackMigration;\n priority: number;\n order: number;\n}\nconst fallbackMigrations = new Map<FallbackMigration, FallbackMigrationEntry>();\nlet registrationOrder = 0;\n\n/**\n * Register a fallback migration function.\n * Called by modules that maintain pre-mount fallback state (adapters, event bus, etc.)\n * to ensure their state is migrated when SpringProvider mounts.\n */\nexport function registerFallbackMigration(migration: FallbackMigration, priority = 0): void {\n const existing = fallbackMigrations.get(migration);\n if (existing) {\n existing.priority = priority;\n return;\n }\n fallbackMigrations.set(migration, {\n migration,\n priority,\n order: registrationOrder++,\n });\n}\n\n/** Clear all registered migrations. For testing only. */\nexport function clearFallbackMigrations(): void {\n fallbackMigrations.clear();\n}\n"],"mappings":";;;;;AAyBO,SAAS,kBAAkB,UAAgC;AAG9D,QAAM,SAAS,CAAC,GAAG,mBAAmB,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AAC3D,QAAI,EAAE,aAAa,EAAE,SAAU,QAAO,EAAE,WAAW,EAAE;AACrD,WAAO,EAAE,QAAQ,EAAE;AAAA,EACvB,CAAC;AACD,aAAW,SAAS,QAAQ;AACxB,QAAI;AACA,YAAM,UAAU,QAAQ;AAAA,IAC5B,SAAS,GAAG;AACR,eAAS,4BAA4B,CAAC;AAAA,IAC1C;AAAA,EACJ;AACJ;AAQA,IAAM,qBAAqB,oBAAI,IAA+C;AAC9E,IAAI,oBAAoB;AAOjB,SAAS,0BAA0B,WAA8B,WAAW,GAAS;AACxF,QAAM,WAAW,mBAAmB,IAAI,SAAS;AACjD,MAAI,UAAU;AACV,aAAS,WAAW;AACpB;AAAA,EACJ;AACA,qBAAmB,IAAI,WAAW;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACX,CAAC;AACL;AAGO,SAAS,0BAAgC;AAC5C,qBAAmB,MAAM;AAC7B;","names":[]}
|
package/dist/chunk-S6RPCN5H.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
registerFallbackMigration
|
|
3
|
-
} from "./chunk-RUCXSQEY.js";
|
|
4
|
-
import {
|
|
5
|
-
tryGetSpringInstance
|
|
6
|
-
} from "./chunk-EFUBAQCV.js";
|
|
7
|
-
|
|
8
|
-
// src/adapters/telemetry-adapter.ts
|
|
9
|
-
var noopAdapter = {
|
|
10
|
-
trackEvent: () => {
|
|
11
|
-
},
|
|
12
|
-
trackError: () => {
|
|
13
|
-
},
|
|
14
|
-
trackTiming: () => {
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
var fallbackAdapter = noopAdapter;
|
|
18
|
-
var UI_KEY = /* @__PURE__ */ Symbol.for("spring:telemetryAdapter");
|
|
19
|
-
registerFallbackMigration((instance) => {
|
|
20
|
-
if (fallbackAdapter !== noopAdapter) {
|
|
21
|
-
instance.ui[UI_KEY] = fallbackAdapter;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
function setTelemetryAdapter(adapter) {
|
|
25
|
-
const instance = tryGetSpringInstance();
|
|
26
|
-
if (instance) {
|
|
27
|
-
instance.ui[UI_KEY] = adapter;
|
|
28
|
-
} else {
|
|
29
|
-
fallbackAdapter = adapter;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function getTelemetryAdapter() {
|
|
33
|
-
const instance = tryGetSpringInstance();
|
|
34
|
-
if (instance) {
|
|
35
|
-
return instance.ui[UI_KEY] ?? noopAdapter;
|
|
36
|
-
}
|
|
37
|
-
return fallbackAdapter;
|
|
38
|
-
}
|
|
39
|
-
function clearTelemetryAdapter() {
|
|
40
|
-
const instance = tryGetSpringInstance();
|
|
41
|
-
if (instance) {
|
|
42
|
-
delete instance.ui[UI_KEY];
|
|
43
|
-
}
|
|
44
|
-
fallbackAdapter = noopAdapter;
|
|
45
|
-
}
|
|
46
|
-
function trackEvent(name, data) {
|
|
47
|
-
getTelemetryAdapter().trackEvent(name, data);
|
|
48
|
-
}
|
|
49
|
-
function trackError(error, context) {
|
|
50
|
-
getTelemetryAdapter().trackError(error, context);
|
|
51
|
-
}
|
|
52
|
-
function trackTiming(metric, durationMs, data) {
|
|
53
|
-
getTelemetryAdapter().trackTiming(metric, durationMs, data);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export {
|
|
57
|
-
setTelemetryAdapter,
|
|
58
|
-
getTelemetryAdapter,
|
|
59
|
-
clearTelemetryAdapter,
|
|
60
|
-
trackEvent,
|
|
61
|
-
trackError,
|
|
62
|
-
trackTiming
|
|
63
|
-
};
|
|
64
|
-
//# sourceMappingURL=chunk-S6RPCN5H.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/telemetry-adapter.ts"],"sourcesContent":["/**\n * Telemetry adapter — provides hooks for observability, monitoring, and analytics.\n *\n * Enterprise deployments can integrate with APM tools (DataDog, New Relic, etc.)\n * by setting a custom telemetry adapter. The framework emits telemetry events\n * at key lifecycle points (form loads, API calls, errors, etc.)\n *\n * @example\n * ```ts\n * import { setTelemetryAdapter } from \"@spring-systems/core/adapters\";\n *\n * setTelemetryAdapter({\n * trackEvent(name, data) {\n * datadogRum.addAction(name, data);\n * },\n * trackError(error, context) {\n * Sentry.captureException(error, { extra: context });\n * },\n * trackTiming(metric, durationMs, data) {\n * performance.measure(metric, { duration: durationMs });\n * },\n * });\n * ```\n *\n * @module telemetry-adapter\n */\n\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\n\nexport interface TelemetryAdapter {\n /**\n * Track a named event with optional structured data.\n * Called on form save, list load, login, navigation, etc.\n */\n trackEvent(name: string, data?: Record<string, unknown>): void;\n\n /**\n * Track an error occurrence with optional context.\n * Called on unhandled errors, API failures, middleware errors, etc.\n */\n trackError(error: Error | unknown, context?: Record<string, unknown>): void;\n\n /**\n * Track a timing measurement (e.g. API latency, form render time).\n * @param metric - Metric name (e.g. \"api.response_time\", \"form.load_time\")\n * @param durationMs - Duration in milliseconds\n * @param data - Optional context data\n */\n trackTiming(metric: string, durationMs: number, data?: Record<string, unknown>): void;\n}\n\nconst noopAdapter = {\n trackEvent: () => {},\n trackError: () => {},\n trackTiming: () => {},\n} satisfies TelemetryAdapter;\n\nlet fallbackAdapter: TelemetryAdapter = noopAdapter;\n\nconst UI_KEY = Symbol.for(\"spring:telemetryAdapter\");\n\n// Migrate fallback telemetry adapter to SpringInstance when SpringProvider mounts\nregisterFallbackMigration((instance) => {\n if (fallbackAdapter !== noopAdapter) {\n instance.ui[UI_KEY] = fallbackAdapter;\n }\n});\n\nexport function setTelemetryAdapter(adapter: TelemetryAdapter): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.ui[UI_KEY] = adapter;\n } else {\n fallbackAdapter = adapter;\n }\n}\n\nexport function getTelemetryAdapter(): TelemetryAdapter {\n const instance = tryGetSpringInstance();\n if (instance) {\n return (instance.ui[UI_KEY] as TelemetryAdapter) ?? noopAdapter;\n }\n return fallbackAdapter;\n}\n\n/** Reset telemetry adapter to no-op defaults. For testing/integration teardown only. */\nexport function clearTelemetryAdapter(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n delete instance.ui[UI_KEY];\n }\n fallbackAdapter = noopAdapter;\n}\n\n/**\n * Convenience helper to track an event via the configured telemetry adapter.\n * Safe to call even if no adapter is configured (no-op).\n */\nexport function trackEvent(name: string, data?: Record<string, unknown>): void {\n getTelemetryAdapter().trackEvent(name, data);\n}\n\n/**\n * Convenience helper to track an error via the configured telemetry adapter.\n */\nexport function trackError(error: Error | unknown, context?: Record<string, unknown>): void {\n getTelemetryAdapter().trackError(error, context);\n}\n\n/**\n * Convenience helper to track timing via the configured telemetry adapter.\n */\nexport function trackTiming(metric: string, durationMs: number, data?: Record<string, unknown>): void {\n getTelemetryAdapter().trackTiming(metric, durationMs, data);\n}\n"],"mappings":";;;;;;;;AAoDA,IAAM,cAAc;AAAA,EAChB,YAAY,MAAM;AAAA,EAAC;AAAA,EACnB,YAAY,MAAM;AAAA,EAAC;AAAA,EACnB,aAAa,MAAM;AAAA,EAAC;AACxB;AAEA,IAAI,kBAAoC;AAExC,IAAM,SAAS,uBAAO,IAAI,yBAAyB;AAGnD,0BAA0B,CAAC,aAAa;AACpC,MAAI,oBAAoB,aAAa;AACjC,aAAS,GAAG,MAAM,IAAI;AAAA,EAC1B;AACJ,CAAC;AAEM,SAAS,oBAAoB,SAAiC;AACjE,QAAM,WAAW,qBAAqB;AACtC,MAAI,UAAU;AACV,aAAS,GAAG,MAAM,IAAI;AAAA,EAC1B,OAAO;AACH,sBAAkB;AAAA,EACtB;AACJ;AAEO,SAAS,sBAAwC;AACpD,QAAM,WAAW,qBAAqB;AACtC,MAAI,UAAU;AACV,WAAQ,SAAS,GAAG,MAAM,KAA0B;AAAA,EACxD;AACA,SAAO;AACX;AAGO,SAAS,wBAA8B;AAC1C,QAAM,WAAW,qBAAqB;AACtC,MAAI,UAAU;AACV,WAAO,SAAS,GAAG,MAAM;AAAA,EAC7B;AACA,oBAAkB;AACtB;AAMO,SAAS,WAAW,MAAc,MAAsC;AAC3E,sBAAoB,EAAE,WAAW,MAAM,IAAI;AAC/C;AAKO,SAAS,WAAW,OAAwB,SAAyC;AACxF,sBAAoB,EAAE,WAAW,OAAO,OAAO;AACnD;AAKO,SAAS,YAAY,QAAgB,YAAoB,MAAsC;AAClG,sBAAoB,EAAE,YAAY,QAAQ,YAAY,IAAI;AAC9D;","names":[]}
|
package/dist/chunk-S7MKRNMI.js
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
registerFallbackMigration
|
|
3
|
-
} from "./chunk-RUCXSQEY.js";
|
|
4
|
-
import {
|
|
5
|
-
tryGetSpringInstance
|
|
6
|
-
} from "./chunk-EFUBAQCV.js";
|
|
7
|
-
|
|
8
|
-
// src/config/capabilities.ts
|
|
9
|
-
var UI_KEY = /* @__PURE__ */ Symbol.for("spring:capabilities");
|
|
10
|
-
function cloneValue(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
11
|
-
if (value === null || typeof value !== "object") {
|
|
12
|
-
return value;
|
|
13
|
-
}
|
|
14
|
-
const obj = value;
|
|
15
|
-
if (seen.has(obj)) return seen.get(obj);
|
|
16
|
-
if (value instanceof Date) {
|
|
17
|
-
return new Date(value.getTime());
|
|
18
|
-
}
|
|
19
|
-
if (value instanceof RegExp) {
|
|
20
|
-
return new RegExp(value.source, value.flags);
|
|
21
|
-
}
|
|
22
|
-
if (value instanceof Map) {
|
|
23
|
-
const cloned = /* @__PURE__ */ new Map();
|
|
24
|
-
seen.set(obj, cloned);
|
|
25
|
-
for (const [k, v] of value.entries()) {
|
|
26
|
-
cloned.set(cloneValue(k, seen), cloneValue(v, seen));
|
|
27
|
-
}
|
|
28
|
-
return cloned;
|
|
29
|
-
}
|
|
30
|
-
if (value instanceof Set) {
|
|
31
|
-
const cloned = /* @__PURE__ */ new Set();
|
|
32
|
-
seen.set(obj, cloned);
|
|
33
|
-
for (const item of value.values()) {
|
|
34
|
-
cloned.add(cloneValue(item, seen));
|
|
35
|
-
}
|
|
36
|
-
return cloned;
|
|
37
|
-
}
|
|
38
|
-
if (Array.isArray(value)) {
|
|
39
|
-
const cloned = [];
|
|
40
|
-
seen.set(obj, cloned);
|
|
41
|
-
for (const item of value) {
|
|
42
|
-
cloned.push(cloneValue(item, seen));
|
|
43
|
-
}
|
|
44
|
-
return cloned;
|
|
45
|
-
}
|
|
46
|
-
const proto = Object.getPrototypeOf(value);
|
|
47
|
-
const clonedObj = Object.create(proto);
|
|
48
|
-
seen.set(obj, clonedObj);
|
|
49
|
-
for (const key of Reflect.ownKeys(value)) {
|
|
50
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
51
|
-
if (!descriptor) continue;
|
|
52
|
-
if ("value" in descriptor) {
|
|
53
|
-
descriptor.value = cloneValue(descriptor.value, seen);
|
|
54
|
-
}
|
|
55
|
-
Object.defineProperty(clonedObj, key, descriptor);
|
|
56
|
-
}
|
|
57
|
-
return clonedObj;
|
|
58
|
-
}
|
|
59
|
-
function deepFreeze(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
60
|
-
if (value !== null && typeof value === "object") {
|
|
61
|
-
const obj = value;
|
|
62
|
-
if (seen.has(obj)) return value;
|
|
63
|
-
seen.add(obj);
|
|
64
|
-
if (value instanceof Map) {
|
|
65
|
-
for (const [k, v] of value.entries()) {
|
|
66
|
-
deepFreeze(k, seen);
|
|
67
|
-
deepFreeze(v, seen);
|
|
68
|
-
}
|
|
69
|
-
Object.freeze(value);
|
|
70
|
-
return value;
|
|
71
|
-
}
|
|
72
|
-
if (value instanceof Set) {
|
|
73
|
-
for (const item of value.values()) {
|
|
74
|
-
deepFreeze(item, seen);
|
|
75
|
-
}
|
|
76
|
-
Object.freeze(value);
|
|
77
|
-
return value;
|
|
78
|
-
}
|
|
79
|
-
for (const key of Reflect.ownKeys(value)) {
|
|
80
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
81
|
-
if (!descriptor || !("value" in descriptor)) continue;
|
|
82
|
-
deepFreeze(descriptor.value, seen);
|
|
83
|
-
}
|
|
84
|
-
Object.freeze(value);
|
|
85
|
-
}
|
|
86
|
-
return value;
|
|
87
|
-
}
|
|
88
|
-
function getStore() {
|
|
89
|
-
const instance = tryGetSpringInstance();
|
|
90
|
-
if (instance) {
|
|
91
|
-
if (!instance.ui[UI_KEY]) {
|
|
92
|
-
const emptyStore = {};
|
|
93
|
-
instance.ui[UI_KEY] = emptyStore;
|
|
94
|
-
}
|
|
95
|
-
return instance.ui[UI_KEY];
|
|
96
|
-
}
|
|
97
|
-
return fallbackStore;
|
|
98
|
-
}
|
|
99
|
-
var fallbackStore = {};
|
|
100
|
-
registerFallbackMigration((instance) => {
|
|
101
|
-
if (Object.keys(fallbackStore).length === 0) return;
|
|
102
|
-
const existing = instance.ui[UI_KEY];
|
|
103
|
-
if (!existing || typeof existing !== "object") {
|
|
104
|
-
instance.ui[UI_KEY] = { ...fallbackStore };
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
const instanceStore = existing;
|
|
108
|
-
for (const [key, value] of Object.entries(fallbackStore)) {
|
|
109
|
-
if (!(key in instanceStore)) {
|
|
110
|
-
instanceStore[key] = value;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
function configureCapabilities(capabilities) {
|
|
115
|
-
const store = getStore();
|
|
116
|
-
Object.assign(store, capabilities);
|
|
117
|
-
}
|
|
118
|
-
function hasCapability(name) {
|
|
119
|
-
const store = getStore();
|
|
120
|
-
const value = store[name];
|
|
121
|
-
if (value === void 0 || value === null) return false;
|
|
122
|
-
if (typeof value === "boolean") return value;
|
|
123
|
-
if (typeof value === "object" && value !== null && "enabled" in value) {
|
|
124
|
-
return !!value.enabled;
|
|
125
|
-
}
|
|
126
|
-
return !!value;
|
|
127
|
-
}
|
|
128
|
-
function getCapability(name) {
|
|
129
|
-
return getStore()[name];
|
|
130
|
-
}
|
|
131
|
-
function getCapabilities() {
|
|
132
|
-
return deepFreeze(cloneValue(getStore()));
|
|
133
|
-
}
|
|
134
|
-
function getRegisteredCapabilityNames() {
|
|
135
|
-
return Object.keys(getStore());
|
|
136
|
-
}
|
|
137
|
-
function clearCapabilities() {
|
|
138
|
-
const instance = tryGetSpringInstance();
|
|
139
|
-
if (instance) {
|
|
140
|
-
instance.ui[UI_KEY] = {};
|
|
141
|
-
}
|
|
142
|
-
fallbackStore = {};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export {
|
|
146
|
-
configureCapabilities,
|
|
147
|
-
hasCapability,
|
|
148
|
-
getCapability,
|
|
149
|
-
getCapabilities,
|
|
150
|
-
getRegisteredCapabilityNames,
|
|
151
|
-
clearCapabilities
|
|
152
|
-
};
|
|
153
|
-
//# sourceMappingURL=chunk-S7MKRNMI.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/capabilities.ts"],"sourcesContent":["/**\n * Feature capability system for enterprise SPRING deployments.\n *\n * Capabilities allow framework consumers to enable/disable features\n * per client deployment. Plugins can declare required capabilities\n * and the framework checks them at registration time.\n *\n * @example\n * ```ts\n * // In project-config.ts:\n * configureCapabilities({\n * charts: true,\n * advancedFiltering: true,\n * bulkOperations: false,\n * export: { enabled: true, formats: [\"xlsx\", \"pdf\"] },\n * });\n *\n * // In a plugin:\n * if (hasCapability(\"advancedFiltering\")) {\n * registerMiddleware(\"list:beforeLoad\", advancedFilterMiddleware);\n * }\n *\n * // In a component:\n * const canExport = hasCapability(\"export\");\n * ```\n *\n * @module capabilities\n */\n\nimport { tryGetSpringInstance } from \"../instance/current-instance\";\nimport { registerFallbackMigration } from \"../instance/fallback-bridge\";\nimport type { CapabilityMap } from \"./capability-types\";\n\nexport type { CapabilityMap } from \"./capability-types\";\n\n/**\n * Extensible capability map. Consumers and plugins extend via declaration merging:\n *\n * @example\n * ```ts\n * declare module \"@spring-systems/core/config\" {\n * interface CapabilityMap {\n * \"myPlugin:feature\": boolean;\n * }\n * }\n * ```\n */\nconst UI_KEY = Symbol.for(\"spring:capabilities\");\n\ntype CapabilityStore = Partial<CapabilityMap> & Record<string, unknown>;\n\nfunction cloneValue<T>(value: T, seen = new WeakMap<object, unknown>()): T {\n if (value === null || typeof value !== \"object\") {\n return value;\n }\n\n const obj = value as object;\n if (seen.has(obj)) return seen.get(obj) as T;\n\n if (value instanceof Date) {\n return new Date(value.getTime()) as T;\n }\n if (value instanceof RegExp) {\n return new RegExp(value.source, value.flags) as T;\n }\n if (value instanceof Map) {\n const cloned = new Map<unknown, unknown>();\n seen.set(obj, cloned);\n for (const [k, v] of value.entries()) {\n cloned.set(cloneValue(k, seen), cloneValue(v, seen));\n }\n return cloned as T;\n }\n if (value instanceof Set) {\n const cloned = new Set<unknown>();\n seen.set(obj, cloned);\n for (const item of value.values()) {\n cloned.add(cloneValue(item, seen));\n }\n return cloned as T;\n }\n if (Array.isArray(value)) {\n const cloned: unknown[] = [];\n seen.set(obj, cloned);\n for (const item of value) {\n cloned.push(cloneValue(item, seen));\n }\n return cloned as T;\n }\n\n const proto = Object.getPrototypeOf(value);\n const clonedObj = Object.create(proto) as Record<PropertyKey, unknown>;\n seen.set(obj, clonedObj);\n for (const key of Reflect.ownKeys(value)) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor) continue;\n if (\"value\" in descriptor) {\n descriptor.value = cloneValue(descriptor.value, seen);\n }\n Object.defineProperty(clonedObj, key, descriptor);\n }\n return clonedObj as T;\n}\n\nfunction deepFreeze<T>(value: T, seen = new WeakSet<object>()): T {\n if (value !== null && typeof value === \"object\") {\n const obj = value as object;\n if (seen.has(obj)) return value;\n seen.add(obj);\n\n if (value instanceof Map) {\n for (const [k, v] of value.entries()) {\n deepFreeze(k, seen);\n deepFreeze(v, seen);\n }\n Object.freeze(value);\n return value;\n }\n\n if (value instanceof Set) {\n for (const item of value.values()) {\n deepFreeze(item, seen);\n }\n Object.freeze(value);\n return value;\n }\n\n for (const key of Reflect.ownKeys(value)) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor || !(\"value\" in descriptor)) continue;\n deepFreeze(descriptor.value, seen);\n }\n Object.freeze(value);\n }\n return value;\n}\n\nfunction getStore(): CapabilityStore {\n const instance = tryGetSpringInstance();\n if (instance) {\n if (!instance.ui[UI_KEY]) {\n const emptyStore: CapabilityStore = {};\n instance.ui[UI_KEY] = emptyStore;\n }\n return instance.ui[UI_KEY] as CapabilityStore;\n }\n return fallbackStore;\n}\n\nlet fallbackStore: CapabilityStore = {};\n\n// Migrate fallback capabilities to SpringInstance when SpringProvider mounts.\n// Merge is non-destructive: explicit instance values win over fallback values.\nregisterFallbackMigration((instance) => {\n if (Object.keys(fallbackStore).length === 0) return;\n\n const existing = instance.ui[UI_KEY];\n if (!existing || typeof existing !== \"object\") {\n instance.ui[UI_KEY] = { ...fallbackStore };\n return;\n }\n\n const instanceStore = existing as CapabilityStore;\n for (const [key, value] of Object.entries(fallbackStore)) {\n if (!(key in instanceStore)) {\n instanceStore[key] = value;\n }\n }\n});\n\n/**\n * Configure feature capabilities for this deployment.\n * Merges with existing capabilities (does not replace).\n */\nexport function configureCapabilities(capabilities: Partial<CapabilityMap> & Record<string, unknown>): void {\n const store = getStore();\n Object.assign(store, capabilities);\n}\n\n/**\n * Check if a capability is enabled.\n * Returns false for unknown/unconfigured capabilities.\n */\nexport function hasCapability<K extends keyof CapabilityMap>(name: K): boolean {\n const store = getStore();\n const value = store[name];\n if (value === undefined || value === null) return false;\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"object\" && value !== null && \"enabled\" in value) {\n return !!(value as { enabled: boolean }).enabled;\n }\n return !!value;\n}\n\n/**\n * Get the full capability configuration for a feature.\n * Returns undefined if the capability is not configured.\n */\nexport function getCapability<K extends keyof CapabilityMap>(name: K): CapabilityMap[K] | undefined {\n return getStore()[name] as CapabilityMap[K] | undefined;\n}\n\n/** Get all configured capabilities. */\nexport function getCapabilities(): Readonly<CapabilityStore> {\n return deepFreeze(cloneValue(getStore()));\n}\n\n/**\n * Get the names of all currently registered (configured) capabilities.\n * Useful for introspection and for validating that plugin capability\n * references point to actually-configured features.\n */\nexport function getRegisteredCapabilityNames(): string[] {\n return Object.keys(getStore());\n}\n\n/** Reset all capabilities. For testing only. */\nexport function clearCapabilities(): void {\n const instance = tryGetSpringInstance();\n if (instance) {\n instance.ui[UI_KEY] = {};\n }\n fallbackStore = {};\n}\n"],"mappings":"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","names":[]}
|