@junejs/server 0.1.3 → 0.2.1
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/assets/icon-latin.LICENSE.txt +92 -0
- package/assets/icon-latin.ttf +0 -0
- package/dist/adapter-D0UnYBuN.d.ts +64 -0
- package/dist/adapter.d.ts +2 -56
- package/dist/adapter.js +107 -6
- package/dist/agent-compile.d.ts +38 -0
- package/dist/agent-compile.js +145 -0
- package/dist/agent-discover.d.ts +4 -4
- package/dist/agent-discover.js +30 -44
- package/dist/agent-durable.d.ts +94 -19
- package/dist/agent-durable.js +647 -32
- package/dist/agent-native.d.ts +44 -13
- package/dist/agent-native.js +264 -27
- package/dist/app.d.ts +5 -5
- package/dist/app.js +42 -10
- package/dist/assets.d.ts +23 -0
- package/dist/assets.js +123 -0
- package/dist/blob.d.ts +4 -5
- package/dist/build.d.ts +8 -30
- package/dist/build.js +143 -298
- package/dist/client-bundle.d.ts +8 -9
- package/dist/client-bundle.js +1 -1
- package/dist/config-freeze-r5p-vTWv.d.ts +17 -0
- package/dist/config-freeze.d.ts +2 -0
- package/dist/config-freeze.js +54 -0
- package/dist/config-loader.d.ts +3 -4
- package/dist/connection-auth.d.ts +38 -0
- package/dist/connection-auth.js +31 -0
- package/dist/content-freeze-CyiW2fRK.d.ts +4 -0
- package/dist/content-freeze.d.ts +2 -0
- package/dist/content-freeze.js +83 -0
- package/dist/content.d.ts +22 -9
- package/dist/content.js +43 -3
- package/dist/core-version.d.ts +4 -0
- package/dist/core-version.js +12 -0
- package/dist/css-modules-ambient.d.ts +2 -1
- package/dist/css-modules.d.ts +10 -11
- package/dist/css.d.ts +9 -10
- package/dist/d1-migrate.d.ts +6 -7
- package/dist/d1-migrate.js +3 -2
- package/dist/db.d.ts +2 -2
- package/dist/deploy.d.ts +3 -4
- package/dist/deploy.js +3 -2
- package/dist/dev-reload.d.ts +3 -4
- package/dist/dev.d.ts +8 -5
- package/dist/dev.js +40 -9
- package/dist/favicon.d.ts +37 -0
- package/dist/favicon.js +248 -0
- package/dist/host.d.ts +6 -5
- package/dist/host.js +2 -1
- package/dist/icon-letter.d.ts +3 -0
- package/dist/icon-letter.js +8 -0
- package/dist/index.d.ts +11 -5
- package/dist/index.js +9 -3
- package/dist/instrumentation.d.ts +2 -3
- package/dist/instrumentation.js +2 -1
- package/dist/island-registry.d.ts +6 -7
- package/dist/isolate-local.d.ts +5 -0
- package/dist/isolate-local.js +12 -0
- package/dist/kv.d.ts +3 -4
- package/dist/llms-links.d.ts +9 -0
- package/dist/llms-links.js +65 -0
- package/dist/manifest-CwTT1zVs.d.ts +11 -0
- package/dist/manifest.d.ts +2 -0
- package/dist/manifest.js +113 -0
- package/dist/negotiate.d.ts +4 -3
- package/dist/negotiate.js +24 -14
- package/dist/{pipeline-CCp9idQ4.d.ts → pipeline-BHUjBO0G.d.ts} +13 -1
- package/dist/pipeline.d.ts +2 -2
- package/dist/pipeline.js +286 -35
- package/dist/resources.d.ts +5 -6
- package/dist/route-rank.d.ts +6 -7
- package/dist/route-scan-BMbBzPIB.d.ts +20 -0
- package/dist/route-scan.d.ts +2 -0
- package/dist/route-scan.js +100 -0
- package/dist/router.d.ts +12 -13
- package/dist/router.js +51 -38
- package/dist/rsc-build.d.ts +6 -7
- package/dist/rsc-bundle.d.ts +6 -7
- package/dist/rsc-manifest.d.ts +5 -6
- package/dist/rsc-runtime/flight-render-routes.d.ts +3 -4
- package/dist/rsc-runtime/flight-render.d.ts +2 -3
- package/dist/rsc-runtime/flight-to-html.d.ts +2 -3
- package/dist/rsc-runtime/flight-to-html.js +3 -2
- package/dist/rsc-runtime/rsc-worker.js +11 -8
- package/dist/rsc-runtime/rsdw-shims.d.ts +2 -1
- package/dist/segment.d.ts +4 -5
- package/dist/sqlite-driver.d.ts +11 -11
- package/dist/sqlite-driver.js +17 -4
- package/dist/static-files.d.ts +4 -5
- package/dist/tsconfig-jsx.d.ts +4 -4
- package/dist/tsconfig-jsx.js +1 -1
- package/dist/turn-events.d.ts +4 -0
- package/dist/turn-events.js +46 -0
- package/dist/web-manifest.d.ts +5 -0
- package/dist/web-manifest.js +42 -0
- package/dist/worker-2qbQjj2c.d.ts +64 -0
- package/dist/worker.d.ts +2 -57
- package/dist/worker.js +69 -27
- package/package.json +28 -9
- package/src/adapter.ts +149 -4
- package/src/agent-compile.ts +271 -0
- package/src/agent-discover.ts +77 -63
- package/src/agent-durable.ts +998 -30
- package/src/agent-native.ts +370 -35
- package/src/app.ts +75 -6
- package/src/assets.ts +200 -0
- package/src/build.ts +241 -449
- package/src/config-freeze.ts +109 -0
- package/src/connection-auth.ts +101 -0
- package/src/content-freeze.ts +151 -0
- package/src/content.ts +55 -4
- package/src/core-version.ts +34 -0
- package/src/dev.ts +41 -8
- package/src/favicon.ts +325 -0
- package/src/host.ts +4 -3
- package/src/icon-letter.ts +14 -0
- package/src/index.ts +22 -0
- package/src/isolate-local.ts +33 -0
- package/src/llms-links.ts +96 -0
- package/src/manifest.ts +130 -0
- package/src/negotiate.ts +39 -15
- package/src/pipeline.ts +494 -44
- package/src/route-scan.ts +161 -0
- package/src/router.ts +66 -54
- package/src/rsc-runtime/rsc-worker.tsx +5 -4
- package/src/sqlite-driver.ts +36 -6
- package/src/tsconfig-jsx.ts +2 -2
- package/src/turn-events.ts +43 -0
- package/src/web-manifest.ts +38 -0
- package/src/worker.ts +131 -35
package/src/worker.ts
CHANGED
|
@@ -17,11 +17,22 @@ import type { DocumentConfig } from "@junejs/core/document";
|
|
|
17
17
|
import type { I18nConfig } from "@junejs/core/i18n";
|
|
18
18
|
import type { Resources } from "@junejs/core/resources";
|
|
19
19
|
|
|
20
|
+
import type { Channel, ChannelFactory } from "@junejs/core/agent-config";
|
|
21
|
+
import { blobFileStore } from "@junejs/core/agent-files";
|
|
22
|
+
|
|
20
23
|
import { createPipeline, type ExtraHandler, type LayoutComponent, type LoadingComponent, type Resolved, type ResolvedResource, type ResourceHandler } from "./pipeline";
|
|
21
|
-
import { durableAgentSurface, type DurableObjectNamespace } from "./agent-durable";
|
|
24
|
+
import { durableAgentSurface, durableChannelSurface, type DurableObjectNamespace } from "./agent-durable";
|
|
25
|
+
import { acceptTarget } from "./negotiate";
|
|
22
26
|
import { compareRoutePatterns, parseSegment } from "./route-rank";
|
|
23
27
|
import { contentTypeFor, RESERVED_PREFIX, safeRelativePath } from "./static-files";
|
|
24
28
|
|
|
29
|
+
// The slice of workerd's ExecutionContext the worker threads through: webhook
|
|
30
|
+
// channels ACK fast and finish their work (post the reply out-of-band) on
|
|
31
|
+
// waitUntil — without it a floating promise can be killed when the isolate is
|
|
32
|
+
// reclaimed. Optional end to end; a host without it (tests, other targets)
|
|
33
|
+
// simply doesn't extend the invocation.
|
|
34
|
+
export type WorkerExecutionContext = { waitUntil?(p: Promise<unknown>): void };
|
|
35
|
+
|
|
25
36
|
export type WorkerManifest = {
|
|
26
37
|
// Static paths → route definitions ("/", "/users", ...).
|
|
27
38
|
routes: Record<string, BrandedRoute>;
|
|
@@ -51,6 +62,13 @@ export type WorkerManifest = {
|
|
|
51
62
|
// by the build when an agent/ directory exists; absent → no durable agent on
|
|
52
63
|
// the edge. The DO namespace binding is `env.AGENT`.
|
|
53
64
|
agentName?: string;
|
|
65
|
+
// The agent's channels (Channel or `(env) => Channel` factories, from the
|
|
66
|
+
// compiled agent module) — mounted as webhook routes on the worker via
|
|
67
|
+
// durableChannelSurface when agent.runtime.channels is on. The SAME factories
|
|
68
|
+
// are also wired into the DO (DoAgentDef.channels) by the generated entry, so
|
|
69
|
+
// capability tools and host-side delivery work; this field is the WORKER half
|
|
70
|
+
// (verify the webhook, run the turn on the DO, reply on waitUntil).
|
|
71
|
+
agentChannels?: (Channel | ChannelFactory)[];
|
|
54
72
|
// Locale routing config, frozen from june.config.ts `i18n`. The locales table
|
|
55
73
|
// is plain data; a `resolveLocale` hook survives the in-process freeze (parity
|
|
56
74
|
// test) but not JSON codegen — worker hook support lands with the codegen pass.
|
|
@@ -106,9 +124,12 @@ function compilePattern(pattern: string): { regex: RegExp; names: string[] } {
|
|
|
106
124
|
return { regex: new RegExp(allOptional ? `^(?:${source}|/)$` : `^${source}$`), names };
|
|
107
125
|
}
|
|
108
126
|
|
|
127
|
+
// opts.staticBuild: set only by the static() build's in-process prerender worker
|
|
128
|
+
// (see PipelineConfig.staticBuild) — never by a deployed entry.
|
|
109
129
|
export function createWorker(
|
|
110
130
|
manifest: WorkerManifest,
|
|
111
|
-
|
|
131
|
+
opts: { staticBuild?: boolean } = {},
|
|
132
|
+
): { fetch(request: Request, env?: unknown, ctx?: WorkerExecutionContext): Promise<Response> } {
|
|
112
133
|
// Pages and resource routes in ONE table, ordered the way `june dev` resolves
|
|
113
134
|
// (#312): app/ before .june/routes/, then segment shape (static > [param] >
|
|
114
135
|
// [...catchAll], required before optional), then a page before a resource
|
|
@@ -149,8 +170,14 @@ export function createWorker(
|
|
|
149
170
|
|
|
150
171
|
// The worker's env (D1/KV/R2 bindings) arrives per fetch and is stable across
|
|
151
172
|
// requests in an isolate; we capture the latest and hand it to the env-aware
|
|
152
|
-
// provider, which memoizes the opened handles on first call.
|
|
173
|
+
// provider, which memoizes the opened handles on first call. That "latest"
|
|
174
|
+
// pattern is safe ONLY for per-isolate-stable values — concurrent fetches
|
|
175
|
+
// interleave at await points, so anything per-INVOCATION (the execution
|
|
176
|
+
// context, and env used at a specific moment) must come from request-scoped
|
|
177
|
+
// storage instead: `requestLocals`, keyed by the Request identity that flows
|
|
178
|
+
// unchanged from fetch() through the pipeline to the agent surface.
|
|
153
179
|
let currentEnv: unknown;
|
|
180
|
+
const requestLocals = new WeakMap<Request, { env: unknown; ctx?: WorkerExecutionContext }>();
|
|
154
181
|
const provider = manifest.resources;
|
|
155
182
|
|
|
156
183
|
// App services: the build sets a raw `(env) => services` factory here; memoize it per
|
|
@@ -159,18 +186,52 @@ export function createWorker(
|
|
|
159
186
|
const servicesProvider = manifest.services;
|
|
160
187
|
let servicesCache: { v: unknown } | undefined;
|
|
161
188
|
|
|
162
|
-
// Durable agent (edge): route the chat endpoint
|
|
163
|
-
// env.AGENT. Built only when the app
|
|
164
|
-
// runtime is enabled; the surface is
|
|
165
|
-
// is present, so a worker without
|
|
189
|
+
// Durable agent (edge): route the chat endpoint — and the agent's channel
|
|
190
|
+
// webhooks — to the per-session DO bound at env.AGENT. Built only when the app
|
|
191
|
+
// has an agent (manifest.agentName) and the runtime is enabled; the surface is
|
|
192
|
+
// inert (null → fall through) until env.AGENT is present, so a worker without
|
|
193
|
+
// the DO binding is unaffected.
|
|
166
194
|
const agentSurface =
|
|
167
195
|
manifest.agent.runtime.enabled && manifest.agentName
|
|
168
196
|
? (() => {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
197
|
+
const agentName = manifest.agentName;
|
|
198
|
+
const wantChannels = manifest.agent.runtime.channels !== false && (manifest.agentChannels?.length ?? 0) > 0;
|
|
199
|
+
return async (req: Request): Promise<Response | null> => {
|
|
200
|
+
// REQUEST-scoped, not isolate-scoped: the pipeline awaits between
|
|
201
|
+
// fetch() and this call, so a concurrent fetch may have run since —
|
|
202
|
+
// a module-level "current request" variable here would hand this
|
|
203
|
+
// webhook ANOTHER request's env (wrong AGENT namespace, factories
|
|
204
|
+
// resolved against foreign secrets) and register its background
|
|
205
|
+
// work on another invocation's waitUntil. Everything below reads
|
|
206
|
+
// THIS request's locals.
|
|
207
|
+
const locals = requestLocals.get(req);
|
|
208
|
+
const ns = () => (locals?.env as { AGENT?: DurableObjectNamespace } | undefined)?.AGENT;
|
|
209
|
+
const chat = durableAgentSurface(ns, { agentName, chatPath: manifest.agent.runtime.chat.path });
|
|
210
|
+
const chatRes = await chat(req);
|
|
211
|
+
if (chatRes) return chatRes;
|
|
212
|
+
if (!wantChannels) return null;
|
|
213
|
+
// Constructed per request — cheap by design: resolveChannel is a
|
|
214
|
+
// call, and resolveServices memoizes the app services bag per
|
|
215
|
+
// (env, agentName), exactly for this construction pattern (see
|
|
216
|
+
// durableChannelSurface's services doc).
|
|
217
|
+
const channels = durableChannelSurface(ns, {
|
|
218
|
+
agentName,
|
|
219
|
+
channels: manifest.agentChannels!,
|
|
220
|
+
env: locals?.env,
|
|
221
|
+
services: servicesProvider,
|
|
222
|
+
waitUntil: locals?.ctx?.waitUntil?.bind(locals.ctx),
|
|
223
|
+
// The blob resource the agent's Durable Object stores files in, opened from
|
|
224
|
+
// this isolate's env — the channels read attached files back from it.
|
|
225
|
+
files: provider
|
|
226
|
+
? blobFileStore(async () => {
|
|
227
|
+
const blob = (await provider(locals?.env)).blob;
|
|
228
|
+
if (!blob) throw new Error(`agent "${agentName}": no blob resource bound in this isolate — attached files can't be read`);
|
|
229
|
+
return blob;
|
|
230
|
+
})
|
|
231
|
+
: undefined,
|
|
232
|
+
});
|
|
233
|
+
return channels(req);
|
|
234
|
+
};
|
|
174
235
|
})()
|
|
175
236
|
: undefined;
|
|
176
237
|
|
|
@@ -180,6 +241,7 @@ export function createWorker(
|
|
|
180
241
|
agentSurface,
|
|
181
242
|
i18n: manifest.i18n,
|
|
182
243
|
routeList: () => routeList,
|
|
244
|
+
staticBuild: opts.staticBuild,
|
|
183
245
|
earlyHints: manifest.earlyHints,
|
|
184
246
|
htmlCacheControl: manifest.htmlCacheControl,
|
|
185
247
|
notFoundComponent: manifest.notFound,
|
|
@@ -208,8 +270,9 @@ export function createWorker(
|
|
|
208
270
|
});
|
|
209
271
|
|
|
210
272
|
return {
|
|
211
|
-
fetch(request, env) {
|
|
212
|
-
currentEnv = env;
|
|
273
|
+
fetch(request, env, ctx) {
|
|
274
|
+
currentEnv = env; // per-isolate-stable consumers only (resources/services)
|
|
275
|
+
requestLocals.set(request, { env, ctx }); // per-invocation consumers (agent surface)
|
|
213
276
|
return pipeline.fetch(request);
|
|
214
277
|
},
|
|
215
278
|
};
|
|
@@ -218,43 +281,71 @@ export function createWorker(
|
|
|
218
281
|
// --- the deployed worker's outermost layer (run_worker_first) ---------------
|
|
219
282
|
// Prerendered pages are served as static ASSETS, which bypass the pipeline —
|
|
220
283
|
// so the agent-ready signals the asset layer can't produce get added HERE:
|
|
221
|
-
// 1.
|
|
284
|
+
// 1. a negotiated projection on a page (Accept: text/markdown / application/
|
|
285
|
+
// json → the prerendered .md / .json asset; else, and for the client
|
|
286
|
+
// router's fragment, the pipeline — never the page's HTML asset).
|
|
222
287
|
// 2. a `Link` header on every HTML response (RFC 8288/9727 discovery).
|
|
223
288
|
// 3. `x-markdown-tokens` on markdown responses.
|
|
224
289
|
// Static assets are served by the ASSETS binding (no re-render); only genuinely
|
|
225
290
|
// dynamic routes reach the pipeline. With no ASSETS binding (no prerender), this
|
|
226
291
|
// is a transparent pass-through to the pipeline.
|
|
227
292
|
type AssetEnv = { ASSETS?: { fetch(request: Request): Promise<Response> } };
|
|
228
|
-
type FetchPipeline = { fetch(request: Request, env?: unknown): Promise<Response> };
|
|
293
|
+
type FetchPipeline = { fetch(request: Request, env?: unknown, ctx?: WorkerExecutionContext): Promise<Response> };
|
|
229
294
|
|
|
230
295
|
const estimateTokens = (s: string) => String(Math.ceil(s.length / 4));
|
|
231
296
|
|
|
297
|
+
// Add Accept to a response's Vary, keeping whatever the asset layer already set.
|
|
298
|
+
function varyAccept(headers: Headers): void {
|
|
299
|
+
const vary = headers.get("vary");
|
|
300
|
+
if (!vary) headers.set("vary", "accept");
|
|
301
|
+
else if (vary.trim() !== "*" && !vary.split(",").some((v) => v.trim().toLowerCase() === "accept")) {
|
|
302
|
+
headers.set("vary", `${vary}, accept`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
232
306
|
export function withAssets(
|
|
233
307
|
pipeline: FetchPipeline,
|
|
234
308
|
opts: { link?: string | null } = {},
|
|
235
|
-
): { fetch(request: Request, env?: AssetEnv): Promise<Response> } {
|
|
309
|
+
): { fetch(request: Request, env?: AssetEnv, ctx?: WorkerExecutionContext): Promise<Response> } {
|
|
236
310
|
return {
|
|
237
|
-
async fetch(request, env) {
|
|
311
|
+
async fetch(request, env, ctx) {
|
|
238
312
|
const assets = env?.ASSETS;
|
|
239
313
|
const url = new URL(request.url);
|
|
240
314
|
const isPagePath = !/\.[a-z0-9]+$/i.test(url.pathname); // no file extension
|
|
241
|
-
|
|
315
|
+
// The pipeline's own Accept decision (q-values included). A page path that
|
|
316
|
+
// negotiates a projection other than the HTML view must get THAT projection
|
|
317
|
+
// or the pipeline's answer for it — never the prerendered HTML asset.
|
|
318
|
+
const target = isPagePath ? acceptTarget(request.headers.get("accept") ?? "") : null;
|
|
242
319
|
|
|
243
|
-
// 1.
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
320
|
+
// 1. Negotiated projections on a page path.
|
|
321
|
+
if (target && (request.method === "GET" || request.method === "HEAD")) {
|
|
322
|
+
// md / json → the prerendered <path>.md / <path>.json asset when the build
|
|
323
|
+
// emitted one (.md unless md = false; .json only for a json() route). Only
|
|
324
|
+
// the flat file — never <path>/index.*, a distinct /path/index route's twin
|
|
325
|
+
// (locale homes' <locale>/index.* are a static()-target artifact; this
|
|
326
|
+
// workers()-only layer never has them).
|
|
327
|
+
if (assets && request.method === "GET" && (target === "md" || target === "json")) {
|
|
328
|
+
const base = url.pathname === "/" ? "/index" : url.pathname.replace(/\/+$/, "");
|
|
329
|
+
const assetUrl = new URL(url);
|
|
330
|
+
assetUrl.pathname = `${base}.${target}`;
|
|
331
|
+
const a = await assets.fetch(new Request(assetUrl.toString(), { headers: request.headers }));
|
|
332
|
+
if (a.ok) {
|
|
333
|
+
const headers = new Headers(a.headers);
|
|
334
|
+
if (opts.link) headers.set("link", opts.link);
|
|
335
|
+
varyAccept(headers);
|
|
336
|
+
if (target === "json") return new Response(a.body, { status: 200, headers });
|
|
337
|
+
const body = await a.text();
|
|
338
|
+
headers.set("content-type", "text/markdown; charset=utf-8");
|
|
339
|
+
headers.set("x-markdown-tokens", estimateTokens(body));
|
|
340
|
+
return new Response(body, { status: 200, headers });
|
|
341
|
+
}
|
|
256
342
|
}
|
|
257
|
-
//
|
|
343
|
+
// No such asset (or a fragment, or HEAD) → the pipeline (step 3). It renders
|
|
344
|
+
// a dynamic route's projection, derives .json from the loader data, 404s a
|
|
345
|
+
// disabled projection, and renders the client router's soft-nav fragment —
|
|
346
|
+
// the HTML asset is a full DOCUMENT, which the router would morph into its
|
|
347
|
+
// [data-june-root] as if it were the root's inner HTML.
|
|
348
|
+
return pipeline.fetch(request, env, ctx);
|
|
258
349
|
}
|
|
259
350
|
|
|
260
351
|
// 2. Static assets (prerendered HTML/.md/.json, /client.js, hashed CSS)
|
|
@@ -271,10 +362,15 @@ export function withAssets(
|
|
|
271
362
|
// URL changes when the bytes do, so the browser may cache forever and
|
|
272
363
|
// never revalidate (no 304 round-trip, no stale window).
|
|
273
364
|
const immutable = /\.[a-f0-9]{8,}\.(css|js)$/.test(url.pathname);
|
|
274
|
-
|
|
365
|
+
// A page path answers HTML here but Markdown under Accept: text/markdown
|
|
366
|
+
// (step 1) — the same URL, so caches must key on Accept or they hand an
|
|
367
|
+
// agent the HTML (or a browser the Markdown).
|
|
368
|
+
const negotiated = isPagePath && ct.includes("text/html");
|
|
369
|
+
if (addLink || immutable || negotiated) {
|
|
275
370
|
const headers = new Headers(a.headers);
|
|
276
371
|
if (addLink) headers.set("link", opts.link!);
|
|
277
372
|
if (immutable) headers.set("cache-control", "public, max-age=31536000, immutable");
|
|
373
|
+
if (negotiated) varyAccept(headers);
|
|
278
374
|
return new Response(a.body, { status: a.status, headers });
|
|
279
375
|
}
|
|
280
376
|
return a;
|
|
@@ -283,7 +379,7 @@ export function withAssets(
|
|
|
283
379
|
|
|
284
380
|
// 3. Dynamic routes → the render pipeline (already sets Link + negotiates).
|
|
285
381
|
// Env flows through so the pipeline's resources get the D1/KV/R2 bindings.
|
|
286
|
-
return pipeline.fetch(request, env);
|
|
382
|
+
return pipeline.fetch(request, env, ctx);
|
|
287
383
|
},
|
|
288
384
|
};
|
|
289
385
|
}
|