js-bao 0.4.1 → 0.5.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/dist/browser.cjs +104 -33
- package/dist/browser.d.cts +25 -0
- package/dist/browser.d.ts +25 -0
- package/dist/browser.js +104 -33
- package/dist/client.d.cts +25 -0
- package/dist/client.d.ts +25 -0
- package/dist/cloudflare-do.d.cts +25 -0
- package/dist/cloudflare-do.d.ts +25 -0
- package/dist/cloudflare.d.cts +25 -0
- package/dist/cloudflare.d.ts +25 -0
- package/dist/codegen-v2.cjs +14 -3
- package/dist/codegen.cjs +1 -1
- package/dist/index.cjs +104 -33
- package/dist/index.d.cts +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +104 -33
- package/dist/node.cjs +104 -33
- package/dist/node.d.cts +25 -0
- package/dist/node.d.ts +25 -0
- package/dist/node.js +104 -33
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -353,6 +353,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
353
353
|
permissionHint: DocumentPermissionHint;
|
|
354
354
|
}>;
|
|
355
355
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
356
|
+
private static _observedStringSetMaps;
|
|
356
357
|
private _localChanges;
|
|
357
358
|
private _isDirty;
|
|
358
359
|
private _isLoadingFromYjs;
|
|
@@ -427,7 +428,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
427
428
|
added: Record<string, any>;
|
|
428
429
|
modified: Record<string, any>;
|
|
429
430
|
removed: string[];
|
|
431
|
+
stringSetChanges: Record<string, {
|
|
432
|
+
additions: Set<string>;
|
|
433
|
+
removals: Set<string>;
|
|
434
|
+
}>;
|
|
430
435
|
};
|
|
436
|
+
/**
|
|
437
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
438
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
439
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
440
|
+
*/
|
|
441
|
+
private applyStringSetChangeToYMap;
|
|
431
442
|
/**
|
|
432
443
|
* Deep equality check for comparing field values
|
|
433
444
|
*/
|
|
@@ -529,6 +540,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
529
540
|
* Execute a callback with automatic transaction handling for all modified models
|
|
530
541
|
*/
|
|
531
542
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
543
|
+
/**
|
|
544
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
545
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
546
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
547
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
548
|
+
*/
|
|
549
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
550
|
+
/**
|
|
551
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
552
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
553
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
554
|
+
* an observer too.
|
|
555
|
+
*/
|
|
556
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
532
557
|
/**
|
|
533
558
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
534
559
|
*/
|
package/dist/cloudflare-do.d.cts
CHANGED
|
@@ -1635,6 +1635,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1635
1635
|
permissionHint: DocumentPermissionHint;
|
|
1636
1636
|
}>;
|
|
1637
1637
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
1638
|
+
private static _observedStringSetMaps;
|
|
1638
1639
|
private _localChanges;
|
|
1639
1640
|
private _isDirty;
|
|
1640
1641
|
private _isLoadingFromYjs;
|
|
@@ -1709,7 +1710,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1709
1710
|
added: Record<string, any>;
|
|
1710
1711
|
modified: Record<string, any>;
|
|
1711
1712
|
removed: string[];
|
|
1713
|
+
stringSetChanges: Record<string, {
|
|
1714
|
+
additions: Set<string>;
|
|
1715
|
+
removals: Set<string>;
|
|
1716
|
+
}>;
|
|
1712
1717
|
};
|
|
1718
|
+
/**
|
|
1719
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
1720
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
1721
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
1722
|
+
*/
|
|
1723
|
+
private applyStringSetChangeToYMap;
|
|
1713
1724
|
/**
|
|
1714
1725
|
* Deep equality check for comparing field values
|
|
1715
1726
|
*/
|
|
@@ -1811,6 +1822,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1811
1822
|
* Execute a callback with automatic transaction handling for all modified models
|
|
1812
1823
|
*/
|
|
1813
1824
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
1825
|
+
/**
|
|
1826
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
1827
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
1828
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
1829
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
1830
|
+
*/
|
|
1831
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
1832
|
+
/**
|
|
1833
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
1834
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
1835
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
1836
|
+
* an observer too.
|
|
1837
|
+
*/
|
|
1838
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
1814
1839
|
/**
|
|
1815
1840
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
1816
1841
|
*/
|
package/dist/cloudflare-do.d.ts
CHANGED
|
@@ -1635,6 +1635,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1635
1635
|
permissionHint: DocumentPermissionHint;
|
|
1636
1636
|
}>;
|
|
1637
1637
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
1638
|
+
private static _observedStringSetMaps;
|
|
1638
1639
|
private _localChanges;
|
|
1639
1640
|
private _isDirty;
|
|
1640
1641
|
private _isLoadingFromYjs;
|
|
@@ -1709,7 +1710,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1709
1710
|
added: Record<string, any>;
|
|
1710
1711
|
modified: Record<string, any>;
|
|
1711
1712
|
removed: string[];
|
|
1713
|
+
stringSetChanges: Record<string, {
|
|
1714
|
+
additions: Set<string>;
|
|
1715
|
+
removals: Set<string>;
|
|
1716
|
+
}>;
|
|
1712
1717
|
};
|
|
1718
|
+
/**
|
|
1719
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
1720
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
1721
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
1722
|
+
*/
|
|
1723
|
+
private applyStringSetChangeToYMap;
|
|
1713
1724
|
/**
|
|
1714
1725
|
* Deep equality check for comparing field values
|
|
1715
1726
|
*/
|
|
@@ -1811,6 +1822,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1811
1822
|
* Execute a callback with automatic transaction handling for all modified models
|
|
1812
1823
|
*/
|
|
1813
1824
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
1825
|
+
/**
|
|
1826
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
1827
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
1828
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
1829
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
1830
|
+
*/
|
|
1831
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
1832
|
+
/**
|
|
1833
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
1834
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
1835
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
1836
|
+
* an observer too.
|
|
1837
|
+
*/
|
|
1838
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
1814
1839
|
/**
|
|
1815
1840
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
1816
1841
|
*/
|
package/dist/cloudflare.d.cts
CHANGED
|
@@ -353,6 +353,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
353
353
|
permissionHint: DocumentPermissionHint;
|
|
354
354
|
}>;
|
|
355
355
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
356
|
+
private static _observedStringSetMaps;
|
|
356
357
|
private _localChanges;
|
|
357
358
|
private _isDirty;
|
|
358
359
|
private _isLoadingFromYjs;
|
|
@@ -427,7 +428,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
427
428
|
added: Record<string, any>;
|
|
428
429
|
modified: Record<string, any>;
|
|
429
430
|
removed: string[];
|
|
431
|
+
stringSetChanges: Record<string, {
|
|
432
|
+
additions: Set<string>;
|
|
433
|
+
removals: Set<string>;
|
|
434
|
+
}>;
|
|
430
435
|
};
|
|
436
|
+
/**
|
|
437
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
438
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
439
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
440
|
+
*/
|
|
441
|
+
private applyStringSetChangeToYMap;
|
|
431
442
|
/**
|
|
432
443
|
* Deep equality check for comparing field values
|
|
433
444
|
*/
|
|
@@ -529,6 +540,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
529
540
|
* Execute a callback with automatic transaction handling for all modified models
|
|
530
541
|
*/
|
|
531
542
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
543
|
+
/**
|
|
544
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
545
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
546
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
547
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
548
|
+
*/
|
|
549
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
550
|
+
/**
|
|
551
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
552
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
553
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
554
|
+
* an observer too.
|
|
555
|
+
*/
|
|
556
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
532
557
|
/**
|
|
533
558
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
534
559
|
*/
|
package/dist/cloudflare.d.ts
CHANGED
|
@@ -353,6 +353,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
353
353
|
permissionHint: DocumentPermissionHint;
|
|
354
354
|
}>;
|
|
355
355
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
356
|
+
private static _observedStringSetMaps;
|
|
356
357
|
private _localChanges;
|
|
357
358
|
private _isDirty;
|
|
358
359
|
private _isLoadingFromYjs;
|
|
@@ -427,7 +428,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
427
428
|
added: Record<string, any>;
|
|
428
429
|
modified: Record<string, any>;
|
|
429
430
|
removed: string[];
|
|
431
|
+
stringSetChanges: Record<string, {
|
|
432
|
+
additions: Set<string>;
|
|
433
|
+
removals: Set<string>;
|
|
434
|
+
}>;
|
|
430
435
|
};
|
|
436
|
+
/**
|
|
437
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
438
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
439
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
440
|
+
*/
|
|
441
|
+
private applyStringSetChangeToYMap;
|
|
431
442
|
/**
|
|
432
443
|
* Deep equality check for comparing field values
|
|
433
444
|
*/
|
|
@@ -529,6 +540,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
529
540
|
* Execute a callback with automatic transaction handling for all modified models
|
|
530
541
|
*/
|
|
531
542
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
543
|
+
/**
|
|
544
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
545
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
546
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
547
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
548
|
+
*/
|
|
549
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
550
|
+
/**
|
|
551
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
552
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
553
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
554
|
+
* an observer too.
|
|
555
|
+
*/
|
|
556
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
532
557
|
/**
|
|
533
558
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
534
559
|
*/
|
package/dist/codegen-v2.cjs
CHANGED
|
@@ -533,7 +533,8 @@ function renderModelFile(input) {
|
|
|
533
533
|
lines.push(`export interface ${className}Attrs {`);
|
|
534
534
|
for (const [fieldName, opts] of Object.entries(fields)) {
|
|
535
535
|
const tsType = tsTypeForFieldType(opts.type);
|
|
536
|
-
const
|
|
536
|
+
const isRequired = opts.required === true || opts.autoAssign === true && fieldName === "id";
|
|
537
|
+
const optional = isRequired ? "" : "?";
|
|
537
538
|
lines.push(` ${fieldName}${optional}: ${tsType};`);
|
|
538
539
|
}
|
|
539
540
|
lines.push(`}`);
|
|
@@ -642,7 +643,9 @@ function renderBarrel(input) {
|
|
|
642
643
|
lines.push(` }`);
|
|
643
644
|
lines.push(`}`);
|
|
644
645
|
lines.push("");
|
|
645
|
-
lines.push(
|
|
646
|
+
lines.push(
|
|
647
|
+
`export const allModels: Array<typeof BaseModel> = _modelPairs.map((m) => m.class);`
|
|
648
|
+
);
|
|
646
649
|
lines.push("");
|
|
647
650
|
return lines.join("\n");
|
|
648
651
|
}
|
|
@@ -1062,10 +1065,18 @@ function parseDefineModelSchemaArg(obj, sf) {
|
|
|
1062
1065
|
if (opts && opts.type === "id") {
|
|
1063
1066
|
fd.severity = "info";
|
|
1064
1067
|
opts.autoAssign = true;
|
|
1068
|
+
if (fd.field === "id") {
|
|
1069
|
+
opts.required = true;
|
|
1070
|
+
}
|
|
1065
1071
|
} else {
|
|
1066
1072
|
fd.severity = "warn";
|
|
1067
1073
|
}
|
|
1068
1074
|
}
|
|
1075
|
+
for (const [fieldName, opts] of Object.entries(fields)) {
|
|
1076
|
+
if (fieldName === "id" && opts.autoAssign === true && opts.required !== false) {
|
|
1077
|
+
opts.required = true;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1069
1080
|
return { modelName, fields, relationships, uniqueConstraints, functionDefaults };
|
|
1070
1081
|
}
|
|
1071
1082
|
function parseFields(obj, sf) {
|
|
@@ -1477,7 +1488,7 @@ var Logger2 = class _Logger {
|
|
|
1477
1488
|
// package.json
|
|
1478
1489
|
var package_default = {
|
|
1479
1490
|
name: "js-bao",
|
|
1480
|
-
version: "0.
|
|
1491
|
+
version: "0.5.0",
|
|
1481
1492
|
description: "A library providing data modeling capabilities which support live updates and queries.",
|
|
1482
1493
|
types: "dist/index.d.ts",
|
|
1483
1494
|
type: "module",
|
package/dist/codegen.cjs
CHANGED
|
@@ -1181,7 +1181,7 @@ var SchemaExtractor = class {
|
|
|
1181
1181
|
// package.json
|
|
1182
1182
|
var package_default = {
|
|
1183
1183
|
name: "js-bao",
|
|
1184
|
-
version: "0.
|
|
1184
|
+
version: "0.5.0",
|
|
1185
1185
|
description: "A library providing data modeling capabilities which support live updates and queries.",
|
|
1186
1186
|
types: "dist/index.d.ts",
|
|
1187
1187
|
type: "module",
|
package/dist/index.cjs
CHANGED
|
@@ -1858,6 +1858,9 @@ var init_BaseModel = __esm({
|
|
|
1858
1858
|
static connectedDocuments = /* @__PURE__ */ new Map();
|
|
1859
1859
|
static documentYMaps = /* @__PURE__ */ new Map();
|
|
1860
1860
|
// Maps docId to YMap for that document
|
|
1861
|
+
// Tracks nested-Y.Map stringset fields we've already attached observers to,
|
|
1862
|
+
// so attachStringSetObserversToRecord() is idempotent across re-entry.
|
|
1863
|
+
static _observedStringSetMaps = /* @__PURE__ */ new WeakSet();
|
|
1861
1864
|
// Copy-on-write state management
|
|
1862
1865
|
_localChanges = null;
|
|
1863
1866
|
_isDirty = false;
|
|
@@ -2317,7 +2320,7 @@ var init_BaseModel = __esm({
|
|
|
2317
2320
|
validateBeforeSave() {
|
|
2318
2321
|
const schema = this.constructor.getSchema();
|
|
2319
2322
|
for (const [fieldKey, fieldOptions] of schema.fields.entries()) {
|
|
2320
|
-
const currentValue = this.getValue(fieldKey);
|
|
2323
|
+
const currentValue = fieldKey === "id" ? this.id : this.getValue(fieldKey);
|
|
2321
2324
|
if (fieldOptions.required && (currentValue === null || currentValue === void 0)) {
|
|
2322
2325
|
throw new Error(`Field ${fieldKey} is required before save`);
|
|
2323
2326
|
}
|
|
@@ -2377,16 +2380,15 @@ var init_BaseModel = __esm({
|
|
|
2377
2380
|
this._isDirty = true;
|
|
2378
2381
|
}
|
|
2379
2382
|
getStringSetCurrentValues(fieldName) {
|
|
2380
|
-
|
|
2381
|
-
if (yjsData && typeof yjsData === "object") {
|
|
2382
|
-
return Object.keys(yjsData);
|
|
2383
|
-
}
|
|
2384
|
-
return [];
|
|
2383
|
+
return this.getStringSetFromYjs(fieldName);
|
|
2385
2384
|
}
|
|
2386
2385
|
getStringSetFromYjs(fieldName) {
|
|
2387
2386
|
const yjsData = this.getFromYjs(fieldName);
|
|
2387
|
+
if (yjsData instanceof Y2.Map) {
|
|
2388
|
+
return Array.from(yjsData.keys());
|
|
2389
|
+
}
|
|
2388
2390
|
if (yjsData && typeof yjsData === "object") {
|
|
2389
|
-
return Object.keys(yjsData);
|
|
2391
|
+
return Object.keys(yjsData).filter((k) => Boolean(yjsData[k]));
|
|
2390
2392
|
}
|
|
2391
2393
|
return [];
|
|
2392
2394
|
}
|
|
@@ -2997,7 +2999,7 @@ var init_BaseModel = __esm({
|
|
|
2997
2999
|
Logger.debug(
|
|
2998
3000
|
`[_diffWithYjsData] No unsaved changes, returning empty diff`
|
|
2999
3001
|
);
|
|
3000
|
-
return { added: {}, modified: {}, removed: [] };
|
|
3002
|
+
return { added: {}, modified: {}, removed: [], stringSetChanges: {} };
|
|
3001
3003
|
}
|
|
3002
3004
|
const modelConstructor = this.constructor;
|
|
3003
3005
|
const schema = modelConstructor.getSchema();
|
|
@@ -3028,6 +3030,7 @@ var init_BaseModel = __esm({
|
|
|
3028
3030
|
const added = {};
|
|
3029
3031
|
const modified = {};
|
|
3030
3032
|
const removed = [];
|
|
3033
|
+
const stringSetChanges = {};
|
|
3031
3034
|
if (!recordYMap) {
|
|
3032
3035
|
Logger.debug(
|
|
3033
3036
|
`[_diffWithYjsData] No existing recordYMap, treating all local changes as 'added'`
|
|
@@ -3036,11 +3039,12 @@ var init_BaseModel = __esm({
|
|
|
3036
3039
|
for (const [key, value] of Object.entries(this._localChanges)) {
|
|
3037
3040
|
Logger.debug(`[_diffWithYjsData] Adding field '${key}': ${value}`);
|
|
3038
3041
|
if (value && value.type === "stringset") {
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
+
if (value.additions.size > 0 || value.removals.size > 0) {
|
|
3043
|
+
stringSetChanges[key] = {
|
|
3044
|
+
additions: value.additions,
|
|
3045
|
+
removals: value.removals
|
|
3046
|
+
};
|
|
3042
3047
|
}
|
|
3043
|
-
added[key] = stringSetData;
|
|
3044
3048
|
} else {
|
|
3045
3049
|
added[key] = value;
|
|
3046
3050
|
}
|
|
@@ -3049,9 +3053,10 @@ var init_BaseModel = __esm({
|
|
|
3049
3053
|
Logger.debug(`[_diffWithYjsData] Final diff for new record:`, {
|
|
3050
3054
|
added,
|
|
3051
3055
|
modified: {},
|
|
3052
|
-
removed: []
|
|
3056
|
+
removed: [],
|
|
3057
|
+
stringSetChanges
|
|
3053
3058
|
});
|
|
3054
|
-
return { added, modified, removed: [] };
|
|
3059
|
+
return { added, modified, removed: [], stringSetChanges };
|
|
3055
3060
|
}
|
|
3056
3061
|
Logger.debug(
|
|
3057
3062
|
`[_diffWithYjsData] Existing record found, comparing local changes with Y.js data`
|
|
@@ -3068,21 +3073,11 @@ var init_BaseModel = __esm({
|
|
|
3068
3073
|
`[_diffWithYjsData] Processing field '${key}' with local value: ${localValue}`
|
|
3069
3074
|
);
|
|
3070
3075
|
if (localValue && localValue.type === "stringset") {
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
newStringSetData[addition] = true;
|
|
3077
|
-
}
|
|
3078
|
-
for (const removal of localValue.removals) {
|
|
3079
|
-
delete newStringSetData[removal];
|
|
3080
|
-
}
|
|
3081
|
-
const yjsValue = recordYMap.get(key);
|
|
3082
|
-
if (yjsValue === void 0) {
|
|
3083
|
-
added[key] = newStringSetData;
|
|
3084
|
-
} else if (!this._deepEqual(yjsValue, newStringSetData)) {
|
|
3085
|
-
modified[key] = newStringSetData;
|
|
3076
|
+
if (localValue.additions.size > 0 || localValue.removals.size > 0) {
|
|
3077
|
+
stringSetChanges[key] = {
|
|
3078
|
+
additions: localValue.additions,
|
|
3079
|
+
removals: localValue.removals
|
|
3080
|
+
};
|
|
3086
3081
|
}
|
|
3087
3082
|
} else {
|
|
3088
3083
|
const yjsValue = recordYMap.get(key);
|
|
@@ -3108,14 +3103,43 @@ var init_BaseModel = __esm({
|
|
|
3108
3103
|
Logger.debug(`[_diffWithYjsData] Final diff result:`, {
|
|
3109
3104
|
added,
|
|
3110
3105
|
modified,
|
|
3111
|
-
removed
|
|
3106
|
+
removed,
|
|
3107
|
+
stringSetChanges
|
|
3112
3108
|
});
|
|
3113
3109
|
Logger.verbose(`[${modelConstructor.name}] Diff for ${this.id}:`, {
|
|
3114
3110
|
added: Object.keys(added),
|
|
3115
3111
|
modified: Object.keys(modified),
|
|
3116
|
-
removed
|
|
3112
|
+
removed,
|
|
3113
|
+
stringSetChanges: Object.keys(stringSetChanges)
|
|
3117
3114
|
});
|
|
3118
|
-
return { added, modified, removed };
|
|
3115
|
+
return { added, modified, removed, stringSetChanges };
|
|
3116
|
+
}
|
|
3117
|
+
/**
|
|
3118
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
3119
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
3120
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
3121
|
+
*/
|
|
3122
|
+
applyStringSetChangeToYMap(recordYMap, fieldName, change) {
|
|
3123
|
+
let nested = recordYMap.get(fieldName);
|
|
3124
|
+
if (!(nested instanceof Y2.Map)) {
|
|
3125
|
+
const migrated = new Y2.Map();
|
|
3126
|
+
if (nested && typeof nested === "object") {
|
|
3127
|
+
for (const [member, marker] of Object.entries(
|
|
3128
|
+
nested
|
|
3129
|
+
)) {
|
|
3130
|
+
if (Boolean(marker)) migrated.set(member, true);
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
recordYMap.set(fieldName, migrated);
|
|
3134
|
+
nested = migrated;
|
|
3135
|
+
}
|
|
3136
|
+
const target = nested;
|
|
3137
|
+
for (const member of change.additions) {
|
|
3138
|
+
target.set(member, true);
|
|
3139
|
+
}
|
|
3140
|
+
for (const member of change.removals) {
|
|
3141
|
+
target.delete(member);
|
|
3142
|
+
}
|
|
3119
3143
|
}
|
|
3120
3144
|
/**
|
|
3121
3145
|
* Deep equality check for comparing field values
|
|
@@ -3354,7 +3378,7 @@ var init_BaseModel = __esm({
|
|
|
3354
3378
|
Logger.debug(`[${modelName}.save] About to calculate diff`);
|
|
3355
3379
|
const diff = this._diffWithYjsData();
|
|
3356
3380
|
Logger.debug(`[${modelName}.save] Diff result:`, diff);
|
|
3357
|
-
const hasChanges = Object.keys(diff.added).length > 0 || Object.keys(diff.modified).length > 0 || diff.removed.length > 0;
|
|
3381
|
+
const hasChanges = Object.keys(diff.added).length > 0 || Object.keys(diff.modified).length > 0 || diff.removed.length > 0 || Object.keys(diff.stringSetChanges).length > 0;
|
|
3358
3382
|
Logger.debug(`[${modelName}.save] hasChanges: ${hasChanges}`);
|
|
3359
3383
|
if (!hasChanges && isUpdate) {
|
|
3360
3384
|
Logger.verbose(
|
|
@@ -3472,6 +3496,16 @@ var init_BaseModel = __esm({
|
|
|
3472
3496
|
Logger.debug(`[${modelName}.save] Removing field '${key}'`);
|
|
3473
3497
|
recordYMap.delete(key);
|
|
3474
3498
|
}
|
|
3499
|
+
for (const [fieldName, change] of Object.entries(diff.stringSetChanges)) {
|
|
3500
|
+
Logger.debug(
|
|
3501
|
+
`[${modelName}.save] Applying stringset change to field '${fieldName}':`,
|
|
3502
|
+
{
|
|
3503
|
+
additions: Array.from(change.additions),
|
|
3504
|
+
removals: Array.from(change.removals)
|
|
3505
|
+
}
|
|
3506
|
+
);
|
|
3507
|
+
this.applyStringSetChangeToYMap(recordYMap, fieldName, change);
|
|
3508
|
+
}
|
|
3475
3509
|
Logger.debug(
|
|
3476
3510
|
`[${modelName}.save] After applying changes, recordYMap contents:`,
|
|
3477
3511
|
Object.fromEntries(recordYMap.entries())
|
|
@@ -4656,6 +4690,39 @@ var init_BaseModel = __esm({
|
|
|
4656
4690
|
_BaseModel.prototype.setValue = originalSetValue;
|
|
4657
4691
|
}
|
|
4658
4692
|
}
|
|
4693
|
+
/**
|
|
4694
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
4695
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
4696
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
4697
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
4698
|
+
*/
|
|
4699
|
+
static observeStringSetMapOnce(nestedMap) {
|
|
4700
|
+
if (_BaseModel._observedStringSetMaps.has(nestedMap)) return;
|
|
4701
|
+
_BaseModel._observedStringSetMaps.add(nestedMap);
|
|
4702
|
+
const modelConstructor = this;
|
|
4703
|
+
nestedMap.observe(() => {
|
|
4704
|
+
Logger.verbose(
|
|
4705
|
+
`[${modelConstructor.name}] Nested stringset Y.Map changed; notifying listeners`
|
|
4706
|
+
);
|
|
4707
|
+
modelConstructor.notifyListeners();
|
|
4708
|
+
});
|
|
4709
|
+
}
|
|
4710
|
+
/**
|
|
4711
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
4712
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
4713
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
4714
|
+
* an observer too.
|
|
4715
|
+
*/
|
|
4716
|
+
static attachStringSetObserversToRecord(recordYMap, schema) {
|
|
4717
|
+
if (!schema?.fields) return;
|
|
4718
|
+
for (const [fieldKey, fieldOptions] of schema.fields) {
|
|
4719
|
+
if (fieldOptions?.type !== "stringset") continue;
|
|
4720
|
+
const value = recordYMap.get(fieldKey);
|
|
4721
|
+
if (value instanceof Y2.Map) {
|
|
4722
|
+
this.observeStringSetMapOnce(value);
|
|
4723
|
+
}
|
|
4724
|
+
}
|
|
4725
|
+
}
|
|
4659
4726
|
/**
|
|
4660
4727
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
4661
4728
|
*/
|
|
@@ -4672,11 +4739,13 @@ var init_BaseModel = __esm({
|
|
|
4672
4739
|
Logger.verbose(
|
|
4673
4740
|
`[${modelName}] Setting up nested YMap observer for record ${recordId}`
|
|
4674
4741
|
);
|
|
4742
|
+
modelConstructor.attachStringSetObserversToRecord(recordYMap, schema);
|
|
4675
4743
|
recordYMap.observe(async (event) => {
|
|
4676
4744
|
Logger.verbose(
|
|
4677
4745
|
`[${modelName}] Nested YMap change detected for record ${recordId}:`,
|
|
4678
4746
|
event
|
|
4679
4747
|
);
|
|
4748
|
+
modelConstructor.attachStringSetObserversToRecord(recordYMap, schema);
|
|
4680
4749
|
const currentDbInstance = _BaseModel.dbInstance;
|
|
4681
4750
|
if (!currentDbInstance) {
|
|
4682
4751
|
Logger.error(
|
|
@@ -4750,11 +4819,13 @@ var init_BaseModel = __esm({
|
|
|
4750
4819
|
Logger.verbose(
|
|
4751
4820
|
`[${modelName}] Setting up nested YMap observer for record ${recordId} in document ${docId}`
|
|
4752
4821
|
);
|
|
4822
|
+
modelConstructor.attachStringSetObserversToRecord(recordYMap, schema);
|
|
4753
4823
|
recordYMap.observe(async (event) => {
|
|
4754
4824
|
Logger.verbose(
|
|
4755
4825
|
`[${modelName}] Nested YMap change detected for record ${recordId} in document ${docId}:`,
|
|
4756
4826
|
event
|
|
4757
4827
|
);
|
|
4828
|
+
modelConstructor.attachStringSetObserversToRecord(recordYMap, schema);
|
|
4758
4829
|
const currentDbInstance = _BaseModel.dbInstance;
|
|
4759
4830
|
if (!currentDbInstance) {
|
|
4760
4831
|
Logger.error(
|
package/dist/index.d.cts
CHANGED
|
@@ -488,6 +488,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
488
488
|
permissionHint: DocumentPermissionHint;
|
|
489
489
|
}>;
|
|
490
490
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
491
|
+
private static _observedStringSetMaps;
|
|
491
492
|
private _localChanges;
|
|
492
493
|
private _isDirty;
|
|
493
494
|
private _isLoadingFromYjs;
|
|
@@ -562,7 +563,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
562
563
|
added: Record<string, any>;
|
|
563
564
|
modified: Record<string, any>;
|
|
564
565
|
removed: string[];
|
|
566
|
+
stringSetChanges: Record<string, {
|
|
567
|
+
additions: Set<string>;
|
|
568
|
+
removals: Set<string>;
|
|
569
|
+
}>;
|
|
565
570
|
};
|
|
571
|
+
/**
|
|
572
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
573
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
574
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
575
|
+
*/
|
|
576
|
+
private applyStringSetChangeToYMap;
|
|
566
577
|
/**
|
|
567
578
|
* Deep equality check for comparing field values
|
|
568
579
|
*/
|
|
@@ -664,6 +675,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
664
675
|
* Execute a callback with automatic transaction handling for all modified models
|
|
665
676
|
*/
|
|
666
677
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
678
|
+
/**
|
|
679
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
680
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
681
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
682
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
683
|
+
*/
|
|
684
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
685
|
+
/**
|
|
686
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
687
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
688
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
689
|
+
* an observer too.
|
|
690
|
+
*/
|
|
691
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
667
692
|
/**
|
|
668
693
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
669
694
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -488,6 +488,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
488
488
|
permissionHint: DocumentPermissionHint;
|
|
489
489
|
}>;
|
|
490
490
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
491
|
+
private static _observedStringSetMaps;
|
|
491
492
|
private _localChanges;
|
|
492
493
|
private _isDirty;
|
|
493
494
|
private _isLoadingFromYjs;
|
|
@@ -562,7 +563,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
562
563
|
added: Record<string, any>;
|
|
563
564
|
modified: Record<string, any>;
|
|
564
565
|
removed: string[];
|
|
566
|
+
stringSetChanges: Record<string, {
|
|
567
|
+
additions: Set<string>;
|
|
568
|
+
removals: Set<string>;
|
|
569
|
+
}>;
|
|
565
570
|
};
|
|
571
|
+
/**
|
|
572
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
573
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
574
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
575
|
+
*/
|
|
576
|
+
private applyStringSetChangeToYMap;
|
|
566
577
|
/**
|
|
567
578
|
* Deep equality check for comparing field values
|
|
568
579
|
*/
|
|
@@ -664,6 +675,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
664
675
|
* Execute a callback with automatic transaction handling for all modified models
|
|
665
676
|
*/
|
|
666
677
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
678
|
+
/**
|
|
679
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
680
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
681
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
682
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
683
|
+
*/
|
|
684
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
685
|
+
/**
|
|
686
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
687
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
688
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
689
|
+
* an observer too.
|
|
690
|
+
*/
|
|
691
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
667
692
|
/**
|
|
668
693
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
669
694
|
*/
|