@converse/skeletor 3.1.1 → 3.1.3
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 +139 -0
- package/dist/skeletor.esm.js +21 -13
- package/dist/skeletor.esm.js.map +1 -1
- package/dist/skeletor.js +21 -13
- package/dist/skeletor.js.map +1 -1
- package/dist/skeletor.min.js +1 -1
- package/dist/skeletor.node.js +21 -13
- package/dist/skeletor.node.mjs +21 -13
- package/package.json +4 -2
- package/src/collection.ts +3 -2
- package/src/model.ts +0 -4
- package/src/storage.ts +18 -6
package/CHANGES.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 3.1.3 (2026-06-23)
|
|
4
|
+
|
|
5
|
+
- Fix a regression (since 3.1.0) where a missing record on a `read` was treated as an error.
|
|
6
|
+
`model.fetch({ promise: true })` rejected with the bare string `'Record Not Found'` on a
|
|
7
|
+
first-run read of a non-existent record (and the `error` callback / `'error'` event fired),
|
|
8
|
+
where previously 3.0.x had resolved. A read miss is a normal empty state, so it now
|
|
9
|
+
resolves with `null` on both the callback (`success`) and promise forms.
|
|
10
|
+
|
|
11
|
+
**Behaviour change:** a read miss no longer fires the `error` callback or the `'error'` event,
|
|
12
|
+
it fires `success(null)` instead.
|
|
13
|
+
|
|
14
|
+
- Storage-layer `sync` failures now surface a real `Error` (with a stack) through the `error`
|
|
15
|
+
callback / rejected promise instead of a bare string. The internal `Model#hydrate`
|
|
16
|
+
`'Record Not Found'` string-match workaround is removed accordingly.
|
|
17
|
+
|
|
18
|
+
## 3.1.2 (2026-06-22)
|
|
19
|
+
|
|
20
|
+
- Fix the published package missing its `dist/` directory. `dist/` is gitignored and nothing built
|
|
21
|
+
it during the publish lifecycle, so `npm publish` could ship a tarball without the compiled
|
|
22
|
+
bundles that `main`/`module`/`exports` point at (3.1.1 was published this way and is unusable).
|
|
23
|
+
Add a `prepack` script that runs the build, so `npm pack` and `npm publish` always include a
|
|
24
|
+
freshly built `dist/`.
|
|
25
|
+
|
|
26
|
+
## 3.1.1 (2026-06-22)
|
|
27
|
+
|
|
28
|
+
- Fix browser builds failing to resolve `./drivers/nodeSQLiteStorage`. The node-only SQLite
|
|
29
|
+
storage driver is now registered by the `@converse/skeletor/node` entry point instead of
|
|
30
|
+
being pulled in via a dynamic `import()` from the shared storage module. The browser bundles
|
|
31
|
+
(`skeletor.esm.js`, `skeletor.js`, `skeletor.min.js`) no longer contain a reference to a file
|
|
32
|
+
that isn't published, which broke downstream bundlers.
|
|
33
|
+
|
|
34
|
+
## 3.1.0 (2026-06-22)
|
|
35
|
+
|
|
36
|
+
- Add an ESM build
|
|
37
|
+
- **Rename `browserStorage` → `storage`** on `Model` and `Collection`
|
|
38
|
+
- Add `BrowserStorage` as a deprecated export alias for `PersistentStorage`
|
|
39
|
+
- Add `autoSync` opt-in for transparent local persistence:
|
|
40
|
+
- Declare `get autoSync() { return true; }` on a model or collection to enable.
|
|
41
|
+
- **Auto-hydrate**: the model/collection loads its stored state on construction. `await model.initialized` resolves when done.
|
|
42
|
+
- **Auto-save** (models only): any `set()` (including `attrs.x = y`) that produces changes schedules a debounced save. Pass `{ noAutoSave: true }` to opt out per-call
|
|
43
|
+
- **Flush on unload**: when `autoSync` is used in a browser, Skeletor lazily registers `pagehide`/`visibilitychange` listeners that make a best-effort flush of pending writes when the tab is hidden/closing.
|
|
44
|
+
- **Destroy/save ordering**: `destroy()` now sequences its delete after any auto-save that has already fired and is still in flight, so a late write can no longer land after the delete and resurrect the record.
|
|
45
|
+
- **Error reporting**: a failed auto-save emits an `error` event on the model. Storage-layer failures surface through `sync`'s `error` callback (as before), and rejections that bypass it are emitted on the same event.
|
|
46
|
+
- Override `get autoSyncDelay()` to tune the debounce window (default: 100 ms).
|
|
47
|
+
- Complete the `fetch({ promise: true })` contract: `Model.fetch` now supports the `promise` option (previously ignored), and the promise returned by both `Model.fetch` and `Collection.fetch` now **rejects** on error instead of hanging forever.
|
|
48
|
+
- Add `PersistentStorage.flushAll()` static method to flush all registered storage instances.
|
|
49
|
+
- Add `getStorage(obj)` helper export — returns the configured storage for a model/collection, checking both `storage` and `browserStorage` (preserves compat with subclasses that still override `get browserStorage()`).
|
|
50
|
+
- Add computed properties to `Model`. Declare a `computed` getter returning `{ key: { deps, fn } }` definitions.
|
|
51
|
+
Values are cached, recalculated when deps change, and fire `change:key` events.
|
|
52
|
+
Accessible via `model.get('key')` and `model.attrs.key`.
|
|
53
|
+
- Add `attrs` proxy property on `Model` for ergonomic reactive attribute access:
|
|
54
|
+
`model.attrs.name` reads, `model.attrs.name = 'Bob'` writes (fires change events).
|
|
55
|
+
- Add `subscribe()` method to `EventEmitter`, `Model`, and `Collection`, returning an unsubscribe function.
|
|
56
|
+
Compatible with React's `useSyncExternalStore` and other store-style APIs.
|
|
57
|
+
`Model.subscribe(callback)` receives `(model, changed)` on any attribute change.
|
|
58
|
+
`Collection.subscribe(callback)` fires once per operation (on `update`, `reset`, or `sort` events).
|
|
59
|
+
|
|
60
|
+
## 3.0.0 (2025-12-13)
|
|
61
|
+
|
|
62
|
+
- `Collection.prototype.create` no longer returns a boolean (but `null` instead)
|
|
63
|
+
- `Storage` is now exported as `BrowserStorage`
|
|
64
|
+
|
|
65
|
+
## 2.0.0 (2025-12-13)
|
|
66
|
+
|
|
67
|
+
### Breaking changes
|
|
68
|
+
|
|
69
|
+
- `Model.prototype.set` no longer returns a boolean when validation fails (but `null` instead)
|
|
70
|
+
- Loosened the `reduce` and `reduceRight` type signatures on the `Collection`
|
|
71
|
+
|
|
72
|
+
## 1.0.0 (2025-12-13)
|
|
73
|
+
|
|
74
|
+
- Rewrite as TypeScript
|
|
75
|
+
|
|
76
|
+
### Breaking changes:
|
|
77
|
+
|
|
78
|
+
- Removed the `clone()` method on `Model`.
|
|
79
|
+
- Removed the old `View` type
|
|
80
|
+
- Removed `ElementView`
|
|
81
|
+
- Removed the old `Events` constructor function and instead added the `EventsEmitter` mixin class.
|
|
82
|
+
- Removed the `Router` and `History` classes.
|
|
83
|
+
- All other types (`Model`, `Collection`) are now ES6 classes.
|
|
84
|
+
|
|
85
|
+
## 0.0.9 (2025-03-04)
|
|
86
|
+
|
|
87
|
+
- Fix a race condition when setting a localForage driver
|
|
88
|
+
- Refactor the sync method to properly call the `fetch` API
|
|
89
|
+
|
|
90
|
+
## 0.0.8 (2023-02-14)
|
|
91
|
+
|
|
92
|
+
- Use the released version of `@converse/localforage-getitems`
|
|
93
|
+
- Update 3rd party dependencies
|
|
94
|
+
|
|
95
|
+
## 0.0.7 (2022-04-08)
|
|
96
|
+
|
|
97
|
+
- Move code that needs to be bundled to `dependencies` from `devDependencies`
|
|
98
|
+
- Update localForage-getItems to fix a build issue on Windows
|
|
99
|
+
|
|
100
|
+
## 0.0.6 (2022-04-08)
|
|
101
|
+
|
|
102
|
+
- Use the `getAll` IndexedDB function, which should result in a significant speedup
|
|
103
|
+
- Update various 3rd party dependencies.
|
|
104
|
+
|
|
105
|
+
## 0.0.5 (2021-07-08)
|
|
106
|
+
|
|
107
|
+
- #13 Import the default export of localforage
|
|
108
|
+
- Don't expect a collection's `model` attribute to have a `prototype`. It might be an arrow function, in which case it doesn't.
|
|
109
|
+
- Update to mergebounce 0.1.0
|
|
110
|
+
|
|
111
|
+
## 0.0.4 (2021-05-12)
|
|
112
|
+
|
|
113
|
+
- Upgrade to lit 2.0.0-rc.2
|
|
114
|
+
|
|
115
|
+
## 0.0.3 (2021-04-28)
|
|
116
|
+
|
|
117
|
+
- Create the `ElementView`, which is like a Backbone View but extends
|
|
118
|
+
`HTMLElement` and is therefore also a custom element or web component.
|
|
119
|
+
/home/kalie/src/converse.prosody/src/converse.js/src/headless/core.js: \* @property {object} converse.env.\_ - The instance of [lodash-es](http://lodash.com) used by Converse.
|
|
120
|
+
- Allow writes to the client-side store to be batched (via [mergebounce](https://github.com/conversejs/mergebounce)).
|
|
121
|
+
This is particularly useful for IndexedDB, which has a very slow writing speed.
|
|
122
|
+
To enabled batched writes, pass in `true` for the 3rd parameter of the
|
|
123
|
+
`Storage` constructor.
|
|
124
|
+
|
|
125
|
+
## 0.0.2 (2020-09-18)
|
|
126
|
+
|
|
127
|
+
Initial fork from Backbone
|
|
128
|
+
|
|
129
|
+
- Removes the dependency on jQuery
|
|
130
|
+
- Instead of the `render` method Views can have a `toHTML` method which must return a
|
|
131
|
+
[lit-html](https://lit-html.polymer-project.org/) `TemplateResult`.
|
|
132
|
+
- Replaces [underscore](http://underscorejs.org) with [lodash](https://lodash.com)
|
|
133
|
+
- Imports lodash methods individually to allow for tree-shaking
|
|
134
|
+
- Uses the native browser API instead of lodash
|
|
135
|
+
- Drops support for older browsers (including IE) and uses ES6+ language features
|
|
136
|
+
- Splits models, views and collections into separate modules
|
|
137
|
+
- Adds a new `ElementView` class, which is a like a Backbone View, but doubles
|
|
138
|
+
as an instance of HTMLElement and can be used to register a custom element or
|
|
139
|
+
web-component.
|
package/dist/skeletor.esm.js
CHANGED
|
@@ -8705,7 +8705,7 @@ class PersistentStorage {
|
|
|
8705
8705
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
8706
8706
|
const that = this;
|
|
8707
8707
|
async function localSync(method, model, options) {
|
|
8708
|
-
let resp,
|
|
8708
|
+
let resp, caughtError, promise, new_attributes;
|
|
8709
8709
|
// We get the collection (and if necessary the model attribute.
|
|
8710
8710
|
// Waiting for storeInitialized will cause another iteration of
|
|
8711
8711
|
// the event loop, after which the collection reference will
|
|
@@ -8762,10 +8762,12 @@ class PersistentStorage {
|
|
|
8762
8762
|
catch (error) {
|
|
8763
8763
|
const storageSize = await that.getStorageSize();
|
|
8764
8764
|
if (error.code === 22 && storageSize === 0) {
|
|
8765
|
-
|
|
8765
|
+
caughtError = new Error('Private browsing is unsupported');
|
|
8766
8766
|
}
|
|
8767
8767
|
else {
|
|
8768
|
-
|
|
8768
|
+
// Preserve a real Error (stack/name); wrap anything else so the
|
|
8769
|
+
// error path always surfaces an Error, never a bare string.
|
|
8770
|
+
caughtError = error instanceof Error ? error : new Error(error?.message ?? String(error));
|
|
8769
8771
|
}
|
|
8770
8772
|
}
|
|
8771
8773
|
if (resp) {
|
|
@@ -8779,10 +8781,21 @@ class PersistentStorage {
|
|
|
8779
8781
|
options.success(data, options);
|
|
8780
8782
|
}
|
|
8781
8783
|
}
|
|
8784
|
+
else if (method === 'read' && !caughtError) {
|
|
8785
|
+
// A read that finds no record is a normal empty result (first run /
|
|
8786
|
+
// empty storage), not an error. Resolve with `null` so the callback
|
|
8787
|
+
// and promise forms of fetch() agree and a first-run read never
|
|
8788
|
+
// rejects.
|
|
8789
|
+
if (options && options.success) {
|
|
8790
|
+
options.success(null, options);
|
|
8791
|
+
}
|
|
8792
|
+
}
|
|
8782
8793
|
else {
|
|
8783
|
-
|
|
8794
|
+
// A genuine failure (storage threw, or a write produced no result):
|
|
8795
|
+
// surface a real Error so consumers get a stack and `instanceof Error`
|
|
8796
|
+
// holds.
|
|
8784
8797
|
if (options && options.error) {
|
|
8785
|
-
options.error(
|
|
8798
|
+
options.error(caughtError ?? new Error('Record Not Found'));
|
|
8786
8799
|
}
|
|
8787
8800
|
}
|
|
8788
8801
|
}
|
|
@@ -11454,12 +11467,6 @@ _Model_computedCache = new WeakMap(), _Model_computedDefs = new WeakMap(), _Mode
|
|
|
11454
11467
|
try {
|
|
11455
11468
|
await this.fetch({ fromStorage: true, promise: true });
|
|
11456
11469
|
}
|
|
11457
|
-
catch (e) {
|
|
11458
|
-
// 'Record Not Found' is a normal first-run state (nothing stored yet);
|
|
11459
|
-
// keep the initial attributes and resolve. Re-throw anything else.
|
|
11460
|
-
if (e !== 'Record Not Found')
|
|
11461
|
-
throw e;
|
|
11462
|
-
}
|
|
11463
11470
|
finally {
|
|
11464
11471
|
__classPrivateFieldSet(this, _Model_state, 'ready', "f");
|
|
11465
11472
|
}
|
|
@@ -12234,8 +12241,9 @@ class Collection extends EventEmitterObject {
|
|
|
12234
12241
|
}
|
|
12235
12242
|
_Collection_instances = new WeakSet(), _Collection_hydrate = async function _Collection_hydrate() {
|
|
12236
12243
|
ensureUnloadListener(PersistentStorage);
|
|
12237
|
-
//
|
|
12238
|
-
//
|
|
12244
|
+
// An empty store is a normal first-run state: findAll() returns [] and a
|
|
12245
|
+
// missing model record resolves to null, so hydration resolves rather
|
|
12246
|
+
// than rejecting.
|
|
12239
12247
|
await this.fetch({ fromStorage: true, promise: true });
|
|
12240
12248
|
}, _a = Symbol.iterator;
|
|
12241
12249
|
// This "enum" defines the three possible kinds of values which can be emitted
|