@stonecrop/stonecrop 0.9.0 → 0.9.1
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/package.json +3 -3
- package/dist/src/stonecrop.js +0 -254
- package/dist/tests/setup.d.ts +0 -5
- package/dist/tests/setup.d.ts.map +0 -1
- package/dist/tests/setup.js +0 -15
- /package/dist/{src/composable.js → composable.js} +0 -0
- /package/dist/{src/composables → composables}/operation-log.js +0 -0
- /package/dist/{src/doctype.js → doctype.js} +0 -0
- /package/dist/{src/exceptions.js → exceptions.js} +0 -0
- /package/dist/{src/field-triggers.js → field-triggers.js} +0 -0
- /package/dist/{src/index.js → index.js} +0 -0
- /package/dist/{src/plugins → plugins}/index.js +0 -0
- /package/dist/{src/registry.js → registry.js} +0 -0
- /package/dist/{src/schema-validator.js → schema-validator.js} +0 -0
- /package/dist/{src/stores → stores}/hst.js +0 -0
- /package/dist/{src/stores → stores}/index.js +0 -0
- /package/dist/{src/stores → stores}/operation-log.js +0 -0
- /package/dist/{src/types → types}/field-triggers.js +0 -0
- /package/dist/{src/types → types}/index.js +0 -0
- /package/dist/{src/types → types}/operation-log.js +0 -0
- /package/dist/{src/types → types}/registry.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stonecrop/stonecrop",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": {
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"vue-router": "^5.0.2",
|
|
60
60
|
"vite": "^7.3.1",
|
|
61
61
|
"vitest": "^4.0.18",
|
|
62
|
-
"@stonecrop/aform": "0.9.
|
|
63
|
-
"@stonecrop/atable": "0.9.
|
|
62
|
+
"@stonecrop/aform": "0.9.1",
|
|
63
|
+
"@stonecrop/atable": "0.9.1",
|
|
64
64
|
"stonecrop-rig": "0.7.0"
|
|
65
65
|
},
|
|
66
66
|
"description": "Schema-driven framework with XState workflows and HST state management",
|
package/dist/src/stonecrop.js
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import { reactive } from 'vue';
|
|
2
|
-
import { createHST } from './stores/hst';
|
|
3
|
-
import { useOperationLogStore } from './stores/operation-log';
|
|
4
|
-
/**
|
|
5
|
-
* Main Stonecrop class with HST integration and built-in Operation Log
|
|
6
|
-
* @public
|
|
7
|
-
*/
|
|
8
|
-
export class Stonecrop {
|
|
9
|
-
hstStore;
|
|
10
|
-
_operationLogStore;
|
|
11
|
-
_operationLogConfig;
|
|
12
|
-
/** The registry instance containing all doctype definitions */
|
|
13
|
-
registry;
|
|
14
|
-
/**
|
|
15
|
-
* Creates a new Stonecrop instance with HST integration
|
|
16
|
-
* @param registry - The Registry instance containing doctype definitions
|
|
17
|
-
* @param operationLogConfig - Optional configuration for the operation log
|
|
18
|
-
*/
|
|
19
|
-
constructor(registry, operationLogConfig) {
|
|
20
|
-
this.registry = registry;
|
|
21
|
-
// Store config for lazy initialization
|
|
22
|
-
this._operationLogConfig = operationLogConfig;
|
|
23
|
-
// Initialize HST store with auto-sync to Registry
|
|
24
|
-
this.initializeHSTStore();
|
|
25
|
-
this.setupRegistrySync();
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Get the operation log store (lazy initialization)
|
|
29
|
-
* @internal
|
|
30
|
-
*/
|
|
31
|
-
getOperationLogStore() {
|
|
32
|
-
if (!this._operationLogStore) {
|
|
33
|
-
this._operationLogStore = useOperationLogStore();
|
|
34
|
-
if (this._operationLogConfig) {
|
|
35
|
-
this._operationLogStore.configure(this._operationLogConfig);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return this._operationLogStore;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Initialize the HST store structure
|
|
42
|
-
*/
|
|
43
|
-
initializeHSTStore() {
|
|
44
|
-
const initialStoreStructure = {};
|
|
45
|
-
// Auto-populate from existing Registry doctypes
|
|
46
|
-
Object.keys(this.registry.registry).forEach(doctypeSlug => {
|
|
47
|
-
initialStoreStructure[doctypeSlug] = {};
|
|
48
|
-
});
|
|
49
|
-
// Wrap the store in Vue's reactive() for automatic change detection
|
|
50
|
-
// This enables Vue computed properties to track HST store changes
|
|
51
|
-
this.hstStore = createHST(reactive(initialStoreStructure), 'StonecropStore');
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Setup automatic sync with Registry when doctypes are added
|
|
55
|
-
*/
|
|
56
|
-
setupRegistrySync() {
|
|
57
|
-
// Extend Registry.addDoctype to auto-create HST store sections
|
|
58
|
-
const originalAddDoctype = this.registry.addDoctype.bind(this.registry);
|
|
59
|
-
this.registry.addDoctype = (doctype) => {
|
|
60
|
-
// Call original method
|
|
61
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
62
|
-
originalAddDoctype(doctype);
|
|
63
|
-
// Auto-create HST store section for new doctype
|
|
64
|
-
if (!this.hstStore.has(doctype.slug)) {
|
|
65
|
-
this.hstStore.set(doctype.slug, {});
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Get records hash for a doctype
|
|
71
|
-
* @param doctype - The doctype to get records for
|
|
72
|
-
* @returns HST node containing records hash
|
|
73
|
-
*/
|
|
74
|
-
records(doctype) {
|
|
75
|
-
const slug = typeof doctype === 'string' ? doctype : doctype.slug;
|
|
76
|
-
this.ensureDoctypeExists(slug);
|
|
77
|
-
return this.hstStore.getNode(slug);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Add a record to the store
|
|
81
|
-
* @param doctype - The doctype
|
|
82
|
-
* @param recordId - The record ID
|
|
83
|
-
* @param recordData - The record data
|
|
84
|
-
*/
|
|
85
|
-
addRecord(doctype, recordId, recordData) {
|
|
86
|
-
const slug = typeof doctype === 'string' ? doctype : doctype.slug;
|
|
87
|
-
this.ensureDoctypeExists(slug);
|
|
88
|
-
// Store raw record data - let HST handle wrapping with proper hierarchy
|
|
89
|
-
this.hstStore.set(`${slug}.${recordId}`, recordData);
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Get a specific record
|
|
93
|
-
* @param doctype - The doctype
|
|
94
|
-
* @param recordId - The record ID
|
|
95
|
-
* @returns HST node for the record or undefined
|
|
96
|
-
*/
|
|
97
|
-
getRecordById(doctype, recordId) {
|
|
98
|
-
const slug = typeof doctype === 'string' ? doctype : doctype.slug;
|
|
99
|
-
this.ensureDoctypeExists(slug);
|
|
100
|
-
// First check if the record exists
|
|
101
|
-
const recordExists = this.hstStore.has(`${slug}.${recordId}`);
|
|
102
|
-
if (!recordExists) {
|
|
103
|
-
return undefined;
|
|
104
|
-
}
|
|
105
|
-
// Check if the actual value is undefined (i.e., record was removed)
|
|
106
|
-
const recordValue = this.hstStore.get(`${slug}.${recordId}`);
|
|
107
|
-
if (recordValue === undefined) {
|
|
108
|
-
return undefined;
|
|
109
|
-
}
|
|
110
|
-
// Use getNode to get the properly wrapped HST node with correct parent relationships
|
|
111
|
-
return this.hstStore.getNode(`${slug}.${recordId}`);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Remove a record from the store
|
|
115
|
-
* @param doctype - The doctype
|
|
116
|
-
* @param recordId - The record ID
|
|
117
|
-
*/
|
|
118
|
-
removeRecord(doctype, recordId) {
|
|
119
|
-
const slug = typeof doctype === 'string' ? doctype : doctype.slug;
|
|
120
|
-
this.ensureDoctypeExists(slug);
|
|
121
|
-
// Remove the specific record directly by setting to undefined
|
|
122
|
-
if (this.hstStore.has(`${slug}.${recordId}`)) {
|
|
123
|
-
this.hstStore.set(`${slug}.${recordId}`, undefined);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Get all record IDs for a doctype
|
|
128
|
-
* @param doctype - The doctype
|
|
129
|
-
* @returns Array of record IDs
|
|
130
|
-
*/
|
|
131
|
-
getRecordIds(doctype) {
|
|
132
|
-
const slug = typeof doctype === 'string' ? doctype : doctype.slug;
|
|
133
|
-
this.ensureDoctypeExists(slug);
|
|
134
|
-
const doctypeNode = this.hstStore.get(slug);
|
|
135
|
-
if (!doctypeNode || typeof doctypeNode !== 'object') {
|
|
136
|
-
return [];
|
|
137
|
-
}
|
|
138
|
-
return Object.keys(doctypeNode).filter(key => doctypeNode[key] !== undefined);
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Clear all records for a doctype
|
|
142
|
-
* @param doctype - The doctype
|
|
143
|
-
*/
|
|
144
|
-
clearRecords(doctype) {
|
|
145
|
-
const slug = typeof doctype === 'string' ? doctype : doctype.slug;
|
|
146
|
-
this.ensureDoctypeExists(slug);
|
|
147
|
-
// Get all record IDs and remove them
|
|
148
|
-
const recordIds = this.getRecordIds(slug);
|
|
149
|
-
recordIds.forEach(recordId => {
|
|
150
|
-
this.hstStore.set(`${slug}.${recordId}`, undefined);
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Setup method for doctype initialization
|
|
155
|
-
* @param doctype - The doctype to setup
|
|
156
|
-
*/
|
|
157
|
-
setup(doctype) {
|
|
158
|
-
// Ensure doctype exists in store
|
|
159
|
-
this.ensureDoctypeExists(doctype.slug);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Run action on doctype
|
|
163
|
-
* Executes the action and logs it to the operation log for audit tracking
|
|
164
|
-
* @param doctype - The doctype
|
|
165
|
-
* @param action - The action to run
|
|
166
|
-
* @param args - Action arguments (typically record IDs)
|
|
167
|
-
*/
|
|
168
|
-
runAction(doctype, action, args) {
|
|
169
|
-
const registry = this.registry.registry[doctype.slug];
|
|
170
|
-
const actions = registry?.actions?.get(action);
|
|
171
|
-
const recordIds = Array.isArray(args) ? args.filter((arg) => typeof arg === 'string') : undefined;
|
|
172
|
-
// Log action execution start
|
|
173
|
-
const opLogStore = this.getOperationLogStore();
|
|
174
|
-
let actionResult = 'success';
|
|
175
|
-
let actionError;
|
|
176
|
-
try {
|
|
177
|
-
// Execute action functions
|
|
178
|
-
if (actions && actions.length > 0) {
|
|
179
|
-
actions.forEach(actionStr => {
|
|
180
|
-
try {
|
|
181
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
182
|
-
const actionFn = new Function('args', actionStr);
|
|
183
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
184
|
-
actionFn(args);
|
|
185
|
-
}
|
|
186
|
-
catch (error) {
|
|
187
|
-
actionResult = 'failure';
|
|
188
|
-
actionError = error instanceof Error ? error.message : 'Unknown error';
|
|
189
|
-
throw error;
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
catch {
|
|
195
|
-
// Error already set in inner catch
|
|
196
|
-
}
|
|
197
|
-
finally {
|
|
198
|
-
// Log the action execution to operation log
|
|
199
|
-
opLogStore.logAction(doctype.doctype, action, recordIds, actionResult, actionError);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Get records from server (maintains compatibility)
|
|
204
|
-
* @param doctype - The doctype
|
|
205
|
-
*/
|
|
206
|
-
async getRecords(doctype) {
|
|
207
|
-
const response = await fetch(`/${doctype.slug}`);
|
|
208
|
-
const records = (await response.json());
|
|
209
|
-
// Store each record in HST
|
|
210
|
-
records.forEach(record => {
|
|
211
|
-
if (record.id) {
|
|
212
|
-
this.addRecord(doctype, record.id, record);
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Get single record from server (maintains compatibility)
|
|
218
|
-
* @param doctype - The doctype
|
|
219
|
-
* @param recordId - The record ID
|
|
220
|
-
*/
|
|
221
|
-
async getRecord(doctype, recordId) {
|
|
222
|
-
const response = await fetch(`/${doctype.slug}/${recordId}`);
|
|
223
|
-
const record = await response.json();
|
|
224
|
-
// Store record
|
|
225
|
-
this.addRecord(doctype, recordId, record);
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Ensure doctype section exists in HST store
|
|
229
|
-
* @param slug - The doctype slug
|
|
230
|
-
*/
|
|
231
|
-
ensureDoctypeExists(slug) {
|
|
232
|
-
if (!this.hstStore.has(slug)) {
|
|
233
|
-
this.hstStore.set(slug, {});
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Get doctype metadata from the registry
|
|
238
|
-
* @param context - The route context
|
|
239
|
-
* @returns The doctype metadata
|
|
240
|
-
*/
|
|
241
|
-
async getMeta(context) {
|
|
242
|
-
if (!this.registry.getMeta) {
|
|
243
|
-
throw new Error('No getMeta function provided to Registry');
|
|
244
|
-
}
|
|
245
|
-
return await this.registry.getMeta(context);
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Get the root HST store node for advanced usage
|
|
249
|
-
* @returns Root HST node
|
|
250
|
-
*/
|
|
251
|
-
getStore() {
|
|
252
|
-
return this.hstStore;
|
|
253
|
-
}
|
|
254
|
-
}
|
package/dist/tests/setup.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../tests/setup.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/tests/setup.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vitest setup file
|
|
3
|
-
* Runs before all test files
|
|
4
|
-
*/
|
|
5
|
-
// Remove Node.js's native BroadcastChannel to avoid conflicts with mocks
|
|
6
|
-
// Tests that need BroadcastChannel will mock it themselves
|
|
7
|
-
if (typeof global !== 'undefined' && 'BroadcastChannel' in global) {
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
9
|
-
delete global.BroadcastChannel;
|
|
10
|
-
}
|
|
11
|
-
// Also remove from globalThis if it exists there
|
|
12
|
-
if (typeof globalThis !== 'undefined' && 'BroadcastChannel' in globalThis) {
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
14
|
-
delete globalThis.BroadcastChannel;
|
|
15
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|