h3 1.14.0 → 1.15.1

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 (3) hide show
  1. package/dist/index.cjs +36 -15
  2. package/dist/index.mjs +35 -14
  3. package/package.json +11 -12
package/dist/index.cjs CHANGED
@@ -2,13 +2,12 @@
2
2
 
3
3
  const ufo = require('ufo');
4
4
  const cookieEs = require('cookie-es');
5
- const ohash = require('ohash');
6
5
  const radix3 = require('radix3');
7
6
  const destr = require('destr');
8
7
  const defu = require('defu');
9
8
  const crypto = require('uncrypto');
10
9
  const ironWebcrypto = require('iron-webcrypto');
11
- const index = require('unenv/runtime/node/http/index');
10
+ const nodeMockHttp = require('node-mock-http');
12
11
 
13
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
14
13
 
@@ -593,24 +592,46 @@ function sanitizeStatusCode(statusCode, defaultStatusCode = 200) {
593
592
  return statusCode;
594
593
  }
595
594
 
595
+ function getDistinctCookieKey(name, opts) {
596
+ return [
597
+ name,
598
+ opts.domain || "",
599
+ opts.path || "/",
600
+ Boolean(opts.secure),
601
+ Boolean(opts.httpOnly),
602
+ Boolean(opts.sameSite)
603
+ ].join(";");
604
+ }
605
+
596
606
  function parseCookies(event) {
597
607
  return cookieEs.parse(event.node.req.headers.cookie || "");
598
608
  }
599
609
  function getCookie(event, name) {
600
610
  return parseCookies(event)[name];
601
611
  }
602
- function setCookie(event, name, value, serializeOptions) {
603
- serializeOptions = { path: "/", ...serializeOptions };
604
- const cookieStr = cookieEs.serialize(name, value, serializeOptions);
605
- let setCookies = event.node.res.getHeader("set-cookie");
606
- if (!Array.isArray(setCookies)) {
607
- setCookies = [setCookies];
612
+ function setCookie(event, name, value, serializeOptions = {}) {
613
+ if (!serializeOptions.path) {
614
+ serializeOptions = { path: "/", ...serializeOptions };
608
615
  }
609
- const _optionsHash = ohash.objectHash(serializeOptions);
610
- setCookies = setCookies.filter((cookieValue) => {
611
- return cookieValue && _optionsHash !== ohash.objectHash(cookieEs.parse(cookieValue));
612
- });
613
- event.node.res.setHeader("set-cookie", [...setCookies, cookieStr]);
616
+ const newCookie = cookieEs.serialize(name, value, serializeOptions);
617
+ const currentCookies = splitCookiesString(
618
+ event.node.res.getHeader("set-cookie")
619
+ );
620
+ if (currentCookies.length === 0) {
621
+ event.node.res.setHeader("set-cookie", newCookie);
622
+ return;
623
+ }
624
+ const newCookieKey = getDistinctCookieKey(name, serializeOptions);
625
+ event.node.res.removeHeader("set-cookie");
626
+ for (const cookie of currentCookies) {
627
+ const parsed = cookieEs.parseSetCookie(cookie);
628
+ const key = getDistinctCookieKey(parsed.name, parsed);
629
+ if (key === newCookieKey) {
630
+ continue;
631
+ }
632
+ event.node.res.appendHeader("set-cookie", cookie);
633
+ }
634
+ event.node.res.appendHeader("set-cookie", newCookie);
614
635
  }
615
636
  function deleteCookie(event, name, serializeOptions) {
616
637
  setCookie(event, name, "", {
@@ -2366,8 +2387,8 @@ async function _handlePlainRequest(app, request) {
2366
2387
  const path = request.path;
2367
2388
  const method = (request.method || "GET").toUpperCase();
2368
2389
  const headers = new Headers(request.headers);
2369
- const nodeReq = new index.IncomingMessage();
2370
- const nodeRes = new index.ServerResponse(nodeReq);
2390
+ const nodeReq = new nodeMockHttp.IncomingMessage();
2391
+ const nodeRes = new nodeMockHttp.ServerResponse(nodeReq);
2371
2392
  nodeReq.method = method;
2372
2393
  nodeReq.url = path;
2373
2394
  nodeReq.headers = Object.fromEntries(headers.entries());
package/dist/index.mjs CHANGED
@@ -1,12 +1,11 @@
1
1
  import { withoutTrailingSlash, withoutBase, getQuery as getQuery$1, decode, decodePath, withLeadingSlash, parseURL, joinURL } from 'ufo';
2
- import { parse as parse$1, serialize } from 'cookie-es';
3
- import { objectHash } from 'ohash';
2
+ import { parse as parse$1, serialize, parseSetCookie } from 'cookie-es';
4
3
  import { createRouter as createRouter$1, toRouteMatcher } from 'radix3';
5
4
  import destr from 'destr';
6
5
  import { defu } from 'defu';
7
6
  import crypto from 'uncrypto';
8
7
  import { seal, defaults, unseal } from 'iron-webcrypto';
9
- import { IncomingMessage, ServerResponse } from 'unenv/runtime/node/http/index';
8
+ import { IncomingMessage, ServerResponse } from 'node-mock-http';
10
9
 
11
10
  function useBase(base, handler) {
12
11
  base = withoutTrailingSlash(base);
@@ -586,24 +585,46 @@ function sanitizeStatusCode(statusCode, defaultStatusCode = 200) {
586
585
  return statusCode;
587
586
  }
588
587
 
588
+ function getDistinctCookieKey(name, opts) {
589
+ return [
590
+ name,
591
+ opts.domain || "",
592
+ opts.path || "/",
593
+ Boolean(opts.secure),
594
+ Boolean(opts.httpOnly),
595
+ Boolean(opts.sameSite)
596
+ ].join(";");
597
+ }
598
+
589
599
  function parseCookies(event) {
590
600
  return parse$1(event.node.req.headers.cookie || "");
591
601
  }
592
602
  function getCookie(event, name) {
593
603
  return parseCookies(event)[name];
594
604
  }
595
- function setCookie(event, name, value, serializeOptions) {
596
- serializeOptions = { path: "/", ...serializeOptions };
597
- const cookieStr = serialize(name, value, serializeOptions);
598
- let setCookies = event.node.res.getHeader("set-cookie");
599
- if (!Array.isArray(setCookies)) {
600
- setCookies = [setCookies];
605
+ function setCookie(event, name, value, serializeOptions = {}) {
606
+ if (!serializeOptions.path) {
607
+ serializeOptions = { path: "/", ...serializeOptions };
601
608
  }
602
- const _optionsHash = objectHash(serializeOptions);
603
- setCookies = setCookies.filter((cookieValue) => {
604
- return cookieValue && _optionsHash !== objectHash(parse$1(cookieValue));
605
- });
606
- event.node.res.setHeader("set-cookie", [...setCookies, cookieStr]);
609
+ const newCookie = serialize(name, value, serializeOptions);
610
+ const currentCookies = splitCookiesString(
611
+ event.node.res.getHeader("set-cookie")
612
+ );
613
+ if (currentCookies.length === 0) {
614
+ event.node.res.setHeader("set-cookie", newCookie);
615
+ return;
616
+ }
617
+ const newCookieKey = getDistinctCookieKey(name, serializeOptions);
618
+ event.node.res.removeHeader("set-cookie");
619
+ for (const cookie of currentCookies) {
620
+ const parsed = parseSetCookie(cookie);
621
+ const key = getDistinctCookieKey(parsed.name, parsed);
622
+ if (key === newCookieKey) {
623
+ continue;
624
+ }
625
+ event.node.res.appendHeader("set-cookie", cookie);
626
+ }
627
+ event.node.res.appendHeader("set-cookie", newCookie);
607
628
  }
608
629
  function deleteCookie(event, name, serializeOptions) {
609
630
  setCookie(event, name, "", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h3",
3
- "version": "1.14.0",
3
+ "version": "1.15.1",
4
4
  "description": "Minimal H(TTP) framework built for high performance and portability.",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
@@ -30,35 +30,34 @@
30
30
  "test": "pnpm lint && vitest --run --coverage"
31
31
  },
32
32
  "resolutions": {
33
- "h3": "link:."
33
+ "h3": "^1.14.0"
34
34
  },
35
35
  "dependencies": {
36
36
  "cookie-es": "^1.2.2",
37
- "crossws": "^0.3.2",
37
+ "crossws": "^0.3.3",
38
38
  "defu": "^6.1.4",
39
39
  "destr": "^2.0.3",
40
40
  "iron-webcrypto": "^1.2.1",
41
- "ohash": "^1.1.4",
41
+ "node-mock-http": "^1.0.0",
42
42
  "radix3": "^1.1.2",
43
43
  "ufo": "^1.5.4",
44
- "uncrypto": "^0.1.3",
45
- "unenv": "^1.10.0"
44
+ "uncrypto": "^0.1.3"
46
45
  },
47
46
  "devDependencies": {
48
47
  "0x": "^5.8.0",
49
48
  "@types/express": "^5.0.0",
50
- "@types/node": "^22.10.7",
49
+ "@types/node": "^22.13.1",
51
50
  "@types/supertest": "^6.0.2",
52
- "@vitest/coverage-v8": "^3.0.3",
51
+ "@vitest/coverage-v8": "^3.0.5",
53
52
  "autocannon": "^8.0.0",
54
53
  "automd": "^0.3.12",
55
54
  "changelogen": "^0.5.7",
56
55
  "connect": "^3.7.0",
57
- "eslint": "^9.18.0",
56
+ "eslint": "^9.19.0",
58
57
  "eslint-config-unjs": "^0.4.2",
59
58
  "express": "^4.21.2",
60
59
  "get-port": "^7.1.0",
61
- "h3": "^1.13.1",
60
+ "h3": "^1.14.0",
62
61
  "jiti": "^2.4.2",
63
62
  "listhen": "^1.9.0",
64
63
  "node-fetch-native": "^1.6.6",
@@ -69,8 +68,8 @@
69
68
  "typescript": "^5.7.3",
70
69
  "unbuild": "^3.3.1",
71
70
  "undici": "^7.3.0",
72
- "vitest": "^3.0.3",
71
+ "vitest": "^3.0.5",
73
72
  "zod": "^3.24.1"
74
73
  },
75
- "packageManager": "pnpm@9.15.4"
74
+ "packageManager": "pnpm@10.2.0"
76
75
  }