@vidyano-labs/virtual-service 0.1.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.
Files changed (4) hide show
  1. package/README.md +1116 -0
  2. package/index.d.ts +559 -0
  3. package/index.js +2008 -0
  4. package/package.json +24 -0
package/index.d.ts ADDED
@@ -0,0 +1,559 @@
1
+ import { Dto, ServiceHooks, Service, Application } from '@vidyano/core';
2
+
3
+ /**
4
+ * Simplified attribute configuration - converted to PersistentObjectAttributeDto
5
+ */
6
+ type VirtualPersistentObjectAttributeConfig = {
7
+ /**
8
+ * Optional fixed id for this attribute. If not provided, a random UUID is generated.
9
+ */
10
+ id?: string;
11
+ /**
12
+ * The unique name of the attribute.
13
+ */
14
+ name: string;
15
+ /**
16
+ * The type of the data. Defaults to "String".
17
+ */
18
+ type?: string;
19
+ /**
20
+ * The label of the attribute. Defaults to name.
21
+ */
22
+ label?: string;
23
+ /**
24
+ * Initial value for the attribute.
25
+ */
26
+ value?: any;
27
+ /**
28
+ * Indicates whether this attribute is required. Defaults to false.
29
+ */
30
+ isRequired?: boolean;
31
+ /**
32
+ * Indicates whether the value of this attribute can be changed. Defaults to false.
33
+ */
34
+ isReadOnly?: boolean;
35
+ /**
36
+ * A semicolon separated list of business rules that should be checked when saving this attribute.
37
+ * @example "NotEmpty; MaxLength(40)"
38
+ */
39
+ rules?: string;
40
+ /**
41
+ * The visibility of this attribute.
42
+ */
43
+ visibility?: Dto.PersistentObjectAttributeVisibility;
44
+ /**
45
+ * The name of the group to which this attribute belongs. Defaults to "".
46
+ */
47
+ group?: string;
48
+ /**
49
+ * The name of the tab to which this attribute belongs. Defaults to "".
50
+ */
51
+ tab?: string;
52
+ /**
53
+ * Gets whether the persistent object is refreshed when this attribute is changed. Defaults to false.
54
+ */
55
+ triggersRefresh?: boolean;
56
+ /**
57
+ * A list of predefined options to choose the attribute value from.
58
+ */
59
+ options?: string[];
60
+ /**
61
+ * Type hints for this attribute.
62
+ */
63
+ typeHints?: Record<string, string>;
64
+ /**
65
+ * The column that should be used when displaying this attribute.
66
+ */
67
+ column?: number;
68
+ /**
69
+ * The column span that should be used when displaying this attribute. Defaults to 4.
70
+ */
71
+ columnSpan?: number;
72
+ /**
73
+ * The position of this attribute when displayed.
74
+ */
75
+ offset?: number;
76
+ /**
77
+ * Indicates whether this attribute can be used to sort the query. Defaults to true for most types.
78
+ */
79
+ canSort?: boolean;
80
+ /**
81
+ * For Reference attributes: the name of the registered query to use as a lookup.
82
+ */
83
+ lookup?: string;
84
+ /**
85
+ * For Reference attributes: the attribute name to use for displaying the reference value. Defaults to the first attribute.
86
+ */
87
+ displayAttribute?: string;
88
+ /**
89
+ * For Reference attributes: whether the user can add a new reference. Defaults to false.
90
+ */
91
+ canAddNewReference?: boolean;
92
+ /**
93
+ * For Reference attributes: whether to use a fixed list of possible references. Defaults to false.
94
+ */
95
+ selectInPlace?: boolean;
96
+ };
97
+ /**
98
+ * Unified action handler arguments (matches C# CustomAction pattern)
99
+ */
100
+ type ActionArgs = {
101
+ /**
102
+ * The parent PersistentObject (like args.Parent in C#)
103
+ * For PersistentObject actions: the PersistentObject itself
104
+ * For Query actions: the parent PO that owns the query, or null for top-level queries
105
+ */
106
+ parent: Dto.PersistentObjectDto | null;
107
+ /**
108
+ * The query context (like args.Query in C#) - present if action invoked from query
109
+ */
110
+ query?: Dto.QueryDto;
111
+ /**
112
+ * Selected items (like args.SelectedItems in C#) - present if query action with selections
113
+ */
114
+ selectedItems?: Dto.QueryResultItemDto[];
115
+ /**
116
+ * Additional parameters (like args.Parameters in C#)
117
+ */
118
+ parameters?: Record<string, any>;
119
+ /**
120
+ * Helper context for modifying attributes and setting notifications
121
+ */
122
+ context: ActionContext;
123
+ };
124
+ /**
125
+ * Unified action handler (matches C# CustomAction Execute signature)
126
+ * Return the PersistentObject to refresh UI, or null to complete silently
127
+ */
128
+ type ActionHandler = (args: ActionArgs) => Promise<Dto.PersistentObjectDto | null> | Dto.PersistentObjectDto | null;
129
+ /**
130
+ * Action configuration
131
+ */
132
+ type ActionConfig = {
133
+ /**
134
+ * The name of the action.
135
+ */
136
+ name: string;
137
+ /**
138
+ * The display name for the action. Defaults to name.
139
+ */
140
+ displayName?: string;
141
+ /**
142
+ * Indicates whether the action is pinned. Defaults to false.
143
+ */
144
+ isPinned?: boolean;
145
+ /**
146
+ * Custom action logic handler.
147
+ */
148
+ handler: ActionHandler;
149
+ };
150
+ /**
151
+ * Context provides safe API to modify the persistent object during actions
152
+ */
153
+ type ActionContext = {
154
+ /**
155
+ * Gets an attribute by name.
156
+ */
157
+ getAttribute: (name: string) => Dto.PersistentObjectAttributeDto | undefined;
158
+ /**
159
+ * Gets the value of an attribute by name.
160
+ */
161
+ getAttributeValue: (name: string) => any;
162
+ /**
163
+ * Sets the value of an attribute by name.
164
+ */
165
+ setAttributeValue: (name: string, value: any) => void;
166
+ /**
167
+ * Gets the converted value of an attribute DTO (e.g., Boolean as boolean, Int32 as number).
168
+ */
169
+ getConvertedValue: (attr: Dto.PersistentObjectAttributeDto) => any;
170
+ /**
171
+ * Sets the value on an attribute DTO with automatic type conversion.
172
+ */
173
+ setConvertedValue: (attr: Dto.PersistentObjectAttributeDto, value: any) => void;
174
+ /**
175
+ * Sets a validation error for an attribute.
176
+ */
177
+ setValidationError: (name: string, error: string) => void;
178
+ /**
179
+ * Clears the validation error for an attribute.
180
+ */
181
+ clearValidationError: (name: string) => void;
182
+ /**
183
+ * Sets a notification message.
184
+ */
185
+ setNotification: (message: string, type: Dto.NotificationType, duration?: number) => void;
186
+ };
187
+ /**
188
+ * PersistentObject configuration - converted to PersistentObjectDto
189
+ */
190
+ type VirtualPersistentObjectConfig = {
191
+ /**
192
+ * The type of the persistent object.
193
+ */
194
+ type: string;
195
+ /**
196
+ * For singleton objects, the id.
197
+ */
198
+ id?: string;
199
+ /**
200
+ * The attributes of this persistent object.
201
+ */
202
+ attributes: VirtualPersistentObjectAttributeConfig[];
203
+ /**
204
+ * The actions allowed for this persistent object (reference by name).
205
+ */
206
+ actions?: string[];
207
+ /**
208
+ * Query names to attach as detail queries (reference by name).
209
+ */
210
+ queries?: string[];
211
+ /**
212
+ * The tab information for the persistent object.
213
+ */
214
+ tabs?: Record<string, Partial<Dto.PersistentObjectTabDto>>;
215
+ /**
216
+ * A set of extra options that influence the state of the persistent object.
217
+ */
218
+ stateBehavior?: Dto.PersistentObjectStateBehavior;
219
+ /**
220
+ * The label of the persistent object.
221
+ */
222
+ label?: string;
223
+ };
224
+ /**
225
+ * Result returned from onExecuteQuery
226
+ */
227
+ type VirtualQueryExecuteResult = {
228
+ /**
229
+ * The items to display (already filtered, sorted, and paginated by your implementation)
230
+ */
231
+ items: Record<string, any>[];
232
+ /**
233
+ * Total number of items matching the query (before pagination)
234
+ */
235
+ totalItems: number;
236
+ };
237
+ /**
238
+ * Query configuration - converted to QueryDto
239
+ */
240
+ type VirtualQueryConfig = {
241
+ /**
242
+ * Query name (e.g., "People")
243
+ */
244
+ name: string;
245
+ /**
246
+ * Display label (defaults to name)
247
+ */
248
+ label?: string;
249
+ /**
250
+ * Type name of already-registered PersistentObject (REQUIRED)
251
+ * MUST reference an already-registered PersistentObject by type name
252
+ */
253
+ persistentObject: string;
254
+ /**
255
+ * Default data for the query. When executeQuery is not overridden in the
256
+ * VirtualPersistentObjectActions class, this data will be used.
257
+ * Text search, sorting, and pagination are applied automatically.
258
+ */
259
+ data?: Record<string, any>[];
260
+ /**
261
+ * Query-level actions (reference by name, e.g., "New", "Export")
262
+ */
263
+ actions?: string[];
264
+ /**
265
+ * Item-level actions (reference by name, e.g., "Edit", "Delete")
266
+ */
267
+ itemActions?: string[];
268
+ /**
269
+ * Enable text search (default: true)
270
+ */
271
+ allowTextSearch?: boolean;
272
+ /**
273
+ * Disable bulk edit (default: false)
274
+ */
275
+ disableBulkEdit?: boolean;
276
+ /**
277
+ * Auto-execute on load (default: true). If false, getQuery returns empty result
278
+ */
279
+ autoQuery?: boolean;
280
+ /**
281
+ * Page size (default: 20)
282
+ */
283
+ pageSize?: number;
284
+ };
285
+
286
+ /**
287
+ * Rule validator function that throws an error if invalid, or returns nothing if valid
288
+ */
289
+ type RuleValidatorFn = (value: any, ...params: any[]) => void;
290
+
291
+ /**
292
+ * VirtualPersistentObjectAttribute combines a PersistentObjectAttributeDto with helper methods
293
+ * This allows clean syntax like attr.getValue() and attr.setValue() while keeping the underlying DTO unchanged
294
+ */
295
+ type VirtualPersistentObjectAttribute = Dto.PersistentObjectAttributeDto & {
296
+ /**
297
+ * Gets the converted value of this attribute (e.g., Boolean as boolean, Int32 as number)
298
+ */
299
+ getValue(): any;
300
+ /**
301
+ * Sets the value of this attribute with automatic type conversion
302
+ */
303
+ setValue(value: any): void;
304
+ /**
305
+ * Sets a validation error on this attribute
306
+ */
307
+ setValidationError(error: string): void;
308
+ /**
309
+ * Clears the validation error on this attribute
310
+ */
311
+ clearValidationError(): void;
312
+ };
313
+ /**
314
+ * VirtualPersistentObject combines a PersistentObjectDto with helper methods
315
+ * This allows clean syntax like obj.setAttributeValue() while keeping the underlying DTO unchanged
316
+ */
317
+ type VirtualPersistentObject = Dto.PersistentObjectDto & {
318
+ /**
319
+ * Gets an attribute by name, wrapped with getValue/setValue methods
320
+ */
321
+ getAttribute(name: string): VirtualPersistentObjectAttribute | undefined;
322
+ /**
323
+ * Gets the value of an attribute by name
324
+ */
325
+ getAttributeValue(name: string): any;
326
+ /**
327
+ * Sets the value of an attribute by name
328
+ */
329
+ setAttributeValue(name: string, value: any): void;
330
+ /**
331
+ * Sets a validation error for an attribute
332
+ */
333
+ setValidationError(name: string, error: string): void;
334
+ /**
335
+ * Clears a validation error for an attribute
336
+ */
337
+ clearValidationError(name: string): void;
338
+ /**
339
+ * Sets a notification message on the persistent object
340
+ */
341
+ setNotification(message: string, type: Dto.NotificationType, duration?: number): void;
342
+ };
343
+
344
+ /**
345
+ * Base class for PersistentObject lifecycle methods
346
+ * Extend this class to override lifecycle hooks like onLoad, onSave, onRefresh, etc.
347
+ * All methods have default implementations, so you only need to override what you need.
348
+ */
349
+ declare class VirtualPersistentObjectActions {
350
+ /**
351
+ * Called every time a PersistentObject DTO is created (both new and existing objects)
352
+ * Use this to set metadata on attributes that can only be known at runtime
353
+ * @param obj - The PersistentObject DTO being constructed
354
+ */
355
+ onConstruct(obj: VirtualPersistentObject): void;
356
+ /**
357
+ * Called when loading an existing PersistentObject by ID
358
+ * Use this to load entity data and populate attribute values
359
+ * @param obj - The constructed PersistentObject DTO (after onConstruct)
360
+ * @param parent - The parent PersistentObject if loaded in a master-detail context, null otherwise
361
+ * @returns The PersistentObject with loaded data
362
+ */
363
+ onLoad(obj: VirtualPersistentObject, parent: VirtualPersistentObject | null): Promise<VirtualPersistentObject>;
364
+ /**
365
+ * Called when creating a new PersistentObject via the "New" action
366
+ * Use this to create a fresh entity instance with default values
367
+ * @param obj - The constructed PersistentObject DTO (after onConstruct)
368
+ * @param parent - The parent PersistentObject if creating from a detail query, null otherwise
369
+ * @param query - The Query from which the New action was invoked, null if not from a query
370
+ * @param parameters - Optional parameters including "MenuOption" if NewOptions exist
371
+ * @returns The PersistentObject with default values set
372
+ */
373
+ onNew(obj: VirtualPersistentObject, parent: VirtualPersistentObject | null, query: Dto.QueryDto | null, parameters: Record<string, string> | null): Promise<VirtualPersistentObject>;
374
+ /**
375
+ * Called when an attribute with triggersRefresh: true is changed
376
+ * Use this to update other attributes based on the changed attribute
377
+ * @param obj - The PersistentObject DTO in edit mode
378
+ * @param attribute - The attribute that triggered the refresh (the one with triggersRefresh=true that was changed), wrapped with getValue/setValue
379
+ * @returns The PersistentObject with refreshed attributes
380
+ */
381
+ onRefresh(obj: VirtualPersistentObject, attribute: VirtualPersistentObjectAttribute | undefined): Promise<VirtualPersistentObject>;
382
+ /**
383
+ * Called when the Save action is executed
384
+ * Orchestrates the save process by calling saveNew or saveExisting based on obj.isNew
385
+ * @param obj - The PersistentObject DTO to save
386
+ * @returns The saved PersistentObject
387
+ */
388
+ onSave(obj: VirtualPersistentObject): Promise<VirtualPersistentObject>;
389
+ /**
390
+ * Called by onSave when obj.isNew === true
391
+ * Use this to save a new entity to the data store
392
+ * @param obj - The new PersistentObject DTO to save
393
+ * @returns The saved PersistentObject
394
+ */
395
+ protected saveNew(obj: VirtualPersistentObject): Promise<VirtualPersistentObject>;
396
+ /**
397
+ * Called by onSave when obj.isNew === false
398
+ * Use this to update an existing entity in the data store
399
+ * @param obj - The existing PersistentObject DTO to save
400
+ * @returns The saved PersistentObject
401
+ */
402
+ protected saveExisting(obj: VirtualPersistentObject): Promise<VirtualPersistentObject>;
403
+ /**
404
+ * Called when a reference attribute is changed (via changeReference() on a PersistentObjectAttributeWithReference)
405
+ * The base implementation sets objectId, value, and isValueChanged on the reference attribute.
406
+ * Override this to add custom logic after the reference is set.
407
+ * @param parent - The PersistentObject that contains the reference attribute
408
+ * @param referenceAttribute - The reference attribute that was changed
409
+ * @param query - The query that was used to select the reference
410
+ * @param selectedItem - The QueryResultItem that was selected, or null if reference was cleared
411
+ */
412
+ onSelectReference(_parent: VirtualPersistentObject, referenceAttribute: Dto.PersistentObjectAttributeDto, _query: Dto.QueryDto, selectedItem: Dto.QueryResultItemDto | null): Promise<void>;
413
+ /**
414
+ * Called when the Delete action is executed on selected items in a Query
415
+ * Use this to handle deletion of entities
416
+ * @param parent - The parent PersistentObject if deleting from a detail query, null for top-level queries
417
+ * @param query - The query from which items are being deleted
418
+ * @param selectedItems - The QueryResultItems that are selected for deletion
419
+ */
420
+ onDelete(parent: VirtualPersistentObject | null, query: Dto.QueryDto, selectedItems: Dto.QueryResultItemDto[]): Promise<void>;
421
+ /**
422
+ * Called when a Query of this PersistentObject type is constructed
423
+ * Use this to set metadata on query columns that can only be known at runtime
424
+ * @param query - The Query DTO being constructed
425
+ * @param parent - The parent PersistentObject if this is a detail query, null for top-level queries
426
+ */
427
+ onConstructQuery(query: Dto.QueryDto, parent: VirtualPersistentObject | null): void;
428
+ /**
429
+ * Called when a Query is executed.
430
+ * The base implementation calls getEntities() and applies text search, sorting, and pagination.
431
+ * @param query - The Query DTO with textSearch, sortOptions, skip, top properties set
432
+ * @param parent - The parent PersistentObject if this is a detail query, null for top-level queries
433
+ * @param data - Default data from the query config (used if getEntities is not overridden)
434
+ * @returns The items matching the query criteria and the total count before pagination
435
+ */
436
+ onExecuteQuery(query: Dto.QueryDto, parent: VirtualPersistentObject | null, data: Record<string, any>[]): Promise<VirtualQueryExecuteResult>;
437
+ /**
438
+ * Override this to provide the full list of items for a query.
439
+ * The base onExecuteQuery will handle text search, sorting, and pagination automatically.
440
+ * @param query - The Query DTO with textSearch, sortOptions properties set
441
+ * @param parent - The parent PersistentObject if this is a detail query, null for top-level queries
442
+ * @param data - Default data from the query config
443
+ * @returns All items matching the query criteria (before pagination)
444
+ */
445
+ getEntities(_query: Dto.QueryDto, _parent: VirtualPersistentObject | null, data: Record<string, any>[]): Promise<Record<string, any>[]>;
446
+ }
447
+
448
+ /**
449
+ * Virtual implementation of ServiceHooks for testing without a backend
450
+ */
451
+ declare class VirtualServiceHooks extends ServiceHooks {
452
+ #private;
453
+ constructor();
454
+ /**
455
+ * Intercepts fetch requests and routes them to virtual handlers
456
+ */
457
+ onFetch(request: Request): Promise<Response>;
458
+ /**
459
+ * Registers a PersistentObject configuration
460
+ */
461
+ registerPersistentObject(config: VirtualPersistentObjectConfig): void;
462
+ /**
463
+ * Registers a Query configuration
464
+ */
465
+ registerQuery(config: VirtualQueryConfig): void;
466
+ /**
467
+ * Registers a custom action that can be used on PersistentObjects and Queries
468
+ * @param config - The action configuration with handler
469
+ */
470
+ registerAction(config: ActionConfig): void;
471
+ /**
472
+ * Registers a custom business rule for validation
473
+ * @param name - The rule name (cannot override built-in rules)
474
+ * @param validator - The validation function
475
+ */
476
+ registerBusinessRule(name: string, validator: RuleValidatorFn): void;
477
+ /**
478
+ * Registers a VirtualPersistentObjectActions class for a specific type
479
+ * @param type - The PersistentObject type name
480
+ * @param ActionsClass - The VirtualPersistentObjectActions class constructor
481
+ */
482
+ registerPersistentObjectActions(type: string, ActionsClass: typeof VirtualPersistentObjectActions): void;
483
+ }
484
+
485
+ /**
486
+ * A virtual service for testing without a backend.
487
+ *
488
+ * Register PersistentObjects, Queries, Actions, and BusinessRules before calling initialize().
489
+ * Once initialize() is called, no more registrations are allowed.
490
+ *
491
+ * @example
492
+ * ```typescript
493
+ * const service = new VirtualService();
494
+ * service.registerPersistentObject({ type: "Person", attributes: [...] });
495
+ * service.registerQuery({ name: "AllPersons", persistentObject: "Person" });
496
+ * await service.initialize();
497
+ *
498
+ * // Now use the service
499
+ * const query = await service.getQuery("AllPersons");
500
+ * ```
501
+ */
502
+ declare class VirtualService extends Service {
503
+ #private;
504
+ /**
505
+ * Creates a new VirtualService instance.
506
+ * @param hooks - Optional custom VirtualServiceHooks. If not provided, a default instance is created.
507
+ */
508
+ constructor(hooks?: VirtualServiceHooks);
509
+ /**
510
+ * Gets the VirtualServiceHooks instance.
511
+ */
512
+ get virtualHooks(): VirtualServiceHooks;
513
+ /**
514
+ * Initializes the service and finalizes all registrations.
515
+ * After this method is called, no more registrations are allowed.
516
+ */
517
+ initialize(skipDefaultCredentialLogin?: boolean): Promise<Application>;
518
+ initialize(oneTimeSignInToken: string): Promise<Application>;
519
+ /**
520
+ * Registers a PersistentObject configuration.
521
+ * Must be called before initialize().
522
+ * @param config - The PersistentObject configuration.
523
+ * @throws Error if called after initialize().
524
+ */
525
+ registerPersistentObject(config: VirtualPersistentObjectConfig): void;
526
+ /**
527
+ * Registers a Query configuration.
528
+ * Must be called before initialize().
529
+ * @param config - The Query configuration.
530
+ * @throws Error if called after initialize().
531
+ */
532
+ registerQuery(config: VirtualQueryConfig): void;
533
+ /**
534
+ * Registers a custom action that can be used on PersistentObjects and Queries.
535
+ * Must be called before initialize().
536
+ * @param config - The action configuration with handler.
537
+ * @throws Error if called after initialize().
538
+ */
539
+ registerAction(config: ActionConfig): void;
540
+ /**
541
+ * Registers a custom business rule for validation.
542
+ * Must be called before initialize().
543
+ * @param name - The rule name (cannot override built-in rules).
544
+ * @param validator - The validation function.
545
+ * @throws Error if called after initialize().
546
+ */
547
+ registerBusinessRule(name: string, validator: RuleValidatorFn): void;
548
+ /**
549
+ * Registers a VirtualPersistentObjectActions class for a specific type.
550
+ * Must be called before initialize().
551
+ * @param type - The PersistentObject type name.
552
+ * @param ActionsClass - The VirtualPersistentObjectActions class constructor.
553
+ * @throws Error if called after initialize().
554
+ */
555
+ registerPersistentObjectActions(type: string, ActionsClass: typeof VirtualPersistentObjectActions): void;
556
+ }
557
+
558
+ export { VirtualPersistentObjectActions, VirtualService, VirtualServiceHooks };
559
+ export type { ActionArgs, ActionConfig, ActionContext, ActionHandler, RuleValidatorFn, VirtualPersistentObject, VirtualPersistentObjectAttribute, VirtualPersistentObjectAttributeConfig, VirtualPersistentObjectConfig, VirtualQueryConfig, VirtualQueryExecuteResult };