@converse/skeletor 3.1.3 → 3.1.4
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/CHANGES.md +12 -0
- package/README.md +3 -2
- package/dist/skeletor.d.ts +3 -3
- package/dist/skeletor.esm.js +9 -9
- package/dist/skeletor.esm.js.map +1 -1
- package/dist/skeletor.js +9 -9
- package/dist/skeletor.js.map +1 -1
- package/dist/skeletor.min.js +3 -3
- package/dist/skeletor.node.js +9 -9
- package/dist/skeletor.node.mjs +9 -9
- package/package.json +1 -1
- package/src/collection.ts +5 -5
- package/src/model.ts +6 -6
package/CHANGES.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.1.4 (2026-06-23)
|
|
4
|
+
|
|
5
|
+
- Fix the `autoSync` hydration promise clobbering a consumer's own `initialized` promise.
|
|
6
|
+
The promise that resolves once hydration is complete is now exposed as `hydrated` (on both
|
|
7
|
+
`Model` and `Collection`) instead of `initialized`. The old name collided with the common
|
|
8
|
+
convention (used by Converse.js) of setting a `model.initialized` promise inside
|
|
9
|
+
`initialize()` to track a consumer's own async setup.
|
|
10
|
+
|
|
11
|
+
Skeletor no longer sets or reads `initialized`. Await `model.hydrated` / `collection.hydrated`
|
|
12
|
+
to know when hydration is complete. If you used the autoSync `initialized` promise added
|
|
13
|
+
in 3.1.0, rename those reads to `hydrated`.
|
|
14
|
+
|
|
3
15
|
## 3.1.3 (2026-06-23)
|
|
4
16
|
|
|
5
17
|
- Fix a regression (since 3.1.0) where a missing record on a `read` was treated as an error.
|
package/README.md
CHANGED
|
@@ -159,7 +159,7 @@ class Settings extends Model {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
const settings = new Settings({ id: 'main' });
|
|
162
|
-
await settings.
|
|
162
|
+
await settings.hydrated; // resolves when prior data has been loaded
|
|
163
163
|
|
|
164
164
|
settings.attrs.theme = 'dark'; // persisted automatically (debounced)
|
|
165
165
|
settings.set('lang', 'en'); // also auto-saved
|
|
@@ -171,7 +171,8 @@ settings.set('transient', true, { noAutoSave: true });
|
|
|
171
171
|
Pending writes are debounced (see `autoSyncDelay`, default 100ms) and flushed when the
|
|
172
172
|
page is hidden (`visibilitychange`) or unloaded (`pagehide`).
|
|
173
173
|
|
|
174
|
-
When `autoSync` is off, `
|
|
174
|
+
When `autoSync` is off, `hydrated` is `undefined`, but `await model.hydrated` is still safe
|
|
175
|
+
(awaiting `undefined` is a no-op), so code can await it uniformly.
|
|
175
176
|
|
|
176
177
|
On a `Collection`, `autoSync` is **hydrate-only**: the collection loads its stored
|
|
177
178
|
state on construction but does not auto-save on `add`/`remove`/`reset`. To persist
|
package/dist/skeletor.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare class Collection<T extends Model = Model> extends EventEmitterObj
|
|
|
26
26
|
_storage?: PersistentStorage;
|
|
27
27
|
_comparator?: Comparator<T>;
|
|
28
28
|
_url: string;
|
|
29
|
-
|
|
29
|
+
hydrated?: Promise<void>;
|
|
30
30
|
models: T[];
|
|
31
31
|
protected _byId: Record<string, T>;
|
|
32
32
|
protected _model?: new (attributes?: Partial<ModelAttributes>, options?: ModelOptions) => T;
|
|
@@ -51,7 +51,7 @@ export declare class Collection<T extends Model = Model> extends EventEmitterObj
|
|
|
51
51
|
set browserStorage(s: PersistentStorage);
|
|
52
52
|
/**
|
|
53
53
|
* Override to return `true` to automatically load the collection from
|
|
54
|
-
* storage on construction. Await `
|
|
54
|
+
* storage on construction. Await `hydrated` to know when hydration
|
|
55
55
|
* is complete.
|
|
56
56
|
*
|
|
57
57
|
* Note: collection `autoSync` is hydrate-only. Unlike `Model`, it does
|
|
@@ -545,7 +545,7 @@ export declare class Model<T extends ModelAttributes = ModelAttributes> extends
|
|
|
545
545
|
cid: string;
|
|
546
546
|
collection?: Collection;
|
|
547
547
|
id: string | number;
|
|
548
|
-
|
|
548
|
+
hydrated?: Promise<void>;
|
|
549
549
|
validationError: string | number | null;
|
|
550
550
|
/**
|
|
551
551
|
* Create a new model with the specified attributes. A client id (`cid`)
|
package/dist/skeletor.esm.js
CHANGED
|
@@ -10907,18 +10907,18 @@ class Model extends EventEmitterObject {
|
|
|
10907
10907
|
this.initialize.apply(this, arguments);
|
|
10908
10908
|
// Reset changed after initial set
|
|
10909
10909
|
this.changed = {};
|
|
10910
|
-
// When autoSync is on, `
|
|
10911
|
-
// uniformly `await model.
|
|
10910
|
+
// When autoSync is on, `hydrated` is always a Promise so callers can
|
|
10911
|
+
// uniformly `await model.hydrated`. It only hydrates from storage when
|
|
10912
10912
|
// there's something to load (storage configured and the model isn't new);
|
|
10913
10913
|
// otherwise it's already ready and resolves immediately.
|
|
10914
10914
|
if (this.autoSync) {
|
|
10915
10915
|
if (getStorage(this) && !this.isNew()) {
|
|
10916
10916
|
__classPrivateFieldSet(this, _Model_state, 'hydrating', "f");
|
|
10917
|
-
this.
|
|
10917
|
+
this.hydrated = __classPrivateFieldGet(this, _Model_instances, "m", _Model_hydrate).call(this);
|
|
10918
10918
|
}
|
|
10919
10919
|
else {
|
|
10920
10920
|
__classPrivateFieldSet(this, _Model_state, 'ready', "f");
|
|
10921
|
-
this.
|
|
10921
|
+
this.hydrated = Promise.resolve();
|
|
10922
10922
|
}
|
|
10923
10923
|
}
|
|
10924
10924
|
else {
|
|
@@ -11091,7 +11091,7 @@ class Model extends EventEmitterObject {
|
|
|
11091
11091
|
// Guard must come after arg normalization: when called as set(obj, opts),
|
|
11092
11092
|
// fromStorage lives in `val` (second arg), not `options` (third arg).
|
|
11093
11093
|
if (this.autoSync && __classPrivateFieldGet(this, _Model_state, "f") === 'hydrating' && !options.fromStorage) {
|
|
11094
|
-
throw new Error(`Skeletor: set() called on an autoSync model before
|
|
11094
|
+
throw new Error(`Skeletor: set() called on an autoSync model before hydration resolved. Await model.hydrated first.`);
|
|
11095
11095
|
}
|
|
11096
11096
|
// Run validation.
|
|
11097
11097
|
if (!this._validate(attrs, options))
|
|
@@ -11531,11 +11531,11 @@ class Collection extends EventEmitterObject {
|
|
|
11531
11531
|
if (models)
|
|
11532
11532
|
this.reset(models, Object.assign({ silent: true }, options));
|
|
11533
11533
|
this[Symbol.iterator] = this.values;
|
|
11534
|
-
// When autoSync is on, `
|
|
11535
|
-
// uniformly `await collection.
|
|
11534
|
+
// When autoSync is on, `hydrated` is always a Promise so callers can
|
|
11535
|
+
// uniformly `await collection.hydrated`; it resolves immediately when
|
|
11536
11536
|
// there's no storage to hydrate from.
|
|
11537
11537
|
if (this.autoSync) {
|
|
11538
|
-
this.
|
|
11538
|
+
this.hydrated = getStorage(this) ? __classPrivateFieldGet(this, _Collection_instances, "m", _Collection_hydrate).call(this) : Promise.resolve();
|
|
11539
11539
|
}
|
|
11540
11540
|
}
|
|
11541
11541
|
get comparator() {
|
|
@@ -11567,7 +11567,7 @@ class Collection extends EventEmitterObject {
|
|
|
11567
11567
|
}
|
|
11568
11568
|
/**
|
|
11569
11569
|
* Override to return `true` to automatically load the collection from
|
|
11570
|
-
* storage on construction. Await `
|
|
11570
|
+
* storage on construction. Await `hydrated` to know when hydration
|
|
11571
11571
|
* is complete.
|
|
11572
11572
|
*
|
|
11573
11573
|
* Note: collection `autoSync` is hydrate-only. Unlike `Model`, it does
|