toiljs 0.0.115 → 0.0.117
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 +10 -0
- package/README.md +16 -7
- package/TYPESCRIPT_LAW.md +1946 -2073
- 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/dev/devtools.js +1 -1
- package/build/client/dev/error-overlay.js +1 -1
- 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 +25 -4
- 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 +6 -5
- package/build/compiler/vite.js +3 -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/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/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/test/prerender.test.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
|
|
5
|
-
import ts from 'typescript';
|
|
6
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
extractStaticMetadata,
|
|
10
|
-
loadTypeScript,
|
|
11
|
-
loadTypeScriptSync,
|
|
12
|
-
} from '../src/compiler/prerender';
|
|
13
|
-
|
|
14
|
-
const written: string[] = [];
|
|
15
|
-
function tmp(source: string): string {
|
|
16
|
-
const file = path.join(
|
|
17
|
-
os.tmpdir(),
|
|
18
|
-
`toil-prerender-${String(written.length)}-${process.pid}.tsx`,
|
|
19
|
-
);
|
|
20
|
-
fs.writeFileSync(file, source);
|
|
21
|
-
written.push(file);
|
|
22
|
-
return file;
|
|
23
|
-
}
|
|
24
|
-
afterEach(() => {
|
|
25
|
-
for (const f of written.splice(0)) fs.rmSync(f, { force: true });
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
describe('extractStaticMetadata', () => {
|
|
29
|
-
it('extracts a static metadata object literal (nested objects/arrays)', () => {
|
|
30
|
-
const file = tmp(
|
|
31
|
-
`export const metadata = { title: 'X', keywords: ['a', 'b'], openGraph: { type: 'website' } };\n` +
|
|
32
|
-
`export default function P() { return null; }\n`,
|
|
33
|
-
);
|
|
34
|
-
expect(extractStaticMetadata(ts, file)).toEqual({
|
|
35
|
-
title: 'X',
|
|
36
|
-
keywords: ['a', 'b'],
|
|
37
|
-
openGraph: { type: 'website' },
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('returns null when there is no static metadata export', () => {
|
|
42
|
-
expect(
|
|
43
|
-
extractStaticMetadata(ts, tmp(`export default function P() { return null; }\n`)),
|
|
44
|
-
).toBeNull();
|
|
45
|
-
// generateMetadata (a function) is not a static object literal → not extracted.
|
|
46
|
-
expect(
|
|
47
|
-
extractStaticMetadata(
|
|
48
|
-
ts,
|
|
49
|
-
tmp(`export const generateMetadata = () => ({ title: 'X' });\n`),
|
|
50
|
-
),
|
|
51
|
-
).toBeNull();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('skips computed/non-literal properties but keeps the static ones', () => {
|
|
55
|
-
const file = tmp(`const x = foo();\nexport const metadata = { title: 'X', dyn: x };\n`);
|
|
56
|
-
expect(extractStaticMetadata(ts, file)).toEqual({ title: 'X' });
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Builds a throwaway project root whose resolvable `typescript` is `main`-ed at a module exporting
|
|
62
|
-
* only `version` — the shape TypeScript 7 ships, having moved the compiler API to
|
|
63
|
-
* `typescript/unstable/*`. Resolution succeeds, so a truthy check can't tell it apart from a usable
|
|
64
|
-
* compiler; only probing the API can.
|
|
65
|
-
*/
|
|
66
|
-
function rootWithApiLessTypeScript(): string {
|
|
67
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), `toil-ts7-${process.pid}-`));
|
|
68
|
-
dirs.push(root);
|
|
69
|
-
const pkgDir = path.join(root, 'node_modules', 'typescript');
|
|
70
|
-
fs.mkdirSync(pkgDir, { recursive: true });
|
|
71
|
-
fs.writeFileSync(path.join(root, 'package.json'), '{"name":"fixture"}');
|
|
72
|
-
fs.writeFileSync(
|
|
73
|
-
path.join(pkgDir, 'package.json'),
|
|
74
|
-
'{"name":"typescript","version":"7.0.2","main":"./version.cjs"}',
|
|
75
|
-
);
|
|
76
|
-
fs.writeFileSync(
|
|
77
|
-
path.join(pkgDir, 'version.cjs'),
|
|
78
|
-
`module.exports = { version: '7.0.2', versionMajorMinor: '7.0' };\n`,
|
|
79
|
-
);
|
|
80
|
-
return root;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const dirs: string[] = [];
|
|
84
|
-
afterEach(() => {
|
|
85
|
-
for (const d of dirs.splice(0)) fs.rmSync(d, { recursive: true, force: true });
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe('loadTypeScript', () => {
|
|
89
|
-
it('returns null (not a half-built module) when typescript exposes no compiler API', async () => {
|
|
90
|
-
const root = rootWithApiLessTypeScript();
|
|
91
|
-
const warn = vi.spyOn(process.stderr, 'write').mockReturnValue(true);
|
|
92
|
-
try {
|
|
93
|
-
// Both must degrade rather than hand back `{ version }`, whose first `ts.ScriptTarget`
|
|
94
|
-
// read would throw `Cannot read properties of undefined (reading 'Latest')` mid-build.
|
|
95
|
-
expect(loadTypeScriptSync(root)).toBeNull();
|
|
96
|
-
await expect(loadTypeScript(root)).resolves.toBeNull();
|
|
97
|
-
} finally {
|
|
98
|
-
warn.mockRestore();
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('returns null when typescript is not installed at all', async () => {
|
|
103
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), `toil-nots-${process.pid}-`));
|
|
104
|
-
dirs.push(root);
|
|
105
|
-
fs.writeFileSync(path.join(root, 'package.json'), '{"name":"fixture"}');
|
|
106
|
-
expect(loadTypeScriptSync(root)).toBeNull();
|
|
107
|
-
await expect(loadTypeScript(root)).resolves.toBeNull();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('returns the compiler API when a usable typescript is installed', async () => {
|
|
111
|
-
// This repo's own root resolves its devDependency typescript, which has the classic API.
|
|
112
|
-
const root = path.resolve(__dirname, '..');
|
|
113
|
-
expect(loadTypeScriptSync(root)?.createSourceFile).toBeTypeOf('function');
|
|
114
|
-
expect((await loadTypeScript(root))?.ScriptTarget.Latest).toBeTypeOf('number');
|
|
115
|
-
});
|
|
116
|
-
});
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import prettier from 'prettier';
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import * as plugin from '../presets/prettier-plugin.js';
|
|
5
|
-
|
|
6
|
-
function fmt(src: string): Promise<string> {
|
|
7
|
-
return prettier.format(src, {
|
|
8
|
-
parser: 'typescript',
|
|
9
|
-
plugins: [plugin],
|
|
10
|
-
tabWidth: 4,
|
|
11
|
-
singleQuote: true,
|
|
12
|
-
semi: true,
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// The plugin lets prettier format toilscript server code, whose native decorators on free
|
|
17
|
-
// functions (@main, @remote function) are not valid JS/TS grammar (so stock prettier throws).
|
|
18
|
-
describe('toiljs prettier-plugin', () => {
|
|
19
|
-
it('formats a free @remote function and keeps the decorator', async () => {
|
|
20
|
-
const out = await fmt('@remote\nfunction ping(n:i32):i32{return n+1}\n');
|
|
21
|
-
expect(out).toContain('@remote');
|
|
22
|
-
expect(out).toContain('function ping(n: i32): i32 {');
|
|
23
|
-
expect(out).not.toContain('toil-decorator'); // marker fully restored
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('formats @main', async () => {
|
|
27
|
-
const out = await fmt('@main\nfunction run():i32{return 42}\n');
|
|
28
|
-
expect(out).toMatch(/@main\nfunction run\(\): i32 \{/);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('handles @remote export function', async () => {
|
|
32
|
-
const out = await fmt('@remote\nexport function pong():void{}\n');
|
|
33
|
-
expect(out).toContain('@remote\nexport function pong(): void {}');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('leaves class/method decorators untouched', async () => {
|
|
37
|
-
const out = await fmt('@data\nclass A{ x:i32=0 }\n');
|
|
38
|
-
expect(out).toContain('@data');
|
|
39
|
-
expect(out).toContain('class A {');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('is idempotent', async () => {
|
|
43
|
-
const once = await fmt('@remote\nfunction f():void{}\n@main\nfunction g():void{}\n');
|
|
44
|
-
expect(await fmt(once)).toBe(once);
|
|
45
|
-
});
|
|
46
|
-
});
|
package/test/routes.test.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { matchRoute } from '../src/client/routing/match';
|
|
4
|
-
import { filePathToRoute, interceptTarget } from '../src/compiler/routes';
|
|
5
|
-
|
|
6
|
-
describe('filePathToRoute', () => {
|
|
7
|
-
it('maps index, static, nested, and dynamic files to patterns', () => {
|
|
8
|
-
expect(filePathToRoute('index.tsx')).toBe('/');
|
|
9
|
-
expect(filePathToRoute('about.tsx')).toBe('/about');
|
|
10
|
-
expect(filePathToRoute('blog/index.tsx')).toBe('/blog');
|
|
11
|
-
expect(filePathToRoute('blog/[id].tsx')).toBe('/blog/:id');
|
|
12
|
-
expect(filePathToRoute('docs/guide/intro.jsx')).toBe('/docs/guide/intro');
|
|
13
|
-
expect(filePathToRoute('docs/[...slug].tsx')).toBe('/docs/*slug');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('maps optional catch-all and strips route groups', () => {
|
|
17
|
-
expect(filePathToRoute('docs/[[...slug]].tsx')).toBe('/docs/**slug');
|
|
18
|
-
expect(filePathToRoute('[[...slug]].tsx')).toBe('/**slug');
|
|
19
|
-
expect(filePathToRoute('(marketing)/about.tsx')).toBe('/about');
|
|
20
|
-
expect(filePathToRoute('(shop)/index.tsx')).toBe('/');
|
|
21
|
-
expect(filePathToRoute('(a)/(b)/deep.tsx')).toBe('/deep');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('strips parallel-slot (@slot) segments from the URL', () => {
|
|
25
|
-
expect(filePathToRoute('@modal/photo/[id].tsx')).toBe('/photo/:id');
|
|
26
|
-
expect(filePathToRoute('@sidebar/index.tsx')).toBe('/');
|
|
27
|
-
expect(filePathToRoute('dashboard/@chart/views.tsx')).toBe('/dashboard/views');
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('interceptTarget', () => {
|
|
32
|
-
it('resolves (.)/(..)/(...) marker targets', () => {
|
|
33
|
-
expect(interceptTarget('@modal/(.)photo/[id].tsx')).toBe('/photo/:id');
|
|
34
|
-
expect(interceptTarget('feed/@modal/(..)photo/[id].tsx')).toBe('/photo/:id');
|
|
35
|
-
expect(interceptTarget('a/b/@m/(...)login.tsx')).toBe('/login');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('returns null for routes with no interception marker', () => {
|
|
39
|
-
expect(interceptTarget('photo/[id].tsx')).toBeNull();
|
|
40
|
-
expect(interceptTarget('@modal/settings.tsx')).toBeNull();
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('matchRoute', () => {
|
|
45
|
-
it('matches static routes', () => {
|
|
46
|
-
expect(matchRoute('/', '/')).toEqual({});
|
|
47
|
-
expect(matchRoute('/about', '/about')).toEqual({});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('rejects non-matches', () => {
|
|
51
|
-
expect(matchRoute('/about', '/x')).toBeNull();
|
|
52
|
-
expect(matchRoute('/blog/:id', '/blog')).toBeNull();
|
|
53
|
-
expect(matchRoute('/', '/about')).toBeNull();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('extracts dynamic params', () => {
|
|
57
|
-
expect(matchRoute('/blog/:id', '/blog/42')).toEqual({ id: '42' });
|
|
58
|
-
expect(matchRoute('/u/:user/p/:post', '/u/ann/p/7')).toEqual({ user: 'ann', post: '7' });
|
|
59
|
-
expect(matchRoute('/blog/:id', '/blog/a%20b')).toEqual({ id: 'a b' });
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('captures the tail with catch-all routes', () => {
|
|
63
|
-
expect(matchRoute('/docs/*slug', '/docs/a/b/c')).toEqual({ slug: 'a/b/c' });
|
|
64
|
-
expect(matchRoute('/docs/*slug', '/docs/intro')).toEqual({ slug: 'intro' });
|
|
65
|
-
expect(matchRoute('/files/*path', '/files/a%20b/c')).toEqual({ path: 'a b/c' });
|
|
66
|
-
// catch-all needs at least one trailing segment
|
|
67
|
-
expect(matchRoute('/docs/*slug', '/docs')).toBeNull();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('matches optional catch-all with zero or more segments', () => {
|
|
71
|
-
expect(matchRoute('/docs/**slug', '/docs')).toEqual({ slug: '' });
|
|
72
|
-
expect(matchRoute('/docs/**slug', '/docs/a/b')).toEqual({ slug: 'a/b' });
|
|
73
|
-
expect(matchRoute('/**slug', '/')).toEqual({ slug: '' });
|
|
74
|
-
expect(matchRoute('/**slug', '/x/y')).toEqual({ slug: 'x/y' });
|
|
75
|
-
});
|
|
76
|
-
});
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Regression test for the bignum JSON wire format. 64-bit-and-up integers
|
|
3
|
-
* (u64/i64/u128/i128/u256/i256) must cross JSON as DECIMAL STRINGS, not number tokens
|
|
4
|
-
* or limb arrays: JSON numbers ride through a browser client's JSON.parse as IEEE
|
|
5
|
-
* doubles, which silently corrupt any integer past 2^53.
|
|
6
|
-
*
|
|
7
|
-
* Compiles test/fixtures/bignum-wire/spec.ts with the installed toilscript (so it
|
|
8
|
-
* exercises the published compiler + generated client, not a hand-written stub), then
|
|
9
|
-
* imports the generated TS client and asserts the wire shape both directions, including
|
|
10
|
-
* values far above 2^53.
|
|
11
|
-
*/
|
|
12
|
-
import { spawnSync } from 'node:child_process';
|
|
13
|
-
import fs from 'node:fs';
|
|
14
|
-
import os from 'node:os';
|
|
15
|
-
import path from 'node:path';
|
|
16
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
17
|
-
|
|
18
|
-
import { beforeAll, describe, expect, it } from 'vitest';
|
|
19
|
-
|
|
20
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
-
const spec = path.join(here, 'fixtures', 'bignum-wire', 'spec.ts');
|
|
22
|
-
// The generated module imports DataWriter/DataReader from this specifier.
|
|
23
|
-
const codec = path.join(here, '..', 'src', 'io', 'codec.ts');
|
|
24
|
-
|
|
25
|
-
/** Resolves the installed toilscript CLI entry (no PATH / .bin assumptions). */
|
|
26
|
-
function toilscriptBin(): string {
|
|
27
|
-
if (process.env.TOILSCRIPT_BIN) return process.env.TOILSCRIPT_BIN;
|
|
28
|
-
const sibling = path.resolve(here, '..', '..', 'toilscript', 'bin', 'toilscript.js');
|
|
29
|
-
if (fs.existsSync(sibling)) return sibling;
|
|
30
|
-
const pkgPath = require.resolve('toilscript/package.json');
|
|
31
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) as { bin?: Record<string, string> };
|
|
32
|
-
const binRel = pkg.bin?.toilscript;
|
|
33
|
-
if (!binRel) throw new Error('toilscript declares no bin');
|
|
34
|
-
return path.join(path.dirname(pkgPath), binRel);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface Wallet {
|
|
38
|
-
u: bigint;
|
|
39
|
-
i: bigint;
|
|
40
|
-
a: bigint;
|
|
41
|
-
b: bigint;
|
|
42
|
-
c: bigint;
|
|
43
|
-
d: bigint;
|
|
44
|
-
label: string;
|
|
45
|
-
toJSONValue(): Record<string, unknown>;
|
|
46
|
-
}
|
|
47
|
-
interface WalletStatic {
|
|
48
|
-
new (): Wallet;
|
|
49
|
-
fromJSONValue(v: unknown): Wallet;
|
|
50
|
-
}
|
|
51
|
-
interface AccountStatic {
|
|
52
|
-
new (): { main: Wallet; ids: bigint[]; toJSONValue(): Record<string, unknown> };
|
|
53
|
-
fromJSONValue(v: unknown): { main: Wallet; ids: bigint[] };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let Wallet: WalletStatic;
|
|
57
|
-
let Account: AccountStatic;
|
|
58
|
-
let tmp: string;
|
|
59
|
-
|
|
60
|
-
beforeAll(async () => {
|
|
61
|
-
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'bignum-wire-'));
|
|
62
|
-
fs.writeFileSync(path.join(tmp, 'package.json'), '{ "type": "module" }\n');
|
|
63
|
-
// vitest transforms the imported .ts through Vite/oxc, which walks up for a tsconfig.
|
|
64
|
-
fs.writeFileSync(
|
|
65
|
-
path.join(tmp, 'tsconfig.json'),
|
|
66
|
-
JSON.stringify({ compilerOptions: { target: 'esnext', module: 'esnext' } }),
|
|
67
|
-
);
|
|
68
|
-
const mod = path.join(tmp, 'server.ts');
|
|
69
|
-
const wasm = path.join(tmp, 'spec.wasm');
|
|
70
|
-
const res = spawnSync(
|
|
71
|
-
process.execPath,
|
|
72
|
-
[
|
|
73
|
-
toilscriptBin(),
|
|
74
|
-
spec,
|
|
75
|
-
'-o',
|
|
76
|
-
wasm,
|
|
77
|
-
'--runtime',
|
|
78
|
-
'stub',
|
|
79
|
-
'--initialMemory',
|
|
80
|
-
'32',
|
|
81
|
-
'--rpcModule',
|
|
82
|
-
mod,
|
|
83
|
-
'--rpcRuntime',
|
|
84
|
-
codec,
|
|
85
|
-
],
|
|
86
|
-
{ encoding: 'utf8' },
|
|
87
|
-
);
|
|
88
|
-
if (res.status !== 0) throw new Error('toilscript compile failed:\n' + res.stderr);
|
|
89
|
-
const generatedSource = fs.readFileSync(mod, 'utf8');
|
|
90
|
-
const removedHelper = ['__toil', 'Unlimb'].join('');
|
|
91
|
-
expect(generatedSource).toContain('__toilBigInt');
|
|
92
|
-
expect(generatedSource).not.toContain(removedHelper);
|
|
93
|
-
const gen = (await import(pathToFileURL(mod).href)) as {
|
|
94
|
-
Wallet: WalletStatic;
|
|
95
|
-
Account: AccountStatic;
|
|
96
|
-
};
|
|
97
|
-
Wallet = gen.Wallet;
|
|
98
|
-
Account = gen.Account;
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// A few representative bignum types; `huge` is well past Number.MAX_SAFE_INTEGER.
|
|
102
|
-
const huge = '123456789012345678901234567890';
|
|
103
|
-
const u128Max = '340282366920938463463374607431768211455';
|
|
104
|
-
const i64Min = '-9223372036854775808';
|
|
105
|
-
|
|
106
|
-
describe('generated client bignum JSON wire format', () => {
|
|
107
|
-
it('serializes every 64-bit-and-up integer as a decimal string', () => {
|
|
108
|
-
const w = new Wallet();
|
|
109
|
-
w.u = BigInt(huge.slice(0, 19)); // fits u64
|
|
110
|
-
w.i = BigInt(i64Min);
|
|
111
|
-
w.a = BigInt(u128Max);
|
|
112
|
-
w.b = -123n;
|
|
113
|
-
w.c = BigInt(huge);
|
|
114
|
-
w.d = -1n;
|
|
115
|
-
w.label = 'x';
|
|
116
|
-
const json = w.toJSONValue();
|
|
117
|
-
// Each bignum field is a string, never a number or an array.
|
|
118
|
-
for (const k of ['u', 'i', 'a', 'b', 'c', 'd'] as const) {
|
|
119
|
-
expect(typeof json[k], `field ${k}`).toBe('string');
|
|
120
|
-
}
|
|
121
|
-
expect(json.a).toBe(u128Max);
|
|
122
|
-
expect(json.c).toBe(huge);
|
|
123
|
-
expect(json.i).toBe(i64Min);
|
|
124
|
-
expect(json.label).toBe('x');
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('revives a decimal string past 2^53 into an exact bigint', () => {
|
|
128
|
-
const w = Wallet.fromJSONValue({
|
|
129
|
-
u: '0',
|
|
130
|
-
i: i64Min,
|
|
131
|
-
a: u128Max,
|
|
132
|
-
b: '-123',
|
|
133
|
-
c: huge,
|
|
134
|
-
d: '-1',
|
|
135
|
-
label: 'y',
|
|
136
|
-
});
|
|
137
|
-
expect(w.c).toBe(BigInt(huge));
|
|
138
|
-
expect(w.a).toBe(BigInt(u128Max));
|
|
139
|
-
expect(w.i).toBe(BigInt(i64Min));
|
|
140
|
-
expect(w.d).toBe(-1n);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('round-trips a value through send then revive without loss', () => {
|
|
144
|
-
const w = new Wallet();
|
|
145
|
-
w.c = BigInt(huge);
|
|
146
|
-
w.d = BigInt('-' + huge);
|
|
147
|
-
const back = Wallet.fromJSONValue(JSON.parse(JSON.stringify(w.toJSONValue())));
|
|
148
|
-
expect(back.c).toBe(BigInt(huge));
|
|
149
|
-
expect(back.d).toBe(BigInt('-' + huge));
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('recurses into nested @data and arrays of bignums', () => {
|
|
153
|
-
const a = new Account();
|
|
154
|
-
a.main.c = BigInt(huge);
|
|
155
|
-
a.ids = [1n, BigInt(huge)];
|
|
156
|
-
const json = a.toJSONValue();
|
|
157
|
-
const main = json.main as Record<string, unknown>;
|
|
158
|
-
expect(main.c).toBe(huge);
|
|
159
|
-
expect(json.ids).toEqual(['1', huge]);
|
|
160
|
-
const back = Account.fromJSONValue(JSON.parse(JSON.stringify(json)));
|
|
161
|
-
expect(back.main.c).toBe(BigInt(huge));
|
|
162
|
-
expect(back.ids).toEqual([1n, BigInt(huge)]);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @service / @remote RPC: a real round trip into the example project's toilscript-compiled server
|
|
3
|
-
* wasm. A `POST /__toil_rpc` carrying the FNV method id in the `dacely-rpc` header is dispatched by the
|
|
4
|
-
* runtime `Rpc` registry (compiler-injected `__rpcDispatch` + `Rpc.register`) to the @remote method,
|
|
5
|
-
* and the @data/scalar result comes back encoded with the same DataWriter codec the client decodes.
|
|
6
|
-
*/
|
|
7
|
-
import fs from 'node:fs';
|
|
8
|
-
import path from 'node:path';
|
|
9
|
-
import { fileURLToPath } from 'node:url';
|
|
10
|
-
|
|
11
|
-
import { describe, expect, it } from 'vitest';
|
|
12
|
-
|
|
13
|
-
import { WasmServerModule } from '../src/devserver/index.js';
|
|
14
|
-
|
|
15
|
-
const EXAMPLE_WASM = path.resolve(
|
|
16
|
-
path.dirname(fileURLToPath(import.meta.url)),
|
|
17
|
-
'../examples/basic/build/server/release.wasm',
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
/** FNV-1a (the toilscript `dataTypeId`); the client + the parser injection must agree on this. */
|
|
21
|
-
function fnv1a(s: string): number {
|
|
22
|
-
let h = 0x811c9dc5;
|
|
23
|
-
for (let i = 0; i < s.length; i++) h = Math.imul(h ^ s.charCodeAt(i), 0x01000193) >>> 0;
|
|
24
|
-
return h >>> 0;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
describe.skipIf(!fs.existsSync(EXAMPLE_WASM))('@service RPC dispatch', () => {
|
|
28
|
-
const load = (): WasmServerModule => {
|
|
29
|
-
const m = new WasmServerModule(EXAMPLE_WASM);
|
|
30
|
-
m.refresh();
|
|
31
|
-
return m;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
it('dispatches Server.stats.playerCount() over /__toil_rpc', () => {
|
|
35
|
-
const id = fnv1a('Stats.playerCount');
|
|
36
|
-
expect(id).toBe(118912982); // matches the generated __toilRpc client
|
|
37
|
-
const r = load().dispatch({
|
|
38
|
-
method: 'POST',
|
|
39
|
-
path: '/__toil_rpc',
|
|
40
|
-
headers: [['dacely-rpc', String(id)]],
|
|
41
|
-
body: new Uint8Array(0),
|
|
42
|
-
});
|
|
43
|
-
expect(r.unhandled).toBe(false);
|
|
44
|
-
expect(r.status).toBe(200);
|
|
45
|
-
// The result is a DataWriter-encoded i32 (the seeded player count = 3).
|
|
46
|
-
expect(r.body.length).toBe(4);
|
|
47
|
-
const dv = new DataView(r.body.buffer, r.body.byteOffset, r.body.length);
|
|
48
|
-
expect(dv.getInt32(0, true)).toBe(3);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('dispatches a free Server.ping(n) over /__toil_rpc', () => {
|
|
52
|
-
const id = fnv1a('ping');
|
|
53
|
-
const body = new Uint8Array(4);
|
|
54
|
-
new DataView(body.buffer).setInt32(0, 41, true); // arg n = 41 (DataWriter writeI32, LE)
|
|
55
|
-
const r = load().dispatch({
|
|
56
|
-
method: 'POST',
|
|
57
|
-
path: '/__toil_rpc',
|
|
58
|
-
headers: [['dacely-rpc', String(id)]],
|
|
59
|
-
body,
|
|
60
|
-
});
|
|
61
|
-
expect(r.status).toBe(200);
|
|
62
|
-
expect(r.body.length).toBe(4);
|
|
63
|
-
const dv = new DataView(r.body.buffer, r.body.byteOffset, r.body.length);
|
|
64
|
-
expect(dv.getInt32(0, true)).toBe(42); // ping(41) = 42
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('round-trips a Uint8Array[] arg + result (writeBytes/readBytes loop, the #5 fix)', () => {
|
|
68
|
-
const id = fnv1a('echoParts');
|
|
69
|
-
const parts = [Uint8Array.from([1, 2]), Uint8Array.from([3, 4, 5])];
|
|
70
|
-
const buf: number[] = [];
|
|
71
|
-
const pushU32 = (v: number) => buf.push(v & 255, (v >> 8) & 255, (v >> 16) & 255, (v >>> 24) & 255);
|
|
72
|
-
pushU32(parts.length); // u32 count, then per part: u32 len + bytes (DataWriter.writeBytes)
|
|
73
|
-
for (const p of parts) {
|
|
74
|
-
pushU32(p.length);
|
|
75
|
-
for (const b of p) buf.push(b);
|
|
76
|
-
}
|
|
77
|
-
const r = load().dispatch({
|
|
78
|
-
method: 'POST',
|
|
79
|
-
path: '/__toil_rpc',
|
|
80
|
-
headers: [['dacely-rpc', String(id)]],
|
|
81
|
-
body: Uint8Array.from(buf),
|
|
82
|
-
});
|
|
83
|
-
expect(r.status).toBe(200);
|
|
84
|
-
const dv = new DataView(r.body.buffer, r.body.byteOffset, r.body.length);
|
|
85
|
-
let off = 0;
|
|
86
|
-
const count = dv.getUint32(off, true);
|
|
87
|
-
off += 4;
|
|
88
|
-
const out: number[][] = [];
|
|
89
|
-
for (let i = 0; i < count; i++) {
|
|
90
|
-
const len = dv.getUint32(off, true);
|
|
91
|
-
off += 4;
|
|
92
|
-
out.push([...r.body.subarray(off, off + len)]);
|
|
93
|
-
off += len;
|
|
94
|
-
}
|
|
95
|
-
expect(out).toEqual([
|
|
96
|
-
[1, 2],
|
|
97
|
-
[3, 4, 5],
|
|
98
|
-
]);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('rejects an @auth @remote with 401 when there is no session', () => {
|
|
102
|
-
const id = fnv1a('Stats.secretCount');
|
|
103
|
-
const r = load().dispatch({
|
|
104
|
-
method: 'POST',
|
|
105
|
-
path: '/__toil_rpc',
|
|
106
|
-
headers: [['dacely-rpc', String(id)]],
|
|
107
|
-
body: new Uint8Array(0),
|
|
108
|
-
});
|
|
109
|
-
expect(r.status).toBe(401);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('returns 400 for an unknown method id', () => {
|
|
113
|
-
const r = load().dispatch({
|
|
114
|
-
method: 'POST',
|
|
115
|
-
path: '/__toil_rpc',
|
|
116
|
-
headers: [['dacely-rpc', '999999']],
|
|
117
|
-
body: new Uint8Array(0),
|
|
118
|
-
});
|
|
119
|
-
expect(r.status).toBe(400);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('does not intercept a non-RPC request (no dacely-rpc header)', () => {
|
|
123
|
-
const r = load().dispatch({
|
|
124
|
-
method: 'GET',
|
|
125
|
-
path: '/json',
|
|
126
|
-
headers: [['host', 'localhost:3000']],
|
|
127
|
-
body: new Uint8Array(0),
|
|
128
|
-
});
|
|
129
|
-
expect(r.status).toBe(200);
|
|
130
|
-
expect(Buffer.from(r.body).toString()).toBe('{"hello":"toiljs"}\n');
|
|
131
|
-
});
|
|
132
|
-
});
|
package/test/rpc-kinds.test.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The dev-server RPC DB-kind resolution (audit #2): an `@action` @remote may write; a plain/read-only
|
|
3
|
-
* @remote (absent from `toildb.rpc_kinds`) defaults to read-only Query, matching the edge host gate.
|
|
4
|
-
*/
|
|
5
|
-
import { describe, expect, it } from 'vitest';
|
|
6
|
-
|
|
7
|
-
import { rpcKindForId, type RpcKindEntry } from '../src/devserver/db/routeKinds.js';
|
|
8
|
-
import { DbFunctionKind } from '../src/devserver/db/types.js';
|
|
9
|
-
|
|
10
|
-
describe('rpcKindForId', () => {
|
|
11
|
-
it('returns the @action kind for a listed id, and read-only Query for an absent one', () => {
|
|
12
|
-
const methods: RpcKindEntry[] = [{ methodId: 42, kind: DbFunctionKind.Action }];
|
|
13
|
-
expect(rpcKindForId(methods, 42)).toBe(DbFunctionKind.Action);
|
|
14
|
-
// An id NOT in rpc_kinds (a plain/read-only @remote) defaults to Query - the safe default.
|
|
15
|
-
expect(rpcKindForId(methods, 999)).toBe(DbFunctionKind.Query);
|
|
16
|
-
expect(rpcKindForId([], 42)).toBe(DbFunctionKind.Query);
|
|
17
|
-
});
|
|
18
|
-
});
|
package/test/rpc.test.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { Server } from '../src/client/rpc';
|
|
4
|
-
|
|
5
|
-
// `Server` is the runtime behind the generated typed surface. The RPC branch surfaces
|
|
6
|
-
// `globalThis.__toilRpc` (attached by the generated `shared/server.ts`); when that client has
|
|
7
|
-
// not loaded, the proxy throws a helpful "client has not loaded" error naming the path.
|
|
8
|
-
describe('Server RPC stub (client not loaded)', () => {
|
|
9
|
-
afterEach(() => {
|
|
10
|
-
delete (globalThis as { __toilRpc?: unknown }).__toilRpc;
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('throws on a direct call, naming the path', () => {
|
|
14
|
-
const s = Server as { ping: () => unknown };
|
|
15
|
-
expect(() => s.ping()).toThrow(/Server\.ping\(\)/);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('throws on a nested service.method call', () => {
|
|
19
|
-
const s = Server as { accounts: { getUser: () => unknown } };
|
|
20
|
-
expect(() => s.accounts.getUser()).toThrow(/Server\.accounts\.getUser\(\)/);
|
|
21
|
-
expect(() => s.accounts.getUser()).toThrow(/has not loaded/);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('surfaces the attached RPC client (service method + free remote) once loaded', async () => {
|
|
25
|
-
const fake = { stats: { playerCount: async () => 3 }, ping: async (n: number) => n + 1 };
|
|
26
|
-
(globalThis as { __toilRpc?: unknown }).__toilRpc = fake;
|
|
27
|
-
const s = Server as {
|
|
28
|
-
stats: { playerCount: () => Promise<number> };
|
|
29
|
-
ping: (n: number) => Promise<number>;
|
|
30
|
-
};
|
|
31
|
-
expect(await s.stats.playerCount()).toBe(3);
|
|
32
|
-
expect(await s.ping(41)).toBe(42);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('is not thenable (so it is not mistaken for a promise)', () => {
|
|
36
|
-
const s = Server as Record<string, unknown>;
|
|
37
|
-
expect(s.then).toBeUndefined();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('ignores symbol probes without throwing', () => {
|
|
41
|
-
const s = Server as Record<PropertyKey, unknown>;
|
|
42
|
-
expect(s[Symbol.iterator]).toBeUndefined();
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// `Server.REST` surfaces the working fetch client that the generated `shared/server.ts`
|
|
47
|
-
// attaches to `globalThis.__toilRest` on import.
|
|
48
|
-
describe('Server.REST surface', () => {
|
|
49
|
-
afterEach(() => {
|
|
50
|
-
delete (globalThis as { __toilRest?: unknown }).__toilRest;
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('returns the attached REST client when shared/server has loaded', () => {
|
|
54
|
-
const fake = { todos: { getTodo: async () => 'ok' } };
|
|
55
|
-
(globalThis as { __toilRest?: unknown }).__toilRest = fake;
|
|
56
|
-
const s = Server as { REST: typeof fake };
|
|
57
|
-
expect(s.REST).toBe(fake);
|
|
58
|
-
expect(s.REST.todos.getTodo).toBeTypeOf('function');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('throws a helpful "not loaded" error when the REST client is absent', () => {
|
|
62
|
-
const s = Server as { REST: { todos: { getTodo: () => unknown } } };
|
|
63
|
-
expect(() => s.REST.todos.getTodo()).toThrow(/Server\.REST\.todos\.getTodo\(\)/);
|
|
64
|
-
expect(() => s.REST.todos.getTodo()).toThrow(/has not loaded/);
|
|
65
|
-
});
|
|
66
|
-
});
|