@turnipxenon/pineapple 5.3.16 → 5.3.17

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.
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Server middleware that handles locale-based routing and request processing.
3
+ *
4
+ * Configure `disableAsyncLocalStorage` when generating Paraglide with
5
+ * `paraglideVitePlugin()` or `compile()`, not when calling
6
+ * `paraglideMiddleware()`. Keep AsyncLocalStorage enabled by default and
7
+ * only disable it for runtimes that lack `AsyncLocalStorage` support and
8
+ * guarantee request isolation.
9
+ *
10
+ * This middleware performs several key functions:
11
+ *
12
+ * 1. Determines the locale for the incoming request using configured strategies
13
+ * 2. Handles URL localization and redirects (only for document requests)
14
+ * 3. Maintains locale state using AsyncLocalStorage to prevent request interference
15
+ *
16
+ * When URL strategy is used:
17
+ *
18
+ * - The locale is extracted from the URL for all request types
19
+ * - If URL doesn't match the determined locale, redirects to localized URL (only for document requests)
20
+ * - De-localizes URLs before passing to server (e.g., `/fr/about` → `/about`)
21
+ *
22
+ * @see https://paraglidejs.com/middleware
23
+ *
24
+ * @template T - The return type of the resolve function
25
+ *
26
+ * @param {Request} request - The incoming request object
27
+ * @param {(args: { request: Request, locale: import("./runtime.js").Locale }) => T | Promise<T>} resolve - Function to handle the request. The callback receives:
28
+ * - `request`: A modified request with a delocalized URL when the URL strategy is used (e.g., `/fr/about` → `/about`).
29
+ * If your framework handles URL localization itself (e.g., TanStack Router's `rewrite` option), use the original
30
+ * request instead to avoid redirect loops.
31
+ * - `locale`: The determined locale for this request.
32
+ * @param {{
33
+ * effectiveRequestUrl?: string | URL | ((request: Request) => string | URL),
34
+ * onRedirect?: (response: Response) => void
35
+ * }} [options] - Options to control middleware behavior. `effectiveRequestUrl` sets the effective request URL used for route matching, URL-based locale detection, redirects, and `getUrlOrigin()`.
36
+ * @returns {Promise<Response>}
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * // Basic usage in metaframeworks like NextJS, SvelteKit, Astro, Nuxt, etc.
41
+ * export const handle = async ({ event, resolve }) => {
42
+ * return paraglideMiddleware(event.request, ({ request, locale }) => {
43
+ * // let the framework further resolve the request
44
+ * return resolve(request);
45
+ * });
46
+ * };
47
+ * ```
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * // Usage in a framework like Express JS or Hono
52
+ * app.use(async (req, res, next) => {
53
+ * const result = await paraglideMiddleware(req, ({ request, locale }) => {
54
+ * // If a redirect happens this won't be called
55
+ * return next(request);
56
+ * });
57
+ * });
58
+ * ```
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * // Usage with frameworks that handle URL localization/delocalization themselves
63
+ * //
64
+ * // Some frameworks like TanStack Router handle URL localization and delocalization
65
+ * // themselves via their own rewrite APIs (e.g., `rewrite.input`/`rewrite.output`).
66
+ * //
67
+ * // When the framework handles this, the middleware's URL delocalization is not needed.
68
+ * // Using the modified `request` from the callback would cause a redirect loop because
69
+ * // both the middleware and the framework would attempt to delocalize the URL.
70
+ * //
71
+ * // Solution: Pass the original request to the handler instead of the modified one.
72
+ * // The middleware still handles locale detection, cookies, and AsyncLocalStorage context.
73
+ * //
74
+ * // ❌ WRONG - causes redirect loop when framework handles URL rewriting:
75
+ * // paraglideMiddleware(req, ({ request }) => handler.fetch(request))
76
+ * //
77
+ * // ✅ CORRECT - use original request when framework handles URL localization:
78
+ * // paraglideMiddleware(req, () => handler.fetch(req))
79
+ *
80
+ * * *
81
+ * export default {
82
+ * fetch(req: Request): Promise<Response> {
83
+ * // TanStack Router handles URL rewriting via deLocalizeUrl/localizeUrl
84
+ * // so we pass the original `req` instead of the modified `request`
85
+ * return paraglideMiddleware(req, () => handler.fetch(req))
86
+ * },
87
+ * }
88
+ * ```
89
+ */
90
+ export function paraglideMiddleware<T>(request: Request, resolve: (args: {
91
+ request: Request;
92
+ locale: import("./runtime.js").Locale;
93
+ }) => T | Promise<T>, options?: {
94
+ effectiveRequestUrl?: string | URL | ((request: Request) => string | URL);
95
+ onRedirect?: (response: Response) => void;
96
+ }): Promise<Response>;
97
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/lib/external/paraglide/server.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AACH,oCAlEa,CAAC,WAEH,OAAO,WACP,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAA;CAAE,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,YAKrF;IACN,mBAAmB,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,GAAG,CAAC,CAAC;IAC1E,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;CAC1C,GACS,OAAO,CAAC,QAAQ,CAAC,CA0J7B"}
@@ -0,0 +1,290 @@
1
+ /* eslint-disable */
2
+
3
+ import * as runtime from "./runtime.js";
4
+
5
+ /**
6
+ * Server middleware that handles locale-based routing and request processing.
7
+ *
8
+ * Configure `disableAsyncLocalStorage` when generating Paraglide with
9
+ * `paraglideVitePlugin()` or `compile()`, not when calling
10
+ * `paraglideMiddleware()`. Keep AsyncLocalStorage enabled by default and
11
+ * only disable it for runtimes that lack `AsyncLocalStorage` support and
12
+ * guarantee request isolation.
13
+ *
14
+ * This middleware performs several key functions:
15
+ *
16
+ * 1. Determines the locale for the incoming request using configured strategies
17
+ * 2. Handles URL localization and redirects (only for document requests)
18
+ * 3. Maintains locale state using AsyncLocalStorage to prevent request interference
19
+ *
20
+ * When URL strategy is used:
21
+ *
22
+ * - The locale is extracted from the URL for all request types
23
+ * - If URL doesn't match the determined locale, redirects to localized URL (only for document requests)
24
+ * - De-localizes URLs before passing to server (e.g., `/fr/about` → `/about`)
25
+ *
26
+ * @see https://paraglidejs.com/middleware
27
+ *
28
+ * @template T - The return type of the resolve function
29
+ *
30
+ * @param {Request} request - The incoming request object
31
+ * @param {(args: { request: Request, locale: import("./runtime.js").Locale }) => T | Promise<T>} resolve - Function to handle the request. The callback receives:
32
+ * - `request`: A modified request with a delocalized URL when the URL strategy is used (e.g., `/fr/about` → `/about`).
33
+ * If your framework handles URL localization itself (e.g., TanStack Router's `rewrite` option), use the original
34
+ * request instead to avoid redirect loops.
35
+ * - `locale`: The determined locale for this request.
36
+ * @param {{
37
+ * effectiveRequestUrl?: string | URL | ((request: Request) => string | URL),
38
+ * onRedirect?: (response: Response) => void
39
+ * }} [options] - Options to control middleware behavior. `effectiveRequestUrl` sets the effective request URL used for route matching, URL-based locale detection, redirects, and `getUrlOrigin()`.
40
+ * @returns {Promise<Response>}
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Basic usage in metaframeworks like NextJS, SvelteKit, Astro, Nuxt, etc.
45
+ * export const handle = async ({ event, resolve }) => {
46
+ * return paraglideMiddleware(event.request, ({ request, locale }) => {
47
+ * // let the framework further resolve the request
48
+ * return resolve(request);
49
+ * });
50
+ * };
51
+ * ```
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * // Usage in a framework like Express JS or Hono
56
+ * app.use(async (req, res, next) => {
57
+ * const result = await paraglideMiddleware(req, ({ request, locale }) => {
58
+ * // If a redirect happens this won't be called
59
+ * return next(request);
60
+ * });
61
+ * });
62
+ * ```
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * // Usage with frameworks that handle URL localization/delocalization themselves
67
+ * //
68
+ * // Some frameworks like TanStack Router handle URL localization and delocalization
69
+ * // themselves via their own rewrite APIs (e.g., `rewrite.input`/`rewrite.output`).
70
+ * //
71
+ * // When the framework handles this, the middleware's URL delocalization is not needed.
72
+ * // Using the modified `request` from the callback would cause a redirect loop because
73
+ * // both the middleware and the framework would attempt to delocalize the URL.
74
+ * //
75
+ * // Solution: Pass the original request to the handler instead of the modified one.
76
+ * // The middleware still handles locale detection, cookies, and AsyncLocalStorage context.
77
+ * //
78
+ * // ❌ WRONG - causes redirect loop when framework handles URL rewriting:
79
+ * // paraglideMiddleware(req, ({ request }) => handler.fetch(request))
80
+ * //
81
+ * // ✅ CORRECT - use original request when framework handles URL localization:
82
+ * // paraglideMiddleware(req, () => handler.fetch(req))
83
+ *
84
+ * * *
85
+ * export default {
86
+ * fetch(req: Request): Promise<Response> {
87
+ * // TanStack Router handles URL rewriting via deLocalizeUrl/localizeUrl
88
+ * // so we pass the original `req` instead of the modified `request`
89
+ * return paraglideMiddleware(req, () => handler.fetch(req))
90
+ * },
91
+ * }
92
+ * ```
93
+ */
94
+ export async function paraglideMiddleware(request, resolve, options) {
95
+ let requestAsyncLocalStorage = runtime.serverAsyncLocalStorage;
96
+ requestAsyncLocalStorage = runtime.getServerAsyncLocalStorage();
97
+ if (!runtime.disableAsyncLocalStorage && !requestAsyncLocalStorage) {
98
+ const { AsyncLocalStorage } = await import("async_hooks");
99
+ requestAsyncLocalStorage = runtime.getServerAsyncLocalStorage();
100
+ if (!requestAsyncLocalStorage) {
101
+ requestAsyncLocalStorage = new AsyncLocalStorage();
102
+ runtime.overwriteServerAsyncLocalStorage(requestAsyncLocalStorage);
103
+ }
104
+ }
105
+ if (!requestAsyncLocalStorage) {
106
+ requestAsyncLocalStorage = createMockAsyncLocalStorage();
107
+ runtime.overwriteServerAsyncLocalStorage(requestAsyncLocalStorage);
108
+ }
109
+ const url = resolveMiddlewareUrl(request, options?.effectiveRequestUrl);
110
+ const origin = url.origin;
111
+ if (runtime.isExcludedByRouteStrategy(url.href)) {
112
+ const locale = runtime.baseLocale;
113
+ const newRequest = cloneRequestWithFallback(request, url);
114
+ /** @type {Set<string>} */
115
+ const messageCalls = new Set();
116
+ return /** @type {Response} */ (await requestAsyncLocalStorage?.run({ locale, origin, messageCalls }, () => resolve({ locale, request: newRequest })));
117
+ }
118
+ const strategy = runtime.getStrategyForUrl(url.href);
119
+ const decision = await runtime.shouldRedirect({ request, effectiveRequestUrl: url });
120
+ const locale = decision.locale;
121
+ // if the client makes a request to a URL that doesn't match
122
+ // the localizedUrl, redirect the client to the localized URL
123
+ if (request.headers.get("Sec-Fetch-Dest") === "document" &&
124
+ decision.shouldRedirect &&
125
+ decision.redirectUrl) {
126
+ // Create headers object with Vary header if preferredLanguage strategy is used
127
+ /** @type {Record<string, string>} */
128
+ const headers = {};
129
+ if (strategy.includes("preferredLanguage")) {
130
+ headers["Vary"] = "Accept-Language";
131
+ }
132
+ const response = new Response(null, {
133
+ status: 307,
134
+ headers: {
135
+ Location: decision.redirectUrl.href,
136
+ ...headers,
137
+ },
138
+ });
139
+ options?.onRedirect?.(response);
140
+ return response;
141
+ }
142
+ // If the strategy includes "url", we need to de-localize the URL
143
+ // before passing it to the server middleware.
144
+ //
145
+ // The middleware is responsible for mapping a localized URL to the
146
+ // de-localized URL e.g. `/en/about` to `/about`. Otherwise,
147
+ // the server can't render the correct page.
148
+ let newRequest;
149
+ if (strategy.includes("url")) {
150
+ newRequest = cloneRequestWithFallback(request, runtime.deLocalizeUrl(url));
151
+ }
152
+ else {
153
+ newRequest = cloneRequestWithFallback(request, url);
154
+ }
155
+ // the message functions that have been called in this request
156
+ /** @type {Set<string>} */
157
+ const messageCalls = new Set();
158
+ const response = await requestAsyncLocalStorage?.run({ locale, origin, messageCalls }, () => resolve({ locale, request: newRequest }));
159
+ // Only modify HTML responses
160
+ if (runtime.experimentalMiddlewareLocaleSplitting &&
161
+ response.headers.get("Content-Type")?.includes("html")) {
162
+ const body = await response.text();
163
+ const messages = [];
164
+ // using .values() to avoid polyfilling in older projects. else the following error is thrown
165
+ // Type 'Set<string>' can only be iterated through when using the '--downlevelIteration' flag or with a '--target' of 'es2015' or higher.
166
+ for (const messageCall of Array.from(messageCalls)) {
167
+ const [id, locale] =
168
+ /** @type {[string, import("./runtime.js").Locale]} */ (messageCall.split(":"));
169
+ messages.push(`${id}: ${compiledBundles[id]?.[locale]}`);
170
+ }
171
+ // Prevent translated content from terminating the inline script tag.
172
+ const escapedMessages = messages
173
+ .join(",")
174
+ .replace(/<\/(script)/gi, "<\\/$1");
175
+ // Reuse the request's CSP nonce (if any) so the injected script is allowed under a strict CSP
176
+ const nonce = response.headers
177
+ .get("Content-Security-Policy")
178
+ ?.match(/'nonce-([\w+/=-]+)'/)?.[1];
179
+ const nonceAttr = nonce ? `nonce="${nonce}"` : "";
180
+ const script = `<script ${nonceAttr}>globalThis.__paraglide = globalThis.__paraglide ?? {}; globalThis.__paraglide.ssr = { ${escapedMessages} }</script>`;
181
+ // Insert the script before the closing head tag
182
+ const newBody = body.replace("</head>", `${script}</head>`);
183
+ // Create a new response with the modified body
184
+ // Clone all headers except Content-Length which will be set automatically
185
+ const newHeaders = new Headers(response.headers);
186
+ newHeaders.delete("Content-Length"); // Let the browser calculate the correct length
187
+ return new Response(newBody, {
188
+ status: response.status,
189
+ statusText: response.statusText,
190
+ headers: newHeaders,
191
+ });
192
+ }
193
+ return response;
194
+ }
195
+ /**
196
+ * @param {Request} request
197
+ * @param {string | URL | ((request: Request) => string | URL) | undefined} effectiveRequestUrl
198
+ * @returns {URL}
199
+ */
200
+ function resolveMiddlewareUrl(request, effectiveRequestUrl) {
201
+ if (typeof effectiveRequestUrl === "function") {
202
+ return new URL(effectiveRequestUrl(request), request.url);
203
+ }
204
+ if (typeof effectiveRequestUrl === "string" || effectiveRequestUrl instanceof URL) {
205
+ return new URL(effectiveRequestUrl, request.url);
206
+ }
207
+ return new URL(request.url);
208
+ }
209
+ /**
210
+ * Some metaframeworks (NextJS) require a new Request object.
211
+ * https://github.com/opral/inlang-paraglide-js/issues/411
212
+ *
213
+ * However, some frameworks (TanStack Start 1.143+) use custom Request
214
+ * implementations that cannot be cloned with `new Request(request)`.
215
+ * https://github.com/opral/paraglide-js/issues/573
216
+ *
217
+ * Effective request URL overrides behind proxies:
218
+ * https://github.com/opral/paraglide-js/issues/652
219
+ *
220
+ * @param {Request} request
221
+ * @param {string | URL} [url]
222
+ * @returns {Request}
223
+ */
224
+ function cloneRequestWithFallback(request, url = request.url) {
225
+ const targetUrl = typeof url === "string" ? url : url.href;
226
+ if (targetUrl === request.url) {
227
+ try {
228
+ // Clone first so building a new Request does not consume the original body stream.
229
+ return new Request(request.clone());
230
+ }
231
+ catch {
232
+ try {
233
+ return new Request(request);
234
+ }
235
+ catch {
236
+ return request;
237
+ }
238
+ }
239
+ }
240
+ try {
241
+ // Clone first so building a new Request does not consume the original body stream.
242
+ return new Request(targetUrl, request.clone());
243
+ }
244
+ catch {
245
+ try {
246
+ return new Request(targetUrl, request);
247
+ }
248
+ catch {
249
+ return request;
250
+ }
251
+ }
252
+ }
253
+ /**
254
+ * Creates a mock AsyncLocalStorage implementation for environments where
255
+ * native AsyncLocalStorage is not available or disabled.
256
+ *
257
+ * This mock implementation mimics the behavior of the native AsyncLocalStorage
258
+ * but doesn't require the async_hooks module. It's used as a fallback when
259
+ * the runtime does not expose AsyncLocalStorage or when it has been disabled.
260
+ *
261
+ * @returns {import("./runtime.js").ParaglideAsyncLocalStorage}
262
+ */
263
+ function createMockAsyncLocalStorage() {
264
+ /** @type {any} */
265
+ let currentStore = undefined;
266
+ return {
267
+ getStore() {
268
+ return currentStore;
269
+ },
270
+ async run(store, callback) {
271
+ currentStore = store;
272
+ try {
273
+ return await callback();
274
+ }
275
+ finally {
276
+ currentStore = undefined;
277
+ }
278
+ },
279
+ };
280
+ }
281
+ // Used in generated server.js when async local storage is disabled.
282
+ void createMockAsyncLocalStorage;
283
+ /**
284
+ * The compiled messages for the server middleware.
285
+ *
286
+ * Only populated if `enableMiddlewareOptimizations` is set to `true`.
287
+ *
288
+ * @type {Record<string, Record<import("./runtime.js").Locale, string>>}
289
+ */
290
+ const compiledBundles = {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@turnipxenon/pineapple",
3
3
  "description": "personal package for base styling for other personal projects",
4
- "version": "5.3.16",
4
+ "version": "5.3.17",
5
5
  "devDependencies": {
6
6
  "@commitlint/cli": "^19.8.1",
7
7
  "@commitlint/config-conventional": "^19.8.1",
@@ -126,7 +126,7 @@
126
126
  "scripts": {
127
127
  "dev": "vite dev",
128
128
  "build": "vite build",
129
- "package": "svelte-kit sync && svelte-package && publint",
129
+ "package": "svelte-kit sync && svelte-package && node scripts/strip-dist-gitignore.mjs && publint",
130
130
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
131
131
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
132
132
  "check-baseline": "bash scripts/check-baseline.sh",