@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.
Files changed (134) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/adapters/memory.cjs +46 -0
  4. package/dist/adapters/memory.d.ts +8 -0
  5. package/dist/adapters/memory.d.ts.map +1 -0
  6. package/dist/adapters/memory.js +26 -0
  7. package/dist/adapters/memory.mjs +25 -0
  8. package/dist/browser/document-cookie.cjs +101 -0
  9. package/dist/browser/document-cookie.d.ts +14 -0
  10. package/dist/browser/document-cookie.d.ts.map +1 -0
  11. package/dist/browser/document-cookie.js +53 -0
  12. package/dist/browser/document-cookie.mjs +80 -0
  13. package/dist/browser/index.cjs +209 -0
  14. package/dist/browser/index.d.ts +4 -0
  15. package/dist/browser/index.d.ts.map +1 -0
  16. package/dist/browser/index.js +3 -0
  17. package/dist/browser/index.mjs +187 -0
  18. package/dist/browser/web-storage.cjs +150 -0
  19. package/dist/browser/web-storage.d.ts +6 -0
  20. package/dist/browser/web-storage.d.ts.map +1 -0
  21. package/dist/browser/web-storage.js +105 -0
  22. package/dist/browser/web-storage.mjs +127 -0
  23. package/dist/core/async-storage.cjs +583 -0
  24. package/dist/core/async-storage.d.ts +17 -0
  25. package/dist/core/async-storage.d.ts.map +1 -0
  26. package/dist/core/async-storage.js +275 -0
  27. package/dist/core/async-storage.mjs +560 -0
  28. package/dist/core/bus.cjs +52 -0
  29. package/dist/core/bus.d.ts +19 -0
  30. package/dist/core/bus.d.ts.map +1 -0
  31. package/dist/core/bus.js +31 -0
  32. package/dist/core/bus.mjs +31 -0
  33. package/dist/core/envelope.cjs +119 -0
  34. package/dist/core/envelope.d.ts +38 -0
  35. package/dist/core/envelope.d.ts.map +1 -0
  36. package/dist/core/envelope.js +83 -0
  37. package/dist/core/envelope.mjs +96 -0
  38. package/dist/core/errors.cjs +115 -0
  39. package/dist/core/errors.d.ts +109 -0
  40. package/dist/core/errors.d.ts.map +1 -0
  41. package/dist/core/errors.js +99 -0
  42. package/dist/core/errors.mjs +94 -0
  43. package/dist/core/storage.cjs +782 -0
  44. package/dist/core/storage.d.ts +63 -0
  45. package/dist/core/storage.d.ts.map +1 -0
  46. package/dist/core/storage.js +260 -0
  47. package/dist/core/storage.mjs +759 -0
  48. package/dist/core/types.cjs +18 -0
  49. package/dist/core/types.d.ts +239 -0
  50. package/dist/core/types.d.ts.map +1 -0
  51. package/dist/core/types.js +1 -0
  52. package/dist/core/types.mjs +0 -0
  53. package/dist/encryption/base64.cjs +38 -0
  54. package/dist/encryption/base64.d.ts +4 -0
  55. package/dist/encryption/base64.d.ts.map +1 -0
  56. package/dist/encryption/base64.js +16 -0
  57. package/dist/encryption/base64.mjs +17 -0
  58. package/dist/encryption/keys.cjs +77 -0
  59. package/dist/encryption/keys.d.ts +14 -0
  60. package/dist/encryption/keys.d.ts.map +1 -0
  61. package/dist/encryption/keys.js +28 -0
  62. package/dist/encryption/keys.mjs +54 -0
  63. package/dist/encryption/seal.cjs +154 -0
  64. package/dist/encryption/seal.d.ts +24 -0
  65. package/dist/encryption/seal.d.ts.map +1 -0
  66. package/dist/encryption/seal.js +83 -0
  67. package/dist/encryption/seal.mjs +131 -0
  68. package/dist/encryption/types.cjs +18 -0
  69. package/dist/encryption/types.d.ts +50 -0
  70. package/dist/encryption/types.d.ts.map +1 -0
  71. package/dist/encryption/types.js +1 -0
  72. package/dist/encryption/types.mjs +0 -0
  73. package/dist/encryption/web-crypto.cjs +81 -0
  74. package/dist/encryption/web-crypto.d.ts +9 -0
  75. package/dist/encryption/web-crypto.d.ts.map +1 -0
  76. package/dist/encryption/web-crypto.js +45 -0
  77. package/dist/encryption/web-crypto.mjs +58 -0
  78. package/dist/index.cjs +870 -0
  79. package/dist/index.d.ts +16 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +13 -0
  82. package/dist/index.mjs +848 -0
  83. package/dist/serialization/json.cjs +83 -0
  84. package/dist/serialization/json.d.ts +3 -0
  85. package/dist/serialization/json.d.ts.map +1 -0
  86. package/dist/serialization/json.js +51 -0
  87. package/dist/serialization/json.mjs +60 -0
  88. package/dist/serialization/serializer.cjs +28 -0
  89. package/dist/serialization/serializer.d.ts +4 -0
  90. package/dist/serialization/serializer.d.ts.map +1 -0
  91. package/dist/serialization/serializer.js +4 -0
  92. package/dist/serialization/serializer.mjs +7 -0
  93. package/dist/server/contracts.cjs +36 -0
  94. package/dist/server/contracts.d.ts +27 -0
  95. package/dist/server/contracts.d.ts.map +1 -0
  96. package/dist/server/contracts.js +16 -0
  97. package/dist/server/contracts.mjs +15 -0
  98. package/dist/server/cookie.cjs +126 -0
  99. package/dist/server/cookie.d.ts +21 -0
  100. package/dist/server/cookie.d.ts.map +1 -0
  101. package/dist/server/cookie.js +71 -0
  102. package/dist/server/cookie.mjs +105 -0
  103. package/dist/server/index.cjs +155 -0
  104. package/dist/server/index.d.ts +5 -0
  105. package/dist/server/index.d.ts.map +1 -0
  106. package/dist/server/index.js +4 -0
  107. package/dist/server/index.mjs +133 -0
  108. package/dist/server/request.cjs +46 -0
  109. package/dist/server/request.d.ts +7 -0
  110. package/dist/server/request.d.ts.map +1 -0
  111. package/dist/server/request.js +25 -0
  112. package/dist/server/request.mjs +25 -0
  113. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  114. package/dist/utils/cookie-names.cjs +38 -0
  115. package/dist/utils/cookie-names.d.ts +10 -0
  116. package/dist/utils/cookie-names.d.ts.map +1 -0
  117. package/dist/utils/cookie-names.js +15 -0
  118. package/dist/utils/cookie-names.mjs +17 -0
  119. package/dist/utils/copy.cjs +38 -0
  120. package/dist/utils/copy.d.ts +17 -0
  121. package/dist/utils/copy.d.ts.map +1 -0
  122. package/dist/utils/copy.js +15 -0
  123. package/dist/utils/copy.mjs +17 -0
  124. package/dist/utils/environment.cjs +28 -0
  125. package/dist/utils/environment.d.ts +3 -0
  126. package/dist/utils/environment.d.ts.map +1 -0
  127. package/dist/utils/environment.js +4 -0
  128. package/dist/utils/environment.mjs +7 -0
  129. package/dist/utils/keys.cjs +33 -0
  130. package/dist/utils/keys.d.ts +5 -0
  131. package/dist/utils/keys.d.ts.map +1 -0
  132. package/dist/utils/keys.js +10 -0
  133. package/dist/utils/keys.mjs +12 -0
  134. 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,3 @@
1
+ import type { StorageSerializer } from '../core/types.js';
2
+ export declare const jsonSerializer: StorageSerializer;
3
+ //# sourceMappingURL=json.d.ts.map
@@ -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,4 @@
1
+ /** A serializer from two functions. */
2
+ export function createSerializer(serialize, deserialize) {
3
+ return { serialize, deserialize };
4
+ }
@@ -0,0 +1,7 @@
1
+ // src/serialization/serializer.ts
2
+ function createSerializer(serialize, deserialize) {
3
+ return { serialize, deserialize };
4
+ }
5
+ export {
6
+ createSerializer
7
+ };
@@ -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
+ }