@sjcx/vorma 0.0.0-pre.2 → 0.0.0-pre.4

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.
Files changed (137) hide show
  1. package/dist/build/assemble-artifacts.d.ts +1 -1
  2. package/dist/build/bundle-client.d.ts +1 -1
  3. package/dist/build/cli.js +53 -44
  4. package/dist/build/compile-application.d.ts +2 -2
  5. package/dist/build/development-artifacts.d.ts +1 -1
  6. package/dist/build/development-build.d.ts +3 -6
  7. package/dist/build/development-server-process.d.ts +3 -3
  8. package/dist/build/development-work.d.ts +4 -3
  9. package/dist/build/generate-application.d.ts +4 -4
  10. package/dist/build/index.d.ts +2 -3
  11. package/dist/build/index.js +1 -1
  12. package/dist/build/inspect-projects.d.ts +3 -3
  13. package/dist/build/load-config.d.ts +17 -16
  14. package/dist/build/publish-artifacts.d.ts +1 -4
  15. package/dist/build/render-client-transport.d.ts +1 -1
  16. package/dist/build/render-server-generated.d.ts +1 -12
  17. package/dist/build/render-types.d.ts +1 -1
  18. package/dist/build/resolve-config.d.ts +6 -9
  19. package/dist/build/source-layout.d.ts +2 -2
  20. package/dist/build/typescript-projects.d.ts +5 -0
  21. package/dist/{build-DcP5_DUV.js → build-BeUTL6eX.js} +104 -301
  22. package/package.json +5 -36
  23. package/dist/build/compile-server.d.ts +0 -42
  24. package/dist/client/assembly.d.ts +0 -40
  25. package/dist/client/browser-http-client.d.ts +0 -10
  26. package/dist/client/client-loaders.d.ts +0 -93
  27. package/dist/client/commit.d.ts +0 -41
  28. package/dist/client/contracts.d.ts +0 -192
  29. package/dist/client/core.d.ts +0 -45
  30. package/dist/client/development.d.ts +0 -16
  31. package/dist/client/document-recovery.d.ts +0 -4
  32. package/dist/client/endpoints.d.ts +0 -54
  33. package/dist/client/errors.d.ts +0 -87
  34. package/dist/client/freshness.d.ts +0 -51
  35. package/dist/client/head.d.ts +0 -14
  36. package/dist/client/history.d.ts +0 -25
  37. package/dist/client/index.d.ts +0 -80
  38. package/dist/client/index.js +0 -150
  39. package/dist/client/links.d.ts +0 -48
  40. package/dist/client/materialize.d.ts +0 -21
  41. package/dist/client/modules.d.ts +0 -2
  42. package/dist/client/navigation.d.ts +0 -47
  43. package/dist/client/payload.d.ts +0 -54
  44. package/dist/client/prefetch.d.ts +0 -28
  45. package/dist/client/prepare.d.ts +0 -47
  46. package/dist/client/projections.d.ts +0 -26
  47. package/dist/client/queries.d.ts +0 -33
  48. package/dist/client/react/application.d.ts +0 -87
  49. package/dist/client/react/hooks.d.ts +0 -36
  50. package/dist/client/react/index.d.ts +0 -5
  51. package/dist/client/react/index.js +0 -3237
  52. package/dist/client/react/link.d.ts +0 -27
  53. package/dist/client/react/view.d.ts +0 -86
  54. package/dist/client/request.d.ts +0 -16
  55. package/dist/client/route-context.d.ts +0 -31
  56. package/dist/client/route-matching.d.ts +0 -22
  57. package/dist/client/route-synchronization.d.ts +0 -30
  58. package/dist/client/route-url.d.ts +0 -5
  59. package/dist/client/runtime.d.ts +0 -82
  60. package/dist/client/scroll.d.ts +0 -16
  61. package/dist/client/services.d.ts +0 -34
  62. package/dist/client/state.d.ts +0 -102
  63. package/dist/client/static-assets.d.ts +0 -3
  64. package/dist/client/stylesheets.d.ts +0 -7
  65. package/dist/client/transport-type-entries.d.ts +0 -2
  66. package/dist/client/types.d.ts +0 -152
  67. package/dist/client/view-definition.d.ts +0 -24
  68. package/dist/client/work-indicator.d.ts +0 -18
  69. package/dist/compile-Me8EOyMK.js +0 -870
  70. package/dist/development-B_rxuwY7.js +0 -128
  71. package/dist/hash-set-BPx3iXec.js +0 -141
  72. package/dist/href-Cqyax8Y0.js +0 -357
  73. package/dist/materialize-DZ7VSLFk.js +0 -739
  74. package/dist/metadata-BoPKo-G2.js +0 -32
  75. package/dist/primitives/tasks/index.d.ts +0 -1
  76. package/dist/primitives/tasks/index.js +0 -1
  77. package/dist/route-context-CtY_9U_W.js +0 -559
  78. package/dist/route-matching-D_uSG2P9.js +0 -33
  79. package/dist/search-parse-0f7oqVsG.js +0 -375
  80. package/dist/server/config/index.d.ts +0 -36
  81. package/dist/server/config/index.js +0 -30
  82. package/dist/server/development/metadata.d.ts +0 -11
  83. package/dist/server/document.d.ts +0 -37
  84. package/dist/server/form-data.d.ts +0 -21
  85. package/dist/server/graph/compile.d.ts +0 -118
  86. package/dist/server/graph/declarations.d.ts +0 -117
  87. package/dist/server/graph/literal-error-tag.d.ts +0 -14
  88. package/dist/server/graph/pattern-conflicts.d.ts +0 -36
  89. package/dist/server/graph/search-schema.d.ts +0 -13
  90. package/dist/server/graph/transport-schema.d.ts +0 -11
  91. package/dist/server/index.d.ts +0 -310
  92. package/dist/server/index.js +0 -2311
  93. package/dist/server/public-assets.d.ts +0 -18
  94. package/dist/server/runtime/application.d.ts +0 -15
  95. package/dist/server/runtime/assets.d.ts +0 -15
  96. package/dist/server/runtime/context.d.ts +0 -96
  97. package/dist/server/runtime/domain-errors.d.ts +0 -11
  98. package/dist/server/runtime/effects.d.ts +0 -83
  99. package/dist/server/runtime/execute.d.ts +0 -13
  100. package/dist/server/runtime/finalize.d.ts +0 -44
  101. package/dist/server/runtime/handler.d.ts +0 -106
  102. package/dist/server/runtime/head.d.ts +0 -22
  103. package/dist/server/runtime/payload.d.ts +0 -50
  104. package/dist/server/runtime/pipeline.d.ts +0 -27
  105. package/dist/server/runtime/plan.d.ts +0 -98
  106. package/dist/server/runtime/render-document.d.ts +0 -16
  107. package/dist/server/runtime/startup-error.d.ts +0 -11
  108. package/dist/server/runtime/transport-type-entries.d.ts +0 -2
  109. package/dist/server/runtime/vercel-deployment.d.ts +0 -2
  110. package/dist/server/url-pathname.d.ts +0 -13
  111. package/dist/static-assets-BrH3O0M8.js +0 -199
  112. package/dist/universal/generated-types.d.ts +0 -9
  113. package/dist/universal/href.d.ts +0 -17
  114. package/dist/universal/http-method.d.ts +0 -4
  115. package/dist/universal/json-transport.d.ts +0 -14
  116. package/dist/universal/null-prototype-record.d.ts +0 -7
  117. package/dist/universal/path-wire.d.ts +0 -71
  118. package/dist/universal/pattern-language.d.ts +0 -4
  119. package/dist/universal/protocol-schemas.d.ts +0 -99
  120. package/dist/universal/protocol.d.ts +0 -162
  121. package/dist/universal/search-grammar.d.ts +0 -7
  122. package/dist/universal/search-parse.d.ts +0 -22
  123. package/dist/universal/search-serialize.d.ts +0 -16
  124. package/dist/universal/search-shape.d.ts +0 -32
  125. package/dist/universal/static-assets.d.ts +0 -2
  126. package/dist/universal/transport-types/big-decimal.d.ts +0 -13
  127. package/dist/universal/transport-types/chunk.d.ts +0 -8
  128. package/dist/universal/transport-types/date-time-utc.d.ts +0 -13
  129. package/dist/universal/transport-types/date-time-zoned.d.ts +0 -13
  130. package/dist/universal/transport-types/duration.d.ts +0 -13
  131. package/dist/universal/transport-types/hash-map.d.ts +0 -8
  132. package/dist/universal/transport-types/hash-set.d.ts +0 -8
  133. package/dist/universal/transport-types/option.d.ts +0 -10
  134. package/dist/universal/transport-types/redacted.d.ts +0 -9
  135. package/dist/universal/value-transport.d.ts +0 -117
  136. package/dist/value-transport-Bst4Hk-n.js +0 -864
  137. /package/dist/{universal → build}/content-digest.d.ts +0 -0
@@ -1,2311 +0,0 @@
1
- import { _ as DOCUMENT_PROTOCOL, b as HTTP_PROTOCOL, c as compileUiPattern, g as DEVELOPMENT_PROTOCOL, i as encodeTransportedValue, l as decodeMatchCaptures, m as ARTIFACT_PROTOCOL, o as canonicalizeRequestPathForMatcher, p as makeNullPrototypeRecord, r as decodeTransportedValue, x as PROCESS_ENVIRONMENT_PROTOCOL } from "../value-transport-Bst4Hk-n.js";
2
- import { a as compileUiLoader, d as FormData, i as compileMiddleware, l as getLiteralErrorTag, n as checkEndpointPatternRegistrations, o as createNestedRouteChains, r as compileEndpoint, s as groupEndpointsByMethod, t as checkDuplicates, u as getInputTransport } from "../compile-Me8EOyMK.js";
3
- import { n as getOwnEntries, r as projectSearchFields, t as buildHref } from "../href-Cqyax8Y0.js";
4
- import { a as bigDecimalTransportType, c as redactedTransportType, i as dateTimeUtcTransportType, l as optionTransportType, n as hashMapTransportType, o as durationTransportType, r as dateTimeZonedTransportType, s as chunkTransportType, t as hashSetTransportType } from "../hash-set-BPx3iXec.js";
5
- import { i as readTransportedValue, t as getStaticAssetDestination } from "../static-assets-BrH3O0M8.js";
6
- import { t as parseSearchParams } from "../search-parse-0f7oqVsG.js";
7
- import { Cause, Config, Context, Data, Deferred, Effect, Exit, Fiber, Layer, Option, Record, Ref, Result, Schema } from "effect";
8
- import { base64 } from "@scure/base";
9
- import * as Path$1 from "effect/Path";
10
- import { createFlatMatcher, createFlatValueMatcher, createNestedValueMatcher, findBestMatch, findBestValueMatch, findNestedValueMatches } from "@vorma/primitives/matcher";
11
- import { HttpServerError, HttpServerRequest, HttpServerResponse, UrlParams } from "effect/unstable/http";
12
- import { TaskContext, TaskRuntime } from "@vorma/primitives/tasks";
13
- import { sha256 } from "@noble/hashes/sha2.js";
14
- import * as HttpPlatform from "effect/unstable/http/HttpPlatform";
15
- import * as HttpServerRequest$1 from "effect/unstable/http/HttpServerRequest";
16
- import * as HttpServerResponse$1 from "effect/unstable/http/HttpServerResponse";
17
- import { memoize } from "effect/Function";
18
- import * as Cookies from "effect/unstable/http/Cookies";
19
- import * as Headers$1 from "effect/unstable/http/Headers";
20
- //#region src/server/runtime/startup-error.ts
21
- function createVormaStartupError(input) {
22
- return {
23
- _tag: "VormaStartupError",
24
- operation: input.operation,
25
- message: input.message,
26
- ...input.cause === void 0 ? {} : { cause: input.cause }
27
- };
28
- }
29
- //#endregion
30
- //#region src/server/runtime/application.ts
31
- const ApplicationRuntime = Context.Service("vorma/server/ApplicationRuntime");
32
- const APPLICATION_RUNTIME = Symbol("vorma/server/ApplicationRuntimeLayer");
33
- /** One shared acquisition for an application's compiled registration and asset metadata. */
34
- function makeApplicationRuntime(config) {
35
- return Layer.effect(ApplicationRuntime, Effect.tryPromise({
36
- try: async () => {
37
- const [registration, metadata] = await Promise.all([import(new URL(`./${ARTIFACT_PROTOCOL.compiledRuntimeFileName}`, config.importMeta.url).href), import(new URL(`./${ARTIFACT_PROTOCOL.productionMetadataFileName}`, config.importMeta.url).href, { with: { type: "json" } })]);
38
- const initial = {
39
- ...metadata.default,
40
- publicAssetDirectoryUrl: registration.publicAssetDirectoryUrl
41
- };
42
- return {
43
- registeredDeclarations: registration.registeredDeclarations,
44
- metadata: initial,
45
- ...initial.runtimeMode === "development" ? { readDevelopmentMetadata: (await import("../metadata-BoPKo-G2.js")).createDevelopmentMetadataReader({
46
- url: new URL(`./${ARTIFACT_PROTOCOL.productionMetadataFileName}`, config.importMeta.url),
47
- initial
48
- }) } : {}
49
- };
50
- },
51
- catch: (cause) => {
52
- return createVormaStartupError({
53
- operation: "loadApplicationRuntime",
54
- message: "Vorma could not load its compiled application runtime. Build the application and start its compiled server entry.",
55
- cause
56
- });
57
- }
58
- }));
59
- }
60
- //#endregion
61
- //#region src/server/public-assets.ts
62
- /** A content-addressed public asset remains immutable at its published URL. */
63
- const IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
64
- function resolvePublicAssetFilePaths(input) {
65
- return Effect.gen(function* () {
66
- const { metadata, path } = input;
67
- const directoryUrl = yield* Schema.decodeUnknownEffect(Schema.URLFromString)(metadata.publicAssetDirectoryUrl).pipe(Effect.mapError((cause) => {
68
- return createVormaStartupError({
69
- operation: "resolvePublicAssetDirectory",
70
- message: `Vorma production metadata does not carry a valid public asset directory URL: ${metadata.publicAssetDirectoryUrl}`,
71
- cause
72
- });
73
- }));
74
- const directory = yield* path.fromFileUrl(directoryUrl).pipe(Effect.mapError((cause) => {
75
- return createVormaStartupError({
76
- operation: "resolvePublicAssetDirectory",
77
- message: `Vorma public asset bytes are not on a local filesystem: ${metadata.publicAssetDirectoryUrl}`,
78
- cause
79
- });
80
- }));
81
- const filePathsByUrl = /* @__PURE__ */ new Map();
82
- for (const file of metadata.publicFiles) filePathsByUrl.set(file.url, {
83
- filePath: path.join(directory, ...file.fileName.split("/")),
84
- immutable: file.immutable
85
- });
86
- return filePathsByUrl;
87
- });
88
- }
89
- function serveFile(input) {
90
- return HttpServerResponse$1.file(input.file.filePath, { headers: input.file.immutable ? { "cache-control": IMMUTABLE_CACHE_CONTROL } : {} }).pipe(Effect.provideService(HttpPlatform.HttpPlatform, input.platform));
91
- }
92
- /**
93
- * Serves the build's public directory from the process filesystem. Requests for
94
- * URLs outside the published set, and every other method than `GET` and `HEAD`,
95
- * continue to the host's own router. The host passes its explicitly assembled
96
- * application so that this constructor can read the build metadata. The caller
97
- * explicitly registers the returned middleware through the host router.
98
- */
99
- function makePublicAssetsFileMiddleware(input) {
100
- return Effect.gen(function* () {
101
- const path = yield* Path$1.Path;
102
- const runtime = yield* ApplicationRuntime;
103
- const { metadata } = runtime;
104
- let resolvedMetadata = metadata;
105
- let filePathsByUrl = yield* resolvePublicAssetFilePaths({
106
- metadata,
107
- path
108
- });
109
- const platform = yield* HttpPlatform.HttpPlatform;
110
- return (httpEffect) => {
111
- return Effect.gen(function* () {
112
- const request = yield* HttpServerRequest$1.HttpServerRequest;
113
- const method = request.method;
114
- if (method !== "GET" && method !== "HEAD") return yield* httpEffect;
115
- if (runtime.readDevelopmentMetadata !== void 0) {
116
- const next = yield* runtime.readDevelopmentMetadata;
117
- if (next !== resolvedMetadata) {
118
- filePathsByUrl = yield* resolvePublicAssetFilePaths({
119
- metadata: next,
120
- path
121
- });
122
- resolvedMetadata = next;
123
- }
124
- }
125
- const queryOffset = request.url.indexOf("?");
126
- const file = filePathsByUrl.get(queryOffset === -1 ? request.url : request.url.slice(0, queryOffset));
127
- if (file === void 0) return yield* httpEffect;
128
- return yield* serveFile({
129
- file,
130
- platform
131
- });
132
- });
133
- };
134
- }).pipe(Effect.provide(input.app[APPLICATION_RUNTIME]));
135
- }
136
- //#endregion
137
- //#region src/server/runtime/effects.ts
138
- const empty = {
139
- status: null,
140
- terminal: null,
141
- headerOps: [],
142
- cookies: Cookies.empty,
143
- headElements: []
144
- };
145
- /** Whether these effects end the response for everything after them. */
146
- function endsResponse(effects) {
147
- return effects.terminal !== null;
148
- }
149
- function mergeResponseEffects(input) {
150
- const { earlier, later } = input;
151
- return {
152
- status: later.status === null ? earlier.status : later.status,
153
- terminal: later.terminal === null ? earlier.terminal : later.terminal,
154
- headerOps: [...earlier.headerOps, ...later.headerOps],
155
- cookies: Cookies.merge(earlier.cookies, later.cookies),
156
- headElements: [...earlier.headElements, ...later.headElements]
157
- };
158
- }
159
- function setStatus(input) {
160
- return {
161
- ...input.effects,
162
- status: input.status
163
- };
164
- }
165
- function setHeader(input) {
166
- return {
167
- ...input.effects,
168
- headerOps: [...input.effects.headerOps, {
169
- kind: "set",
170
- name: input.name,
171
- value: input.value
172
- }]
173
- };
174
- }
175
- function appendHeader(input) {
176
- return {
177
- ...input.effects,
178
- headerOps: [...input.effects.headerOps, {
179
- kind: "append",
180
- name: input.name,
181
- value: input.value
182
- }]
183
- };
184
- }
185
- function setCookie(input) {
186
- return {
187
- ...input.effects,
188
- cookies: Cookies.setCookie(input.effects.cookies, input.cookie)
189
- };
190
- }
191
- function appendHeadElements(input) {
192
- return {
193
- ...input.effects,
194
- headElements: [...input.effects.headElements, ...input.elements]
195
- };
196
- }
197
- function setRedirect(input) {
198
- return {
199
- ...input.effects,
200
- status: input.client ? 200 : input.status,
201
- terminal: {
202
- _tag: "Redirect",
203
- location: input.location,
204
- status: input.status,
205
- client: input.client
206
- }
207
- };
208
- }
209
- /** Made by the execute program from a handler's error, never by a handler. */
210
- function setTerminalError(input) {
211
- return {
212
- ...input.effects,
213
- status: input.status,
214
- terminal: {
215
- _tag: "Error",
216
- status: input.status,
217
- text: input.text,
218
- ...input.domain === void 0 ? {} : { domain: input.domain }
219
- }
220
- };
221
- }
222
- //#endregion
223
- //#region src/server/runtime/handler.ts
224
- /**
225
- * How any handler fails on purpose. In a UI loader: the response carries the
226
- * status and public message without the failed route's metadata or module.
227
- * An available ancestor boundary or the application boundary renders the error.
228
- * In an endpoint or
229
- * task middleware: the response is the status and the message. `cause` never
230
- * leaves the server.
231
- */
232
- var HandlerError = class extends Data.TaggedError("HandlerError") {};
233
- /**
234
- * A declared domain failure on its way to the wire. A `HandlerError` with
235
- * the encoded domain payload beside it, so the execute program keeps its
236
- * single error channel while the response keeps the tag and data a generic
237
- * rejection cannot carry. Constructed only by the endpoint runner after it
238
- * matched the thrown value against the declaration's error schemas.
239
- */
240
- var DeclaredDomainError = class extends HandlerError {
241
- tag;
242
- data;
243
- constructor(input) {
244
- super(input);
245
- this.tag = input.tag;
246
- this.data = input.data;
247
- }
248
- };
249
- /** The public message for a status the application did not explain. */
250
- function getStatusText(status) {
251
- switch (status) {
252
- case 400: return "Bad Request";
253
- case 401: return "Unauthorized";
254
- case 403: return "Forbidden";
255
- case 404: return "Not Found";
256
- case 405: return "Method Not Allowed";
257
- case 409: return "Conflict";
258
- case 413: return "Payload Too Large";
259
- case 415: return "Unsupported Media Type";
260
- case 422: return "Unprocessable Content";
261
- case 429: return "Too Many Requests";
262
- case 500: return "Internal Server Error";
263
- case 503: return "Service Unavailable";
264
- default: return "Error";
265
- }
266
- }
267
- const HANDLER_ENDED_INTERRUPT_ID = -1;
268
- /** Ends a handler without exposing private control flow in its error channel. */
269
- const interruptHandler = Effect.failCause(Cause.interrupt(HANDLER_ENDED_INTERRUPT_ID));
270
- function matchesHandlerEndInterruption(cause) {
271
- const reason = cause.reasons[0];
272
- return cause.reasons.length === 1 && reason !== void 0 && Cause.isInterruptReason(reason) && reason.fiberId === HANDLER_ENDED_INTERRUPT_ID;
273
- }
274
- //#endregion
275
- //#region src/server/runtime/transport-type-entries.ts
276
- const SERVER_TRANSPORT_TYPE_ENTRIES = [
277
- optionTransportType,
278
- redactedTransportType,
279
- chunkTransportType,
280
- durationTransportType,
281
- bigDecimalTransportType,
282
- dateTimeUtcTransportType,
283
- dateTimeZonedTransportType,
284
- hashMapTransportType,
285
- hashSetTransportType
286
- ];
287
- //#endregion
288
- //#region src/server/runtime/context.ts
289
- var ResponseInputError = class extends Data.TaggedError("ResponseInputError") {};
290
- function makeIncomingRequestFacts(source) {
291
- return {
292
- request: source.request,
293
- clientBuildId: source.clientBuildId,
294
- getCookie: (name) => source.request.cookies[name],
295
- getPublicUrl: (key) => {
296
- const normalized = key.startsWith("/") ? key.slice(1) : key;
297
- const { publicFilemap } = source.metadata;
298
- const url = Object.hasOwn(publicFilemap, normalized) ? publicFilemap[normalized] : void 0;
299
- if (url === void 0) throw new Error(`Vorma: ${JSON.stringify(key)} is not a public asset of this build`);
300
- return url;
301
- }
302
- };
303
- }
304
- function makeRequestFacts(source, facts) {
305
- return {
306
- ...makeIncomingRequestFacts(source),
307
- pattern: facts.pattern,
308
- params: facts.params,
309
- splatValues: facts.splatValues,
310
- input: facts.input
311
- };
312
- }
313
- function makeResponseOps(input) {
314
- function updateEffects(f) {
315
- return Ref.update(input.effects, f);
316
- }
317
- function redirectToLocation(location, status) {
318
- return updateEffects((current) => {
319
- return setRedirect({
320
- effects: current,
321
- location,
322
- status,
323
- client: input.acceptsClientRedirect
324
- });
325
- }).pipe(Effect.andThen(interruptHandler));
326
- }
327
- return {
328
- setStatus: (status) => {
329
- return updateEffects((current) => setStatus({
330
- effects: current,
331
- status
332
- }));
333
- },
334
- setHeader: ({ name, value }) => {
335
- return updateEffects((current) => {
336
- return setHeader({
337
- effects: current,
338
- name,
339
- value
340
- });
341
- });
342
- },
343
- appendHeader: ({ name, value }) => {
344
- return updateEffects((current) => {
345
- return appendHeader({
346
- effects: current,
347
- name,
348
- value
349
- });
350
- });
351
- },
352
- setCookie: (cookie) => {
353
- return updateEffects((current) => {
354
- return setCookie({
355
- effects: current,
356
- cookie
357
- });
358
- });
359
- },
360
- expireCookie: (options) => {
361
- const cookie = Cookies.makeCookie(options.name, "", {
362
- maxAge: 0,
363
- expires: /* @__PURE__ */ new Date(0),
364
- ...options.path === void 0 ? {} : { path: options.path },
365
- ...options.domain === void 0 ? {} : { domain: options.domain }
366
- });
367
- if (Result.isFailure(cookie)) return new ResponseInputError({
368
- operation: "expireCookie",
369
- message: "Cookie expiration options are invalid",
370
- cause: cookie.failure
371
- });
372
- return updateEffects((current) => setCookie({
373
- effects: current,
374
- cookie: cookie.success
375
- }));
376
- },
377
- redirectToUrl: ({ url, status }) => redirectToLocation(String(url), status),
378
- redirectToPattern: ({ pattern, params, splatValues, input: routeInput, hash, status }) => {
379
- return input.resolveRouteTargetFn({
380
- pattern,
381
- search: routeInput
382
- }).pipe(Effect.mapError((cause) => {
383
- return new ResponseInputError({
384
- operation: "redirectToPattern",
385
- message: "Route search input does not satisfy its contract",
386
- cause
387
- });
388
- }), Effect.flatMap((target) => {
389
- const href = buildHref({
390
- kind: "ui",
391
- pattern: target.pattern,
392
- transportTypeEntries: SERVER_TRANSPORT_TYPE_ENTRIES,
393
- ...params === void 0 ? {} : { params },
394
- ...splatValues === void 0 ? {} : { splatValues },
395
- ...target.search === void 0 ? {} : { search: target.search },
396
- ...hash === void 0 ? {} : { hash }
397
- });
398
- return Result.isFailure(href) ? Effect.fail(new ResponseInputError({
399
- operation: "redirectToPattern",
400
- message: href.failure.reason,
401
- cause: href.failure
402
- })) : redirectToLocation(href.success, status);
403
- }));
404
- }
405
- };
406
- }
407
- function makeHeadOps(effects) {
408
- function appendHeadElements$1(elements) {
409
- return Ref.update(effects, (current) => appendHeadElements({
410
- effects: current,
411
- elements
412
- }));
413
- }
414
- return {
415
- setTitle: (title) => {
416
- return appendHeadElements$1([{
417
- tag: "title",
418
- textContent: title
419
- }]);
420
- },
421
- setDescription: (description) => {
422
- return appendHeadElements$1([{
423
- tag: "meta",
424
- attributes: {
425
- name: "description",
426
- content: description
427
- }
428
- }]);
429
- },
430
- addMeta: (attributes) => appendHeadElements$1([{
431
- tag: "meta",
432
- attributes
433
- }]),
434
- addHead: appendHeadElements$1
435
- };
436
- }
437
- //#endregion
438
- //#region src/server/runtime/domain-errors.ts
439
- function matchDeclaredError(input) {
440
- if (typeof input.value !== "object" || input.value === null) return;
441
- for (const entry of input.errors) {
442
- const tag = getLiteralErrorTag(entry.schema);
443
- if (tag === void 0) continue;
444
- const validated = Schema.decodeUnknownResult(Schema.toType(entry.schema))(input.value);
445
- if (Result.isFailure(validated)) continue;
446
- const data = encodeTransportedValue({
447
- value: validated.success,
448
- typeEntries: SERVER_TRANSPORT_TYPE_ENTRIES
449
- });
450
- if (Result.isFailure(data)) continue;
451
- return {
452
- tag: tag.tag,
453
- status: entry.status,
454
- data: data.success
455
- };
456
- }
457
- }
458
- //#endregion
459
- //#region src/server/runtime/execute.ts
460
- function executeEndpoint(input) {
461
- return Effect.gen(function* () {
462
- const endpoint = yield* Effect.forkScoped(observeInvocation(input.endpoint));
463
- const outcome = yield* Fiber.join(endpoint);
464
- if (outcome._tag === "Failed") return toTerminalFailure({
465
- effects: mergeResponseEffects({
466
- earlier: input.effects,
467
- later: outcome.effects
468
- }),
469
- cause: outcome.cause
470
- });
471
- return mergeOutput(input.effects, outcome);
472
- });
473
- }
474
- function executeUi(input) {
475
- return Effect.gen(function* () {
476
- const phase = yield* runPhase(input.positions, input.effects);
477
- if (phase._tag === "Terminal") return phase;
478
- if (phase._tag === "Completed") return {
479
- _tag: "Ui",
480
- effects: phase.effects,
481
- positions: phase.positions
482
- };
483
- const error = getHandlerErrorOf(phase.failed.cause);
484
- return {
485
- _tag: "Ui",
486
- effects: setStatus({
487
- effects: phase.effects,
488
- status: error.status
489
- }),
490
- positions: [
491
- ...phase.before,
492
- {
493
- _tag: "Failed",
494
- owner: phase.failed.owner,
495
- error: {
496
- id: phase.failed.id,
497
- pattern: phase.failed.pattern,
498
- index: phase.failed.index,
499
- ...error
500
- }
501
- },
502
- ...phase.after.map((owner) => {
503
- return {
504
- _tag: "Suppressed",
505
- owner
506
- };
507
- })
508
- ]
509
- };
510
- });
511
- }
512
- function executeMiddleware(invocations) {
513
- return Effect.gen(function* () {
514
- const phase = yield* runPhase(invocations.map((invocation) => {
515
- return {
516
- owner: void 0,
517
- invocation
518
- };
519
- }), empty);
520
- if (phase._tag === "Terminal") return phase;
521
- if (phase._tag === "Failed") return toTerminalFailure({
522
- effects: phase.effects,
523
- cause: phase.failed.cause
524
- });
525
- return {
526
- _tag: "Continue",
527
- data: void 0,
528
- effects: phase.effects
529
- };
530
- });
531
- }
532
- function runPhase(positions, initialEffects) {
533
- return Effect.gen(function* () {
534
- if (positions.length === 0) return {
535
- _tag: "Completed",
536
- effects: initialEffects,
537
- positions: []
538
- };
539
- const fibersReady = yield* Deferred.make();
540
- const forked = [];
541
- for (const [index, { owner, invocation }] of positions.entries()) {
542
- if (invocation === null) {
543
- forked.push({
544
- owner,
545
- invocation: null,
546
- fiber: null
547
- });
548
- continue;
549
- }
550
- const body = observeInvocation(invocation).pipe(Effect.flatMap((outcome) => {
551
- return (marksBoundary(outcome) ? Effect.flatMap(Deferred.await(fibersReady), (all) => {
552
- return Fiber.interruptAll(all.slice(index + 1).filter((fiber) => fiber !== null));
553
- }) : Effect.void).pipe(Effect.as(outcome));
554
- }));
555
- forked.push({
556
- owner,
557
- invocation,
558
- fiber: yield* Effect.forkScoped(body)
559
- });
560
- }
561
- yield* Deferred.succeed(fibersReady, forked.map((entry) => entry.fiber));
562
- let effects = initialEffects;
563
- const completed = [];
564
- for (const [index, position] of forked.entries()) {
565
- if (position.fiber === null) {
566
- completed.push({
567
- _tag: "NoHandler",
568
- owner: position.owner
569
- });
570
- continue;
571
- }
572
- const joined = yield* Effect.exit(Fiber.join(position.fiber));
573
- if (Exit.isFailure(joined)) return yield* Effect.interrupt;
574
- const outcome = joined.value;
575
- if (outcome._tag === "Failed") return {
576
- _tag: "Failed",
577
- effects: mergeResponseEffects({
578
- earlier: effects,
579
- later: outcome.effects
580
- }),
581
- before: completed,
582
- failed: {
583
- owner: position.owner,
584
- index,
585
- id: position.invocation.id,
586
- pattern: position.invocation.pattern,
587
- cause: outcome.cause
588
- },
589
- after: forked.slice(index + 1).map((entry) => entry.owner)
590
- };
591
- const output = mergeOutput(effects, outcome);
592
- if (output._tag === "Terminal") return output;
593
- effects = output.effects;
594
- completed.push({
595
- _tag: "Completed",
596
- owner: position.owner,
597
- data: output.data
598
- });
599
- }
600
- return {
601
- _tag: "Completed",
602
- effects,
603
- positions: completed
604
- };
605
- });
606
- }
607
- /** Handler work stays interruptible; logging a produced failure completes before suppression can discard it. */
608
- function observeInvocation(invocation) {
609
- return Effect.uninterruptibleMask((restore) => {
610
- return Effect.flatMap(Effect.exit(restore(invocation.run)), (exit) => {
611
- const outcome = Exit.isSuccess(exit) ? exit.value : {
612
- _tag: "Failed",
613
- cause: exit.cause,
614
- effects: empty
615
- };
616
- if (outcome._tag === "Failed" && Cause.hasInterruptsOnly(outcome.cause)) return Effect.interrupt;
617
- return logFailure(invocation, outcome).pipe(Effect.as(outcome));
618
- });
619
- });
620
- }
621
- function logFailure(invocation, outcome) {
622
- if (outcome._tag !== "Failed") return Effect.void;
623
- return Effect.logError("Vorma handler failed", {
624
- handlerId: invocation.id,
625
- role: invocation.role,
626
- pattern: invocation.pattern
627
- }, outcome.cause);
628
- }
629
- function marksBoundary(outcome) {
630
- return outcome._tag !== "Continue";
631
- }
632
- function mergeOutput(earlier, output) {
633
- const effects = mergeResponseEffects({
634
- earlier,
635
- later: output.effects
636
- });
637
- return output._tag === "Terminal" ? {
638
- _tag: "Terminal",
639
- effects: {
640
- ...effects,
641
- terminal: output.effects.terminal
642
- }
643
- } : {
644
- ...output,
645
- effects
646
- };
647
- }
648
- function toTerminalFailure(input) {
649
- const error = getHandlerErrorOf(input.cause);
650
- const domain = getDeclaredDomainOf(input.cause);
651
- return {
652
- _tag: "Terminal",
653
- effects: setTerminalError({
654
- effects: input.effects,
655
- status: error.status,
656
- text: error.clientMessage,
657
- ...domain === void 0 ? {} : { domain }
658
- })
659
- };
660
- }
661
- /** The domain payload when the failure is a matched declared error. */
662
- function getDeclaredDomainOf(cause) {
663
- const reason = cause.reasons[0];
664
- if (cause.reasons.length === 1 && reason !== void 0 && Cause.isFailReason(reason) && reason.error instanceof DeclaredDomainError) return {
665
- tag: reason.error.tag,
666
- data: reason.error.data
667
- };
668
- }
669
- /** The handler's public error when it failed on purpose; a generic 500 when it did not. */
670
- function getHandlerErrorOf(cause) {
671
- const reason = cause.reasons[0];
672
- if (cause.reasons.length === 1 && reason !== void 0 && Cause.isFailReason(reason) && reason.error instanceof HandlerError) {
673
- const { status, clientMessage } = reason.error;
674
- return {
675
- status,
676
- clientMessage: clientMessage === void 0 ? getStatusText(status) : clientMessage
677
- };
678
- }
679
- return {
680
- status: 500,
681
- clientMessage: getStatusText(500)
682
- };
683
- }
684
- //#endregion
685
- //#region src/server/runtime/finalize.ts
686
- const JSON_CONTENT_TYPE = "application/json; charset=utf-8";
687
- const HTML_CONTENT_TYPE = "text/html; charset=utf-8";
688
- const TEXT_CONTENT_TYPE = "text/plain; charset=utf-8";
689
- const UI_CACHE_CONTROL = "private, max-age=0, must-revalidate, no-cache";
690
- const FRAMEWORK_OWNED_HEADERS = /* @__PURE__ */ new Set([
691
- HTTP_PROTOCOL.responseHeaders.clientBuildId,
692
- HTTP_PROTOCOL.responseHeaders.buildSkew,
693
- HTTP_PROTOCOL.responseHeaders.clientRedirect,
694
- HTTP_PROTOCOL.responseHeaders.clientRedirectStatus
695
- ]);
696
- /** Replays the header operations and adds the framework's own headers. */
697
- function getBaseHeaders(input) {
698
- let headers = Headers$1.empty;
699
- for (const op of input.effects.headerOps) {
700
- const name = op.name.toLowerCase();
701
- if (FRAMEWORK_OWNED_HEADERS.has(name)) return Result.fail({
702
- _tag: "FrameworkOwnedHeader",
703
- name
704
- });
705
- const existing = headers[name];
706
- headers = Headers$1.set(headers, name, op.kind === "append" && existing !== void 0 ? `${existing}, ${op.value}` : op.value);
707
- }
708
- return Result.succeed(Headers$1.set(headers, HTTP_PROTOCOL.responseHeaders.clientBuildId, input.clientBuildId));
709
- }
710
- function finalizeWith(input) {
711
- const baseHeaders = getBaseHeaders({
712
- effects: input.effects,
713
- clientBuildId: input.clientBuildId
714
- });
715
- if (Result.isFailure(baseHeaders)) return Result.fail(baseHeaders.failure);
716
- let headers = baseHeaders.success;
717
- const effects = input.effects;
718
- let status = effects.status === null ? 200 : effects.status;
719
- let body = input.body;
720
- if (effects.terminal !== null) {
721
- if (effects.terminal._tag === "Redirect") {
722
- if (effects.terminal.client) {
723
- status = 200;
724
- headers = Headers$1.set(headers, HTTP_PROTOCOL.responseHeaders.clientRedirect, effects.terminal.location);
725
- headers = Headers$1.set(headers, HTTP_PROTOCOL.responseHeaders.clientRedirectStatus, String(effects.terminal.status));
726
- } else {
727
- status = effects.terminal.status;
728
- headers = Headers$1.set(headers, "location", effects.terminal.location);
729
- }
730
- body = null;
731
- } else {
732
- status = effects.terminal.status;
733
- body = effects.terminal.text;
734
- headers = Headers$1.set(headers, "content-type", TEXT_CONTENT_TYPE);
735
- }
736
- } else if (input.contentType !== null) headers = Headers$1.set(headers, "content-type", input.contentType);
737
- const options = {
738
- status,
739
- headers,
740
- cookies: effects.cookies
741
- };
742
- return Result.succeed(body === null ? HttpServerResponse$1.empty(options) : HttpServerResponse$1.text(body, options));
743
- }
744
- /** Prevents implicit reuse of request-dependent UI data without replacing an authored policy. */
745
- function withUiCacheControl(response) {
746
- return Headers$1.has(response.headers, "cache-control") ? response : HttpServerResponse$1.setHeader(response, "cache-control", UI_CACHE_CONTROL);
747
- }
748
- /** A navigation's JSON payload response with its application or conservative cache policy. */
749
- function finalizeJson(input) {
750
- return finalizeWith({
751
- effects: input.effects,
752
- clientBuildId: input.clientBuildId,
753
- body: input.json,
754
- contentType: JSON_CONTENT_TYPE
755
- }).pipe(Result.map(withUiCacheControl));
756
- }
757
- /** A first load's HTML response with its application or conservative cache policy. */
758
- function finalizeHtml(input) {
759
- return finalizeWith({
760
- effects: input.effects,
761
- clientBuildId: input.clientBuildId,
762
- body: input.html,
763
- contentType: HTML_CONTENT_TYPE
764
- }).pipe(Result.map(withUiCacheControl));
765
- }
766
- /** An endpoint's JSON response. No cache-control is assumed for endpoints. */
767
- function finalizeEndpointJson(input) {
768
- return finalizeWith({
769
- effects: input.effects,
770
- clientBuildId: input.clientBuildId,
771
- body: input.json,
772
- contentType: JSON_CONTENT_TYPE
773
- });
774
- }
775
- /** An endpoint redirect, or its structured public handler rejection. */
776
- function finalizeEndpointTerminal(input) {
777
- const terminal = input.effects.terminal;
778
- if (terminal === null || terminal._tag !== "Error") return finalizeTerminal(input);
779
- const envelope = {
780
- error: {
781
- status: terminal.status,
782
- client_message: terminal.text
783
- },
784
- ...terminal.domain === void 0 ? {} : { domain: {
785
- tag: terminal.domain.tag,
786
- data: terminal.domain.data
787
- } }
788
- };
789
- return finalizeWith({
790
- effects: {
791
- ...input.effects,
792
- status: terminal.status,
793
- terminal: null
794
- },
795
- clientBuildId: input.clientBuildId,
796
- body: JSON.stringify(envelope),
797
- contentType: JSON_CONTENT_TYPE
798
- });
799
- }
800
- /** A response that ended before any body was produced: a redirect or an error. */
801
- function finalizeTerminal(input) {
802
- return finalizeWith({
803
- effects: input.effects,
804
- clientBuildId: input.clientBuildId,
805
- body: null,
806
- contentType: null
807
- });
808
- }
809
- /** The answer to a client whose build does not match the server's. */
810
- function finalizeBuildSkew(clientBuildId) {
811
- return HttpServerResponse$1.text(HTTP_PROTOCOL.buildSkewBody, {
812
- status: 200,
813
- headers: [
814
- ["content-type", JSON_CONTENT_TYPE],
815
- [HTTP_PROTOCOL.responseHeaders.clientBuildId, clientBuildId],
816
- [HTTP_PROTOCOL.responseHeaders.buildSkew, "1"],
817
- ["cache-control", "no-store"]
818
- ]
819
- });
820
- }
821
- /** A plain-text response for a Vorma protocol or execution failure. */
822
- function finalizeStatus(input) {
823
- const headers = [["content-type", TEXT_CONTENT_TYPE], [HTTP_PROTOCOL.responseHeaders.clientBuildId, input.clientBuildId]];
824
- return HttpServerResponse$1.text(input.text, {
825
- status: input.status,
826
- headers
827
- });
828
- }
829
- //#endregion
830
- //#region src/server/document.ts
831
- const NAME_PATTERN = /^[A-Za-z][A-Za-z0-9:._-]*$/;
832
- const VOID_ELEMENTS = /* @__PURE__ */ new Set([
833
- "area",
834
- "base",
835
- "br",
836
- "col",
837
- "embed",
838
- "hr",
839
- "img",
840
- "input",
841
- "link",
842
- "meta",
843
- "source",
844
- "track",
845
- "wbr"
846
- ]);
847
- /** Escapes ordinary text once, when producing HTML. */
848
- function escapeText(value) {
849
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
850
- }
851
- /** Escapes a value for a double-quoted HTML attribute. */
852
- function escapeAttributeValue(value) {
853
- return escapeText(value).replaceAll("\"", "&quot;");
854
- }
855
- /** Escapes serialized JSON for insertion through a script element's dangerousInnerHtml. */
856
- function escapeJsonForScript(serializedJson) {
857
- return serializedJson.replaceAll("&", "\\u0026").replaceAll("<", "\\u003c").replaceAll(">", "\\u003e").replaceAll("\u2028", "\\u2028").replaceAll("\u2029", "\\u2029");
858
- }
859
- function renderElementContent(element) {
860
- const tag = element.tag;
861
- if (!NAME_PATTERN.test(element.tag)) return Result.fail({
862
- _tag: "InvalidTagName",
863
- tag: element.tag
864
- });
865
- for (const name of Object.keys(element.attributes ?? {})) if (!NAME_PATTERN.test(name)) return Result.fail({
866
- _tag: "InvalidAttributeName",
867
- attribute: name,
868
- tag: element.tag
869
- });
870
- if (element.textContent !== void 0 && element.dangerousInnerHtml !== void 0) return Result.fail({
871
- _tag: "MixedTextAndRawContent",
872
- tag
873
- });
874
- const content = element.dangerousInnerHtml ?? escapeText(element.textContent ?? "");
875
- if (VOID_ELEMENTS.has(element.tag.toLowerCase()) && content !== "") return Result.fail({
876
- _tag: "VoidElementWithContent",
877
- tag: element.tag
878
- });
879
- return Result.succeed(content);
880
- }
881
- /** Serializes one element without interpreting raw code or markup. */
882
- function renderElement(element) {
883
- return Result.map(renderElementContent(element), (content) => {
884
- const attributes = Object.entries(element.attributes ?? {}).map(([name, value]) => {
885
- return value === true ? ` ${name}` : ` ${name}="${escapeAttributeValue(value)}"`;
886
- }).join("");
887
- const start = `<${element.tag}${attributes}>`;
888
- return VOID_ELEMENTS.has(element.tag.toLowerCase()) ? start : `${start}${content}</${element.tag}>`;
889
- });
890
- }
891
- function renderElements(elements) {
892
- const rendered = [];
893
- for (const element of elements) {
894
- const result = renderElement(element);
895
- if (Result.isFailure(result)) return result;
896
- rendered.push(result.success);
897
- }
898
- return Result.succeed(rendered.join("\n"));
899
- }
900
- //#endregion
901
- //#region src/server/runtime/assets.ts
902
- /** Combines static module metadata without running application code. */
903
- function prepareAssets(input) {
904
- function collectUrls(key) {
905
- const entry = new Set(input.clientEntry[key]);
906
- const combined = new Set(entry);
907
- for (const view of input.views) if (view !== null) for (const url of view[key]) combined.add(url);
908
- const document = [...combined];
909
- return {
910
- document,
911
- navigation: document.slice(entry.size)
912
- };
913
- }
914
- const deps = collectUrls("depUrls");
915
- const css = collectUrls("cssBundleUrls");
916
- const assets = collectUrls("staticAssetUrls");
917
- return {
918
- navigationDepUrls: deps.navigation,
919
- documentDepUrls: deps.document,
920
- navigationCssBundleUrls: css.navigation,
921
- documentCssBundleUrls: css.document,
922
- navigationStaticAssetUrls: assets.navigation,
923
- documentStaticAssetUrls: assets.document
924
- };
925
- }
926
- //#endregion
927
- //#region src/server/runtime/head.ts
928
- /** The built-in identities. An element matches a rule when its tag matches and every listed attribute matches; `true` means present with any value. */
929
- const defaultDedupeRules = [
930
- {
931
- tag: "title",
932
- attributes: {}
933
- },
934
- {
935
- tag: "meta",
936
- attributes: { name: "description" }
937
- },
938
- {
939
- tag: "meta",
940
- attributes: { name: "viewport" }
941
- },
942
- {
943
- tag: "meta",
944
- attributes: { name: "robots" }
945
- },
946
- {
947
- tag: "meta",
948
- attributes: { charset: true }
949
- },
950
- {
951
- tag: "link",
952
- attributes: { rel: "icon" }
953
- },
954
- {
955
- tag: "link",
956
- attributes: { rel: "canonical" }
957
- },
958
- {
959
- tag: "meta",
960
- attributes: { property: "og:title" }
961
- },
962
- {
963
- tag: "meta",
964
- attributes: { property: "og:description" }
965
- },
966
- {
967
- tag: "meta",
968
- attributes: { property: "og:url" }
969
- },
970
- {
971
- tag: "meta",
972
- attributes: { property: "og:type" }
973
- },
974
- {
975
- tag: "meta",
976
- attributes: { property: "og:locale" }
977
- },
978
- {
979
- tag: "meta",
980
- attributes: { property: "og:site_name" }
981
- },
982
- {
983
- tag: "meta",
984
- attributes: { property: "og:determiner" }
985
- }
986
- ];
987
- /** Normalizes the application's static rules once, preserving priority within each tag. */
988
- function compileHeadRules(rules) {
989
- const byTag = /* @__PURE__ */ new Map();
990
- for (const [index, rule] of rules.entries()) {
991
- const tag = rule.tag.toLowerCase();
992
- const compiled = {
993
- index,
994
- attributes: Object.entries(rule.attributes).map(([name, value]) => {
995
- return [name.toLowerCase(), value];
996
- })
997
- };
998
- const existing = byTag.get(tag);
999
- if (existing === void 0) byTag.set(tag, [compiled]);
1000
- else existing.push(compiled);
1001
- }
1002
- return byTag;
1003
- }
1004
- /** Deduplicates managed defaults and ordered contributions before classification. */
1005
- function prepareHead(input) {
1006
- const deduped = dedupeHeadElements(input);
1007
- let title = null;
1008
- const meta = [];
1009
- const rest = [];
1010
- for (const element of deduped) if (element.tag === "title") title = element;
1011
- else if (element.tag === "meta") meta.push(element);
1012
- else rest.push(element);
1013
- return {
1014
- title,
1015
- meta,
1016
- rest
1017
- };
1018
- }
1019
- function matchesRule(element, rule) {
1020
- for (const [name, expected] of rule.attributes) {
1021
- const actual = element.attributes?.[name];
1022
- if (actual === void 0 || expected !== true && actual !== expected) return false;
1023
- }
1024
- return true;
1025
- }
1026
- /** Later elements replace an identity's first position; unmatched identities use structural equality. */
1027
- function dedupeHeadElements(input) {
1028
- const elements = [];
1029
- const indexByRule = /* @__PURE__ */ new Map();
1030
- const indexByShape = /* @__PURE__ */ new Map();
1031
- function appendElement(indexes, key, element) {
1032
- const index = indexes.get(key);
1033
- if (index === void 0) {
1034
- indexes.set(key, elements.length);
1035
- elements.push(element);
1036
- } else elements[index] = element;
1037
- }
1038
- for (const authored of input.elements) {
1039
- const element = {
1040
- ...authored,
1041
- tag: authored.tag.toLowerCase(),
1042
- attributes: Object.fromEntries(Object.entries(authored.attributes ?? {}).map(([name, value]) => [name.toLowerCase(), value]))
1043
- };
1044
- const matchedRule = input.rules.get(element.tag)?.find((rule) => matchesRule(element, rule));
1045
- if (matchedRule !== void 0) appendElement(indexByRule, matchedRule.index, element);
1046
- else appendElement(indexByShape, toShapeKey(element), element);
1047
- }
1048
- return elements;
1049
- }
1050
- function toShapeKey(node) {
1051
- const attributes = Object.entries(node.attributes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1052
- return JSON.stringify([
1053
- "Element",
1054
- node.tag,
1055
- attributes,
1056
- node.textContent ?? null,
1057
- node.dangerousInnerHtml ?? null
1058
- ]);
1059
- }
1060
- //#endregion
1061
- //#region src/server/runtime/payload.ts
1062
- function projectPayload(input) {
1063
- const { report } = input;
1064
- let serverError = null;
1065
- let allEligible = true;
1066
- const routes = [];
1067
- for (const executed of report.positions) {
1068
- if (executed._tag === "Suppressed") {
1069
- allEligible = false;
1070
- continue;
1071
- }
1072
- const { position, searchInput } = executed.owner;
1073
- const { node } = position;
1074
- if (executed._tag === "Failed") {
1075
- allEligible = false;
1076
- serverError = executed.error;
1077
- continue;
1078
- }
1079
- const module = node.clientViewModule;
1080
- const loaderData = executed._tag === "Completed" ? executed.data : executed._tag === "NoHandler" ? null : void 0;
1081
- routes.push({
1082
- pattern: node.pattern,
1083
- ...Object.keys(position.params).length === 0 ? {} : { params: position.params },
1084
- ...position.splatValues.length === 0 ? {} : { splat_values: position.splatValues },
1085
- compiled_pattern: {
1086
- ...node.registered.pattern === node.pattern ? {} : { pattern: node.registered.pattern },
1087
- segments: node.registered.segments
1088
- },
1089
- ...node.uiLoader === null || node.uiLoader.search === null ? {} : { search_contract: node.uiLoader.search.document },
1090
- ...searchInput === null ? {} : { search_input: searchInput },
1091
- ...module === void 0 ? {} : module === null ? { import_url: null } : {
1092
- import_url: module.importUrl,
1093
- export_names: module.exportNames
1094
- },
1095
- ...loaderData === void 0 ? {} : { loader_data: loaderData }
1096
- });
1097
- }
1098
- const preparedHead = prepareHeadOf({
1099
- report,
1100
- headDefaults: input.headDefaults,
1101
- dedupeRules: input.dedupeRules
1102
- });
1103
- return {
1104
- route: {
1105
- routes,
1106
- ...serverError === null ? {} : { server_error: {
1107
- index: serverError.index,
1108
- status: serverError.status,
1109
- client_message: serverError.clientMessage
1110
- } }
1111
- },
1112
- preparedHead,
1113
- ...allEligible ? input.assets : prepareAssets({
1114
- clientEntry: input.clientEntry,
1115
- views: report.positions.flatMap((executed) => {
1116
- return executed._tag === "Failed" || executed._tag === "Suppressed" ? [] : [executed.owner.position.node.clientViewModule];
1117
- })
1118
- })
1119
- };
1120
- }
1121
- function toNavigationPayload(projection) {
1122
- return Result.map(toWireHead(projection.preparedHead), (head) => {
1123
- return {
1124
- ...projection.route,
1125
- head,
1126
- ...projection.navigationDepUrls.length === 0 ? {} : { deps: projection.navigationDepUrls },
1127
- ...projection.navigationCssBundleUrls.length === 0 ? {} : { css_bundles: projection.navigationCssBundleUrls },
1128
- ...projection.navigationStaticAssetUrls.length === 0 ? {} : { static_assets: projection.navigationStaticAssetUrls }
1129
- };
1130
- });
1131
- }
1132
- function toSsrPayload(input) {
1133
- return {
1134
- ...input.projection.route,
1135
- client_build_id: input.clientBuildId,
1136
- ...input.isDev ? { is_dev: true } : {},
1137
- ...input.deploymentId === void 0 ? {} : { deployment_id: input.deploymentId }
1138
- };
1139
- }
1140
- /** The deduped head for a response, with later contributions replacing the first position of each identity. */
1141
- function prepareHeadOf(input) {
1142
- const { effects } = input.report;
1143
- return prepareHead({
1144
- elements: [...input.headDefaults, ...effects.headElements],
1145
- rules: input.dedupeRules
1146
- });
1147
- }
1148
- /**
1149
- * A head element on the wire: raw attribute values, which the client sets
1150
- * through the DOM, and escaped text or trusted HTML, which the client sets
1151
- * as inner HTML. The initial document uses the same serialization.
1152
- */
1153
- function toWireHeadElement(element) {
1154
- const attrs = element.attributes ?? {};
1155
- const inner = renderElementContent(element);
1156
- if (Result.isFailure(inner)) return Result.fail({
1157
- _tag: "HeadRender",
1158
- tag: element.tag,
1159
- reason: inner.failure
1160
- });
1161
- const innerHtml = inner.success;
1162
- return Result.succeed({
1163
- tag: element.tag,
1164
- ...Object.keys(attrs).length === 0 ? {} : { attrs },
1165
- ...innerHtml === "" ? {} : { html: innerHtml }
1166
- });
1167
- }
1168
- function toWireHead(prepared) {
1169
- const sections = Result.all({
1170
- meta: toWireHeadElements(prepared.meta),
1171
- rest: toWireHeadElements(prepared.rest)
1172
- });
1173
- if (Result.isFailure(sections)) return Result.fail(sections.failure);
1174
- const title = prepared.title === null ? null : toWireHeadElement(prepared.title);
1175
- if (title !== null && Result.isFailure(title)) return Result.fail(title.failure);
1176
- return Result.succeed({
1177
- ...title === null ? {} : { title: title.success },
1178
- ...sections.success.meta.length === 0 ? {} : { meta: sections.success.meta },
1179
- ...sections.success.rest.length === 0 ? {} : { rest: sections.success.rest }
1180
- });
1181
- }
1182
- function toWireHeadElements(elements) {
1183
- const out = [];
1184
- for (const element of elements) {
1185
- const wire = toWireHeadElement(element);
1186
- if (Result.isFailure(wire)) return Result.fail(wire.failure);
1187
- out.push(wire.success);
1188
- }
1189
- return Result.succeed(out);
1190
- }
1191
- //#endregion
1192
- //#region src/server/runtime/plan.ts
1193
- /** Compiles application declarations and server-side view metadata into request matchers. */
1194
- function compileRequestPlan(input) {
1195
- const errors = [];
1196
- const uiLoaders = [];
1197
- const endpointNodes = [];
1198
- const middleware = [];
1199
- for (const declaration of new Set(input.handlers)) if (declaration._tag === "UiLoader") {
1200
- const node = compileUiLoader(declaration, errors);
1201
- if (node !== null) uiLoaders.push(node);
1202
- } else {
1203
- const node = compileEndpoint(declaration, errors);
1204
- if (node !== null) endpointNodes.push(node);
1205
- }
1206
- for (const [index, declaration] of input.middleware.entries()) {
1207
- const node = compileMiddleware(declaration, index, errors);
1208
- if (node !== null) middleware.push(node);
1209
- }
1210
- checkDuplicates(uiLoaders, endpointNodes, errors);
1211
- const viewErrors = [];
1212
- const uiNodes = linkSearchOwners(buildUiNodes({
1213
- uiLoaders,
1214
- clientViews: input.clientViews,
1215
- errors: viewErrors
1216
- }));
1217
- checkEndpointPatternRegistrations(endpointNodes, errors);
1218
- if (errors.length > 0) return Result.fail(errors);
1219
- const viewError = viewErrors[0];
1220
- if (viewError !== void 0) return Result.fail(viewError);
1221
- const endpoints = /* @__PURE__ */ new Map();
1222
- for (const [method, nodes] of groupEndpointsByMethod(endpointNodes)) endpoints.set(method, createFlatValueMatcher(nodes.map((node) => {
1223
- return {
1224
- pattern: node.registered,
1225
- value: node
1226
- };
1227
- })));
1228
- return Result.succeed({
1229
- clientEntry: input.clientEntry,
1230
- preparedRequests: /* @__PURE__ */ new Map(),
1231
- headDeduplicationRules: compileHeadRules([...defaultDedupeRules, ...input.document.headDeduplicationRules]),
1232
- document: input.document,
1233
- uiMatcher: createNestedValueMatcher(uiNodes.map((node) => {
1234
- return {
1235
- pattern: node.registered,
1236
- value: node
1237
- };
1238
- })),
1239
- uiByAuthoredPattern: new Map(uiNodes.map((node) => [node.pattern, node])),
1240
- endpoints,
1241
- middleware: middleware.map((node) => {
1242
- return {
1243
- node,
1244
- matcher: createFlatMatcher(node.registered)
1245
- };
1246
- })
1247
- });
1248
- }
1249
- function buildUiNodes(input) {
1250
- const nodes = /* @__PURE__ */ new Map();
1251
- for (const uiLoader of input.uiLoaders) nodes.set(uiLoader.registered.pattern, {
1252
- pattern: uiLoader.declaration.pattern,
1253
- registered: uiLoader.registered,
1254
- uiLoader,
1255
- clientViewModule: null
1256
- });
1257
- for (const [pattern, clientViewModule] of Object.entries(input.clientViews)) {
1258
- const registered = compileUiPattern(pattern);
1259
- if (Result.isFailure(registered)) {
1260
- input.errors.push({
1261
- _tag: "PlanError",
1262
- cause: registered.failure
1263
- });
1264
- continue;
1265
- }
1266
- const existing = nodes.get(registered.success.pattern);
1267
- nodes.set(registered.success.pattern, {
1268
- pattern,
1269
- registered: registered.success,
1270
- uiLoader: existing === void 0 ? null : existing.uiLoader,
1271
- clientViewModule
1272
- });
1273
- }
1274
- return [...nodes.values()];
1275
- }
1276
- /** Each UI position's search owners: the loaders above and at it whose search fields compose into its input. */
1277
- function linkSearchOwners(nodes) {
1278
- return createNestedRouteChains({ nodes }).map(({ target, chain }) => {
1279
- const owners = chain.filter((node) => node.uiLoader !== null && node.uiLoader.search !== null);
1280
- return {
1281
- ...target,
1282
- searchOwners: owners.map((owner) => owner.uiLoader)
1283
- };
1284
- });
1285
- }
1286
- /** Reuses only operation/pathname-derived data within this compiled application. */
1287
- function getRequestPreparation(input) {
1288
- const { plan, operation, path } = input;
1289
- const key = operation._tag === "Ui" ? `Ui ${path}` : `Endpoint ${operation.method} ${path}`;
1290
- const cached = plan.preparedRequests.get(key);
1291
- if (cached !== void 0) {
1292
- plan.preparedRequests.delete(key);
1293
- plan.preparedRequests.set(key, cached);
1294
- return cached;
1295
- }
1296
- const prepared = Result.map(classifyRequest(input), (target) => {
1297
- return {
1298
- target,
1299
- middleware: target._tag === "NotFound" ? [] : getMiddlewareFor({
1300
- plan,
1301
- method: operation._tag === "Ui" ? "GET" : operation.method,
1302
- path
1303
- })
1304
- };
1305
- });
1306
- plan.preparedRequests.set(key, prepared);
1307
- if (plan.preparedRequests.size > 4096) {
1308
- const oldest = plan.preparedRequests.keys().next();
1309
- if (!oldest.done) plan.preparedRequests.delete(oldest.value);
1310
- }
1311
- return prepared;
1312
- }
1313
- function classifyRequest(input) {
1314
- const { plan, path, operation } = input;
1315
- return (operation._tag === "Ui" ? matchUi({
1316
- plan,
1317
- path
1318
- }) : matchEndpoint({
1319
- plan,
1320
- path,
1321
- method: operation.method
1322
- })).pipe(Result.map((target) => target ?? { _tag: "NotFound" }));
1323
- }
1324
- /** Selects task middleware for the mounted operation, in declaration order. */
1325
- function getMiddlewareFor(input) {
1326
- const selected = [];
1327
- for (const entry of input.plan.middleware) {
1328
- if (!entry.node.declaration.methods.some((allowed) => allowed === input.method)) continue;
1329
- if (Option.isSome(findBestMatch(entry.matcher, input.path))) selected.push(entry.node);
1330
- }
1331
- return selected;
1332
- }
1333
- function matchEndpoint(input) {
1334
- const table = input.plan.endpoints.get(input.method);
1335
- if (table === void 0) return Result.succeed(null);
1336
- const best = findBestValueMatch(table, input.path);
1337
- if (Option.isNone(best)) return Result.succeed(null);
1338
- const node = best.value.value;
1339
- const captures = decodeMatchCaptures(best.value);
1340
- if (Result.isFailure(captures)) return Result.fail(captures.failure);
1341
- return Result.succeed({
1342
- _tag: "Endpoint",
1343
- node,
1344
- ...captures.success
1345
- });
1346
- }
1347
- function matchUi(input) {
1348
- const matches = findNestedValueMatches(input.plan.uiMatcher, input.path);
1349
- if (Option.isNone(matches)) return Result.succeed(null);
1350
- const positions = [];
1351
- for (const match of matches.value) {
1352
- const node = match.value;
1353
- const captures = decodeMatchCaptures(match);
1354
- if (Result.isFailure(captures)) return Result.fail(captures.failure);
1355
- positions.push({
1356
- node,
1357
- ...captures.success
1358
- });
1359
- }
1360
- return Result.succeed({
1361
- _tag: "Ui",
1362
- positions,
1363
- assets: prepareAssets({
1364
- clientEntry: input.plan.clientEntry,
1365
- views: positions.map((position) => position.node.clientViewModule)
1366
- })
1367
- });
1368
- }
1369
- //#endregion
1370
- //#region src/server/runtime/render-document.ts
1371
- /** Serializes the fixed document structure after head deduplication and classification. */
1372
- function renderDocument(input) {
1373
- const assets = [];
1374
- if (input.criticalCss !== "") assets.push({
1375
- tag: "style",
1376
- attributes: { id: DOCUMENT_PROTOCOL.elementIds.criticalCss },
1377
- dangerousInnerHtml: input.criticalCss
1378
- });
1379
- for (const href of input.cssBundleUrls) assets.push({
1380
- tag: "link",
1381
- attributes: {
1382
- rel: "stylesheet",
1383
- href,
1384
- [DOCUMENT_PROTOCOL.attributes.cssBundle]: href
1385
- }
1386
- });
1387
- for (const href of input.modulePreloadUrls) assets.push({
1388
- tag: "link",
1389
- attributes: {
1390
- rel: "modulepreload",
1391
- href
1392
- }
1393
- });
1394
- for (const href of input.staticAssetUrls) {
1395
- const destination = getStaticAssetDestination(href);
1396
- assets.push({
1397
- tag: "link",
1398
- attributes: {
1399
- rel: "preload",
1400
- href,
1401
- as: destination,
1402
- ...destination === "image" ? {} : { crossorigin: "anonymous" },
1403
- [DOCUMENT_PROTOCOL.attributes.staticAsset]: href
1404
- }
1405
- });
1406
- }
1407
- const sections = Result.all({
1408
- title: renderElements(input.prepared.title === null ? [] : [input.prepared.title]),
1409
- meta: renderElements(input.prepared.meta),
1410
- rest: renderElements(input.prepared.rest),
1411
- assets: renderElements(assets),
1412
- body: renderElements([
1413
- {
1414
- tag: "div",
1415
- attributes: { id: DOCUMENT_PROTOCOL.elementIds.root }
1416
- },
1417
- {
1418
- tag: "script",
1419
- attributes: {
1420
- id: DOCUMENT_PROTOCOL.elementIds.data,
1421
- type: "application/json"
1422
- },
1423
- dangerousInnerHtml: escapeJsonForScript(input.payloadJson)
1424
- },
1425
- {
1426
- tag: "script",
1427
- attributes: {
1428
- type: "module",
1429
- src: input.entryImportUrl
1430
- }
1431
- }
1432
- ])
1433
- });
1434
- if (Result.isFailure(sections)) return Result.fail(sections.failure);
1435
- const headHtml = [
1436
- "title",
1437
- "meta",
1438
- "rest",
1439
- "assets"
1440
- ].map((section) => `<!--${DOCUMENT_PROTOCOL.headComments[section]}-->\n${sections.success[section]}`).join("\n");
1441
- const document = Result.all({
1442
- head: renderElement({
1443
- tag: "head",
1444
- attributes: input.attributes.head,
1445
- dangerousInnerHtml: headHtml + (input.developmentHeadHtml ?? "")
1446
- }),
1447
- body: renderElement({
1448
- tag: "body",
1449
- attributes: input.attributes.body,
1450
- dangerousInnerHtml: sections.success.body
1451
- })
1452
- });
1453
- if (Result.isFailure(document)) return Result.fail(document.failure);
1454
- return Result.map(renderElement({
1455
- tag: "html",
1456
- attributes: input.attributes.html,
1457
- dangerousInnerHtml: document.success.head + document.success.body
1458
- }), (html) => `<!doctype html>\n${html}`);
1459
- }
1460
- //#endregion
1461
- //#region src/server/runtime/pipeline.ts
1462
- function handleRequest(input) {
1463
- return Effect.gen(function* () {
1464
- const { plan, metadata, request } = input;
1465
- const clientBuildId = metadata.clientBuildId;
1466
- const badRequest = finalizeStatus({
1467
- status: 400,
1468
- text: "Bad Request",
1469
- clientBuildId
1470
- });
1471
- const queryOffset = request.url.indexOf("?");
1472
- const rawPath = queryOffset === -1 ? request.url : request.url.slice(0, queryOffset);
1473
- const matcherPath = canonicalizeRequestPathForMatcher(rawPath);
1474
- if (Result.isFailure(matcherPath)) return badRequest;
1475
- const url = new URL(`${matcherPath.success}${queryOffset === -1 ? "" : request.url.slice(queryOffset)}`, "http://vorma.invalid");
1476
- const prepared = getRequestPreparation({
1477
- plan,
1478
- operation: input.operation,
1479
- path: matcherPath.success
1480
- });
1481
- if (Result.isFailure(prepared)) return badRequest;
1482
- const { target } = prepared.success;
1483
- if (target._tag === "NotFound") return yield* Effect.fail(new HttpServerError.HttpServerError({ reason: new HttpServerError.RouteNotFound({ request }) }));
1484
- const submittedClientBuildIds = target._tag === "Ui" ? url.searchParams.getAll(HTTP_PROTOCOL.queryKeys.viewPayload) : target._tag === "Endpoint" ? [request.headers[HTTP_PROTOCOL.requestHeaders.clientBuildId]].filter((value) => value !== void 0) : [];
1485
- if (submittedClientBuildIds.length > 1) return badRequest;
1486
- const submittedClientBuildId = submittedClientBuildIds[0];
1487
- const isJsonRequest = submittedClientBuildId !== void 0 && submittedClientBuildId !== "";
1488
- if (target._tag === "Ui" && isJsonRequest && submittedClientBuildId !== clientBuildId && submittedClientBuildId !== "_") return finalizeBuildSkew(clientBuildId);
1489
- if (target._tag === "Ui") {
1490
- url.searchParams.delete(HTTP_PROTOCOL.queryKeys.viewPayload);
1491
- url.searchParams.delete(HTTP_PROTOCOL.queryKeys.deployment);
1492
- }
1493
- const source = {
1494
- request,
1495
- clientBuildId: isJsonRequest && submittedClientBuildId !== "_" ? submittedClientBuildId : void 0,
1496
- acceptsClientRedirect: request.headers[HTTP_PROTOCOL.requestHeaders.clientAcceptsRedirect] !== void 0,
1497
- metadata
1498
- };
1499
- const requestContext = input.requestServices === void 0 ? Context.empty() : yield* Layer.buildWithMemoMap(input.requestServices, Layer.makeMemoMapUnsafe(), yield* Effect.scope);
1500
- const middleware = getMiddlewareInvocations({
1501
- pipeline: input,
1502
- source,
1503
- nodes: prepared.success.middleware
1504
- });
1505
- switch (target._tag) {
1506
- case "Endpoint": return yield* handleEndpoint({
1507
- pipeline: input,
1508
- source,
1509
- url,
1510
- middleware,
1511
- node: target.node,
1512
- params: target.params,
1513
- splatValues: target.splatValues
1514
- }).pipe(Effect.provideContext(requestContext));
1515
- case "Ui": return yield* handleUi({
1516
- pipeline: input,
1517
- source,
1518
- url,
1519
- isJsonRequest,
1520
- middleware,
1521
- positions: target.positions,
1522
- assets: target.assets
1523
- }).pipe(Effect.provideContext(requestContext));
1524
- }
1525
- });
1526
- }
1527
- function makeInternalError(input) {
1528
- return Effect.logError(input.message, input.detail).pipe(Effect.as(finalizeStatus({
1529
- status: 500,
1530
- text: "Internal Server Error",
1531
- clientBuildId: input.clientBuildId
1532
- })));
1533
- }
1534
- function describeFinalizeError(error) {
1535
- switch (error._tag) {
1536
- case "FrameworkOwnedHeader": return "a handler set a header the framework owns";
1537
- }
1538
- }
1539
- function finalizeResult(input) {
1540
- if (Result.isFailure(input.result)) return makeInternalError({
1541
- clientBuildId: input.clientBuildId,
1542
- message: describeFinalizeError(input.result.failure),
1543
- detail: input.result.failure
1544
- });
1545
- return Effect.succeed(input.result.success);
1546
- }
1547
- function runHandler(input) {
1548
- return Effect.gen(function* () {
1549
- const effects = yield* Ref.make(empty);
1550
- const context = input.makeContextFn(effects);
1551
- const body = input.fn(context);
1552
- const provided = Effect.provideContext(body, input.services);
1553
- const exit = yield* Effect.exit(provided);
1554
- const contributions = yield* Ref.get(effects);
1555
- if (Exit.isFailure(exit)) {
1556
- if (matchesHandlerEndInterruption(exit.cause) && endsResponse(contributions)) return {
1557
- _tag: "Terminal",
1558
- effects: contributions
1559
- };
1560
- return {
1561
- _tag: "Failed",
1562
- effects: contributions,
1563
- cause: resolveDeclaredCause({
1564
- cause: exit.cause,
1565
- errors: input.errors
1566
- })
1567
- };
1568
- }
1569
- const output = yield* Effect.exit(input.readOutputFn(exit.value));
1570
- if (Exit.isFailure(output)) return {
1571
- _tag: "Failed",
1572
- effects: contributions,
1573
- cause: output.cause
1574
- };
1575
- return endsResponse(contributions) ? {
1576
- _tag: "Terminal",
1577
- effects: contributions
1578
- } : {
1579
- _tag: "Continue",
1580
- effects: contributions,
1581
- data: output.value
1582
- };
1583
- });
1584
- }
1585
- /** Reuses schema preparation by identity; each invocation still validates its own value. */
1586
- const getTypeDecoder = memoize((schema) => {
1587
- return Schema.decodeUnknownEffect(Schema.toType(schema));
1588
- });
1589
- /** Validates the decoded output before transporting its supported values. */
1590
- function encodeHandlerOutput(input) {
1591
- return Effect.gen(function* () {
1592
- const validated = yield* getTypeDecoder(input.schema)(input.value).pipe(Effect.mapError((cause) => new HandlerError({
1593
- status: 500,
1594
- cause
1595
- })));
1596
- return yield* Effect.fromResult(encodeTransportedValue({
1597
- value: validated,
1598
- typeEntries: SERVER_TRANSPORT_TYPE_ENTRIES
1599
- })).pipe(Effect.mapError((cause) => new HandlerError({
1600
- status: 500,
1601
- cause
1602
- })));
1603
- });
1604
- }
1605
- function resolveDeclaredCause(input) {
1606
- const reason = input.cause.reasons[0];
1607
- if (input.cause.reasons.length === 1 && reason !== void 0 && Cause.isFailReason(reason) && !(reason.error instanceof HandlerError)) {
1608
- const matched = matchDeclaredError({
1609
- errors: input.errors,
1610
- value: reason.error
1611
- });
1612
- if (matched !== void 0) return Cause.fail(new DeclaredDomainError({
1613
- status: matched.status,
1614
- clientMessage: getStatusText(matched.status),
1615
- tag: matched.tag,
1616
- data: matched.data
1617
- }));
1618
- }
1619
- return input.cause;
1620
- }
1621
- /** The response operations every handler context shares: one effects ref, the request's redirect acceptance, and route targets resolved against the plan. */
1622
- function makeSharedResponseOps(input) {
1623
- return makeResponseOps({
1624
- effects: input.effects,
1625
- acceptsClientRedirect: input.source.acceptsClientRedirect,
1626
- resolveRouteTargetFn: (options) => {
1627
- return resolveRouteTarget({
1628
- plan: input.plan,
1629
- ...options
1630
- });
1631
- }
1632
- });
1633
- }
1634
- function makeRouteContext(input) {
1635
- return {
1636
- ...makeRequestFacts(input.source, input.facts),
1637
- ...makeSharedResponseOps(input)
1638
- };
1639
- }
1640
- function makeUiLoaderContext(input) {
1641
- return {
1642
- ...makeRouteContext(input),
1643
- ...makeHeadOps(input.effects)
1644
- };
1645
- }
1646
- function makeMiddlewareContext(input) {
1647
- return {
1648
- ...makeIncomingRequestFacts(input.source),
1649
- ...makeSharedResponseOps(input),
1650
- ...makeHeadOps(input.effects)
1651
- };
1652
- }
1653
- /** A UI pattern an application names, with the search it supplies validated by the pattern's owners. */
1654
- function resolveRouteTarget(input) {
1655
- const target = input.plan.uiByAuthoredPattern.get(`${input.pattern === "/" ? "" : input.pattern}/_index`) ?? input.plan.uiByAuthoredPattern.get(input.pattern);
1656
- if (target === void 0) return Effect.fail({
1657
- _tag: "UnknownRoutePattern",
1658
- pattern: input.pattern
1659
- });
1660
- const pattern = target.pattern;
1661
- const owners = target.searchOwners;
1662
- if (owners.length === 0) return input.search === void 0 ? Effect.succeed({
1663
- pattern,
1664
- search: void 0
1665
- }) : Effect.fail({
1666
- _tag: "UnexpectedRouteSearch",
1667
- pattern: input.pattern
1668
- });
1669
- const value = input.search === void 0 ? {} : input.search;
1670
- return Effect.forEach(owners, (owner) => {
1671
- return getTypeDecoder(owner.search.schema)(projectSearchFields(value, owner.search.fields.keys()));
1672
- }, { concurrency: "unbounded" }).pipe(Effect.flatMap((validated) => {
1673
- return Effect.gen(function* () {
1674
- const merged = makeNullPrototypeRecord();
1675
- for (const part of validated) {
1676
- if (typeof part !== "object" || part === null) return yield* Effect.fail({
1677
- _tag: "InvalidRouteSearchEncoding",
1678
- pattern: input.pattern
1679
- });
1680
- for (const [key, child] of getOwnEntries(part)) merged[key] = child;
1681
- }
1682
- return {
1683
- pattern,
1684
- search: merged
1685
- };
1686
- });
1687
- }));
1688
- }
1689
- function getMiddlewareInvocations(input) {
1690
- const { pipeline, source } = input;
1691
- return input.nodes.map((node, index) => {
1692
- return {
1693
- id: `middleware:${index}`,
1694
- role: "middleware",
1695
- pattern: node.declaration.patterns.join(" "),
1696
- run: runHandler({
1697
- makeContextFn: (effects) => {
1698
- return makeMiddlewareContext({
1699
- effects,
1700
- source,
1701
- plan: pipeline.plan
1702
- });
1703
- },
1704
- fn: node.declaration.fn,
1705
- readOutputFn: () => Effect.void,
1706
- errors: [],
1707
- services: pipeline.services.middleware
1708
- })
1709
- };
1710
- });
1711
- }
1712
- /** Parses a request's search through its check-free contract document; a grammar failure is the handler's 400. */
1713
- function parseSearch(input) {
1714
- return Result.mapError(parseSearchParams({
1715
- document: input.document,
1716
- params: input.params,
1717
- typeEntries: SERVER_TRANSPORT_TYPE_ENTRIES
1718
- }), (cause) => {
1719
- return new HandlerError({
1720
- status: 400,
1721
- clientMessage: "Invalid search parameters",
1722
- cause
1723
- });
1724
- });
1725
- }
1726
- /** Validates a parsed search against the declared codec's decoded side; a contract failure is the handler's 400. */
1727
- function decodeParsedSearch(input) {
1728
- return getTypeDecoder(input.schema)(input.parsed).pipe(Effect.mapError((cause) => {
1729
- return new HandlerError({
1730
- status: 400,
1731
- clientMessage: "Invalid search parameters",
1732
- cause
1733
- });
1734
- }));
1735
- }
1736
- function decodeSearch(input) {
1737
- if (input.search === null) return Effect.succeed(void 0);
1738
- return Effect.fromResult(parseSearch({
1739
- document: input.search.document,
1740
- params: input.params
1741
- })).pipe(Effect.flatMap((parsed) => {
1742
- return decodeParsedSearch({
1743
- schema: input.search.schema,
1744
- parsed
1745
- });
1746
- }));
1747
- }
1748
- function makeBadBodyError(cause) {
1749
- return new HandlerError({
1750
- status: 400,
1751
- clientMessage: "Invalid body",
1752
- cause
1753
- });
1754
- }
1755
- /** Acquires the body through native Effect readers and their request-context controls. */
1756
- function readEndpointBody(input) {
1757
- const transport = getInputTransport(input.declaration);
1758
- if (transport.kind === "json") return input.request.json;
1759
- if (transport.kind === "formData") return input.request.headers["content-type"]?.toLowerCase().includes("multipart/form-data") ? input.request.multipart : input.request.urlParamsBody.pipe(Effect.map(UrlParams.toRecord));
1760
- return Effect.succeed(void 0);
1761
- }
1762
- function decodeBody(input) {
1763
- const transport = getInputTransport(input.declaration);
1764
- if (transport.kind !== "json" && transport.kind !== "formData") return Effect.succeed(void 0);
1765
- const raw = transport.kind === "formData" ? Effect.succeed(input.value) : Effect.fromResult(readTransportedValue(input.value)).pipe(Effect.flatMap((transported) => {
1766
- return Effect.fromResult(decodeTransportedValue({
1767
- transported,
1768
- typeEntries: SERVER_TRANSPORT_TYPE_ENTRIES
1769
- }));
1770
- }), Effect.mapError(makeBadBodyError));
1771
- const decode = transport.kind === "formData" ? Schema.decodeUnknownEffect(transport.schema) : getTypeDecoder(transport.schema);
1772
- return raw.pipe(Effect.flatMap((value) => {
1773
- return decode(value).pipe(Effect.mapError(makeBadBodyError));
1774
- }));
1775
- }
1776
- const SERVICES_FOR_ENDPOINT_KIND = {
1777
- query: "queries",
1778
- mutation: "mutations",
1779
- stream: "streams"
1780
- };
1781
- function getServicesForKind(input) {
1782
- return input.services[SERVICES_FOR_ENDPOINT_KIND[input.kind]];
1783
- }
1784
- function handleEndpoint(input) {
1785
- return Effect.gen(function* () {
1786
- const { pipeline, node, source } = input;
1787
- const { metadata, request } = pipeline;
1788
- const declaration = node.declaration;
1789
- const clientBuildId = metadata.clientBuildId;
1790
- if (declaration.kind === "stream") return yield* makeInternalError({
1791
- clientBuildId,
1792
- message: "stream endpoints are not implemented in this runtime yet",
1793
- detail: declaration.pattern
1794
- });
1795
- const middleware = yield* executeMiddleware(input.middleware);
1796
- if (middleware._tag === "Terminal") return yield* finalizeResult({
1797
- clientBuildId,
1798
- result: finalizeEndpointTerminal({
1799
- effects: middleware.effects,
1800
- clientBuildId
1801
- })
1802
- });
1803
- const value = declaration.method === "GET" ? void 0 : yield* readEndpointBody({
1804
- declaration,
1805
- request
1806
- });
1807
- const services = getServicesForKind({
1808
- services: pipeline.services,
1809
- kind: declaration.kind
1810
- });
1811
- const decodeInput = (declaration.method === "GET" ? decodeSearch({
1812
- search: node.search,
1813
- params: input.url.searchParams
1814
- }) : decodeBody({
1815
- declaration,
1816
- value
1817
- })).pipe(Effect.provideContext(services));
1818
- const invocation = {
1819
- id: `endpoint:${declaration.method} ${declaration.pattern}`,
1820
- role: "endpoint",
1821
- pattern: declaration.pattern,
1822
- run: decodeInput.pipe(Effect.flatMap((decoded) => {
1823
- return runHandler({
1824
- makeContextFn: (effects) => {
1825
- return makeRouteContext({
1826
- effects,
1827
- source,
1828
- plan: pipeline.plan,
1829
- facts: {
1830
- pattern: declaration.pattern,
1831
- params: { ...input.params },
1832
- splatValues: [...input.splatValues],
1833
- input: decoded
1834
- }
1835
- });
1836
- },
1837
- fn: declaration.fn,
1838
- readOutputFn: (value) => {
1839
- return encodeHandlerOutput({
1840
- schema: declaration.output,
1841
- value
1842
- });
1843
- },
1844
- errors: declaration.errors,
1845
- services
1846
- });
1847
- }))
1848
- };
1849
- return yield* executeEndpoint({
1850
- effects: middleware.effects,
1851
- endpoint: invocation
1852
- }).pipe(Effect.flatMap((report) => {
1853
- if (report._tag === "Terminal") return finalizeResult({
1854
- clientBuildId,
1855
- result: finalizeEndpointTerminal({
1856
- effects: report.effects,
1857
- clientBuildId
1858
- })
1859
- });
1860
- const serialized = serializeResponseJson(report.data);
1861
- if (Result.isFailure(serialized)) return makeInternalError({
1862
- clientBuildId,
1863
- message: "the endpoint response could not be serialized",
1864
- detail: serialized.failure
1865
- });
1866
- return finalizeResult({
1867
- clientBuildId,
1868
- result: finalizeEndpointJson({
1869
- json: serialized.success,
1870
- effects: report.effects,
1871
- clientBuildId
1872
- })
1873
- });
1874
- }));
1875
- });
1876
- }
1877
- function prepareDocumentValue(input) {
1878
- return Effect.suspend(() => {
1879
- return Effect.provideContext(input.fn(makeIncomingRequestFacts(input.source)), input.services);
1880
- }).pipe(Effect.catchCause((cause) => {
1881
- return Cause.hasInterruptsOnly(cause) ? Effect.interrupt : Effect.fail({
1882
- _tag: "DocumentPreparationError",
1883
- cause
1884
- });
1885
- }));
1886
- }
1887
- function handleUi(input) {
1888
- const { pipeline, source, positions } = input;
1889
- const { plan, metadata } = pipeline;
1890
- const executionPositions = positions.map((position) => {
1891
- const search = position.node.uiLoader === null ? null : position.node.uiLoader.search;
1892
- return {
1893
- position,
1894
- searchInput: search === null ? null : parseSearch({
1895
- document: search.document,
1896
- params: input.url.searchParams
1897
- })
1898
- };
1899
- }).map((owner) => {
1900
- const { position, searchInput } = owner;
1901
- const uiLoader = position.node.uiLoader;
1902
- if (uiLoader === null) return {
1903
- owner,
1904
- invocation: null
1905
- };
1906
- const search = uiLoader.search;
1907
- return {
1908
- owner,
1909
- invocation: {
1910
- id: `uiLoader:${uiLoader.declaration.pattern}`,
1911
- role: "uiLoader",
1912
- pattern: uiLoader.declaration.pattern,
1913
- run: (search === null || searchInput === null ? Effect.succeed(void 0) : Effect.fromResult(searchInput).pipe(Effect.flatMap((parsed) => {
1914
- return decodeParsedSearch({
1915
- schema: search.schema,
1916
- parsed
1917
- });
1918
- }))).pipe(Effect.flatMap((decoded) => {
1919
- return runHandler({
1920
- makeContextFn: (effects) => {
1921
- return makeUiLoaderContext({
1922
- effects,
1923
- source,
1924
- plan,
1925
- facts: {
1926
- pattern: uiLoader.declaration.pattern,
1927
- params: { ...position.params },
1928
- splatValues: [...position.splatValues],
1929
- input: decoded
1930
- }
1931
- });
1932
- },
1933
- fn: uiLoader.declaration.fn,
1934
- readOutputFn: (value) => {
1935
- return encodeHandlerOutput({
1936
- schema: uiLoader.declaration.output,
1937
- value
1938
- });
1939
- },
1940
- errors: [],
1941
- services: pipeline.services.uiLoaders
1942
- });
1943
- }))
1944
- }
1945
- };
1946
- });
1947
- return Effect.scoped(Effect.gen(function* () {
1948
- const middleware = yield* executeMiddleware(input.middleware);
1949
- if (middleware._tag === "Terminal") return yield* finalizeResult({
1950
- clientBuildId: metadata.clientBuildId,
1951
- result: finalizeTerminal({
1952
- effects: middleware.effects,
1953
- clientBuildId: metadata.clientBuildId
1954
- })
1955
- });
1956
- const defaults = yield* Effect.forkScoped(prepareDocumentValue({
1957
- fn: plan.document.defaultHeadFn,
1958
- source,
1959
- services: pipeline.services.document
1960
- }));
1961
- const attributes = input.isJsonRequest ? null : yield* Effect.forkScoped(prepareDocumentValue({
1962
- fn: plan.document.attributesFn,
1963
- source,
1964
- services: pipeline.services.document
1965
- }));
1966
- const routes = yield* Effect.forkScoped(executeUi({
1967
- effects: middleware.effects,
1968
- positions: executionPositions
1969
- }));
1970
- const report = yield* Fiber.join(routes);
1971
- if (report._tag === "Terminal") return yield* finalizeResult({
1972
- clientBuildId: metadata.clientBuildId,
1973
- result: finalizeTerminal({
1974
- effects: report.effects,
1975
- clientBuildId: metadata.clientBuildId
1976
- })
1977
- });
1978
- const headDefaults = yield* Fiber.join(defaults);
1979
- return yield* respondUi({
1980
- pipeline,
1981
- assets: input.assets,
1982
- output: attributes === null ? { kind: "navigation" } : {
1983
- kind: "document",
1984
- attributes: yield* Fiber.join(attributes)
1985
- },
1986
- report,
1987
- headDefaults
1988
- });
1989
- })).pipe(Effect.catchTag("DocumentPreparationError", (error) => {
1990
- return makeInternalError({
1991
- clientBuildId: metadata.clientBuildId,
1992
- message: "the document could not be prepared",
1993
- detail: error.cause
1994
- });
1995
- }));
1996
- }
1997
- function respondUi(input) {
1998
- const { pipeline, report } = input;
1999
- const { metadata } = pipeline;
2000
- const clientBuildId = metadata.clientBuildId;
2001
- const dedupeRules = pipeline.plan.headDeduplicationRules;
2002
- const positions = [];
2003
- for (const executed of report.positions) {
2004
- if (executed._tag === "Suppressed") continue;
2005
- const route = executed.owner;
2006
- let searchInput = null;
2007
- if (executed._tag !== "Failed" && route.searchInput !== null && Result.isSuccess(route.searchInput)) {
2008
- const transported = encodeTransportedValue({
2009
- value: route.searchInput.success,
2010
- typeEntries: SERVER_TRANSPORT_TYPE_ENTRIES
2011
- });
2012
- if (Result.isFailure(transported)) return makeInternalError({
2013
- clientBuildId,
2014
- message: "the route search input could not be transported",
2015
- detail: transported.failure
2016
- });
2017
- searchInput = transported.success;
2018
- }
2019
- positions.push({
2020
- ...executed,
2021
- owner: {
2022
- position: route.position,
2023
- searchInput
2024
- }
2025
- });
2026
- }
2027
- const payload = projectPayload({
2028
- clientEntry: metadata.clientEntry,
2029
- assets: input.assets,
2030
- report: {
2031
- ...report,
2032
- positions
2033
- },
2034
- headDefaults: input.headDefaults,
2035
- dedupeRules
2036
- });
2037
- if (input.output.kind === "navigation") {
2038
- const navigationPayload = toNavigationPayload(payload);
2039
- if (Result.isFailure(navigationPayload)) return makeInternalError({
2040
- clientBuildId,
2041
- message: "the navigation head could not be serialized",
2042
- detail: navigationPayload.failure
2043
- });
2044
- const serialized = serializeResponseJson(navigationPayload.success);
2045
- if (Result.isFailure(serialized)) return makeInternalError({
2046
- clientBuildId,
2047
- message: "the UI payload could not be serialized",
2048
- detail: serialized.failure
2049
- });
2050
- return finalizeResult({
2051
- clientBuildId,
2052
- result: finalizeJson({
2053
- json: serialized.success,
2054
- effects: report.effects,
2055
- clientBuildId
2056
- })
2057
- });
2058
- }
2059
- const serialized = serializeResponseJson(toSsrPayload({
2060
- projection: payload,
2061
- clientBuildId,
2062
- isDev: pipeline.isDev,
2063
- deploymentId: pipeline.deploymentId
2064
- }));
2065
- if (Result.isFailure(serialized)) return makeInternalError({
2066
- clientBuildId,
2067
- message: "the document payload could not be serialized",
2068
- detail: serialized.failure
2069
- });
2070
- const html = renderDocument({
2071
- attributes: input.output.attributes,
2072
- prepared: payload.preparedHead,
2073
- criticalCss: metadata.criticalCss,
2074
- ...metadata.developmentHeadHtml === void 0 ? {} : { developmentHeadHtml: metadata.developmentHeadHtml },
2075
- cssBundleUrls: payload.documentCssBundleUrls,
2076
- staticAssetUrls: payload.documentStaticAssetUrls,
2077
- modulePreloadUrls: [
2078
- metadata.clientEntry.importUrl,
2079
- ...payload.route.routes.flatMap((route) => {
2080
- return route.import_url === void 0 || route.import_url === null ? [] : [route.import_url];
2081
- }),
2082
- ...payload.documentDepUrls
2083
- ],
2084
- entryImportUrl: metadata.clientEntry.importUrl,
2085
- payloadJson: serialized.success
2086
- });
2087
- if (Result.isFailure(html)) return makeInternalError({
2088
- clientBuildId,
2089
- message: "the document failed to render",
2090
- detail: html.failure
2091
- });
2092
- return finalizeResult({
2093
- clientBuildId,
2094
- result: finalizeHtml({
2095
- html: html.success,
2096
- effects: report.effects,
2097
- clientBuildId
2098
- })
2099
- });
2100
- }
2101
- /** Application data has been captured and parsed; serialization can still exceed engine limits. */
2102
- function serializeResponseJson(payload) {
2103
- return Result.flatMap(Result.try(() => JSON.stringify(payload)), (json) => {
2104
- return json === void 0 ? Result.fail("The response has no JSON representation") : Result.succeed(json);
2105
- });
2106
- }
2107
- //#endregion
2108
- //#region src/server/runtime/vercel-deployment.ts
2109
- const VERCEL_SKEW_PROTECTION_ENABLED = Config.option(Config.Boolean(PROCESS_ENVIRONMENT_PROTOCOL.vercelSkewProtectionEnabledVariable));
2110
- const VERCEL_DEPLOYMENT_ID = Config.option(Config.String(PROCESS_ENVIRONMENT_PROTOCOL.vercelDeploymentIdVariable));
2111
- const getVercelDeploymentId = Effect.gen(function* () {
2112
- const enabled = yield* VERCEL_SKEW_PROTECTION_ENABLED;
2113
- if (Option.isNone(enabled) || enabled.value === false) return;
2114
- return Option.getOrUndefined(yield* VERCEL_DEPLOYMENT_ID);
2115
- });
2116
- //#endregion
2117
- //#region src/server/index.ts
2118
- function makeUiLoader(definition) {
2119
- return {
2120
- _tag: "UiLoader",
2121
- pattern: definition.pattern,
2122
- input: definition.input,
2123
- output: definition.output,
2124
- fn: definition.fn
2125
- };
2126
- }
2127
- const UiLoader = { make: makeUiLoader };
2128
- /** Query and mutation declarations have the same construction and HTTP method choices. */
2129
- function makeResponseEndpointMaker(kind) {
2130
- function make(definition) {
2131
- return {
2132
- _tag: "Endpoint",
2133
- kind,
2134
- method: definition.method,
2135
- pattern: definition.pattern,
2136
- input: definition.input,
2137
- output: definition.output,
2138
- event: void 0,
2139
- errors: definition.errors === void 0 ? [] : definition.errors,
2140
- fn: definition.fn
2141
- };
2142
- }
2143
- return make;
2144
- }
2145
- function makeStreamEndpoint(definition) {
2146
- return {
2147
- _tag: "Endpoint",
2148
- kind: "stream",
2149
- method: definition.method,
2150
- pattern: definition.pattern,
2151
- input: definition.input,
2152
- output: void 0,
2153
- event: definition.event,
2154
- errors: [],
2155
- fn: definition.fn
2156
- };
2157
- }
2158
- const QueryEndpoint = { make: makeResponseEndpointMaker("query") };
2159
- const MutationEndpoint = { make: makeResponseEndpointMaker("mutation") };
2160
- /** Unimplemented declaration scaffold. The build rejects registered stream endpoints. */
2161
- const StreamEndpoint = { make: makeStreamEndpoint };
2162
- function makeTaskMiddleware(definition) {
2163
- return {
2164
- _tag: "TaskMiddleware",
2165
- patterns: definition.patterns,
2166
- methods: definition.methods,
2167
- fn: definition.fn
2168
- };
2169
- }
2170
- const TaskMiddleware = { make: makeTaskMiddleware };
2171
- function makeHtmlDocument(definition) {
2172
- return {
2173
- _tag: "HtmlDocument",
2174
- attributesFn: definition.attributesFn,
2175
- defaultHeadFn: definition.defaultHeadFn,
2176
- headDeduplicationRules: definition.headDeduplicationRules ?? []
2177
- };
2178
- }
2179
- const HtmlDocument = { make: makeHtmlDocument };
2180
- /**
2181
- * Connects configuration, the document, and ordered task middleware without
2182
- * starting execution. Explicit startup acquires the compiled declarations and
2183
- * metadata through one shared application Layer.
2184
- */
2185
- function makeApplication(input) {
2186
- return {
2187
- _tag: "Application",
2188
- [APPLICATION_RUNTIME]: makeApplicationRuntime(input.config),
2189
- document: input.document,
2190
- middleware: input.middleware
2191
- };
2192
- }
2193
- /** A startup failure: the deployment or its generated source is wrong, never a defect. */
2194
- function failStartup(input) {
2195
- return Effect.fail(createVormaStartupError(input));
2196
- }
2197
- /**
2198
- * Acquires handlers for application-controlled mounting. Per-kind Layers provide
2199
- * application services, and the optional request Layer supplies request services.
2200
- */
2201
- function makeHandlers(options) {
2202
- return Effect.gen(function* () {
2203
- const { app } = options;
2204
- const runtime = yield* ApplicationRuntime;
2205
- const { metadata } = runtime;
2206
- const isDev = metadata.runtimeMode === "development";
2207
- function toCriticalCssDigest(css) {
2208
- return base64.encode(sha256(new TextEncoder().encode(css)));
2209
- }
2210
- const criticalCssDigest = runtime.readDevelopmentMetadata === void 0 ? Effect.succeed(toCriticalCssDigest(metadata.criticalCss)) : runtime.readDevelopmentMetadata.pipe(Effect.map((current) => toCriticalCssDigest(current.criticalCss)));
2211
- const deploymentId = yield* getVercelDeploymentId.pipe(Effect.mapError((cause) => {
2212
- return createVormaStartupError({
2213
- operation: "readDeploymentConfiguration",
2214
- message: "Vorma could not read deployment configuration",
2215
- cause
2216
- });
2217
- }));
2218
- const plan = compileRequestPlan({
2219
- clientEntry: metadata.clientEntry,
2220
- document: app.document,
2221
- handlers: runtime.registeredDeclarations,
2222
- middleware: app.middleware,
2223
- clientViews: metadata.clientViews
2224
- });
2225
- if (Result.isFailure(plan)) {
2226
- const invalidDeclarations = Array.isArray(plan.failure);
2227
- return yield* failStartup({
2228
- operation: invalidDeclarations ? "validateApplicationGraph" : "buildRequestPlan",
2229
- message: invalidDeclarations ? "The Vorma application graph is invalid" : "Vorma could not build the request plan",
2230
- cause: plan.failure
2231
- });
2232
- }
2233
- const memoMap = Layer.CurrentMemoMap.forkOrCreate(yield* Effect.context());
2234
- const scope = yield* Effect.scope;
2235
- const serviceLayers = {
2236
- document: options.documentServices,
2237
- uiLoaders: options.uiLoaderServices,
2238
- queries: options.queryServices,
2239
- mutations: options.mutationServices,
2240
- streams: options.streamServices,
2241
- middleware: options.middlewareServices
2242
- };
2243
- const services = yield* Effect.all(Record.map(serviceLayers, (serviceLayer) => {
2244
- return Layer.buildWithMemoMap(serviceLayer === void 0 ? Layer.empty : serviceLayer, memoMap, scope);
2245
- }), { concurrency: "unbounded" });
2246
- const taskRuntime = yield* Layer.buildWithMemoMap(TaskRuntime.layer, memoMap, scope);
2247
- let compiledPlan = plan.success;
2248
- let plannedMetadata = metadata;
2249
- function forOperation(operation) {
2250
- return Effect.gen(function* () {
2251
- const request = yield* HttpServerRequest.HttpServerRequest;
2252
- const requestMetadata = runtime.readDevelopmentMetadata === void 0 ? metadata : yield* runtime.readDevelopmentMetadata;
2253
- if (requestMetadata !== plannedMetadata) {
2254
- const nextPlan = compileRequestPlan({
2255
- clientEntry: requestMetadata.clientEntry,
2256
- document: app.document,
2257
- handlers: runtime.registeredDeclarations,
2258
- middleware: app.middleware,
2259
- clientViews: requestMetadata.clientViews
2260
- });
2261
- if (Result.isFailure(nextPlan)) return yield* failStartup({
2262
- operation: "buildRequestPlan",
2263
- message: "Vorma could not prepare the development request plan",
2264
- cause: nextPlan.failure
2265
- });
2266
- compiledPlan = nextPlan.success;
2267
- plannedMetadata = requestMetadata;
2268
- }
2269
- return yield* handleRequest({
2270
- plan: compiledPlan,
2271
- operation,
2272
- metadata: requestMetadata,
2273
- request,
2274
- services,
2275
- ...options.requestServices === void 0 ? {} : { requestServices: options.requestServices },
2276
- isDev,
2277
- ...deploymentId === void 0 ? {} : { deploymentId }
2278
- });
2279
- }).pipe(Effect.provideServiceEffect(TaskContext, TaskContext.make), Effect.provideContext(taskRuntime));
2280
- }
2281
- const ui = forOperation({ _tag: "Ui" });
2282
- return {
2283
- ui: isDev ? Effect.gen(function* () {
2284
- const request = yield* HttpServerRequest.HttpServerRequest;
2285
- if (request.method === "GET" && request.url.split("?", 1)[0] === DEVELOPMENT_PROTOCOL.readinessPath) return HttpServerResponse.text("ok");
2286
- return yield* ui;
2287
- }) : ui,
2288
- /** Base64 SHA-256 of the exact inline critical CSS; use it in a CSP hash source. */
2289
- getCriticalCssContentSha256: () => {
2290
- return criticalCssDigest;
2291
- },
2292
- forEndpointMethod: (method) => forOperation({
2293
- _tag: "Endpoint",
2294
- method
2295
- })
2296
- };
2297
- }).pipe(Effect.provide(options.app[APPLICATION_RUNTIME]));
2298
- }
2299
- const Vorma = {
2300
- /** Inert application construction from configuration, a document, and ordered task middleware. */
2301
- makeApplication,
2302
- /**
2303
- * Acquires UI and endpoint handlers. The application selects each native
2304
- * registration's method and path and owns serving and service composition.
2305
- */
2306
- makeHandlers,
2307
- /** Creates file-serving middleware that the application explicitly mounts. */
2308
- makePublicAssetsFileMiddleware
2309
- };
2310
- //#endregion
2311
- export { FormData, HandlerError, HtmlDocument, MutationEndpoint, QueryEndpoint, ResponseInputError, StreamEndpoint, TaskMiddleware, UiLoader, Vorma, escapeJsonForScript };