@timber-js/app 0.2.0-alpha.135 → 0.2.0-alpha.137
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/server/internal.js +16 -0
- package/dist/server/internal.js.map +1 -1
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/route-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts +11 -2
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/types.d.ts +22 -2
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/server/pipeline-phases.ts +19 -0
- package/src/server/route-handler.ts +7 -0
- package/src/server/rsc-entry/api-handler.ts +55 -17
- package/src/server/rsc-entry/render-route.ts +1 -1
- package/src/server/types.ts +22 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAwBD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAwBD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,QAAQ,CAAC,CAqSnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-handler.d.ts","sourceRoot":"","sources":["../../src/server/route-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"route-handler.d.ts","sourceRoot":"","sources":["../../src/server/route-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1F,2DAA2D;AAC3D,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,YAAY,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE/E,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG;KACvB,CAAC,IAAI,UAAU,CAAC,CAAC,EAAE,YAAY;CACjC,CAAC;AAOF;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,GAAG,UAAU,EAAE,CAyBpE;AAID;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyC/F"}
|
|
@@ -6,6 +6,15 @@
|
|
|
6
6
|
* See design/04-authorization.md §"Auth in API Routes".
|
|
7
7
|
*/
|
|
8
8
|
import type { ManifestSegmentNode } from '../route-matcher.js';
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Handle a `route.ts` request.
|
|
11
|
+
*
|
|
12
|
+
* Segment-param coercion has already run (in pipeline-phases.ts), and the
|
|
13
|
+
* coerced values + raw URLSearchParams are seeded into the request-context
|
|
14
|
+
* ALS — so `segmentParams.get()` / `searchParams.get()` work inside
|
|
15
|
+
* `middleware.ts`, `access.ts`, and the HTTP method handler. This function
|
|
16
|
+
* only runs the access chain and dispatches; it does not duplicate the
|
|
17
|
+
* coercion or ALS setup the pipeline already performed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function handleApiRoute(req: Request, segments: ManifestSegmentNode[], responseHeaders: Headers): Promise<Response>;
|
|
11
20
|
//# sourceMappingURL=api-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-handler.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/api-handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"api-handler.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/api-handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAO/D;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,eAAe,EAAE,OAAO,GACvB,OAAO,CAAC,QAAQ,CAAC,CAsDnB"}
|
package/dist/server/types.d.ts
CHANGED
|
@@ -18,10 +18,30 @@ export interface MiddlewareContext {
|
|
|
18
18
|
/** Declare early hints for critical resources. Appends Link headers. */
|
|
19
19
|
earlyHints: (hints: EarlyHint[]) => void;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Context passed to `route.ts` HTTP method handlers (GET/POST/etc.).
|
|
23
|
+
*
|
|
24
|
+
* `req` is the original incoming Request; `headers` is the response-headers
|
|
25
|
+
* container the framework will apply to the final Response.
|
|
26
|
+
*
|
|
27
|
+
* Segment params and query parameters are NOT on this context — they are
|
|
28
|
+
* accessed via the same ALS-backed `.get()` accessors pages use:
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* // app/api/users/[id]/params.ts
|
|
32
|
+
* export const segmentParams = defineSegmentParams({ id: z.coerce.number() });
|
|
33
|
+
* // app/api/users/[id]/route.ts
|
|
34
|
+
* import { segmentParams } from './params';
|
|
35
|
+
* export async function GET() {
|
|
36
|
+
* const { id } = segmentParams.get(); // typed number — 404 on bad input
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* See design/07-routing.md §"RouteContext", design/23-search-params.md,
|
|
41
|
+
* design/40-segment-params.md.
|
|
42
|
+
*/
|
|
21
43
|
export interface RouteContext {
|
|
22
44
|
req: Request;
|
|
23
|
-
params: Record<string, string | string[]>;
|
|
24
|
-
searchParams: URLSearchParams;
|
|
25
45
|
headers: Headers;
|
|
26
46
|
}
|
|
27
47
|
export interface AccessContext {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,gBAAgB,EAAE,GAClB;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAA;CAAE,CAAC;AAExC,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,OAAO,CAAC;IACb,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IACjD,wEAAwE;IACxE,UAAU,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.137",
|
|
4
4
|
"description": "Vite-native React framework built for Servers and Serverless Platforms — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -88,6 +88,12 @@ export async function runProxyPhase(
|
|
|
88
88
|
);
|
|
89
89
|
return { kind: 'response', phase: 'proxy', response };
|
|
90
90
|
} catch (error) {
|
|
91
|
+
if (error instanceof RedirectSignal) {
|
|
92
|
+
return { kind: 'redirect', phase: 'proxy', signal: error };
|
|
93
|
+
}
|
|
94
|
+
if (error instanceof DenySignal) {
|
|
95
|
+
return { kind: 'deny', phase: 'proxy', signal: error };
|
|
96
|
+
}
|
|
91
97
|
return { kind: 'error', phase: 'proxy', error };
|
|
92
98
|
}
|
|
93
99
|
}
|
|
@@ -313,6 +319,19 @@ export async function handleRequest(
|
|
|
313
319
|
headers: { 'Content-Type': `${contentType}; charset=utf-8` },
|
|
314
320
|
});
|
|
315
321
|
} catch (error) {
|
|
322
|
+
// Control-flow signals from the metadata handler (e.g. a sitemap that
|
|
323
|
+
// calls deny(404) for an unknown tenant, or a dynamic icon that
|
|
324
|
+
// redirects to a CDN-hosted asset) translate to proper HTTP responses
|
|
325
|
+
// instead of being logged as 500s.
|
|
326
|
+
if (error instanceof RedirectSignal) {
|
|
327
|
+
return new Response(null, {
|
|
328
|
+
status: error.status,
|
|
329
|
+
headers: { Location: error.location },
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
if (error instanceof DenySignal) {
|
|
333
|
+
return new Response(null, { status: error.status });
|
|
334
|
+
}
|
|
316
335
|
logRenderError({ method, path, error });
|
|
317
336
|
if (config.onPipelineError && error instanceof Error)
|
|
318
337
|
config.onPipelineError(error, 'metadata-route');
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type { RouteContext } from './types.js';
|
|
12
12
|
import { logRouteError } from './logger.js';
|
|
13
|
+
import { DenySignal, RedirectSignal } from './primitives.js';
|
|
13
14
|
|
|
14
15
|
// ─── Types ───────────────────────────────────────────────────────────────
|
|
15
16
|
|
|
@@ -123,6 +124,12 @@ async function runHandler(handler: RouteHandler, ctx: RouteContext): Promise<Res
|
|
|
123
124
|
const res = await handler(ctx);
|
|
124
125
|
return mergeResponseHeaders(res, ctx.headers);
|
|
125
126
|
} catch (error) {
|
|
127
|
+
// Control-flow signals — propagate to the API route dispatcher so deny()
|
|
128
|
+
// gets the JSON status-file chain and redirect() gets a proper 3xx with
|
|
129
|
+
// Location. Not errors; don't log them.
|
|
130
|
+
if (error instanceof DenySignal || error instanceof RedirectSignal) {
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
126
133
|
logRouteError({ method: ctx.req.method, path: new URL(ctx.req.url).pathname, error });
|
|
127
134
|
return new Response(null, { status: 500 });
|
|
128
135
|
}
|
|
@@ -9,15 +9,23 @@
|
|
|
9
9
|
import { withSpan, setSpanAttribute } from '../tracing.js';
|
|
10
10
|
import type { ManifestSegmentNode } from '../route-matcher.js';
|
|
11
11
|
import { loadModule } from '../safe-load.js';
|
|
12
|
-
import type { RouteMatch } from '../pipeline.js';
|
|
13
12
|
import { DenySignal, RedirectSignal } from '../primitives.js';
|
|
14
13
|
import { handleRouteRequest } from '../route-handler.js';
|
|
15
14
|
import type { RouteModule } from '../route-handler.js';
|
|
16
15
|
import type { RouteContext } from '../types.js';
|
|
17
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Handle a `route.ts` request.
|
|
19
|
+
*
|
|
20
|
+
* Segment-param coercion has already run (in pipeline-phases.ts), and the
|
|
21
|
+
* coerced values + raw URLSearchParams are seeded into the request-context
|
|
22
|
+
* ALS — so `segmentParams.get()` / `searchParams.get()` work inside
|
|
23
|
+
* `middleware.ts`, `access.ts`, and the HTTP method handler. This function
|
|
24
|
+
* only runs the access chain and dispatches; it does not duplicate the
|
|
25
|
+
* coercion or ALS setup the pipeline already performed.
|
|
26
|
+
*/
|
|
18
27
|
export async function handleApiRoute(
|
|
19
28
|
req: Request,
|
|
20
|
-
match: RouteMatch,
|
|
21
29
|
segments: ManifestSegmentNode[],
|
|
22
30
|
responseHeaders: Headers
|
|
23
31
|
): Promise<Response> {
|
|
@@ -53,28 +61,58 @@ export async function handleApiRoute(
|
|
|
53
61
|
}
|
|
54
62
|
);
|
|
55
63
|
} catch (error) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
if (error instanceof RedirectSignal) {
|
|
60
|
-
responseHeaders.set('Location', error.location);
|
|
61
|
-
return new Response(null, { status: error.status, headers: responseHeaders });
|
|
62
|
-
}
|
|
64
|
+
const signalResponse = await translateApiSignal(error, req, segments, responseHeaders);
|
|
65
|
+
if (signalResponse) return signalResponse;
|
|
63
66
|
throw error;
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
|
|
69
|
-
// Load route.ts module and dispatch
|
|
72
|
+
// Load route.ts module and dispatch.
|
|
73
|
+
// Segment params / query params are NOT on `ctx` — handlers read them
|
|
74
|
+
// through `segmentParams.get()` / `searchParams.get()`, which pull from
|
|
75
|
+
// the request-context ALS that the pipeline already populated.
|
|
70
76
|
const routeMod = await loadModule<RouteModule>(leaf.route!);
|
|
71
|
-
const ctx: RouteContext = {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
const ctx: RouteContext = { req, headers: responseHeaders };
|
|
78
|
+
try {
|
|
79
|
+
return await handleRouteRequest(routeMod, ctx);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
const signalResponse = await translateApiSignal(error, req, segments, responseHeaders);
|
|
82
|
+
if (signalResponse) return signalResponse;
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Translate a control-flow signal thrown from access.ts or a route.ts
|
|
89
|
+
* method handler into the proper API response: DenySignal → JSON status-file
|
|
90
|
+
* chain via `renderApiDeny`, RedirectSignal → bare 3xx with Location header.
|
|
91
|
+
*
|
|
92
|
+
* For HEAD requests, strip the deny body to preserve HEAD semantics — the
|
|
93
|
+
* normal HEAD path in `handleRouteRequest` strips bodies after the handler
|
|
94
|
+
* returns, but signals bypass that codepath.
|
|
95
|
+
*
|
|
96
|
+
* Returns `null` for non-signal errors so the caller knows to rethrow.
|
|
97
|
+
*/
|
|
98
|
+
async function translateApiSignal(
|
|
99
|
+
error: unknown,
|
|
100
|
+
req: Request,
|
|
101
|
+
segments: ManifestSegmentNode[],
|
|
102
|
+
responseHeaders: Headers
|
|
103
|
+
): Promise<Response | null> {
|
|
104
|
+
if (error instanceof DenySignal) {
|
|
105
|
+
const res = await renderApiDeny(error, segments, responseHeaders);
|
|
106
|
+
if (req.method.toUpperCase() === 'HEAD') {
|
|
107
|
+
return new Response(null, { status: res.status, headers: res.headers });
|
|
108
|
+
}
|
|
109
|
+
return res;
|
|
110
|
+
}
|
|
111
|
+
if (error instanceof RedirectSignal) {
|
|
112
|
+
responseHeaders.set('Location', error.location);
|
|
113
|
+
return new Response(null, { status: error.status, headers: responseHeaders });
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
78
116
|
}
|
|
79
117
|
|
|
80
118
|
/**
|
|
@@ -87,7 +87,7 @@ export async function renderRoute(
|
|
|
87
87
|
// No React render pass — AccessGate is not used, React.cache is not active.
|
|
88
88
|
// See design/04-authorization.md §"Auth in API Routes".
|
|
89
89
|
if (leaf.route && !leaf.page) {
|
|
90
|
-
return handleApiRoute(req,
|
|
90
|
+
return handleApiRoute(req, segments, responseHeaders);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// Parse X-Timber-State-Tree for RSC payload requests (client navigation).
|
package/src/server/types.ts
CHANGED
|
@@ -27,10 +27,30 @@ export interface MiddlewareContext {
|
|
|
27
27
|
earlyHints: (hints: EarlyHint[]) => void;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Context passed to `route.ts` HTTP method handlers (GET/POST/etc.).
|
|
32
|
+
*
|
|
33
|
+
* `req` is the original incoming Request; `headers` is the response-headers
|
|
34
|
+
* container the framework will apply to the final Response.
|
|
35
|
+
*
|
|
36
|
+
* Segment params and query parameters are NOT on this context — they are
|
|
37
|
+
* accessed via the same ALS-backed `.get()` accessors pages use:
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* // app/api/users/[id]/params.ts
|
|
41
|
+
* export const segmentParams = defineSegmentParams({ id: z.coerce.number() });
|
|
42
|
+
* // app/api/users/[id]/route.ts
|
|
43
|
+
* import { segmentParams } from './params';
|
|
44
|
+
* export async function GET() {
|
|
45
|
+
* const { id } = segmentParams.get(); // typed number — 404 on bad input
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* See design/07-routing.md §"RouteContext", design/23-search-params.md,
|
|
50
|
+
* design/40-segment-params.md.
|
|
51
|
+
*/
|
|
30
52
|
export interface RouteContext {
|
|
31
53
|
req: Request;
|
|
32
|
-
params: Record<string, string | string[]>;
|
|
33
|
-
searchParams: URLSearchParams;
|
|
34
54
|
headers: Headers;
|
|
35
55
|
}
|
|
36
56
|
|