@holo-js/session 0.1.3 → 0.1.5
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/dist/drivers/redis-adapter.mjs +2 -1
- package/dist/index.mjs +33 -17
- package/package.json +5 -5
|
@@ -54,7 +54,8 @@ function parseClusterNodeUrl(node, label) {
|
|
|
54
54
|
...parsed.protocol === "rediss:" ? { tls: {} } : {}
|
|
55
55
|
};
|
|
56
56
|
} catch (error) {
|
|
57
|
-
|
|
57
|
+
const message = String(error).replace(/^[A-Z][A-Za-z]*Error: /, "");
|
|
58
|
+
throw new Error(`[@holo-js/session] ${label} is invalid: ${message}`);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
function resolveClusterStartupNodes(config) {
|
package/dist/index.mjs
CHANGED
|
@@ -78,6 +78,13 @@ function parseRememberMeToken(token) {
|
|
|
78
78
|
issuedAt
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
|
+
function decodeCookiePart(value) {
|
|
82
|
+
try {
|
|
83
|
+
return decodeURIComponent(value);
|
|
84
|
+
} catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
81
88
|
function normalizeCookieOptions(options = {}) {
|
|
82
89
|
const config = getSessionRuntimeState().bindings?.config.cookie;
|
|
83
90
|
return {
|
|
@@ -103,7 +110,7 @@ function serializeCookie(name, value, options = {}) {
|
|
|
103
110
|
if (normalized.domain) {
|
|
104
111
|
attributes.push(`Domain=${normalized.domain}`);
|
|
105
112
|
}
|
|
106
|
-
if (normalized.maxAge > 0) {
|
|
113
|
+
if (normalized.maxAge > 0 || options.maxAge === 0) {
|
|
107
114
|
attributes.push(`Max-Age=${normalized.maxAge}`);
|
|
108
115
|
}
|
|
109
116
|
if (normalized.expires) {
|
|
@@ -130,8 +137,11 @@ function parseCookieHeader(header) {
|
|
|
130
137
|
if (separator <= 0) {
|
|
131
138
|
return void 0;
|
|
132
139
|
}
|
|
133
|
-
const key =
|
|
134
|
-
const value =
|
|
140
|
+
const key = decodeCookiePart(segment.slice(0, separator));
|
|
141
|
+
const value = decodeCookiePart(segment.slice(separator + 1));
|
|
142
|
+
if (key === null || value === null) {
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
135
145
|
return [key, value];
|
|
136
146
|
}).filter((entry) => !!entry);
|
|
137
147
|
return Object.freeze(Object.fromEntries(entries));
|
|
@@ -189,7 +199,7 @@ async function writeSession(record) {
|
|
|
189
199
|
const nextRecord = Object.freeze({
|
|
190
200
|
...record,
|
|
191
201
|
store: name,
|
|
192
|
-
data: Object.freeze({ ...record.data
|
|
202
|
+
data: Object.freeze({ ...record.data }),
|
|
193
203
|
createdAt: ensureDate(record.createdAt),
|
|
194
204
|
lastActivityAt: ensureDate(record.lastActivityAt),
|
|
195
205
|
expiresAt: ensureDate(record.expiresAt)
|
|
@@ -259,23 +269,20 @@ async function consumeRememberMeToken(token, options) {
|
|
|
259
269
|
}
|
|
260
270
|
const bindings = getSessionRuntimeBindings();
|
|
261
271
|
const stores = options?.store ? [getStore(options.store).store] : Object.values(bindings.stores);
|
|
262
|
-
let record = null;
|
|
263
|
-
for (const store of stores) {
|
|
264
|
-
record = await store.read(parsed.sessionId);
|
|
265
|
-
if (record) {
|
|
266
|
-
break;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
if (!record?.rememberTokenHash) {
|
|
270
|
-
return null;
|
|
271
|
-
}
|
|
272
272
|
if (parsed.issuedAt) {
|
|
273
273
|
const rememberExpiry = parsed.issuedAt + getSessionRuntimeBindings().config.rememberMeLifetime * 6e4;
|
|
274
274
|
if (rememberExpiry <= Date.now()) {
|
|
275
275
|
return null;
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
|
-
|
|
278
|
+
const tokenHash = hashRememberToken(parsed.secretPayload);
|
|
279
|
+
for (const store of stores) {
|
|
280
|
+
const record = await store.read(parsed.sessionId);
|
|
281
|
+
if (record?.rememberTokenHash === tokenHash) {
|
|
282
|
+
return record;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
279
286
|
}
|
|
280
287
|
var cookies = Object.freeze({
|
|
281
288
|
make(name, value, options) {
|
|
@@ -376,11 +383,20 @@ function deserializeRecord(raw) {
|
|
|
376
383
|
function getRecordPath(root, sessionId) {
|
|
377
384
|
return join(root, `${encodeURIComponent(sessionId)}.json`);
|
|
378
385
|
}
|
|
386
|
+
function isMissingFileError(error) {
|
|
387
|
+
return error instanceof Error && error.code === "ENOENT";
|
|
388
|
+
}
|
|
379
389
|
function createFileSessionStore(root) {
|
|
380
390
|
return {
|
|
381
391
|
async read(sessionId) {
|
|
382
|
-
|
|
383
|
-
|
|
392
|
+
try {
|
|
393
|
+
return deserializeRecord(await readFile(getRecordPath(root, sessionId), "utf8"));
|
|
394
|
+
} catch (error) {
|
|
395
|
+
if (isMissingFileError(error)) {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
throw error;
|
|
399
|
+
}
|
|
384
400
|
},
|
|
385
401
|
async write(record) {
|
|
386
402
|
await mkdir(root, { recursive: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/session",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Holo-JS Framework - session contracts, cookie helpers, and session config helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"test": "vitest --run"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@holo-js/config": "^0.1.
|
|
31
|
+
"@holo-js/config": "^0.1.5"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"ioredis": "
|
|
34
|
+
"ioredis": "^5.4.2"
|
|
35
35
|
},
|
|
36
36
|
"peerDependenciesMeta": {
|
|
37
37
|
"ioredis": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^22.10.2",
|
|
43
|
-
"ioredis": "
|
|
43
|
+
"ioredis": "^5.4.2",
|
|
44
44
|
"tsup": "^8.3.5",
|
|
45
45
|
"typescript": "^5.7.2",
|
|
46
|
-
"vitest": "^
|
|
46
|
+
"vitest": "^4.1.5"
|
|
47
47
|
}
|
|
48
48
|
}
|