cogsbox-state 0.5.470 → 0.5.472
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 +2 -51
- package/dist/CogsState.d.ts +15 -5
- package/dist/CogsState.d.ts.map +1 -1
- package/dist/CogsState.jsx +915 -890
- package/dist/CogsState.jsx.map +1 -1
- package/dist/Components.d.ts.map +1 -1
- package/dist/Components.jsx +214 -223
- package/dist/Components.jsx.map +1 -1
- package/dist/store.d.ts +23 -15
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +476 -231
- package/dist/store.js.map +1 -1
- package/package.json +8 -13
- package/src/CogsState.tsx +221 -161
- package/src/Components.tsx +215 -169
- package/src/store.ts +476 -39
package/src/store.ts
CHANGED
|
@@ -99,9 +99,28 @@ export type ValidationState = {
|
|
|
99
99
|
lastValidated?: number;
|
|
100
100
|
validatedValue?: any;
|
|
101
101
|
};
|
|
102
|
+
export type TypeInfo = {
|
|
103
|
+
type:
|
|
104
|
+
| 'string'
|
|
105
|
+
| 'number'
|
|
106
|
+
| 'boolean'
|
|
107
|
+
| 'array'
|
|
108
|
+
| 'object'
|
|
109
|
+
| 'date'
|
|
110
|
+
| 'unknown';
|
|
111
|
+
schema: any; // Store the actual Zod schema object
|
|
112
|
+
source: 'sync' | 'zod4' | 'zod3' | 'runtime' | 'default';
|
|
113
|
+
default: any;
|
|
114
|
+
nullable?: boolean;
|
|
115
|
+
optional?: boolean;
|
|
116
|
+
};
|
|
102
117
|
|
|
118
|
+
// Update ShadowMetadata to include typeInfo
|
|
103
119
|
export type ShadowMetadata = {
|
|
120
|
+
value?: any;
|
|
121
|
+
syncArrayIdPrefix?: string;
|
|
104
122
|
id?: string;
|
|
123
|
+
typeInfo?: TypeInfo;
|
|
105
124
|
stateSource?: 'default' | 'server' | 'localStorage';
|
|
106
125
|
lastServerSync?: number;
|
|
107
126
|
isDirty?: boolean;
|
|
@@ -119,22 +138,13 @@ export type ShadowMetadata = {
|
|
|
119
138
|
validationEnabled: boolean;
|
|
120
139
|
localStorageEnabled: boolean;
|
|
121
140
|
};
|
|
122
|
-
lastUpdated?: number;
|
|
123
141
|
signals?: Array<{
|
|
124
142
|
instanceId: string;
|
|
125
143
|
parentId: string;
|
|
126
144
|
position: number;
|
|
127
145
|
effect?: string;
|
|
128
146
|
}>;
|
|
129
|
-
|
|
130
|
-
instanceId: string;
|
|
131
|
-
path: string[];
|
|
132
|
-
componentId: string;
|
|
133
|
-
meta?: any;
|
|
134
|
-
mapFn: (setter: any, index: number, arraySetter: any) => ReactNode;
|
|
135
|
-
containerRef: HTMLDivElement | null;
|
|
136
|
-
rebuildStateShape: any;
|
|
137
|
-
}>;
|
|
147
|
+
|
|
138
148
|
transformCaches?: Map<
|
|
139
149
|
string,
|
|
140
150
|
{
|
|
@@ -154,7 +164,6 @@ export type ShadowMetadata = {
|
|
|
154
164
|
} & ComponentsType;
|
|
155
165
|
|
|
156
166
|
type ShadowNode = {
|
|
157
|
-
value?: any;
|
|
158
167
|
_meta?: ShadowMetadata;
|
|
159
168
|
[key: string]: any;
|
|
160
169
|
};
|
|
@@ -198,7 +207,7 @@ export type CogsGlobalState = {
|
|
|
198
207
|
arrayPath: string[],
|
|
199
208
|
newItem: any,
|
|
200
209
|
index?: number
|
|
201
|
-
) =>
|
|
210
|
+
) => string;
|
|
202
211
|
removeShadowArrayElement: (key: string, itemPath: string[]) => void;
|
|
203
212
|
registerComponent: (
|
|
204
213
|
stateKey: string,
|
|
@@ -256,37 +265,447 @@ export type CogsGlobalState = {
|
|
|
256
265
|
getSyncInfo: (key: string) => SyncInfo | null;
|
|
257
266
|
};
|
|
258
267
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
268
|
+
function getTypeFromZodSchema(
|
|
269
|
+
schema: any,
|
|
270
|
+
source: 'zod4' | 'zod3' | 'sync' = 'zod4'
|
|
271
|
+
): TypeInfo | null {
|
|
272
|
+
if (!schema) return null;
|
|
273
|
+
|
|
274
|
+
let baseSchema = schema;
|
|
275
|
+
let isNullable = false;
|
|
276
|
+
let isOptional = false;
|
|
277
|
+
let defaultValue: any = undefined;
|
|
278
|
+
let hasDefault = false;
|
|
279
|
+
|
|
280
|
+
// Zod v4 unwrapping
|
|
281
|
+
if (schema._def) {
|
|
282
|
+
let current = schema;
|
|
283
|
+
|
|
284
|
+
// Keep unwrapping until we get to the base type
|
|
285
|
+
while (current._def) {
|
|
286
|
+
const typeName = current._def.typeName;
|
|
287
|
+
|
|
288
|
+
if (typeName === 'ZodOptional') {
|
|
289
|
+
isOptional = true;
|
|
290
|
+
current = current._def.innerType || current.unwrap();
|
|
291
|
+
} else if (typeName === 'ZodNullable') {
|
|
292
|
+
isNullable = true;
|
|
293
|
+
current = current._def.innerType || current.unwrap();
|
|
294
|
+
} else if (typeName === 'ZodDefault') {
|
|
295
|
+
hasDefault = true;
|
|
296
|
+
defaultValue = current._def.defaultValue();
|
|
297
|
+
current = current._def.innerType;
|
|
298
|
+
} else if (typeName === 'ZodEffects') {
|
|
299
|
+
// Handle .refine(), .transform() etc
|
|
300
|
+
current = current._def.schema;
|
|
301
|
+
} else {
|
|
302
|
+
// We've reached the base type
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
baseSchema = current;
|
|
308
|
+
const typeName = baseSchema._def?.typeName;
|
|
309
|
+
|
|
310
|
+
if (typeName === 'ZodNumber') {
|
|
311
|
+
return {
|
|
312
|
+
type: 'number',
|
|
313
|
+
schema: schema, // Store the original schema with wrappers
|
|
314
|
+
source,
|
|
315
|
+
default: hasDefault ? defaultValue : 0,
|
|
316
|
+
nullable: isNullable,
|
|
317
|
+
optional: isOptional,
|
|
318
|
+
};
|
|
319
|
+
} else if (typeName === 'ZodString') {
|
|
320
|
+
return {
|
|
321
|
+
type: 'string',
|
|
322
|
+
schema: schema,
|
|
323
|
+
source,
|
|
324
|
+
default: hasDefault ? defaultValue : '',
|
|
325
|
+
nullable: isNullable,
|
|
326
|
+
optional: isOptional,
|
|
327
|
+
};
|
|
328
|
+
} else if (typeName === 'ZodBoolean') {
|
|
329
|
+
return {
|
|
330
|
+
type: 'boolean',
|
|
331
|
+
schema: schema,
|
|
332
|
+
source,
|
|
333
|
+
default: hasDefault ? defaultValue : false,
|
|
334
|
+
nullable: isNullable,
|
|
335
|
+
optional: isOptional,
|
|
336
|
+
};
|
|
337
|
+
} else if (typeName === 'ZodArray') {
|
|
338
|
+
return {
|
|
339
|
+
type: 'array',
|
|
340
|
+
schema: schema,
|
|
341
|
+
source,
|
|
342
|
+
default: hasDefault ? defaultValue : [],
|
|
343
|
+
nullable: isNullable,
|
|
344
|
+
optional: isOptional,
|
|
345
|
+
};
|
|
346
|
+
} else if (typeName === 'ZodObject') {
|
|
347
|
+
return {
|
|
348
|
+
type: 'object',
|
|
349
|
+
schema: schema,
|
|
350
|
+
source,
|
|
351
|
+
default: hasDefault ? defaultValue : {},
|
|
352
|
+
nullable: isNullable,
|
|
353
|
+
optional: isOptional,
|
|
354
|
+
};
|
|
355
|
+
} else if (typeName === 'ZodDate') {
|
|
356
|
+
return {
|
|
357
|
+
type: 'date',
|
|
358
|
+
schema: schema,
|
|
359
|
+
source,
|
|
360
|
+
default: hasDefault ? defaultValue : new Date(),
|
|
361
|
+
nullable: isNullable,
|
|
362
|
+
optional: isOptional,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Zod v3 unwrapping
|
|
368
|
+
if (schema._type) {
|
|
369
|
+
let current = schema;
|
|
370
|
+
|
|
371
|
+
// Check for wrappers in v3
|
|
372
|
+
while (current) {
|
|
373
|
+
if (current._type === 'optional') {
|
|
374
|
+
isOptional = true;
|
|
375
|
+
current = current._def?.innerType || current._inner;
|
|
376
|
+
} else if (current._type === 'nullable') {
|
|
377
|
+
isNullable = true;
|
|
378
|
+
current = current._def?.innerType || current._inner;
|
|
379
|
+
} else if (current._def?.defaultValue !== undefined) {
|
|
380
|
+
hasDefault = true;
|
|
381
|
+
defaultValue =
|
|
382
|
+
typeof current._def.defaultValue === 'function'
|
|
383
|
+
? current._def.defaultValue()
|
|
384
|
+
: current._def.defaultValue;
|
|
385
|
+
break;
|
|
386
|
+
} else {
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
baseSchema = current;
|
|
392
|
+
|
|
393
|
+
if (baseSchema._type === 'number') {
|
|
394
|
+
return {
|
|
395
|
+
type: 'number',
|
|
396
|
+
schema: schema,
|
|
397
|
+
source,
|
|
398
|
+
default: hasDefault ? defaultValue : 0,
|
|
399
|
+
nullable: isNullable,
|
|
400
|
+
optional: isOptional,
|
|
401
|
+
};
|
|
402
|
+
} else if (baseSchema._type === 'string') {
|
|
403
|
+
return {
|
|
404
|
+
type: 'string',
|
|
405
|
+
schema: schema,
|
|
406
|
+
source,
|
|
407
|
+
default: hasDefault ? defaultValue : '',
|
|
408
|
+
nullable: isNullable,
|
|
409
|
+
optional: isOptional,
|
|
410
|
+
};
|
|
411
|
+
} else if (baseSchema._type === 'boolean') {
|
|
412
|
+
return {
|
|
413
|
+
type: 'boolean',
|
|
414
|
+
schema: schema,
|
|
415
|
+
source,
|
|
416
|
+
default: hasDefault ? defaultValue : false,
|
|
417
|
+
nullable: isNullable,
|
|
418
|
+
optional: isOptional,
|
|
419
|
+
};
|
|
420
|
+
} else if (baseSchema._type === 'array') {
|
|
421
|
+
return {
|
|
422
|
+
type: 'array',
|
|
423
|
+
schema: schema,
|
|
424
|
+
source,
|
|
425
|
+
default: hasDefault ? defaultValue : [],
|
|
426
|
+
nullable: isNullable,
|
|
427
|
+
optional: isOptional,
|
|
428
|
+
};
|
|
429
|
+
} else if (baseSchema._type === 'object') {
|
|
430
|
+
return {
|
|
431
|
+
type: 'object',
|
|
432
|
+
schema: schema,
|
|
433
|
+
source,
|
|
434
|
+
default: hasDefault ? defaultValue : {},
|
|
435
|
+
nullable: isNullable,
|
|
436
|
+
optional: isOptional,
|
|
437
|
+
};
|
|
438
|
+
} else if (baseSchema._type === 'date') {
|
|
439
|
+
return {
|
|
440
|
+
type: 'date',
|
|
441
|
+
schema: schema,
|
|
442
|
+
source,
|
|
443
|
+
default: hasDefault ? defaultValue : new Date(),
|
|
444
|
+
nullable: isNullable,
|
|
445
|
+
optional: isOptional,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Helper to get type info from runtime value
|
|
454
|
+
function getTypeFromValue(value: any): TypeInfo {
|
|
455
|
+
if (value === null) {
|
|
456
|
+
return {
|
|
457
|
+
type: 'unknown',
|
|
458
|
+
schema: null,
|
|
459
|
+
source: 'default',
|
|
460
|
+
default: null,
|
|
461
|
+
nullable: true,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (value === undefined) {
|
|
466
|
+
return {
|
|
467
|
+
type: 'unknown',
|
|
468
|
+
schema: null,
|
|
469
|
+
source: 'default',
|
|
470
|
+
default: undefined,
|
|
471
|
+
optional: true,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const valueType = typeof value;
|
|
476
|
+
|
|
477
|
+
if (valueType === 'number') {
|
|
478
|
+
return { type: 'number', schema: null, source: 'runtime', default: value };
|
|
479
|
+
} else if (valueType === 'string') {
|
|
480
|
+
return { type: 'string', schema: null, source: 'runtime', default: value };
|
|
481
|
+
} else if (valueType === 'boolean') {
|
|
482
|
+
return { type: 'boolean', schema: null, source: 'runtime', default: value };
|
|
483
|
+
} else if (Array.isArray(value)) {
|
|
484
|
+
return { type: 'array', schema: null, source: 'runtime', default: [] };
|
|
485
|
+
} else if (value instanceof Date) {
|
|
486
|
+
return { type: 'date', schema: null, source: 'runtime', default: value };
|
|
487
|
+
} else if (valueType === 'object') {
|
|
488
|
+
return { type: 'object', schema: null, source: 'runtime', default: {} };
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return { type: 'unknown', schema: null, source: 'runtime', default: value };
|
|
492
|
+
}
|
|
493
|
+
type BuildContext = {
|
|
494
|
+
stateKey: string;
|
|
495
|
+
path: string[];
|
|
496
|
+
schemas: {
|
|
497
|
+
sync?: any;
|
|
498
|
+
zodV4?: any;
|
|
499
|
+
zodV3?: any;
|
|
500
|
+
};
|
|
501
|
+
};
|
|
502
|
+
// Update buildShadowNode to use the new schema storage
|
|
503
|
+
export function buildShadowNode(
|
|
504
|
+
stateKey: string,
|
|
505
|
+
value: any,
|
|
506
|
+
context?: BuildContext
|
|
507
|
+
): ShadowNode {
|
|
508
|
+
// For primitive values
|
|
509
|
+
if (value === null || value === undefined || typeof value !== 'object') {
|
|
510
|
+
const node: ShadowNode = { _meta: {} };
|
|
511
|
+
node._meta!.value = value;
|
|
512
|
+
if (context) {
|
|
513
|
+
let typeInfo: TypeInfo | null = null;
|
|
514
|
+
|
|
515
|
+
// 1. Try to get type from sync schema
|
|
516
|
+
if (context.schemas.sync && context.schemas.sync[context.stateKey]) {
|
|
517
|
+
const syncEntry = context.schemas.sync[context.stateKey];
|
|
518
|
+
if (syncEntry.schemas?.validation) {
|
|
519
|
+
// Navigate to the field in the validation schema
|
|
520
|
+
let fieldSchema = syncEntry.schemas.validation;
|
|
521
|
+
for (const segment of context.path) {
|
|
522
|
+
if (fieldSchema?.shape) {
|
|
523
|
+
fieldSchema = fieldSchema.shape[segment];
|
|
524
|
+
} else if (fieldSchema?._def?.shape) {
|
|
525
|
+
fieldSchema = fieldSchema._def.shape()[segment];
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (fieldSchema) {
|
|
530
|
+
typeInfo = getTypeFromZodSchema(fieldSchema, 'sync');
|
|
531
|
+
if (typeInfo) {
|
|
532
|
+
// Use the default from sync schema if available
|
|
533
|
+
if (syncEntry.schemas.defaults) {
|
|
534
|
+
let defaultValue = syncEntry.schemas.defaults;
|
|
535
|
+
for (const segment of context.path) {
|
|
536
|
+
if (defaultValue && typeof defaultValue === 'object') {
|
|
537
|
+
defaultValue = defaultValue[segment];
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (defaultValue !== undefined) {
|
|
541
|
+
typeInfo.default = defaultValue;
|
|
542
|
+
// If no value provided and not optional, use the default
|
|
543
|
+
if (
|
|
544
|
+
(value === undefined || value === null) &&
|
|
545
|
+
!typeInfo.optional
|
|
546
|
+
) {
|
|
547
|
+
node._meta!.value = defaultValue;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// 2. If no sync schema, try Zod v4
|
|
557
|
+
if (!typeInfo && context.schemas.zodV4) {
|
|
558
|
+
let fieldSchema = context.schemas.zodV4;
|
|
559
|
+
for (const segment of context.path) {
|
|
560
|
+
if (fieldSchema?.shape) {
|
|
561
|
+
fieldSchema = fieldSchema.shape[segment];
|
|
562
|
+
} else if (fieldSchema?._def?.shape) {
|
|
563
|
+
fieldSchema = fieldSchema._def.shape()[segment];
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (fieldSchema) {
|
|
568
|
+
typeInfo = getTypeFromZodSchema(fieldSchema, 'zod4');
|
|
569
|
+
if (typeInfo && (value === undefined || value === null)) {
|
|
570
|
+
// Only use default if the field is not optional/nullable
|
|
571
|
+
if (!typeInfo.optional && !typeInfo.nullable) {
|
|
572
|
+
node.value = typeInfo.default;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// 3. If no Zod v4, try Zod v3
|
|
579
|
+
if (!typeInfo && context.schemas.zodV3) {
|
|
580
|
+
let fieldSchema = context.schemas.zodV3;
|
|
581
|
+
for (const segment of context.path) {
|
|
582
|
+
if (fieldSchema?.shape) {
|
|
583
|
+
fieldSchema = fieldSchema.shape[segment];
|
|
584
|
+
} else if (fieldSchema?._shape) {
|
|
585
|
+
fieldSchema = fieldSchema._shape[segment];
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (fieldSchema) {
|
|
590
|
+
typeInfo = getTypeFromZodSchema(fieldSchema, 'zod3');
|
|
591
|
+
if (typeInfo && (value === undefined || value === null)) {
|
|
592
|
+
// Only use default if the field is not optional/nullable
|
|
593
|
+
if (!typeInfo.optional && !typeInfo.nullable) {
|
|
594
|
+
node.value = typeInfo.default;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// 4. Fall back to runtime type
|
|
601
|
+
if (!typeInfo) {
|
|
602
|
+
typeInfo = getTypeFromValue(node._meta!.value);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// Store the type info
|
|
606
|
+
if (typeInfo) {
|
|
607
|
+
if (!node._meta) node._meta = {};
|
|
608
|
+
node._meta.typeInfo = typeInfo;
|
|
609
|
+
}
|
|
610
|
+
} else {
|
|
611
|
+
// No context, just use runtime type
|
|
612
|
+
const typeInfo = getTypeFromValue(value);
|
|
613
|
+
if (!node._meta) node._meta = {};
|
|
614
|
+
node._meta.typeInfo = typeInfo;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return node;
|
|
262
618
|
}
|
|
263
619
|
|
|
620
|
+
// For arrays
|
|
264
621
|
if (Array.isArray(value)) {
|
|
265
622
|
const arrayNode: ShadowNode = { _meta: { arrayKeys: [] } };
|
|
266
623
|
const idKeys: string[] = [];
|
|
267
624
|
|
|
268
|
-
value.forEach((item) => {
|
|
269
|
-
const itemId =
|
|
270
|
-
|
|
625
|
+
value.forEach((item, index) => {
|
|
626
|
+
const itemId = `${generateId(stateKey)}`;
|
|
627
|
+
// Pass context down for array items
|
|
628
|
+
const itemContext = context
|
|
629
|
+
? {
|
|
630
|
+
...context,
|
|
631
|
+
path: [...context.path, index.toString()],
|
|
632
|
+
}
|
|
633
|
+
: undefined;
|
|
634
|
+
arrayNode[itemId] = buildShadowNode(stateKey, item, itemContext);
|
|
271
635
|
idKeys.push(itemId);
|
|
272
636
|
});
|
|
273
637
|
|
|
274
638
|
arrayNode._meta!.arrayKeys = idKeys;
|
|
639
|
+
if (context) {
|
|
640
|
+
// Try to get the array schema
|
|
641
|
+
let arraySchema = null;
|
|
642
|
+
|
|
643
|
+
if (context.schemas.zodV4) {
|
|
644
|
+
let fieldSchema = context.schemas.zodV4;
|
|
645
|
+
for (const segment of context.path) {
|
|
646
|
+
if (fieldSchema?.shape) {
|
|
647
|
+
fieldSchema = fieldSchema.shape[segment];
|
|
648
|
+
} else if (fieldSchema?._def?.shape) {
|
|
649
|
+
fieldSchema = fieldSchema._def.shape()[segment];
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
arraySchema = fieldSchema;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
arrayNode._meta!.typeInfo = {
|
|
656
|
+
type: 'array',
|
|
657
|
+
schema: arraySchema,
|
|
658
|
+
source: arraySchema ? 'zod4' : 'runtime',
|
|
659
|
+
default: [],
|
|
660
|
+
};
|
|
661
|
+
}
|
|
275
662
|
return arrayNode;
|
|
276
663
|
}
|
|
277
664
|
|
|
665
|
+
// For objects
|
|
278
666
|
if (value.constructor === Object) {
|
|
279
667
|
const objectNode: ShadowNode = { _meta: {} };
|
|
280
668
|
for (const key in value) {
|
|
281
669
|
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
282
|
-
|
|
670
|
+
// Pass context down for object properties
|
|
671
|
+
const propContext = context
|
|
672
|
+
? {
|
|
673
|
+
...context,
|
|
674
|
+
path: [...context.path, key],
|
|
675
|
+
}
|
|
676
|
+
: undefined;
|
|
677
|
+
objectNode[key] = buildShadowNode(stateKey, value[key], propContext);
|
|
283
678
|
}
|
|
284
679
|
}
|
|
680
|
+
if (context) {
|
|
681
|
+
// Try to get the object schema
|
|
682
|
+
let objectSchema = null;
|
|
683
|
+
|
|
684
|
+
if (context.schemas.zodV4) {
|
|
685
|
+
let fieldSchema = context.schemas.zodV4;
|
|
686
|
+
for (const segment of context.path) {
|
|
687
|
+
if (fieldSchema?.shape) {
|
|
688
|
+
fieldSchema = fieldSchema.shape[segment];
|
|
689
|
+
} else if (fieldSchema?._def?.shape) {
|
|
690
|
+
fieldSchema = fieldSchema._def.shape()[segment];
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
objectSchema = fieldSchema;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
objectNode._meta!.typeInfo = {
|
|
697
|
+
type: 'object',
|
|
698
|
+
schema: objectSchema,
|
|
699
|
+
source: objectSchema ? 'zod4' : 'runtime',
|
|
700
|
+
default: {},
|
|
701
|
+
};
|
|
702
|
+
}
|
|
285
703
|
return objectNode;
|
|
286
704
|
}
|
|
287
705
|
|
|
288
706
|
return { value };
|
|
289
707
|
}
|
|
708
|
+
|
|
290
709
|
// store.ts - Replace the shadow store methods with mutable versions
|
|
291
710
|
// store.ts - Replace the shadow store methods with mutable versions
|
|
292
711
|
|
|
@@ -294,10 +713,11 @@ export function buildShadowNode(value: any): ShadowNode {
|
|
|
294
713
|
const shadowStateStore = new Map<string, ShadowNode>();
|
|
295
714
|
let globalCounter = 0;
|
|
296
715
|
|
|
297
|
-
export function generateId(
|
|
298
|
-
|
|
716
|
+
export function generateId(stateKey: string): string {
|
|
717
|
+
const rootMeta = getGlobalStore.getState().getShadowMetadata(stateKey, []);
|
|
718
|
+
const prefix = rootMeta?.syncArrayIdPrefix || 'local';
|
|
719
|
+
return `id:${prefix}_${(globalCounter++).toString(36)}`;
|
|
299
720
|
}
|
|
300
|
-
|
|
301
721
|
export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
302
722
|
// Remove shadowStateStore from Zustand state
|
|
303
723
|
|
|
@@ -340,14 +760,29 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
340
760
|
shadowStateStore.delete(key);
|
|
341
761
|
shadowStateStore.delete(`[${key}`);
|
|
342
762
|
|
|
343
|
-
|
|
763
|
+
// Get all available schemas for this state
|
|
764
|
+
const options = get().getInitialOptions(key);
|
|
765
|
+
const syncSchemas = get().getInitialOptions('__syncSchemas');
|
|
766
|
+
|
|
767
|
+
const context: BuildContext = {
|
|
768
|
+
stateKey: key,
|
|
769
|
+
path: [],
|
|
770
|
+
schemas: {
|
|
771
|
+
sync: syncSchemas,
|
|
772
|
+
zodV4: options?.validation?.zodSchemaV4,
|
|
773
|
+
zodV3: options?.validation?.zodSchemaV3,
|
|
774
|
+
},
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
// Build with context so type info is stored
|
|
778
|
+
const newRoot = buildShadowNode(key, initialState, context);
|
|
779
|
+
|
|
344
780
|
if (!newRoot._meta) newRoot._meta = {};
|
|
345
781
|
Object.assign(newRoot._meta, preservedMetadata);
|
|
346
782
|
|
|
347
783
|
const storageKey = Array.isArray(initialState) ? `[${key}` : key;
|
|
348
784
|
shadowStateStore.set(storageKey, newRoot);
|
|
349
785
|
},
|
|
350
|
-
|
|
351
786
|
getShadowNode: (key: string, path: string[]): ShadowNode | undefined => {
|
|
352
787
|
let current: any =
|
|
353
788
|
shadowStateStore.get(key) || shadowStateStore.get(`[${key}`);
|
|
@@ -413,12 +848,13 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
413
848
|
|
|
414
849
|
const nodeKeys = Object.keys(node);
|
|
415
850
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
851
|
+
if (
|
|
852
|
+
node._meta &&
|
|
853
|
+
Object.prototype.hasOwnProperty.call(node._meta, 'value') &&
|
|
854
|
+
nodeKeys.length === 1 &&
|
|
855
|
+
nodeKeys[0] === '_meta'
|
|
856
|
+
) {
|
|
857
|
+
return node._meta.value;
|
|
422
858
|
}
|
|
423
859
|
|
|
424
860
|
const isArrayNode =
|
|
@@ -463,7 +899,7 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
463
899
|
path.length === 0 ? parentNode : parentNode[path[path.length - 1]!];
|
|
464
900
|
|
|
465
901
|
if (!targetNode) {
|
|
466
|
-
parentNode[path[path.length - 1]!] = buildShadowNode(newValue);
|
|
902
|
+
parentNode[path[path.length - 1]!] = buildShadowNode(key, newValue);
|
|
467
903
|
get().notifyPathSubscribers([key, ...path].join('.'), {
|
|
468
904
|
type: 'UPDATE',
|
|
469
905
|
newValue,
|
|
@@ -482,7 +918,7 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
482
918
|
for (const key in nodeToUpdate) {
|
|
483
919
|
if (key !== '_meta') delete nodeToUpdate[key];
|
|
484
920
|
}
|
|
485
|
-
const newNode = buildShadowNode(plainValue);
|
|
921
|
+
const newNode = buildShadowNode(key, plainValue);
|
|
486
922
|
Object.assign(nodeToUpdate, newNode);
|
|
487
923
|
if (oldMeta) {
|
|
488
924
|
nodeToUpdate._meta = { ...oldMeta, ...(nodeToUpdate._meta || {}) };
|
|
@@ -497,7 +933,7 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
497
933
|
if (nodeToUpdate[propKey]) {
|
|
498
934
|
intelligentMerge(nodeToUpdate[propKey], childValue);
|
|
499
935
|
} else {
|
|
500
|
-
nodeToUpdate[propKey] = buildShadowNode(childValue);
|
|
936
|
+
nodeToUpdate[propKey] = buildShadowNode(key, childValue);
|
|
501
937
|
}
|
|
502
938
|
}
|
|
503
939
|
|
|
@@ -549,14 +985,13 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
549
985
|
insertShadowArrayElement: (key, arrayPath, newItem, index) => {
|
|
550
986
|
const arrayNode = get().getShadowNode(key, arrayPath);
|
|
551
987
|
if (!arrayNode?._meta?.arrayKeys) {
|
|
552
|
-
|
|
988
|
+
throw new Error(
|
|
553
989
|
`Array not found at path: ${[key, ...arrayPath].join('.')}`
|
|
554
990
|
);
|
|
555
|
-
return;
|
|
556
991
|
}
|
|
557
992
|
|
|
558
|
-
const newItemId =
|
|
559
|
-
const itemsToAdd = { [newItemId]: buildShadowNode(newItem) };
|
|
993
|
+
const newItemId = `${generateId(key)}`;
|
|
994
|
+
const itemsToAdd = { [newItemId]: buildShadowNode(key, newItem) };
|
|
560
995
|
|
|
561
996
|
// Mutate the array directly
|
|
562
997
|
const currentKeys = arrayNode._meta.arrayKeys;
|
|
@@ -581,6 +1016,8 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
581
1016
|
itemKey: `${arrayKey}.${newItemId}`,
|
|
582
1017
|
index: insertionPoint,
|
|
583
1018
|
});
|
|
1019
|
+
|
|
1020
|
+
return newItemId;
|
|
584
1021
|
},
|
|
585
1022
|
|
|
586
1023
|
insertManyShadowArrayElements: (key, arrayPath, newItems, index) => {
|
|
@@ -600,9 +1037,9 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
600
1037
|
const newIds: string[] = [];
|
|
601
1038
|
|
|
602
1039
|
newItems.forEach((item) => {
|
|
603
|
-
const newItemId =
|
|
1040
|
+
const newItemId = `${generateId(key)}`;
|
|
604
1041
|
newIds.push(newItemId);
|
|
605
|
-
itemsToAdd[newItemId] = buildShadowNode(item);
|
|
1042
|
+
itemsToAdd[newItemId] = buildShadowNode(key, item);
|
|
606
1043
|
});
|
|
607
1044
|
|
|
608
1045
|
// Mutate directly
|