@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,83 @@
|
|
|
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/serialization/json.ts
|
|
21
|
+
var json_exports = {};
|
|
22
|
+
__export(json_exports, {
|
|
23
|
+
jsonSerializer: () => jsonSerializer
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(json_exports);
|
|
26
|
+
|
|
27
|
+
// src/core/errors.ts
|
|
28
|
+
var StorageError = class extends Error {
|
|
29
|
+
constructor(code, message, options = {}) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = new.target.name;
|
|
32
|
+
this.code = code;
|
|
33
|
+
this.key = options.key;
|
|
34
|
+
if (options.cause !== void 0) this.cause = options.cause;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var StorageSerializationError = class extends StorageError {
|
|
38
|
+
constructor(message, options = {}) {
|
|
39
|
+
super("serialization", message, options);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/serialization/json.ts
|
|
44
|
+
function assertJson(value, path, seen) {
|
|
45
|
+
switch (typeof value) {
|
|
46
|
+
case "string":
|
|
47
|
+
case "boolean":
|
|
48
|
+
return;
|
|
49
|
+
case "number":
|
|
50
|
+
if (!Number.isFinite(value)) throw new StorageSerializationError(`${path} is ${value}, which JSON cannot hold.`);
|
|
51
|
+
return;
|
|
52
|
+
case "object":
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
throw new StorageSerializationError(`${path} is a ${typeof value}, which JSON cannot hold.`);
|
|
56
|
+
}
|
|
57
|
+
if (value === null) return;
|
|
58
|
+
if (seen.has(value)) throw new StorageSerializationError(`${path} refers back to itself.`);
|
|
59
|
+
seen.add(value);
|
|
60
|
+
if (Array.isArray(value)) {
|
|
61
|
+
value.forEach((item, i) => assertJson(item, `${path}[${i}]`, seen));
|
|
62
|
+
} else {
|
|
63
|
+
const proto = Object.getPrototypeOf(value);
|
|
64
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
65
|
+
const name = value.constructor?.name ?? "an object with a prototype";
|
|
66
|
+
throw new StorageSerializationError(`${path} is ${name}, which does not survive JSON. Convert it to plain data first.`);
|
|
67
|
+
}
|
|
68
|
+
for (const [key, item] of Object.entries(value)) {
|
|
69
|
+
if (item === void 0) throw new StorageSerializationError(`${path}.${key} is undefined, which JSON drops. Omit the key or use null.`);
|
|
70
|
+
assertJson(item, `${path}.${key}`, seen);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
seen.delete(value);
|
|
74
|
+
}
|
|
75
|
+
var jsonSerializer = {
|
|
76
|
+
serialize(value) {
|
|
77
|
+
assertJson(value, "value", /* @__PURE__ */ new Set());
|
|
78
|
+
return JSON.stringify(value);
|
|
79
|
+
},
|
|
80
|
+
deserialize(text) {
|
|
81
|
+
return JSON.parse(text);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/serialization/json.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAkC1D,eAAO,MAAM,cAAc,EAAE,iBAQ5B,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strict JSON. JSON.stringify drops a function, turns NaN into null and a Date into a string
|
|
3
|
+
* that reads back as a string, all without a word. This refuses them instead, naming where:
|
|
4
|
+
* convert first (a Date to its ISO string), and the value reads back as it was written.
|
|
5
|
+
*/
|
|
6
|
+
import { StorageSerializationError } from '../core/errors.js';
|
|
7
|
+
function assertJson(value, path, seen) {
|
|
8
|
+
switch (typeof value) {
|
|
9
|
+
case 'string':
|
|
10
|
+
case 'boolean':
|
|
11
|
+
return;
|
|
12
|
+
case 'number':
|
|
13
|
+
if (!Number.isFinite(value))
|
|
14
|
+
throw new StorageSerializationError(`${path} is ${value}, which JSON cannot hold.`);
|
|
15
|
+
return;
|
|
16
|
+
case 'object':
|
|
17
|
+
break;
|
|
18
|
+
default:
|
|
19
|
+
throw new StorageSerializationError(`${path} is a ${typeof value}, which JSON cannot hold.`);
|
|
20
|
+
}
|
|
21
|
+
if (value === null)
|
|
22
|
+
return;
|
|
23
|
+
if (seen.has(value))
|
|
24
|
+
throw new StorageSerializationError(`${path} refers back to itself.`);
|
|
25
|
+
seen.add(value);
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
value.forEach((item, i) => assertJson(item, `${path}[${i}]`, seen));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const proto = Object.getPrototypeOf(value);
|
|
31
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
32
|
+
const name = value.constructor?.name ?? 'an object with a prototype';
|
|
33
|
+
throw new StorageSerializationError(`${path} is ${name}, which does not survive JSON. Convert it to plain data first.`);
|
|
34
|
+
}
|
|
35
|
+
for (const [key, item] of Object.entries(value)) {
|
|
36
|
+
if (item === undefined)
|
|
37
|
+
throw new StorageSerializationError(`${path}.${key} is undefined, which JSON drops. Omit the key or use null.`);
|
|
38
|
+
assertJson(item, `${path}.${key}`, seen);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
seen.delete(value);
|
|
42
|
+
}
|
|
43
|
+
export const jsonSerializer = {
|
|
44
|
+
serialize(value) {
|
|
45
|
+
assertJson(value, 'value', new Set());
|
|
46
|
+
return JSON.stringify(value);
|
|
47
|
+
},
|
|
48
|
+
deserialize(text) {
|
|
49
|
+
return JSON.parse(text);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
|
|
17
|
+
// src/serialization/json.ts
|
|
18
|
+
function assertJson(value, path, seen) {
|
|
19
|
+
switch (typeof value) {
|
|
20
|
+
case "string":
|
|
21
|
+
case "boolean":
|
|
22
|
+
return;
|
|
23
|
+
case "number":
|
|
24
|
+
if (!Number.isFinite(value)) throw new StorageSerializationError(`${path} is ${value}, which JSON cannot hold.`);
|
|
25
|
+
return;
|
|
26
|
+
case "object":
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
throw new StorageSerializationError(`${path} is a ${typeof value}, which JSON cannot hold.`);
|
|
30
|
+
}
|
|
31
|
+
if (value === null) return;
|
|
32
|
+
if (seen.has(value)) throw new StorageSerializationError(`${path} refers back to itself.`);
|
|
33
|
+
seen.add(value);
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
value.forEach((item, i) => assertJson(item, `${path}[${i}]`, seen));
|
|
36
|
+
} else {
|
|
37
|
+
const proto = Object.getPrototypeOf(value);
|
|
38
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
39
|
+
const name = value.constructor?.name ?? "an object with a prototype";
|
|
40
|
+
throw new StorageSerializationError(`${path} is ${name}, which does not survive JSON. Convert it to plain data first.`);
|
|
41
|
+
}
|
|
42
|
+
for (const [key, item] of Object.entries(value)) {
|
|
43
|
+
if (item === void 0) throw new StorageSerializationError(`${path}.${key} is undefined, which JSON drops. Omit the key or use null.`);
|
|
44
|
+
assertJson(item, `${path}.${key}`, seen);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
seen.delete(value);
|
|
48
|
+
}
|
|
49
|
+
var jsonSerializer = {
|
|
50
|
+
serialize(value) {
|
|
51
|
+
assertJson(value, "value", /* @__PURE__ */ new Set());
|
|
52
|
+
return JSON.stringify(value);
|
|
53
|
+
},
|
|
54
|
+
deserialize(text) {
|
|
55
|
+
return JSON.parse(text);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
export {
|
|
59
|
+
jsonSerializer
|
|
60
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
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/serialization/serializer.ts
|
|
21
|
+
var serializer_exports = {};
|
|
22
|
+
__export(serializer_exports, {
|
|
23
|
+
createSerializer: () => createSerializer
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(serializer_exports);
|
|
26
|
+
function createSerializer(serialize, deserialize) {
|
|
27
|
+
return { serialize, deserialize };
|
|
28
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StorageSerializer } from '../core/types.js';
|
|
2
|
+
/** A serializer from two functions. */
|
|
3
|
+
export declare function createSerializer(serialize: (value: unknown) => string, deserialize: <T = unknown>(text: string) => T): StorageSerializer;
|
|
4
|
+
//# sourceMappingURL=serializer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../src/serialization/serializer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,uCAAuC;AACvC,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,EACrC,WAAW,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC,GAC5C,iBAAiB,CAEnB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
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/server/contracts.ts
|
|
21
|
+
var contracts_exports = {};
|
|
22
|
+
__export(contracts_exports, {
|
|
23
|
+
toStorageRequest: () => toStorageRequest,
|
|
24
|
+
toStorageResponse: () => toStorageResponse
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(contracts_exports);
|
|
27
|
+
function toStorageRequest(request) {
|
|
28
|
+
if ("getHeader" in request) return request;
|
|
29
|
+
const headers = "headers" in request ? request.headers : request;
|
|
30
|
+
return { getHeader: (name) => headers.get(name) };
|
|
31
|
+
}
|
|
32
|
+
function toStorageResponse(response) {
|
|
33
|
+
if ("appendHeader" in response) return response;
|
|
34
|
+
const headers = "headers" in response ? response.headers : response;
|
|
35
|
+
return { appendHeader: (name, value) => headers.append(name, value) };
|
|
36
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a server adapter needs from the request and the response. Any framework fits: a fetch
|
|
3
|
+
* `Request` and `Headers` are accepted as they are, anything else adapts in one line.
|
|
4
|
+
*/
|
|
5
|
+
export interface StorageRequest {
|
|
6
|
+
getHeader(name: string): string | null | undefined;
|
|
7
|
+
}
|
|
8
|
+
export interface StorageResponse {
|
|
9
|
+
/** Adds a header value without replacing earlier ones (one `Set-Cookie` per cookie). */
|
|
10
|
+
appendHeader(name: string, value: string): void;
|
|
11
|
+
}
|
|
12
|
+
interface HeadersLike {
|
|
13
|
+
get(name: string): string | null;
|
|
14
|
+
}
|
|
15
|
+
interface MutableHeadersLike {
|
|
16
|
+
append(name: string, value: string): void;
|
|
17
|
+
}
|
|
18
|
+
export type RequestLike = StorageRequest | HeadersLike | {
|
|
19
|
+
headers: HeadersLike;
|
|
20
|
+
};
|
|
21
|
+
export type ResponseLike = StorageResponse | MutableHeadersLike | {
|
|
22
|
+
headers: MutableHeadersLike;
|
|
23
|
+
};
|
|
24
|
+
export declare function toStorageRequest(request: RequestLike): StorageRequest;
|
|
25
|
+
export declare function toStorageResponse(response: ResponseLike): StorageResponse;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=contracts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/server/contracts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACpD;AAED,MAAM,WAAW,eAAe;IAC9B,wFAAwF;IACxF,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACjD;AAED,UAAU,WAAW;IACnB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAClC;AACD,UAAU,kBAAkB;IAC1B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,WAAW,GAAG;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAClF,MAAM,MAAM,YAAY,GAAG,eAAe,GAAG,kBAAkB,GAAG;IAAE,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAElG,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAIrE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,eAAe,CAIzE"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a server adapter needs from the request and the response. Any framework fits: a fetch
|
|
3
|
+
* `Request` and `Headers` are accepted as they are, anything else adapts in one line.
|
|
4
|
+
*/
|
|
5
|
+
export function toStorageRequest(request) {
|
|
6
|
+
if ('getHeader' in request)
|
|
7
|
+
return request;
|
|
8
|
+
const headers = 'headers' in request ? request.headers : request;
|
|
9
|
+
return { getHeader: (name) => headers.get(name) };
|
|
10
|
+
}
|
|
11
|
+
export function toStorageResponse(response) {
|
|
12
|
+
if ('appendHeader' in response)
|
|
13
|
+
return response;
|
|
14
|
+
const headers = 'headers' in response ? response.headers : response;
|
|
15
|
+
return { appendHeader: (name, value) => headers.append(name, value) };
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/server/contracts.ts
|
|
2
|
+
function toStorageRequest(request) {
|
|
3
|
+
if ("getHeader" in request) return request;
|
|
4
|
+
const headers = "headers" in request ? request.headers : request;
|
|
5
|
+
return { getHeader: (name) => headers.get(name) };
|
|
6
|
+
}
|
|
7
|
+
function toStorageResponse(response) {
|
|
8
|
+
if ("appendHeader" in response) return response;
|
|
9
|
+
const headers = "headers" in response ? response.headers : response;
|
|
10
|
+
return { appendHeader: (name, value) => headers.append(name, value) };
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
toStorageRequest,
|
|
14
|
+
toStorageResponse
|
|
15
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
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/server/cookie.ts
|
|
21
|
+
var cookie_exports = {};
|
|
22
|
+
__export(cookie_exports, {
|
|
23
|
+
cookieStorage: () => cookieStorage
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(cookie_exports);
|
|
26
|
+
var import_cookie = require("@fluixi/utils/cookie");
|
|
27
|
+
|
|
28
|
+
// src/core/errors.ts
|
|
29
|
+
var StorageError = class extends Error {
|
|
30
|
+
constructor(code, message, options = {}) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = new.target.name;
|
|
33
|
+
this.code = code;
|
|
34
|
+
this.key = options.key;
|
|
35
|
+
if (options.cause !== void 0) this.cause = options.cause;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var StorageUnavailableError = class extends StorageError {
|
|
39
|
+
constructor(message, options = {}) {
|
|
40
|
+
super("unavailable", message, options);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var StorageQuotaError = class extends StorageError {
|
|
44
|
+
constructor(message, options = {}) {
|
|
45
|
+
super("quota", message, options);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/utils/cookie-names.ts
|
|
50
|
+
var encodeCookieName = (key) => encodeURIComponent(key).replace(/[()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
51
|
+
var decodeCookieName = (name) => {
|
|
52
|
+
try {
|
|
53
|
+
return decodeURIComponent(name);
|
|
54
|
+
} catch {
|
|
55
|
+
return name;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var cookiePairSize = (header) => new TextEncoder().encode(header.slice(0, header.indexOf(";"))).length;
|
|
59
|
+
var withEntryExpiry = (cookie, expiresAt) => expiresAt === void 0 ? cookie : { ...cookie, maxAge: void 0, expires: new Date(expiresAt) };
|
|
60
|
+
|
|
61
|
+
// src/server/contracts.ts
|
|
62
|
+
function toStorageRequest(request) {
|
|
63
|
+
if ("getHeader" in request) return request;
|
|
64
|
+
const headers = "headers" in request ? request.headers : request;
|
|
65
|
+
return { getHeader: (name) => headers.get(name) };
|
|
66
|
+
}
|
|
67
|
+
function toStorageResponse(response) {
|
|
68
|
+
if ("appendHeader" in response) return response;
|
|
69
|
+
const headers = "headers" in response ? response.headers : response;
|
|
70
|
+
return { appendHeader: (name, value) => headers.append(name, value) };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/server/cookie.ts
|
|
74
|
+
function cookieStorage(options = {}) {
|
|
75
|
+
const { request, response, maxSize = 4096, ...cookie } = options;
|
|
76
|
+
const reader = request ? toStorageRequest(request) : null;
|
|
77
|
+
const writer = response ? toStorageResponse(response) : null;
|
|
78
|
+
let incoming = null;
|
|
79
|
+
const written = /* @__PURE__ */ new Map();
|
|
80
|
+
const read = () => {
|
|
81
|
+
if (!incoming) {
|
|
82
|
+
incoming = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const [name, value] of Object.entries((0, import_cookie.parseCookies)(reader?.getHeader("cookie")))) incoming.set(decodeCookieName(name), value);
|
|
84
|
+
}
|
|
85
|
+
return incoming;
|
|
86
|
+
};
|
|
87
|
+
const emit = (key, header) => {
|
|
88
|
+
if (!writer) throw new StorageUnavailableError("This cookie storage has no response to write to.", { key });
|
|
89
|
+
writer.appendHeader("set-cookie", header);
|
|
90
|
+
};
|
|
91
|
+
const get = (key) => written.has(key) ? written.get(key) : read().get(key) ?? null;
|
|
92
|
+
const keys = () => {
|
|
93
|
+
const all = new Set(read().keys());
|
|
94
|
+
for (const [key, value] of written) value === null ? all.delete(key) : all.add(key);
|
|
95
|
+
return [...all];
|
|
96
|
+
};
|
|
97
|
+
const remove = (key) => {
|
|
98
|
+
if (get(key) === null) return;
|
|
99
|
+
emit(key, (0, import_cookie.serializeCookie)(encodeCookieName(key), "", { ...cookie, maxAge: 0, expires: /* @__PURE__ */ new Date(0) }));
|
|
100
|
+
written.set(key, null);
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
name: "cookie",
|
|
104
|
+
scope: "cookie",
|
|
105
|
+
capabilities: {
|
|
106
|
+
synchronous: true,
|
|
107
|
+
persistent: true,
|
|
108
|
+
reactive: false,
|
|
109
|
+
crossContext: true,
|
|
110
|
+
expiration: false,
|
|
111
|
+
transactions: false
|
|
112
|
+
},
|
|
113
|
+
get,
|
|
114
|
+
set(key, value, writeOptions) {
|
|
115
|
+
const header = (0, import_cookie.serializeCookie)(encodeCookieName(key), value, withEntryExpiry(cookie, writeOptions?.expiresAt));
|
|
116
|
+
const size = cookiePairSize(header);
|
|
117
|
+
if (size > maxSize) throw new StorageQuotaError(`Cookie ${key} is ${size} bytes, over the ${maxSize} limit.`, { key });
|
|
118
|
+
emit(key, header);
|
|
119
|
+
written.set(key, value);
|
|
120
|
+
},
|
|
121
|
+
remove,
|
|
122
|
+
has: (key) => get(key) !== null,
|
|
123
|
+
keys,
|
|
124
|
+
clear: () => keys().forEach(remove)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type CookieOptions } from '@fluixi/utils/cookie';
|
|
2
|
+
import type { StorageAdapter } from '../core/types.js';
|
|
3
|
+
import { type RequestLike, type ResponseLike } from './contracts.js';
|
|
4
|
+
export interface CookieStorageOptions extends CookieOptions {
|
|
5
|
+
/** Where the cookies are read from. Without it the adapter starts empty. */
|
|
6
|
+
request?: RequestLike;
|
|
7
|
+
/** Where `Set-Cookie` headers go. Without it the adapter is read-only. */
|
|
8
|
+
response?: ResponseLike;
|
|
9
|
+
/** Largest `name=value` in bytes. Browsers keep about 4096. */
|
|
10
|
+
maxSize?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Cookies of one request. Reads come from the request's `Cookie` header plus this adapter's own
|
|
14
|
+
* writes; each write appends a `Set-Cookie` to the response. Make one per request.
|
|
15
|
+
*
|
|
16
|
+
* Every cookie the request carries is visible, so give the storage a namespace: `clear()` on a
|
|
17
|
+
* storage without one deletes the session cookie too. Expiry set through the storage lives in the
|
|
18
|
+
* value and also sets the cookie's Expires; without one the cookie lasts as `maxAge`/`expires` say.
|
|
19
|
+
*/
|
|
20
|
+
export declare function cookieStorage(options?: CookieStorageOptions): StorageAdapter;
|
|
21
|
+
//# sourceMappingURL=cookie.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie.d.ts","sourceRoot":"","sources":["../../src/server/cookie.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAuC,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE1G,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,4EAA4E;IAC5E,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAuDhF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { parseCookies, serializeCookie } from '@fluixi/utils/cookie';
|
|
2
|
+
import { StorageQuotaError, StorageUnavailableError } from '../core/errors.js';
|
|
3
|
+
import { cookiePairSize, decodeCookieName as decodeName, encodeCookieName as encodeName, withEntryExpiry } from '../utils/cookie-names.js';
|
|
4
|
+
import { toStorageRequest, toStorageResponse } from './contracts.js';
|
|
5
|
+
/**
|
|
6
|
+
* Cookies of one request. Reads come from the request's `Cookie` header plus this adapter's own
|
|
7
|
+
* writes; each write appends a `Set-Cookie` to the response. Make one per request.
|
|
8
|
+
*
|
|
9
|
+
* Every cookie the request carries is visible, so give the storage a namespace: `clear()` on a
|
|
10
|
+
* storage without one deletes the session cookie too. Expiry set through the storage lives in the
|
|
11
|
+
* value and also sets the cookie's Expires; without one the cookie lasts as `maxAge`/`expires` say.
|
|
12
|
+
*/
|
|
13
|
+
export function cookieStorage(options = {}) {
|
|
14
|
+
const { request, response, maxSize = 4096, ...cookie } = options;
|
|
15
|
+
const reader = request ? toStorageRequest(request) : null;
|
|
16
|
+
const writer = response ? toStorageResponse(response) : null;
|
|
17
|
+
let incoming = null;
|
|
18
|
+
// This request's writes: a value, or null once removed.
|
|
19
|
+
const written = new Map();
|
|
20
|
+
const read = () => {
|
|
21
|
+
if (!incoming) {
|
|
22
|
+
incoming = new Map();
|
|
23
|
+
for (const [name, value] of Object.entries(parseCookies(reader?.getHeader('cookie'))))
|
|
24
|
+
incoming.set(decodeName(name), value);
|
|
25
|
+
}
|
|
26
|
+
return incoming;
|
|
27
|
+
};
|
|
28
|
+
const emit = (key, header) => {
|
|
29
|
+
if (!writer)
|
|
30
|
+
throw new StorageUnavailableError('This cookie storage has no response to write to.', { key });
|
|
31
|
+
writer.appendHeader('set-cookie', header);
|
|
32
|
+
};
|
|
33
|
+
const get = (key) => (written.has(key) ? written.get(key) : read().get(key) ?? null);
|
|
34
|
+
const keys = () => {
|
|
35
|
+
const all = new Set(read().keys());
|
|
36
|
+
for (const [key, value] of written)
|
|
37
|
+
value === null ? all.delete(key) : all.add(key);
|
|
38
|
+
return [...all];
|
|
39
|
+
};
|
|
40
|
+
const remove = (key) => {
|
|
41
|
+
if (get(key) === null)
|
|
42
|
+
return;
|
|
43
|
+
emit(key, serializeCookie(encodeName(key), '', { ...cookie, maxAge: 0, expires: new Date(0) }));
|
|
44
|
+
written.set(key, null);
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
name: 'cookie',
|
|
48
|
+
scope: 'cookie',
|
|
49
|
+
capabilities: {
|
|
50
|
+
synchronous: true,
|
|
51
|
+
persistent: true,
|
|
52
|
+
reactive: false,
|
|
53
|
+
crossContext: true,
|
|
54
|
+
expiration: false,
|
|
55
|
+
transactions: false,
|
|
56
|
+
},
|
|
57
|
+
get,
|
|
58
|
+
set(key, value, writeOptions) {
|
|
59
|
+
const header = serializeCookie(encodeName(key), value, withEntryExpiry(cookie, writeOptions?.expiresAt));
|
|
60
|
+
const size = cookiePairSize(header);
|
|
61
|
+
if (size > maxSize)
|
|
62
|
+
throw new StorageQuotaError(`Cookie ${key} is ${size} bytes, over the ${maxSize} limit.`, { key });
|
|
63
|
+
emit(key, header);
|
|
64
|
+
written.set(key, value);
|
|
65
|
+
},
|
|
66
|
+
remove,
|
|
67
|
+
has: (key) => get(key) !== null,
|
|
68
|
+
keys,
|
|
69
|
+
clear: () => keys().forEach(remove),
|
|
70
|
+
};
|
|
71
|
+
}
|