@stacksjs/stx 0.2.176 → 0.2.178
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/dist/builtins/attrs.d.ts +19 -0
- package/dist/builtins/attrs.js +18 -0
- package/dist/builtins/safe-image.js +2 -1
- package/dist/builtins/stx-image.js +2 -1
- package/dist/builtins/stx-link.js +2 -1
- package/dist/cli-flags.d.ts +34 -0
- package/dist/cli-flags.js +20 -0
- package/dist/cli.js +899 -778
- package/dist/client-script.js +2 -1
- package/dist/component-registry.d.ts +9 -0
- package/dist/component-renderer.js +20 -1
- package/dist/composables/use-fetch.d.ts +6 -1
- package/dist/composables/use-fetch.js +40 -18
- package/dist/composables/use-query.d.ts +7 -2
- package/dist/cookie-serialize.d.ts +40 -0
- package/dist/cookie-serialize.js +18 -0
- package/dist/craft.js +500 -381
- package/dist/crosswind-config.d.ts +13 -0
- package/dist/crosswind-config.js +6 -2
- package/dist/dev-server/crosswind.js +2 -1
- package/dist/edge-runtime.d.ts +2 -9
- package/dist/edge-runtime.js +2 -16
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/page-action.d.ts +10 -20
- package/dist/page-action.js +33 -9
- package/dist/production-server.js +8 -7
- package/dist/pwa.js +452 -333
- package/dist/reactive.js +2 -3
- package/dist/signal-processing.js +37 -6
- package/dist/signals.js +150 -32
- package/dist/ssg.js +465 -346
- package/dist/ssr.js +2 -16
- package/dist/stx-virtual-ts.d.ts +45 -1
- package/dist/stx-virtual-ts.js +75 -5
- package/dist/stx.d.ts +66 -7
- package/dist/template-hydrator.d.ts +1 -1
- package/dist/template-hydrator.js +6 -6
- package/dist/theme-tokens.d.ts +88 -0
- package/dist/theme-tokens.js +71 -0
- package/dist/typecheck.d.ts +6 -1
- package/dist/typecheck.js +7 -6
- package/package.json +5 -5
- package/stx.d.ts +66 -7
|
@@ -46,6 +46,19 @@ export interface MergedCrosswindConfig {
|
|
|
46
46
|
includePreflight: boolean;
|
|
47
47
|
/** Honours the user's `minify` key (default false). */
|
|
48
48
|
minify: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* The `:root` / `.dark` declarations backing the role tokens (#1930).
|
|
51
|
+
*
|
|
52
|
+
* Returned rather than folded into `preflights` because a project can set
|
|
53
|
+
* `preflight: false`, and the tokens are not preflight — they are the values
|
|
54
|
+
* the generated utilities resolve against. Callers prepend this to the CSS
|
|
55
|
+
* they emit.
|
|
56
|
+
*
|
|
57
|
+
* Missing it degrades rather than breaks: every token carries its light value
|
|
58
|
+
* as the `var()` fallback, so light mode stays correct and dark mode reverts
|
|
59
|
+
* to the light colour.
|
|
60
|
+
*/
|
|
61
|
+
tokenCSS: string;
|
|
49
62
|
}
|
|
50
63
|
/**
|
|
51
64
|
* Merge a project's crosswind config over the package defaults.
|
package/dist/crosswind-config.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { semanticColors, semanticTokenCSS } from "./theme-tokens.js";
|
|
1
2
|
function isPlainObject(value) {
|
|
2
3
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
4
|
}
|
|
@@ -8,7 +9,9 @@ export function deepMergeThemes(target, source) {
|
|
|
8
9
|
return out;
|
|
9
10
|
}
|
|
10
11
|
export function mergeCrosswindConfig(base = {}, user = {}) {
|
|
11
|
-
const baseTheme = base.theme || {}, userTheme = user.theme || {}, { extend: userExtend, ...userThemeKeys } = userTheme, { extend: baseExtend, ...baseThemeKeys } = baseTheme,
|
|
12
|
+
const baseTheme = base.theme || {}, userTheme = user.theme || {}, { extend: userExtend, ...userThemeKeys } = userTheme, { extend: baseExtend, ...baseThemeKeys } = baseTheme, basePalette = baseThemeKeys.colors || {};
|
|
13
|
+
baseThemeKeys.colors = { ...basePalette, ...semanticColors(basePalette) };
|
|
14
|
+
const theme = deepMergeThemes(baseThemeKeys, userThemeKeys), extend = deepMergeThemes(baseExtend || {}, userExtend || {});
|
|
12
15
|
if (Object.keys(extend).length > 0)
|
|
13
16
|
theme.extend = extend;
|
|
14
17
|
const safelist = [
|
|
@@ -35,6 +38,7 @@ export function mergeCrosswindConfig(base = {}, user = {}) {
|
|
|
35
38
|
safelist,
|
|
36
39
|
shortcuts,
|
|
37
40
|
includePreflight: user.preflight !== !1,
|
|
38
|
-
minify: user.minify === !0
|
|
41
|
+
minify: user.minify === !0,
|
|
42
|
+
tokenCSS: semanticTokenCSS(basePalette)
|
|
39
43
|
};
|
|
40
44
|
}
|
|
@@ -324,7 +324,7 @@ export async function generateCrosswindCSS(htmlContent, appDir) {
|
|
|
324
324
|
configFingerprint = "unhashable";
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
|
-
const baseConfig = hw.defaultConfig || hw.config, userConfig = cachedConfig || {}, merged = mergeCrosswindConfig(baseConfig, userConfig), { safelist, includePreflight, minify } = merged, crosswindConfig = merged.config, generator = new hw.CSSGenerator(crosswindConfig);
|
|
327
|
+
const baseConfig = hw.defaultConfig || hw.config, userConfig = cachedConfig || {}, merged = mergeCrosswindConfig(baseConfig, userConfig), { safelist, includePreflight, minify, tokenCSS } = merged, crosswindConfig = merged.config, generator = new hw.CSSGenerator(crosswindConfig);
|
|
328
328
|
for (const cls of safelist)
|
|
329
329
|
generator.generate(cls);
|
|
330
330
|
for (const className of classes)
|
|
@@ -374,6 +374,7 @@ export async function generateCrosswindCSS(htmlContent, appDir) {
|
|
|
374
374
|
css += `
|
|
375
375
|
@media (prefers-color-scheme: dark) { .dark .${name} { ${darkDecls.join(" ")} } }`;
|
|
376
376
|
}
|
|
377
|
+
css = tokenCSS + css;
|
|
377
378
|
setLruCache(cacheKey, css);
|
|
378
379
|
writeDiskCache(cacheKey, css);
|
|
379
380
|
return css;
|
package/dist/edge-runtime.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SetCookieOptions } from './cookie-serialize';
|
|
1
2
|
/**
|
|
2
3
|
* Detect the current edge runtime platform.
|
|
3
4
|
*/
|
|
@@ -63,15 +64,7 @@ export declare function parseCookies(request: Request): Record<string, string>;
|
|
|
63
64
|
/**
|
|
64
65
|
* Create a Set-Cookie header value.
|
|
65
66
|
*/
|
|
66
|
-
export declare function createCookie(name: string, value: string, options?:
|
|
67
|
-
maxAge?: number
|
|
68
|
-
expires?: Date
|
|
69
|
-
path?: string
|
|
70
|
-
domain?: string
|
|
71
|
-
secure?: boolean
|
|
72
|
-
httpOnly?: boolean
|
|
73
|
-
sameSite?: 'Strict' | 'Lax' | 'None'
|
|
74
|
-
}): string;
|
|
67
|
+
export declare function createCookie(name: string, value: string, options?: SetCookieOptions): string;
|
|
75
68
|
/**
|
|
76
69
|
* JSON response helper.
|
|
77
70
|
*/
|
package/dist/edge-runtime.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { serializeSetCookie } from "./cookie-serialize.js";
|
|
1
2
|
import nodeProcess from "node:process";
|
|
2
3
|
export function detectRuntime() {
|
|
3
4
|
if (typeof globalThis < "u" && "caches" in globalThis && "CF" in globalThis)
|
|
@@ -500,22 +501,7 @@ export function parseCookies(request) {
|
|
|
500
501
|
return cookies;
|
|
501
502
|
}
|
|
502
503
|
export function createCookie(name, value, options) {
|
|
503
|
-
|
|
504
|
-
if (options?.maxAge !== void 0)
|
|
505
|
-
cookie += `; Max-Age=${options.maxAge}`;
|
|
506
|
-
if (options?.expires)
|
|
507
|
-
cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
508
|
-
if (options?.path)
|
|
509
|
-
cookie += `; Path=${options.path}`;
|
|
510
|
-
if (options?.domain)
|
|
511
|
-
cookie += `; Domain=${options.domain}`;
|
|
512
|
-
if (options?.secure)
|
|
513
|
-
cookie += "; Secure";
|
|
514
|
-
if (options?.httpOnly)
|
|
515
|
-
cookie += "; HttpOnly";
|
|
516
|
-
if (options?.sameSite)
|
|
517
|
-
cookie += `; SameSite=${options.sameSite}`;
|
|
518
|
-
return cookie;
|
|
504
|
+
return serializeSetCookie(name, value, options);
|
|
519
505
|
}
|
|
520
506
|
export function jsonResponse(data, init) {
|
|
521
507
|
const headers = new Headers(init?.headers);
|
package/dist/index.d.ts
CHANGED
|
@@ -205,6 +205,8 @@ export * from './client-helpers';
|
|
|
205
205
|
export * from './client-script';
|
|
206
206
|
export * from './strip-literals';
|
|
207
207
|
export * from './resolve-stx-targets';
|
|
208
|
+
export * from './cookie-serialize';
|
|
209
|
+
export * from './cli-flags';
|
|
208
210
|
export * from './component-hmr';
|
|
209
211
|
export * from './hydration';
|
|
210
212
|
// ssg moved to stx/ssg
|
package/dist/index.js
CHANGED
|
@@ -114,6 +114,8 @@ export * from "./client-helpers.js";
|
|
|
114
114
|
export * from "./client-script.js";
|
|
115
115
|
export * from "./strip-literals.js";
|
|
116
116
|
export * from "./resolve-stx-targets.js";
|
|
117
|
+
export * from "./cookie-serialize.js";
|
|
118
|
+
export * from "./cli-flags.js";
|
|
117
119
|
export * from "./component-hmr.js";
|
|
118
120
|
export * from "./hydration.js";
|
|
119
121
|
export * from "./ssr.js";
|
package/dist/page-action.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SetCookieOptions } from './cookie-serialize';
|
|
1
2
|
/**
|
|
2
3
|
* Parse a form submission body into a plain object.
|
|
3
4
|
*
|
|
@@ -36,26 +37,7 @@ export declare function runPageAction(context: Record<string, any>, options?: Ru
|
|
|
36
37
|
* 303 rather than 302 deliberately: it is the status that makes a browser
|
|
37
38
|
* follow up with a GET, so a reload or a Back does not resubmit the form.
|
|
38
39
|
*/
|
|
39
|
-
export declare function actionRedirectResponse(to: string): Response;
|
|
40
|
-
/**
|
|
41
|
-
* A page handling its own form submission (stacksjs/stx#1847).
|
|
42
|
-
*
|
|
43
|
-
* A page that declares `action` in its `<script server>` block receives its own
|
|
44
|
-
* non-GET request. Whatever the action returns is merged into the render
|
|
45
|
-
* context, so `errors` and `values` repopulate the very same template that drew
|
|
46
|
-
* the form — one handler for the no-JS submit and the enhanced one, which is
|
|
47
|
-
* the half of the Laravel/Remix/SvelteKit contract stx was missing.
|
|
48
|
-
*
|
|
49
|
-
* ## Why this is a module rather than two implementations
|
|
50
|
-
*
|
|
51
|
-
* It shipped in `bun-plugin/src/serve.ts` only, so a form worked under
|
|
52
|
-
* `buddy dev` and silently did nothing in production — the request fell through
|
|
53
|
-
* to the ordinary render and answered 200 with the pre-submit markup, which is
|
|
54
|
-
* indistinguishable from the action having run and found nothing wrong. That is
|
|
55
|
-
* the same dev-only-correctness shape as `stx typecheck` being stricter than
|
|
56
|
-
* the editor, and this repo has been bitten repeatedly by two hand-maintained
|
|
57
|
-
* copies of one rule drifting apart. One module, both servers.
|
|
58
|
-
*/
|
|
40
|
+
export declare function actionRedirectResponse(to: string, cookies?: readonly string[]): Response;
|
|
59
41
|
/**
|
|
60
42
|
* Everything an action is given about the request.
|
|
61
43
|
*
|
|
@@ -72,6 +54,7 @@ export declare interface PageActionContext {
|
|
|
72
54
|
/** What running an action produced. */
|
|
73
55
|
export declare interface PageActionResult {
|
|
74
56
|
redirect?: string
|
|
57
|
+
cookies?: string[]
|
|
75
58
|
ran: boolean
|
|
76
59
|
}
|
|
77
60
|
/** Request data a caller has already parsed, if it has. */
|
|
@@ -81,3 +64,10 @@ export declare interface RunPageActionOptions {
|
|
|
81
64
|
params?: Record<string, string>
|
|
82
65
|
cookies?: Record<string, string>
|
|
83
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* A cookie an action wants set on the response.
|
|
69
|
+
*
|
|
70
|
+
* A bare string is the whole cookie for the common case; the object form adds
|
|
71
|
+
* the attributes a session cookie needs.
|
|
72
|
+
*/
|
|
73
|
+
export type PageActionCookie = string | (SetCookieOptions & { value: string });
|
package/dist/page-action.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { serializeSetCookie } from "./cookie-serialize.js";
|
|
1
2
|
export async function parseFormBody(request) {
|
|
2
3
|
const type = request.headers.get("content-type") || "", form = {}, put = (key, value) => {
|
|
3
4
|
const existing = form[key];
|
|
@@ -46,19 +47,42 @@ export async function runPageAction(context, options = {}) {
|
|
|
46
47
|
cookies: options.cookies ?? {}
|
|
47
48
|
});
|
|
48
49
|
if (result && typeof result === "object") {
|
|
49
|
-
const
|
|
50
|
+
const returned = result, cookies = serializeActionCookies(returned.cookies), to = returned.redirect;
|
|
50
51
|
if (typeof to === "string" && to)
|
|
51
|
-
return { redirect: to, ran: !0 };
|
|
52
|
-
|
|
52
|
+
return { redirect: to, ran: !0, ...cookies.length > 0 ? { cookies } : {} };
|
|
53
|
+
const { cookies: _cookies, redirect: _redirect, ...data } = returned;
|
|
54
|
+
Object.assign(context, data);
|
|
55
|
+
if (cookies.length > 0)
|
|
56
|
+
return { ran: !0, cookies };
|
|
53
57
|
}
|
|
54
58
|
return { ran: !0 };
|
|
55
59
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
function serializeActionCookies(value) {
|
|
61
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
62
|
+
return [];
|
|
63
|
+
const headers = [];
|
|
64
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
65
|
+
if (!name)
|
|
66
|
+
continue;
|
|
67
|
+
if (typeof entry === "string") {
|
|
68
|
+
headers.push(serializeSetCookie(name, entry));
|
|
69
|
+
continue;
|
|
62
70
|
}
|
|
71
|
+
if (entry && typeof entry === "object") {
|
|
72
|
+
const options = entry;
|
|
73
|
+
if (typeof options.value !== "string")
|
|
74
|
+
continue;
|
|
75
|
+
headers.push(serializeSetCookie(name, options.value, options));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return headers;
|
|
79
|
+
}
|
|
80
|
+
export function actionRedirectResponse(to, cookies = []) {
|
|
81
|
+
const headers = new Headers({
|
|
82
|
+
Location: to,
|
|
83
|
+
"Cache-Control": "no-store"
|
|
63
84
|
});
|
|
85
|
+
for (const cookie of cookies)
|
|
86
|
+
headers.append("Set-Cookie", cookie);
|
|
87
|
+
return new Response(null, { status: 303, headers });
|
|
64
88
|
}
|
|
@@ -165,25 +165,26 @@ export async function startProductionServer(options = {}) {
|
|
|
165
165
|
}
|
|
166
166
|
});
|
|
167
167
|
try {
|
|
168
|
-
const { html, boundaries, redirect } = await hydrateTemplateStream(compiled, {
|
|
168
|
+
const { html, boundaries, redirect, cookies } = await hydrateTemplateStream(compiled, {
|
|
169
169
|
params,
|
|
170
170
|
request,
|
|
171
171
|
method: request.method
|
|
172
172
|
});
|
|
173
173
|
if (redirect)
|
|
174
|
-
return actionRedirectResponse(redirect);
|
|
174
|
+
return actionRedirectResponse(redirect, cookies);
|
|
175
175
|
if (boundaries && boundaries.length > 0) {
|
|
176
176
|
const { renderStreamingPage, streamToResponse } = await import("./streaming.js");
|
|
177
177
|
return streamToResponse(renderStreamingPage(html, boundaries, { timeoutMs: 30000 }), {
|
|
178
178
|
headers: { "Cache-Control": "no-cache" }
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
"Cache-Control": "no-cache"
|
|
185
|
-
}
|
|
181
|
+
const headers = new Headers({
|
|
182
|
+
"Content-Type": "text/html",
|
|
183
|
+
"Cache-Control": "no-cache"
|
|
186
184
|
});
|
|
185
|
+
for (const cookie of cookies ?? [])
|
|
186
|
+
headers.append("Set-Cookie", cookie);
|
|
187
|
+
return new Response(html, { headers });
|
|
187
188
|
} catch (error) {
|
|
188
189
|
console.error(`[stx] Hydration error for ${pathname}:`, error);
|
|
189
190
|
return new Response(compiled.html, {
|