@c9up/ream 0.2.27 → 0.2.28
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/README.md +1 -0
- package/dist/Ignitor.d.ts +3 -1
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +7 -0
- package/dist/Ignitor.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/native/generated.d.ts +34 -0
- package/dist/native/generated.d.ts.map +1 -1
- package/dist/server/Server.d.ts +37 -0
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/Server.js +30 -0
- package/dist/server/Server.js.map +1 -1
- package/dist/session/Session.d.ts +33 -0
- package/dist/session/Session.d.ts.map +1 -1
- package/dist/session/Session.js +31 -2
- package/dist/session/Session.js.map +1 -1
- package/dist/session/SessionMiddleware.d.ts.map +1 -1
- package/dist/session/SessionMiddleware.js +24 -4
- package/dist/session/SessionMiddleware.js.map +1 -1
- package/dist/session/drivers/CookieDriver.d.ts +12 -3
- package/dist/session/drivers/CookieDriver.d.ts.map +1 -1
- package/dist/session/drivers/CookieDriver.js +20 -6
- package/dist/session/drivers/CookieDriver.js.map +1 -1
- package/dist/session/drivers/DatabaseDriver.d.ts +2 -0
- package/dist/session/drivers/DatabaseDriver.d.ts.map +1 -1
- package/dist/session/drivers/DatabaseDriver.js +6 -0
- package/dist/session/drivers/DatabaseDriver.js.map +1 -1
- package/dist/session/drivers/FileDriver.d.ts +8 -0
- package/dist/session/drivers/FileDriver.d.ts.map +1 -1
- package/dist/session/drivers/FileDriver.js +85 -11
- package/dist/session/drivers/FileDriver.js.map +1 -1
- package/dist/session/drivers/MemoryDriver.d.ts +2 -0
- package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/session/drivers/MemoryDriver.js +9 -0
- package/dist/session/drivers/MemoryDriver.js.map +1 -1
- package/dist/session/drivers/RedisDriver.d.ts +2 -0
- package/dist/session/drivers/RedisDriver.d.ts.map +1 -1
- package/dist/session/drivers/RedisDriver.js +6 -0
- package/dist/session/drivers/RedisDriver.js.map +1 -1
- package/dist/session/errors.d.ts +10 -0
- package/dist/session/errors.d.ts.map +1 -1
- package/dist/session/errors.js +12 -0
- package/dist/session/errors.js.map +1 -1
- package/events.darwin-arm64.node +0 -0
- package/events.darwin-x64.node +0 -0
- package/events.linux-arm64-gnu.node +0 -0
- package/events.linux-x64-gnu.node +0 -0
- package/events.win32-x64-msvc.node +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
- package/scheduler.darwin-arm64.node +0 -0
- package/scheduler.darwin-x64.node +0 -0
- package/scheduler.linux-arm64-gnu.node +0 -0
- package/scheduler.linux-x64-gnu.node +0 -0
- package/scheduler.win32-x64-msvc.node +0 -0
- package/src/Ignitor.ts +14 -1
- package/src/index.ts +5 -1
- package/src/native/generated.ts +38 -0
- package/src/server/Server.ts +49 -0
- package/src/session/Session.ts +56 -2
- package/src/session/SessionMiddleware.ts +23 -4
- package/src/session/drivers/CookieDriver.ts +21 -6
- package/src/session/drivers/DatabaseDriver.ts +10 -0
- package/src/session/drivers/FileDriver.ts +91 -11
- package/src/session/drivers/MemoryDriver.ts +9 -0
- package/src/session/drivers/RedisDriver.ts +7 -0
- package/src/session/errors.ts +17 -0
|
@@ -46,6 +46,15 @@ export class MemoryDriver {
|
|
|
46
46
|
this.#store.delete(oldest.value);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
/** Atomic by construction: nothing else runs between the check and the set. */
|
|
50
|
+
async update(sessionId, data, ttl) {
|
|
51
|
+
const entry = this.#store.get(sessionId);
|
|
52
|
+
if (!entry || entry.expiresAt < Date.now())
|
|
53
|
+
return false;
|
|
54
|
+
this.#store.delete(sessionId);
|
|
55
|
+
this.#store.set(sessionId, { data, expiresAt: Date.now() + ttl * 1000 });
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
49
58
|
async destroy(sessionId) {
|
|
50
59
|
this.#store.delete(sessionId);
|
|
51
60
|
// Drop the tags too: a destroyed session left in the index would be
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryDriver.js","sourceRoot":"","sources":["../../../src/session/drivers/MemoryDriver.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MemoryDriver.js","sourceRoot":"","sources":["../../../src/session/drivers/MemoryDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,6 +36,8 @@ export declare class RedisDriver implements SessionDriverWithTagging {
|
|
|
36
36
|
*/
|
|
37
37
|
read(sessionId: string): Promise<Record<string, unknown> | null>;
|
|
38
38
|
write(sessionId: string, data: Record<string, unknown>, ttl: number): Promise<void>;
|
|
39
|
+
/** `XX` makes the existence check and the write one command. */
|
|
40
|
+
update(sessionId: string, data: Record<string, unknown>, ttl: number): Promise<boolean>;
|
|
39
41
|
destroy(sessionId: string): Promise<void>;
|
|
40
42
|
/** Slide the expiry — a session must not die while its owner is active. */
|
|
41
43
|
touch(sessionId: string, ttl: number): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedisDriver.d.ts","sourceRoot":"","sources":["../../../src/session/drivers/RedisDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE5E,4EAA4E;AAC5E,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACrE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACrD,iFAAiF;IACjF,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACzD,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACzD,QAAQ,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACzC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACtC;AAaD,uFAAuF;AACvF,MAAM,MAAM,wBAAwB,GAChC,kBAAkB,GAClB,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAA;AAE5D,MAAM,WAAW,mBAAmB;IAClC,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,qBAAa,WAAY,YAAW,wBAAwB;;gBAM9C,MAAM,EAAE,wBAAwB,EAAE,OAAO,GAAE,mBAAwB;IAmE/E;;;;OAIG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAahE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"RedisDriver.d.ts","sourceRoot":"","sources":["../../../src/session/drivers/RedisDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE5E,4EAA4E;AAC5E,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACrE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACrD,iFAAiF;IACjF,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACzD,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACzD,QAAQ,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACzC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACtC;AAaD,uFAAuF;AACvF,MAAM,MAAM,wBAAwB,GAChC,kBAAkB,GAClB,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAA;AAE5D,MAAM,WAAW,mBAAmB;IAClC,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,qBAAa,WAAY,YAAW,wBAAwB;;gBAM9C,MAAM,EAAE,wBAAwB,EAAE,OAAO,GAAE,mBAAwB;IAmE/E;;;;OAIG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAahE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzF,gEAAgE;IAC1D,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMvF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/C,2EAA2E;IACrE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9D,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CA0BhE"}
|
|
@@ -102,6 +102,12 @@ export class RedisDriver {
|
|
|
102
102
|
// if the process dies between the two.
|
|
103
103
|
await client.set(this.#key(sessionId), JSON.stringify(data), 'EX', ttl);
|
|
104
104
|
}
|
|
105
|
+
/** `XX` makes the existence check and the write one command. */
|
|
106
|
+
async update(sessionId, data, ttl) {
|
|
107
|
+
const client = await this.#client();
|
|
108
|
+
const reply = await client.set(this.#key(sessionId), JSON.stringify(data), 'EX', ttl, 'XX');
|
|
109
|
+
return reply !== null;
|
|
110
|
+
}
|
|
105
111
|
async destroy(sessionId) {
|
|
106
112
|
const client = await this.#client();
|
|
107
113
|
await client.del(this.#key(sessionId));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedisDriver.js","sourceRoot":"","sources":["../../../src/session/drivers/RedisDriver.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RedisDriver.js","sourceRoot":"","sources":["../../../src/session/drivers/RedisDriver.ts"],"names":[],"mappings":"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"}
|
package/dist/session/errors.d.ts
CHANGED
|
@@ -16,6 +16,16 @@ export declare class E_SESSION_NOT_READY extends Exception {
|
|
|
16
16
|
static code: string;
|
|
17
17
|
constructor(method: string);
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* A store with no `update()`: it cannot write a session back only while its
|
|
21
|
+
* entry still exists, so a request running across a logout could sign the
|
|
22
|
+
* user in again. Refused when the store is attached, not at the first race.
|
|
23
|
+
*/
|
|
24
|
+
export declare class E_SESSION_STORE_NOT_CONDITIONAL extends Exception {
|
|
25
|
+
static status: number;
|
|
26
|
+
static code: string;
|
|
27
|
+
constructor();
|
|
28
|
+
}
|
|
19
29
|
/** The configured store cannot tag sessions (cookie and file stores cannot). */
|
|
20
30
|
export declare class E_SESSION_TAGGING_NOT_SUPPORTED extends Exception {
|
|
21
31
|
static status: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/session/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEhD,8DAA8D;AAC9D,qBAAa,mBAAoB,SAAQ,SAAS;IAChD,OAAgB,MAAM,SAAM;IAC5B,OAAgB,IAAI,SAAwB;gBAEhC,MAAM,EAAE,MAAM;CAM3B;AAED,gFAAgF;AAChF,qBAAa,+BAAgC,SAAQ,SAAS;IAC5D,OAAgB,MAAM,SAAM;IAC5B,OAAgB,IAAI,SAAoC;gBAE5C,MAAM,EAAE,MAAM;CAM3B"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/session/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEhD,8DAA8D;AAC9D,qBAAa,mBAAoB,SAAQ,SAAS;IAChD,OAAgB,MAAM,SAAM;IAC5B,OAAgB,IAAI,SAAwB;gBAEhC,MAAM,EAAE,MAAM;CAM3B;AAED;;;;GAIG;AACH,qBAAa,+BAAgC,SAAQ,SAAS;IAC5D,OAAgB,MAAM,SAAM;IAC5B,OAAgB,IAAI,SAAoC;;CAQzD;AAED,gFAAgF;AAChF,qBAAa,+BAAgC,SAAQ,SAAS;IAC5D,OAAgB,MAAM,SAAM;IAC5B,OAAgB,IAAI,SAAoC;gBAE5C,MAAM,EAAE,MAAM;CAM3B"}
|
package/dist/session/errors.js
CHANGED
|
@@ -21,6 +21,18 @@ export class E_SESSION_NOT_READY extends Exception {
|
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* A store with no `update()`: it cannot write a session back only while its
|
|
26
|
+
* entry still exists, so a request running across a logout could sign the
|
|
27
|
+
* user in again. Refused when the store is attached, not at the first race.
|
|
28
|
+
*/
|
|
29
|
+
export class E_SESSION_STORE_NOT_CONDITIONAL extends Exception {
|
|
30
|
+
static status = 500;
|
|
31
|
+
static code = 'E_SESSION_STORE_NOT_CONDITIONAL';
|
|
32
|
+
constructor() {
|
|
33
|
+
super('This session store has no update(): it must write a session only over an entry that still exists, in one step. See "Writing a session store".', { status: 500, code: 'E_SESSION_STORE_NOT_CONDITIONAL' });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
24
36
|
/** The configured store cannot tag sessions (cookie and file stores cannot). */
|
|
25
37
|
export class E_SESSION_TAGGING_NOT_SUPPORTED extends Exception {
|
|
26
38
|
static status = 500;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/session/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEhD,8DAA8D;AAC9D,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IAChD,MAAM,CAAU,MAAM,GAAG,GAAG,CAAA;IAC5B,MAAM,CAAU,IAAI,GAAG,qBAAqB,CAAA;IAE5C,YAAY,MAAc;QACxB,KAAK,CAAC,WAAW,MAAM,gEAAgE,EAAE;YACvF,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,qBAAqB;SAC5B,CAAC,CAAA;IACJ,CAAC;;AAGH,gFAAgF;AAChF,MAAM,OAAO,+BAAgC,SAAQ,SAAS;IAC5D,MAAM,CAAU,MAAM,GAAG,GAAG,CAAA;IAC5B,MAAM,CAAU,IAAI,GAAG,iCAAiC,CAAA;IAExD,YAAY,MAAc;QACxB,KAAK,CACH,WAAW,MAAM,gGAAgG,EACjH,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,iCAAiC,EAAE,CACzD,CAAA;IACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/session/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEhD,8DAA8D;AAC9D,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IAChD,MAAM,CAAU,MAAM,GAAG,GAAG,CAAA;IAC5B,MAAM,CAAU,IAAI,GAAG,qBAAqB,CAAA;IAE5C,YAAY,MAAc;QACxB,KAAK,CAAC,WAAW,MAAM,gEAAgE,EAAE;YACvF,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,qBAAqB;SAC5B,CAAC,CAAA;IACJ,CAAC;;AAGH;;;;GAIG;AACH,MAAM,OAAO,+BAAgC,SAAQ,SAAS;IAC5D,MAAM,CAAU,MAAM,GAAG,GAAG,CAAA;IAC5B,MAAM,CAAU,IAAI,GAAG,iCAAiC,CAAA;IAExD;QACE,KAAK,CACH,+IAA+I,EAC/I,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,iCAAiC,EAAE,CACzD,CAAA;IACH,CAAC;;AAGH,gFAAgF;AAChF,MAAM,OAAO,+BAAgC,SAAQ,SAAS;IAC5D,MAAM,CAAU,MAAM,GAAG,GAAG,CAAA;IAC5B,MAAM,CAAU,IAAI,GAAG,iCAAiC,CAAA;IAExD,YAAY,MAAc;QACxB,KAAK,CACH,WAAW,MAAM,gGAAgG,EACjH,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,iCAAiC,EAAE,CACzD,CAAA;IACH,CAAC"}
|
package/events.darwin-arm64.node
CHANGED
|
Binary file
|
package/events.darwin-x64.node
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/index.darwin-arm64.node
CHANGED
|
Binary file
|
package/index.darwin-x64.node
CHANGED
|
Binary file
|
|
Binary file
|
package/index.linux-x64-gnu.node
CHANGED
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/Ignitor.ts
CHANGED
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
import { Router } from './router/Router.js'
|
|
52
52
|
import { CookieSigner } from './security/CookieSigner.js'
|
|
53
53
|
import { SignedUrl } from './security/SignedUrl.js'
|
|
54
|
-
import { Server } from './server/Server.js'
|
|
54
|
+
import { type GrpcHandler, Server } from './server/Server.js'
|
|
55
55
|
import { clearApp, setApp } from './services/app.js'
|
|
56
56
|
import { clearEncryption, setEncryption } from './services/encryption.js'
|
|
57
57
|
import { clearLogger, setLogger } from './services/logger.js'
|
|
@@ -268,6 +268,8 @@ export function defineConfig(config: ReamrcConfig): ReamrcConfig {
|
|
|
268
268
|
/** Minimal interface for the HTTP server (NAPI or mock). */
|
|
269
269
|
export interface HyperServerLike {
|
|
270
270
|
onRequest(callback: (request: HttpKernelRequest) => Promise<HttpKernelResponse>): void
|
|
271
|
+
/** Optional — present on the real `HyperServer`; required once `server.grpc()` is used. */
|
|
272
|
+
onGrpc?(callback: GrpcHandler): void
|
|
271
273
|
/**
|
|
272
274
|
* Optional — present on the real `HyperServer` (Rust-backed), absent on
|
|
273
275
|
* trivial test mocks. Ignitor only calls it when a shield config is set.
|
|
@@ -903,6 +905,17 @@ export class Ignitor {
|
|
|
903
905
|
this.#config.host ?? process.env.HOST ?? (this.#app.inProduction ? '0.0.0.0' : 'localhost')
|
|
904
906
|
this.#_httpServer = this.#config.serverFactory(availablePort, this.#host)
|
|
905
907
|
this.#_httpServer.onRequest(kernel)
|
|
908
|
+
const grpc = this.#server.getGrpcHandler()
|
|
909
|
+
if (grpc) {
|
|
910
|
+
if (typeof this.#_httpServer.onGrpc !== 'function') {
|
|
911
|
+
throw new ReamError(
|
|
912
|
+
'E_IGNITOR_GRPC_UNSUPPORTED',
|
|
913
|
+
'A gRPC handler is registered, but this server cannot serve gRPC.',
|
|
914
|
+
{ hint: 'Use the native HyperServer, or a test server that implements onGrpc().' },
|
|
915
|
+
)
|
|
916
|
+
}
|
|
917
|
+
this.#_httpServer.onGrpc(grpc)
|
|
918
|
+
}
|
|
906
919
|
// Pre-resolve client IPs in Rust from the trusted-proxy CIDRs before
|
|
907
920
|
// listen. Security filtering itself lives in @c9up/blackhole.
|
|
908
921
|
const trustedProxies = this.#server.getTrustedProxies()
|
package/src/index.ts
CHANGED
|
@@ -91,6 +91,7 @@ export type {
|
|
|
91
91
|
export { RedisDriver as SessionRedisDriver } from './session/drivers/RedisDriver.js'
|
|
92
92
|
export {
|
|
93
93
|
E_SESSION_NOT_READY,
|
|
94
|
+
E_SESSION_STORE_NOT_CONDITIONAL,
|
|
94
95
|
E_SESSION_TAGGING_NOT_SUPPORTED,
|
|
95
96
|
} from './session/errors.js'
|
|
96
97
|
export type { ValuePath } from './session/ReadOnlyValuesStore.js'
|
|
@@ -220,6 +221,9 @@ export { createHttpKernel } from './HttpKernel.js'
|
|
|
220
221
|
|
|
221
222
|
export type {
|
|
222
223
|
ErrorHandlerClass,
|
|
224
|
+
GrpcCall,
|
|
225
|
+
GrpcHandler,
|
|
226
|
+
GrpcReply,
|
|
223
227
|
LazyImport,
|
|
224
228
|
MiddlewareClass,
|
|
225
229
|
MiddlewareEntry,
|
|
@@ -405,4 +409,4 @@ export {
|
|
|
405
409
|
StatsTracker,
|
|
406
410
|
} from './scheduler/index.js'
|
|
407
411
|
|
|
408
|
-
export const VERSION = '0.2.
|
|
412
|
+
export const VERSION = '0.2.28'
|
package/src/native/generated.ts
CHANGED
|
@@ -23,6 +23,35 @@ export interface NapiResponse {
|
|
|
23
23
|
streamId?: string
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* One gRPC call, handed to the JS handler registered with `onGrpc`.
|
|
28
|
+
*
|
|
29
|
+
* The message crosses as BYTES — never through the `String` (base64 for
|
|
30
|
+
* binary) body of the HTTP path.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
export interface NapiGrpcCall {
|
|
34
|
+
/** `/package.Service/Method`. */
|
|
35
|
+
path: string
|
|
36
|
+
/** Request metadata, header names lowercased. */
|
|
37
|
+
metadata: Record<string, string>
|
|
38
|
+
/** The request message, still encoded. */
|
|
39
|
+
message: Uint8Array
|
|
40
|
+
/** Resolved client IP, by the same trusted-proxy rules as `request.ip`. */
|
|
41
|
+
ip: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* What the gRPC handler answers: a reply `message`, or a status `code`
|
|
46
|
+
* (with its `details`) instead of one.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
export interface NapiGrpcReply {
|
|
50
|
+
message?: Uint8Array
|
|
51
|
+
code?: number
|
|
52
|
+
details?: string
|
|
53
|
+
}
|
|
54
|
+
|
|
26
55
|
/**
|
|
27
56
|
* Configuration for the wire-level shield filter. Mirrors the Rust
|
|
28
57
|
* `ShieldConfig` shape; the JS layer constructs it from `ShieldMiddleware`
|
|
@@ -95,6 +124,15 @@ export declare class HyperServer {
|
|
|
95
124
|
* this comment described until the boundary stopped carrying them.
|
|
96
125
|
*/
|
|
97
126
|
onRequest(callback: (request: Record<string, unknown>) => Promise<NapiResponse>): void
|
|
127
|
+
/**
|
|
128
|
+
* Register the gRPC handler. From `listen()` on, `application/grpc`
|
|
129
|
+
* requests on this port are gRPC calls handed to it; without it they stay
|
|
130
|
+
* HTTP requests. Must be called BEFORE `listen()`.
|
|
131
|
+
*
|
|
132
|
+
* A rejected promise is answered `INTERNAL`, with nothing of the error
|
|
133
|
+
* sent to the client.
|
|
134
|
+
*/
|
|
135
|
+
onGrpc(callback: (arg: NapiGrpcCall) => Promise<NapiGrpcReply>): void
|
|
98
136
|
/**
|
|
99
137
|
* Configure the trusted-proxy CIDR list used by `request.ip` resolution.
|
|
100
138
|
* Must be called BEFORE `listen()`. Empty list = legacy permissive mode
|
package/src/server/Server.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* - server.errorHandler(() => import('#exceptions/handler')) — custom exception handler
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { ReamError } from '../errors/ReamError.js'
|
|
9
10
|
import type { ExceptionHandler } from '../http/Exception.js'
|
|
10
11
|
import type { HttpContext } from '../http/HttpContext.js'
|
|
11
12
|
import type { MiddlewareFunction } from '../middleware/Pipeline.js'
|
|
@@ -32,12 +33,30 @@ export type MiddlewareClassConstructor = new (...args: never[]) => MiddlewareCla
|
|
|
32
33
|
/** What server.use() and router.use() accept: lazy imports or direct functions. */
|
|
33
34
|
export type MiddlewareEntry = LazyImport<MiddlewareClassConstructor> | MiddlewareFunction
|
|
34
35
|
|
|
36
|
+
/** One unary gRPC call, as the native server hands it over. */
|
|
37
|
+
export interface GrpcCall {
|
|
38
|
+
/** `/package.Service/Method`, as it arrived. */
|
|
39
|
+
path: string
|
|
40
|
+
/** Request metadata, header names lowercased. */
|
|
41
|
+
metadata: Record<string, string>
|
|
42
|
+
/** The request message, still encoded. */
|
|
43
|
+
message: Uint8Array
|
|
44
|
+
/** Resolved client IP, by the same trusted-proxy rules as `request.ip()`. */
|
|
45
|
+
ip: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A reply message, still encoded — or a gRPC status code instead of one. */
|
|
49
|
+
export type GrpcReply = { message: Uint8Array } | { code: number; details: string }
|
|
50
|
+
|
|
51
|
+
export type GrpcHandler = (call: GrpcCall) => Promise<GrpcReply>
|
|
52
|
+
|
|
35
53
|
export class Server {
|
|
36
54
|
#router: Router
|
|
37
55
|
#serverMiddleware: MiddlewareFunction[] = []
|
|
38
56
|
#errorHandlerImporter?: LazyImport<ErrorHandlerClass>
|
|
39
57
|
#resolvedErrorHandler?: ExceptionHandler
|
|
40
58
|
#trustedProxies: string[] = []
|
|
59
|
+
#grpcHandler?: GrpcHandler
|
|
41
60
|
|
|
42
61
|
constructor(router: Router) {
|
|
43
62
|
this.#router = router
|
|
@@ -65,6 +84,36 @@ export class Server {
|
|
|
65
84
|
return this.#trustedProxies
|
|
66
85
|
}
|
|
67
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Serve gRPC on the HTTP port. Once a handler is set, a request whose
|
|
89
|
+
* content-type is `application/grpc*` is a gRPC call handed to it — ahead
|
|
90
|
+
* of the router and the middleware, which never see it. The native server
|
|
91
|
+
* still applies its rate limiter and security filter first. Without a
|
|
92
|
+
* handler such a request stays an ordinary HTTP request.
|
|
93
|
+
*
|
|
94
|
+
* No AdonisJS counterpart: it serves on Node's `http.Server`, where gRPC
|
|
95
|
+
* would attach a library of its own. Here the native server owns the
|
|
96
|
+
* socket, so the gRPC branch is part of it, and this is how a package
|
|
97
|
+
* reaches it — `@c9up/neutrino` registers its dispatcher here.
|
|
98
|
+
*
|
|
99
|
+
* One handler per server: a second one throws. Two packages both serving
|
|
100
|
+
* gRPC is a conflict to resolve, not to settle by load order.
|
|
101
|
+
*/
|
|
102
|
+
grpc(handler: GrpcHandler): this {
|
|
103
|
+
if (this.#grpcHandler) {
|
|
104
|
+
throw new ReamError('E_SERVER_GRPC_ALREADY_SET', 'A gRPC handler is already registered.', {
|
|
105
|
+
hint: 'Only one package can serve gRPC on the HTTP port.',
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
this.#grpcHandler = handler
|
|
109
|
+
return this
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** The gRPC handler, if one is set (consumed by Ignitor at boot). */
|
|
113
|
+
getGrpcHandler(): GrpcHandler | undefined {
|
|
114
|
+
return this.#grpcHandler
|
|
115
|
+
}
|
|
116
|
+
|
|
68
117
|
/**
|
|
69
118
|
* Register global server middleware.
|
|
70
119
|
* Accepts lazy imports of middleware classes (AdonisJS pattern):
|
package/src/session/Session.ts
CHANGED
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { SessionRedisClientSource } from './drivers/RedisDriver.js'
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
E_SESSION_NOT_READY,
|
|
16
|
+
E_SESSION_STORE_NOT_CONDITIONAL,
|
|
17
|
+
E_SESSION_TAGGING_NOT_SUPPORTED,
|
|
18
|
+
} from './errors.js'
|
|
15
19
|
import { ReadOnlyValuesStore } from './ReadOnlyValuesStore.js'
|
|
16
20
|
|
|
17
21
|
export interface SessionDriver {
|
|
@@ -26,8 +30,27 @@ export interface SessionDriver {
|
|
|
26
30
|
*/
|
|
27
31
|
read(sessionId: string): Promise<Record<string, unknown> | null>
|
|
28
32
|
write(sessionId: string, data: Record<string, unknown>, ttl: number): Promise<void>
|
|
33
|
+
/**
|
|
34
|
+
* Write only over an entry that is still there, in one step; `false` when it
|
|
35
|
+
* is gone, and nothing written.
|
|
36
|
+
*
|
|
37
|
+
* What `commit()` uses for a session that existed when the request came in.
|
|
38
|
+
* A request still running when the same session was logged out, rotated or
|
|
39
|
+
* destroyed everywhere would otherwise write its stale copy back — the user
|
|
40
|
+
* id included — and undo the logout. Upstream writes unconditionally and has
|
|
41
|
+
* that race; this is the named deviation that closes it.
|
|
42
|
+
*
|
|
43
|
+
* Required, and checked when the store is attached: a read followed by a
|
|
44
|
+
* write leaves the race open between the two calls.
|
|
45
|
+
*/
|
|
46
|
+
update(sessionId: string, data: Record<string, unknown>, ttl: number): Promise<boolean>
|
|
29
47
|
destroy(sessionId: string): Promise<void>
|
|
30
48
|
touch(sessionId: string, ttl: number): Promise<void>
|
|
49
|
+
/**
|
|
50
|
+
* The session lives with the client, not here: nothing on the server can
|
|
51
|
+
* delete a copy of it. Only the cookie store sets it.
|
|
52
|
+
*/
|
|
53
|
+
readonly stateless?: boolean
|
|
31
54
|
}
|
|
32
55
|
|
|
33
56
|
/** One session belonging to a tagged user (AdonisJS `TaggedSession`). */
|
|
@@ -179,6 +202,8 @@ export class Session {
|
|
|
179
202
|
#ttl = 0
|
|
180
203
|
/** Whether {@link initiate} already ran, so a second call is a no-op. */
|
|
181
204
|
#initiated = false
|
|
205
|
+
/** The entry vanished while this request ran — see {@link wasLost}. */
|
|
206
|
+
#lost = false
|
|
182
207
|
|
|
183
208
|
constructor(sessionId: string, data: Record<string, unknown> = {}) {
|
|
184
209
|
this.#sessionId = sessionId
|
|
@@ -228,6 +253,15 @@ export class Session {
|
|
|
228
253
|
return this.#regenerated
|
|
229
254
|
}
|
|
230
255
|
|
|
256
|
+
/**
|
|
257
|
+
* @internal — the stored entry was gone by the time {@link commit} ran: it
|
|
258
|
+
* was logged out, rotated or destroyed by another request meanwhile. Nothing
|
|
259
|
+
* was written, and the middleware must not hand the browser this id again.
|
|
260
|
+
*/
|
|
261
|
+
wasLost(): boolean {
|
|
262
|
+
return this.#lost
|
|
263
|
+
}
|
|
264
|
+
|
|
231
265
|
/** @internal — the id captured at request arrival; used to destroy the old driver entry post-regenerate. */
|
|
232
266
|
originalSessionId(): string {
|
|
233
267
|
return this.#originalSessionId
|
|
@@ -554,6 +588,11 @@ export class Session {
|
|
|
554
588
|
* {@link initiate} / {@link commit} then have nothing to do.
|
|
555
589
|
*/
|
|
556
590
|
setStore(driver: SessionDriver, options: { fresh: boolean; ttl: number }): void {
|
|
591
|
+
// A store written in JavaScript, or against the older contract, reaches
|
|
592
|
+
// here without the method the type requires.
|
|
593
|
+
if (typeof Reflect.get(driver, 'update') !== 'function') {
|
|
594
|
+
throw new E_SESSION_STORE_NOT_CONDITIONAL()
|
|
595
|
+
}
|
|
557
596
|
this.#driver = driver
|
|
558
597
|
this.#fresh = options.fresh
|
|
559
598
|
this.#ttl = options.ttl
|
|
@@ -600,12 +639,27 @@ export class Session {
|
|
|
600
639
|
return
|
|
601
640
|
}
|
|
602
641
|
if (this.#dirty) {
|
|
603
|
-
|
|
642
|
+
if (this.#fresh) {
|
|
643
|
+
await driver.write(this.#sessionId, this.toJSON(), this.#ttl)
|
|
644
|
+
return
|
|
645
|
+
}
|
|
646
|
+
this.#lost = !(await driver.update(this.#sessionId, this.toJSON(), this.#ttl))
|
|
604
647
|
return
|
|
605
648
|
}
|
|
606
649
|
if (!this.#fresh) await driver.touch(this.#sessionId, this.#ttl)
|
|
607
650
|
}
|
|
608
651
|
|
|
652
|
+
/**
|
|
653
|
+
* Whether ending this session on the server ends every copy of it.
|
|
654
|
+
*
|
|
655
|
+
* False under the cookie store, where the session travels with the client:
|
|
656
|
+
* a logout replaces the cookie in one browser and cannot reach a copy. What
|
|
657
|
+
* an auth guard reads to refuse signing in on a store it cannot revoke.
|
|
658
|
+
*/
|
|
659
|
+
get revocable(): boolean {
|
|
660
|
+
return this.#driver !== undefined && this.#driver.stateless !== true
|
|
661
|
+
}
|
|
662
|
+
|
|
609
663
|
/**
|
|
610
664
|
* Whether the store behind this session can tag sessions with a user
|
|
611
665
|
* (AdonisJS `supportsTagging`). False under the cookie and file drivers.
|
|
@@ -79,7 +79,7 @@ export default class SessionMiddleware {
|
|
|
79
79
|
'Cookie session driver requires a secret. Set session.secret in your config.',
|
|
80
80
|
)
|
|
81
81
|
}
|
|
82
|
-
this.#cookieDriver = new CookieDriver(config.secret)
|
|
82
|
+
this.#cookieDriver = new CookieDriver(config.secret, this.#config.cookieName)
|
|
83
83
|
this.#driver = this.#cookieDriver
|
|
84
84
|
} else if (this.#config.driver === 'memory') {
|
|
85
85
|
this.#driver = new MemoryDriver()
|
|
@@ -136,6 +136,9 @@ export default class SessionMiddleware {
|
|
|
136
136
|
|
|
137
137
|
// Cookie driver: the cookie value IS the session data (encrypted)
|
|
138
138
|
if (this.#cookieDriver) {
|
|
139
|
+
// When the data this request carries was last vouched for. See the
|
|
140
|
+
// re-emission below.
|
|
141
|
+
const readAt = Date.now()
|
|
139
142
|
const data = await this.#driver.read(sessionId ?? '')
|
|
140
143
|
sessionId = sessionId ?? generateSessionId()
|
|
141
144
|
// `null` means the cookie carried nothing readable — an empty session,
|
|
@@ -162,8 +165,20 @@ export default class SessionMiddleware {
|
|
|
162
165
|
// the cookie maxAge window slides forward (active users don't time out
|
|
163
166
|
// mid-session). Caller opts in via SessionConfig.rolling.
|
|
164
167
|
const shouldEmit = session.isDirty() || (rolling && hadIncomingCookie)
|
|
165
|
-
|
|
166
|
-
|
|
168
|
+
// The re-emitted cookie lives `maxAge` from when this request READ the
|
|
169
|
+
// session, not from its response. Counted from the response, a request
|
|
170
|
+
// that outlasted a logout re-issued the signed-in data with a full new
|
|
171
|
+
// lifetime — past the window a revocation is kept for, after which the
|
|
172
|
+
// sign-in it carried was accepted again. Counted from the read, no cookie
|
|
173
|
+
// carrying a sign-in outlives the logout by more than `maxAge`. A session
|
|
174
|
+
// regenerated during the request (a login) is new data, so it counts from
|
|
175
|
+
// now; so does a session that came in with no cookie.
|
|
176
|
+
const issuedAt = hadIncomingCookie && !session.wasRegenerated() ? readAt : Date.now()
|
|
177
|
+
const remaining = issuedAt + maxAge * 1000 - Date.now()
|
|
178
|
+
// Expired while the request ran: nothing to hand back, and the browser
|
|
179
|
+
// keeps whatever cookie it was given since.
|
|
180
|
+
if (shouldEmit && remaining > 0) {
|
|
181
|
+
const encoded = this.#cookieDriver.encode(session.toJSON(), remaining / 1000)
|
|
167
182
|
if (encoded.length > 4096) {
|
|
168
183
|
process.stderr.write(
|
|
169
184
|
`[session] Cookie session exceeds 4096 bytes (${encoded.length}). ` +
|
|
@@ -174,7 +189,7 @@ export default class SessionMiddleware {
|
|
|
174
189
|
// Already encrypted by the cookie driver; packing it again would
|
|
175
190
|
// only make the cookie bigger and change nothing.
|
|
176
191
|
encode: false,
|
|
177
|
-
maxAge: this.#config.clearWithBrowser ? undefined :
|
|
192
|
+
maxAge: this.#config.clearWithBrowser ? undefined : Math.ceil(remaining / 1000),
|
|
178
193
|
path: '/',
|
|
179
194
|
httpOnly: true,
|
|
180
195
|
sameSite: 'lax',
|
|
@@ -216,6 +231,10 @@ export default class SessionMiddleware {
|
|
|
216
231
|
// no server-side row (touch() is a no-op without a backing entry),
|
|
217
232
|
// defeats HTTP caching, and leaks a Set-Cookie to CDNs. This mirrors
|
|
218
233
|
// the cookie-driver path above (which already omits `isNew`).
|
|
234
|
+
// A session logged out or rotated by another request while this one ran
|
|
235
|
+
// was not written back (see `Session.wasLost`); handing the browser its id
|
|
236
|
+
// again would only point it at nothing, over the cookie it got since.
|
|
237
|
+
if (session.wasLost()) return
|
|
219
238
|
if (session.isDirty() || regenerated || (rolling && hadIncomingCookie)) {
|
|
220
239
|
// SIGNED, as AdonisJS signs it (`response.cookie(cookieName, id, …)`).
|
|
221
240
|
// The id is 192 bits of entropy, so it was never guessable — what the
|
|
@@ -5,23 +5,33 @@ import type { SessionDriver } from '../Session.js'
|
|
|
5
5
|
* Cookie session driver — stores session data in an encrypted cookie (AES-256-GCM).
|
|
6
6
|
* Stateless on the server. Limited by cookie size (~4KB).
|
|
7
7
|
* Requires a secret for encryption.
|
|
8
|
+
*
|
|
9
|
+
* Sealed for the cookie's name, as upstream seals every encrypted cookie, so a
|
|
10
|
+
* value encrypted for another cookie under the same key cannot be presented as
|
|
11
|
+
* the session. And sealed with its expiry — the named deviation: upstream
|
|
12
|
+
* leaves expiry to the browser's `maxAge`, which a copied cookie does not
|
|
13
|
+
* obey, so a session lifted from a browser stayed valid for as long as the key
|
|
14
|
+
* did. Here a value older than the session's lifetime opens as nothing.
|
|
8
15
|
*/
|
|
9
16
|
export class CookieDriver implements SessionDriver {
|
|
10
17
|
#signer: CookieSigner
|
|
18
|
+
readonly #purpose: string
|
|
19
|
+
readonly stateless = true
|
|
11
20
|
|
|
12
|
-
constructor(secret: string) {
|
|
21
|
+
constructor(secret: string, cookieName = 'ream_session') {
|
|
13
22
|
if (!secret) {
|
|
14
23
|
throw new Error(
|
|
15
24
|
'CookieDriver requires a secret for session encryption. Set session.secret in your config.',
|
|
16
25
|
)
|
|
17
26
|
}
|
|
18
27
|
this.#signer = new CookieSigner(secret)
|
|
28
|
+
this.#purpose = cookieName
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
async read(sessionId: string): Promise<Record<string, unknown> | null> {
|
|
22
32
|
if (!sessionId) return null
|
|
23
|
-
const decrypted = this.#signer.decrypt(sessionId)
|
|
24
|
-
if (
|
|
33
|
+
const decrypted = this.#signer.decrypt(sessionId, this.#purpose)
|
|
34
|
+
if (typeof decrypted !== 'string') return null
|
|
25
35
|
try {
|
|
26
36
|
return JSON.parse(decrypted)
|
|
27
37
|
} catch {
|
|
@@ -33,6 +43,11 @@ export class CookieDriver implements SessionDriver {
|
|
|
33
43
|
// Cookie driver writes via the response cookie — handled by middleware
|
|
34
44
|
}
|
|
35
45
|
|
|
46
|
+
async update(_sessionId: string, _data: Record<string, unknown>, _ttl: number): Promise<boolean> {
|
|
47
|
+
// Cookie driver writes via the response cookie — handled by middleware
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
|
|
36
51
|
async destroy(_sessionId: string): Promise<void> {
|
|
37
52
|
// Cookie deletion handled by middleware setting maxAge=0
|
|
38
53
|
}
|
|
@@ -41,8 +56,8 @@ export class CookieDriver implements SessionDriver {
|
|
|
41
56
|
// Cookie renewal handled by middleware
|
|
42
57
|
}
|
|
43
58
|
|
|
44
|
-
/** Encode session data for cookie storage (encrypted). */
|
|
45
|
-
encode(data: Record<string, unknown
|
|
46
|
-
return this.#signer.encrypt(JSON.stringify(data))
|
|
59
|
+
/** Encode session data for cookie storage (encrypted), valid for `ttl` seconds. */
|
|
60
|
+
encode(data: Record<string, unknown>, ttl: number): string {
|
|
61
|
+
return this.#signer.encrypt(JSON.stringify(data), ttl * 1000, this.#purpose)
|
|
47
62
|
}
|
|
48
63
|
}
|
|
@@ -143,6 +143,16 @@ export class DatabaseDriver implements SessionDriverWithTagging {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/** One UPDATE: a row deleted or expired meanwhile matches nothing. */
|
|
147
|
+
async update(sessionId: string, data: Record<string, unknown>, ttl: number): Promise<boolean> {
|
|
148
|
+
const now = Date.now()
|
|
149
|
+
const updated = await this.#db.execute(
|
|
150
|
+
`UPDATE ${this.#table} SET data = ?, expires_at = ? WHERE id = ? AND expires_at >= ?`,
|
|
151
|
+
[JSON.stringify(data), now + ttl * 1000, sessionId, now],
|
|
152
|
+
)
|
|
153
|
+
return updated.rowsAffected > 0
|
|
154
|
+
}
|
|
155
|
+
|
|
146
156
|
async destroy(sessionId: string): Promise<void> {
|
|
147
157
|
await this.#db.execute(`DELETE FROM ${this.#table} WHERE id = ?`, [sessionId])
|
|
148
158
|
}
|