@torpor/build 1.0.0 → 1.0.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 (174) hide show
  1. package/dist/{flattenHeaders-C_YYLdOq.mjs → Server-BnjLJleZ.mjs} +2 -12
  2. package/dist/Server-BnjLJleZ.mjs.map +1 -0
  3. package/dist/{Server-C_IKav_e.d.mts → Server-Cler2w5O.d.mts} +3 -48
  4. package/dist/Server-Cler2w5O.d.mts.map +1 -0
  5. package/dist/ServerEvent-CTx3Q-hk.d.mts +48 -0
  6. package/dist/ServerEvent-CTx3Q-hk.d.mts.map +1 -0
  7. package/dist/{Site-CMa153FA.d.mts → Site-CE0_o5Ci.d.mts} +3 -2
  8. package/dist/Site-CE0_o5Ci.d.mts.map +1 -0
  9. package/dist/bin/index.js +1 -1
  10. package/dist/clientEntry.d.mts +1 -0
  11. package/dist/clientEntry.mjs +59 -0
  12. package/dist/clientEntry.mjs.map +1 -0
  13. package/dist/clientEntryDev.d.mts +1 -0
  14. package/dist/clientEntryDev.mjs +7 -0
  15. package/dist/clientEntryDev.mjs.map +1 -0
  16. package/dist/dev.d.mts +3 -0
  17. package/dist/dev.mjs +3 -0
  18. package/dist/endpoint-EULRGCKA.mjs +108 -0
  19. package/dist/endpoint-EULRGCKA.mjs.map +1 -0
  20. package/dist/flattenHeaders-DM5qsSqO.mjs +13 -0
  21. package/dist/flattenHeaders-DM5qsSqO.mjs.map +1 -0
  22. package/dist/index.d.mts +1 -1
  23. package/dist/load-BntzvmwL.mjs +228 -0
  24. package/dist/load-BntzvmwL.mjs.map +1 -0
  25. package/dist/nav.mjs +1 -225
  26. package/dist/nav.mjs.map +1 -1
  27. package/dist/openapi.d.mts +1 -1
  28. package/dist/run.d.mts +1 -1
  29. package/dist/run.d.mts.map +1 -1
  30. package/dist/run.mjs +1 -1
  31. package/dist/{runOpenApi-BUi1RH1l.mjs → runOpenApi-DlOgF2Il.mjs} +54 -16
  32. package/dist/runOpenApi-DlOgF2Il.mjs.map +1 -0
  33. package/dist/server/Server.d.mts +2 -0
  34. package/dist/server/Server.mjs +2 -0
  35. package/dist/server.d.mts +2 -1
  36. package/dist/server.d.mts.map +1 -1
  37. package/dist/server.mjs +2 -1
  38. package/dist/server.mjs.map +1 -1
  39. package/dist/serverEntry-1qY3wZig.mjs +351 -0
  40. package/dist/serverEntry-1qY3wZig.mjs.map +1 -0
  41. package/dist/serverEntry-BAO8m03V.d.mts +6 -0
  42. package/dist/serverEntry-BAO8m03V.d.mts.map +1 -0
  43. package/dist/serverEntry.d.mts +2 -0
  44. package/dist/serverEntry.mjs +2 -0
  45. package/dist/test.d.mts +2 -2
  46. package/dist/test.mjs +2 -104
  47. package/dist/test.mjs.map +1 -1
  48. package/package.json +9 -8
  49. package/dist/Server-C_IKav_e.d.mts.map +0 -1
  50. package/dist/Site-CMa153FA.d.mts.map +0 -1
  51. package/dist/flattenHeaders-C_YYLdOq.mjs.map +0 -1
  52. package/dist/runOpenApi-BUi1RH1l.mjs.map +0 -1
  53. package/src/bin/index.ts +0 -22
  54. package/src/dev.ts +0 -10
  55. package/src/form/formDataToRecord.ts +0 -23
  56. package/src/form/readForm.ts +0 -71
  57. package/src/form.ts +0 -4
  58. package/src/index.ts +0 -82
  59. package/src/nav/api.test-d.ts +0 -79
  60. package/src/nav/api.ts +0 -104
  61. package/src/nav/formSubmit.ts +0 -70
  62. package/src/nav/load.ts +0 -9
  63. package/src/nav/loadData.ts +0 -134
  64. package/src/nav/navigate.ts +0 -189
  65. package/src/nav/reload.ts +0 -9
  66. package/src/nav/route.ts +0 -38
  67. package/src/nav.ts +0 -6
  68. package/src/openapi/docsHtml.ts +0 -25
  69. package/src/openapi/document.ts +0 -154
  70. package/src/openapi/plugin.ts +0 -78
  71. package/src/openapi/types.ts +0 -82
  72. package/src/openapi.ts +0 -14
  73. package/src/response/TypedResponse.ts +0 -17
  74. package/src/response/badRequest.ts +0 -31
  75. package/src/response/created.ts +0 -31
  76. package/src/response/forbidden.ts +0 -21
  77. package/src/response/found.ts +0 -30
  78. package/src/response/methodNotAllowed.ts +0 -18
  79. package/src/response/movedPermanently.ts +0 -25
  80. package/src/response/notFound.ts +0 -24
  81. package/src/response/notModified.ts +0 -34
  82. package/src/response/ok.ts +0 -38
  83. package/src/response/permanentRedirect.ts +0 -30
  84. package/src/response/response.ts +0 -22
  85. package/src/response/seeOther.ts +0 -19
  86. package/src/response/serverError.ts +0 -24
  87. package/src/response/temporaryRedirect.ts +0 -31
  88. package/src/response/transfer.ts +0 -14
  89. package/src/response/unauthorized.ts +0 -21
  90. package/src/response/unprocessable.ts +0 -30
  91. package/src/response.ts +0 -37
  92. package/src/run/depCache.ts +0 -175
  93. package/src/run/devPlugin.ts +0 -128
  94. package/src/run/prepareTemplate.ts +0 -42
  95. package/src/run/run.ts +0 -86
  96. package/src/run/runBuild.ts +0 -128
  97. package/src/run/runDev.ts +0 -177
  98. package/src/run/runOpenApi.ts +0 -52
  99. package/src/run/runPreview.ts +0 -84
  100. package/src/run/staleTorpCopies.ts +0 -100
  101. package/src/run.ts +0 -7
  102. package/src/schema.ts +0 -7
  103. package/src/server/CookieHelper.ts +0 -46
  104. package/src/server/HeaderHelper.ts +0 -25
  105. package/src/server/Server.ts +0 -168
  106. package/src/server/ServerEvent.ts +0 -62
  107. package/src/server/connect/connectMiddleware.ts +0 -85
  108. package/src/server/connect/flattenHeaders.ts +0 -22
  109. package/src/server/connect/nodeMessageToNodeResponse.ts +0 -89
  110. package/src/server/connect/requestToNodeMessage.ts +0 -29
  111. package/src/server/contentType.ts +0 -85
  112. package/src/server/types/HttpMethod.ts +0 -12
  113. package/src/server/types/MiddlewareFunction.ts +0 -22
  114. package/src/server/types/ServerFunction.ts +0 -7
  115. package/src/server.ts +0 -7
  116. package/src/site/Router.ts +0 -175
  117. package/src/site/Site.ts +0 -388
  118. package/src/site/checkLayoutSlots.ts +0 -114
  119. package/src/site/checkRoutes.ts +0 -435
  120. package/src/site/clientEntry.ts +0 -121
  121. package/src/site/clientEntryDev.ts +0 -3
  122. package/src/site/defaultAdapter.ts +0 -11
  123. package/src/site/layoutSlots.ts +0 -53
  124. package/src/site/manifest.ts +0 -173
  125. package/src/site/serverEntry.ts +0 -648
  126. package/src/state/$page.ts +0 -25
  127. package/src/state/$serverPage.ts +0 -22
  128. package/src/state/client.ts +0 -15
  129. package/src/state.ts +0 -3
  130. package/src/test/runTest.ts +0 -538
  131. package/src/test.ts +0 -3
  132. package/src/types/Adapter.ts +0 -20
  133. package/src/types/ClientState.ts +0 -8
  134. package/src/types/InternalState.ts +0 -7
  135. package/src/types/Jsonify.ts +0 -20
  136. package/src/types/LayoutHandler.ts +0 -5
  137. package/src/types/LayoutPath.ts +0 -10
  138. package/src/types/ManifestRoute.ts +0 -6
  139. package/src/types/PageData.test-d.ts +0 -136
  140. package/src/types/PageData.ts +0 -35
  141. package/src/types/PageEndPoint.ts +0 -55
  142. package/src/types/PageForm.test-d.ts +0 -78
  143. package/src/types/PageForm.ts +0 -29
  144. package/src/types/PageLoadEvent.ts +0 -26
  145. package/src/types/PageLoadReturn.ts +0 -13
  146. package/src/types/PageProps.ts +0 -14
  147. package/src/types/PageServerAction.ts +0 -13
  148. package/src/types/PageServerEndPoint.test-d.ts +0 -105
  149. package/src/types/PageServerEndPoint.ts +0 -110
  150. package/src/types/PageServerLoad.ts +0 -15
  151. package/src/types/PageState.ts +0 -8
  152. package/src/types/ParseRouteParams.test-d.ts +0 -84
  153. package/src/types/ParseRouteParams.ts +0 -64
  154. package/src/types/Route.ts +0 -30
  155. package/src/types/RouteHandler.ts +0 -23
  156. package/src/types/RouteLayoutHandler.ts +0 -5
  157. package/src/types/RouteMatchResult.ts +0 -7
  158. package/src/types/RouteType.ts +0 -19
  159. package/src/types/ServerEndPoint.test-d.ts +0 -77
  160. package/src/types/ServerEndPoint.ts +0 -169
  161. package/src/types/ServerHook.ts +0 -18
  162. package/src/types/ServerLoadEvent.ts +0 -82
  163. package/src/types/ServerRequest.ts +0 -15
  164. package/src/types/SitePlugin.ts +0 -24
  165. package/src/types/StandardSchema.ts +0 -109
  166. package/src/utils/pathToRegex.ts +0 -17
  167. package/src/utils/pathTrie.ts +0 -182
  168. package/src/utils/searchParamsToRecord.ts +0 -18
  169. package/src/utils/torporPackages.ts +0 -150
  170. package/src/utils/tsconfigAliases.ts +0 -90
  171. package/src/validation/ValidationError.ts +0 -18
  172. package/src/validation/endpoint.ts +0 -83
  173. package/src/validation/validate.ts +0 -26
  174. package/src/vite-env.d.ts +0 -2
@@ -1,109 +0,0 @@
1
- /**
2
- * The Standard Schema interface, per the spec at https://standardschema.dev.
3
- *
4
- * It is implemented by Zod, Valibot, ArkType, Effect Schema and others, so
5
- * endpoints can validate request bodies with whichever library they prefer
6
- * without this package depending on any of them.
7
- */
8
- export interface StandardSchemaV1<Input = unknown, Output = Input> {
9
- readonly "~standard": StandardSchemaV1.Props<Input, Output>;
10
- }
11
-
12
- export declare namespace StandardSchemaV1 {
13
- /** The Standard Schema props interface. */
14
- export interface Props<Input = unknown, Output = Input> {
15
- /**
16
- * The Standard Schema version.
17
- */
18
- readonly version: 1;
19
- /**
20
- * The vendor name of the schema library.
21
- */
22
- readonly vendor: string;
23
- /**
24
- * Validates unknown input values and returns the parsed output.
25
- */
26
- readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
27
- /**
28
- * Inferred types associated with the schema.
29
- */
30
- readonly types?: Types<Input, Output> | undefined;
31
- }
32
-
33
- /**
34
- * The result of a validation: a success with a value, or a failure with
35
- * issues.
36
- */
37
- export type Result<Output> = SuccessResult<Output> | FailureResult;
38
-
39
- /**
40
- * The result of a successful validation.
41
- */
42
- export interface SuccessResult<Output> {
43
- /**
44
- * The typed output value.
45
- */
46
- readonly value: Output;
47
- /**
48
- * Only set when there are issues, so a success can be tested with
49
- * `if (result.issues)`.
50
- */
51
- readonly issues?: undefined;
52
- }
53
-
54
- /**
55
- * The result of a failed validation.
56
- */
57
- export interface FailureResult {
58
- /**
59
- * The issues detected during validation.
60
- */
61
- readonly issues: ReadonlyArray<Issue>;
62
- }
63
-
64
- /**
65
- * An issue encountered during validation.
66
- */
67
- export interface Issue {
68
- /**
69
- * The error message.
70
- */
71
- readonly message: string;
72
- /**
73
- * The path to the property the issue belongs to.
74
- */
75
- readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
76
- }
77
-
78
- /**
79
- * A segment of the path to an issue.
80
- */
81
- export interface PathSegment {
82
- /**
83
- * The key of the property.
84
- */
85
- readonly key: PropertyKey;
86
- }
87
-
88
- /**
89
- * The input and output types inferred from a schema.
90
- */
91
- export interface Types<Input = unknown, Output = Input> {
92
- readonly input: Input;
93
- readonly output: Output;
94
- }
95
-
96
- /**
97
- * Infers the input type of a schema.
98
- */
99
- export type InferInput<Schema extends StandardSchemaV1> = NonNullable<
100
- Schema["~standard"]["types"]
101
- >["input"];
102
-
103
- /**
104
- * Infers the output type of a schema.
105
- */
106
- export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<
107
- Schema["~standard"]["types"]
108
- >["output"];
109
- }
@@ -1,17 +0,0 @@
1
- export default function pathToRegex(path: string): RegExp {
2
- const pattern =
3
- path
4
- .split("/")
5
- // Replace `[slug]` (and `[...splat]`) with named capture groups
6
- .map((p) => {
7
- return p.replace(/\[(\.\.\.)?([^/]+?)\]/, (_, splat, name) =>
8
- splat ? `(?<${name as string}>.+)` : `(?<${name as string}>[^\\/]+?)`,
9
- );
10
- })
11
- .join("\\/")
12
- // Replace globs with regex syntax
13
- .replaceAll("*", ".*") +
14
- // Ignore trailing slashes -- `/path` should be treated the same as `/path/`
15
- "/*";
16
- return new RegExp(`^${pattern}/*$`);
17
- }
@@ -1,182 +0,0 @@
1
- /**
2
- * A simple trie router for path patterns.
3
- *
4
- * Pattern segments:
5
- * - `posts` — static segment
6
- * - `[id]` — matches one non-empty path segment, captured as `params.id`
7
- * - `[...path]` — matches the rest of the path (at least one segment),
8
- * captured as `params.path`
9
- * - `*` — matches the rest of the path (possibly nothing), not captured
10
- * - `*.css` — a segment with an embedded `*` matches one path segment
11
- *
12
- * `*` and `[...]` must be the last segment of a pattern. Matching priority at
13
- * each level is static, then param, then glob, then rest. Trailing slashes are
14
- * ignored, so `/posts` and `/posts/` match the same route.
15
- */
16
- export default class PathTrie<T> {
17
- #root = new TrieNode<T>();
18
-
19
- /**
20
- * Registers a value at a path pattern. The first registration of an exact
21
- * pattern wins, matching the previous regex-scanning router.
22
- */
23
- insert(pattern: string, value: T): void {
24
- let node = this.#root;
25
- const segments = splitPath(pattern);
26
- for (let i = 0; i < segments.length; i++) {
27
- const segment = segments[i];
28
- if (segment === "*") {
29
- if (i !== segments.length - 1) {
30
- throw new Error(`The '*' wildcard must be the last segment of a path: ${pattern}`);
31
- }
32
- node.rest ??= { name: undefined, allowEmpty: true, child: new TrieNode() };
33
- node = node.rest.child;
34
- } else if (segment.startsWith("[...") && segment.endsWith("]")) {
35
- if (i !== segments.length - 1) {
36
- throw new Error(`The '[...x]' splat must be the last segment of a path: ${pattern}`);
37
- }
38
- node.rest ??= {
39
- name: segment.slice(4, -1),
40
- allowEmpty: false,
41
- child: new TrieNode(),
42
- };
43
- node = node.rest.child;
44
- } else if (segment.startsWith("[") && segment.endsWith("]")) {
45
- node.param ??= { name: segment.slice(1, -1), child: new TrieNode() };
46
- node = node.param.child;
47
- } else if (segment.includes("*")) {
48
- node.glob ??= { regex: globToRegex(segment), child: new TrieNode() };
49
- node = node.glob.child;
50
- } else {
51
- node.static ??= new Map();
52
- let child = node.static.get(segment);
53
- if (!child) {
54
- child = new TrieNode();
55
- node.static.set(segment, child);
56
- }
57
- node = child;
58
- }
59
- }
60
- node.value ??= value;
61
- }
62
-
63
- /**
64
- * Matches a request path against the trie. Returns the registered value
65
- * and any captured params, or undefined when nothing matches.
66
- */
67
- match(path: string): PathMatch<T> | undefined {
68
- // Trailing slashes are optional: `/posts/` matches `/posts`. Whether
69
- // there WAS a trailing separator still matters for a trailing bare
70
- // `*`, which requires one (e.g. `/assets/*` matches `/assets/` but
71
- // not `/assets`)
72
- let trailingSlash = path === "/";
73
- while (path.length > 1 && path.endsWith("/")) {
74
- path = path.slice(0, -1);
75
- trailingSlash = true;
76
- }
77
- const segments = path === "/" ? [] : splitPath(path);
78
- return this.#matchNode(this.#root, segments, 0, {}, trailingSlash);
79
- }
80
-
81
- #matchNode(
82
- node: TrieNode<T>,
83
- segments: string[],
84
- i: number,
85
- params: Record<string, string>,
86
- trailingSlash: boolean,
87
- ): PathMatch<T> | undefined {
88
- if (i === segments.length) {
89
- if (node.value !== undefined) {
90
- return { value: node.value, params: orUndefined(params) };
91
- }
92
- // A trailing bare `*` also matches nothing, when the path ended
93
- // with its separator (e.g. `/assets/*` matches `/assets/`)
94
- const rest = node.rest;
95
- if (rest?.allowEmpty && trailingSlash && rest.child.value !== undefined) {
96
- return { value: rest.child.value, params: orUndefined(params) };
97
- }
98
- return undefined;
99
- }
100
-
101
- const segment = segments[i];
102
-
103
- // Static segments win over params
104
- const stat = node.static?.get(segment);
105
- if (stat) {
106
- const match = this.#matchNode(stat, segments, i + 1, params, trailingSlash);
107
- if (match) return match;
108
- }
109
-
110
- if (node.param && segment !== "") {
111
- const match = this.#matchNode(node.param.child, segments, i + 1, {
112
- ...params,
113
- [node.param.name]: segment,
114
- }, trailingSlash);
115
- if (match) return match;
116
- }
117
-
118
- if (node.glob?.regex.test(segment)) {
119
- const glob = node.glob;
120
- const match = this.#matchNode(glob.child, segments, i + 1, params, trailingSlash);
121
- if (match) return match;
122
- }
123
-
124
- // The rest matcher consumes all remaining segments
125
- const rest = node.rest;
126
- if (rest?.child.value !== undefined) {
127
- // Only build the captured value (and a new params object) when the
128
- // pattern actually names it — a bare `*` catch-all shouldn't pay
129
- // for a slice+join on every request
130
- if (rest.name !== undefined) {
131
- return {
132
- value: rest.child.value,
133
- params: orUndefined({ ...params, [rest.name]: segments.slice(i).join("/") }),
134
- };
135
- }
136
- return { value: rest.child.value, params: orUndefined(params) };
137
- }
138
-
139
- return undefined;
140
- }
141
- }
142
-
143
- export interface PathMatch<T> {
144
- value: T;
145
- params: Record<string, string> | undefined;
146
- }
147
-
148
- class TrieNode<T> {
149
- value: T | undefined = undefined;
150
- static: Map<string, TrieNode<T>> | undefined;
151
- param: { name: string; child: TrieNode<T> } | undefined;
152
- glob: { regex: RegExp; child: TrieNode<T> } | undefined;
153
- rest: { name: string | undefined; allowEmpty: boolean; child: TrieNode<T> } | undefined;
154
- }
155
-
156
- /**
157
- * Splits a path or pattern into segments, dropping the leading empty segment
158
- * and any trailing empty (from a trailing slash). `/posts/5` becomes
159
- * `["posts", "5"]` and `/` becomes `[]`.
160
- */
161
- function splitPath(path: string): string[] {
162
- const segments = path.split("/");
163
- if (segments[0] === "") segments.shift();
164
- if (segments.length && segments[segments.length - 1] === "") segments.pop();
165
- return segments;
166
- }
167
-
168
- /**
169
- * Compiles a pattern segment with an embedded `*` (e.g. `*.css`) into a
170
- * regex that matches a single path segment.
171
- */
172
- function globToRegex(segment: string): RegExp {
173
- const source = segment
174
- .split("*")
175
- .map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
176
- .join(".*");
177
- return new RegExp(`^${source}$`);
178
- }
179
-
180
- function orUndefined(params: Record<string, string>): Record<string, string> | undefined {
181
- return Object.keys(params).length ? params : undefined;
182
- }
@@ -1,18 +0,0 @@
1
- import type { QueryRecord } from "../types/ServerLoadEvent";
2
-
3
- /**
4
- * Converts a URL's query string into a plain record: one string per param,
5
- * or an array when a param was repeated.
6
- *
7
- * @param searchParams The URL's search params
8
- * @returns The param values
9
- */
10
- export default function searchParamsToRecord(searchParams: URLSearchParams): QueryRecord {
11
- const result: QueryRecord = {};
12
- for (const key of searchParams.keys()) {
13
- if (key in result) continue;
14
- const values = searchParams.getAll(key);
15
- result[key] = values.length > 1 ? values : values[0];
16
- }
17
- return result;
18
- }
@@ -1,150 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { createRequire, isBuiltin } from "node:module";
3
- import path from "node:path";
4
- import type { UserConfig } from "vite";
5
-
6
- export type PackageJson = {
7
- name?: string;
8
- torpor?: string;
9
- exports?: unknown;
10
- dependencies?: Record<string, string>;
11
- devDependencies?: Record<string, string>;
12
- optionalDependencies?: Record<string, string>;
13
- peerDependencies?: Record<string, string>;
14
- [key: string]: unknown;
15
- };
16
-
17
- /**
18
- * Finds packages installed in the site that ship `.torp` files, e.g. icon
19
- * libraries like phosphor-torpor. These packages need the torpor compiler, so
20
- * they can't go through Vite's default pipelines: dep optimization parses
21
- * their files as plain JavaScript (and fails on torpor syntax like `@render`
22
- * or `import type` from an uncompiled source), and SSR externalization would
23
- * leave raw `.torp` imports that neither Node nor workerd can load.
24
- *
25
- * A package is a torpor package when it declares a `torpor` entry in its
26
- * package.json (e.g. `"torpor": "./lib/index.js"`, mirroring the `svelte`
27
- * field convention), or when any of its export targets is a `.torp` file.
28
- *
29
- * @param siteRoot The root folder of the site
30
- * @returns The names of the torpor packages found (may be empty)
31
- */
32
- export default function findTorporPackages(siteRoot: string): string[] {
33
- const sitePackageJson = path.resolve(siteRoot, "package.json");
34
- if (!existsSync(sitePackageJson)) return [];
35
-
36
- const pkg: PackageJson = JSON.parse(readFileSync(sitePackageJson, "utf8"));
37
- const packages = new Set<string>();
38
- const visited = new Set<string>();
39
-
40
- const rootRequire = createRequire(sitePackageJson);
41
- for (const name of dependencyNames(pkg)) {
42
- collectTorporPackage(name, rootRequire, packages, visited);
43
- }
44
- return [...packages];
45
- }
46
-
47
- /**
48
- * Adds `optimizeDeps.exclude` and `ssr.noExternal` entries for packages that
49
- * ship `.torp` files, so that they are served/bundled through the torpor
50
- * compiler instead.
51
- */
52
- export function addTorporPackageConfig(siteRoot: string, config: UserConfig): void {
53
- const packages = findTorporPackages(siteRoot);
54
- if (packages.length === 0) return;
55
-
56
- config.optimizeDeps ??= {};
57
- config.optimizeDeps.exclude = [...(config.optimizeDeps.exclude ?? []), ...packages];
58
-
59
- config.ssr ??= {};
60
- const noExternal = config.ssr.noExternal;
61
- if (noExternal === undefined) {
62
- config.ssr.noExternal = packages;
63
- } else if (Array.isArray(noExternal)) {
64
- noExternal.push(...packages);
65
- }
66
- // For `true` (bundle everything) or string/regex values there is nothing
67
- // sensible to merge, and they already bundle more than we need
68
- }
69
-
70
- function dependencyNames(pkg: PackageJson): string[] {
71
- return [
72
- ...Object.keys(pkg.dependencies ?? {}),
73
- ...Object.keys(pkg.devDependencies ?? {}),
74
- ...Object.keys(pkg.optionalDependencies ?? {}),
75
- ...Object.keys(pkg.peerDependencies ?? {}),
76
- ];
77
- }
78
-
79
- function collectTorporPackage(
80
- name: string,
81
- require: NodeRequire,
82
- packages: Set<string>,
83
- visited: Set<string>,
84
- ): void {
85
- // Some packages shadow Node builtins (e.g. a dependency literally named
86
- // "path"), and builtins can't contain .torp files
87
- if (isBuiltin(name)) return;
88
-
89
- const packageJsonPath = resolvePackageJson(name, require);
90
- if (!packageJsonPath || visited.has(packageJsonPath)) return;
91
- visited.add(packageJsonPath);
92
-
93
- let pkg: PackageJson;
94
- try {
95
- pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
96
- } catch {
97
- return;
98
- }
99
-
100
- if (isTorporPackage(pkg)) {
101
- packages.add(pkg.name ?? name);
102
- }
103
-
104
- // Recurse into the package's own dependencies, resolved relative to it
105
- // (pnpm keeps transitive deps out of the site's top-level node_modules)
106
- const depRequire = createRequire(packageJsonPath);
107
- for (const depName of dependencyNames(pkg)) {
108
- collectTorporPackage(depName, depRequire, packages, visited);
109
- }
110
- }
111
-
112
- function isTorporPackage(pkg: PackageJson): boolean {
113
- if (typeof pkg.torpor === "string") return true;
114
- return exportsIncludeTorp(pkg.exports);
115
- }
116
-
117
- function exportsIncludeTorp(exports: unknown): boolean {
118
- if (typeof exports === "string") return exports.endsWith(".torp");
119
- if (Array.isArray(exports)) return exports.some(exportsIncludeTorp);
120
- if (exports && typeof exports === "object") {
121
- return Object.values(exports).some(exportsIncludeTorp);
122
- }
123
- return false;
124
- }
125
-
126
- function resolvePackageJson(name: string, require: NodeRequire): string | undefined {
127
- // require.resolve returns the name itself for Node builtins, so guard
128
- // everything below with absolute path checks
129
- try {
130
- const packageJson = require.resolve(`${name}/package.json`);
131
- return path.isAbsolute(packageJson) ? packageJson : undefined;
132
- } catch {
133
- let entry: string;
134
- try {
135
- entry = require.resolve(name);
136
- } catch {
137
- // Not resolvable from here (e.g. an optional peer), skip it
138
- return undefined;
139
- }
140
- if (!path.isAbsolute(entry)) return undefined;
141
- let dir = path.dirname(entry);
142
- while (true) {
143
- const packageJson = path.join(dir, "package.json");
144
- if (existsSync(packageJson)) return packageJson;
145
- const parent = path.dirname(dir);
146
- if (parent === dir) return undefined;
147
- dir = parent;
148
- }
149
- }
150
- }
@@ -1,90 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import path from "node:path";
3
-
4
- export interface AliasEntry {
5
- find: string | RegExp;
6
- replacement: string;
7
- }
8
-
9
- /**
10
- * Reads `tsconfig.json` `compilerOptions.paths` (relative to `baseUrl`,
11
- * defaulting to the tsconfig directory) and converts them to Vite
12
- * `resolve.alias` entries. Only handles paths declared in the root tsconfig
13
- * (not inherited via `extends`).
14
- */
15
- export default function tsconfigAliases(root: string): AliasEntry[] {
16
- const file = path.join(root, "tsconfig.json");
17
- let paths: Record<string, string[]> | undefined;
18
- let baseUrl: string;
19
- try {
20
- const tsconfig = JSON.parse(stripJsonc(readFileSync(file, "utf-8")));
21
- const compilerOptions = tsconfig.compilerOptions ?? {};
22
- baseUrl = compilerOptions.baseUrl ? path.resolve(root, compilerOptions.baseUrl) : root;
23
- paths = compilerOptions.paths;
24
- } catch {
25
- return [];
26
- }
27
- if (!paths) return [];
28
-
29
- const aliases: AliasEntry[] = [];
30
- for (const [pattern, targets] of Object.entries(paths)) {
31
- const target = targets?.[0];
32
- if (!target) continue;
33
- if (pattern.endsWith("*")) {
34
- // `@/*` -> `./src/*`: match the literal prefix (`@/`) and rewrite to
35
- // the target dir. A string `find` is used (not a RegExp) because
36
- // Vite applies prefix-string aliases during SSR transform, which is
37
- // what makes path aliases resolve in the SSR module runner.
38
- const find = pattern.slice(0, -1);
39
- const targetDir = target.slice(0, -1);
40
- aliases.push({
41
- find,
42
- replacement: `${path.resolve(baseUrl, targetDir)}/`,
43
- });
44
- } else {
45
- aliases.push({ find: pattern, replacement: path.resolve(baseUrl, target) });
46
- }
47
- }
48
- return aliases;
49
- }
50
-
51
- /**
52
- * Strips JSONC comments and trailing commas so `tsconfig.json` (which permits
53
- * both) can be parsed with `JSON.parse`. String contents are preserved.
54
- */
55
- export function stripJsonc(text: string): string {
56
- let out = "";
57
- for (let i = 0; i < text.length;) {
58
- const c = text[i];
59
- if (c === '"' || c === "'") {
60
- const quote = c;
61
- out += c;
62
- i++;
63
- while (i < text.length) {
64
- if (text[i] === "\\") {
65
- out += text[i] + (text[i + 1] ?? "");
66
- i += 2;
67
- continue;
68
- }
69
- const cc = text[i++];
70
- out += cc;
71
- if (cc === quote) break;
72
- }
73
- continue;
74
- }
75
- if (c === "/" && text[i + 1] === "/") {
76
- i += 2;
77
- while (i < text.length && text[i] !== "\n") i++;
78
- continue;
79
- }
80
- if (c === "/" && text[i + 1] === "*") {
81
- i += 2;
82
- while (i < text.length && !(text[i] === "*" && text[i + 1] === "/")) i++;
83
- i += 2;
84
- continue;
85
- }
86
- out += c;
87
- i++;
88
- }
89
- return out.replace(/,(\s*[}\]])/g, "$1");
90
- }
@@ -1,18 +0,0 @@
1
- import type { StandardSchemaV1 } from "../types/StandardSchema";
2
-
3
- /**
4
- * The error thrown when a value fails standard schema validation. The
5
- * framework turns it into a 422 response for endpoint request bodies.
6
- */
7
- export default class ValidationError extends Error {
8
- /**
9
- * The issues reported by the schema.
10
- */
11
- issues: ReadonlyArray<StandardSchemaV1.Issue>;
12
-
13
- constructor(issues: ReadonlyArray<StandardSchemaV1.Issue>) {
14
- super("Validation failed");
15
- this.name = "ValidationError";
16
- this.issues = issues;
17
- }
18
- }
@@ -1,83 +0,0 @@
1
- import type PageServerEndPoint from "../types/PageServerEndPoint";
2
- import type ServerEndPoint from "../types/ServerEndPoint";
3
- import type { StandardSchemaV1 } from "../types/StandardSchema";
4
- import type ServerEvent from "../server/ServerEvent";
5
- import searchParamsToRecord from "../utils/searchParamsToRecord";
6
- import unprocessable from "../response/unprocessable";
7
- import ValidationError from "./ValidationError";
8
- import validate from "./validate";
9
-
10
- /**
11
- * Loose views of an endpoint's schema map, keyed by handler/action name (plus
12
- * the reserved `params` key). The type-level constraint differs per endpoint
13
- * type, but the runtime treats them the same.
14
- */
15
- type Schemas = Record<string, StandardSchemaV1 | undefined>;
16
-
17
- type EndPoint = ServerEndPoint | PageServerEndPoint;
18
-
19
- /**
20
- * Gets the standard schema declared for a handler or action, if any. The
21
- * schemas map is keyed by name; the runtime treats it as a loose record.
22
- */
23
- export function endpointSchema(endPoint: EndPoint, name: string): StandardSchemaV1 | undefined {
24
- return (endPoint.schema as Schemas | undefined)?.[name];
25
- }
26
-
27
- /**
28
- * Validates the route params against the endpoint's `params` schema, if it
29
- * declares one, returning the coerced params. Throws a ValidationError when
30
- * they don't match, which callers turn into a 404 (params come from the URL,
31
- * so a failed validation means the resource doesn't exist).
32
- *
33
- * @param endPoint The endpoint declaring the (optional) `params` schema
34
- * @param params The route params from the matched route
35
- * @returns The validated params
36
- */
37
- export async function validateEndpointParams(
38
- endPoint: EndPoint,
39
- params: Record<string, any>,
40
- ): Promise<Record<string, any>> {
41
- const schema = endpointSchema(endPoint, "params");
42
- return schema ? ((await validate(schema, params)) as Record<string, any>) : params;
43
- }
44
-
45
- /**
46
- * Validates a handler's input against its schema: get/head handlers and load
47
- * functions validate the URL's query string, other handlers validate the JSON
48
- * request body. Returns the validated values (an empty object when no schema
49
- * is declared), which callers pass through to the handler's event.
50
- *
51
- * @param schema The handler's (optional) schema
52
- * @param functionName The handler name (`get`, `post`, `load`, etc)
53
- * @param url The request URL, for the query string
54
- * @param ev The server event, for the request body
55
- * @returns The validated values
56
- */
57
- export async function validateHandlerInput(
58
- schema: StandardSchemaV1 | undefined,
59
- functionName: string,
60
- url: URL,
61
- ev: ServerEvent,
62
- ): Promise<{ json?: unknown; form?: unknown; query?: unknown }> {
63
- if (!schema) return {};
64
- if (functionName === "get" || functionName === "head" || functionName === "load") {
65
- return { query: await validate(schema, searchParamsToRecord(url.searchParams)) };
66
- }
67
- return { json: await validate(schema, await ev.json()) };
68
- }
69
-
70
- /**
71
- * Turns a ValidationError thrown during endpoint validation into a 422
72
- * response with the schema's issues. Returns undefined for any other error,
73
- * which callers should rethrow.
74
- *
75
- * @param error The error thrown by a handler or validation
76
- * @returns A 422 response, or undefined when the error isn't a validation failure
77
- */
78
- export function validationErrorResponse(error: unknown): Response | undefined {
79
- if (error instanceof ValidationError) {
80
- return unprocessable({ message: error.message, issues: error.issues });
81
- }
82
- return undefined;
83
- }
@@ -1,26 +0,0 @@
1
- import type { StandardSchemaV1 } from "../types/StandardSchema";
2
- import ValidationError from "./ValidationError";
3
-
4
- /**
5
- * Validates a value against a standard schema (zod, valibot, arktype, etc),
6
- * returning the parsed value, or throwing a `ValidationError` with the
7
- * schema's issues.
8
- *
9
- * ```ts
10
- * const post = validate(postSchema, { title: "Hello" });
11
- * ```
12
- *
13
- * @param schema A schema implementing the Standard Schema interface
14
- * @param value The value to validate
15
- * @returns The parsed value
16
- */
17
- export default async function validate<Schema extends StandardSchemaV1>(
18
- schema: Schema,
19
- value: unknown,
20
- ): Promise<StandardSchemaV1.InferOutput<Schema>> {
21
- const result = await schema["~standard"].validate(value);
22
- if (result.issues) {
23
- throw new ValidationError(result.issues);
24
- }
25
- return result.value as StandardSchemaV1.InferOutput<Schema>;
26
- }