strata-storage 2.7.0 → 2.7.1
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/AI-INTEGRATION-GUIDE.md +41 -1
- package/README.md +1 -1
- package/dist/README.md +1 -1
- package/dist/adapters/web/CacheAdapter.d.ts.map +1 -1
- package/dist/adapters/web/CacheAdapter.js +20 -5
- package/dist/adapters/web/CookieAdapter.d.ts.map +1 -1
- package/dist/adapters/web/CookieAdapter.js +27 -3
- package/dist/adapters/web/IndexedDBAdapter.d.ts.map +1 -1
- package/dist/adapters/web/IndexedDBAdapter.js +5 -1
- package/dist/adapters/web/LocalStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/LocalStorageAdapter.js +15 -1
- package/dist/adapters/web/MemoryAdapter.d.ts +7 -0
- package/dist/adapters/web/MemoryAdapter.d.ts.map +1 -1
- package/dist/adapters/web/MemoryAdapter.js +22 -5
- package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/SessionStorageAdapter.js +14 -1
- package/dist/core/Strata.d.ts +12 -0
- package/dist/core/Strata.d.ts.map +1 -1
- package/dist/core/Strata.js +119 -21
- package/dist/features/compression.d.ts +23 -8
- package/dist/features/compression.d.ts.map +1 -1
- package/dist/features/compression.js +164 -77
- package/dist/features/migration.d.ts.map +1 -1
- package/dist/features/migration.js +7 -2
- package/dist/features/query.d.ts +1 -0
- package/dist/features/query.d.ts.map +1 -1
- package/dist/features/query.js +29 -6
- package/dist/features/sync.d.ts.map +1 -1
- package/dist/features/sync.js +18 -3
- package/dist/features/ttl.d.ts.map +1 -1
- package/dist/features/ttl.js +4 -2
- package/dist/firebase.d.ts.map +1 -1
- package/dist/firebase.js +39 -2
- package/dist/index.d.ts +2 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
- package/scripts/build.js +30 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/features/query.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,SAAS,CAAC;AAG9D;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO;IAwB3D;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,OAAO,CAAC,eAAe;
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/features/query.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,SAAS,CAAC;AAG9D;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO;IAwB3D;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAkEvB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkBrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAqBtB;;OAEG;IACH,OAAO,CAAC,MAAM;IA+Bd;;OAEG;IACH,OAAO,CAAC,OAAO;IAyBf;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,OAAO,CAAC,OAAO;IASf;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;IAoBxD;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA6B5E;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAsD;IAE5F,OAAO,CAAC,cAAc;IAyBtB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAkB1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CAE/C"}
|
package/dist/features/query.js
CHANGED
|
@@ -73,7 +73,15 @@ export class QueryEngine {
|
|
|
73
73
|
// Otherwise check if value equals any operand value
|
|
74
74
|
return operand.some((v) => this.equals(value, v));
|
|
75
75
|
case '$nin':
|
|
76
|
-
|
|
76
|
+
if (!Array.isArray(operand))
|
|
77
|
+
return false;
|
|
78
|
+
// Mirror $in: for an array field, "not in" means none of its items
|
|
79
|
+
// match any operand value (the previous code compared the whole array
|
|
80
|
+
// to each scalar operand, giving wrong results for array fields).
|
|
81
|
+
if (Array.isArray(value)) {
|
|
82
|
+
return !operand.some((v) => value.some((item) => this.equals(item, v)));
|
|
83
|
+
}
|
|
84
|
+
return !operand.some((v) => this.equals(value, v));
|
|
77
85
|
case '$regex':
|
|
78
86
|
return this.matchesRegex(value, operand);
|
|
79
87
|
case '$exists':
|
|
@@ -272,8 +280,10 @@ export class QueryEngine {
|
|
|
272
280
|
}
|
|
273
281
|
}
|
|
274
282
|
else {
|
|
275
|
-
// Exclusion mode - include all except specified fields
|
|
276
|
-
result
|
|
283
|
+
// Exclusion mode - include all except specified fields. Spread the item's
|
|
284
|
+
// own fields directly onto result (NOT under a `value` wrapper, which left
|
|
285
|
+
// the excluded keys unreachable and returned the whole item unchanged).
|
|
286
|
+
Object.assign(result, item);
|
|
277
287
|
for (const [key, exclude] of Object.entries(projection)) {
|
|
278
288
|
if (exclude === 0 || exclude === false) {
|
|
279
289
|
this.deleteNestedValue(result, key);
|
|
@@ -285,17 +295,28 @@ export class QueryEngine {
|
|
|
285
295
|
/**
|
|
286
296
|
* Set nested value in object using dot notation
|
|
287
297
|
*/
|
|
298
|
+
static FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
288
299
|
setNestedValue(obj, path, value) {
|
|
289
300
|
const parts = path.split('.');
|
|
290
301
|
let current = obj;
|
|
291
302
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
292
303
|
const part = parts[i];
|
|
293
|
-
|
|
304
|
+
// Refuse prototype-polluting paths and use own-property checks only — `in`
|
|
305
|
+
// walks the prototype chain, so a '__proto__.x' path could reach
|
|
306
|
+
// Object.prototype.
|
|
307
|
+
if (QueryEngine.FORBIDDEN_KEYS.has(part))
|
|
308
|
+
return;
|
|
309
|
+
if (!Object.prototype.hasOwnProperty.call(current, part) ||
|
|
310
|
+
typeof current[part] !== 'object' ||
|
|
311
|
+
current[part] === null) {
|
|
294
312
|
current[part] = {};
|
|
295
313
|
}
|
|
296
314
|
current = current[part];
|
|
297
315
|
}
|
|
298
|
-
|
|
316
|
+
const last = parts[parts.length - 1];
|
|
317
|
+
if (QueryEngine.FORBIDDEN_KEYS.has(last))
|
|
318
|
+
return;
|
|
319
|
+
current[last] = value;
|
|
299
320
|
}
|
|
300
321
|
/**
|
|
301
322
|
* Delete nested value from object using dot notation
|
|
@@ -305,7 +326,9 @@ export class QueryEngine {
|
|
|
305
326
|
let current = obj;
|
|
306
327
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
307
328
|
const part = parts[i];
|
|
308
|
-
if (!(
|
|
329
|
+
if (!Object.prototype.hasOwnProperty.call(current, part) ||
|
|
330
|
+
typeof current[part] !== 'object' ||
|
|
331
|
+
current[part] === null) {
|
|
309
332
|
return;
|
|
310
333
|
}
|
|
311
334
|
current = current[part];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/features/sync.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAEV,WAAW,EAEX,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAYjB;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,kBAAkB,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAC,CAAmB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAuE;IACxF,OAAO,CAAC,cAAc,CAAyD;gBAEnE,MAAM,GAAE,UAAe;IAYnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,IAAI;IAuBrD;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,oBAAoB,GAAG,mBAAmB;IAY9D;;OAEG;IACH,KAAK,IAAI,IAAI;IAuBb;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAInC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAkC7B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,kBAAkB;IA2C1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/features/sync.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAEV,WAAW,EAEX,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAYjB;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,kBAAkB,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAC,CAAmB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAuE;IACxF,OAAO,CAAC,cAAc,CAAyD;gBAEnE,MAAM,GAAE,UAAe;IAYnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,IAAI;IAuBrD;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,oBAAoB,GAAG,mBAAmB;IAY9D;;OAEG;IACH,KAAK,IAAI,IAAI;IAuBb;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAInC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAkC7B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,kBAAkB;IA2C1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO;CAyD5C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAElE"}
|
package/dist/features/sync.js
CHANGED
|
@@ -247,9 +247,24 @@ export class SyncManager extends EventEmitter {
|
|
|
247
247
|
return this.config.conflictResolution(values);
|
|
248
248
|
}
|
|
249
249
|
switch (this.config.conflictResolution) {
|
|
250
|
-
case 'latest':
|
|
251
|
-
//
|
|
252
|
-
|
|
250
|
+
case 'latest': {
|
|
251
|
+
// Most-recent-wins by the StorageValue `updated` timestamp so two tabs
|
|
252
|
+
// with concurrent same-key writes converge on the genuinely newest
|
|
253
|
+
// value, instead of each applying the other's (last-received-wins, which
|
|
254
|
+
// diverges and lets a delayed older message clobber a newer local
|
|
255
|
+
// write). Falls back to positional-last when values carry no timestamp.
|
|
256
|
+
let newest = values[values.length - 1];
|
|
257
|
+
let newestTime = isStorageValue(newest) ? newest.updated : undefined;
|
|
258
|
+
for (const candidate of values) {
|
|
259
|
+
if (!isStorageValue(candidate))
|
|
260
|
+
continue;
|
|
261
|
+
if (typeof newestTime !== 'number' || candidate.updated >= newestTime) {
|
|
262
|
+
newest = candidate;
|
|
263
|
+
newestTime = candidate.updated;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return newest;
|
|
267
|
+
}
|
|
253
268
|
case 'merge':
|
|
254
269
|
if (values.every(isStorageValue)) {
|
|
255
270
|
const wrappers = values;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ttl.d.ts","sourceRoot":"","sources":["../../src/features/ttl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAEzB;;OAEG;IACH,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,eAAe,CAAC,CAAiC;IACzD,OAAO,CAAC,gBAAgB,CAA+C;gBAE3D,MAAM,GAAE,SAAc;IAWlC;;OAEG;IACH,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS;
|
|
1
|
+
{"version":3,"file":"ttl.d.ts","sourceRoot":"","sources":["../../src/features/ttl.ts"],"names":[],"mappings":"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"}
|
package/dist/features/ttl.js
CHANGED
|
@@ -32,10 +32,12 @@ export class TTLManager extends EventEmitter {
|
|
|
32
32
|
const time = options.expireAt instanceof Date ? options.expireAt.getTime() : options.expireAt;
|
|
33
33
|
return time > Date.now() ? time : undefined;
|
|
34
34
|
}
|
|
35
|
-
// Expire after a certain date
|
|
35
|
+
// Expire after a certain date — documented as an alias of expireAt, so it
|
|
36
|
+
// gets the same past-guard (a past time yields no expiry rather than an
|
|
37
|
+
// entry that is dead on arrival).
|
|
36
38
|
if (options.expireAfter) {
|
|
37
39
|
const afterTime = options.expireAfter instanceof Date ? options.expireAfter.getTime() : options.expireAfter;
|
|
38
|
-
return afterTime;
|
|
40
|
+
return afterTime > Date.now() ? afterTime : undefined;
|
|
39
41
|
}
|
|
40
42
|
// TTL from now
|
|
41
43
|
if (options.ttl) {
|
package/dist/firebase.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase.d.ts","sourceRoot":"","sources":["../src/firebase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"firebase.d.ts","sourceRoot":"","sources":["../src/firebase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA4DD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CAkPf;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAQ5D"}
|
package/dist/firebase.js
CHANGED
|
@@ -6,6 +6,35 @@ function isStorageValue(value) {
|
|
|
6
6
|
'created' in value &&
|
|
7
7
|
'updated' in value);
|
|
8
8
|
}
|
|
9
|
+
function isPlainObject(value) {
|
|
10
|
+
if (typeof value !== 'object' || value === null)
|
|
11
|
+
return false;
|
|
12
|
+
const proto = Object.getPrototypeOf(value);
|
|
13
|
+
return proto === Object.prototype || proto === null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Recursively drop `undefined`-valued keys. Firestore `setDoc()` and Realtime
|
|
17
|
+
* Database `set()` both throw on `undefined` field values, and the StorageValue
|
|
18
|
+
* wrapper Strata builds always carries `expires`/`tags`/`metadata` keys that are
|
|
19
|
+
* `undefined` for a plain write — so writing it verbatim breaks the happy path.
|
|
20
|
+
* Only plain objects/arrays are traversed, so Dates and other class instances
|
|
21
|
+
* are preserved as-is.
|
|
22
|
+
*/
|
|
23
|
+
function stripUndefined(input) {
|
|
24
|
+
if (Array.isArray(input)) {
|
|
25
|
+
return input.map((item) => stripUndefined(item));
|
|
26
|
+
}
|
|
27
|
+
if (isPlainObject(input)) {
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const [key, val] of Object.entries(input)) {
|
|
30
|
+
if (val === undefined)
|
|
31
|
+
continue;
|
|
32
|
+
out[key] = stripUndefined(val);
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
return input;
|
|
37
|
+
}
|
|
9
38
|
function normalizeRemoteValue(value) {
|
|
10
39
|
if (!value)
|
|
11
40
|
return null;
|
|
@@ -71,7 +100,7 @@ export async function enableFirebaseSync(storage, config) {
|
|
|
71
100
|
},
|
|
72
101
|
async set(key, value) {
|
|
73
102
|
const docRef = doc(db, collectionName, key);
|
|
74
|
-
await setDoc(docRef, value);
|
|
103
|
+
await setDoc(docRef, stripUndefined(value));
|
|
75
104
|
},
|
|
76
105
|
async remove(key) {
|
|
77
106
|
const docRef = doc(db, collectionName, key);
|
|
@@ -168,7 +197,7 @@ export async function enableFirebaseSync(storage, config) {
|
|
|
168
197
|
return snapshot.exists() ? normalizeRemoteValue(snapshot.val()) : null;
|
|
169
198
|
},
|
|
170
199
|
async set(key, value) {
|
|
171
|
-
await set(ref(db, `strata-storage/${key}`), value);
|
|
200
|
+
await set(ref(db, `strata-storage/${key}`), stripUndefined(value));
|
|
172
201
|
},
|
|
173
202
|
async remove(key) {
|
|
174
203
|
await remove(ref(db, `strata-storage/${key}`));
|
|
@@ -230,6 +259,14 @@ export async function enableFirebaseSync(storage, config) {
|
|
|
230
259
|
// Cast to unknown first to bypass type checking for custom adapter
|
|
231
260
|
storage.registerAdapter(realtimeAdapter);
|
|
232
261
|
}
|
|
262
|
+
// Attach the freshly registered adapters to the active set so they join
|
|
263
|
+
// multi-adapter operations (subscribe/keys/clear/size) immediately — not
|
|
264
|
+
// only after an explicit `{ storage: 'firestore' }` call. Mirrors
|
|
265
|
+
// registerCapacitorAdapters(). Without this, a top-level subscribe() issued
|
|
266
|
+
// before any firestore op never wires up the onSnapshot listener.
|
|
267
|
+
if (config.firestore || config.realtimeDatabase) {
|
|
268
|
+
await storage.refreshAdapters();
|
|
269
|
+
}
|
|
233
270
|
// Firebase sync enabled successfully
|
|
234
271
|
}
|
|
235
272
|
catch (error) {
|
package/dist/index.d.ts
CHANGED
|
@@ -18,10 +18,10 @@ export { computeChecksum, verifyChecksum } from "./features/integrity.js";
|
|
|
18
18
|
export { MigrationManager } from "./features/migration.js";
|
|
19
19
|
export type { Migration } from "./features/migration.js";
|
|
20
20
|
export { StrataError, StorageError, IntegrityError, QuotaExceededError, EncryptionError, CompressionError, SerializationError, ValidationError, NotSupportedError, AdapterNotAvailableError, } from "./utils/errors.js";
|
|
21
|
-
export type { StorageType, StorageOptions, StorageValue, StorageAdapter, AdapterConfig, QueryOptions, SyncConfig, EncryptionConfig, CompressionConfig, ObserverCallback, StorageEvent, StorageCapabilities, StorageMetadata, TTLConfig, StrataConfig, StorageChange, SubscriptionCallback, UnsubscribeFunction, } from "./types.js";
|
|
21
|
+
export type { StorageType, StorageOptions, StorageValue, StorageAdapter, AdapterConfig, QueryOptions, SyncConfig, EncryptionConfig, CompressionConfig, ObserverCallback, StorageEvent, StorageCapabilities, StorageMetadata, TTLConfig, StrataConfig, StorageChange, SubscriptionCallback, UnsubscribeFunction, } from "./types/index.js";
|
|
22
22
|
export { isValidKey, isValidValue, serializeValue, deserializeValue, generateId, createError, retry, debounce, throttle, } from "./utils/index.js";
|
|
23
23
|
import { Strata } from "./core/Strata.js";
|
|
24
|
-
import type { StrataConfig } from "./types.js";
|
|
24
|
+
import type { StrataConfig } from "./types/index.js";
|
|
25
25
|
/**
|
|
26
26
|
* Register the standard web storage adapters on a Strata instance: memory,
|
|
27
27
|
* localStorage, sessionStorage, indexedDB, cookies, and cache. Exported so any
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strata-storage",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"description": "Zero-dependency universal storage plugin providing a unified API for all storage operations across web, Android, and iOS platforms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strata-storage",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"description": "Zero-dependency universal storage plugin providing a unified API for all storage operations across web, Android, and iOS platforms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "yarn@4.17.0",
|
package/scripts/build.js
CHANGED
|
@@ -83,20 +83,37 @@ const fixPathAliases = (dir) => {
|
|
|
83
83
|
.replace(/from\s+["']\.\/utils["']/g, `from "./utils/index.js"`)
|
|
84
84
|
.replace(/from\s+["']\.\/plugin["']/g, `from "./plugin/index.js"`);
|
|
85
85
|
|
|
86
|
-
// Add
|
|
86
|
+
// Add the correct extension to extensionless relative imports.
|
|
87
|
+
// Directory-aware: a barrel import like './types' must resolve to
|
|
88
|
+
// './types/index.js', a file import like './core/Strata' to
|
|
89
|
+
// './core/Strata.js'. tsc has already emitted every .js by now, so we
|
|
90
|
+
// resolve against the real dist files instead of blindly appending '.js'
|
|
91
|
+
// (the previous naive appender produced a dead './types.js' that broke
|
|
92
|
+
// type resolution for every TS consumer).
|
|
93
|
+
const fileDir = path.dirname(filePath);
|
|
94
|
+
const resolveRel = (importPath) => {
|
|
95
|
+
if (importPath.endsWith('.js') || importPath.endsWith('.json')) {
|
|
96
|
+
return importPath;
|
|
97
|
+
}
|
|
98
|
+
const abs = path.resolve(fileDir, importPath);
|
|
99
|
+
if (fs.existsSync(`${abs}.js`)) {
|
|
100
|
+
return `${importPath}.js`;
|
|
101
|
+
}
|
|
102
|
+
if (fs.existsSync(path.join(abs, 'index.js'))) {
|
|
103
|
+
return `${importPath.replace(/\/+$/, '')}/index.js`;
|
|
104
|
+
}
|
|
105
|
+
// Fall back to the legacy behavior if nothing matched on disk.
|
|
106
|
+
return `${importPath}.js`;
|
|
107
|
+
};
|
|
87
108
|
content = content
|
|
88
|
-
.replace(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return `import("${path}.js")`;
|
|
97
|
-
}
|
|
98
|
-
return match;
|
|
99
|
-
});
|
|
109
|
+
.replace(
|
|
110
|
+
/from\s+["'](\.[^"']+)["']/g,
|
|
111
|
+
(_match, p) => `from "${resolveRel(p)}"`,
|
|
112
|
+
)
|
|
113
|
+
.replace(
|
|
114
|
+
/import\(["'](\.[^"']+)["']\)/g,
|
|
115
|
+
(_match, p) => `import("${resolveRel(p)}")`,
|
|
116
|
+
);
|
|
100
117
|
|
|
101
118
|
fs.writeFileSync(filePath, content);
|
|
102
119
|
}
|