brustjs 0.1.24-alpha → 0.1.26-alpha
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/example/pokedex/actions.ts +10 -2
- package/example/pokedex/app.css +56 -30
- package/example/pokedex/components/AddToTeamButton.tsx +1 -2
- package/example/pokedex/components/AppLayout.tsx +15 -27
- package/example/pokedex/components/NavLink.tsx +50 -0
- package/example/pokedex/components/NavPreloader.tsx +21 -0
- package/example/pokedex/components/ThemeToggle.tsx +51 -0
- package/example/pokedex/lib/loaders.ts +14 -6
- package/example/pokedex/lib/pokeapi.ts +7 -5
- package/example/pokedex/lib/types.ts +1 -0
- package/package.json +11 -9
- package/runtime/client/index.ts +4 -0
- package/runtime/cookies.ts +61 -0
- package/runtime/define-actions.ts +34 -7
- package/runtime/index.js +52 -52
- package/runtime/index.ts +9 -0
- package/runtime/islands/bootstrap.ts +10 -1
- package/runtime/islands/island.tsx +8 -4
- package/runtime/islands/native-render.ts +3 -1
- package/runtime/loader-cache.ts +42 -0
- package/runtime/navigation/active-nav.ts +75 -0
- package/runtime/navigation/index.ts +13 -0
- package/runtime/navigation/react.ts +24 -0
- package/runtime/navigation/store.ts +208 -0
- package/runtime/request-context.ts +35 -0
- package/runtime/routes.ts +96 -25
- package/runtime/treaty.ts +47 -10
- package/runtime/treaty.type-test.ts +69 -0
- package/runtime/tsconfig.typecheck.json +23 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Isolated TYPE TEST for the B2 typed treaty client. Not executed — every
|
|
2
|
+
// assertion is a pure type check inside an un-called async function. Run via:
|
|
3
|
+
// bun run typecheck:treaty → tsc -p tsconfig.typecheck.json --noEmit
|
|
4
|
+
//
|
|
5
|
+
// It exercises: (1) static-path methods are fully typed (output + error union),
|
|
6
|
+
// (2) the discriminated error union narrows on `code`, (3) accessing a
|
|
7
|
+
// non-existent output field is a type error, (4) a wrong error code / field is a
|
|
8
|
+
// type error, (5) param paths stay permissive (no type error, the fallback).
|
|
9
|
+
import { z } from 'zod'
|
|
10
|
+
import { defineActions } from './define-actions.ts'
|
|
11
|
+
import { client } from './treaty.ts'
|
|
12
|
+
|
|
13
|
+
const actions = defineActions()
|
|
14
|
+
.get('/team', () => ({ team: [{ id: 1 }], max: 6 }))
|
|
15
|
+
.post('/team', ({ body }: { body: { id: number } }) => ({ team: [{ id: body.id }], max: 6 }), {
|
|
16
|
+
body: z.object({ id: z.number() }),
|
|
17
|
+
errors: {
|
|
18
|
+
TEAM_FULL: z.object({ max: z.number() }),
|
|
19
|
+
DUPLICATE: z.object({ existingId: z.number() }),
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
.delete('/team/{id}', () => ({ ok: true }))
|
|
23
|
+
|
|
24
|
+
const api = client<typeof actions>()
|
|
25
|
+
|
|
26
|
+
// Never called — purely for type checking.
|
|
27
|
+
export async function _typeTest() {
|
|
28
|
+
// (1) static POST → output typed.
|
|
29
|
+
const r = await api.team.post({ id: 5 })
|
|
30
|
+
if (r.data) {
|
|
31
|
+
const max: number = r.data.max
|
|
32
|
+
void max
|
|
33
|
+
// (3) non-existent output field → must be a type error.
|
|
34
|
+
// @ts-expect-error `nope` is not a field of the typed output
|
|
35
|
+
void r.data.nope
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// (2) error union narrows on the discriminant `code` to the SPECIFIC branch,
|
|
39
|
+
// and that branch's `data` is typed (multi-member union: TEAM_FULL | DUPLICATE).
|
|
40
|
+
if (r.error && r.error.value.code === 'TEAM_FULL') {
|
|
41
|
+
const m: number = r.error.value.data.max
|
|
42
|
+
void m
|
|
43
|
+
// (4a) non-existent error-data field → must be a type error.
|
|
44
|
+
// @ts-expect-error `min` is not a field of the TEAM_FULL error data
|
|
45
|
+
void r.error.value.data.min
|
|
46
|
+
// (4c) narrowing is per-branch: DUPLICATE's `existingId` is NOT on TEAM_FULL.
|
|
47
|
+
// @ts-expect-error `existingId` belongs to the DUPLICATE branch, not TEAM_FULL
|
|
48
|
+
void r.error.value.data.existingId
|
|
49
|
+
}
|
|
50
|
+
if (r.error && r.error.value.code === 'DUPLICATE') {
|
|
51
|
+
const e: number = r.error.value.data.existingId
|
|
52
|
+
void e
|
|
53
|
+
}
|
|
54
|
+
// (4b) comparing against an undeclared error code → must be a type error.
|
|
55
|
+
if (r.error) {
|
|
56
|
+
// @ts-expect-error 'NOPE' is not a declared error code
|
|
57
|
+
void (r.error.value.code === 'NOPE')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// GET → output typed.
|
|
61
|
+
const g = await api.team.get()
|
|
62
|
+
if (g.data) {
|
|
63
|
+
const max2: number = g.data.max
|
|
64
|
+
void max2
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// (5) param path stays permissive — MUST NOT error (locks the fallback).
|
|
68
|
+
await api.team({ id: '5' }).delete()
|
|
69
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"strict": true,
|
|
4
|
+
"skipLibCheck": true,
|
|
5
|
+
"target": "ES2022",
|
|
6
|
+
"lib": ["ES2022", "DOM"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"jsx": "react-jsx",
|
|
12
|
+
"types": []
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"treaty.ts",
|
|
16
|
+
"define-actions.ts",
|
|
17
|
+
"standard-schema.ts",
|
|
18
|
+
"treaty.type-test.ts",
|
|
19
|
+
"navigation/index.ts",
|
|
20
|
+
"navigation/store.ts",
|
|
21
|
+
"navigation/active-nav.ts"
|
|
22
|
+
]
|
|
23
|
+
}
|