@warlock.js/web 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/LICENSE +21 -0
- package/README.md +125 -0
- package/esm/build/contribution.d.mts +55 -0
- package/esm/build/contribution.mjs +132 -0
- package/esm/build/contribution.mjs.map +1 -0
- package/esm/build/discover-pages.mjs +294 -0
- package/esm/build/discover-pages.mjs.map +1 -0
- package/esm/build/generate-client-registry.mjs +123 -0
- package/esm/build/generate-client-registry.mjs.map +1 -0
- package/esm/build/generate-pages-barrel.mjs +330 -0
- package/esm/build/generate-pages-barrel.mjs.map +1 -0
- package/esm/build/read-route-exports.mjs +212 -0
- package/esm/build/read-route-exports.mjs.map +1 -0
- package/esm/client/build-hydrated-tree.mjs +113 -0
- package/esm/client/build-hydrated-tree.mjs.map +1 -0
- package/esm/client/hydrate-page.mjs +73 -0
- package/esm/client/hydrate-page.mjs.map +1 -0
- package/esm/client/navigation/current-route.d.mts +91 -0
- package/esm/client/navigation/current-route.mjs +66 -0
- package/esm/client/navigation/current-route.mjs.map +1 -0
- package/esm/client/navigation/fetch-page-data.mjs +97 -0
- package/esm/client/navigation/fetch-page-data.mjs.map +1 -0
- package/esm/client/navigation/navigation-root.mjs +196 -0
- package/esm/client/navigation/navigation-root.mjs.map +1 -0
- package/esm/client/navigation/prefetch.mjs +110 -0
- package/esm/client/navigation/prefetch.mjs.map +1 -0
- package/esm/client/navigation/refresh.d.mts +40 -0
- package/esm/client/navigation/refresh.mjs +146 -0
- package/esm/client/navigation/refresh.mjs.map +1 -0
- package/esm/client/navigation/verbs.d.mts +55 -0
- package/esm/client/navigation/verbs.mjs +66 -0
- package/esm/client/navigation/verbs.mjs.map +1 -0
- package/esm/client/runtime/index.d.mts +4 -0
- package/esm/client/runtime/index.mjs +4 -0
- package/esm/client/runtime/manifest.d.mts +8 -0
- package/esm/client/runtime/manifest.mjs +77 -0
- package/esm/client/runtime/manifest.mjs.map +1 -0
- package/esm/client/runtime/matcher.d.mts +7 -0
- package/esm/client/runtime/matcher.mjs +169 -0
- package/esm/client/runtime/matcher.mjs.map +1 -0
- package/esm/client/runtime/types.d.mts +22 -0
- package/esm/components/default-app.mjs +32 -0
- package/esm/components/default-app.mjs.map +1 -0
- package/esm/components/document-context.d.mts +1 -0
- package/esm/components/document-context.mjs +24 -0
- package/esm/components/document-context.mjs.map +1 -0
- package/esm/components/head.d.mts +14 -0
- package/esm/components/head.mjs +63 -0
- package/esm/components/head.mjs.map +1 -0
- package/esm/components/link.d.mts +157 -0
- package/esm/components/link.mjs +194 -0
- package/esm/components/link.mjs.map +1 -0
- package/esm/components/scripts.d.mts +14 -0
- package/esm/components/scripts.mjs +21 -0
- package/esm/components/scripts.mjs.map +1 -0
- package/esm/connector/index.d.mts +6 -0
- package/esm/connector/index.mjs +7 -0
- package/esm/context.d.mts +107 -0
- package/esm/hydration/index.d.mts +1 -0
- package/esm/hydration/index.mjs +33 -0
- package/esm/hydration/index.mjs.map +1 -0
- package/esm/hydration-payload.d.mts +1 -0
- package/esm/hydration-payload.mjs +72 -0
- package/esm/hydration-payload.mjs.map +1 -0
- package/esm/index.d.mts +35 -0
- package/esm/index.mjs +12 -0
- package/esm/loaders.d.mts +47 -0
- package/esm/metadata.d.mts +54 -0
- package/esm/props.d.mts +42 -0
- package/esm/route.d.mts +30 -0
- package/esm/routing/compose-route-path.mjs +33 -0
- package/esm/routing/compose-route-path.mjs.map +1 -0
- package/esm/routing/data-request.mjs +52 -0
- package/esm/routing/data-request.mjs.map +1 -0
- package/esm/routing/layout-policy.mjs +78 -0
- package/esm/routing/layout-policy.mjs.map +1 -0
- package/esm/routing/navigator.mjs +21 -0
- package/esm/routing/navigator.mjs.map +1 -0
- package/esm/routing/query-string.d.mts +250 -0
- package/esm/routing/query-string.mjs +340 -0
- package/esm/routing/query-string.mjs.map +1 -0
- package/esm/routing/route-identity.mjs +68 -0
- package/esm/routing/route-identity.mjs.map +1 -0
- package/esm/routing/route-table.d.mts +34 -0
- package/esm/routing/route-table.mjs +182 -0
- package/esm/routing/route-table.mjs.map +1 -0
- package/esm/routing/router-events.d.mts +159 -0
- package/esm/routing/router-events.mjs +83 -0
- package/esm/routing/router-events.mjs.map +1 -0
- package/esm/server/buffered-response.mjs +115 -0
- package/esm/server/buffered-response.mjs.map +1 -0
- package/esm/server/build-hydration-payload.mjs +27 -0
- package/esm/server/build-hydration-payload.mjs.map +1 -0
- package/esm/server/client-asset-url-prefix.d.mts +22 -0
- package/esm/server/client-asset-url-prefix.mjs +23 -0
- package/esm/server/client-asset-url-prefix.mjs.map +1 -0
- package/esm/server/create-page-module-loader.mjs +49 -0
- package/esm/server/create-page-module-loader.mjs.map +1 -0
- package/esm/server/create-page-route-handler.mjs +107 -0
- package/esm/server/create-page-route-handler.mjs.map +1 -0
- package/esm/server/dev-server.mjs +167 -0
- package/esm/server/dev-server.mjs.map +1 -0
- package/esm/server/execute-page-request.d.mts +1 -0
- package/esm/server/execute-page-request.mjs +166 -0
- package/esm/server/execute-page-request.mjs.map +1 -0
- package/esm/server/execute-page-request.types.d.mts +1 -0
- package/esm/server/hydration-client-url.d.mts +37 -0
- package/esm/server/hydration-client-url.mjs +101 -0
- package/esm/server/hydration-client-url.mjs.map +1 -0
- package/esm/server/index.mjs +13 -0
- package/esm/server/install-page-routes-from-manifest.mjs +133 -0
- package/esm/server/install-page-routes-from-manifest.mjs.map +1 -0
- package/esm/server/install-page-routes.d.mts +1 -0
- package/esm/server/install-page-routes.mjs +6 -0
- package/esm/server/install-production-page-routes.mjs +55 -0
- package/esm/server/install-production-page-routes.mjs.map +1 -0
- package/esm/server/match-page-route.mjs +48 -0
- package/esm/server/match-page-route.mjs.map +1 -0
- package/esm/server/page-context.d.mts +1 -0
- package/esm/server/page-context.mjs +33 -0
- package/esm/server/page-context.mjs.map +1 -0
- package/esm/server/page-manifest.d.mts +102 -0
- package/esm/server/page-manifest.mjs +31 -0
- package/esm/server/page-manifest.mjs.map +1 -0
- package/esm/server/render-page.mjs +214 -0
- package/esm/server/render-page.mjs.map +1 -0
- package/esm/server/resolve-page-metadata.mjs +33 -0
- package/esm/server/resolve-page-metadata.mjs.map +1 -0
- package/esm/server/resolve-validation-data.mjs +27 -0
- package/esm/server/resolve-validation-data.mjs.map +1 -0
- package/esm/server/settle-page-response.d.mts +1 -0
- package/esm/server/settle-page-response.mjs +90 -0
- package/esm/server/settle-page-response.mjs.map +1 -0
- package/esm/server/stylesheet-urls.mjs +65 -0
- package/esm/server/stylesheet-urls.mjs.map +1 -0
- package/esm/server/web-connector-factory.d.mts +25 -0
- package/esm/server/web-connector-factory.mjs +121 -0
- package/esm/server/web-connector-factory.mjs.map +1 -0
- package/esm/server/web-connector.d.mts +34 -0
- package/esm/server/web-connector.mjs +516 -0
- package/esm/server/web-connector.mjs.map +1 -0
- package/esm/shared.d.mts +22 -0
- package/esm/shared.mjs +223 -0
- package/esm/shared.mjs.map +1 -0
- package/esm/validation.d.mts +31 -0
- package/esm/vite/app-convention-aliases.mjs +43 -0
- package/esm/vite/app-convention-aliases.mjs.map +1 -0
- package/esm/vite/build-client.d.mts +38 -0
- package/esm/vite/build-client.mjs +72 -0
- package/esm/vite/build-client.mjs.map +1 -0
- package/esm/vite/gate-a-resolve.d.mts +57 -0
- package/esm/vite/gate-a-resolve.mjs +834 -0
- package/esm/vite/gate-a-resolve.mjs.map +1 -0
- package/esm/vite/gate-b-secrets.d.mts +57 -0
- package/esm/vite/gate-b-secrets.mjs +299 -0
- package/esm/vite/gate-b-secrets.mjs.map +1 -0
- package/esm/vite/gate-c-verify.d.mts +118 -0
- package/esm/vite/gate-c-verify.mjs +263 -0
- package/esm/vite/gate-c-verify.mjs.map +1 -0
- package/esm/vite/hydration-entries.d.mts +17 -0
- package/esm/vite/hydration-entries.mjs +45 -0
- package/esm/vite/hydration-entries.mjs.map +1 -0
- package/esm/vite/index.d.mts +126 -0
- package/esm/vite/index.mjs +146 -0
- package/esm/vite/index.mjs.map +1 -0
- package/esm/vite/page-registry-plugin.d.mts +43 -0
- package/esm/vite/page-registry-plugin.mjs +138 -0
- package/esm/vite/page-registry-plugin.mjs.map +1 -0
- package/esm/vite/projection.d.mts +31 -0
- package/esm/vite/projection.mjs +384 -0
- package/esm/vite/projection.mjs.map +1 -0
- package/llms-full.txt +1041 -0
- package/llms.txt +21 -0
- package/package.json +77 -0
- package/skills/add-web-to-an-app/SKILL.md +103 -0
- package/skills/create-a-page/SKILL.md +141 -0
- package/skills/load-page-data/SKILL.md +183 -0
- package/skills/navigate-on-the-client/SKILL.md +182 -0
- package/skills/serve-styles/SKILL.md +145 -0
- package/skills/use-layouts/SKILL.md +121 -0
- package/skills/write-the-root/SKILL.md +131 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
//#region ../web/src/server/settle-page-response.ts
|
|
4
|
+
/** Root → leaf. The pipeline's one ordering, used by every stage that walks levels. */
|
|
5
|
+
const LEVEL_ORDER = [
|
|
6
|
+
"app",
|
|
7
|
+
"layout",
|
|
8
|
+
"page"
|
|
9
|
+
];
|
|
10
|
+
/**
|
|
11
|
+
* Settle the surviving buffers root→leaf, per cookie name / header key: a
|
|
12
|
+
* leafward level re-writing the same key wins it, everything else merges.
|
|
13
|
+
*
|
|
14
|
+
* **Headers and status are mirrored onto the live response here; COOKIES ARE
|
|
15
|
+
* NOT**, and that asymmetry is the fix for a real defect rather than an
|
|
16
|
+
* oversight. `header()` and `setStatusCode()` are keyed SETs, so mirroring here
|
|
17
|
+
* and re-applying at the emit is idempotent. `cookie()` APPENDS — Fastify emits
|
|
18
|
+
* one `Set-Cookie` per call — so doing both put the same cookie on the wire
|
|
19
|
+
* twice, on every page response including the happy path.
|
|
20
|
+
*
|
|
21
|
+
* The emit is the authoritative application site (`createPageRouteHandler`
|
|
22
|
+
* replays `rendered.cookies` through `applyBufferedCookie`), so the cookie loop
|
|
23
|
+
* is the one that goes.
|
|
24
|
+
*/
|
|
25
|
+
function commitBuffers(realResponse, ordered, forcedStatusCode) {
|
|
26
|
+
const headers = /* @__PURE__ */ new Map();
|
|
27
|
+
const cookies = /* @__PURE__ */ new Map();
|
|
28
|
+
let statusCode;
|
|
29
|
+
for (const { buffer } of ordered) {
|
|
30
|
+
for (const header of buffer.headers) headers.set(header.key.toLowerCase(), header);
|
|
31
|
+
for (const cookie of buffer.cookies) cookies.set(cookie.name, cookie);
|
|
32
|
+
if (buffer.statusCode !== void 0) statusCode = buffer.statusCode;
|
|
33
|
+
}
|
|
34
|
+
if (forcedStatusCode !== void 0) statusCode = forcedStatusCode;
|
|
35
|
+
for (const header of headers.values()) realResponse.header(header.key, header.value);
|
|
36
|
+
if (statusCode !== void 0) realResponse.setStatusCode(statusCode);
|
|
37
|
+
return {
|
|
38
|
+
headers: [...headers.values()],
|
|
39
|
+
cookies: [...cookies.values()],
|
|
40
|
+
statusCode,
|
|
41
|
+
committedLevels: ordered.map(({ level }) => level)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Nearest `ErrorBoundary` at or rootward of the throw; `app` is terminal. */
|
|
45
|
+
function designateBoundary(throwingLevel, triple) {
|
|
46
|
+
const throwingIndex = LEVEL_ORDER.indexOf(throwingLevel);
|
|
47
|
+
for (let index = throwingIndex; index >= 0; index--) {
|
|
48
|
+
const level = LEVEL_ORDER[index];
|
|
49
|
+
if (triple[level].ErrorBoundary) return {
|
|
50
|
+
throwingLevel,
|
|
51
|
+
boundaryLevel: level
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
throwingLevel,
|
|
56
|
+
boundaryLevel: "app"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The one place a throw enters the bundle.
|
|
61
|
+
*
|
|
62
|
+
* **Production never lets the raw error reach a client** — the boundary gets a
|
|
63
|
+
* surrogate carrying only `digest`, which is all the reference app's
|
|
64
|
+
* ErrorBoundary renders. Dev keeps the real thrown value so the stack survives,
|
|
65
|
+
* and it is never mutated to attach `digest`: that lives on the RECORD only.
|
|
66
|
+
*/
|
|
67
|
+
function buildErrorRecord(thrown, boundary, requestPath) {
|
|
68
|
+
const digest = randomUUID();
|
|
69
|
+
console.error("[warlock] page error", digest, ...requestPath ? [requestPath] : [], thrown);
|
|
70
|
+
if (process.env.NODE_ENV === "production") {
|
|
71
|
+
const surrogate = /* @__PURE__ */ new Error("An unexpected error occurred.");
|
|
72
|
+
surrogate.digest = digest;
|
|
73
|
+
return {
|
|
74
|
+
error: surrogate,
|
|
75
|
+
boundary,
|
|
76
|
+
digest,
|
|
77
|
+
scrubbed: true
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
error: thrown,
|
|
82
|
+
boundary,
|
|
83
|
+
digest,
|
|
84
|
+
scrubbed: false
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
export { LEVEL_ORDER, buildErrorRecord, commitBuffers, designateBoundary };
|
|
90
|
+
//# sourceMappingURL=settle-page-response.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settle-page-response.mjs","names":[],"sources":["../../../../../../../web/src/server/settle-page-response.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { BufferedCookie, BufferedHeader, ResponseBuffer } from \"./buffered-response\";\nimport type {\n PageBoundaryDesignation,\n PageErrorRecord,\n PageLevelName,\n PageResponseCommit,\n PageRouteEntry,\n PipelineResponse,\n} from \"./execute-page-request.types\";\n\n/** Root → leaf. The pipeline's one ordering, used by every stage that walks levels. */\nexport const LEVEL_ORDER: readonly PageLevelName[] = [\"app\", \"layout\", \"page\"];\n\n/**\n * Settle the surviving buffers root→leaf, per cookie name / header key: a\n * leafward level re-writing the same key wins it, everything else merges.\n *\n * **Headers and status are mirrored onto the live response here; COOKIES ARE\n * NOT**, and that asymmetry is the fix for a real defect rather than an\n * oversight. `header()` and `setStatusCode()` are keyed SETs, so mirroring here\n * and re-applying at the emit is idempotent. `cookie()` APPENDS — Fastify emits\n * one `Set-Cookie` per call — so doing both put the same cookie on the wire\n * twice, on every page response including the happy path.\n *\n * The emit is the authoritative application site (`createPageRouteHandler`\n * replays `rendered.cookies` through `applyBufferedCookie`), so the cookie loop\n * is the one that goes.\n */\nexport function commitBuffers(\n realResponse: PipelineResponse,\n ordered: readonly { level: PageLevelName; buffer: ResponseBuffer }[],\n forcedStatusCode?: number,\n): PageResponseCommit {\n const headers = new Map<string, BufferedHeader>();\n const cookies = new Map<string, BufferedCookie>();\n let statusCode: number | undefined;\n\n for (const { buffer } of ordered) {\n for (const header of buffer.headers) headers.set(header.key.toLowerCase(), header);\n for (const cookie of buffer.cookies) cookies.set(cookie.name, cookie);\n if (buffer.statusCode !== undefined) statusCode = buffer.statusCode;\n }\n\n if (forcedStatusCode !== undefined) statusCode = forcedStatusCode;\n\n for (const header of headers.values()) realResponse.header(header.key, header.value);\n if (statusCode !== undefined) realResponse.setStatusCode(statusCode);\n\n // No `realResponse.cookie(...)` loop — see above. Settled cookies leave\n // through the return value only, and the emit applies them exactly once.\n\n return {\n headers: [...headers.values()],\n cookies: [...cookies.values()],\n statusCode,\n committedLevels: ordered.map(({ level }) => level),\n };\n}\n\n/** Nearest `ErrorBoundary` at or rootward of the throw; `app` is terminal. */\nexport function designateBoundary(\n throwingLevel: PageLevelName,\n triple: PageRouteEntry[\"triple\"],\n): PageBoundaryDesignation {\n const throwingIndex = LEVEL_ORDER.indexOf(throwingLevel);\n\n for (let index = throwingIndex; index >= 0; index--) {\n const level = LEVEL_ORDER[index];\n\n if (triple[level].ErrorBoundary) {\n return { throwingLevel, boundaryLevel: level };\n }\n }\n\n // The framework owns a root boundary.\n return { throwingLevel, boundaryLevel: \"app\" };\n}\n\n/**\n * The one place a throw enters the bundle.\n *\n * **Production never lets the raw error reach a client** — the boundary gets a\n * surrogate carrying only `digest`, which is all the reference app's\n * ErrorBoundary renders. Dev keeps the real thrown value so the stack survives,\n * and it is never mutated to attach `digest`: that lives on the RECORD only.\n */\nexport function buildErrorRecord(\n thrown: unknown,\n boundary: PageBoundaryDesignation,\n requestPath?: string,\n): PageErrorRecord {\n const digest = randomUUID();\n\n // The boundary tells the user this was logged, so log it. A digest that\n // appears in no log is worse than no digest.\n console.error(\"[warlock] page error\", digest, ...(requestPath ? [requestPath] : []), thrown);\n\n if (process.env.NODE_ENV === \"production\") {\n const surrogate = new Error(\"An unexpected error occurred.\");\n\n (surrogate as Error & { digest: string }).digest = digest;\n\n return { error: surrogate, boundary, digest, scrubbed: true };\n }\n\n return { error: thrown, boundary, digest, scrubbed: false };\n}\n"],"mappings":";;;;AAYA,MAAa,cAAwC;CAAC;CAAO;CAAU;AAAM;;;;;;;;;;;;;;;;AAiB7E,SAAgB,cACd,cACA,SACA,kBACoB;CACpB,MAAM,0BAAU,IAAI,IAA4B;CAChD,MAAM,0BAAU,IAAI,IAA4B;CAChD,IAAI;CAEJ,KAAK,MAAM,EAAE,YAAY,SAAS;EAChC,KAAK,MAAM,UAAU,OAAO,SAAS,QAAQ,IAAI,OAAO,IAAI,YAAY,GAAG,MAAM;EACjF,KAAK,MAAM,UAAU,OAAO,SAAS,QAAQ,IAAI,OAAO,MAAM,MAAM;EACpE,IAAI,OAAO,eAAe,QAAW,aAAa,OAAO;CAC3D;CAEA,IAAI,qBAAqB,QAAW,aAAa;CAEjD,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG,aAAa,OAAO,OAAO,KAAK,OAAO,KAAK;CACnF,IAAI,eAAe,QAAW,aAAa,cAAc,UAAU;CAKnE,OAAO;EACL,SAAS,CAAC,GAAG,QAAQ,OAAO,CAAC;EAC7B,SAAS,CAAC,GAAG,QAAQ,OAAO,CAAC;EAC7B;EACA,iBAAiB,QAAQ,KAAK,EAAE,YAAY,KAAK;CACnD;AACF;;AAGA,SAAgB,kBACd,eACA,QACyB;CACzB,MAAM,gBAAgB,YAAY,QAAQ,aAAa;CAEvD,KAAK,IAAI,QAAQ,eAAe,SAAS,GAAG,SAAS;EACnD,MAAM,QAAQ,YAAY;EAE1B,IAAI,OAAO,MAAM,CAAC,eAChB,OAAO;GAAE;GAAe,eAAe;EAAM;CAEjD;CAGA,OAAO;EAAE;EAAe,eAAe;CAAM;AAC/C;;;;;;;;;AAUA,SAAgB,iBACd,QACA,UACA,aACiB;CACjB,MAAM,SAAS,WAAW;CAI1B,QAAQ,MAAM,wBAAwB,QAAQ,GAAI,cAAc,CAAC,WAAW,IAAI,CAAC,GAAI,MAAM;CAE3F,IAAI,QAAQ,IAAI,aAAa,cAAc;EACzC,MAAM,4BAAY,IAAI,MAAM,+BAA+B;EAE3D,AAAC,UAAyC,SAAS;EAEnD,OAAO;GAAE,OAAO;GAAW;GAAU;GAAQ,UAAU;EAAK;CAC9D;CAEA,OAAO;EAAE,OAAO;EAAQ;EAAU;EAAQ,UAAU;CAAM;AAC5D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { CLIENT_ASSET_URL_PREFIX } from "./client-asset-url-prefix.mjs";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
//#region ../web/src/server/stylesheet-urls.ts
|
|
6
|
+
/**
|
|
7
|
+
* Which stylesheets a document must link, in each of the two modes.
|
|
8
|
+
*
|
|
9
|
+
* WHY THIS EXISTS AT ALL. Nothing used to put CSS into the server-rendered
|
|
10
|
+
* document. A stylesheet reached the browser only because the CLIENT bundle
|
|
11
|
+
* imported it, which means JavaScript applied it after the module graph
|
|
12
|
+
* loaded — so every full page load painted unstyled first and restyled a
|
|
13
|
+
* moment later. The markup was correct the whole time, which is precisely why
|
|
14
|
+
* it was easy to miss.
|
|
15
|
+
*
|
|
16
|
+
* The two modes learn the answer from different places, and neither can use
|
|
17
|
+
* the other's:
|
|
18
|
+
*
|
|
19
|
+
* - PRODUCTION reads Vite's client manifest, the same artifact the hydration
|
|
20
|
+
* entry is already resolved from.
|
|
21
|
+
* - DEV has no manifest — Vite serves modules on demand — so the URLs are
|
|
22
|
+
* derived from the source files themselves.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Every stylesheet the client build emitted, as URLs the asset route serves.
|
|
26
|
+
*
|
|
27
|
+
* Vite records CSS against the CHUNK that imported it — an app whose
|
|
28
|
+
* `root.tsx` imports `app.css` produces a `root.tsx` entry carrying
|
|
29
|
+
* `css: ["assets/root-<hash>.css"]`, not a hydration entry carrying it. So
|
|
30
|
+
* this collects across every entry rather than looking under one name, which
|
|
31
|
+
* would silently find nothing the moment a stylesheet moved file.
|
|
32
|
+
*
|
|
33
|
+
* Duplicates are collapsed and order is preserved: two chunks importing the
|
|
34
|
+
* same stylesheet must not emit two `<link>` tags.
|
|
35
|
+
*
|
|
36
|
+
* A missing or malformed manifest returns NOTHING rather than throwing. The
|
|
37
|
+
* hydration resolver already fails loudly on exactly those conditions, from
|
|
38
|
+
* exactly the same file, and it runs first — a second, worse error for the
|
|
39
|
+
* same cause helps nobody.
|
|
40
|
+
*/
|
|
41
|
+
function productionStylesheetUrls(clientDir) {
|
|
42
|
+
const manifestPath = path.join(clientDir, ".vite", "manifest.json");
|
|
43
|
+
let manifest;
|
|
44
|
+
try {
|
|
45
|
+
manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
46
|
+
} catch {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
if (typeof manifest !== "object" || manifest === null) return [];
|
|
50
|
+
const urls = [];
|
|
51
|
+
for (const entry of Object.values(manifest)) {
|
|
52
|
+
if (entry === void 0 || !Array.isArray(entry.css)) continue;
|
|
53
|
+
for (const file of entry.css) {
|
|
54
|
+
if (typeof file !== "string" || file === "") continue;
|
|
55
|
+
const url = `/${file}`;
|
|
56
|
+
if (!url.startsWith(`${"/assets"}/`)) continue;
|
|
57
|
+
if (!urls.includes(url)) urls.push(url);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return urls;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { productionStylesheetUrls };
|
|
65
|
+
//# sourceMappingURL=stylesheet-urls.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stylesheet-urls.mjs","names":[],"sources":["../../../../../../../web/src/server/stylesheet-urls.ts"],"sourcesContent":["/**\n * Which stylesheets a document must link, in each of the two modes.\n *\n * WHY THIS EXISTS AT ALL. Nothing used to put CSS into the server-rendered\n * document. A stylesheet reached the browser only because the CLIENT bundle\n * imported it, which means JavaScript applied it after the module graph\n * loaded — so every full page load painted unstyled first and restyled a\n * moment later. The markup was correct the whole time, which is precisely why\n * it was easy to miss.\n *\n * The two modes learn the answer from different places, and neither can use\n * the other's:\n *\n * - PRODUCTION reads Vite's client manifest, the same artifact the hydration\n * entry is already resolved from.\n * - DEV has no manifest — Vite serves modules on demand — so the URLs are\n * derived from the source files themselves.\n */\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { CLIENT_ASSET_URL_PREFIX } from \"./client-asset-url-prefix\";\n\n/** Stylesheet extensions Vite can serve directly. Mirrors the build's list. */\nconst STYLE_EXTENSIONS = [\".css\", \".scss\", \".sass\", \".less\", \".styl\"];\n\n/**\n * The stylesheets the ROOT document imports, as dev URLs.\n *\n * Dev has no manifest, so the source is the root file itself: whatever\n * `root.tsx` imports with a stylesheet extension is what the document needs.\n * That is deliberately narrow — it answers \"what CSS does this application\n * set up globally\", which is where `app.css` lives and where Tailwind is\n * wired, and it does NOT try to reproduce Vite's per-route CSS graph.\n *\n * The narrowness is the honest part: production splits CSS per chunk, dev\n * links the root's stylesheets on every page. A page whose own module imports\n * its own stylesheet still gets it in dev — Vite's client graph injects it as\n * before — it simply is not render-blocking the way the root's is. That is a\n * smaller gap than the flash this removes, and it is stated rather than\n * hidden.\n *\n * Specifiers are resolved against the root file and expressed relative to the\n * app root, because that is the shape Vite's dev server serves from.\n */\nexport function devStylesheetUrls(appRoot: string, appFile: string): string[] {\n let source: string;\n\n try {\n source = readFileSync(appFile, \"utf-8\");\n } catch {\n return [];\n }\n\n const urls: string[] = [];\n const pattern = /\\bimport\\s*[\"']([^\"']+)[\"']/g;\n\n let match = pattern.exec(source);\n\n while (match !== null) {\n const specifier = match[1];\n const lowered = specifier.toLowerCase();\n\n if (STYLE_EXTENSIONS.some((extension) => lowered.endsWith(extension))) {\n const absolute = path.resolve(path.dirname(appFile), specifier);\n const relative = path.relative(appRoot, absolute).split(path.sep).join(\"/\");\n\n // Outside the app root Vite would need an `/@fs/` URL and a widened\n // `fs.allow`; a stylesheet living there is unusual enough that guessing\n // is worse than leaving it to the client import.\n if (!relative.startsWith(\"..\")) {\n const url = `/${relative}${VITE_DIRECT_CSS_QUERY}`;\n\n if (!urls.includes(url)) urls.push(url);\n }\n }\n\n match = pattern.exec(source);\n }\n\n return urls;\n}\n\n/**\n * A stylesheet Vite serves in DEV must be requested with `?direct`.\n *\n * Without it Vite answers the same URL with `text/javascript` — its CSS-as-JS\n * module transform, meant for `import \"./app.css\"` — and a\n * `<link rel=\"stylesheet\">` pointing at a JavaScript response applies\n * NOTHING, silently. No console error, no network failure, just an unstyled\n * page. `?direct` is what makes Vite reply with real `text/css`.\n */\nexport const VITE_DIRECT_CSS_QUERY = \"?direct\";\n\ntype ManifestEntry = {\n css?: unknown;\n file?: unknown;\n};\n\n/**\n * Every stylesheet the client build emitted, as URLs the asset route serves.\n *\n * Vite records CSS against the CHUNK that imported it — an app whose\n * `root.tsx` imports `app.css` produces a `root.tsx` entry carrying\n * `css: [\"assets/root-<hash>.css\"]`, not a hydration entry carrying it. So\n * this collects across every entry rather than looking under one name, which\n * would silently find nothing the moment a stylesheet moved file.\n *\n * Duplicates are collapsed and order is preserved: two chunks importing the\n * same stylesheet must not emit two `<link>` tags.\n *\n * A missing or malformed manifest returns NOTHING rather than throwing. The\n * hydration resolver already fails loudly on exactly those conditions, from\n * exactly the same file, and it runs first — a second, worse error for the\n * same cause helps nobody.\n */\nexport function productionStylesheetUrls(clientDir: string): string[] {\n const manifestPath = path.join(clientDir, \".vite\", \"manifest.json\");\n\n let manifest: Record<string, ManifestEntry | undefined>;\n\n try {\n manifest = JSON.parse(readFileSync(manifestPath, \"utf-8\")) as Record<\n string,\n ManifestEntry | undefined\n >;\n } catch {\n return [];\n }\n\n if (typeof manifest !== \"object\" || manifest === null) return [];\n\n const urls: string[] = [];\n\n for (const entry of Object.values(manifest)) {\n if (entry === undefined || !Array.isArray(entry.css)) continue;\n\n for (const file of entry.css) {\n if (typeof file !== \"string\" || file === \"\") continue;\n\n // Built EXACTLY as the hydration entry's URL is built — `/${file}`, then\n // checked against the prefix — rather than reassembled from a basename.\n // The manifest already records `assets/root-<hash>.css`, and rebuilding\n // that path here would be a second expression of a convention\n // `client-asset-url-prefix.ts` owns.\n const url = `/${file}`;\n\n // A stylesheet outside the directory the asset route mounts would 404.\n // Dropped rather than emitted, because a dead <link> in <head> is a\n // silent styling failure — the exact thing this module exists to end.\n if (!url.startsWith(`${CLIENT_ASSET_URL_PREFIX}/`)) continue;\n\n if (!urls.includes(url)) urls.push(url);\n }\n }\n\n return urls;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmHA,SAAgB,yBAAyB,WAA6B;CACpE,MAAM,eAAe,KAAK,KAAK,WAAW,SAAS,eAAe;CAElE,IAAI;CAEJ,IAAI;EACF,WAAW,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;CAI3D,QAAQ;EACN,OAAO,CAAC;CACV;CAEA,IAAI,OAAO,aAAa,YAAY,aAAa,MAAM,OAAO,CAAC;CAE/D,MAAM,OAAiB,CAAC;CAExB,KAAK,MAAM,SAAS,OAAO,OAAO,QAAQ,GAAG;EAC3C,IAAI,UAAU,UAAa,CAAC,MAAM,QAAQ,MAAM,GAAG,GAAG;EAEtD,KAAK,MAAM,QAAQ,MAAM,KAAK;GAC5B,IAAI,OAAO,SAAS,YAAY,SAAS,IAAI;GAO7C,MAAM,MAAM,IAAI;GAKhB,IAAI,CAAC,IAAI,WAAW,aAA2B,EAAE,GAAG;GAEpD,IAAI,CAAC,KAAK,SAAS,GAAG,GAAG,KAAK,KAAK,GAAG;EACxC;CACF;CAEA,OAAO;AACT"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { WebBuildOptions } from "../build/contribution.mjs";
|
|
2
|
+
import { WebConnectorOptions } from "./web-connector.mjs";
|
|
3
|
+
import { Connector } from "@warlock.js/core";
|
|
4
|
+
|
|
5
|
+
//#region ../web/src/server/web-connector-factory.d.ts
|
|
6
|
+
type WebConnectorFactoryOptions = WebConnectorOptions & {
|
|
7
|
+
/**
|
|
8
|
+
* What web contributes to `warlock build`. Passed straight to
|
|
9
|
+
* {@link createWebBuildContribution}; JSON-serializable values only — no
|
|
10
|
+
* plugin or pipeline instances, so a config load never pulls Vite in.
|
|
11
|
+
*/
|
|
12
|
+
build?: WebBuildOptions;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Construct web's connector for `warlock.config.ts > connectors`.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* export default defineConfig({ connectors: [webConnector()] });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
declare function webConnector(options?: WebConnectorFactoryOptions): Connector;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { webConnector };
|
|
25
|
+
//# sourceMappingURL=web-connector-factory.d.mts.map
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { createWebBuildContribution } from "../build/contribution.mjs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { ConnectorLifecyclePhase } from "@warlock.js/core";
|
|
5
|
+
|
|
6
|
+
//#region ../web/src/server/web-connector-factory.ts
|
|
7
|
+
/**
|
|
8
|
+
* `webConnector()` — the ONE thing `warlock.config.ts` imports from
|
|
9
|
+
* `@warlock.js/web/connector`, and the only value the `./connector` barrel
|
|
10
|
+
* adds beyond the build/runtime seams.
|
|
11
|
+
*
|
|
12
|
+
* WHY THIS MODULE EXISTS AT ALL, rather than the barrel exporting
|
|
13
|
+
* `WebConnector` directly: `./web-connector.ts` imports `../vite`
|
|
14
|
+
* (`web-connector.ts:52` → `@babel/parser` + `magic-string`),
|
|
15
|
+
* `../../../core/src/router/router` (`:51`) and `./dev-server` (`:53`, which
|
|
16
|
+
* itself pulls core's http stack and `../vite`) at VALUE level. Re-exporting
|
|
17
|
+
* that class from `web/src/connector/index.ts` would drag every one of those
|
|
18
|
+
* into the static graph of every consuming app's config file — the exact
|
|
19
|
+
* config-load weight the `./connector` subpath was created to prevent.
|
|
20
|
+
*
|
|
21
|
+
* So the factory returns a LAZY DELEGATE: a `Connector` whose identity fields
|
|
22
|
+
* (`name`, `priority`, `lifecyclePhase`, `build`) are plain data available
|
|
23
|
+
* synchronously, and whose lifecycle methods `await import("./web-connector")`
|
|
24
|
+
* on first use. `warlock build` reads `build` off this object and never boots
|
|
25
|
+
* anything, so a build never loads Vite or React through
|
|
26
|
+
* here either. This is the third instance of a pattern the codebase already
|
|
27
|
+
* uses twice — `core/src/connectors/access-connector.ts:39` and
|
|
28
|
+
* `web/src/server/dev-cli.ts:61` — not a new one.
|
|
29
|
+
*
|
|
30
|
+
* KEEP THIS MODULE LIGHT. Its whole value-level static graph is `node:path`,
|
|
31
|
+
* `node:url`, `../../../core/src/connectors/types` (whose own two imports are
|
|
32
|
+
* both `import type` and therefore erased — `core/src/connectors/types.ts:1-2`)
|
|
33
|
+
* and `../build/contribution` (`node:fs` + `node:path` + type-only core).
|
|
34
|
+
* Everything else here is `import type`, which `verbatimModuleSyntax` erases.
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Boot/shutdown position relative to core's own connectors.
|
|
38
|
+
*
|
|
39
|
+
* `ConnectorPriority.HTTP` is `5` and `ConnectorPriority.STORAGE` is `6`
|
|
40
|
+
* (`core/src/connectors/types.ts:187-188`), and the manager sorts on a plain
|
|
41
|
+
* numeric compare (`core/src/connectors/connectors-manager.ts:46`) — so `5.5`
|
|
42
|
+
* is "immediately after http, before everything else".
|
|
43
|
+
*
|
|
44
|
+
* Defined HERE and re-exported by `./web-connector` rather than the other way
|
|
45
|
+
* round: the delegate must publish `priority` synchronously, and reading it
|
|
46
|
+
* from the heavy module would defeat the whole point of the delegate.
|
|
47
|
+
*/
|
|
48
|
+
const WEB_CONNECTOR_PRIORITY = 5.5;
|
|
49
|
+
/**
|
|
50
|
+
* The `@warlock.js/web` package root, derived once from THIS module's location
|
|
51
|
+
* and then passed EXPLICITLY to both halves.
|
|
52
|
+
*
|
|
53
|
+
* `web/src/server/web-connector-factory.ts` → `web/src/server` → `web/src` →
|
|
54
|
+
* `web`; published as `web/esm/server/web-connector-factory.js`, two levels up
|
|
55
|
+
* is the package root under both layouts — the same arithmetic
|
|
56
|
+
* `contribution.ts:136-140` documents.
|
|
57
|
+
*
|
|
58
|
+
* Deriving it here and handing it down means the build contribution never falls
|
|
59
|
+
* back to its own `import.meta.url` guess (`contribution.ts:129-141`): one
|
|
60
|
+
* derivation, one place to be wrong, and `assertWebPackageRoot` verifies it
|
|
61
|
+
* against `<root>/package.json`'s `name` either way.
|
|
62
|
+
*/
|
|
63
|
+
function deriveWebRoot() {
|
|
64
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Construct web's connector for `warlock.config.ts > connectors`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* export default defineConfig({ connectors: [webConnector()] });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
function webConnector(options = {}) {
|
|
75
|
+
const { build: buildOptions, ...connectorOptions } = options;
|
|
76
|
+
const webRoot = connectorOptions.webRoot ?? deriveWebRoot();
|
|
77
|
+
const build = createWebBuildContribution({
|
|
78
|
+
...buildOptions,
|
|
79
|
+
webRoot: buildOptions?.webRoot ?? webRoot
|
|
80
|
+
});
|
|
81
|
+
let instance;
|
|
82
|
+
/**
|
|
83
|
+
* Load the heavy half on first lifecycle call. `boot()` is always the first
|
|
84
|
+
* of these to run (`core/src/connectors/connectors-manager.ts:87-93`), so the
|
|
85
|
+
* import lands in a process that has already committed to serving pages.
|
|
86
|
+
*/
|
|
87
|
+
const load = async () => {
|
|
88
|
+
if (!instance) {
|
|
89
|
+
const { WebConnector: WebConnectorClass } = await import("./web-connector.mjs");
|
|
90
|
+
instance = new WebConnectorClass({
|
|
91
|
+
...connectorOptions,
|
|
92
|
+
webRoot
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return instance;
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
name: "web",
|
|
99
|
+
priority: WEB_CONNECTOR_PRIORITY,
|
|
100
|
+
lifecyclePhase: ConnectorLifecyclePhase.Late,
|
|
101
|
+
build,
|
|
102
|
+
isActive: () => instance?.isActive() ?? false,
|
|
103
|
+
boot: async () => {
|
|
104
|
+
await (await load()).boot();
|
|
105
|
+
},
|
|
106
|
+
start: async () => {
|
|
107
|
+
await (await load()).start();
|
|
108
|
+
},
|
|
109
|
+
restart: async () => {
|
|
110
|
+
await (await load()).restart();
|
|
111
|
+
},
|
|
112
|
+
shutdown: async () => {
|
|
113
|
+
await instance?.shutdown();
|
|
114
|
+
},
|
|
115
|
+
shouldRestart: () => false
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//#endregion
|
|
120
|
+
export { WEB_CONNECTOR_PRIORITY, webConnector };
|
|
121
|
+
//# sourceMappingURL=web-connector-factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-connector-factory.mjs","names":[],"sources":["../../../../../../../web/src/server/web-connector-factory.ts"],"sourcesContent":["/**\n * `webConnector()` — the ONE thing `warlock.config.ts` imports from\n * `@warlock.js/web/connector`, and the only value the `./connector` barrel\n * adds beyond the build/runtime seams.\n *\n * WHY THIS MODULE EXISTS AT ALL, rather than the barrel exporting\n * `WebConnector` directly: `./web-connector.ts` imports `../vite`\n * (`web-connector.ts:52` → `@babel/parser` + `magic-string`),\n * `../../../core/src/router/router` (`:51`) and `./dev-server` (`:53`, which\n * itself pulls core's http stack and `../vite`) at VALUE level. Re-exporting\n * that class from `web/src/connector/index.ts` would drag every one of those\n * into the static graph of every consuming app's config file — the exact\n * config-load weight the `./connector` subpath was created to prevent.\n *\n * So the factory returns a LAZY DELEGATE: a `Connector` whose identity fields\n * (`name`, `priority`, `lifecyclePhase`, `build`) are plain data available\n * synchronously, and whose lifecycle methods `await import(\"./web-connector\")`\n * on first use. `warlock build` reads `build` off this object and never boots\n * anything, so a build never loads Vite or React through\n * here either. This is the third instance of a pattern the codebase already\n * uses twice — `core/src/connectors/access-connector.ts:39` and\n * `web/src/server/dev-cli.ts:61` — not a new one.\n *\n * KEEP THIS MODULE LIGHT. Its whole value-level static graph is `node:path`,\n * `node:url`, `../../../core/src/connectors/types` (whose own two imports are\n * both `import type` and therefore erased — `core/src/connectors/types.ts:1-2`)\n * and `../build/contribution` (`node:fs` + `node:path` + type-only core).\n * Everything else here is `import type`, which `verbatimModuleSyntax` erases.\n */\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n type Connector,\n type ConnectorBuildContribution,\n ConnectorLifecyclePhase,\n type ConnectorName,\n} from \"@warlock.js/core\";\nimport { createWebBuildContribution, type WebBuildOptions } from \"../build/contribution\";\nimport type { WebConnector, WebConnectorOptions } from \"./web-connector\";\n\n/**\n * Boot/shutdown position relative to core's own connectors.\n *\n * `ConnectorPriority.HTTP` is `5` and `ConnectorPriority.STORAGE` is `6`\n * (`core/src/connectors/types.ts:187-188`), and the manager sorts on a plain\n * numeric compare (`core/src/connectors/connectors-manager.ts:46`) — so `5.5`\n * is \"immediately after http, before everything else\".\n *\n * Defined HERE and re-exported by `./web-connector` rather than the other way\n * round: the delegate must publish `priority` synchronously, and reading it\n * from the heavy module would defeat the whole point of the delegate.\n */\nexport const WEB_CONNECTOR_PRIORITY = 5.5;\n\nexport type WebConnectorFactoryOptions = WebConnectorOptions & {\n /**\n * What web contributes to `warlock build`. Passed straight to\n * {@link createWebBuildContribution}; JSON-serializable values only — no\n * plugin or pipeline instances, so a config load never pulls Vite in.\n */\n build?: WebBuildOptions;\n};\n\n/**\n * The `@warlock.js/web` package root, derived once from THIS module's location\n * and then passed EXPLICITLY to both halves.\n *\n * `web/src/server/web-connector-factory.ts` → `web/src/server` → `web/src` →\n * `web`; published as `web/esm/server/web-connector-factory.js`, two levels up\n * is the package root under both layouts — the same arithmetic\n * `contribution.ts:136-140` documents.\n *\n * Deriving it here and handing it down means the build contribution never falls\n * back to its own `import.meta.url` guess (`contribution.ts:129-141`): one\n * derivation, one place to be wrong, and `assertWebPackageRoot` verifies it\n * against `<root>/package.json`'s `name` either way.\n */\nfunction deriveWebRoot(): string {\n return path.resolve(path.dirname(fileURLToPath(import.meta.url)), \"..\", \"..\");\n}\n\n/**\n * Construct web's connector for `warlock.config.ts > connectors`.\n *\n * @example\n * ```ts\n * export default defineConfig({ connectors: [webConnector()] });\n * ```\n */\nexport function webConnector(options: WebConnectorFactoryOptions = {}): Connector {\n const { build: buildOptions, ...connectorOptions } = options;\n const webRoot = connectorOptions.webRoot ?? deriveWebRoot();\n\n const build: ConnectorBuildContribution = createWebBuildContribution({\n ...buildOptions,\n webRoot: buildOptions?.webRoot ?? webRoot,\n });\n\n let instance: WebConnector | undefined;\n\n /**\n * Load the heavy half on first lifecycle call. `boot()` is always the first\n * of these to run (`core/src/connectors/connectors-manager.ts:87-93`), so the\n * import lands in a process that has already committed to serving pages.\n */\n const load = async (): Promise<WebConnector> => {\n if (!instance) {\n const { WebConnector: WebConnectorClass } = await import(\"./web-connector\");\n\n instance = new WebConnectorClass({ ...connectorOptions, webRoot });\n }\n\n return instance;\n };\n\n return {\n name: \"web\" satisfies ConnectorName,\n priority: WEB_CONNECTOR_PRIORITY,\n lifecyclePhase: ConnectorLifecyclePhase.Late,\n build,\n\n // Never loads the heavy half: a connector that was never booted is not\n // active, and answering that must not cost a Vite import.\n isActive: () => instance?.isActive() ?? false,\n\n boot: async () => {\n await (await load()).boot();\n },\n start: async () => {\n await (await load()).start();\n },\n restart: async () => {\n await (await load()).restart();\n },\n\n // Both of these are asked of every registered connector, including ones\n // that never booted — so neither may force the import.\n shutdown: async () => {\n await instance?.shutdown();\n },\n shouldRestart: () => false,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAa,yBAAyB;;;;;;;;;;;;;;;AAyBtC,SAAS,gBAAwB;CAC/B,OAAO,KAAK,QAAQ,KAAK,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC,GAAG,MAAM,IAAI;AAC9E;;;;;;;;;AAUA,SAAgB,aAAa,UAAsC,CAAC,GAAc;CAChF,MAAM,EAAE,OAAO,cAAc,GAAG,qBAAqB;CACrD,MAAM,UAAU,iBAAiB,WAAW,cAAc;CAE1D,MAAM,QAAoC,2BAA2B;EACnE,GAAG;EACH,SAAS,cAAc,WAAW;CACpC,CAAC;CAED,IAAI;;;;;;CAOJ,MAAM,OAAO,YAAmC;EAC9C,IAAI,CAAC,UAAU;GACb,MAAM,EAAE,cAAc,sBAAsB,MAAM,OAAO;GAEzD,WAAW,IAAI,kBAAkB;IAAE,GAAG;IAAkB;GAAQ,CAAC;EACnE;EAEA,OAAO;CACT;CAEA,OAAO;EACL,MAAM;EACN,UAAU;EACV,gBAAgB,wBAAwB;EACxC;EAIA,gBAAgB,UAAU,SAAS,KAAK;EAExC,MAAM,YAAY;GAChB,OAAO,MAAM,KAAK,EAAC,CAAE,KAAK;EAC5B;EACA,OAAO,YAAY;GACjB,OAAO,MAAM,KAAK,EAAC,CAAE,MAAM;EAC7B;EACA,SAAS,YAAY;GACnB,OAAO,MAAM,KAAK,EAAC,CAAE,QAAQ;EAC/B;EAIA,UAAU,YAAY;GACpB,MAAM,UAAU,SAAS;EAC3B;EACA,qBAAqB;CACvB;AACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BaseConnector, ConnectorLifecyclePhase } from "@warlock.js/core";
|
|
2
|
+
import { Alias, PluginOption } from "vite";
|
|
3
|
+
|
|
4
|
+
//#region ../web/src/server/web-connector.d.ts
|
|
5
|
+
type WebConnectorOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Vite's `root` — the application directory that owns `src/`, `package.json`
|
|
8
|
+
* and `tsconfig.json`. Rooting Vite at the APP (not at the `web` package) is
|
|
9
|
+
* what makes the app's own bare specifiers and dependency-optimizer scan
|
|
10
|
+
* resolve correctly. Defaults to `process.cwd()`, which is where `warlock dev`
|
|
11
|
+
* already runs.
|
|
12
|
+
*/
|
|
13
|
+
appRoot?: string; /** `<appRoot>/src` by default. Pages are `<appSrcRoot>/app/**\/*.page.tsx`. */
|
|
14
|
+
appSrcRoot?: string; /** The single global app-root file. `<appSrcRoot>/web/root.tsx` by default. */
|
|
15
|
+
appFile?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Root of the `@warlock.js/web` package, used to locate the hydration client
|
|
18
|
+
* entry. Derived from this module's own location by default — a caller only
|
|
19
|
+
* sets it when the package is not laid out normally.
|
|
20
|
+
*/
|
|
21
|
+
webRoot?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Extra `resolve.alias` entries, prepended to the app-convention aliases
|
|
24
|
+
* (`web/*` → `src/web`, `app/*` → `src/app`) so a caller can win a conflict.
|
|
25
|
+
* A normal application needs none of these; a monorepo checkout with unbuilt
|
|
26
|
+
* workspace packages does.
|
|
27
|
+
*/
|
|
28
|
+
resolveAlias?: Alias[]; /** Extra `ssr.external` entries, appended to {@link CORE_OPTIONAL_PEERS}. */
|
|
29
|
+
ssrExternal?: string[]; /** Extra Vite plugins, appended after the client-boundary gates. */
|
|
30
|
+
plugins?: PluginOption[];
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { WebConnectorOptions };
|
|
34
|
+
//# sourceMappingURL=web-connector.d.mts.map
|