@stonecrop/stonecrop 0.10.16 → 0.11.0
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/README.md +72 -29
- package/dist/composable.js +1 -0
- package/dist/composables/lazy-link.js +125 -0
- package/dist/composables/stonecrop.js +123 -68
- package/dist/composables/use-lazy-link-state.js +125 -0
- package/dist/composables/use-stonecrop.js +476 -0
- package/dist/doctype.js +10 -2
- package/dist/field-triggers.js +15 -3
- package/dist/index.js +4 -3
- package/dist/operation-log-DB-dGNT9.js +593 -0
- package/dist/operation-log-DB-dGNT9.js.map +1 -0
- package/dist/registry.js +261 -101
- package/dist/schema-validator.js +105 -1
- package/dist/src/composable.d.ts +11 -0
- package/dist/src/composable.d.ts.map +1 -0
- package/dist/src/composable.js +477 -0
- package/dist/src/composables/lazy-link.d.ts +25 -0
- package/dist/src/composables/lazy-link.d.ts.map +1 -0
- package/dist/src/composables/operation-log.d.ts +5 -5
- package/dist/src/composables/operation-log.d.ts.map +1 -1
- package/dist/src/composables/operation-log.js +224 -0
- package/dist/src/composables/stonecrop.d.ts +11 -1
- package/dist/src/composables/stonecrop.d.ts.map +1 -1
- package/dist/src/composables/stonecrop.js +574 -0
- package/dist/src/composables/use-lazy-link-state.d.ts +25 -0
- package/dist/src/composables/use-lazy-link-state.d.ts.map +1 -0
- package/dist/src/composables/use-stonecrop.d.ts +93 -0
- package/dist/src/composables/use-stonecrop.d.ts.map +1 -0
- package/dist/src/composables/useNestedSchema.d.ts +110 -0
- package/dist/src/composables/useNestedSchema.d.ts.map +1 -0
- package/dist/src/composables/useNestedSchema.js +155 -0
- package/dist/src/doctype.d.ts +9 -1
- package/dist/src/doctype.d.ts.map +1 -1
- package/dist/src/doctype.js +234 -0
- package/dist/src/exceptions.js +16 -0
- package/dist/src/field-triggers.d.ts +6 -0
- package/dist/src/field-triggers.d.ts.map +1 -1
- package/dist/src/field-triggers.js +567 -0
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +23 -0
- package/dist/src/plugins/index.js +96 -0
- package/dist/src/registry.d.ts +102 -23
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +246 -0
- package/dist/src/schema-validator.d.ts +8 -1
- package/dist/src/schema-validator.d.ts.map +1 -1
- package/dist/src/schema-validator.js +315 -0
- package/dist/src/stonecrop.d.ts +73 -28
- package/dist/src/stonecrop.d.ts.map +1 -1
- package/dist/src/stonecrop.js +339 -0
- package/dist/src/stores/data.d.ts +11 -0
- package/dist/src/stores/data.d.ts.map +1 -0
- package/dist/src/stores/hst.d.ts +5 -75
- package/dist/src/stores/hst.d.ts.map +1 -1
- package/dist/src/stores/hst.js +495 -0
- package/dist/src/stores/index.js +12 -0
- package/dist/src/stores/operation-log.d.ts +14 -14
- package/dist/src/stores/operation-log.d.ts.map +1 -1
- package/dist/src/stores/operation-log.js +568 -0
- package/dist/src/stores/xstate.d.ts +31 -0
- package/dist/src/stores/xstate.d.ts.map +1 -0
- package/dist/src/tsdoc-metadata.json +11 -0
- package/dist/src/types/composable.d.ts +50 -12
- package/dist/src/types/composable.d.ts.map +1 -1
- package/dist/src/types/doctype.d.ts +6 -7
- package/dist/src/types/doctype.d.ts.map +1 -1
- package/dist/src/types/field-triggers.d.ts +1 -1
- package/dist/src/types/field-triggers.d.ts.map +1 -1
- package/dist/src/types/field-triggers.js +4 -0
- package/dist/src/types/hst.d.ts +70 -0
- package/dist/src/types/hst.d.ts.map +1 -0
- package/dist/src/types/index.d.ts +1 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +4 -0
- package/dist/src/types/operation-log.d.ts +4 -4
- package/dist/src/types/operation-log.d.ts.map +1 -1
- package/dist/src/types/operation-log.js +0 -0
- package/dist/src/types/registry.js +0 -0
- package/dist/src/types/schema-validator.d.ts +2 -0
- package/dist/src/types/schema-validator.d.ts.map +1 -1
- package/dist/src/utils.d.ts +24 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/stonecrop.d.ts +317 -99
- package/dist/stonecrop.js +2191 -1897
- package/dist/stonecrop.js.map +1 -1
- package/dist/stonecrop.umd.cjs +6 -0
- package/dist/stonecrop.umd.cjs.map +1 -0
- package/dist/stores/data.js +7 -0
- package/dist/stores/hst.js +27 -25
- package/dist/stores/operation-log.js +59 -47
- package/dist/stores/xstate.js +29 -0
- package/dist/tests/setup.d.ts +5 -0
- package/dist/tests/setup.d.ts.map +1 -0
- package/dist/tests/setup.js +15 -0
- package/dist/types/hst.js +0 -0
- package/dist/types/index.js +1 -0
- package/dist/utils.js +46 -0
- package/package.json +5 -5
- package/src/composables/lazy-link.ts +146 -0
- package/src/composables/operation-log.ts +1 -1
- package/src/composables/stonecrop.ts +142 -73
- package/src/doctype.ts +13 -4
- package/src/field-triggers.ts +18 -4
- package/src/index.ts +4 -2
- package/src/registry.ts +289 -111
- package/src/schema-validator.ts +120 -1
- package/src/stonecrop.ts +230 -106
- package/src/stores/hst.ts +29 -104
- package/src/stores/operation-log.ts +64 -50
- package/src/types/composable.ts +55 -12
- package/src/types/doctype.ts +6 -7
- package/src/types/field-triggers.ts +1 -1
- package/src/types/hst.ts +77 -0
- package/src/types/index.ts +1 -0
- package/src/types/operation-log.ts +4 -4
- package/src/types/schema-validator.ts +2 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema Validation Utilities
|
|
3
|
+
* Validates Stonecrop schemas for integrity and consistency
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import { getGlobalTriggerEngine } from './field-triggers';
|
|
7
|
+
/**
|
|
8
|
+
* Validation severity levels
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
export var ValidationSeverity;
|
|
12
|
+
(function (ValidationSeverity) {
|
|
13
|
+
/** Blocking error that prevents save */
|
|
14
|
+
ValidationSeverity["ERROR"] = "error";
|
|
15
|
+
/** Advisory warning that allows save */
|
|
16
|
+
ValidationSeverity["WARNING"] = "warning";
|
|
17
|
+
/** Informational message */
|
|
18
|
+
ValidationSeverity["INFO"] = "info";
|
|
19
|
+
})(ValidationSeverity || (ValidationSeverity = {}));
|
|
20
|
+
/**
|
|
21
|
+
* Schema validator class
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export class SchemaValidator {
|
|
25
|
+
options;
|
|
26
|
+
/**
|
|
27
|
+
* Creates a new SchemaValidator instance
|
|
28
|
+
* @param options - Validator configuration options
|
|
29
|
+
*/
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
this.options = {
|
|
32
|
+
registry: options.registry || null,
|
|
33
|
+
validateLinkTargets: options.validateLinkTargets ?? true,
|
|
34
|
+
validateActions: options.validateActions ?? true,
|
|
35
|
+
validateWorkflows: options.validateWorkflows ?? true,
|
|
36
|
+
validateRequiredProperties: options.validateRequiredProperties ?? true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validates a complete doctype schema
|
|
41
|
+
* @param doctype - Doctype name
|
|
42
|
+
* @param schema - Schema fields (List or Array)
|
|
43
|
+
* @param workflow - Optional workflow configuration
|
|
44
|
+
* @param actions - Optional actions map
|
|
45
|
+
* @returns Validation result
|
|
46
|
+
*/
|
|
47
|
+
validate(doctype, schema, workflow, actions) {
|
|
48
|
+
const issues = [];
|
|
49
|
+
// Convert schema to array for easier iteration
|
|
50
|
+
const schemaArray = schema ? (Array.isArray(schema) ? schema : schema.toArray()) : [];
|
|
51
|
+
// Validate required properties
|
|
52
|
+
if (this.options.validateRequiredProperties) {
|
|
53
|
+
issues.push(...this.validateRequiredProperties(doctype, schemaArray));
|
|
54
|
+
}
|
|
55
|
+
// Validate Link field targets
|
|
56
|
+
if (this.options.validateLinkTargets && this.options.registry) {
|
|
57
|
+
issues.push(...this.validateLinkFields(doctype, schemaArray, this.options.registry));
|
|
58
|
+
}
|
|
59
|
+
// Validate workflow configuration
|
|
60
|
+
if (this.options.validateWorkflows && workflow) {
|
|
61
|
+
issues.push(...this.validateWorkflow(doctype, workflow));
|
|
62
|
+
}
|
|
63
|
+
// Validate action registration
|
|
64
|
+
if (this.options.validateActions && actions) {
|
|
65
|
+
const actionsMap = actions instanceof Map ? actions : actions.toObject();
|
|
66
|
+
issues.push(...this.validateActionRegistration(doctype, actionsMap));
|
|
67
|
+
}
|
|
68
|
+
// Calculate counts
|
|
69
|
+
const errorCount = issues.filter(i => i.severity === ValidationSeverity.ERROR).length;
|
|
70
|
+
const warningCount = issues.filter(i => i.severity === ValidationSeverity.WARNING).length;
|
|
71
|
+
const infoCount = issues.filter(i => i.severity === ValidationSeverity.INFO).length;
|
|
72
|
+
return {
|
|
73
|
+
valid: errorCount === 0,
|
|
74
|
+
issues,
|
|
75
|
+
errorCount,
|
|
76
|
+
warningCount,
|
|
77
|
+
infoCount,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Validates that required schema properties are present
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
validateRequiredProperties(doctype, schema) {
|
|
85
|
+
const issues = [];
|
|
86
|
+
for (const field of schema) {
|
|
87
|
+
// Check for fieldname
|
|
88
|
+
if (!field.fieldname) {
|
|
89
|
+
issues.push({
|
|
90
|
+
severity: ValidationSeverity.ERROR,
|
|
91
|
+
rule: 'required-fieldname',
|
|
92
|
+
message: 'Field is missing required property: fieldname',
|
|
93
|
+
doctype,
|
|
94
|
+
context: { field },
|
|
95
|
+
});
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Check for component or fieldtype
|
|
99
|
+
if (!field.component && !('fieldtype' in field)) {
|
|
100
|
+
issues.push({
|
|
101
|
+
severity: ValidationSeverity.ERROR,
|
|
102
|
+
rule: 'required-component-or-fieldtype',
|
|
103
|
+
message: `Field "${field.fieldname}" must have either component or fieldtype property`,
|
|
104
|
+
doctype,
|
|
105
|
+
fieldname: field.fieldname,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Validate nested schemas (recursively)
|
|
109
|
+
if ('schema' in field) {
|
|
110
|
+
const nestedSchema = field.schema;
|
|
111
|
+
const nestedArray = (Array.isArray(nestedSchema) ? nestedSchema : nestedSchema.toArray?.() || []);
|
|
112
|
+
issues.push(...this.validateRequiredProperties(doctype, nestedArray));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return issues;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Validates Link field targets exist in registry
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
validateLinkFields(doctype, schema, registry) {
|
|
122
|
+
const issues = [];
|
|
123
|
+
for (const field of schema) {
|
|
124
|
+
const fieldtype = 'fieldtype' in field ? field.fieldtype : undefined;
|
|
125
|
+
// Check Link fields
|
|
126
|
+
if (fieldtype === 'Link') {
|
|
127
|
+
const options = 'options' in field ? field.options : undefined;
|
|
128
|
+
if (!options) {
|
|
129
|
+
issues.push({
|
|
130
|
+
severity: ValidationSeverity.ERROR,
|
|
131
|
+
rule: 'link-missing-options',
|
|
132
|
+
message: `Link field "${field.fieldname}" is missing options property (target doctype)`,
|
|
133
|
+
doctype,
|
|
134
|
+
fieldname: field.fieldname,
|
|
135
|
+
});
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// Check if target doctype exists in registry
|
|
139
|
+
// Options should be a string representing the target doctype name
|
|
140
|
+
const targetDoctype = typeof options === 'string' ? options : '';
|
|
141
|
+
if (!targetDoctype) {
|
|
142
|
+
issues.push({
|
|
143
|
+
severity: ValidationSeverity.ERROR,
|
|
144
|
+
rule: 'link-invalid-options',
|
|
145
|
+
message: `Link field "${field.fieldname}" has invalid options format (expected string doctype name)`,
|
|
146
|
+
doctype,
|
|
147
|
+
fieldname: field.fieldname,
|
|
148
|
+
});
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const targetMeta = registry.registry[targetDoctype] || registry.registry[targetDoctype.toLowerCase()];
|
|
152
|
+
if (!targetMeta) {
|
|
153
|
+
issues.push({
|
|
154
|
+
severity: ValidationSeverity.ERROR,
|
|
155
|
+
rule: 'link-invalid-target',
|
|
156
|
+
message: `Link field "${field.fieldname}" references non-existent doctype: "${targetDoctype}"`,
|
|
157
|
+
doctype,
|
|
158
|
+
fieldname: field.fieldname,
|
|
159
|
+
context: { targetDoctype },
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Recursively check nested schemas
|
|
164
|
+
if ('schema' in field) {
|
|
165
|
+
const nestedSchema = field.schema;
|
|
166
|
+
const nestedArray = (Array.isArray(nestedSchema) ? nestedSchema : nestedSchema.toArray?.() || []);
|
|
167
|
+
issues.push(...this.validateLinkFields(doctype, nestedArray, registry));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return issues;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Validates workflow state machine configuration
|
|
174
|
+
* @internal
|
|
175
|
+
*/
|
|
176
|
+
validateWorkflow(doctype, workflow) {
|
|
177
|
+
const issues = [];
|
|
178
|
+
// Check for initial state
|
|
179
|
+
if (!workflow.initial && !workflow.type) {
|
|
180
|
+
issues.push({
|
|
181
|
+
severity: ValidationSeverity.WARNING,
|
|
182
|
+
rule: 'workflow-missing-initial',
|
|
183
|
+
message: 'Workflow is missing initial state property',
|
|
184
|
+
doctype,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
// Check for states
|
|
188
|
+
if (!workflow.states || Object.keys(workflow.states).length === 0) {
|
|
189
|
+
issues.push({
|
|
190
|
+
severity: ValidationSeverity.WARNING,
|
|
191
|
+
rule: 'workflow-no-states',
|
|
192
|
+
message: 'Workflow has no states defined',
|
|
193
|
+
doctype,
|
|
194
|
+
});
|
|
195
|
+
return issues;
|
|
196
|
+
}
|
|
197
|
+
// Validate initial state exists
|
|
198
|
+
if (workflow.initial && typeof workflow.initial === 'string' && !workflow.states[workflow.initial]) {
|
|
199
|
+
issues.push({
|
|
200
|
+
severity: ValidationSeverity.ERROR,
|
|
201
|
+
rule: 'workflow-invalid-initial',
|
|
202
|
+
message: `Workflow initial state "${workflow.initial}" does not exist in states`,
|
|
203
|
+
doctype,
|
|
204
|
+
context: { initialState: workflow.initial },
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
// Check state reachability (simple check - all states should have at least one incoming transition or be initial)
|
|
208
|
+
const stateNames = Object.keys(workflow.states);
|
|
209
|
+
const reachableStates = new Set();
|
|
210
|
+
// Initial state is always reachable
|
|
211
|
+
if (workflow.initial && typeof workflow.initial === 'string') {
|
|
212
|
+
reachableStates.add(workflow.initial);
|
|
213
|
+
}
|
|
214
|
+
// Find all target states from transitions
|
|
215
|
+
for (const [_stateName, stateConfig] of Object.entries(workflow.states)) {
|
|
216
|
+
const state = stateConfig;
|
|
217
|
+
if (state.on) {
|
|
218
|
+
for (const [_event, transition] of Object.entries(state.on)) {
|
|
219
|
+
if (typeof transition === 'string') {
|
|
220
|
+
reachableStates.add(transition);
|
|
221
|
+
}
|
|
222
|
+
else if (transition && typeof transition === 'object') {
|
|
223
|
+
const target = 'target' in transition ? transition.target : undefined;
|
|
224
|
+
if (typeof target === 'string') {
|
|
225
|
+
reachableStates.add(target);
|
|
226
|
+
}
|
|
227
|
+
else if (Array.isArray(target)) {
|
|
228
|
+
target.forEach((t) => {
|
|
229
|
+
if (typeof t === 'string') {
|
|
230
|
+
reachableStates.add(t);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Check for unreachable states
|
|
239
|
+
for (const stateName of stateNames) {
|
|
240
|
+
if (!reachableStates.has(stateName)) {
|
|
241
|
+
issues.push({
|
|
242
|
+
severity: ValidationSeverity.WARNING,
|
|
243
|
+
rule: 'workflow-unreachable-state',
|
|
244
|
+
message: `Workflow state "${stateName}" may not be reachable`,
|
|
245
|
+
doctype,
|
|
246
|
+
context: { stateName },
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return issues;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Validates that actions are registered in the FieldTriggerEngine
|
|
254
|
+
* @internal
|
|
255
|
+
*/
|
|
256
|
+
validateActionRegistration(doctype, actions) {
|
|
257
|
+
const issues = [];
|
|
258
|
+
const triggerEngine = getGlobalTriggerEngine();
|
|
259
|
+
for (const [triggerName, actionNames] of Object.entries(actions)) {
|
|
260
|
+
if (!Array.isArray(actionNames)) {
|
|
261
|
+
issues.push({
|
|
262
|
+
severity: ValidationSeverity.ERROR,
|
|
263
|
+
rule: 'action-invalid-format',
|
|
264
|
+
message: `Action configuration for "${triggerName}" must be an array`,
|
|
265
|
+
doctype,
|
|
266
|
+
context: { triggerName, actionNames },
|
|
267
|
+
});
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
// Check each action name
|
|
271
|
+
for (const actionName of actionNames) {
|
|
272
|
+
// Check if action is registered globally
|
|
273
|
+
const engine = triggerEngine;
|
|
274
|
+
const isRegistered = engine.globalActions?.has(actionName) || engine.globalTransitionActions?.has(actionName);
|
|
275
|
+
if (!isRegistered) {
|
|
276
|
+
issues.push({
|
|
277
|
+
severity: ValidationSeverity.WARNING,
|
|
278
|
+
rule: 'action-not-registered',
|
|
279
|
+
message: `Action "${actionName}" referenced in "${triggerName}" is not registered in FieldTriggerEngine`,
|
|
280
|
+
doctype,
|
|
281
|
+
context: { triggerName, actionName },
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return issues;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Creates a validator with the given registry
|
|
291
|
+
* @param registry - Registry instance
|
|
292
|
+
* @param options - Additional validator options
|
|
293
|
+
* @returns SchemaValidator instance
|
|
294
|
+
* @public
|
|
295
|
+
*/
|
|
296
|
+
export function createValidator(registry, options) {
|
|
297
|
+
return new SchemaValidator({
|
|
298
|
+
registry,
|
|
299
|
+
...options,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Quick validation helper
|
|
304
|
+
* @param doctype - Doctype name
|
|
305
|
+
* @param schema - Schema fields
|
|
306
|
+
* @param registry - Registry instance
|
|
307
|
+
* @param workflow - Optional workflow configuration
|
|
308
|
+
* @param actions - Optional actions map
|
|
309
|
+
* @returns Validation result
|
|
310
|
+
* @public
|
|
311
|
+
*/
|
|
312
|
+
export function validateSchema(doctype, schema, registry, workflow, actions) {
|
|
313
|
+
const validator = createValidator(registry);
|
|
314
|
+
return validator.validate(doctype, schema, workflow, actions);
|
|
315
|
+
}
|
package/dist/src/stonecrop.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type SchemaTypes } from '@stonecrop/aform';
|
|
2
1
|
import type { DataClient } from '@stonecrop/schema';
|
|
3
2
|
import Doctype from './doctype';
|
|
4
3
|
import Registry from './registry';
|
|
@@ -18,6 +17,7 @@ export declare class Stonecrop {
|
|
|
18
17
|
* @internal
|
|
19
18
|
*/
|
|
20
19
|
static _root: Stonecrop;
|
|
20
|
+
/** The HST store instance for reactive state management */
|
|
21
21
|
private hstStore;
|
|
22
22
|
private _operationLogStore?;
|
|
23
23
|
private _operationLogConfig?;
|
|
@@ -77,8 +77,8 @@ export declare class Stonecrop {
|
|
|
77
77
|
actionError?: string | undefined;
|
|
78
78
|
userId?: string | undefined;
|
|
79
79
|
metadata?: Record<string, any> | undefined;
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
ancestorOperationId?: string | undefined;
|
|
81
|
+
descendantOperationIds?: string[] | undefined;
|
|
82
82
|
}[], import("./types").HSTOperation[] | {
|
|
83
83
|
id: string;
|
|
84
84
|
type: import("./types").HSTOperationType;
|
|
@@ -101,8 +101,8 @@ export declare class Stonecrop {
|
|
|
101
101
|
actionError?: string | undefined;
|
|
102
102
|
userId?: string | undefined;
|
|
103
103
|
metadata?: Record<string, any> | undefined;
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
ancestorOperationId?: string | undefined;
|
|
105
|
+
descendantOperationIds?: string[] | undefined;
|
|
106
106
|
}[]>;
|
|
107
107
|
currentIndex: import("vue").Ref<number, number>;
|
|
108
108
|
config: import("vue").Ref<{
|
|
@@ -140,7 +140,7 @@ export declare class Stonecrop {
|
|
|
140
140
|
getSnapshot: () => import("./types").OperationLogSnapshot;
|
|
141
141
|
markIrreversible: (operationId: string, reason: string) => void;
|
|
142
142
|
logAction: (doctype: string, actionName: string, recordIds?: string[], result?: "success" | "failure" | "pending", error?: string) => string;
|
|
143
|
-
}, "operations" | "
|
|
143
|
+
}, "operations" | "currentIndex" | "config" | "clientId">, Pick<{
|
|
144
144
|
operations: import("vue").Ref<{
|
|
145
145
|
id: string;
|
|
146
146
|
type: import("./types").HSTOperationType;
|
|
@@ -163,8 +163,8 @@ export declare class Stonecrop {
|
|
|
163
163
|
actionError?: string | undefined;
|
|
164
164
|
userId?: string | undefined;
|
|
165
165
|
metadata?: Record<string, any> | undefined;
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
ancestorOperationId?: string | undefined;
|
|
167
|
+
descendantOperationIds?: string[] | undefined;
|
|
168
168
|
}[], import("./types").HSTOperation[] | {
|
|
169
169
|
id: string;
|
|
170
170
|
type: import("./types").HSTOperationType;
|
|
@@ -187,8 +187,8 @@ export declare class Stonecrop {
|
|
|
187
187
|
actionError?: string | undefined;
|
|
188
188
|
userId?: string | undefined;
|
|
189
189
|
metadata?: Record<string, any> | undefined;
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
ancestorOperationId?: string | undefined;
|
|
191
|
+
descendantOperationIds?: string[] | undefined;
|
|
192
192
|
}[]>;
|
|
193
193
|
currentIndex: import("vue").Ref<number, number>;
|
|
194
194
|
config: import("vue").Ref<{
|
|
@@ -249,8 +249,8 @@ export declare class Stonecrop {
|
|
|
249
249
|
actionError?: string | undefined;
|
|
250
250
|
userId?: string | undefined;
|
|
251
251
|
metadata?: Record<string, any> | undefined;
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
ancestorOperationId?: string | undefined;
|
|
253
|
+
descendantOperationIds?: string[] | undefined;
|
|
254
254
|
}[], import("./types").HSTOperation[] | {
|
|
255
255
|
id: string;
|
|
256
256
|
type: import("./types").HSTOperationType;
|
|
@@ -273,8 +273,8 @@ export declare class Stonecrop {
|
|
|
273
273
|
actionError?: string | undefined;
|
|
274
274
|
userId?: string | undefined;
|
|
275
275
|
metadata?: Record<string, any> | undefined;
|
|
276
|
-
|
|
277
|
-
|
|
276
|
+
ancestorOperationId?: string | undefined;
|
|
277
|
+
descendantOperationIds?: string[] | undefined;
|
|
278
278
|
}[]>;
|
|
279
279
|
currentIndex: import("vue").Ref<number, number>;
|
|
280
280
|
config: import("vue").Ref<{
|
|
@@ -370,7 +370,25 @@ export declare class Stonecrop {
|
|
|
370
370
|
* @param action - The action to run
|
|
371
371
|
* @param args - Action arguments (typically record IDs)
|
|
372
372
|
*/
|
|
373
|
-
runAction(doctype: Doctype, action: string, args?:
|
|
373
|
+
runAction(doctype: Doctype, action: string, args?: string[]): void;
|
|
374
|
+
/**
|
|
375
|
+
* Get the effective blockWorkflows value for a link.
|
|
376
|
+
* Returns true if blockWorkflows is explicitly true, or if it's absent and fetch method is 'sync'.
|
|
377
|
+
* @param link - The link declaration
|
|
378
|
+
* @returns Whether workflows should be blocked until this link is loaded
|
|
379
|
+
*/
|
|
380
|
+
private getEffectiveBlockWorkflows;
|
|
381
|
+
/**
|
|
382
|
+
* Check if workflow actions are ready to run (all required link data is loaded).
|
|
383
|
+
* A link's data is considered loaded if it exists in HST at `slug.recordId.linkname`.
|
|
384
|
+
* @param doctype - The doctype to check
|
|
385
|
+
* @param recordId - The record ID
|
|
386
|
+
* @returns Object with `ready: true` if all blocked links are loaded, or `ready: false` with `blockedLinks` array
|
|
387
|
+
*/
|
|
388
|
+
isWorkflowReady(doctype: Doctype, recordId: string): {
|
|
389
|
+
ready: boolean;
|
|
390
|
+
blockedLinks?: string[];
|
|
391
|
+
};
|
|
374
392
|
/**
|
|
375
393
|
* Get records from server using the configured data client.
|
|
376
394
|
* @param doctype - The doctype
|
|
@@ -438,23 +456,50 @@ export declare class Stonecrop {
|
|
|
438
456
|
*/
|
|
439
457
|
collectRecordPayload(doctype: Doctype, recordId: string): Record<string, any>;
|
|
440
458
|
/**
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
459
|
+
* Scaffold empty descendant records from defaults for all descendant links.
|
|
460
|
+
*
|
|
461
|
+
* Initializes all scalar and link fields at their HST paths with default values.
|
|
462
|
+
* For new records, call this after setting up the doctype to ensure all paths exist.
|
|
463
|
+
*
|
|
464
|
+
* @param path - HST path (e.g., "customer.new")
|
|
465
|
+
* @param doctype - The doctype to initialize
|
|
466
|
+
* @public
|
|
467
|
+
*/
|
|
468
|
+
initializeNestedData(path: string, doctype: Doctype): void;
|
|
469
|
+
/**
|
|
470
|
+
* Fetch a record and its nested data from the server.
|
|
471
|
+
*
|
|
472
|
+
* Calls `_client.getRecord()` with nested sub-selections and stores each scalar field at its own HST path
|
|
473
|
+
* (`slug.recordId.fieldname`), descendants at the link-level path (`slug.recordId.linkname`).
|
|
474
|
+
*
|
|
475
|
+
* @param path - HST path (e.g., "recipe.r1")
|
|
476
|
+
* @param doctype - The doctype to fetch
|
|
477
|
+
* @param recordId - Record ID to fetch
|
|
478
|
+
* @param options - Query options (includeNested to control which links are fetched)
|
|
479
|
+
* @throws Error with code `"CLIENT_REQUIRED"` if no data client is configured
|
|
480
|
+
* @throws Error with code `"RECORD_NOT_FOUND"` if the server returns null
|
|
446
481
|
* @public
|
|
447
482
|
*/
|
|
448
|
-
|
|
483
|
+
fetchNestedData(path: string, doctype: Doctype, recordId: string, options?: {
|
|
484
|
+
includeNested?: boolean | string[];
|
|
485
|
+
}): Promise<void>;
|
|
486
|
+
/**
|
|
487
|
+
* Recursively collect nested data from HST
|
|
488
|
+
* @param basePath - The base path in HST (e.g., "customer.123.address")
|
|
489
|
+
* @param doctype - The doctype whose links drive the recursive traversal
|
|
490
|
+
* @returns The collected data object
|
|
491
|
+
*/
|
|
492
|
+
private collectNestedData;
|
|
449
493
|
}
|
|
450
494
|
/**
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
495
|
+
* Returns the global Stonecrop singleton instance, or `undefined` if no
|
|
496
|
+
* instance has been created yet.
|
|
497
|
+
*
|
|
498
|
+
* Use this when you need the Stonecrop instance outside a Vue component
|
|
499
|
+
* context (e.g., in workflow action handlers, plugin setup code, or
|
|
500
|
+
* non-component utilities). Inside a component, prefer `useStonecrop()`.
|
|
501
|
+
*
|
|
456
502
|
* @public
|
|
457
503
|
*/
|
|
458
|
-
declare function
|
|
459
|
-
export { collectNestedData };
|
|
504
|
+
export declare function getStonecrop(): Stonecrop | undefined;
|
|
460
505
|
//# sourceMappingURL=stonecrop.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stonecrop.d.ts","sourceRoot":"","sources":["../../src/stonecrop.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"stonecrop.d.ts","sourceRoot":"","sources":["../../src/stonecrop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAGnD,OAAO,OAAO,MAAM,WAAW,CAAA;AAE/B,OAAO,QAAQ,MAAM,YAAY,CAAA;AACjC,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAGtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD;;;GAGG;AACH,qBAAa,SAAS;IACrB;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,SAAS,CAAA;IAEvB,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,kBAAkB,CAAC,CAAyC;IACpE,OAAO,CAAC,mBAAmB,CAAC,CAA6B;IACzD,OAAO,CAAC,OAAO,CAAC,CAAY;IAE5B,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAG,QAAQ,CAAA;IAE5B;;;;;OAKG;gBACS,QAAQ,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB;IAmB5G;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAInC;;;OAGG;IACH,SAAS,IAAI,UAAU,GAAG,SAAS;IAInC;;;OAGG;IACH,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAUpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO;IAM3C;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,IAAI;IAS7E;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAoB/E;;;;OAIG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAU/D;;;;OAIG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE;IAYjD;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAW7C;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAK7B;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IA2DlE;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;IAWlC;;;;;;OAMG;IACH,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE;IAwBhG;;;;OAIG;IACG,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBjD;;;;;OAKG;IACG,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAelE;;;;;;;;;OASG;IACG,cAAc,CACnB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,OAAO,EAAE,GACd,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAWrE;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC;IAOlD;;;OAGG;IACH,QAAQ,IAAI,OAAO;IAInB;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IA0BnE;;;;;;OAMG;IACH,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA+B7E;;;;;;;;;OASG;IACH,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAoB1D;;;;;;;;;;;;;OAaG;IACG,eAAe,CACpB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAA;KAAE,GAC9C,OAAO,CAAC,IAAI,CAAC;IAgChB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;CA2BzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,IAAI,SAAS,GAAG,SAAS,CAEpD"}
|