@fluixi/storage 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/adapters/memory.cjs +46 -0
- package/dist/adapters/memory.d.ts +8 -0
- package/dist/adapters/memory.d.ts.map +1 -0
- package/dist/adapters/memory.js +26 -0
- package/dist/adapters/memory.mjs +25 -0
- package/dist/browser/document-cookie.cjs +101 -0
- package/dist/browser/document-cookie.d.ts +14 -0
- package/dist/browser/document-cookie.d.ts.map +1 -0
- package/dist/browser/document-cookie.js +53 -0
- package/dist/browser/document-cookie.mjs +80 -0
- package/dist/browser/index.cjs +209 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +3 -0
- package/dist/browser/index.mjs +187 -0
- package/dist/browser/web-storage.cjs +150 -0
- package/dist/browser/web-storage.d.ts +6 -0
- package/dist/browser/web-storage.d.ts.map +1 -0
- package/dist/browser/web-storage.js +105 -0
- package/dist/browser/web-storage.mjs +127 -0
- package/dist/core/async-storage.cjs +583 -0
- package/dist/core/async-storage.d.ts +17 -0
- package/dist/core/async-storage.d.ts.map +1 -0
- package/dist/core/async-storage.js +275 -0
- package/dist/core/async-storage.mjs +560 -0
- package/dist/core/bus.cjs +52 -0
- package/dist/core/bus.d.ts +19 -0
- package/dist/core/bus.d.ts.map +1 -0
- package/dist/core/bus.js +31 -0
- package/dist/core/bus.mjs +31 -0
- package/dist/core/envelope.cjs +119 -0
- package/dist/core/envelope.d.ts +38 -0
- package/dist/core/envelope.d.ts.map +1 -0
- package/dist/core/envelope.js +83 -0
- package/dist/core/envelope.mjs +96 -0
- package/dist/core/errors.cjs +115 -0
- package/dist/core/errors.d.ts +109 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +99 -0
- package/dist/core/errors.mjs +94 -0
- package/dist/core/storage.cjs +782 -0
- package/dist/core/storage.d.ts +63 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/storage.js +260 -0
- package/dist/core/storage.mjs +759 -0
- package/dist/core/types.cjs +18 -0
- package/dist/core/types.d.ts +239 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +1 -0
- package/dist/core/types.mjs +0 -0
- package/dist/encryption/base64.cjs +38 -0
- package/dist/encryption/base64.d.ts +4 -0
- package/dist/encryption/base64.d.ts.map +1 -0
- package/dist/encryption/base64.js +16 -0
- package/dist/encryption/base64.mjs +17 -0
- package/dist/encryption/keys.cjs +77 -0
- package/dist/encryption/keys.d.ts +14 -0
- package/dist/encryption/keys.d.ts.map +1 -0
- package/dist/encryption/keys.js +28 -0
- package/dist/encryption/keys.mjs +54 -0
- package/dist/encryption/seal.cjs +154 -0
- package/dist/encryption/seal.d.ts +24 -0
- package/dist/encryption/seal.d.ts.map +1 -0
- package/dist/encryption/seal.js +83 -0
- package/dist/encryption/seal.mjs +131 -0
- package/dist/encryption/types.cjs +18 -0
- package/dist/encryption/types.d.ts +50 -0
- package/dist/encryption/types.d.ts.map +1 -0
- package/dist/encryption/types.js +1 -0
- package/dist/encryption/types.mjs +0 -0
- package/dist/encryption/web-crypto.cjs +81 -0
- package/dist/encryption/web-crypto.d.ts +9 -0
- package/dist/encryption/web-crypto.d.ts.map +1 -0
- package/dist/encryption/web-crypto.js +45 -0
- package/dist/encryption/web-crypto.mjs +58 -0
- package/dist/index.cjs +870 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.mjs +848 -0
- package/dist/serialization/json.cjs +83 -0
- package/dist/serialization/json.d.ts +3 -0
- package/dist/serialization/json.d.ts.map +1 -0
- package/dist/serialization/json.js +51 -0
- package/dist/serialization/json.mjs +60 -0
- package/dist/serialization/serializer.cjs +28 -0
- package/dist/serialization/serializer.d.ts +4 -0
- package/dist/serialization/serializer.d.ts.map +1 -0
- package/dist/serialization/serializer.js +4 -0
- package/dist/serialization/serializer.mjs +7 -0
- package/dist/server/contracts.cjs +36 -0
- package/dist/server/contracts.d.ts +27 -0
- package/dist/server/contracts.d.ts.map +1 -0
- package/dist/server/contracts.js +16 -0
- package/dist/server/contracts.mjs +15 -0
- package/dist/server/cookie.cjs +126 -0
- package/dist/server/cookie.d.ts +21 -0
- package/dist/server/cookie.d.ts.map +1 -0
- package/dist/server/cookie.js +71 -0
- package/dist/server/cookie.mjs +105 -0
- package/dist/server/index.cjs +155 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +4 -0
- package/dist/server/index.mjs +133 -0
- package/dist/server/request.cjs +46 -0
- package/dist/server/request.d.ts +7 -0
- package/dist/server/request.d.ts.map +1 -0
- package/dist/server/request.js +25 -0
- package/dist/server/request.mjs +25 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/dist/utils/cookie-names.cjs +38 -0
- package/dist/utils/cookie-names.d.ts +10 -0
- package/dist/utils/cookie-names.d.ts.map +1 -0
- package/dist/utils/cookie-names.js +15 -0
- package/dist/utils/cookie-names.mjs +17 -0
- package/dist/utils/copy.cjs +38 -0
- package/dist/utils/copy.d.ts +17 -0
- package/dist/utils/copy.d.ts.map +1 -0
- package/dist/utils/copy.js +15 -0
- package/dist/utils/copy.mjs +17 -0
- package/dist/utils/environment.cjs +28 -0
- package/dist/utils/environment.d.ts +3 -0
- package/dist/utils/environment.d.ts.map +1 -0
- package/dist/utils/environment.js +4 -0
- package/dist/utils/environment.mjs +7 -0
- package/dist/utils/keys.cjs +33 -0
- package/dist/utils/keys.d.ts +5 -0
- package/dist/utils/keys.d.ts.map +1 -0
- package/dist/utils/keys.js +10 -0
- package/dist/utils/keys.mjs +12 -0
- package/package.json +61 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/core/bus.ts
|
|
2
|
+
var buses = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function joinBus(adapter, subscriber) {
|
|
4
|
+
let bus = buses.get(adapter);
|
|
5
|
+
if (!bus) buses.set(adapter, bus = { subscribers: /* @__PURE__ */ new Set() });
|
|
6
|
+
const current = bus;
|
|
7
|
+
current.subscribers.add(subscriber);
|
|
8
|
+
if (current.subscribers.size === 1 && adapter.subscribe) {
|
|
9
|
+
current.stop = adapter.subscribe((change) => {
|
|
10
|
+
for (const s of [...current.subscribers]) s.external(change);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return () => {
|
|
14
|
+
current.subscribers.delete(subscriber);
|
|
15
|
+
if (current.subscribers.size === 0) {
|
|
16
|
+
current.stop?.();
|
|
17
|
+
current.stop = void 0;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function publish(adapter, type, key, prefix, value) {
|
|
22
|
+
const bus = buses.get(adapter);
|
|
23
|
+
if (!bus) return;
|
|
24
|
+
for (const s of [...bus.subscribers]) {
|
|
25
|
+
if (key === null ? s.prefix.startsWith(prefix) : key.startsWith(s.prefix)) s.local(type, key, value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
joinBus,
|
|
30
|
+
publish
|
|
31
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/core/envelope.ts
|
|
21
|
+
var envelope_exports = {};
|
|
22
|
+
__export(envelope_exports, {
|
|
23
|
+
decodeEnvelope: () => decodeEnvelope,
|
|
24
|
+
deserializeOrThrow: () => deserializeOrThrow,
|
|
25
|
+
globToRegExp: () => globToRegExp,
|
|
26
|
+
isExpired: () => isExpired,
|
|
27
|
+
latestVersion: () => latestVersion,
|
|
28
|
+
metaFor: () => metaFor,
|
|
29
|
+
migrate: () => migrate,
|
|
30
|
+
selectItems: () => selectItems,
|
|
31
|
+
serializeOrThrow: () => serializeOrThrow,
|
|
32
|
+
toEntry: () => toEntry
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(envelope_exports);
|
|
35
|
+
|
|
36
|
+
// src/core/errors.ts
|
|
37
|
+
var StorageError = class extends Error {
|
|
38
|
+
constructor(code, message, options = {}) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = new.target.name;
|
|
41
|
+
this.code = code;
|
|
42
|
+
this.key = options.key;
|
|
43
|
+
if (options.cause !== void 0) this.cause = options.cause;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var StorageSerializationError = class extends StorageError {
|
|
47
|
+
constructor(message, options = {}) {
|
|
48
|
+
super("serialization", message, options);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var StorageDeserializationError = class extends StorageError {
|
|
52
|
+
constructor(message, options = {}) {
|
|
53
|
+
super("deserialization", message, options);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/core/envelope.ts
|
|
58
|
+
function isEnvelope(x) {
|
|
59
|
+
return !!x && typeof x === "object" && x.v === 1 && ("value" in x || "enc" in x) && typeof x.createdAt === "number";
|
|
60
|
+
}
|
|
61
|
+
function serializeOrThrow(serializer, key, value) {
|
|
62
|
+
try {
|
|
63
|
+
return serializer.serialize(value);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (error instanceof StorageError) throw Object.assign(error, { key });
|
|
66
|
+
throw new StorageSerializationError(`The value of ${key} could not be serialized.`, { key, cause: error });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function deserializeOrThrow(serializer, key, text) {
|
|
70
|
+
try {
|
|
71
|
+
return serializer.deserialize(text);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
throw new StorageDeserializationError(`The stored value of ${key} could not be read.`, { key, cause: error });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function decodeEnvelope(serializer, key, text) {
|
|
77
|
+
const parsed = deserializeOrThrow(serializer, key, text);
|
|
78
|
+
return isEnvelope(parsed) ? parsed : { v: 1, value: parsed, createdAt: 0 };
|
|
79
|
+
}
|
|
80
|
+
var isExpired = (envelope, now) => envelope.expiresAt !== void 0 && envelope.expiresAt <= now;
|
|
81
|
+
function latestVersion(steps) {
|
|
82
|
+
if (!steps) return void 0;
|
|
83
|
+
const versions = Object.keys(steps).map(Number).filter(Number.isFinite);
|
|
84
|
+
return versions.length ? Math.max(...versions) : void 0;
|
|
85
|
+
}
|
|
86
|
+
function migrate(steps, from, value) {
|
|
87
|
+
const latest = latestVersion(steps);
|
|
88
|
+
if (!steps || latest === void 0 || (from ?? 0) >= latest) return void 0;
|
|
89
|
+
for (const version of Object.keys(steps).map(Number).sort((a, b) => a - b)) {
|
|
90
|
+
if (version > (from ?? 0)) value = steps[version](value);
|
|
91
|
+
}
|
|
92
|
+
return { value, version: latest };
|
|
93
|
+
}
|
|
94
|
+
function metaFor(createdAt, ttl, version) {
|
|
95
|
+
const meta = { createdAt };
|
|
96
|
+
if (ttl !== void 0) meta.expiresAt = createdAt + ttl;
|
|
97
|
+
if (version !== void 0) meta.version = version;
|
|
98
|
+
return meta;
|
|
99
|
+
}
|
|
100
|
+
function toEntry(envelope, value) {
|
|
101
|
+
const entry = { value, createdAt: envelope.createdAt };
|
|
102
|
+
if (envelope.expiresAt !== void 0) entry.expiresAt = envelope.expiresAt;
|
|
103
|
+
if (envelope.version !== void 0) entry.version = envelope.version;
|
|
104
|
+
if (envelope.enc) entry.encrypted = true;
|
|
105
|
+
return entry;
|
|
106
|
+
}
|
|
107
|
+
var globToRegExp = (glob) => new RegExp(`^${glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
|
|
108
|
+
function selectItems(items, query) {
|
|
109
|
+
const pattern = typeof query.match === "string" ? globToRegExp(query.match) : query.match;
|
|
110
|
+
const out = [];
|
|
111
|
+
for (const item of items) {
|
|
112
|
+
if (query.prefix !== void 0 && !item.key.startsWith(query.prefix)) continue;
|
|
113
|
+
if (pattern && !pattern.test(item.key)) continue;
|
|
114
|
+
if (query.where && !query.where(item)) continue;
|
|
115
|
+
out.push(item);
|
|
116
|
+
if (query.limit !== void 0 && out.length >= query.limit) break;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** The stored form and the pieces the sync and async storages share. */
|
|
2
|
+
import type { EncryptedPayload } from '../encryption/seal.js';
|
|
3
|
+
import type { StorageEntry, StorageQuery, StorageSchema, StorageSerializer, StoredItem } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* `v` is the envelope format, so a later format can read this one. A plaintext entry has
|
|
6
|
+
* `value`; an encrypted one has `enc` instead, with the value serialized inside it.
|
|
7
|
+
*/
|
|
8
|
+
export interface Envelope {
|
|
9
|
+
v: 1;
|
|
10
|
+
value?: unknown;
|
|
11
|
+
enc?: EncryptedPayload;
|
|
12
|
+
createdAt: number;
|
|
13
|
+
expiresAt?: number;
|
|
14
|
+
version?: number;
|
|
15
|
+
}
|
|
16
|
+
export type Migrations = Record<string, Record<number, (value: unknown) => unknown> | undefined>;
|
|
17
|
+
export declare function serializeOrThrow(serializer: StorageSerializer, key: string, value: unknown): string;
|
|
18
|
+
export declare function deserializeOrThrow(serializer: StorageSerializer, key: string, text: string): unknown;
|
|
19
|
+
export declare function decodeEnvelope(serializer: StorageSerializer, key: string, text: string): Envelope;
|
|
20
|
+
export declare const isExpired: (envelope: Envelope, now: number) => boolean;
|
|
21
|
+
/** The newest version a key's migrations reach, or undefined without migrations. */
|
|
22
|
+
export declare function latestVersion(steps: Record<number, unknown> | undefined): number | undefined;
|
|
23
|
+
/** The value brought up to the latest version, or undefined when it is already there. */
|
|
24
|
+
export declare function migrate(steps: Record<number, (value: unknown) => unknown> | undefined, from: number | undefined, value: unknown): {
|
|
25
|
+
value: unknown;
|
|
26
|
+
version: number;
|
|
27
|
+
} | undefined;
|
|
28
|
+
/** Envelope metadata for a new write. */
|
|
29
|
+
export declare function metaFor(createdAt: number, ttl: number | undefined, version: number | undefined): {
|
|
30
|
+
createdAt: number;
|
|
31
|
+
expiresAt?: number;
|
|
32
|
+
version?: number;
|
|
33
|
+
};
|
|
34
|
+
export declare function toEntry(envelope: Envelope, value: unknown): StorageEntry<unknown>;
|
|
35
|
+
/** `draft:*` style: `*` any run, `?` one character, everything else literal. */
|
|
36
|
+
export declare const globToRegExp: (glob: string) => RegExp;
|
|
37
|
+
export declare function selectItems<S extends StorageSchema>(items: StoredItem<S>[], query: StorageQuery<S>): StoredItem<S>[];
|
|
38
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/core/envelope.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3G;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,CAAC,CAAC;IACL,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC;AAMjG,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAOnG;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAMpG;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAIjG;AAED,eAAO,MAAM,SAAS,GAAI,UAAU,QAAQ,EAAE,KAAK,MAAM,YAAkE,CAAC;AAE5H,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI5F;AAED,yFAAyF;AACzF,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,OAAO;;;cAO/H;AAED,yCAAyC;AACzC,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS;eACpE,MAAM;gBAAc,MAAM;cAAY,MAAM;EAItE;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAMjF;AAED,gFAAgF;AAChF,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,WAC8D,CAAC;AAExG,wBAAgB,WAAW,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAWpH"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { StorageDeserializationError, StorageError, StorageSerializationError } from './errors.js';
|
|
2
|
+
function isEnvelope(x) {
|
|
3
|
+
return !!x && typeof x === 'object' && x.v === 1 && ('value' in x || 'enc' in x) && typeof x.createdAt === 'number';
|
|
4
|
+
}
|
|
5
|
+
export function serializeOrThrow(serializer, key, value) {
|
|
6
|
+
try {
|
|
7
|
+
return serializer.serialize(value);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (error instanceof StorageError)
|
|
11
|
+
throw Object.assign(error, { key });
|
|
12
|
+
throw new StorageSerializationError(`The value of ${key} could not be serialized.`, { key, cause: error });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function deserializeOrThrow(serializer, key, text) {
|
|
16
|
+
try {
|
|
17
|
+
return serializer.deserialize(text);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
throw new StorageDeserializationError(`The stored value of ${key} could not be read.`, { key, cause: error });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function decodeEnvelope(serializer, key, text) {
|
|
24
|
+
const parsed = deserializeOrThrow(serializer, key, text);
|
|
25
|
+
// Written by something else, without metadata: the value as it is.
|
|
26
|
+
return isEnvelope(parsed) ? parsed : { v: 1, value: parsed, createdAt: 0 };
|
|
27
|
+
}
|
|
28
|
+
export const isExpired = (envelope, now) => envelope.expiresAt !== undefined && envelope.expiresAt <= now;
|
|
29
|
+
/** The newest version a key's migrations reach, or undefined without migrations. */
|
|
30
|
+
export function latestVersion(steps) {
|
|
31
|
+
if (!steps)
|
|
32
|
+
return undefined;
|
|
33
|
+
const versions = Object.keys(steps).map(Number).filter(Number.isFinite);
|
|
34
|
+
return versions.length ? Math.max(...versions) : undefined;
|
|
35
|
+
}
|
|
36
|
+
/** The value brought up to the latest version, or undefined when it is already there. */
|
|
37
|
+
export function migrate(steps, from, value) {
|
|
38
|
+
const latest = latestVersion(steps);
|
|
39
|
+
if (!steps || latest === undefined || (from ?? 0) >= latest)
|
|
40
|
+
return undefined;
|
|
41
|
+
for (const version of Object.keys(steps).map(Number).sort((a, b) => a - b)) {
|
|
42
|
+
if (version > (from ?? 0))
|
|
43
|
+
value = steps[version](value);
|
|
44
|
+
}
|
|
45
|
+
return { value, version: latest };
|
|
46
|
+
}
|
|
47
|
+
/** Envelope metadata for a new write. */
|
|
48
|
+
export function metaFor(createdAt, ttl, version) {
|
|
49
|
+
const meta = { createdAt };
|
|
50
|
+
if (ttl !== undefined)
|
|
51
|
+
meta.expiresAt = createdAt + ttl;
|
|
52
|
+
if (version !== undefined)
|
|
53
|
+
meta.version = version;
|
|
54
|
+
return meta;
|
|
55
|
+
}
|
|
56
|
+
export function toEntry(envelope, value) {
|
|
57
|
+
const entry = { value, createdAt: envelope.createdAt };
|
|
58
|
+
if (envelope.expiresAt !== undefined)
|
|
59
|
+
entry.expiresAt = envelope.expiresAt;
|
|
60
|
+
if (envelope.version !== undefined)
|
|
61
|
+
entry.version = envelope.version;
|
|
62
|
+
if (envelope.enc)
|
|
63
|
+
entry.encrypted = true;
|
|
64
|
+
return entry;
|
|
65
|
+
}
|
|
66
|
+
/** `draft:*` style: `*` any run, `?` one character, everything else literal. */
|
|
67
|
+
export const globToRegExp = (glob) => new RegExp(`^${glob.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.')}$`);
|
|
68
|
+
export function selectItems(items, query) {
|
|
69
|
+
const pattern = typeof query.match === 'string' ? globToRegExp(query.match) : query.match;
|
|
70
|
+
const out = [];
|
|
71
|
+
for (const item of items) {
|
|
72
|
+
if (query.prefix !== undefined && !item.key.startsWith(query.prefix))
|
|
73
|
+
continue;
|
|
74
|
+
if (pattern && !pattern.test(item.key))
|
|
75
|
+
continue;
|
|
76
|
+
if (query.where && !query.where(item))
|
|
77
|
+
continue;
|
|
78
|
+
out.push(item);
|
|
79
|
+
if (query.limit !== undefined && out.length >= query.limit)
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/core/errors.ts
|
|
2
|
+
var StorageError = class extends Error {
|
|
3
|
+
constructor(code, message, options = {}) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = new.target.name;
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.key = options.key;
|
|
8
|
+
if (options.cause !== void 0) this.cause = options.cause;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var StorageSerializationError = class extends StorageError {
|
|
12
|
+
constructor(message, options = {}) {
|
|
13
|
+
super("serialization", message, options);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var StorageDeserializationError = class extends StorageError {
|
|
17
|
+
constructor(message, options = {}) {
|
|
18
|
+
super("deserialization", message, options);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/core/envelope.ts
|
|
23
|
+
function isEnvelope(x) {
|
|
24
|
+
return !!x && typeof x === "object" && x.v === 1 && ("value" in x || "enc" in x) && typeof x.createdAt === "number";
|
|
25
|
+
}
|
|
26
|
+
function serializeOrThrow(serializer, key, value) {
|
|
27
|
+
try {
|
|
28
|
+
return serializer.serialize(value);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error instanceof StorageError) throw Object.assign(error, { key });
|
|
31
|
+
throw new StorageSerializationError(`The value of ${key} could not be serialized.`, { key, cause: error });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function deserializeOrThrow(serializer, key, text) {
|
|
35
|
+
try {
|
|
36
|
+
return serializer.deserialize(text);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw new StorageDeserializationError(`The stored value of ${key} could not be read.`, { key, cause: error });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function decodeEnvelope(serializer, key, text) {
|
|
42
|
+
const parsed = deserializeOrThrow(serializer, key, text);
|
|
43
|
+
return isEnvelope(parsed) ? parsed : { v: 1, value: parsed, createdAt: 0 };
|
|
44
|
+
}
|
|
45
|
+
var isExpired = (envelope, now) => envelope.expiresAt !== void 0 && envelope.expiresAt <= now;
|
|
46
|
+
function latestVersion(steps) {
|
|
47
|
+
if (!steps) return void 0;
|
|
48
|
+
const versions = Object.keys(steps).map(Number).filter(Number.isFinite);
|
|
49
|
+
return versions.length ? Math.max(...versions) : void 0;
|
|
50
|
+
}
|
|
51
|
+
function migrate(steps, from, value) {
|
|
52
|
+
const latest = latestVersion(steps);
|
|
53
|
+
if (!steps || latest === void 0 || (from ?? 0) >= latest) return void 0;
|
|
54
|
+
for (const version of Object.keys(steps).map(Number).sort((a, b) => a - b)) {
|
|
55
|
+
if (version > (from ?? 0)) value = steps[version](value);
|
|
56
|
+
}
|
|
57
|
+
return { value, version: latest };
|
|
58
|
+
}
|
|
59
|
+
function metaFor(createdAt, ttl, version) {
|
|
60
|
+
const meta = { createdAt };
|
|
61
|
+
if (ttl !== void 0) meta.expiresAt = createdAt + ttl;
|
|
62
|
+
if (version !== void 0) meta.version = version;
|
|
63
|
+
return meta;
|
|
64
|
+
}
|
|
65
|
+
function toEntry(envelope, value) {
|
|
66
|
+
const entry = { value, createdAt: envelope.createdAt };
|
|
67
|
+
if (envelope.expiresAt !== void 0) entry.expiresAt = envelope.expiresAt;
|
|
68
|
+
if (envelope.version !== void 0) entry.version = envelope.version;
|
|
69
|
+
if (envelope.enc) entry.encrypted = true;
|
|
70
|
+
return entry;
|
|
71
|
+
}
|
|
72
|
+
var globToRegExp = (glob) => new RegExp(`^${glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
|
|
73
|
+
function selectItems(items, query) {
|
|
74
|
+
const pattern = typeof query.match === "string" ? globToRegExp(query.match) : query.match;
|
|
75
|
+
const out = [];
|
|
76
|
+
for (const item of items) {
|
|
77
|
+
if (query.prefix !== void 0 && !item.key.startsWith(query.prefix)) continue;
|
|
78
|
+
if (pattern && !pattern.test(item.key)) continue;
|
|
79
|
+
if (query.where && !query.where(item)) continue;
|
|
80
|
+
out.push(item);
|
|
81
|
+
if (query.limit !== void 0 && out.length >= query.limit) break;
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
decodeEnvelope,
|
|
87
|
+
deserializeOrThrow,
|
|
88
|
+
globToRegExp,
|
|
89
|
+
isExpired,
|
|
90
|
+
latestVersion,
|
|
91
|
+
metaFor,
|
|
92
|
+
migrate,
|
|
93
|
+
selectItems,
|
|
94
|
+
serializeOrThrow,
|
|
95
|
+
toEntry
|
|
96
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/core/errors.ts
|
|
21
|
+
var errors_exports = {};
|
|
22
|
+
__export(errors_exports, {
|
|
23
|
+
StorageAdapterError: () => StorageAdapterError,
|
|
24
|
+
StorageDecryptionError: () => StorageDecryptionError,
|
|
25
|
+
StorageDeserializationError: () => StorageDeserializationError,
|
|
26
|
+
StorageEncryptedPayloadError: () => StorageEncryptedPayloadError,
|
|
27
|
+
StorageEncryptionAlgorithmError: () => StorageEncryptionAlgorithmError,
|
|
28
|
+
StorageEncryptionError: () => StorageEncryptionError,
|
|
29
|
+
StorageEncryptionKeyError: () => StorageEncryptionKeyError,
|
|
30
|
+
StorageEncryptionMetadataError: () => StorageEncryptionMetadataError,
|
|
31
|
+
StorageEncryptionUnavailableError: () => StorageEncryptionUnavailableError,
|
|
32
|
+
StorageEncryptionVersionError: () => StorageEncryptionVersionError,
|
|
33
|
+
StorageError: () => StorageError,
|
|
34
|
+
StorageQuotaError: () => StorageQuotaError,
|
|
35
|
+
StorageSecurityError: () => StorageSecurityError,
|
|
36
|
+
StorageSerializationError: () => StorageSerializationError,
|
|
37
|
+
StorageUnavailableError: () => StorageUnavailableError
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(errors_exports);
|
|
40
|
+
var StorageError = class extends Error {
|
|
41
|
+
constructor(code, message, options = {}) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = new.target.name;
|
|
44
|
+
this.code = code;
|
|
45
|
+
this.key = options.key;
|
|
46
|
+
if (options.cause !== void 0) this.cause = options.cause;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var StorageSerializationError = class extends StorageError {
|
|
50
|
+
constructor(message, options = {}) {
|
|
51
|
+
super("serialization", message, options);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var StorageDeserializationError = class extends StorageError {
|
|
55
|
+
constructor(message, options = {}) {
|
|
56
|
+
super("deserialization", message, options);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var StorageUnavailableError = class extends StorageError {
|
|
60
|
+
constructor(message, options = {}) {
|
|
61
|
+
super("unavailable", message, options);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
var StorageQuotaError = class extends StorageError {
|
|
65
|
+
constructor(message, options = {}) {
|
|
66
|
+
super("quota", message, options);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var StorageSecurityError = class extends StorageError {
|
|
70
|
+
constructor(message, options = {}) {
|
|
71
|
+
super("security", message, options);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var StorageAdapterError = class extends StorageError {
|
|
75
|
+
constructor(message, options = {}) {
|
|
76
|
+
super("adapter", message, options);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var StorageEncryptionError = class extends StorageError {
|
|
80
|
+
};
|
|
81
|
+
var StorageEncryptionKeyError = class extends StorageEncryptionError {
|
|
82
|
+
constructor(message, options = {}) {
|
|
83
|
+
super("encryption-key", message, options);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var StorageEncryptionMetadataError = class extends StorageEncryptionError {
|
|
87
|
+
constructor(message, options = {}) {
|
|
88
|
+
super("encryption-metadata", message, options);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var StorageEncryptionVersionError = class extends StorageEncryptionError {
|
|
92
|
+
constructor(message, options = {}) {
|
|
93
|
+
super("encryption-version", message, options);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var StorageEncryptionAlgorithmError = class extends StorageEncryptionError {
|
|
97
|
+
constructor(message, options = {}) {
|
|
98
|
+
super("encryption-algorithm", message, options);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
var StorageDecryptionError = class extends StorageEncryptionError {
|
|
102
|
+
constructor(message, options = {}) {
|
|
103
|
+
super("decryption", message, options);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var StorageEncryptedPayloadError = class extends StorageEncryptionError {
|
|
107
|
+
constructor(message, options = {}) {
|
|
108
|
+
super("encryption-payload", message, options);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var StorageEncryptionUnavailableError = class extends StorageEncryptionError {
|
|
112
|
+
constructor(message, options = {}) {
|
|
113
|
+
super("encryption-unavailable", message, options);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/** Every error the storage throws: one base, a stable `code`, the key when there is one. */
|
|
2
|
+
export declare class StorageError extends Error {
|
|
3
|
+
readonly code: string;
|
|
4
|
+
readonly key?: string;
|
|
5
|
+
/** What went wrong underneath: the browser's DOMException, a JSON SyntaxError. */
|
|
6
|
+
readonly cause?: unknown;
|
|
7
|
+
constructor(code: string, message: string, options?: {
|
|
8
|
+
key?: string;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
/** A value the serializer refuses: a function, a class instance, a cycle. */
|
|
13
|
+
export declare class StorageSerializationError extends StorageError {
|
|
14
|
+
constructor(message: string, options?: {
|
|
15
|
+
key?: string;
|
|
16
|
+
cause?: unknown;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/** Stored text that does not deserialize. */
|
|
20
|
+
export declare class StorageDeserializationError extends StorageError {
|
|
21
|
+
constructor(message: string, options?: {
|
|
22
|
+
key?: string;
|
|
23
|
+
cause?: unknown;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** The backend does not exist here: localStorage on a server, IndexedDB in a worker without it. */
|
|
27
|
+
export declare class StorageUnavailableError extends StorageError {
|
|
28
|
+
constructor(message: string, options?: {
|
|
29
|
+
key?: string;
|
|
30
|
+
cause?: unknown;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** The backend is full. */
|
|
34
|
+
export declare class StorageQuotaError extends StorageError {
|
|
35
|
+
constructor(message: string, options?: {
|
|
36
|
+
key?: string;
|
|
37
|
+
cause?: unknown;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** The backend refused access: storage blocked by the browser's privacy settings. */
|
|
41
|
+
export declare class StorageSecurityError extends StorageError {
|
|
42
|
+
constructor(message: string, options?: {
|
|
43
|
+
key?: string;
|
|
44
|
+
cause?: unknown;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Anything else an adapter failed with. */
|
|
48
|
+
export declare class StorageAdapterError extends StorageError {
|
|
49
|
+
constructor(message: string, options?: {
|
|
50
|
+
key?: string;
|
|
51
|
+
cause?: unknown;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** Base of every encryption failure, so one `instanceof` catches them all. */
|
|
55
|
+
export declare class StorageEncryptionError extends StorageError {
|
|
56
|
+
}
|
|
57
|
+
/** No key provider is configured, or it gave no usable AES-256-GCM key. */
|
|
58
|
+
export declare class StorageEncryptionKeyError extends StorageEncryptionError {
|
|
59
|
+
constructor(message: string, options?: {
|
|
60
|
+
key?: string;
|
|
61
|
+
cause?: unknown;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** The encryption fields of a stored entry are missing or of the wrong type. */
|
|
65
|
+
export declare class StorageEncryptionMetadataError extends StorageEncryptionError {
|
|
66
|
+
constructor(message: string, options?: {
|
|
67
|
+
key?: string;
|
|
68
|
+
cause?: unknown;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** The entry was encrypted with a format version this release does not know. */
|
|
72
|
+
export declare class StorageEncryptionVersionError extends StorageEncryptionError {
|
|
73
|
+
constructor(message: string, options?: {
|
|
74
|
+
key?: string;
|
|
75
|
+
cause?: unknown;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** The entry names an algorithm the configured provider does not implement. */
|
|
79
|
+
export declare class StorageEncryptionAlgorithmError extends StorageEncryptionError {
|
|
80
|
+
constructor(message: string, options?: {
|
|
81
|
+
key?: string;
|
|
82
|
+
cause?: unknown;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Authentication failed: wrong key, or the ciphertext or its metadata was changed. */
|
|
86
|
+
export declare class StorageDecryptionError extends StorageEncryptionError {
|
|
87
|
+
constructor(message: string, options?: {
|
|
88
|
+
key?: string;
|
|
89
|
+
cause?: unknown;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/** The IV, ciphertext or tag is not valid base64 or has the wrong length. */
|
|
93
|
+
export declare class StorageEncryptedPayloadError extends StorageEncryptionError {
|
|
94
|
+
constructor(message: string, options?: {
|
|
95
|
+
key?: string;
|
|
96
|
+
cause?: unknown;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Encryption cannot run here: no Web Crypto in this runtime, or an encrypted value read through
|
|
101
|
+
* a synchronous storage, which has no way to decrypt it.
|
|
102
|
+
*/
|
|
103
|
+
export declare class StorageEncryptionUnavailableError extends StorageEncryptionError {
|
|
104
|
+
constructor(message: string, options?: {
|
|
105
|
+
key?: string;
|
|
106
|
+
cause?: unknown;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
|