@tenphi/tasty 3.0.0 → 3.0.2
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.
- package/README.md +16 -16
- package/dist/{babel-HlEpSZrj.d.ts → babel-R2qT7yLN.d.ts} +2 -2
- package/dist/{collector-D14DcZx9.js → collector-BpkjNQDo.js} +3 -3
- package/dist/{collector-D14DcZx9.js.map → collector-BpkjNQDo.js.map} +1 -1
- package/dist/{collector-BPzZezAG.d.ts → collector-D8o4Wdq-.d.ts} +2 -2
- package/dist/{config-CCcE_tqx.js → config-DOCuTykY.js} +260 -107
- package/dist/config-DOCuTykY.js.map +1 -0
- package/dist/{config-D2INrjr_.d.ts → config-De8L9NWM.d.ts} +2 -2
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +5 -5
- package/dist/{core-B5d0IPi2.js → core-p6iTbQnn.js} +7 -7
- package/dist/core-p6iTbQnn.js.map +1 -0
- package/dist/{css-writer-B5DBoxhf.js → css-writer-BHjTF0YN.js} +3 -3
- package/dist/{css-writer-B5DBoxhf.js.map → css-writer-BHjTF0YN.js.map} +1 -1
- package/dist/{format-rules-BbKDjsfO.js → format-rules-Cb0YIjyS.js} +2 -2
- package/dist/{format-rules-BbKDjsfO.js.map → format-rules-Cb0YIjyS.js.map} +1 -1
- package/dist/{hydrate-CwALW3J9.js → hydrate-xnaB3SDm.js} +2 -2
- package/dist/{hydrate-CwALW3J9.js.map → hydrate-xnaB3SDm.js.map} +1 -1
- package/dist/{index-BAAbdfRs.d.ts → index-DzGxoeyN.d.ts} +5 -5
- package/dist/{index-l_NdJSUS.d.ts → index-KUYya3x7.d.ts} +11 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +6 -6
- package/dist/{keyframes-B8M1FmtE.js → keyframes-DiXjNoBZ.js} +2 -2
- package/dist/{keyframes-B8M1FmtE.js.map → keyframes-DiXjNoBZ.js.map} +1 -1
- package/dist/{merge-styles--1zOSFlS.js → merge-styles-B0lMso5W.js} +2 -2
- package/dist/{merge-styles--1zOSFlS.js.map → merge-styles-B0lMso5W.js.map} +1 -1
- package/dist/{merge-styles-NEvqayL_.d.ts → merge-styles-DLm4wdnb.d.ts} +2 -2
- package/dist/{resolve-recipes-Caix5NnH.js → resolve-recipes-C9nAuwgR.js} +3 -3
- package/dist/{resolve-recipes-Caix5NnH.js.map → resolve-recipes-C9nAuwgR.js.map} +1 -1
- package/dist/ssr/astro-client.js +1 -1
- package/dist/ssr/astro-middleware-static.d.ts +16 -0
- package/dist/ssr/astro-middleware-static.js +18 -0
- package/dist/ssr/astro-middleware-static.js.map +1 -0
- package/dist/ssr/astro-middleware.d.ts +8 -6
- package/dist/ssr/astro-middleware.js +10 -10
- package/dist/ssr/astro-middleware.js.map +1 -1
- package/dist/ssr/astro.js +156 -1
- package/dist/ssr/astro.js.map +1 -0
- package/dist/ssr/index.d.ts +1 -1
- package/dist/ssr/index.js +3 -3
- package/dist/ssr/next.d.ts +1 -1
- package/dist/ssr/next.js +4 -4
- package/dist/static/index.d.ts +2 -2
- package/dist/static/index.js +1 -1
- package/dist/zero/babel.d.ts +1 -1
- package/dist/zero/babel.js +4 -4
- package/dist/zero/index.d.ts +1 -1
- package/dist/zero/index.js +1 -1
- package/dist/zero/next.d.ts +1 -1
- package/docs/ai-agents.md +3 -0
- package/docs/configuration.md +1 -0
- package/docs/ssr.md +1 -0
- package/package.json +27 -11
- package/dist/astro-B53trJyX.js +0 -156
- package/dist/astro-B53trJyX.js.map +0 -1
- package/dist/config-CCcE_tqx.js.map +0 -1
- package/dist/core-B5d0IPi2.js.map +0 -1
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
//#region src/ssr/astro-middleware.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Astro middleware entrypoint for tastyIntegration()
|
|
3
|
+
* Astro middleware entrypoint for `tastyIntegration()`.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* as a
|
|
7
|
-
* you need manual middleware composition.
|
|
5
|
+
* Registered via `addMiddleware()` as `@tenphi/tasty/ssr/astro-middleware`.
|
|
6
|
+
* Exposed as a package subpath only so Astro can resolve it — use
|
|
7
|
+
* `tastyMiddleware()` directly if you need manual middleware composition.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* This is the islands variant: the rendered class list is transferred to the
|
|
10
|
+
* client so hydrating islands skip the style pipeline. See
|
|
11
|
+
* `./astro-middleware-static` for the variant used by
|
|
12
|
+
* `tastyIntegration({ islands: false })`.
|
|
11
13
|
*/
|
|
12
14
|
declare const onRequest: (_context: unknown, next: () => Promise<Response>) => Promise<Response>;
|
|
13
15
|
//#endregion
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tastyMiddleware } from "./astro.js";
|
|
2
2
|
//#region src/ssr/astro-middleware.ts
|
|
3
3
|
/**
|
|
4
|
-
* Astro middleware entrypoint for tastyIntegration()
|
|
4
|
+
* Astro middleware entrypoint for `tastyIntegration()`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* as a
|
|
8
|
-
* you need manual middleware composition.
|
|
6
|
+
* Registered via `addMiddleware()` as `@tenphi/tasty/ssr/astro-middleware`.
|
|
7
|
+
* Exposed as a package subpath only so Astro can resolve it — use
|
|
8
|
+
* `tastyMiddleware()` directly if you need manual middleware composition.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* This is the islands variant: the rendered class list is transferred to the
|
|
11
|
+
* client so hydrating islands skip the style pipeline. See
|
|
12
|
+
* `./astro-middleware-static` for the variant used by
|
|
13
|
+
* `tastyIntegration({ islands: false })`.
|
|
12
14
|
*/
|
|
13
|
-
const onRequest = tastyMiddleware({
|
|
14
|
-
return getMiddlewareTransferCache();
|
|
15
|
-
} });
|
|
15
|
+
const onRequest = tastyMiddleware({ transferCache: true });
|
|
16
16
|
//#endregion
|
|
17
17
|
export { onRequest };
|
|
18
18
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"astro-middleware.js","names":[],"sources":["../../src/ssr/astro-middleware.ts"],"sourcesContent":["/**\n * Astro middleware entrypoint for tastyIntegration()
|
|
1
|
+
{"version":3,"file":"astro-middleware.js","names":[],"sources":["../../src/ssr/astro-middleware.ts"],"sourcesContent":["/**\n * Astro middleware entrypoint for `tastyIntegration()`.\n *\n * Registered via `addMiddleware()` as `@tenphi/tasty/ssr/astro-middleware`.\n * Exposed as a package subpath only so Astro can resolve it — use\n * `tastyMiddleware()` directly if you need manual middleware composition.\n *\n * This is the islands variant: the rendered class list is transferred to the\n * client so hydrating islands skip the style pipeline. See\n * `./astro-middleware-static` for the variant used by\n * `tastyIntegration({ islands: false })`.\n */\n\nimport { tastyMiddleware } from './astro';\n\nexport const onRequest = tastyMiddleware({ transferCache: true });\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAa,YAAY,gBAAgB,EAAE,eAAe,KAAK,CAAC"}
|
package/dist/ssr/astro.js
CHANGED
|
@@ -1,2 +1,157 @@
|
|
|
1
|
-
import { n as
|
|
1
|
+
import { n as getConfig } from "../config-DOCuTykY.js";
|
|
2
|
+
import { a as registerSSRCollectorGetterGlobal } from "../format-rules-Cb0YIjyS.js";
|
|
3
|
+
import { t as ServerStyleCollector } from "../collector-BpkjNQDo.js";
|
|
4
|
+
import { n as runWithCollector, t as getSSRCollector } from "../async-storage-DKK-wTD4.js";
|
|
5
|
+
//#region src/ssr/astro.ts
|
|
6
|
+
/**
|
|
7
|
+
* Astro integration for Tasty SSR.
|
|
8
|
+
*
|
|
9
|
+
* Provides:
|
|
10
|
+
* - tastyIntegration() — Astro Integration API (recommended)
|
|
11
|
+
* - tastyMiddleware() — manual middleware for advanced composition
|
|
12
|
+
*
|
|
13
|
+
* Import from '@tenphi/tasty/ssr/astro'.
|
|
14
|
+
*/
|
|
15
|
+
registerSSRCollectorGetterGlobal(getSSRCollector);
|
|
16
|
+
/**
|
|
17
|
+
* Create an Astro middleware that collects Tasty styles during SSR.
|
|
18
|
+
*
|
|
19
|
+
* All React components rendered during the request will have their
|
|
20
|
+
* computeStyles() calls captured by the collector via AsyncLocalStorage.
|
|
21
|
+
* After rendering, the middleware injects the collected CSS into </head>.
|
|
22
|
+
*
|
|
23
|
+
* @example Manual middleware setup
|
|
24
|
+
* ```ts
|
|
25
|
+
* // src/middleware.ts
|
|
26
|
+
* import { tastyMiddleware } from '@tenphi/tasty/ssr/astro';
|
|
27
|
+
* export const onRequest = tastyMiddleware();
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example Composing with other middleware
|
|
31
|
+
* ```ts
|
|
32
|
+
* // src/middleware.ts
|
|
33
|
+
* import { sequence } from 'astro:middleware';
|
|
34
|
+
* import { tastyMiddleware } from '@tenphi/tasty/ssr/astro';
|
|
35
|
+
*
|
|
36
|
+
* export const onRequest = sequence(
|
|
37
|
+
* tastyMiddleware(),
|
|
38
|
+
* myOtherMiddleware,
|
|
39
|
+
* );
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
function tastyMiddleware(options) {
|
|
43
|
+
return async (_context, next) => {
|
|
44
|
+
const transferCache = options?.transferCache ?? true;
|
|
45
|
+
const collector = new ServerStyleCollector();
|
|
46
|
+
const rendered = await runWithCollector(collector, async () => {
|
|
47
|
+
const response = await next();
|
|
48
|
+
const body = response.body;
|
|
49
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
50
|
+
if (!body || !contentType.includes("text/html")) return { response };
|
|
51
|
+
const reader = body.pipeThrough(new TextDecoderStream()).getReader();
|
|
52
|
+
const parts = [];
|
|
53
|
+
for (;;) {
|
|
54
|
+
const { done, value } = await reader.read();
|
|
55
|
+
if (done) break;
|
|
56
|
+
parts.push(value);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
html: parts.join(""),
|
|
60
|
+
status: response.status,
|
|
61
|
+
headers: response.headers
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
if ("response" in rendered) return rendered.response;
|
|
65
|
+
if (!rendered.html) return new Response(null, {
|
|
66
|
+
status: rendered.status,
|
|
67
|
+
headers: rendered.headers
|
|
68
|
+
});
|
|
69
|
+
let { html } = rendered;
|
|
70
|
+
const css = collector.getCSS();
|
|
71
|
+
if (!css) return new Response(html, {
|
|
72
|
+
status: rendered.status,
|
|
73
|
+
headers: rendered.headers
|
|
74
|
+
});
|
|
75
|
+
const nonce = getConfig().nonce;
|
|
76
|
+
const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
77
|
+
const styleTag = `<style data-tasty-ssr${nonceAttr}>${css}</style>`;
|
|
78
|
+
let cacheTag = "";
|
|
79
|
+
if (transferCache) {
|
|
80
|
+
const classNames = collector.getRenderedClassNames();
|
|
81
|
+
if (classNames.length > 0) cacheTag = `<script${nonceAttr}>(window.__TASTY__=window.__TASTY__||[]).push(${classNames.map((n) => `"${n}"`).join(",")})<\/script>`;
|
|
82
|
+
}
|
|
83
|
+
const injection = styleTag + cacheTag;
|
|
84
|
+
const idx = html.indexOf("</head>");
|
|
85
|
+
if (idx !== -1) html = html.slice(0, idx) + injection + html.slice(idx);
|
|
86
|
+
else html = injection + html;
|
|
87
|
+
const headers = new Headers(rendered.headers);
|
|
88
|
+
headers.delete("content-length");
|
|
89
|
+
return new Response(html, {
|
|
90
|
+
status: rendered.status,
|
|
91
|
+
headers
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Package subpaths of the middleware entrypoints registered by
|
|
97
|
+
* `tastyIntegration()`.
|
|
98
|
+
*
|
|
99
|
+
* These must be bare specifiers rather than
|
|
100
|
+
* `new URL('./astro-middleware.js', import.meta.url)`. The bundler is free to
|
|
101
|
+
* hoist `tastyIntegration` into a shared chunk at a different directory depth
|
|
102
|
+
* than `dist/ssr/`, which makes a relative URL resolve to a file that does not
|
|
103
|
+
* exist and breaks the build for every consumer. A package subpath is resolved
|
|
104
|
+
* by the consumer through our `exports` map, so it never depends on the
|
|
105
|
+
* chunk layout.
|
|
106
|
+
*
|
|
107
|
+
* There are two entrypoints instead of one parameterised entrypoint because
|
|
108
|
+
* `addMiddleware()` cannot pass options: the integration runs when the Astro
|
|
109
|
+
* config is loaded, while the middleware module is evaluated in the server
|
|
110
|
+
* runtime — a different process for built output — so module-level state set
|
|
111
|
+
* by the integration is not visible to the middleware.
|
|
112
|
+
*/
|
|
113
|
+
const MIDDLEWARE_ENTRYPOINT = "@tenphi/tasty/ssr/astro-middleware";
|
|
114
|
+
const MIDDLEWARE_ENTRYPOINT_STATIC = "@tenphi/tasty/ssr/astro-middleware-static";
|
|
115
|
+
/**
|
|
116
|
+
* Astro integration that automatically sets up Tasty SSR.
|
|
117
|
+
*
|
|
118
|
+
* Registers middleware for cross-component CSS deduplication and
|
|
119
|
+
* optionally injects a client hydration script for island support.
|
|
120
|
+
*
|
|
121
|
+
* @example Basic setup (with islands)
|
|
122
|
+
* ```ts
|
|
123
|
+
* // astro.config.mjs
|
|
124
|
+
* import { tastyIntegration } from '@tenphi/tasty/ssr/astro';
|
|
125
|
+
*
|
|
126
|
+
* export default defineConfig({
|
|
127
|
+
* integrations: [tastyIntegration()],
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* @example Static-only (no client JS)
|
|
132
|
+
* ```ts
|
|
133
|
+
* // astro.config.mjs
|
|
134
|
+
* import { tastyIntegration } from '@tenphi/tasty/ssr/astro';
|
|
135
|
+
*
|
|
136
|
+
* export default defineConfig({
|
|
137
|
+
* integrations: [tastyIntegration({ islands: false })],
|
|
138
|
+
* });
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
function tastyIntegration(options) {
|
|
142
|
+
const { islands = true } = options ?? {};
|
|
143
|
+
return {
|
|
144
|
+
name: "@tenphi/tasty",
|
|
145
|
+
hooks: { "astro:config:setup": ({ addMiddleware, injectScript }) => {
|
|
146
|
+
addMiddleware({
|
|
147
|
+
entrypoint: islands ? MIDDLEWARE_ENTRYPOINT : MIDDLEWARE_ENTRYPOINT_STATIC,
|
|
148
|
+
order: "pre"
|
|
149
|
+
});
|
|
150
|
+
if (islands) injectScript("before-hydration", `import "@tenphi/tasty/ssr/astro-client";`);
|
|
151
|
+
} }
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
2
155
|
export { tastyIntegration, tastyMiddleware };
|
|
156
|
+
|
|
157
|
+
//# sourceMappingURL=astro.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astro.js","names":[],"sources":["../../src/ssr/astro.ts"],"sourcesContent":["/**\n * Astro integration for Tasty SSR.\n *\n * Provides:\n * - tastyIntegration() — Astro Integration API (recommended)\n * - tastyMiddleware() — manual middleware for advanced composition\n *\n * Import from '@tenphi/tasty/ssr/astro'.\n */\n\nimport { getConfig } from '../config';\nimport { getSSRCollector, runWithCollector } from './async-storage';\nimport { ServerStyleCollector } from './collector';\nimport { registerSSRCollectorGetterGlobal } from './ssr-collector-ref';\n\n// Wire up ALS-based collector discovery so computeStyles() can find\n// the collector set by tastyMiddleware's runWithCollector().\n// Uses globalThis so the getter is visible across Astro's separate\n// module graphs (middleware vs page components).\nregisterSSRCollectorGetterGlobal(getSSRCollector);\n\nexport interface TastyMiddlewareOptions {\n /**\n * Whether to embed the class-list script for client hydration.\n * Set to false to skip class transfer (e.g. for CSP restrictions).\n * Without it, client components may re-inject CSS that already exists\n * in server-rendered `<style>` tags. Default: true.\n */\n transferCache?: boolean;\n}\n\n/**\n * Create an Astro middleware that collects Tasty styles during SSR.\n *\n * All React components rendered during the request will have their\n * computeStyles() calls captured by the collector via AsyncLocalStorage.\n * After rendering, the middleware injects the collected CSS into </head>.\n *\n * @example Manual middleware setup\n * ```ts\n * // src/middleware.ts\n * import { tastyMiddleware } from '@tenphi/tasty/ssr/astro';\n * export const onRequest = tastyMiddleware();\n * ```\n *\n * @example Composing with other middleware\n * ```ts\n * // src/middleware.ts\n * import { sequence } from 'astro:middleware';\n * import { tastyMiddleware } from '@tenphi/tasty/ssr/astro';\n *\n * export const onRequest = sequence(\n * tastyMiddleware(),\n * myOtherMiddleware,\n * );\n * ```\n */\nexport function tastyMiddleware(options?: TastyMiddlewareOptions) {\n return async (\n _context: unknown,\n next: () => Promise<Response>,\n ): Promise<Response> => {\n const transferCache = options?.transferCache ?? true;\n const collector = new ServerStyleCollector();\n\n // Run the entire request — including body stream consumption — inside\n // the ALS context so that components rendering lazily during stream\n // reads can still find the collector via getSSRCollector().\n type Rendered =\n | { response: Response }\n | { html: string | null; status: number; headers: Headers };\n\n const rendered = await runWithCollector<Promise<Rendered>>(\n collector,\n async (): Promise<Rendered> => {\n const response = await next();\n const body = response.body;\n\n // Only process HTML responses. Reading a non-HTML body (e.g. an\n // image, font, or JSON endpoint) as UTF-8 text corrupts binary\n // payloads: every byte >= 0x80 is decoded to U+FFFD and re-encoded\n // as EF BF BD. Pass anything that isn't HTML straight through.\n const contentType = response.headers.get('content-type') ?? '';\n if (!body || !contentType.includes('text/html')) {\n return { response };\n }\n\n const reader = body.pipeThrough(new TextDecoderStream()).getReader();\n const parts: string[] = [];\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n parts.push(value);\n }\n return {\n html: parts.join(''),\n status: response.status,\n headers: response.headers,\n };\n },\n );\n\n // Non-HTML responses are returned untouched to avoid corrupting\n // binary payloads.\n if ('response' in rendered) {\n return rendered.response;\n }\n\n if (!rendered.html) {\n return new Response(null, {\n status: rendered.status,\n headers: rendered.headers,\n });\n }\n\n let { html } = rendered;\n\n const css = collector.getCSS();\n if (!css) {\n return new Response(html, {\n status: rendered.status,\n headers: rendered.headers,\n });\n }\n\n const nonce = getConfig().nonce;\n const nonceAttr = nonce ? ` nonce=\"${nonce}\"` : '';\n const styleTag = `<style data-tasty-ssr${nonceAttr}>${css}</style>`;\n\n let cacheTag = '';\n if (transferCache) {\n const classNames = collector.getRenderedClassNames();\n if (classNames.length > 0) {\n const classListJSON = classNames.map((n) => `\"${n}\"`).join(',');\n cacheTag = `<script${nonceAttr}>(window.__TASTY__=window.__TASTY__||[]).push(${classListJSON})</script>`;\n }\n }\n\n const injection = styleTag + cacheTag;\n const idx = html.indexOf('</head>');\n if (idx !== -1) {\n html = html.slice(0, idx) + injection + html.slice(idx);\n } else {\n html = injection + html;\n }\n\n const headers = new Headers(rendered.headers);\n headers.delete('content-length');\n\n return new Response(html, {\n status: rendered.status,\n headers,\n });\n };\n}\n\n// ============================================================================\n// Astro Integration API\n// ============================================================================\n\n/**\n * Package subpaths of the middleware entrypoints registered by\n * `tastyIntegration()`.\n *\n * These must be bare specifiers rather than\n * `new URL('./astro-middleware.js', import.meta.url)`. The bundler is free to\n * hoist `tastyIntegration` into a shared chunk at a different directory depth\n * than `dist/ssr/`, which makes a relative URL resolve to a file that does not\n * exist and breaks the build for every consumer. A package subpath is resolved\n * by the consumer through our `exports` map, so it never depends on the\n * chunk layout.\n *\n * There are two entrypoints instead of one parameterised entrypoint because\n * `addMiddleware()` cannot pass options: the integration runs when the Astro\n * config is loaded, while the middleware module is evaluated in the server\n * runtime — a different process for built output — so module-level state set\n * by the integration is not visible to the middleware.\n */\nconst MIDDLEWARE_ENTRYPOINT = '@tenphi/tasty/ssr/astro-middleware';\nconst MIDDLEWARE_ENTRYPOINT_STATIC =\n '@tenphi/tasty/ssr/astro-middleware-static';\n\nexport interface TastyIntegrationOptions {\n /**\n * Enable island hydration support.\n *\n * When `true` (default): injects a client hydration script via\n * `injectScript('before-hydration')` and sets `transferCache: true`\n * on the middleware. Islands skip the style pipeline during hydration.\n *\n * When `false`: no client JS is shipped and `transferCache` is set\n * to `false`. Use this for fully static sites without `client:*`\n * directives.\n */\n islands?: boolean;\n}\n\n/**\n * Astro integration that automatically sets up Tasty SSR.\n *\n * Registers middleware for cross-component CSS deduplication and\n * optionally injects a client hydration script for island support.\n *\n * @example Basic setup (with islands)\n * ```ts\n * // astro.config.mjs\n * import { tastyIntegration } from '@tenphi/tasty/ssr/astro';\n *\n * export default defineConfig({\n * integrations: [tastyIntegration()],\n * });\n * ```\n *\n * @example Static-only (no client JS)\n * ```ts\n * // astro.config.mjs\n * import { tastyIntegration } from '@tenphi/tasty/ssr/astro';\n *\n * export default defineConfig({\n * integrations: [tastyIntegration({ islands: false })],\n * });\n * ```\n */\nexport function tastyIntegration(options?: TastyIntegrationOptions): {\n name: string;\n hooks: Record<string, (...args: never[]) => void>;\n} {\n const { islands = true } = options ?? {};\n\n return {\n name: '@tenphi/tasty',\n hooks: {\n 'astro:config:setup': ({\n addMiddleware,\n injectScript,\n }: {\n addMiddleware: (middleware: {\n entrypoint: string | URL;\n order: 'pre' | 'post';\n }) => void;\n injectScript: (\n stage: 'head-inline' | 'before-hydration' | 'page' | 'page-ssr',\n content: string,\n ) => void;\n }) => {\n addMiddleware({\n entrypoint: islands\n ? MIDDLEWARE_ENTRYPOINT\n : MIDDLEWARE_ENTRYPOINT_STATIC,\n order: 'pre',\n });\n\n if (islands) {\n injectScript(\n 'before-hydration',\n `import \"@tenphi/tasty/ssr/astro-client\";`,\n );\n }\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAmBA,iCAAiC,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsChD,SAAgB,gBAAgB,SAAkC;CAChE,OAAO,OACL,UACA,SACsB;EACtB,MAAM,gBAAgB,SAAS,iBAAiB;EAChD,MAAM,YAAY,IAAI,qBAAqB;EAS3C,MAAM,WAAW,MAAM,iBACrB,WACA,YAA+B;GAC7B,MAAM,WAAW,MAAM,KAAK;GAC5B,MAAM,OAAO,SAAS;GAMtB,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;GAC5D,IAAI,CAAC,QAAQ,CAAC,YAAY,SAAS,WAAW,GAC5C,OAAO,EAAE,SAAS;GAGpB,MAAM,SAAS,KAAK,YAAY,IAAI,kBAAkB,CAAC,CAAC,CAAC,UAAU;GACnE,MAAM,QAAkB,CAAC;GACzB,SAAS;IACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;IAC1C,IAAI,MAAM;IACV,MAAM,KAAK,KAAK;GAClB;GACA,OAAO;IACL,MAAM,MAAM,KAAK,EAAE;IACnB,QAAQ,SAAS;IACjB,SAAS,SAAS;GACpB;EACF,CACF;EAIA,IAAI,cAAc,UAChB,OAAO,SAAS;EAGlB,IAAI,CAAC,SAAS,MACZ,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ,SAAS;GACjB,SAAS,SAAS;EACpB,CAAC;EAGH,IAAI,EAAE,SAAS;EAEf,MAAM,MAAM,UAAU,OAAO;EAC7B,IAAI,CAAC,KACH,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ,SAAS;GACjB,SAAS,SAAS;EACpB,CAAC;EAGH,MAAM,QAAQ,UAAU,CAAC,CAAC;EAC1B,MAAM,YAAY,QAAQ,WAAW,MAAM,KAAK;EAChD,MAAM,WAAW,wBAAwB,UAAU,GAAG,IAAI;EAE1D,IAAI,WAAW;EACf,IAAI,eAAe;GACjB,MAAM,aAAa,UAAU,sBAAsB;GACnD,IAAI,WAAW,SAAS,GAEtB,WAAW,UAAU,UAAU,gDADT,WAAW,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,GACgC,EAAE;EAEjG;EAEA,MAAM,YAAY,WAAW;EAC7B,MAAM,MAAM,KAAK,QAAQ,SAAS;EAClC,IAAI,QAAQ,IACV,OAAO,KAAK,MAAM,GAAG,GAAG,IAAI,YAAY,KAAK,MAAM,GAAG;OAEtD,OAAO,YAAY;EAGrB,MAAM,UAAU,IAAI,QAAQ,SAAS,OAAO;EAC5C,QAAQ,OAAO,gBAAgB;EAE/B,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ,SAAS;GACjB;EACF,CAAC;CACH;AACF;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,wBAAwB;AAC9B,MAAM,+BACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CF,SAAgB,iBAAiB,SAG/B;CACA,MAAM,EAAE,UAAU,SAAS,WAAW,CAAC;CAEvC,OAAO;EACL,MAAM;EACN,OAAO,EACL,uBAAuB,EACrB,eACA,mBAUI;GACJ,cAAc;IACZ,YAAY,UACR,wBACA;IACJ,OAAO;GACT,CAAC;GAED,IAAI,SACF,aACE,oBACA,0CACF;EAEJ,EACF;CACF;AACF"}
|
package/dist/ssr/index.d.ts
CHANGED
package/dist/ssr/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as registerSSRCollectorGetterGlobal } from "../format-rules-
|
|
2
|
-
import { n as createServerStyleCollector, t as ServerStyleCollector } from "../collector-
|
|
1
|
+
import { a as registerSSRCollectorGetterGlobal } from "../format-rules-Cb0YIjyS.js";
|
|
2
|
+
import { n as createServerStyleCollector, t as ServerStyleCollector } from "../collector-BpkjNQDo.js";
|
|
3
3
|
import { n as runWithCollector, t as getSSRCollector } from "../async-storage-DKK-wTD4.js";
|
|
4
|
-
import { t as hydrateTastyClasses } from "../hydrate-
|
|
4
|
+
import { t as hydrateTastyClasses } from "../hydrate-xnaB3SDm.js";
|
|
5
5
|
//#region src/ssr/index.ts
|
|
6
6
|
registerSSRCollectorGetterGlobal(getSSRCollector);
|
|
7
7
|
//#endregion
|
package/dist/ssr/next.d.ts
CHANGED
package/dist/ssr/next.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { n as getConfig } from "../config-
|
|
3
|
-
import { i as registerSSRCollectorGetter } from "../format-rules-
|
|
2
|
+
import { n as getConfig } from "../config-DOCuTykY.js";
|
|
3
|
+
import { i as registerSSRCollectorGetter } from "../format-rules-Cb0YIjyS.js";
|
|
4
4
|
import { t as getTastySSRContext } from "../context-CA8YKeMn.js";
|
|
5
|
-
import { t as ServerStyleCollector } from "../collector-
|
|
6
|
-
import { t as hydrateTastyClasses } from "../hydrate-
|
|
5
|
+
import { t as ServerStyleCollector } from "../collector-BpkjNQDo.js";
|
|
6
|
+
import { t as hydrateTastyClasses } from "../hydrate-xnaB3SDm.js";
|
|
7
7
|
import { Fragment, createElement, useState } from "react";
|
|
8
8
|
import { useServerInsertedHTML } from "next/navigation";
|
|
9
9
|
//#region src/ssr/next.ts
|
package/dist/static/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as Styles } from "../index-
|
|
2
|
-
import { t as mergeStyles } from "../merge-styles-
|
|
1
|
+
import { b as Styles } from "../index-KUYya3x7.js";
|
|
2
|
+
import { t as mergeStyles } from "../merge-styles-DLm4wdnb.js";
|
|
3
3
|
|
|
4
4
|
//#region src/static/types.d.ts
|
|
5
5
|
/**
|
package/dist/static/index.js
CHANGED
package/dist/zero/babel.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as _default, r as TastyZeroConfig, t as TastyZeroBabelOptions } from "../babel-
|
|
1
|
+
import { n as _default, r as TastyZeroConfig, t as TastyZeroBabelOptions } from "../babel-R2qT7yLN.js";
|
|
2
2
|
export { TastyZeroBabelOptions, type TastyZeroConfig, _default as default };
|
package/dist/zero/babel.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { b as resetConfig, d as getGlobalStyles, i as getGlobalConfigTokens, s as getGlobalFunctions, t as configure } from "../config-
|
|
2
|
-
import { t as mergeStyles } from "../merge-styles
|
|
3
|
-
import { t as resolveRecipes } from "../resolve-recipes-
|
|
4
|
-
import { a as extractFunctionsFromStyles, c as extractStylesForSelector, i as extractFontFaceFromStyles, l as extractStylesWithChunks, o as extractKeyframesFromStyles, r as extractCounterStyleFromStyles, s as extractPropertiesFromStyles, t as CSSWriter, u as setExtractorNamePrefix } from "../css-writer-
|
|
1
|
+
import { b as resetConfig, d as getGlobalStyles, i as getGlobalConfigTokens, s as getGlobalFunctions, t as configure } from "../config-DOCuTykY.js";
|
|
2
|
+
import { t as mergeStyles } from "../merge-styles-B0lMso5W.js";
|
|
3
|
+
import { t as resolveRecipes } from "../resolve-recipes-C9nAuwgR.js";
|
|
4
|
+
import { a as extractFunctionsFromStyles, c as extractStylesForSelector, i as extractFontFaceFromStyles, l as extractStylesWithChunks, o as extractKeyframesFromStyles, r as extractCounterStyleFromStyles, s as extractPropertiesFromStyles, t as CSSWriter, u as setExtractorNamePrefix } from "../css-writer-BHjTF0YN.js";
|
|
5
5
|
import * as fs from "fs";
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import { declare } from "@babel/helper-plugin-utils";
|
package/dist/zero/index.d.ts
CHANGED
package/dist/zero/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { c as extractStylesForSelector, l as extractStylesWithChunks, n as createCSSWriter, t as CSSWriter } from "../css-writer-
|
|
1
|
+
import { c as extractStylesForSelector, l as extractStylesWithChunks, n as createCSSWriter, t as CSSWriter } from "../css-writer-BHjTF0YN.js";
|
|
2
2
|
export { CSSWriter, createCSSWriter, extractStylesForSelector, extractStylesWithChunks };
|
package/dist/zero/next.d.ts
CHANGED
package/docs/ai-agents.md
CHANGED
|
@@ -70,6 +70,9 @@ The last row goes the other way — longhands over the shorthand — because `fl
|
|
|
70
70
|
- ❌ `#f5f5f5`, `rgb(0 0 0)`, `oklch(…)`, `okhsl(…)`, `red` → ✅ `#surface` (add the token to the config if it doesn't exist).
|
|
71
71
|
- ❌ `var(--gap)` → ✅ `$gap` · ❌ `$accent-color` → ✅ `#accent` · ❌ `transparent` → ✅ `#clear` · ❌ `currentColor` → ✅ `#current`.
|
|
72
72
|
- A `$name` must be declared as a `'$name': value` key in the same styles object, or in the config.
|
|
73
|
+
- Names are case-sensitive and start lowercase — `$myVar` → `--myVar`; a leading capital folds (`$Foo` → `--foo`). Prefer kebab-case.
|
|
74
|
+
- A `$name` reference is untyped: it fills the first free slot in a shorthand (`border: '1bw $my-style'` → the line style). Write colors as `#name`; `$name-color` is a fallback for pointing at a raw CSS custom property that holds a color.
|
|
75
|
+
- `preset` and `transition` take token *names*, not values, so a `$name` cannot stand in for one (it warns in dev and is ignored).
|
|
73
76
|
|
|
74
77
|
### Units
|
|
75
78
|
|
package/docs/configuration.md
CHANGED
|
@@ -164,6 +164,7 @@ configure({
|
|
|
164
164
|
|
|
165
165
|
- `$name` keys become `--name` CSS custom properties
|
|
166
166
|
- `#name` keys become `--name-color` and `--name-color-{colorSpace}` properties (suffix depends on `colorSpace`, default `oklch`)
|
|
167
|
+
- Names keep their case, since CSS custom properties are case-sensitive: `$myVar` is `--myVar` and is referenced as `$myVar`. A leading capital is not supported and folds — `$Foo` and `#Purple` become `--foo` and `--purple-color` — so start names lowercase. Kebab-case (`$my-var`) remains the convention.
|
|
167
168
|
|
|
168
169
|
Tokens are automatically emitted in all rendering modes: runtime (client), SSR, and zero-runtime (Babel plugin).
|
|
169
170
|
|
package/docs/ssr.md
CHANGED
|
@@ -354,6 +354,7 @@ const stream = await runWithCollector(collector, () =>
|
|
|
354
354
|
| `@tenphi/tasty/ssr/next` | Next.js App Router: `TastyRegistry` component |
|
|
355
355
|
| `@tenphi/tasty/ssr/astro` | Astro: `tastyIntegration`, `tastyMiddleware` |
|
|
356
356
|
| `@tenphi/tasty/ssr/astro-client` | Astro: client-side cache hydration (auto-injected by integration, or import manually) |
|
|
357
|
+
| `@tenphi/tasty/ssr/astro-middleware`<br>`@tenphi/tasty/ssr/astro-middleware-static` | Astro: the middleware entrypoints `tastyIntegration()` registers via `addMiddleware()`. Exported so Astro can resolve them by specifier; you should not import them. For manual setups use `tastyMiddleware()`. |
|
|
357
358
|
|
|
358
359
|
### `ServerStyleCollector`
|
|
359
360
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenphi/tasty",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "A design-system-integrated styling system and DSL for concise, state-aware UI styling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -62,6 +62,16 @@
|
|
|
62
62
|
"import": "./dist/ssr/astro-client.js",
|
|
63
63
|
"default": "./dist/ssr/astro-client.js"
|
|
64
64
|
},
|
|
65
|
+
"./ssr/astro-middleware": {
|
|
66
|
+
"types": "./dist/ssr/astro-middleware.d.ts",
|
|
67
|
+
"import": "./dist/ssr/astro-middleware.js",
|
|
68
|
+
"default": "./dist/ssr/astro-middleware.js"
|
|
69
|
+
},
|
|
70
|
+
"./ssr/astro-middleware-static": {
|
|
71
|
+
"types": "./dist/ssr/astro-middleware-static.d.ts",
|
|
72
|
+
"import": "./dist/ssr/astro-middleware-static.js",
|
|
73
|
+
"default": "./dist/ssr/astro-middleware-static.js"
|
|
74
|
+
},
|
|
65
75
|
"./tasty.config": "./tasty.config.ts"
|
|
66
76
|
},
|
|
67
77
|
"files": [
|
|
@@ -73,7 +83,9 @@
|
|
|
73
83
|
"./dist/ssr/index.js",
|
|
74
84
|
"./dist/ssr/next.js",
|
|
75
85
|
"./dist/ssr/astro.js",
|
|
76
|
-
"./dist/ssr/astro-client.js"
|
|
86
|
+
"./dist/ssr/astro-client.js",
|
|
87
|
+
"./dist/ssr/astro-middleware.js",
|
|
88
|
+
"./dist/ssr/astro-middleware-static.js"
|
|
77
89
|
],
|
|
78
90
|
"engines": {
|
|
79
91
|
"node": ">=20"
|
|
@@ -146,39 +158,39 @@
|
|
|
146
158
|
"@types/babel__helper-plugin-utils": "^7.10.3",
|
|
147
159
|
"@types/node": "^25.3.2",
|
|
148
160
|
"@types/react": "^19.0.0",
|
|
161
|
+
"@vitest/browser-playwright": "^4.1.10",
|
|
149
162
|
"eslint": "^10.0.0",
|
|
150
163
|
"eslint-config-prettier": "^10.1.8",
|
|
151
|
-
"happy-dom": "^20.9.0",
|
|
152
164
|
"jiti": "^2.6.1",
|
|
153
|
-
"jsdom": "^29.0.2",
|
|
154
165
|
"knip": "^5.61.3",
|
|
155
166
|
"next": "^16.0.0",
|
|
167
|
+
"playwright": "^1.62.1",
|
|
156
168
|
"prettier": "^3.8.1",
|
|
157
169
|
"react": "^19.0.0",
|
|
158
170
|
"size-limit": "^12.0.0",
|
|
159
171
|
"tsdown": "^0.22.0",
|
|
160
172
|
"typescript": "^6.0.2",
|
|
161
173
|
"typescript-eslint": "^8.56.0",
|
|
162
|
-
"vitest": "^4.
|
|
174
|
+
"vitest": "^4.1.10"
|
|
163
175
|
},
|
|
164
176
|
"size-limit": [
|
|
165
177
|
{
|
|
166
178
|
"name": "main (import *)",
|
|
167
179
|
"path": "dist/index.js",
|
|
168
180
|
"import": "*",
|
|
169
|
-
"limit": "57 kB"
|
|
181
|
+
"limit": "57.5 kB"
|
|
170
182
|
},
|
|
171
183
|
{
|
|
172
184
|
"name": "core (import *)",
|
|
173
185
|
"path": "dist/core/index.js",
|
|
174
186
|
"import": "*",
|
|
175
|
-
"limit": "54 kB"
|
|
187
|
+
"limit": "54.5 kB"
|
|
176
188
|
},
|
|
177
189
|
{
|
|
178
190
|
"name": "static",
|
|
179
191
|
"path": "dist/static/index.js",
|
|
180
192
|
"import": "*",
|
|
181
|
-
"limit": "18.
|
|
193
|
+
"limit": "18.75 kB"
|
|
182
194
|
},
|
|
183
195
|
{
|
|
184
196
|
"name": "zero",
|
|
@@ -189,7 +201,7 @@
|
|
|
189
201
|
"path",
|
|
190
202
|
"crypto"
|
|
191
203
|
],
|
|
192
|
-
"limit": "33 kB"
|
|
204
|
+
"limit": "33.25 kB"
|
|
193
205
|
},
|
|
194
206
|
{
|
|
195
207
|
"name": "babel-plugin",
|
|
@@ -200,12 +212,15 @@
|
|
|
200
212
|
"path",
|
|
201
213
|
"crypto"
|
|
202
214
|
],
|
|
203
|
-
"limit": "50.
|
|
215
|
+
"limit": "50.75 kB"
|
|
204
216
|
}
|
|
205
217
|
],
|
|
206
218
|
"scripts": {
|
|
207
219
|
"build": "tsdown",
|
|
208
220
|
"test": "vitest run",
|
|
221
|
+
"test:node": "vitest run --project node",
|
|
222
|
+
"test:browser": "vitest run --project browser",
|
|
223
|
+
"test:setup": "playwright install chromium",
|
|
209
224
|
"test:watch": "vitest",
|
|
210
225
|
"test:coverage": "vitest run --coverage",
|
|
211
226
|
"typecheck": "tsc --noEmit",
|
|
@@ -214,7 +229,8 @@
|
|
|
214
229
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
215
230
|
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
|
|
216
231
|
"size": "size-limit",
|
|
217
|
-
"bench": "vitest bench",
|
|
232
|
+
"bench": "vitest bench --project node",
|
|
233
|
+
"bench:browser": "vitest bench --project browser",
|
|
218
234
|
"changeset": "changeset",
|
|
219
235
|
"version": "changeset version",
|
|
220
236
|
"release": "changeset publish",
|
package/dist/astro-B53trJyX.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { n as getConfig } from "./config-CCcE_tqx.js";
|
|
2
|
-
import { a as registerSSRCollectorGetterGlobal } from "./format-rules-BbKDjsfO.js";
|
|
3
|
-
import { t as ServerStyleCollector } from "./collector-D14DcZx9.js";
|
|
4
|
-
import { n as runWithCollector, t as getSSRCollector } from "./async-storage-DKK-wTD4.js";
|
|
5
|
-
//#region src/ssr/astro-transfer-cache.ts
|
|
6
|
-
/**
|
|
7
|
-
* Internal module-level state for the Astro middleware transfer-cache flag.
|
|
8
|
-
*
|
|
9
|
-
* Set by `tastyIntegration` and read by `astro-middleware.ts`. Kept in a
|
|
10
|
-
* separate non-exported module so it does not appear on the public API
|
|
11
|
-
* surface of `@tenphi/tasty/ssr/astro`.
|
|
12
|
-
*/
|
|
13
|
-
let _middlewareTransferCache = true;
|
|
14
|
-
/** @internal */
|
|
15
|
-
function setMiddlewareTransferCache(value) {
|
|
16
|
-
_middlewareTransferCache = value;
|
|
17
|
-
}
|
|
18
|
-
/** @internal */
|
|
19
|
-
function getMiddlewareTransferCache() {
|
|
20
|
-
return _middlewareTransferCache;
|
|
21
|
-
}
|
|
22
|
-
//#endregion
|
|
23
|
-
//#region src/ssr/astro.ts
|
|
24
|
-
/**
|
|
25
|
-
* Astro integration for Tasty SSR.
|
|
26
|
-
*
|
|
27
|
-
* Provides:
|
|
28
|
-
* - tastyIntegration() — Astro Integration API (recommended)
|
|
29
|
-
* - tastyMiddleware() — manual middleware for advanced composition
|
|
30
|
-
*
|
|
31
|
-
* Import from '@tenphi/tasty/ssr/astro'.
|
|
32
|
-
*/
|
|
33
|
-
registerSSRCollectorGetterGlobal(getSSRCollector);
|
|
34
|
-
/**
|
|
35
|
-
* Create an Astro middleware that collects Tasty styles during SSR.
|
|
36
|
-
*
|
|
37
|
-
* All React components rendered during the request will have their
|
|
38
|
-
* computeStyles() calls captured by the collector via AsyncLocalStorage.
|
|
39
|
-
* After rendering, the middleware injects the collected CSS into </head>.
|
|
40
|
-
*
|
|
41
|
-
* @example Manual middleware setup
|
|
42
|
-
* ```ts
|
|
43
|
-
* // src/middleware.ts
|
|
44
|
-
* import { tastyMiddleware } from '@tenphi/tasty/ssr/astro';
|
|
45
|
-
* export const onRequest = tastyMiddleware();
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @example Composing with other middleware
|
|
49
|
-
* ```ts
|
|
50
|
-
* // src/middleware.ts
|
|
51
|
-
* import { sequence } from 'astro:middleware';
|
|
52
|
-
* import { tastyMiddleware } from '@tenphi/tasty/ssr/astro';
|
|
53
|
-
*
|
|
54
|
-
* export const onRequest = sequence(
|
|
55
|
-
* tastyMiddleware(),
|
|
56
|
-
* myOtherMiddleware,
|
|
57
|
-
* );
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
function tastyMiddleware(options) {
|
|
61
|
-
return async (_context, next) => {
|
|
62
|
-
const transferCache = options?.transferCache ?? true;
|
|
63
|
-
const collector = new ServerStyleCollector();
|
|
64
|
-
const rendered = await runWithCollector(collector, async () => {
|
|
65
|
-
const response = await next();
|
|
66
|
-
const body = response.body;
|
|
67
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
68
|
-
if (!body || !contentType.includes("text/html")) return { response };
|
|
69
|
-
const reader = body.pipeThrough(new TextDecoderStream()).getReader();
|
|
70
|
-
const parts = [];
|
|
71
|
-
for (;;) {
|
|
72
|
-
const { done, value } = await reader.read();
|
|
73
|
-
if (done) break;
|
|
74
|
-
parts.push(value);
|
|
75
|
-
}
|
|
76
|
-
return {
|
|
77
|
-
html: parts.join(""),
|
|
78
|
-
status: response.status,
|
|
79
|
-
headers: response.headers
|
|
80
|
-
};
|
|
81
|
-
});
|
|
82
|
-
if ("response" in rendered) return rendered.response;
|
|
83
|
-
if (!rendered.html) return new Response(null, {
|
|
84
|
-
status: rendered.status,
|
|
85
|
-
headers: rendered.headers
|
|
86
|
-
});
|
|
87
|
-
let { html } = rendered;
|
|
88
|
-
const css = collector.getCSS();
|
|
89
|
-
if (!css) return new Response(html, {
|
|
90
|
-
status: rendered.status,
|
|
91
|
-
headers: rendered.headers
|
|
92
|
-
});
|
|
93
|
-
const nonce = getConfig().nonce;
|
|
94
|
-
const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
95
|
-
const styleTag = `<style data-tasty-ssr${nonceAttr}>${css}</style>`;
|
|
96
|
-
let cacheTag = "";
|
|
97
|
-
if (transferCache) {
|
|
98
|
-
const classNames = collector.getRenderedClassNames();
|
|
99
|
-
if (classNames.length > 0) cacheTag = `<script${nonceAttr}>(window.__TASTY__=window.__TASTY__||[]).push(${classNames.map((n) => `"${n}"`).join(",")})<\/script>`;
|
|
100
|
-
}
|
|
101
|
-
const injection = styleTag + cacheTag;
|
|
102
|
-
const idx = html.indexOf("</head>");
|
|
103
|
-
if (idx !== -1) html = html.slice(0, idx) + injection + html.slice(idx);
|
|
104
|
-
else html = injection + html;
|
|
105
|
-
const headers = new Headers(rendered.headers);
|
|
106
|
-
headers.delete("content-length");
|
|
107
|
-
return new Response(html, {
|
|
108
|
-
status: rendered.status,
|
|
109
|
-
headers
|
|
110
|
-
});
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Astro integration that automatically sets up Tasty SSR.
|
|
115
|
-
*
|
|
116
|
-
* Registers middleware for cross-component CSS deduplication and
|
|
117
|
-
* optionally injects a client hydration script for island support.
|
|
118
|
-
*
|
|
119
|
-
* @example Basic setup (with islands)
|
|
120
|
-
* ```ts
|
|
121
|
-
* // astro.config.mjs
|
|
122
|
-
* import { tastyIntegration } from '@tenphi/tasty/ssr/astro';
|
|
123
|
-
*
|
|
124
|
-
* export default defineConfig({
|
|
125
|
-
* integrations: [tastyIntegration()],
|
|
126
|
-
* });
|
|
127
|
-
* ```
|
|
128
|
-
*
|
|
129
|
-
* @example Static-only (no client JS)
|
|
130
|
-
* ```ts
|
|
131
|
-
* // astro.config.mjs
|
|
132
|
-
* import { tastyIntegration } from '@tenphi/tasty/ssr/astro';
|
|
133
|
-
*
|
|
134
|
-
* export default defineConfig({
|
|
135
|
-
* integrations: [tastyIntegration({ islands: false })],
|
|
136
|
-
* });
|
|
137
|
-
* ```
|
|
138
|
-
*/
|
|
139
|
-
function tastyIntegration(options) {
|
|
140
|
-
const { islands = true } = options ?? {};
|
|
141
|
-
setMiddlewareTransferCache(islands);
|
|
142
|
-
return {
|
|
143
|
-
name: "@tenphi/tasty",
|
|
144
|
-
hooks: { "astro:config:setup": ({ addMiddleware, injectScript }) => {
|
|
145
|
-
addMiddleware({
|
|
146
|
-
entrypoint: new URL("./astro-middleware.js", import.meta.url),
|
|
147
|
-
order: "pre"
|
|
148
|
-
});
|
|
149
|
-
if (islands) injectScript("before-hydration", `import "@tenphi/tasty/ssr/astro-client";`);
|
|
150
|
-
} }
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
//#endregion
|
|
154
|
-
export { tastyMiddleware as n, getMiddlewareTransferCache as r, tastyIntegration as t };
|
|
155
|
-
|
|
156
|
-
//# sourceMappingURL=astro-B53trJyX.js.map
|