@holo-js/session 0.1.4 → 0.1.6

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.
@@ -54,7 +54,8 @@ function parseClusterNodeUrl(node, label) {
54
54
  ...parsed.protocol === "rediss:" ? { tls: {} } : {}
55
55
  };
56
56
  } catch (error) {
57
- throw new Error(`[@holo-js/session] ${label} is invalid: ${error instanceof Error ? error.message : String(error)}`);
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 = decodeURIComponent(segment.slice(0, separator));
134
- const value = decodeURIComponent(segment.slice(separator + 1));
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
- return record.rememberTokenHash === hashRememberToken(parsed.secretPayload) ? record : null;
278
+ const tokenHash = hashRememberToken(parsed.secretPayload);
279
+ for (const store of stores) {
280
+ const record = await readRecordFromStore(parsed.sessionId, store);
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
- const contents = await readFile(getRecordPath(root, sessionId), "utf8").catch(() => void 0);
383
- return contents ? deserializeRecord(contents) : null;
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.4",
3
+ "version": "0.1.6",
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.4"
31
+ "@holo-js/config": "^0.1.6"
32
32
  },
33
33
  "peerDependencies": {
34
- "ioredis": "catalog:"
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": "catalog:",
43
+ "ioredis": "^5.4.2",
44
44
  "tsup": "^8.3.5",
45
45
  "typescript": "^5.7.2",
46
- "vitest": "^2.1.8"
46
+ "vitest": "^4.1.5"
47
47
  }
48
48
  }