create-stitchkit 0.6.0 → 0.6.2
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 +40 -0
- package/UPGRADING.md +23 -0
- package/package.json +10 -10
- package/template/biome.json +1 -1
- package/template/bun.lock +195 -177
- package/template/e2e/starter.spec.ts +7 -1
- package/template/package.json +14 -8
- package/template/packages/backend/package.json +5 -5
- package/template/packages/config/package.json +3 -3
- package/template/packages/db/package.json +3 -3
- package/template/packages/frontend/package.json +15 -15
- package/template/packages/frontend/src/lib/query-client.test.ts +23 -0
- package/template/packages/frontend/src/lib/query-client.ts +15 -26
- package/template/packages/shared/package.json +2 -2
- package/templates/agent/biome.json +1 -1
- package/templates/agent/package.json +5 -5
|
@@ -26,7 +26,13 @@ test('calls the live backend through the typed contract client', async () => {
|
|
|
26
26
|
}),
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
// The release gate runs several isolated starters in parallel. A process can
|
|
30
|
+
// pass readiness and still briefly lose the first new connection while the
|
|
31
|
+
// host is saturated; retry the real typed call, while a dead backend still
|
|
32
|
+
// fails within the bounded acceptance window.
|
|
33
|
+
await expect(async () => {
|
|
34
|
+
await expect(client.status()).resolves.toEqual({ status: 'ok' });
|
|
35
|
+
}).toPass({ timeout: 5_000 });
|
|
30
36
|
});
|
|
31
37
|
|
|
32
38
|
test('publishes complete page metadata', async ({ page }) => {
|
package/template/package.json
CHANGED
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
"packages/*"
|
|
8
8
|
],
|
|
9
9
|
"catalog": {
|
|
10
|
-
"stitchkit": "^0.
|
|
10
|
+
"stitchkit": "^0.90.7"
|
|
11
|
+
},
|
|
12
|
+
"overrides": {
|
|
13
|
+
"@playwright/test": "1.63.0",
|
|
14
|
+
"playwright": "1.63.0",
|
|
15
|
+
"playwright-core": "1.63.0",
|
|
16
|
+
"zod": "4.6.5"
|
|
11
17
|
},
|
|
12
18
|
"scripts": {
|
|
13
19
|
"dev": "bun scripts/dev.ts",
|
|
@@ -37,22 +43,22 @@
|
|
|
37
43
|
"gen:declaration": "bun scripts/declaration.ts"
|
|
38
44
|
},
|
|
39
45
|
"dependencies": {
|
|
40
|
-
"dotenv": "^
|
|
46
|
+
"dotenv": "^18.0.1"
|
|
41
47
|
},
|
|
42
48
|
"devDependencies": {
|
|
43
49
|
"@app/config": "workspace:*",
|
|
44
50
|
"@app/shared": "workspace:*",
|
|
45
51
|
"@axe-core/playwright": "^4.13.0",
|
|
46
|
-
"@biomejs/biome": "^2.5.
|
|
52
|
+
"@biomejs/biome": "^2.5.14",
|
|
47
53
|
"@modelcontextprotocol/client": "^2.0.0",
|
|
48
|
-
"@playwright/test": "^1.
|
|
49
|
-
"@types/bun": "^1.4.
|
|
50
|
-
"@types/node": "^26.
|
|
51
|
-
"oxc-parser": "^0.
|
|
54
|
+
"@playwright/test": "^1.63.0",
|
|
55
|
+
"@types/bun": "^1.4.2",
|
|
56
|
+
"@types/node": "^26.6.2",
|
|
57
|
+
"oxc-parser": "^0.150.0",
|
|
52
58
|
"socket.io-client": "^4.8.3",
|
|
53
59
|
"stitchkit": "catalog:",
|
|
54
60
|
"typescript": "^7.0.2",
|
|
55
|
-
"zod": "^4.5
|
|
61
|
+
"zod": "^4.6.5"
|
|
56
62
|
},
|
|
57
63
|
"engines": {
|
|
58
64
|
"bun": ">=1.2.0",
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
"@app/db": "workspace:*",
|
|
18
18
|
"@app/shared": "workspace:*",
|
|
19
19
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
20
|
-
"@prisma/adapter-pg": "^7.
|
|
21
|
-
"@socket.io/bun-engine": "^0.1.
|
|
22
|
-
"ai": "^7.0.
|
|
20
|
+
"@prisma/adapter-pg": "^7.10.0",
|
|
21
|
+
"@socket.io/bun-engine": "^0.1.2",
|
|
22
|
+
"ai": "^7.0.107",
|
|
23
23
|
"socket.io": "^4.8.3",
|
|
24
24
|
"stitchkit": "catalog:",
|
|
25
|
-
"zod": "^4.
|
|
25
|
+
"zod": "^4.6.5"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@types/bun": "^1.4.
|
|
28
|
+
"@types/bun": "^1.4.2",
|
|
29
29
|
"typescript": "^7.0.2"
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@t3-oss/env-core": "^0.13.11",
|
|
19
|
-
"dotenv": "^
|
|
19
|
+
"dotenv": "^18.0.1",
|
|
20
20
|
"stitchkit": "catalog:",
|
|
21
|
-
"zod": "^4.
|
|
21
|
+
"zod": "^4.6.5"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@types/bun": "^1.4.
|
|
24
|
+
"@types/bun": "^1.4.2",
|
|
25
25
|
"typescript": "^7.0.2"
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@app/config": "workspace:*",
|
|
20
|
-
"@prisma/adapter-pg": "^7.
|
|
21
|
-
"@prisma/client": "^7.
|
|
20
|
+
"@prisma/adapter-pg": "^7.10.0",
|
|
21
|
+
"@prisma/client": "^7.10.0",
|
|
22
22
|
"pg": "^8.23.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/pg": "^8.23.1",
|
|
26
|
-
"prisma": "^7.
|
|
26
|
+
"prisma": "^7.10.0",
|
|
27
27
|
"typescript": "^7.0.2"
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -25,35 +25,35 @@
|
|
|
25
25
|
"@radix-ui/react-tabs": "^1.1.21",
|
|
26
26
|
"@radix-ui/react-tooltip": "^1.2.16",
|
|
27
27
|
"@t3-oss/env-nextjs": "^0.13.11",
|
|
28
|
-
"@tabler/icons-react": "^3.
|
|
29
|
-
"@tanstack/react-query": "^5.
|
|
30
|
-
"@tanstack/react-table": "^9.
|
|
28
|
+
"@tabler/icons-react": "^3.47.0",
|
|
29
|
+
"@tanstack/react-query": "^5.103.1",
|
|
30
|
+
"@tanstack/react-table": "^9.2.4",
|
|
31
31
|
"@wrksz/themes": "^1.2.0",
|
|
32
32
|
"class-variance-authority": "^0.7.1",
|
|
33
33
|
"clsx": "^2.1.1",
|
|
34
34
|
"date-fns": "^4.4.0",
|
|
35
|
-
"dotenv": "^
|
|
36
|
-
"framer-motion": "^13.
|
|
37
|
-
"next": "^16.3.
|
|
38
|
-
"next-intl": "^4.
|
|
39
|
-
"react": "^19.
|
|
40
|
-
"react-dom": "^19.
|
|
35
|
+
"dotenv": "^18.0.1",
|
|
36
|
+
"framer-motion": "^13.4.0",
|
|
37
|
+
"next": "^16.3.5",
|
|
38
|
+
"next-intl": "^4.14.5",
|
|
39
|
+
"react": "^19.3.0",
|
|
40
|
+
"react-dom": "^19.3.0",
|
|
41
41
|
"react-query-kit": "^3.3.4",
|
|
42
42
|
"recharts": "^3.10.1",
|
|
43
43
|
"shiki": "^4.4.3",
|
|
44
44
|
"socket.io-client": "^4.8.3",
|
|
45
45
|
"sonner": "^2.0.8",
|
|
46
46
|
"stitchkit": "catalog:",
|
|
47
|
-
"tailwind-merge": "^3.
|
|
47
|
+
"tailwind-merge": "^3.7.0",
|
|
48
48
|
"vaul": "^1.1.2",
|
|
49
|
-
"zod": "^4.
|
|
49
|
+
"zod": "^4.6.5"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@tailwindcss/postcss": "^4.3.3",
|
|
53
|
-
"@types/bun": "^1.4.
|
|
54
|
-
"@types/node": "^26.
|
|
55
|
-
"@types/react": "^19.
|
|
56
|
-
"@types/react-dom": "^19.
|
|
53
|
+
"@types/bun": "^1.4.2",
|
|
54
|
+
"@types/node": "^26.6.2",
|
|
55
|
+
"@types/react": "^19.3.0",
|
|
56
|
+
"@types/react-dom": "^19.3.0",
|
|
57
57
|
"babel-plugin-react-compiler": "^1.0.0",
|
|
58
58
|
"tailwindcss": "^4.3.3",
|
|
59
59
|
"tw-animate-css": "^1.4.0",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { ApiError } from 'stitchkit';
|
|
2
3
|
import { getQueryClient } from './query-client';
|
|
3
4
|
|
|
4
5
|
describe('query dehydration policy', () => {
|
|
@@ -19,4 +20,26 @@ describe('query dehydration policy', () => {
|
|
|
19
20
|
expect(shouldDehydrate(successful)).toBe(true);
|
|
20
21
|
expect(shouldDehydrate(pending)).toBe(true);
|
|
21
22
|
});
|
|
23
|
+
|
|
24
|
+
test('retries a server failure once and never retries a mutation', () => {
|
|
25
|
+
// Asserted through the decision, not through the literal: the policy is a
|
|
26
|
+
// predicate now, and `retry === 1` would pass for a client that retries an
|
|
27
|
+
// unauthorized request too.
|
|
28
|
+
const defaults = getQueryClient().getDefaultOptions();
|
|
29
|
+
const retry = defaults.queries?.retry;
|
|
30
|
+
if (typeof retry !== 'function') throw new Error('query retry policy is required');
|
|
31
|
+
const serverFailure = new ApiError('INTERNAL_SERVER_ERROR', 500);
|
|
32
|
+
expect(retry(0, serverFailure)).toBe(true);
|
|
33
|
+
expect(retry(1, serverFailure)).toBe(false);
|
|
34
|
+
expect(defaults.mutations?.retry).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('a request the user cannot repeat into success is not retried', () => {
|
|
38
|
+
const defaults = getQueryClient().getDefaultOptions();
|
|
39
|
+
const retry = defaults.queries?.retry;
|
|
40
|
+
if (typeof retry !== 'function') throw new Error('query retry policy is required');
|
|
41
|
+
for (const code of ['UNAUTHORIZED', 'FORBIDDEN', 'VALIDATION_ERROR']) {
|
|
42
|
+
expect(retry(0, new ApiError(code, 401))).toBe(false);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
22
45
|
});
|
|
@@ -1,28 +1,17 @@
|
|
|
1
|
-
import { defaultShouldDehydrateQuery, isServer, QueryClient } from '@tanstack/react-query';
|
|
2
1
|
import { cache } from 'react';
|
|
2
|
+
import { createQueryClientFactory } from 'stitchkit/react';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const getServerQueryClient = cache(createQueryClient);
|
|
22
|
-
let browserQueryClient: QueryClient | undefined;
|
|
23
|
-
|
|
24
|
-
export function getQueryClient(): QueryClient {
|
|
25
|
-
if (isServer) return getServerQueryClient();
|
|
26
|
-
if (!browserQueryClient) browserQueryClient = createQueryClient();
|
|
27
|
-
return browserQueryClient;
|
|
28
|
-
}
|
|
4
|
+
// One request-local server client and one browser singleton, both from the
|
|
5
|
+
// framework. The local construction this replaced was a second implementation
|
|
6
|
+
// of the same thing: it restated the dehydration policy and the mutation rule,
|
|
7
|
+
// and it spelled the query retry as a plain `1`, which retries an unauthorized
|
|
8
|
+
// or invalid request exactly as eagerly as a network blip. `apiErrorRetry` —
|
|
9
|
+
// the factory's default — retries what is worth retrying and nothing else.
|
|
10
|
+
// Project-specific cache configuration and mutation toasts belong in these
|
|
11
|
+
// options, never in a copy of the framework's retry predicate.
|
|
12
|
+
export const getQueryClient = createQueryClientFactory({
|
|
13
|
+
serverCache: cache,
|
|
14
|
+
queryClient: {
|
|
15
|
+
defaultOptions: { queries: { staleTime: 30_000 } },
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
"build": "bun build src/index.ts --outdir dist --target bun --packages external"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@openrouter/ai-sdk-provider": "^3.
|
|
20
|
-
"ai": "^7.0.
|
|
19
|
+
"@openrouter/ai-sdk-provider": "^3.1.0",
|
|
20
|
+
"ai": "^7.0.107",
|
|
21
21
|
"stitchkit": "file:../../../core",
|
|
22
22
|
"stitchkit-tui": "file:../../../tui",
|
|
23
|
-
"zod": "4.5
|
|
23
|
+
"zod": "4.6.5"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
27
|
-
"@types/bun": "^1.4.
|
|
28
|
-
"@types/react": "^19.
|
|
27
|
+
"@types/bun": "^1.4.2",
|
|
28
|
+
"@types/react": "^19.3.0",
|
|
29
29
|
"typescript": "^7.0.2"
|
|
30
30
|
},
|
|
31
31
|
"engines": {
|