toiljs 0.0.116 → 0.0.118
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 +14 -0
- package/README.md +16 -7
- package/build/backend/.tsbuildinfo +1 -1
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/index.js +2375 -258
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/auth.d.ts +3 -0
- package/build/client/auth.js +19 -10
- package/build/client/dev/devtools.js +1 -1
- package/build/client/dev/error-overlay.js +1 -1
- package/build/client/index.d.ts +1 -1
- package/build/client/index.js +1 -1
- package/build/client/navigation/navigation.js +28 -3
- package/build/client/routing/Router.js +5 -2
- package/build/client/routing/mount.js +1 -1
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/auth-emails.js +7 -3
- package/build/compiler/emails.js +1 -1
- package/build/compiler/index.d.ts +1 -0
- package/build/compiler/index.js +26 -5
- package/build/compiler/pages.js +2 -3
- package/build/compiler/prerender.d.ts +3 -8
- package/build/compiler/prerender.js +88 -127
- package/build/compiler/ssg.js +3 -4
- package/build/compiler/template-build.js +3 -4
- package/build/compiler/toil-docs.generated.js +8 -7
- package/build/compiler/vite.js +4 -6
- package/build/devserver/.tsbuildinfo +1 -1
- package/build/devserver/db/database.js +7 -3
- package/build/devserver/db/types.js +1 -1
- package/build/devserver/production.js +4 -3
- package/build/devserver/runtime/crypto.d.ts +1 -1
- package/build/io/.tsbuildinfo +1 -1
- package/build/logger/.tsbuildinfo +1 -1
- package/build/shared/.tsbuildinfo +1 -1
- package/examples/basic/client/routes/analytics.tsx +7 -5
- package/examples/basic/client/routes/pq.tsx +2 -1
- package/examples/basic/server/tsconfig.json +1 -3
- package/package.json +45 -44
- package/presets/no-uint8array-tostring.js +120 -153
- package/presets/oxlint.d.ts +5 -0
- package/presets/oxlint.js +224 -0
- package/server/auth/AuthController.ts +53 -14
- package/server/auth/FactorSettings.ts +41 -0
- package/server/auth/SessionEpochs.ts +58 -0
- package/server/auth/SessionRevocations.ts +13 -0
- package/server/globals/auth.ts +27 -2
- package/server/runtime/tsconfig.json +1 -3
- package/tsconfig.json +2 -11
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
- package/.github/ISSUE_TEMPLATE/config.yml +0 -8
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -43
- package/.github/changelog-config.json +0 -45
- package/.github/dependabot.yml +0 -27
- package/.github/workflows/ci.yml +0 -222
- package/.vscode/settings.json +0 -10
- package/docs/README.md +0 -107
- package/docs/auth/README.md +0 -104
- package/docs/auth/configuration.md +0 -105
- package/docs/auth/emails.md +0 -92
- package/docs/auth/extending.md +0 -202
- package/docs/auth/how-it-works.md +0 -138
- package/docs/auth/usage.md +0 -188
- package/docs/backend/README.md +0 -143
- package/docs/backend/data.md +0 -351
- package/docs/backend/rest.md +0 -402
- package/docs/backend/rpc.md +0 -226
- package/docs/background/README.md +0 -114
- package/docs/background/daemons.md +0 -276
- package/docs/background/derive.md +0 -179
- package/docs/cli/README.md +0 -379
- package/docs/concepts/ai-guide.md +0 -132
- package/docs/concepts/config.md +0 -416
- package/docs/concepts/decorators.md +0 -127
- package/docs/concepts/security.md +0 -108
- package/docs/concepts/tiers.md +0 -166
- package/docs/concepts/types.md +0 -216
- package/docs/database/README.md +0 -143
- package/docs/database/capacity.md +0 -350
- package/docs/database/counters.md +0 -174
- package/docs/database/documents.md +0 -277
- package/docs/database/events.md +0 -307
- package/docs/database/membership.md +0 -246
- package/docs/database/setup.md +0 -155
- package/docs/database/unique.md +0 -216
- package/docs/database/views.md +0 -246
- package/docs/frontend/README.md +0 -104
- package/docs/frontend/components.md +0 -286
- package/docs/frontend/data-fetching.md +0 -260
- package/docs/frontend/images.md +0 -148
- package/docs/frontend/metadata.md +0 -344
- package/docs/frontend/navigation.md +0 -296
- package/docs/frontend/rendering.md +0 -236
- package/docs/frontend/routing.md +0 -346
- package/docs/frontend/scripts.md +0 -118
- package/docs/frontend/search.md +0 -191
- package/docs/frontend/styling.md +0 -147
- package/docs/frontend/toil-global.md +0 -216
- package/docs/getting-started/README.md +0 -81
- package/docs/getting-started/create-project.md +0 -131
- package/docs/getting-started/deploy.md +0 -101
- package/docs/getting-started/first-app.md +0 -215
- package/docs/getting-started/installation.md +0 -124
- package/docs/getting-started/migrating.md +0 -125
- package/docs/getting-started/project-structure.md +0 -163
- package/docs/introduction/README.md +0 -66
- package/docs/introduction/design-principles.md +0 -81
- package/docs/introduction/distributed.md +0 -91
- package/docs/introduction/how-it-works.md +0 -121
- package/docs/introduction/hyperscale.md +0 -70
- package/docs/introduction/modern-stack.md +0 -85
- package/docs/introduction/vs-other-frameworks.md +0 -64
- package/docs/introduction/why-toil.md +0 -99
- package/docs/llms.txt +0 -95
- package/docs/realtime/README.md +0 -102
- package/docs/realtime/channels.md +0 -211
- package/docs/realtime/streams.md +0 -369
- package/docs/services/README.md +0 -60
- package/docs/services/analytics.md +0 -279
- package/docs/services/caching.md +0 -175
- package/docs/services/cookies.md +0 -235
- package/docs/services/crypto.md +0 -209
- package/docs/services/email.md +0 -289
- package/docs/services/environment.md +0 -141
- package/docs/services/ratelimit.md +0 -174
- package/docs/services/time.md +0 -85
- package/eslint.config.js +0 -57
- package/examples/basic/client/routes/docs/[...slug].tsx +0 -12
- package/presets/eslint.js +0 -88
- package/src/backend/index.ts +0 -204
- package/src/cli/configure.ts +0 -363
- package/src/cli/create.ts +0 -924
- package/src/cli/db.ts +0 -158
- package/src/cli/diagnostics.ts +0 -665
- package/src/cli/doctor.ts +0 -982
- package/src/cli/features.ts +0 -170
- package/src/cli/index.ts +0 -326
- package/src/cli/notify.ts +0 -120
- package/src/cli/proc.ts +0 -56
- package/src/cli/ui.ts +0 -169
- package/src/cli/update.ts +0 -248
- package/src/cli/updates.ts +0 -92
- package/src/cli/validate.ts +0 -31
- package/src/cli/version-check.ts +0 -125
- package/src/client/auth.ts +0 -869
- package/src/client/channel/channel.ts +0 -146
- package/src/client/components/Form.tsx +0 -65
- package/src/client/components/Image.tsx +0 -160
- package/src/client/components/Script.tsx +0 -113
- package/src/client/components/Slot.tsx +0 -21
- package/src/client/dev/devtools.tsx +0 -1089
- package/src/client/dev/error-overlay.tsx +0 -225
- package/src/client/errors.ts +0 -11
- package/src/client/head/head.ts +0 -182
- package/src/client/head/metadata.ts +0 -110
- package/src/client/index.ts +0 -130
- package/src/client/navigation/Link.tsx +0 -108
- package/src/client/navigation/NavLink.tsx +0 -86
- package/src/client/navigation/navigation.ts +0 -235
- package/src/client/navigation/prefetch.ts +0 -169
- package/src/client/navigation/scroll.ts +0 -53
- package/src/client/routing/Router.tsx +0 -216
- package/src/client/routing/action.ts +0 -122
- package/src/client/routing/error-boundary.tsx +0 -43
- package/src/client/routing/hooks.ts +0 -140
- package/src/client/routing/lazy.ts +0 -77
- package/src/client/routing/loader.ts +0 -381
- package/src/client/routing/match.ts +0 -47
- package/src/client/routing/mount.tsx +0 -90
- package/src/client/routing/params-context.ts +0 -10
- package/src/client/routing/slot-context.ts +0 -7
- package/src/client/rpc.ts +0 -97
- package/src/client/search/search.ts +0 -189
- package/src/client/search/use-page-search.ts +0 -73
- package/src/client/ssr/markers.tsx +0 -172
- package/src/client/stream/client.ts +0 -237
- package/src/client/types.ts +0 -73
- package/src/compiler/auth-emails.ts +0 -312
- package/src/compiler/config.ts +0 -369
- package/src/compiler/docs.ts +0 -127
- package/src/compiler/email-preview.ts +0 -314
- package/src/compiler/emails.ts +0 -404
- package/src/compiler/fonts.ts +0 -89
- package/src/compiler/generate.ts +0 -471
- package/src/compiler/image-blur.ts +0 -42
- package/src/compiler/image-report.ts +0 -88
- package/src/compiler/index.ts +0 -1362
- package/src/compiler/pages.ts +0 -49
- package/src/compiler/plugin.ts +0 -391
- package/src/compiler/prerender.ts +0 -263
- package/src/compiler/routes.ts +0 -170
- package/src/compiler/seo.ts +0 -415
- package/src/compiler/sri.ts +0 -144
- package/src/compiler/ssg.ts +0 -177
- package/src/compiler/ssr-codegen.ts +0 -85
- package/src/compiler/template-build.ts +0 -676
- package/src/compiler/template.ts +0 -262
- package/src/compiler/toil-docs.generated.ts +0 -77
- package/src/compiler/vite.ts +0 -245
- package/src/devserver/analytics/index.ts +0 -317
- package/src/devserver/config/dotenv.ts +0 -102
- package/src/devserver/config/env.ts +0 -30
- package/src/devserver/config/ratelimit.ts +0 -123
- package/src/devserver/daemon/catalog.ts +0 -120
- package/src/devserver/daemon/cron.ts +0 -87
- package/src/devserver/daemon/host.ts +0 -134
- package/src/devserver/daemon/index.ts +0 -369
- package/src/devserver/daemon/runtime.ts +0 -48
- package/src/devserver/db/catalog.ts +0 -109
- package/src/devserver/db/database.ts +0 -1834
- package/src/devserver/db/derives.ts +0 -121
- package/src/devserver/db/index.ts +0 -20
- package/src/devserver/db/routeKinds.ts +0 -191
- package/src/devserver/db/types.ts +0 -168
- package/src/devserver/email/caps.ts +0 -0
- package/src/devserver/email/config.ts +0 -141
- package/src/devserver/email/console.ts +0 -348
- package/src/devserver/email/index.ts +0 -155
- package/src/devserver/email/providers.ts +0 -131
- package/src/devserver/email/status.ts +0 -23
- package/src/devserver/email/validate.ts +0 -37
- package/src/devserver/email/wire.ts +0 -55
- package/src/devserver/http/cache.ts +0 -0
- package/src/devserver/http/envelope.ts +0 -157
- package/src/devserver/http/proxy.ts +0 -172
- package/src/devserver/http/runtime.ts +0 -387
- package/src/devserver/index.ts +0 -43
- package/src/devserver/production-ipc.ts +0 -63
- package/src/devserver/production-worker.ts +0 -83
- package/src/devserver/production.ts +0 -718
- package/src/devserver/runtime/crypto.ts +0 -587
- package/src/devserver/runtime/host.ts +0 -427
- package/src/devserver/runtime/module.ts +0 -442
- package/src/devserver/server.ts +0 -251
- package/src/devserver/ssr.ts +0 -208
- package/src/devserver/stream/catalog.ts +0 -106
- package/src/devserver/stream/host.ts +0 -42
- package/src/devserver/stream/index.ts +0 -301
- package/src/devserver/stream/manager.ts +0 -167
- package/src/devserver/stream/router.ts +0 -101
- package/src/devserver/stream/wire.ts +0 -58
- package/src/devserver/stream/ws.ts +0 -78
- package/src/devserver/wasm/sections.ts +0 -59
- package/src/devserver/wasm/surface.ts +0 -115
- package/src/io/FastMap.ts +0 -151
- package/src/io/FastSet.ts +0 -113
- package/src/io/codec.ts +0 -362
- package/src/io/index.ts +0 -10
- package/src/io/lengths.ts +0 -14
- package/src/io/types.ts +0 -19
- package/src/logger/index.ts +0 -22
- package/src/shared/index.ts +0 -46
- package/test/analytics-dev.test.ts +0 -113
- package/test/assembly/aspect-shim.ts +0 -33
- package/test/assembly/cookie.spec.ts +0 -303
- package/test/assembly/example.spec.ts +0 -22
- package/test/assembly/ssr.spec.ts +0 -95
- package/test/assembly.test.ts +0 -59
- package/test/auth-emails.test.ts +0 -118
- package/test/built-ssr.test.ts +0 -148
- package/test/channel.test.ts +0 -21
- package/test/config-host-port.test.ts +0 -59
- package/test/configure.test.ts +0 -94
- package/test/daemon-build.test.ts +0 -278
- package/test/daemon-catalog.test.ts +0 -349
- package/test/daemon-emulation.test.ts +0 -256
- package/test/db.test.ts +0 -0
- package/test/devserver-database.test.ts +0 -1102
- package/test/devserver-email.test.ts +0 -306
- package/test/devserver-pqauth.test.ts +0 -93
- package/test/devserver-secrets.test.ts +0 -63
- package/test/devserver.test.ts +0 -259
- package/test/doctor.test.ts +0 -298
- package/test/dom/Image.test.tsx +0 -144
- package/test/dom/Link.test.tsx +0 -67
- package/test/dom/NavLink.test.tsx +0 -37
- package/test/dom/Script.test.tsx +0 -48
- package/test/dom/action.test.tsx +0 -146
- package/test/dom/error-overlay.test.tsx +0 -44
- package/test/dom/loader.test.tsx +0 -121
- package/test/dom/navigation.test.ts +0 -59
- package/test/dom/revalidate.test.tsx +0 -38
- package/test/dom/route-head.test.tsx +0 -56
- package/test/dom/router-loading.test.tsx +0 -44
- package/test/dom/scroll.test.ts +0 -56
- package/test/dom/slot.test.tsx +0 -131
- package/test/dom/use-metadata.test.tsx +0 -58
- package/test/dom/view-transitions.test.tsx +0 -53
- package/test/dynamic-routing.test.ts +0 -132
- package/test/email-console.test.ts +0 -86
- package/test/email-preview.test.ts +0 -73
- package/test/emails.test.ts +0 -58
- package/test/errors.test.ts +0 -21
- package/test/example-guestbook.test.ts +0 -123
- package/test/features.test.ts +0 -149
- package/test/fixtures/bignum-wire/spec.ts +0 -25
- package/test/fixtures/daemon-app.ts +0 -65
- package/test/fixtures/stream-echo.ts +0 -26
- package/test/fixtures/stream-gate.ts +0 -28
- package/test/fixtures/stream-trap.ts +0 -18
- package/test/fixtures/stream-typed.ts +0 -41
- package/test/fonts.test.ts +0 -28
- package/test/global-setup.ts +0 -17
- package/test/head.test.ts +0 -42
- package/test/image-blur.test.ts +0 -50
- package/test/io.test.ts +0 -117
- package/test/metadata.test.ts +0 -40
- package/test/navlink.test.ts +0 -28
- package/test/pages.test.ts +0 -105
- package/test/placeholder.test.ts +0 -9
- package/test/pqauth-e2e.test.ts +0 -216
- package/test/pqauth-email.test.ts +0 -801
- package/test/prerender.test.ts +0 -116
- package/test/prettier-plugin.test.ts +0 -46
- package/test/routes.test.ts +0 -76
- package/test/rpc-bignum-wire.test.ts +0 -164
- package/test/rpc-dispatch.test.ts +0 -132
- package/test/rpc-kinds.test.ts +0 -18
- package/test/rpc.test.ts +0 -66
- package/test/search.test.ts +0 -114
- package/test/seo.test.ts +0 -175
- package/test/slot-layouts.test.ts +0 -69
- package/test/sri.test.ts +0 -129
- package/test/ssg.test.ts +0 -36
- package/test/ssr-hydration.test.tsx +0 -122
- package/test/ssr-render.test.ts +0 -197
- package/test/ssr-template.test.tsx +0 -482
- package/test/stream-emulation.test.ts +0 -479
- package/test/ui.test.ts +0 -40
- package/test/update.test.ts +0 -58
- package/test/validate.test.ts +0 -42
- package/test/version-check.test.ts +0 -130
- package/tests/data-parity/generated-parity.ts +0 -99
- package/tests/data-parity/parity.ts +0 -80
- package/tests/data-parity/spec.ts +0 -46
package/build/compiler/index.js
CHANGED
|
@@ -79,7 +79,7 @@ function serverEntryFiles(root) {
|
|
|
79
79
|
return [...result].sort();
|
|
80
80
|
}
|
|
81
81
|
function authEntryFiles(root, appHasUser) {
|
|
82
|
-
const names = appHasUser ? ['AuthController.ts'] : ['AuthUser.ts', 'AuthController.ts'];
|
|
82
|
+
const names = [...(appHasUser ? ['AuthController.ts'] : ['AuthUser.ts', 'AuthController.ts']), 'SessionRevocations.ts', 'SessionEpochs.ts', 'FactorSettings.ts'];
|
|
83
83
|
const primary = names.map((n) => path.posix.join('node_modules/toiljs/server/auth', n));
|
|
84
84
|
if (primary.every((rel) => fs.existsSync(path.join(root, rel))))
|
|
85
85
|
return primary;
|
|
@@ -297,6 +297,8 @@ export function assertNoStreamInRequestTier(root, split) {
|
|
|
297
297
|
const queue = [...split.request];
|
|
298
298
|
while (queue.length > 0) {
|
|
299
299
|
const rel = queue.pop();
|
|
300
|
+
if (rel === undefined)
|
|
301
|
+
break;
|
|
300
302
|
if (seen.has(rel))
|
|
301
303
|
continue;
|
|
302
304
|
seen.add(rel);
|
|
@@ -330,7 +332,7 @@ export function assertNoStreamInRequestTier(root, split) {
|
|
|
330
332
|
'\nRemove the import, or move the code into a *.stream.ts module.');
|
|
331
333
|
}
|
|
332
334
|
}
|
|
333
|
-
function runToilscriptPass(root, binJs, files, opts) {
|
|
335
|
+
async function runToilscriptPass(root, binJs, files, opts) {
|
|
334
336
|
const args = [binJs, ...files, '--target', 'release'];
|
|
335
337
|
if (opts.mode !== null)
|
|
336
338
|
args.push('--targetMode', opts.mode);
|
|
@@ -347,13 +349,25 @@ function runToilscriptPass(root, binJs, files, opts) {
|
|
|
347
349
|
args.push('--lib', AUTH_EMAILS_LIB_SUBDIR);
|
|
348
350
|
args.push('--noConfigEntries');
|
|
349
351
|
args.push('--disableWarning', '235');
|
|
350
|
-
|
|
352
|
+
await new Promise((resolve, reject) => {
|
|
351
353
|
const child = spawn(process.execPath, args, { cwd: root, stdio: 'inherit' });
|
|
352
354
|
child.on('error', reject);
|
|
353
355
|
child.on('close', (code) => code === 0
|
|
354
356
|
? resolve()
|
|
355
357
|
: reject(new Error(`toilscript ${opts.mode ?? 'release'} build failed (exit ${String(code)})`)));
|
|
356
358
|
});
|
|
359
|
+
if (opts.withRpc) {
|
|
360
|
+
const generated = path.join(root, 'shared/server.ts');
|
|
361
|
+
if (fs.existsSync(generated)) {
|
|
362
|
+
const source = fs.readFileSync(generated, 'utf8');
|
|
363
|
+
const updated = migrateGeneratedRpcClient(source);
|
|
364
|
+
if (source !== updated)
|
|
365
|
+
fs.writeFileSync(generated, updated);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
export function migrateGeneratedRpcClient(source) {
|
|
370
|
+
return source.replace(/(async function __toilRpcCall\(__id: number, __body: )Uint8Array(?=\))/, '$1Uint8Array<ArrayBuffer>');
|
|
357
371
|
}
|
|
358
372
|
function watchServer(cfg, watcher) {
|
|
359
373
|
const root = cfg.root;
|
|
@@ -722,7 +736,11 @@ function lebU(buf, pos) {
|
|
|
722
736
|
return [result >>> 0, p];
|
|
723
737
|
}
|
|
724
738
|
function customSectionBytes(wasm, want) {
|
|
725
|
-
if (wasm.length < 8 ||
|
|
739
|
+
if (wasm.length < 8 ||
|
|
740
|
+
wasm[0] !== 0x00 ||
|
|
741
|
+
wasm[1] !== 0x61 ||
|
|
742
|
+
wasm[2] !== 0x73 ||
|
|
743
|
+
wasm[3] !== 0x6d)
|
|
726
744
|
return null;
|
|
727
745
|
let pos = 8;
|
|
728
746
|
try {
|
|
@@ -853,7 +871,10 @@ function emitStreamClientSurface(root, streamWasmPath, streamFiles) {
|
|
|
853
871
|
if (catalog.length === 0)
|
|
854
872
|
return;
|
|
855
873
|
const classByRoute = new Map(scanStreamSource(root, streamFiles).map((s) => [s.route, s.className]));
|
|
856
|
-
const streams = catalog.map((c) => ({
|
|
874
|
+
const streams = catalog.map((c) => ({
|
|
875
|
+
key: classByRoute.get(c.route) ?? c.name,
|
|
876
|
+
route: c.route,
|
|
877
|
+
}));
|
|
857
878
|
const rpcModule = path.join(root, 'shared', 'server.ts');
|
|
858
879
|
let existing = '';
|
|
859
880
|
try {
|
package/build/compiler/pages.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { extractStaticExports
|
|
1
|
+
import { extractStaticExports } from './prerender.js';
|
|
2
2
|
function isDynamic(pattern) {
|
|
3
3
|
return /[:*]/.test(pattern);
|
|
4
4
|
}
|
|
5
5
|
export function buildPageIndex(root, routes) {
|
|
6
|
-
const ts = loadTypeScriptSync(root);
|
|
7
6
|
const seen = new Set();
|
|
8
7
|
const pages = [];
|
|
9
8
|
for (const route of routes) {
|
|
@@ -12,7 +11,7 @@ export function buildPageIndex(root, routes) {
|
|
|
12
11
|
if (seen.has(route.pattern))
|
|
13
12
|
continue;
|
|
14
13
|
seen.add(route.pattern);
|
|
15
|
-
const exports =
|
|
14
|
+
const exports = extractStaticExports(route.file, ['metadata', 'searchHints']);
|
|
16
15
|
const metadata = { ...exports.metadata, ...exports.searchHints };
|
|
17
16
|
pages.push({ path: route.pattern, dynamic: isDynamic(route.pattern), metadata });
|
|
18
17
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import type * as TS from 'typescript';
|
|
2
1
|
import type { Plugin } from 'vite';
|
|
3
2
|
import { type ResolvedToilConfig } from './config.js';
|
|
4
|
-
|
|
5
|
-
export declare function
|
|
6
|
-
export declare function
|
|
7
|
-
export declare function extractStaticExports(ts: Ts, filePath: string, names: readonly string[]): Record<string, Record<string, unknown>>;
|
|
8
|
-
export declare function extractStaticMetadata(ts: Ts, filePath: string): Record<string, unknown> | null;
|
|
9
|
-
export declare function exportsTrue(ts: Ts, filePath: string, name: string): boolean;
|
|
3
|
+
export declare function extractStaticExports(filePath: string, names: readonly string[]): Record<string, Record<string, unknown>>;
|
|
4
|
+
export declare function extractStaticMetadata(filePath: string): Record<string, unknown> | null;
|
|
5
|
+
export declare function exportsTrue(filePath: string, name: string): boolean;
|
|
10
6
|
export declare function prerenderPlugin(cfg: ResolvedToilConfig): Plugin;
|
|
11
|
-
export {};
|
|
@@ -1,101 +1,73 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';
|
|
2
1
|
import fs from 'node:fs';
|
|
3
2
|
import path from 'node:path';
|
|
4
|
-
import {
|
|
3
|
+
import { parseSync } from 'oxc-parser';
|
|
5
4
|
import { patternToBracketFile, scanRoutes, staticSectionPattern } from './routes.js';
|
|
6
5
|
import { injectSeoHtml, routeSeo } from './seo.js';
|
|
7
|
-
function isCompilerApi(mod) {
|
|
8
|
-
const ts = mod;
|
|
9
|
-
return (typeof ts?.createSourceFile === 'function' &&
|
|
10
|
-
typeof ts.isVariableStatement === 'function' &&
|
|
11
|
-
typeof ts.ScriptTarget === 'object' &&
|
|
12
|
-
typeof ts.ScriptKind === 'object' &&
|
|
13
|
-
typeof ts.SyntaxKind === 'object');
|
|
14
|
-
}
|
|
15
|
-
let warnedUnusable = false;
|
|
16
|
-
function warnUnusableTypeScript(mod) {
|
|
17
|
-
if (warnedUnusable)
|
|
18
|
-
return;
|
|
19
|
-
warnedUnusable = true;
|
|
20
|
-
const version = mod?.version;
|
|
21
|
-
process.stderr.write(` toil: typescript${version ? `@${version}` : ''} does not expose the compiler API ` +
|
|
22
|
-
`(TypeScript 7 moved it to 'typescript/unstable/*').\n` +
|
|
23
|
-
` toil: route metadata will NOT be baked into the built HTML. Install typescript ^6 to restore it.\n`);
|
|
24
|
-
}
|
|
25
|
-
export async function loadTypeScript(root) {
|
|
26
|
-
let mod;
|
|
27
|
-
try {
|
|
28
|
-
const resolved = createRequire(path.join(root, 'package.json')).resolve('typescript');
|
|
29
|
-
const ns = (await import(pathToFileURL(resolved).href));
|
|
30
|
-
mod = ns.default ?? ns;
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
if (isCompilerApi(mod))
|
|
36
|
-
return mod;
|
|
37
|
-
warnUnusableTypeScript(mod);
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
export function loadTypeScriptSync(root) {
|
|
41
|
-
let mod;
|
|
42
|
-
try {
|
|
43
|
-
mod = createRequire(path.join(root, 'package.json'))('typescript');
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
const ts = mod?.default ?? mod;
|
|
49
|
-
if (isCompilerApi(ts))
|
|
50
|
-
return ts;
|
|
51
|
-
warnUnusableTypeScript(ts);
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
6
|
const UNRESOLVED = Symbol('unresolved');
|
|
55
|
-
function evalNode(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (value === UNRESOLVED)
|
|
7
|
+
function evalNode(node) {
|
|
8
|
+
switch (node.type) {
|
|
9
|
+
case 'Literal':
|
|
10
|
+
return 'regex' in node || 'bigint' in node ? UNRESOLVED : node.value;
|
|
11
|
+
case 'TemplateLiteral':
|
|
12
|
+
return node.expressions.length === 0 ? node.quasis[0].value.cooked : UNRESOLVED;
|
|
13
|
+
case 'TSAsExpression':
|
|
14
|
+
case 'TSSatisfiesExpression':
|
|
15
|
+
case 'TSNonNullExpression':
|
|
16
|
+
case 'TSTypeAssertion':
|
|
17
|
+
case 'ParenthesizedExpression':
|
|
18
|
+
return evalNode(node.expression);
|
|
19
|
+
case 'UnaryExpression': {
|
|
20
|
+
const value = evalNode(node.argument);
|
|
21
|
+
if (typeof value !== 'number')
|
|
71
22
|
return UNRESOLVED;
|
|
72
|
-
|
|
23
|
+
return node.operator === '-' ? -value : node.operator === '+' ? value : UNRESOLVED;
|
|
73
24
|
}
|
|
74
|
-
|
|
25
|
+
case 'ArrayExpression': {
|
|
26
|
+
const values = [];
|
|
27
|
+
for (const element of node.elements) {
|
|
28
|
+
if (!element || element.type === 'SpreadElement')
|
|
29
|
+
return UNRESOLVED;
|
|
30
|
+
const value = evalNode(element);
|
|
31
|
+
if (value === UNRESOLVED)
|
|
32
|
+
return UNRESOLVED;
|
|
33
|
+
values.push(value);
|
|
34
|
+
}
|
|
35
|
+
return values;
|
|
36
|
+
}
|
|
37
|
+
case 'ObjectExpression':
|
|
38
|
+
return evalObject(node);
|
|
39
|
+
default:
|
|
40
|
+
return UNRESOLVED;
|
|
75
41
|
}
|
|
76
|
-
if (ts.isObjectLiteralExpression(node))
|
|
77
|
-
return evalObject(ts, node);
|
|
78
|
-
return UNRESOLVED;
|
|
79
42
|
}
|
|
80
|
-
function evalObject(
|
|
81
|
-
const
|
|
82
|
-
for (const
|
|
83
|
-
if (
|
|
43
|
+
function evalObject(node) {
|
|
44
|
+
const result = {};
|
|
45
|
+
for (const property of node.properties) {
|
|
46
|
+
if (property.type !== 'Property' ||
|
|
47
|
+
property.computed ||
|
|
48
|
+
property.method ||
|
|
49
|
+
property.kind !== 'init')
|
|
84
50
|
continue;
|
|
85
|
-
const key =
|
|
86
|
-
?
|
|
87
|
-
:
|
|
88
|
-
?
|
|
51
|
+
const key = property.key.type === 'Identifier'
|
|
52
|
+
? property.key.name
|
|
53
|
+
: property.key.type === 'Literal' && typeof property.key.value === 'string'
|
|
54
|
+
? property.key.value
|
|
89
55
|
: null;
|
|
90
56
|
if (key === null)
|
|
91
57
|
continue;
|
|
92
|
-
const value = evalNode(
|
|
93
|
-
if (value !== UNRESOLVED)
|
|
94
|
-
|
|
58
|
+
const value = evalNode(property.value);
|
|
59
|
+
if (value !== UNRESOLVED) {
|
|
60
|
+
Object.defineProperty(result, key, {
|
|
61
|
+
value,
|
|
62
|
+
enumerable: true,
|
|
63
|
+
configurable: true,
|
|
64
|
+
writable: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
95
67
|
}
|
|
96
|
-
return
|
|
68
|
+
return result;
|
|
97
69
|
}
|
|
98
|
-
|
|
70
|
+
function staticExports(filePath, names) {
|
|
99
71
|
let source;
|
|
100
72
|
try {
|
|
101
73
|
source = fs.readFileSync(filePath, 'utf8');
|
|
@@ -103,58 +75,48 @@ export function extractStaticExports(ts, filePath, names) {
|
|
|
103
75
|
catch {
|
|
104
76
|
return {};
|
|
105
77
|
}
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
78
|
+
const parsed = parseSync(filePath, source);
|
|
79
|
+
if (parsed.errors.length)
|
|
80
|
+
throw new Error(`Cannot parse route ${filePath}: ${parsed.errors.map((e) => e.message).join('; ')}`);
|
|
81
|
+
const result = Object.create(null);
|
|
82
|
+
for (const statement of parsed.program.body) {
|
|
83
|
+
if (statement.type !== 'ExportNamedDeclaration' ||
|
|
84
|
+
statement.declaration?.type !== 'VariableDeclaration')
|
|
111
85
|
continue;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
86
|
+
for (const declaration of statement.declaration.declarations) {
|
|
87
|
+
if (declaration.id.type !== 'Identifier' ||
|
|
88
|
+
!names.includes(declaration.id.name) ||
|
|
89
|
+
!declaration.init)
|
|
90
|
+
continue;
|
|
91
|
+
if (Object.hasOwn(result, declaration.id.name))
|
|
92
|
+
continue;
|
|
93
|
+
const value = evalNode(declaration.init);
|
|
94
|
+
if (value !== UNRESOLVED)
|
|
95
|
+
result[declaration.id.name] = value;
|
|
122
96
|
}
|
|
123
97
|
}
|
|
124
|
-
return
|
|
98
|
+
return result;
|
|
125
99
|
}
|
|
126
|
-
export function
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
source = fs.readFileSync(filePath, 'utf8');
|
|
133
|
-
}
|
|
134
|
-
catch {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
const sf = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
138
|
-
for (const stmt of sf.statements) {
|
|
139
|
-
if (!ts.isVariableStatement(stmt))
|
|
140
|
-
continue;
|
|
141
|
-
if (!stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword))
|
|
142
|
-
continue;
|
|
143
|
-
for (const decl of stmt.declarationList.declarations) {
|
|
144
|
-
if (ts.isIdentifier(decl.name) &&
|
|
145
|
-
decl.name.text === name &&
|
|
146
|
-
decl.initializer?.kind === ts.SyntaxKind.TrueKeyword) {
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
100
|
+
export function extractStaticExports(filePath, names) {
|
|
101
|
+
const result = {};
|
|
102
|
+
for (const [name, value] of Object.entries(staticExports(filePath, names))) {
|
|
103
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
104
|
+
Object.defineProperty(result, name, { value, enumerable: true });
|
|
149
105
|
}
|
|
150
106
|
}
|
|
151
|
-
return
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
export function extractStaticMetadata(filePath) {
|
|
110
|
+
return extractStaticExports(filePath, ['metadata']).metadata ?? null;
|
|
111
|
+
}
|
|
112
|
+
export function exportsTrue(filePath, name) {
|
|
113
|
+
return staticExports(filePath, [name])[name] === true;
|
|
152
114
|
}
|
|
153
115
|
export function prerenderPlugin(cfg) {
|
|
154
116
|
return {
|
|
155
117
|
name: 'toil:prerender-seo',
|
|
156
118
|
apply: 'build',
|
|
157
|
-
|
|
119
|
+
closeBundle() {
|
|
158
120
|
if (!cfg.seo)
|
|
159
121
|
return;
|
|
160
122
|
const outDir = path.resolve(cfg.root, cfg.outDir);
|
|
@@ -163,13 +125,12 @@ export function prerenderPlugin(cfg) {
|
|
|
163
125
|
return;
|
|
164
126
|
const shell = fs.readFileSync(shellPath, 'utf8');
|
|
165
127
|
fs.writeFileSync(path.join(cfg.toilDir, 'shell.html'), shell);
|
|
166
|
-
const ts = await loadTypeScript(cfg.root);
|
|
167
128
|
const routes = scanRoutes(cfg.routesAbsDir).filter((r) => r.slot === undefined && !r.intercept);
|
|
168
129
|
for (const route of routes) {
|
|
169
130
|
const isDynamic = /[:*]/.test(route.pattern);
|
|
170
|
-
if (isDynamic &&
|
|
131
|
+
if (isDynamic && exportsTrue(route.file, 'ssr'))
|
|
171
132
|
continue;
|
|
172
|
-
const metadata =
|
|
133
|
+
const metadata = extractStaticMetadata(route.file);
|
|
173
134
|
const seoPattern = isDynamic ? staticSectionPattern(route.pattern) : route.pattern;
|
|
174
135
|
const html = injectSeoHtml(shell, routeSeo(cfg.seo, metadata, seoPattern));
|
|
175
136
|
const target = isDynamic
|
package/build/compiler/ssg.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { createServer } from 'vite';
|
|
4
|
-
import { extractStaticMetadata
|
|
4
|
+
import { extractStaticMetadata } from './prerender.js';
|
|
5
5
|
import { scanRoutes } from './routes.js';
|
|
6
6
|
import { injectSeoHtml, joinUrl, llmsTxt, routeSeo, sitemapXml } from './seo.js';
|
|
7
7
|
import { createViteConfig } from './vite.js';
|
|
@@ -35,7 +35,7 @@ export async function prerenderStaticParams(cfg) {
|
|
|
35
35
|
const shell = fs.readFileSync(shellPath, 'utf8');
|
|
36
36
|
const server = await createServer({
|
|
37
37
|
...(await createViteConfig(cfg)),
|
|
38
|
-
server: { middlewareMode: true, hmr: false },
|
|
38
|
+
server: { middlewareMode: true, hmr: false, ws: false },
|
|
39
39
|
appType: 'custom',
|
|
40
40
|
logLevel: 'silent',
|
|
41
41
|
});
|
|
@@ -105,11 +105,10 @@ export async function prerenderStaticParams(cfg) {
|
|
|
105
105
|
process.stdout.write(` ✓ prerendered ${String(generated.length)} dynamic route${generated.length === 1 ? '' : 's'}\n`);
|
|
106
106
|
}
|
|
107
107
|
if (baseUrl !== undefined) {
|
|
108
|
-
const ts = await loadTypeScript(cfg.root);
|
|
109
108
|
const staticPages = allRoutes
|
|
110
109
|
.filter((r) => r.slot === undefined && !r.intercept && !/[:*]/.test(r.pattern))
|
|
111
110
|
.map((r) => {
|
|
112
|
-
const meta =
|
|
111
|
+
const meta = extractStaticMetadata(r.file);
|
|
113
112
|
return {
|
|
114
113
|
title: metaString(meta, 'title') ?? (r.pattern === '/' ? 'Home' : r.pattern),
|
|
115
114
|
url: joinUrl(baseUrl, r.pattern),
|
|
@@ -9,7 +9,7 @@ import { scanRoutes } from './routes.js';
|
|
|
9
9
|
import { generateSlotsModule } from './ssr-codegen.js';
|
|
10
10
|
import { assignSlotIds, coherenceHash, encodeSlots, extractFromHtml, } from './template.js';
|
|
11
11
|
import { createViteConfig } from './vite.js';
|
|
12
|
-
import { extractStaticMetadata
|
|
12
|
+
import { extractStaticMetadata } from './prerender.js';
|
|
13
13
|
import { escapeAttr, escapeHtml, injectSeoHtml, routeSeo } from './seo.js';
|
|
14
14
|
const SSR_MARKER = '<template id="__toil_ssr"></template>';
|
|
15
15
|
const ROOT_DIV = '<div id="root"></div>';
|
|
@@ -151,13 +151,12 @@ async function renderSsrRoutes(cfg, shell) {
|
|
|
151
151
|
const routes = scanRoutes(cfg.routesAbsDir).filter((r) => r.slot === undefined && !r.intercept);
|
|
152
152
|
if (routes.length === 0)
|
|
153
153
|
return [];
|
|
154
|
-
const ts = cfg.seo ? await loadTypeScript(cfg.root) : null;
|
|
155
154
|
const warn = (msg) => {
|
|
156
155
|
process.stderr.write(` toil: SSR ${msg}\n`);
|
|
157
156
|
};
|
|
158
157
|
const server = await createServer({
|
|
159
158
|
...(await createViteConfig(cfg)),
|
|
160
|
-
server: { middlewareMode: true, hmr: false },
|
|
159
|
+
server: { middlewareMode: true, hmr: false, ws: false },
|
|
161
160
|
appType: 'custom',
|
|
162
161
|
logLevel: 'silent',
|
|
163
162
|
});
|
|
@@ -197,7 +196,7 @@ async function renderSsrRoutes(cfg, shell) {
|
|
|
197
196
|
const lm = (await server.ssrLoadModule(lf));
|
|
198
197
|
layouts.push(lm.default);
|
|
199
198
|
}
|
|
200
|
-
const metadata =
|
|
199
|
+
const metadata = extractStaticMetadata(r.file);
|
|
201
200
|
const name = routeTemplateName(r.pattern);
|
|
202
201
|
client.__setSsrLocation(samplePath(r.pattern));
|
|
203
202
|
const art = extractRouteTemplate({
|