@timber-js/app 0.2.0-alpha.34 → 0.2.0-alpha.35
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/_chunks/{als-registry-B7DbZ2hS.js → als-registry-Ba7URUIn.js} +1 -1
- package/dist/_chunks/als-registry-Ba7URUIn.js.map +1 -0
- package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
- package/dist/_chunks/{debug-B3Gypr3D.js → debug-ECi_61pb.js} +1 -1
- package/dist/_chunks/{debug-B3Gypr3D.js.map → debug-ECi_61pb.js.map} +1 -1
- package/dist/_chunks/define-cookie-w5GWm_bL.js +93 -0
- package/dist/_chunks/define-cookie-w5GWm_bL.js.map +1 -0
- package/dist/_chunks/error-boundary-TYEQJZ1-.js +211 -0
- package/dist/_chunks/error-boundary-TYEQJZ1-.js.map +1 -0
- package/dist/_chunks/{format-RyoGQL74.js → format-cX7wzEp2.js} +2 -2
- package/dist/_chunks/{format-RyoGQL74.js.map → format-cX7wzEp2.js.map} +1 -1
- package/dist/_chunks/{interception-BOoWmLUA.js → interception-D2djYaIm.js} +112 -77
- package/dist/_chunks/interception-D2djYaIm.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-BU684ls2.js} +1 -1
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-BU684ls2.js.map} +1 -1
- package/dist/_chunks/{request-context-BQUC8PHn.js → request-context-CZz_T0Bc.js} +40 -71
- package/dist/_chunks/request-context-CZz_T0Bc.js.map +1 -0
- package/dist/_chunks/segment-context-Dpq2XOKg.js +34 -0
- package/dist/_chunks/segment-context-Dpq2XOKg.js.map +1 -0
- package/dist/_chunks/stale-reload-C0ValzG7.js +47 -0
- package/dist/_chunks/stale-reload-C0ValzG7.js.map +1 -0
- package/dist/_chunks/{tracing-CemImE6h.js → tracing-BPyIzIdu.js} +2 -2
- package/dist/_chunks/{tracing-CemImE6h.js.map → tracing-BPyIzIdu.js.map} +1 -1
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-BvW0TKDn.js} +1 -1
- package/dist/_chunks/{use-query-states-D5KaffOK.js.map → use-query-states-BvW0TKDn.js.map} +1 -1
- package/dist/_chunks/wrappers-C1SN725w.js +331 -0
- package/dist/_chunks/wrappers-C1SN725w.js.map +1 -0
- package/dist/cache/index.js +1 -1
- package/dist/client/error-boundary.d.ts +10 -1
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -125
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +193 -90
- package/dist/client/index.js.map +1 -1
- package/dist/client/link.d.ts +8 -8
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +2 -2
- package/dist/client/router.d.ts +25 -3
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +23 -2
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +1 -1
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/stale-reload.d.ts +15 -0
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts +1 -1
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/use-params.d.ts +2 -2
- package/dist/client/use-params.d.ts.map +1 -1
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/codec.d.ts +21 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/cookies/define-cookie.d.ts +33 -12
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -81
- package/dist/index.d.ts +87 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +346 -210
- package/dist/index.js.map +1 -1
- package/dist/params/define.d.ts +76 -0
- package/dist/params/define.d.ts.map +1 -0
- package/dist/params/index.d.ts +8 -0
- package/dist/params/index.d.ts.map +1 -0
- package/dist/params/index.js +104 -0
- package/dist/params/index.js.map +1 -0
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +32 -0
- package/dist/plugins/client-chunks.d.ts.map +1 -0
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen.d.ts +2 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/status-file-lint.d.ts +2 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/routing/types.d.ts +6 -4
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/search-params/codecs.d.ts +1 -1
- package/dist/search-params/define.d.ts +153 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -5
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +3 -474
- package/dist/search-params/registry.d.ts +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/server/access-gate.d.ts +4 -0
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-encryption.d.ts +76 -0
- package/dist/server/action-encryption.d.ts.map +1 -0
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +4 -4
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +2 -2
- package/dist/server/early-hints.d.ts +13 -5
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +4 -0
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +78 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/form-data.d.ts +29 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1819 -1629
- package/dist/server/index.js.map +1 -1
- package/dist/server/node-stream-transforms.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +28 -40
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +7 -0
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts +2 -2
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +3 -0
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +12 -8
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -3
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/shims/navigation-client.d.ts +1 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +1 -1
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/state-machine.d.ts +80 -0
- package/dist/utils/state-machine.d.ts.map +1 -0
- package/package.json +12 -8
- package/src/client/browser-entry.ts +55 -13
- package/src/client/error-boundary.tsx +18 -1
- package/src/client/index.ts +9 -1
- package/src/client/link.tsx +9 -9
- package/src/client/navigation-context.ts +2 -2
- package/src/client/router.ts +102 -55
- package/src/client/rsc-fetch.ts +63 -2
- package/src/client/segment-cache.ts +1 -1
- package/src/client/stale-reload.ts +28 -0
- package/src/client/top-loader.tsx +2 -2
- package/src/client/use-params.ts +3 -3
- package/src/client/use-query-states.ts +1 -1
- package/src/codec.ts +21 -0
- package/src/cookies/define-cookie.ts +69 -18
- package/src/index.ts +255 -65
- package/src/params/define.ts +260 -0
- package/src/params/index.ts +28 -0
- package/src/plugins/adapter-build.ts +6 -0
- package/src/plugins/build-manifest.ts +11 -0
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/entries.ts +3 -6
- package/src/plugins/routing.ts +40 -14
- package/src/plugins/server-bundle.ts +32 -1
- package/src/plugins/shims.ts +1 -1
- package/src/plugins/static-build.ts +8 -4
- package/src/routing/codegen.ts +109 -88
- package/src/routing/scanner.ts +55 -6
- package/src/routing/status-file-lint.ts +2 -1
- package/src/routing/types.ts +7 -4
- package/src/rsc-runtime/rsc.ts +2 -0
- package/src/search-params/codecs.ts +1 -1
- package/src/search-params/define.ts +504 -0
- package/src/search-params/index.ts +12 -18
- package/src/search-params/registry.ts +1 -1
- package/src/search-params/wrappers.ts +85 -0
- package/src/server/access-gate.tsx +38 -8
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +16 -0
- package/src/server/als-registry.ts +4 -4
- package/src/server/build-manifest.ts +4 -4
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +57 -14
- package/src/server/flight-injection-state.ts +152 -0
- package/src/server/form-data.ts +76 -0
- package/src/server/html-injectors.ts +42 -26
- package/src/server/index.ts +2 -4
- package/src/server/node-stream-transforms.ts +68 -41
- package/src/server/pipeline.ts +98 -26
- package/src/server/request-context.ts +49 -124
- package/src/server/route-element-builder.ts +102 -99
- package/src/server/route-matcher.ts +2 -2
- package/src/server/rsc-entry/error-renderer.ts +3 -2
- package/src/server/rsc-entry/index.ts +26 -11
- package/src/server/rsc-entry/rsc-payload.ts +2 -2
- package/src/server/rsc-entry/ssr-renderer.ts +4 -4
- package/src/server/slot-resolver.ts +204 -206
- package/src/server/ssr-entry.ts +3 -1
- package/src/server/ssr-render.ts +3 -0
- package/src/server/tree-builder.ts +84 -48
- package/src/server/types.ts +1 -3
- package/src/server/version-skew.ts +104 -0
- package/src/shims/navigation-client.ts +1 -1
- package/src/shims/navigation.ts +1 -1
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/request-context-BQUC8PHn.js.map +0 -1
- package/dist/_chunks/ssr-data-MjmprTmO.js +0 -88
- package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
- package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
- package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
- package/dist/client/error-boundary.js.map +0 -1
- package/dist/cookies/index.js.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/search-params/analyze.d.ts +0 -54
- package/dist/search-params/analyze.d.ts.map +0 -1
- package/dist/search-params/builtin-codecs.d.ts +0 -105
- package/dist/search-params/builtin-codecs.d.ts.map +0 -1
- package/dist/search-params/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/search-params/index.js.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/create.ts +0 -321
- package/src/server/prerender.ts +0 -139
|
@@ -1,474 +1,3 @@
|
|
|
1
|
-
import { i as registerSearchParams,
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* createSearchParams — factory for SearchParamsDefinition<T>.
|
|
5
|
-
*
|
|
6
|
-
* Creates a typed, composable definition for a route's search parameters.
|
|
7
|
-
* Supports codec protocol, URL key aliasing, default-omission serialization,
|
|
8
|
-
* and composition via .extend() / .pick().
|
|
9
|
-
*
|
|
10
|
-
* Design doc: design/09-typescript.md §"Typed searchParams — search-params.ts"
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Convert URLSearchParams or a plain record to a normalized record
|
|
14
|
-
* where repeated keys produce arrays.
|
|
15
|
-
*/
|
|
16
|
-
function normalizeRaw(raw) {
|
|
17
|
-
if (raw instanceof URLSearchParams) {
|
|
18
|
-
const result = {};
|
|
19
|
-
for (const key of new Set(raw.keys())) {
|
|
20
|
-
const values = raw.getAll(key);
|
|
21
|
-
result[key] = values.length === 1 ? values[0] : values;
|
|
22
|
-
}
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
|
-
return raw;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Compute the serialized default value for a codec. Used for
|
|
29
|
-
* default-omission: when serialize(value) === serialize(parse(undefined)),
|
|
30
|
-
* the field is omitted from the URL.
|
|
31
|
-
*/
|
|
32
|
-
function getDefaultSerialized(codec) {
|
|
33
|
-
return codec.serialize(codec.parse(void 0));
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Create a SearchParamsDefinition from a codec map and optional URL key aliases.
|
|
37
|
-
*
|
|
38
|
-
* ```ts
|
|
39
|
-
* import { createSearchParams, fromSchema } from '@timber-js/app/search-params'
|
|
40
|
-
* import { z } from 'zod/v4'
|
|
41
|
-
*
|
|
42
|
-
* export default createSearchParams({
|
|
43
|
-
* page: fromSchema(z.coerce.number().int().min(1).default(1)),
|
|
44
|
-
* q: { parse: (v) => v ?? null, serialize: (v) => v },
|
|
45
|
-
* }, {
|
|
46
|
-
* urlKeys: { q: 'search' },
|
|
47
|
-
* })
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
function createSearchParams(codecs, options) {
|
|
51
|
-
const urlKeys = {};
|
|
52
|
-
if (options?.urlKeys) {
|
|
53
|
-
for (const [k, v] of Object.entries(options.urlKeys)) if (v !== void 0) urlKeys[k] = v;
|
|
54
|
-
}
|
|
55
|
-
return buildDefinition(codecs, urlKeys);
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Internal: build a SearchParamsDefinition from a typed codec map and url keys.
|
|
59
|
-
*/
|
|
60
|
-
function buildDefinition(codecMap, urlKeys) {
|
|
61
|
-
const defaultSerialized = {};
|
|
62
|
-
for (const key of Object.keys(codecMap)) defaultSerialized[key] = getDefaultSerialized(codecMap[key]);
|
|
63
|
-
function getUrlKey(prop) {
|
|
64
|
-
return urlKeys[prop] ?? prop;
|
|
65
|
-
}
|
|
66
|
-
function parse(raw) {
|
|
67
|
-
const normalized = normalizeRaw(raw);
|
|
68
|
-
const result = {};
|
|
69
|
-
for (const prop of Object.keys(codecMap)) {
|
|
70
|
-
const rawValue = normalized[getUrlKey(prop)];
|
|
71
|
-
result[prop] = codecMap[prop].parse(rawValue);
|
|
72
|
-
}
|
|
73
|
-
return result;
|
|
74
|
-
}
|
|
75
|
-
function serialize(values) {
|
|
76
|
-
const parts = [];
|
|
77
|
-
for (const prop of Object.keys(codecMap)) {
|
|
78
|
-
if (!(prop in values)) continue;
|
|
79
|
-
const serialized = codecMap[prop].serialize(values[prop]);
|
|
80
|
-
if (serialized === defaultSerialized[prop]) continue;
|
|
81
|
-
if (serialized === null) continue;
|
|
82
|
-
parts.push(`${encodeURIComponent(getUrlKey(prop))}=${encodeURIComponent(serialized)}`);
|
|
83
|
-
}
|
|
84
|
-
return parts.join("&");
|
|
85
|
-
}
|
|
86
|
-
function href(pathname, values) {
|
|
87
|
-
const qs = serialize(values);
|
|
88
|
-
return qs ? `${pathname}?${qs}` : pathname;
|
|
89
|
-
}
|
|
90
|
-
function toSearchParams(values) {
|
|
91
|
-
const usp = new URLSearchParams();
|
|
92
|
-
for (const prop of Object.keys(codecMap)) {
|
|
93
|
-
if (!(prop in values)) continue;
|
|
94
|
-
const serialized = codecMap[prop].serialize(values[prop]);
|
|
95
|
-
if (serialized === defaultSerialized[prop]) continue;
|
|
96
|
-
if (serialized === null) continue;
|
|
97
|
-
usp.set(getUrlKey(prop), serialized);
|
|
98
|
-
}
|
|
99
|
-
return usp;
|
|
100
|
-
}
|
|
101
|
-
function extend(newCodecs, extendOptions) {
|
|
102
|
-
const combinedCodecs = {
|
|
103
|
-
...codecMap,
|
|
104
|
-
...newCodecs
|
|
105
|
-
};
|
|
106
|
-
const combinedUrlKeys = { ...urlKeys };
|
|
107
|
-
if (extendOptions?.urlKeys) {
|
|
108
|
-
for (const [k, v] of Object.entries(extendOptions.urlKeys)) if (v !== void 0) combinedUrlKeys[k] = v;
|
|
109
|
-
}
|
|
110
|
-
return buildDefinition(combinedCodecs, combinedUrlKeys);
|
|
111
|
-
}
|
|
112
|
-
function pick(...keys) {
|
|
113
|
-
const pickedCodecs = {};
|
|
114
|
-
const pickedUrlKeys = {};
|
|
115
|
-
for (const key of keys) {
|
|
116
|
-
pickedCodecs[key] = codecMap[key];
|
|
117
|
-
if (key in urlKeys) pickedUrlKeys[key] = urlKeys[key];
|
|
118
|
-
}
|
|
119
|
-
return buildDefinition(pickedCodecs, pickedUrlKeys);
|
|
120
|
-
}
|
|
121
|
-
function useQueryStates$1(options) {
|
|
122
|
-
return useQueryStates(codecMap, options, Object.freeze({ ...urlKeys }));
|
|
123
|
-
}
|
|
124
|
-
return {
|
|
125
|
-
parse,
|
|
126
|
-
useQueryStates: useQueryStates$1,
|
|
127
|
-
extend,
|
|
128
|
-
pick,
|
|
129
|
-
serialize,
|
|
130
|
-
href,
|
|
131
|
-
toSearchParams,
|
|
132
|
-
codecs: codecMap,
|
|
133
|
-
urlKeys: Object.freeze({ ...urlKeys })
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
//#endregion
|
|
137
|
-
//#region src/search-params/codecs.ts
|
|
138
|
-
/**
|
|
139
|
-
* Zod v4's ~standard.validate() signature includes Promise in the return union
|
|
140
|
-
* to satisfy the Standard Schema spec, but in practice Zod always validates
|
|
141
|
-
* synchronously for the schema types we use. We assert the result is sync and
|
|
142
|
-
* throw if it isn't — search params parsing must be synchronous.
|
|
143
|
-
*/
|
|
144
|
-
function validateSync(schema, value) {
|
|
145
|
-
const result = schema["~standard"].validate(value);
|
|
146
|
-
if (result instanceof Promise) throw new Error("[timber] fromSchema: schema returned a Promise — only sync schemas are supported for search params.");
|
|
147
|
-
return result;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Bridge a Standard Schema-compatible schema (Zod, Valibot, ArkType) to a
|
|
151
|
-
* SearchParamCodec.
|
|
152
|
-
*
|
|
153
|
-
* Parse: coerces the raw URL string through the schema. On validation failure,
|
|
154
|
-
* parses `undefined` to get the schema's default value (the schema should have
|
|
155
|
-
* a `.default()` call). If that also fails, returns `undefined`.
|
|
156
|
-
*
|
|
157
|
-
* Serialize: uses `String()` for primitives, `null` for null/undefined.
|
|
158
|
-
*
|
|
159
|
-
* ```ts
|
|
160
|
-
* import { fromSchema } from '@timber-js/app/search-params'
|
|
161
|
-
* import { z } from 'zod/v4'
|
|
162
|
-
*
|
|
163
|
-
* const pageCodec = fromSchema(z.coerce.number().int().min(1).default(1))
|
|
164
|
-
* ```
|
|
165
|
-
*/
|
|
166
|
-
function fromSchema(schema) {
|
|
167
|
-
return {
|
|
168
|
-
parse(value) {
|
|
169
|
-
const result = validateSync(schema, Array.isArray(value) ? value[value.length - 1] : value);
|
|
170
|
-
if (!result.issues) return result.value;
|
|
171
|
-
const defaultResult = validateSync(schema, void 0);
|
|
172
|
-
if (!defaultResult.issues) return defaultResult.value;
|
|
173
|
-
},
|
|
174
|
-
serialize(value) {
|
|
175
|
-
if (value === null || value === void 0) return null;
|
|
176
|
-
return String(value);
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Bridge a Standard Schema for array values. Handles both single strings
|
|
182
|
-
* and repeated query keys (`?tag=a&tag=b`).
|
|
183
|
-
*
|
|
184
|
-
* ```ts
|
|
185
|
-
* import { fromArraySchema } from '@timber-js/app/search-params'
|
|
186
|
-
* import { z } from 'zod/v4'
|
|
187
|
-
*
|
|
188
|
-
* const tagsCodec = fromArraySchema(z.array(z.string()).default([]))
|
|
189
|
-
* ```
|
|
190
|
-
*/
|
|
191
|
-
function fromArraySchema(schema) {
|
|
192
|
-
return {
|
|
193
|
-
parse(value) {
|
|
194
|
-
let input = value;
|
|
195
|
-
if (typeof value === "string") input = [value];
|
|
196
|
-
else if (value === void 0) input = void 0;
|
|
197
|
-
const result = validateSync(schema, input);
|
|
198
|
-
if (!result.issues) return result.value;
|
|
199
|
-
const defaultResult = validateSync(schema, void 0);
|
|
200
|
-
if (!defaultResult.issues) return defaultResult.value;
|
|
201
|
-
},
|
|
202
|
-
serialize(value) {
|
|
203
|
-
if (value === null || value === void 0) return null;
|
|
204
|
-
if (Array.isArray(value)) return value.length === 0 ? null : value.join(",");
|
|
205
|
-
return String(value);
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
//#endregion
|
|
210
|
-
//#region src/search-params/builtin-codecs.ts
|
|
211
|
-
/**
|
|
212
|
-
* Normalize array inputs to a single string (last value wins, matching
|
|
213
|
-
* URLSearchParams.get() semantics). Returns undefined if absent or empty.
|
|
214
|
-
*/
|
|
215
|
-
function normalizeInput(value) {
|
|
216
|
-
if (Array.isArray(value)) return value.length > 0 ? value[value.length - 1] : void 0;
|
|
217
|
-
return value;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* String codec. Returns the raw string value, or null if absent.
|
|
221
|
-
*
|
|
222
|
-
* ```ts
|
|
223
|
-
* import { parseAsString } from '@timber-js/app/search-params'
|
|
224
|
-
*
|
|
225
|
-
* const def = createSearchParams({ q: parseAsString })
|
|
226
|
-
* // ?q=shoes → { q: 'shoes' }
|
|
227
|
-
* // (absent) → { q: null }
|
|
228
|
-
* ```
|
|
229
|
-
*/
|
|
230
|
-
var parseAsString = {
|
|
231
|
-
parse(value) {
|
|
232
|
-
const v = normalizeInput(value);
|
|
233
|
-
return v !== void 0 ? v : null;
|
|
234
|
-
},
|
|
235
|
-
serialize(value) {
|
|
236
|
-
return value;
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
/**
|
|
240
|
-
* Integer codec. Parses a base-10 integer, or returns null if absent or
|
|
241
|
-
* not a valid integer. Rejects floats, NaN, Infinity, and non-numeric strings.
|
|
242
|
-
*
|
|
243
|
-
* ```ts
|
|
244
|
-
* import { parseAsInteger, withDefault } from '@timber-js/app/search-params'
|
|
245
|
-
*
|
|
246
|
-
* const def = createSearchParams({ page: withDefault(parseAsInteger, 1) })
|
|
247
|
-
* // ?page=2 → { page: 2 }
|
|
248
|
-
* // ?page=abc → { page: 1 }
|
|
249
|
-
* // (absent) → { page: 1 }
|
|
250
|
-
* ```
|
|
251
|
-
*/
|
|
252
|
-
var parseAsInteger = {
|
|
253
|
-
parse(value) {
|
|
254
|
-
const v = normalizeInput(value);
|
|
255
|
-
if (v === void 0 || v === "") return null;
|
|
256
|
-
const n = Number(v);
|
|
257
|
-
if (!Number.isFinite(n) || !Number.isInteger(n)) return null;
|
|
258
|
-
return n;
|
|
259
|
-
},
|
|
260
|
-
serialize(value) {
|
|
261
|
-
return value === null ? null : String(value);
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
/**
|
|
265
|
-
* Float codec. Parses a finite number, or returns null if absent or invalid.
|
|
266
|
-
* Rejects NaN and Infinity.
|
|
267
|
-
*
|
|
268
|
-
* ```ts
|
|
269
|
-
* import { parseAsFloat, withDefault } from '@timber-js/app/search-params'
|
|
270
|
-
*
|
|
271
|
-
* const def = createSearchParams({ price: withDefault(parseAsFloat, 0) })
|
|
272
|
-
* ```
|
|
273
|
-
*/
|
|
274
|
-
var parseAsFloat = {
|
|
275
|
-
parse(value) {
|
|
276
|
-
const v = normalizeInput(value);
|
|
277
|
-
if (v === void 0 || v === "") return null;
|
|
278
|
-
const n = Number(v);
|
|
279
|
-
if (!Number.isFinite(n)) return null;
|
|
280
|
-
return n;
|
|
281
|
-
},
|
|
282
|
-
serialize(value) {
|
|
283
|
-
return value === null ? null : String(value);
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
/**
|
|
287
|
-
* Boolean codec. Accepts "true"/"1" as true, "false"/"0" as false.
|
|
288
|
-
* Returns null for absent or unrecognized values.
|
|
289
|
-
*
|
|
290
|
-
* ```ts
|
|
291
|
-
* import { parseAsBoolean, withDefault } from '@timber-js/app/search-params'
|
|
292
|
-
*
|
|
293
|
-
* const def = createSearchParams({ debug: withDefault(parseAsBoolean, false) })
|
|
294
|
-
* // ?debug=true → { debug: true }
|
|
295
|
-
* // ?debug=0 → { debug: false }
|
|
296
|
-
* ```
|
|
297
|
-
*/
|
|
298
|
-
var parseAsBoolean = {
|
|
299
|
-
parse(value) {
|
|
300
|
-
const v = normalizeInput(value);
|
|
301
|
-
if (v === void 0) return null;
|
|
302
|
-
if (v === "true" || v === "1") return true;
|
|
303
|
-
if (v === "false" || v === "0") return false;
|
|
304
|
-
return null;
|
|
305
|
-
},
|
|
306
|
-
serialize(value) {
|
|
307
|
-
return value === null ? null : String(value);
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
/**
|
|
311
|
-
* String enum codec. Accepts only values in the provided list.
|
|
312
|
-
* Returns null for absent or invalid values.
|
|
313
|
-
*
|
|
314
|
-
* ```ts
|
|
315
|
-
* import { parseAsStringEnum, withDefault } from '@timber-js/app/search-params'
|
|
316
|
-
*
|
|
317
|
-
* const sortCodec = withDefault(
|
|
318
|
-
* parseAsStringEnum(['price', 'name', 'date']),
|
|
319
|
-
* 'date'
|
|
320
|
-
* )
|
|
321
|
-
* ```
|
|
322
|
-
*/
|
|
323
|
-
function parseAsStringEnum(values) {
|
|
324
|
-
const allowed = new Set(values);
|
|
325
|
-
return {
|
|
326
|
-
parse(value) {
|
|
327
|
-
const v = normalizeInput(value);
|
|
328
|
-
if (v === void 0) return null;
|
|
329
|
-
return allowed.has(v) ? v : null;
|
|
330
|
-
},
|
|
331
|
-
serialize(value) {
|
|
332
|
-
return value;
|
|
333
|
-
}
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* String literal codec. Functionally identical to parseAsStringEnum but
|
|
338
|
-
* accepts `as const` tuples for narrower type inference.
|
|
339
|
-
*
|
|
340
|
-
* ```ts
|
|
341
|
-
* import { parseAsStringLiteral } from '@timber-js/app/search-params'
|
|
342
|
-
*
|
|
343
|
-
* const sizes = ['sm', 'md', 'lg', 'xl'] as const
|
|
344
|
-
* const codec = parseAsStringLiteral(sizes)
|
|
345
|
-
* // Type: SearchParamCodec<'sm' | 'md' | 'lg' | 'xl' | null>
|
|
346
|
-
* ```
|
|
347
|
-
*/
|
|
348
|
-
function parseAsStringLiteral(values) {
|
|
349
|
-
return parseAsStringEnum(values);
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Wrap a nullable codec with a default value. When the inner codec returns
|
|
353
|
-
* null, the default is used instead. The output type becomes non-nullable.
|
|
354
|
-
*
|
|
355
|
-
* ```ts
|
|
356
|
-
* import { parseAsInteger, withDefault } from '@timber-js/app/search-params'
|
|
357
|
-
*
|
|
358
|
-
* const page = withDefault(parseAsInteger, 1)
|
|
359
|
-
* // page.parse(undefined) → 1 (not null)
|
|
360
|
-
* // page.parse('5') → 5
|
|
361
|
-
* ```
|
|
362
|
-
*/
|
|
363
|
-
function withDefault(codec, defaultValue) {
|
|
364
|
-
return {
|
|
365
|
-
parse(value) {
|
|
366
|
-
const result = codec.parse(value);
|
|
367
|
-
return result === null ? defaultValue : result;
|
|
368
|
-
},
|
|
369
|
-
serialize(value) {
|
|
370
|
-
return codec.serialize(value);
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
//#endregion
|
|
375
|
-
//#region src/search-params/analyze.ts
|
|
376
|
-
/**
|
|
377
|
-
* Patterns that indicate a valid default export:
|
|
378
|
-
*
|
|
379
|
-
* 1. `export default createSearchParams(...)`
|
|
380
|
-
* 2. `export default someVar.extend(...)`
|
|
381
|
-
* 3. `export default someVar.pick(...)`
|
|
382
|
-
* 4. `export default someVar.extend(...).extend(...)` (chained)
|
|
383
|
-
* 5. `export default someVar.extend(...).pick(...)` (chained)
|
|
384
|
-
* 6. `export default createSearchParams(...).extend(...)`
|
|
385
|
-
*
|
|
386
|
-
* Invalid patterns:
|
|
387
|
-
* - `export default someFunction(...)` (arbitrary factory)
|
|
388
|
-
* - `export default condition ? a : b` (runtime conditional)
|
|
389
|
-
* - `export default variable` (opaque reference without call)
|
|
390
|
-
*/
|
|
391
|
-
/**
|
|
392
|
-
* Analyze a search-params.ts file source for static analyzability.
|
|
393
|
-
*
|
|
394
|
-
* @param source - The file content as a string
|
|
395
|
-
* @param filePath - Absolute path to the file (for diagnostics)
|
|
396
|
-
*/
|
|
397
|
-
function analyzeSearchParams(source, filePath) {
|
|
398
|
-
const defaultExport = extractDefaultExport(stripComments(source));
|
|
399
|
-
if (!defaultExport) return {
|
|
400
|
-
valid: false,
|
|
401
|
-
error: {
|
|
402
|
-
filePath,
|
|
403
|
-
expression: "(no default export found)",
|
|
404
|
-
suggestion: "search-params.ts must have a default export. Use: export default createSearchParams({ ... })"
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
if (isValidExpression(defaultExport.trim())) return { valid: true };
|
|
408
|
-
return {
|
|
409
|
-
valid: false,
|
|
410
|
-
error: {
|
|
411
|
-
filePath,
|
|
412
|
-
expression: defaultExport.trim(),
|
|
413
|
-
suggestion: "The default export must be a createSearchParams() call, or a chain of .extend() / .pick() calls on a SearchParamsDefinition. Arbitrary factory functions and runtime conditionals are not supported."
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
/** Strip single-line and multi-line comments from source. */
|
|
418
|
-
function stripComments(source) {
|
|
419
|
-
let result = source.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
420
|
-
result = result.replace(/\/\/.*$/gm, "");
|
|
421
|
-
return result;
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Extract the expression from `export default <expr>`.
|
|
425
|
-
*
|
|
426
|
-
* Handles both:
|
|
427
|
-
* export default createSearchParams(...)
|
|
428
|
-
* export default expr\n (terminated by newline or semicolon before next statement)
|
|
429
|
-
*/
|
|
430
|
-
function extractDefaultExport(source) {
|
|
431
|
-
const match = source.match(/export\s+default\s+([\s\S]+?)(?:;|\n(?=export|import|const|let|var|function|class|type|interface|declare))/);
|
|
432
|
-
if (match) return match[1];
|
|
433
|
-
const fallback = source.match(/export\s+default\s+([\s\S]+)$/);
|
|
434
|
-
if (fallback) return fallback[1].replace(/;\s*$/, "");
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* Check if an expression is a valid statically-analyzable pattern.
|
|
438
|
-
*
|
|
439
|
-
* Valid patterns:
|
|
440
|
-
* - Starts with `createSearchParams(`
|
|
441
|
-
* - Contains `.extend(` or `.pick(` chains (possibly starting with createSearchParams or a variable)
|
|
442
|
-
* - A variable identifier followed by chaining
|
|
443
|
-
*/
|
|
444
|
-
function isValidExpression(expr) {
|
|
445
|
-
const normalized = expr.replace(/\s+/g, " ").trim();
|
|
446
|
-
if (normalized.startsWith("createSearchParams(")) return true;
|
|
447
|
-
if (/\.(extend|pick)\s*\(/.test(normalized)) {
|
|
448
|
-
if (/\?/.test(normalized) && /:/.test(normalized)) return false;
|
|
449
|
-
if (/^\s*(function|=>|\()/.test(normalized)) return false;
|
|
450
|
-
return true;
|
|
451
|
-
}
|
|
452
|
-
return false;
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Format an AnalyzeError into a human-readable build error message.
|
|
456
|
-
*/
|
|
457
|
-
function formatAnalyzeError(error) {
|
|
458
|
-
return [
|
|
459
|
-
`[timber] Non-analyzable search-params.ts`,
|
|
460
|
-
``,
|
|
461
|
-
` File: ${error.filePath}`,
|
|
462
|
-
` Expression: ${error.expression}`,
|
|
463
|
-
``,
|
|
464
|
-
` ${error.suggestion}`,
|
|
465
|
-
``,
|
|
466
|
-
` The framework must be able to statically extract the type from your`,
|
|
467
|
-
` search-params.ts at build time. Dynamic values, conditionals, and`,
|
|
468
|
-
` arbitrary factory functions prevent this analysis.`
|
|
469
|
-
].join("\n");
|
|
470
|
-
}
|
|
471
|
-
//#endregion
|
|
472
|
-
export { analyzeSearchParams, createSearchParams, formatAnalyzeError, fromArraySchema, fromSchema, getSearchParams, parseAsBoolean, parseAsFloat, parseAsInteger, parseAsString, parseAsStringEnum, parseAsStringLiteral, registerSearchParams, withDefault };
|
|
473
|
-
|
|
474
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import { i as registerSearchParams, r as getSearchParams } from "../_chunks/use-query-states-BvW0TKDn.js";
|
|
2
|
+
import { a as fromSchema, i as fromArraySchema, n as withUrlKey, r as defineSearchParams, t as withDefault } from "../_chunks/wrappers-C1SN725w.js";
|
|
3
|
+
export { defineSearchParams, fromArraySchema, fromSchema, getSearchParams, registerSearchParams, withDefault, withUrlKey };
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Design doc: design/23-search-params.md §"Runtime: Registration at Route Load"
|
|
8
8
|
*/
|
|
9
|
-
import type { SearchParamsDefinition } from './
|
|
9
|
+
import type { SearchParamsDefinition } from './define.js';
|
|
10
10
|
/**
|
|
11
11
|
* Register a route's search params definition.
|
|
12
12
|
* Called by the generated route manifest loader when a route's modules load.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codec wrappers — withDefault and withUrlKey.
|
|
3
|
+
*
|
|
4
|
+
* These are timber-specific utilities that work with any SearchParamCodec.
|
|
5
|
+
* For actual codecs (string, integer, boolean, etc.), use nuqs parsers
|
|
6
|
+
* or Standard Schema objects (Zod, Valibot, ArkType) with auto-detection.
|
|
7
|
+
*
|
|
8
|
+
* Design doc: design/23-search-params.md
|
|
9
|
+
*/
|
|
10
|
+
import type { SearchParamCodec, SearchParamCodecWithUrlKey } from './define.js';
|
|
11
|
+
/**
|
|
12
|
+
* Wrap a nullable codec with a default value. When the inner codec returns
|
|
13
|
+
* null, the default is used instead. The output type becomes non-nullable.
|
|
14
|
+
*
|
|
15
|
+
* Works with any codec — nuqs parsers, custom codecs, fromSchema results.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { parseAsInteger } from 'nuqs'
|
|
19
|
+
* import { withDefault } from '@timber-js/app/search-params'
|
|
20
|
+
*
|
|
21
|
+
* const page = withDefault(parseAsInteger, 1)
|
|
22
|
+
* // page.parse(undefined) → 1 (not null)
|
|
23
|
+
* // page.parse('5') → 5
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function withDefault<T>(codec: SearchParamCodec<T | null>, defaultValue: T): SearchParamCodec<T>;
|
|
27
|
+
/**
|
|
28
|
+
* Attach a URL key alias to a codec. The alias determines what query
|
|
29
|
+
* parameter key is used in the URL, while the TypeScript property name
|
|
30
|
+
* stays descriptive.
|
|
31
|
+
*
|
|
32
|
+
* Aliases travel with codecs through object spread composition — when
|
|
33
|
+
* you spread a bundle containing aliased codecs into defineSearchParams,
|
|
34
|
+
* the aliases come along automatically.
|
|
35
|
+
*
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { parseAsString } from 'nuqs'
|
|
38
|
+
* import { withUrlKey } from '@timber-js/app/search-params'
|
|
39
|
+
*
|
|
40
|
+
* export const searchable = {
|
|
41
|
+
* q: withUrlKey(parseAsString, 'search'),
|
|
42
|
+
* // ?search=shoes → { q: 'shoes' }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* Composes with withDefault:
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { parseAsInteger } from 'nuqs'
|
|
49
|
+
* withUrlKey(withDefault(parseAsInteger, 1), 'p')
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function withUrlKey<T>(codec: SearchParamCodec<T>, urlKey: string): SearchParamCodecWithUrlKey<T>;
|
|
53
|
+
//# sourceMappingURL=wrappers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrappers.d.ts","sourceRoot":"","sources":["../../src/search-params/wrappers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAMhF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,EAAE,gBAAgB,CAAC,CAAC,GAAG,IAAI,CAAC,EACjC,YAAY,EAAE,CAAC,GACd,gBAAgB,CAAC,CAAC,CAAC,CAUrB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAC1B,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC1B,MAAM,EAAE,MAAM,GACb,0BAA0B,CAAC,CAAC,CAAC,CAM/B"}
|
|
@@ -35,6 +35,10 @@ export declare function AccessGate(props: AccessGateProps): ReactElement | Promi
|
|
|
35
35
|
* The HTTP status code is unaffected — slot denial is a UI concern, not
|
|
36
36
|
* a protocol concern. The parent layout and sibling slots still render.
|
|
37
37
|
*
|
|
38
|
+
* DeniedComponent is passed instead of a pre-built element so that
|
|
39
|
+
* DenySignal.data can be forwarded as the dangerouslyPassData prop
|
|
40
|
+
* and the slot name can be passed as the slot prop. See TIM-488.
|
|
41
|
+
*
|
|
38
42
|
* redirect() in slot access.ts is a dev-mode error — redirecting from a
|
|
39
43
|
* slot doesn't make architectural sense.
|
|
40
44
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access-gate.d.ts","sourceRoot":"","sources":["../../src/server/access-gate.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAM5F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAmBvF;
|
|
1
|
+
{"version":3,"file":"access-gate.d.ts","sourceRoot":"","sources":["../../src/server/access-gate.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAM5F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAmBvF;AAmCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAmDtF"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server action bound args encryption utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides key management for the RSC plugin's built-in bound args encryption.
|
|
5
|
+
* The RSC plugin (@vitejs/plugin-rsc) handles the actual encrypt/decrypt via
|
|
6
|
+
* AES-256-GCM — this module handles:
|
|
7
|
+
*
|
|
8
|
+
* 1. Key sourcing: auto-generated at build time (embedded in bundle), overridable
|
|
9
|
+
* via env var for cross-build key sharing (rolling/blue-green deployments)
|
|
10
|
+
* 2. Build-time key expression generation for the RSC plugin's `defineEncryptionKey`
|
|
11
|
+
*
|
|
12
|
+
* Encryption is always on in production. In dev mode, it's on by default
|
|
13
|
+
* (matching the RSC plugin's behavior) but can be disabled for debugging.
|
|
14
|
+
*
|
|
15
|
+
* ## Known Security Considerations
|
|
16
|
+
*
|
|
17
|
+
* 1. **defineEncryptionKey is a raw JS expression.** The RSC plugin inlines it
|
|
18
|
+
* verbatim into generated code. We only emit the hardcoded string
|
|
19
|
+
* `process.env.TIMBER_ACTIONS_ENCRYPTION_KEY` — never user-controlled input.
|
|
20
|
+
* If this function is ever extended to accept configurable env var names,
|
|
21
|
+
* the expression MUST be validated against a safe pattern.
|
|
22
|
+
*
|
|
23
|
+
* 2. **Key material lives in GC-visible JS strings.** `atob()` decodes the key
|
|
24
|
+
* into a regular JavaScript string on the V8 heap. JavaScript has no
|
|
25
|
+
* `SecureString` or memory-zeroing primitive — this is an inherent platform
|
|
26
|
+
* limitation. Acceptable for web server use; would need review for FIPS.
|
|
27
|
+
*
|
|
28
|
+
* 3. **TIMBER_ACTIONS_ENCRYPTION_KEY must be set at both build time and runtime.**
|
|
29
|
+
* At build time, we validate the key format and emit a runtime expression.
|
|
30
|
+
* If the env var is present at build time but missing at runtime, the server
|
|
31
|
+
* will crash on first action invocation with an opaque `atob(undefined)` error.
|
|
32
|
+
* If the env var is present at runtime but was absent at build time, the RSC
|
|
33
|
+
* plugin will have generated its own key and the env var is silently ignored.
|
|
34
|
+
*
|
|
35
|
+
* See design/08-forms-and-actions.md §"Security"
|
|
36
|
+
* See design/13-security.md
|
|
37
|
+
*/
|
|
38
|
+
/** User-facing configuration for action bound args encryption. */
|
|
39
|
+
export interface ActionEncryptionConfig {
|
|
40
|
+
/**
|
|
41
|
+
* Disable encryption in dev mode for easier debugging.
|
|
42
|
+
* Has no effect in production — encryption is always enabled.
|
|
43
|
+
* Default: false (encryption is on in dev too).
|
|
44
|
+
*/
|
|
45
|
+
disableInDev?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build the `defineEncryptionKey` expression for the RSC plugin.
|
|
49
|
+
*
|
|
50
|
+
* The RSC plugin accepts a JavaScript expression string that will be
|
|
51
|
+
* inlined into the encryption runtime module. At runtime, this expression
|
|
52
|
+
* must evaluate to the base64-encoded encryption key.
|
|
53
|
+
*
|
|
54
|
+
* Priority:
|
|
55
|
+
* 1. `TIMBER_ACTIONS_ENCRYPTION_KEY` env var (for cross-build key sharing
|
|
56
|
+
* in rolling/blue-green deployments)
|
|
57
|
+
* 2. Auto-generated at build time (RSC plugin default — embedded in bundle,
|
|
58
|
+
* consistent across all instances of the same build)
|
|
59
|
+
*
|
|
60
|
+
* For env var keys, we generate a runtime expression that reads the env var.
|
|
61
|
+
* For auto-generated keys, we return undefined and let the RSC plugin handle it.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveEncryptionKeyExpression(): string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Determine whether action encryption should be enabled.
|
|
66
|
+
*
|
|
67
|
+
* Encryption is always enabled in production. In dev mode, it's enabled
|
|
68
|
+
* by default but can be disabled via config for debugging.
|
|
69
|
+
*/
|
|
70
|
+
export declare function shouldEnableEncryption(isDev: boolean, config?: ActionEncryptionConfig): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Validate that a key string is a valid base64-encoded 256-bit key.
|
|
73
|
+
* Throws a descriptive error if the key is malformed.
|
|
74
|
+
*/
|
|
75
|
+
export declare function validateKeyFormat(key: string): void;
|
|
76
|
+
//# sourceMappingURL=action-encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-encryption.d.ts","sourceRoot":"","sources":["../../src/server/action-encryption.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAIH,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAaD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,GAAG,SAAS,CAwBnE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAI/F;AAID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAsBnD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-handler.d.ts","sourceRoot":"","sources":["../../src/server/action-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOtE,OAAO,EAAwC,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAE/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"action-handler.d.ts","sourceRoot":"","sources":["../../src/server/action-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOtE,OAAO,EAAwC,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAE/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAKrD,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,0BAA0B;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,gDAAgD;IAChD,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAQD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAarD;AAID,iGAAiG;AACjG,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,QAAQ,GAAG,YAAY,GAAG,IAAI,CAAC,CAuDzC"}
|
|
@@ -32,11 +32,11 @@ export interface RequestContextStore {
|
|
|
32
32
|
/** Original (pre-overlay) frozen headers, kept for overlay merging. */
|
|
33
33
|
originalHeaders: Headers;
|
|
34
34
|
/**
|
|
35
|
-
* Promise resolving to the
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* Promise resolving to the raw URLSearchParams for the current request.
|
|
36
|
+
* To get typed parsed params, import a search params definition and
|
|
37
|
+
* call `.parse(searchParams())`.
|
|
38
38
|
*/
|
|
39
|
-
searchParamsPromise: Promise<URLSearchParams
|
|
39
|
+
searchParamsPromise: Promise<URLSearchParams>;
|
|
40
40
|
/** Outgoing Set-Cookie entries (name → serialized value + options). Last write wins. */
|
|
41
41
|
cookieJar: Map<string, CookieEntry>;
|
|
42
42
|
/** Whether the response has flushed (headers committed). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"als-registry.d.ts","sourceRoot":"","sources":["../../src/server/als-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAMrD,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,wCAA+C,CAAC;AAE9E,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,uEAAuE;IACvE,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,mBAAmB,EAAE,OAAO,CAAC,eAAe,
|
|
1
|
+
{"version":3,"file":"als-registry.d.ts","sourceRoot":"","sources":["../../src/server/als-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAMrD,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,wCAA+C,CAAC;AAE9E,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,uEAAuE;IACvE,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,mBAAmB,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9C,wFAAwF;IACxF,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,sBAAsB,EAAE,aAAa,CAAC;CACvD;AAMD,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mDAAmD;AACnD,eAAO,MAAM,QAAQ,+BAAsC,CAAC;AAM5D,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,oBAAoB,EAAE,WAAW,EAAE,CAAC;CACrD;AAED,yDAAyD;AACzD,eAAO,MAAM,SAAS,gCAAuC,CAAC;AAM9D,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,mDAAmD;AACnD,eAAO,MAAM,eAAe,sCAA6C,CAAC;AAM1E,sDAAsD;AACtD,eAAO,MAAM,YAAY,4DAAmE,CAAC;AAM7F,4EAA4E;AAC5E,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;AAE3D,8DAA8D;AAC9D,eAAO,MAAM,mBAAmB,uCAA8C,CAAC;AAM/E,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;AAE9D,4DAA4D;AAC5D,eAAO,MAAM,YAAY,gCAAuC,CAAC"}
|