Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
bf9eb4b
fix(adapter-node): validate ORIGIN env var at startup (#14978)
KiraPC Dec 9, 2025
62bbeb1
add changeset
KiraPC Dec 9, 2025
61578e1
chore(deps): update pnpm to v10.25.0 (#15043)
renovate[bot] Dec 9, 2025
2cfcfac
chore: Test remote functions with full-async setup (#15033)
elliott-with-the-longest-name-on-github Dec 13, 2025
475ea75
chore(deps): update actions/upload-artifact action to v6 (#15057)
renovate[bot] Dec 13, 2025
8e0aea3
chore(deps): update pnpm to v10.26.0 (#15065)
renovate[bot] Dec 16, 2025
5fed053
fix: make typescript an optional peer dependency (#15074)
cierny Dec 24, 2025
a01df4c
docs: update Wrangler command for Cloudflare Workers testing (#15077)
teemingc Dec 24, 2025
de8051b
chore(deps): update pnpm to v10.26.2 (#15072)
renovate[bot] Dec 24, 2025
46f2eaf
docs: clarify remote function import (#15082)
Greenheart Dec 24, 2025
966d33c
docs: update description for `static` folder (#15087)
sacrosanctic Dec 24, 2025
0f23304
chore: upgrade Playwright (#15089)
elliott-with-the-longest-name-on-github Dec 24, 2025
5c385cf
chore: upgrade jws (#15095)
benmccann Dec 25, 2025
307588e
chore: upgrade js-yaml (#15096)
benmccann Dec 25, 2025
970bbbe
feat: expose `waitUntil` also for serverless runtime & add docs (#14725)
Fruup Jan 1, 2026
8c952a7
chore(deps): update vitest monorepo to v4 (major) (#14789)
renovate[bot] Jan 3, 2026
89ac4a0
fix: avoid overridden Vite config warning with Vitest 4 (#15121)
Copilot Jan 3, 2026
f9cae31
docs: remove `$lib` path customization (#14812)
hyunbinseo Jan 5, 2026
8923a48
fix: use hasOwn check when deep-setting object properties (#15127)
Rich-Harris Jan 5, 2026
cf29465
Version Packages (#15091)
github-actions[bot] Jan 5, 2026
52b705d
chore: upgrade to pnpm 10.27.0 (#15128)
benmccann Jan 5, 2026
2b84bdf
fix: add `has(name, value)` overload for URLSearchParams (#15076)
RoryDuncan Jan 6, 2026
cdf7224
Merge branch 'main' into 14978
teemingc Jan 6, 2026
acab47d
Apply suggestions from code review
KiraPC Jan 6, 2026
0e5245d
fix: support instrumentation for `vite preview` (#15105)
aloisklink Jan 6, 2026
3e3d1e4
chore: run pnpm dedupe (#15134)
benmccann Jan 8, 2026
f485392
fix: add `experimental.forkPreloads` flag (#15135)
elliott-with-the-longest-name-on-github Jan 9, 2026
08cf928
chore: fix prettier ignoring source code in with build in the name (#…
teemingc Jan 9, 2026
3ab2cbe
Version Packages (#15129)
github-actions[bot] Jan 9, 2026
1f4f0c6
breaking: remove `buttonProps` from experimental remote form function…
dummdidumm Jan 9, 2026
b330e2b
Revert "breaking: remove `buttonProps` from experimental remote form …
Rich-Harris Jan 9, 2026
694612c
feat: add env vars for keepAliveTimeout and headersTimeout (#15125)
theandrew168 Jan 9, 2026
e29eb47
chore: Add AGENTS.md, symlink copilot instructions (#15145)
elliott-with-the-longest-name-on-github Jan 9, 2026
32bdea3
Version Packages (#15146)
github-actions[bot] Jan 12, 2026
bbbb29a
chore: remove unused is_http_method helper and method set to (#15152)
teemingc Jan 12, 2026
881d2b6
fix: avoid overriding Vite default `base` when running Vitest 4 (#14866)
jycouet Jan 14, 2026
049fd1a
docs: remove old references about `invalid.fieldName(...)` for issues…
Copilot Jan 14, 2026
5e09a24
fix: await initialization on every request to prevent race condition …
thomastheyoung Jan 14, 2026
f6a45b9
chore: Upgrade devalue (#15172)
elliott-with-the-longest-name-on-github Jan 15, 2026
35c1aed
Merge commit from fork
teemingc Jan 15, 2026
963d1a9
Merge commit from fork
elliott-with-the-longest-name-on-github Jan 15, 2026
0d4a63d
chore: Upgrade svelte (#15173)
elliott-with-the-longest-name-on-github Jan 15, 2026
6ac9f90
lockfile
elliott-with-the-longest-name-on-github Jan 15, 2026
470e55d
Version Packages (#15162)
github-actions[bot] Jan 15, 2026
d9c2b72
chore: fix lint errors (#15174)
teemingc Jan 16, 2026
20280a1
chore: replace `netlify-cli` with `@netlify/dev` (#14686)
benmccann Jan 16, 2026
e323b79
chore: update suggestion message (#15165)
teemingc Jan 16, 2026
7b98cde
chore: upgrade dependencies (#15176)
benmccann Jan 16, 2026
d3cacea
chore: prevent two concurrent running release workflows (#15160)
Conduitry Jan 16, 2026
16e0b6c
Revert "Revert "breaking: remove `buttonProps` from experimental remo…
Rich-Harris Jan 16, 2026
bda98fe
fix: compatibility with vite-plugin-svelte@7 (#15179)
dominikg Jan 17, 2026
d57f048
Version Packages (#15177)
github-actions[bot] Jan 17, 2026
d0da468
chore: docs update on `vitePreprocess` (#15185)
jycouet Jan 20, 2026
f9e494e
fix: don't send "Vary: Accept-Encoding" header when precompress=false…
theandrew168 Jan 20, 2026
797cf17
fix: include `hooks.server` and `hooks.universal` as entrypoints to g…
elliott-with-the-longest-name-on-github Jan 20, 2026
3eb4f13
fix: Skip failing tests on async (#15189)
elliott-with-the-longest-name-on-github Jan 20, 2026
a02215e
fix: preload links if href changes (#15191)
PatrickG Jan 21, 2026
9703efa
docs: update cloudflare adapter package description and misc (#15164)
teemingc Jan 21, 2026
ebfbef0
fix: ensure injected paths are prefixed with `./` (#15163)
teemingc Jan 21, 2026
22f67b5
docs: convert `picklist` options to a `const` array (#14616)
hyunbinseo Jan 21, 2026
54fe21e
fix: prevent isr routes from handling remote function calls (#15085) …
arichardsmith Jan 22, 2026
6ed4708
fix: improve `fields` type for generic components (#14974)
sillvva Jan 22, 2026
a0fb82c
Version Packages (#15186)
github-actions[bot] Jan 23, 2026
3569038
chore: upgrade dependencies (#15201)
benmccann Jan 23, 2026
81e4e62
chore(deps): update dependency @netlify/edge-functions to v3 (#14772)
renovate[bot] Jan 24, 2026
13fbba2
chore: add closing angle bracket (#15205)
benmccann Jan 26, 2026
e0d593b
fix: reexport browser/dev from esm-env (#15206)
Rich-Harris Jan 26, 2026
62741e3
chore: upgrade netlify/dev library (#15210)
benmccann Jan 26, 2026
d0be2a6
fix: ensure CSS URLs are correct when inlining client stylesheets (#1…
teemingc Jan 27, 2026
374d859
fix: use validated args in batch resolver (#15215)
Rich-Harris Jan 27, 2026
e92257b
chore(deps): update dependency set-cookie-parser to v3 (#15155)
renovate[bot] Jan 27, 2026
f47cb08
fix: only match rest params with matchers when the matcher matches (#…
elliott-with-the-longest-name-on-github Jan 28, 2026
8024a02
chore: restore previous explicit version for magic-string dependency …
dominikg Jan 28, 2026
327257b
fix: emit script CSP nonces when is present if is also present (#15…
elliott-with-the-longest-name-on-github Jan 28, 2026
6ad0682
Update pnpm-workspace.yaml (#15218)
teemingc Jan 28, 2026
393a5e0
fix(kit): properly handle percent-encoded anchors during prerendering…
GauBen Jan 31, 2026
275c6dd
feat: export type Picture in enhanced-img (#15225)
blt-r Jan 31, 2026
677d56e
Merge remote-tracking branch 'origin/main' into 14978
KiraPC Feb 1, 2026
ac2a038
handle pr review comments
KiraPC Feb 1, 2026
6299b1d
fix: address PR review comments
KiraPC Feb 4, 2026
03cb548
Merge branch 'main' into 14978
KiraPC Feb 5, 2026
909c5e3
chore: remove obsolete changesets consumed by releases
KiraPC Feb 5, 2026
180b478
Merge branch 'main' into 14978
teemingc Feb 5, 2026
c543c10
Apply suggestion from @elliott-with-the-longest-name-on-github
teemingc Feb 5, 2026
c1c1130
cleanup
teemingc Feb 5, 2026
52b796c
silly github
teemingc Feb 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dry-hornets-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-node': patch
---

fix: validate `ORIGIN` env var at startup
6 changes: 4 additions & 2 deletions packages/adapter-node/src/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import { getRequest, setResponse, createReadableStream } from '@sveltejs/kit/nod
import { Server } from 'SERVER';
import { manifest, prerendered, base } from 'MANIFEST';
import { env } from 'ENV';
import { parse_as_bytes } from '../utils.js';
import { parse_as_bytes, parse_origin } from '../utils.js';

/* global ENV_PREFIX */
/* global PRECOMPRESS */

const server = new Server(manifest);

const origin = env('ORIGIN', undefined);
// parse_origin validates ORIGIN and throws descriptive errors for invalid values
const origin = parse_origin(env('ORIGIN', undefined));

const xff_depth = parseInt(env('XFF_DEPTH', '1'));
const address_header = env('ADDRESS_HEADER', '').toLowerCase();
const protocol_header = env('PROTOCOL_HEADER', '').toLowerCase();
Expand Down
35 changes: 34 additions & 1 deletion packages/adapter-node/tests/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, test, describe } from 'vitest';
import { parse_as_bytes } from '../utils.js';
import { parse_as_bytes, parse_origin } from '../utils.js';

describe('parse_as_bytes', () => {
test.each([
Expand All @@ -14,3 +14,36 @@ describe('parse_as_bytes', () => {
expect(actual, `Testing input '${input}'`).toBe(expected);
});
});

describe('parse_origin', () => {
test.each([
['http://localhost:3000', 'http://localhost:3000'],
['https://example.com', 'https://example.com'],
['http://192.168.1.1:8080', 'http://192.168.1.1:8080'],
['https://my-site.com', 'https://my-site.com'],
['http://localhost', 'http://localhost'],
// Default ports are normalized by URL.origin per WHATWG URL standard
['https://example.com:443', 'https://example.com'],
['http://example.com:80', 'http://example.com'],
[undefined, undefined]
] as const)('normalizes %s to %s', (input, expected) => {
expect(parse_origin(input)).toBe(expected);
});

test.each([
['http://localhost:3000/path', 'http://localhost:3000'],
['http://localhost:3000?query=1', 'http://localhost:3000'],
['http://localhost:3000#hash', 'http://localhost:3000'],
['https://example.com/path/to/page', 'https://example.com'],
['https://example.com:443/path?query=1#hash', 'https://example.com']
] as const)('strips path/query/hash from %s to get %s', (input, expected) => {
expect(parse_origin(input)).toBe(expected);
});

test.each(['localhost:3000', 'example.com', '', ' ', 'ftp://localhost:3000'] as const)(
'throws error for invalid origin: %s',
(input) => {
expect(() => parse_origin(input)).toThrow('Invalid ORIGIN');
}
);
});
37 changes: 37 additions & 0 deletions packages/adapter-node/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,40 @@ export function parse_as_bytes(value) {
}[value[value.length - 1]?.toUpperCase()] ?? 1;
return Number(multiplier != 1 ? value.substring(0, value.length - 1) : value) * multiplier;
}

/**
* Parses and validates an origin URL.
*
* @param {string | undefined} value - Origin URL with http:// or https:// protocol
* @returns {string | undefined} The validated origin, or undefined if value is undefined
* @throws {Error} If value is provided but invalid
*/
export function parse_origin(value) {
if (value === undefined) {
return undefined;
}

const trimmed = value.trim();

let url;
try {
url = new URL(trimmed);
} catch (error) {
throw new Error(
`Invalid ORIGIN: '${trimmed}'. ` +
`ORIGIN must be a valid URL with http:// or https:// protocol. ` +
`For example: 'http://localhost:3000' or 'https://my.site'`,
{ cause: error }
);
}

if (url.protocol !== 'http:' && url.protocol !== 'https:') {
throw new Error(
`Invalid ORIGIN: '${trimmed}'. ` +
`Only http:// and https:// protocols are supported. ` +
`Received protocol: ${url.protocol}`
);
}

return url.origin;
}
Loading