create-stitchkit 0.3.1 → 0.3.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 CHANGED
@@ -6,6 +6,21 @@ is declared in the template root catalog.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.2] — 2026-08-17
10
+
11
+ ### Changed
12
+
13
+ - **The template targets Stitchkit 0.50.0 and binds process signals through the
14
+ framework.** Generated backends replace the hand-written shutdown coordinator
15
+ with `bindProcessSignals(server, …)`: MCP and Prisma close in `onComplete`, the
16
+ exit code is set there, and failures are reported by phase. The manual version
17
+ the template used to ship reported a failing `mcp.close()` as a failed
18
+ shutdown, did nothing on a third signal, and collapsed the grace period when a
19
+ supervisor delivered two signals at once.
20
+ - **The repository example declares its domain error message once.**
21
+ `GITHUB_UNAVAILABLE` carries its text in the `defineErrors` definition instead
22
+ of repeating it at the throw site.
23
+
9
24
  ## [0.3.1] — 2026-08-15
10
25
 
11
26
  ### Changed
@@ -4,6 +4,8 @@ import { z } from 'zod';
4
4
  export const { errors: domainErrors, codes: domainErrorCodes } = defineErrors({
5
5
  GITHUB_UNAVAILABLE: {
6
6
  status: 503,
7
+ // Declared once here instead of at every throw site.
8
+ message: 'GitHub repository data is temporarily unavailable',
7
9
  details: z.object({ cause: z.string() }),
8
10
  },
9
11
  });
@@ -197,7 +197,6 @@ export class GitHubRepositoryCache {
197
197
  } catch (error) {
198
198
  if (previous) return serialize(previous, 'stale');
199
199
  throw domainErrors.GITHUB_UNAVAILABLE({
200
- message: 'GitHub repository data is temporarily unavailable',
201
200
  details: { cause: error instanceof Error ? error.message : 'Unknown upstream error' },
202
201
  hint: 'Retry after the upstream service recovers',
203
202
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-stitchkit",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Create a production-shaped Stitchkit application",
5
5
  "license": "MIT",
6
6
  "author": "Max Listov <maxlistov@gmail.com>",
package/template/bun.lock CHANGED
@@ -138,7 +138,7 @@
138
138
  },
139
139
  },
140
140
  "catalog": {
141
- "stitchkit": "^0.49.2",
141
+ "stitchkit": "^0.50.0",
142
142
  },
143
143
  "packages": {
144
144
  "@ai-sdk/gateway": ["@ai-sdk/gateway@4.0.46", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.25", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LIAO6kAG8fpXQb9L0iwPk1FIbXftvqnyC56v5NEAzeWTeL8fUsy/Hx86VPBTWEDFdwbVprjWifJOAqS6AOj3mA=="],
@@ -1117,7 +1117,7 @@
1117
1117
 
1118
1118
  "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
1119
1119
 
1120
- "stitchkit": ["stitchkit@0.49.2", "", { "dependencies": { "ky": "^2.0.2" }, "peerDependencies": { "@modelcontextprotocol/ext-apps": "^1.7.2", "@modelcontextprotocol/server": "^2.0.0", "@socket.io/bun-engine": "^0.1.1", "@socket.io/component-emitter": "^3.1.2", "@tanstack/react-query": ">=5", "@types/bun": "^1.3.14", "ai": "^7.0.0", "react": ">=18", "react-query-kit": "^3.3.3", "socket.io": "^4.8.3", "socket.io-client": "^4.8.3", "srvx": "^0.12.5", "zod": "^4.4.3" }, "optionalPeers": ["@modelcontextprotocol/ext-apps", "@modelcontextprotocol/server", "@socket.io/bun-engine", "@socket.io/component-emitter", "@tanstack/react-query", "@types/bun", "ai", "react", "react-query-kit", "socket.io", "socket.io-client", "srvx"] }, "sha512-QP0I//fs/khC+bTqYungjpZskAseQAB/Lm8UOx3mZDx+rmYtdsBhlAn0I0hBYE/du9jag5rE032s9HrZgT2VXg=="],
1120
+ "stitchkit": ["stitchkit@0.50.0", "", { "dependencies": { "ky": "^2.0.2" }, "peerDependencies": { "@modelcontextprotocol/ext-apps": "^1.7.2", "@modelcontextprotocol/server": "^2.0.0", "@socket.io/bun-engine": "^0.1.1", "@socket.io/component-emitter": "^3.1.2", "@tanstack/react-query": ">=5", "@types/bun": "^1.3.14", "ai": "^7.0.0", "react": ">=18", "react-query-kit": "^3.3.3", "socket.io": "^4.8.3", "socket.io-client": "^4.8.3", "srvx": "^0.12.5", "zod": "^4.4.3" }, "optionalPeers": ["@modelcontextprotocol/ext-apps", "@modelcontextprotocol/server", "@socket.io/bun-engine", "@socket.io/component-emitter", "@tanstack/react-query", "@types/bun", "ai", "react", "react-query-kit", "socket.io", "socket.io-client", "srvx"] }, "sha512-lMadqgQ9aryAhULyA0biVjx9bn86HOUhcUj809TyHy2MuUZSnL9qI4fiByQbVAqlxW6i1a1RLAeguEJeu6jwWg=="],
1121
1121
 
1122
1122
  "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
1123
1123
 
@@ -7,7 +7,7 @@
7
7
  "packages/*"
8
8
  ],
9
9
  "catalog": {
10
- "stitchkit": "^0.49.2"
10
+ "stitchkit": "^0.50.0"
11
11
  },
12
12
  "scripts": {
13
13
  "dev": "bun scripts/dev.ts",
@@ -1,7 +1,12 @@
1
1
  import { env } from '@app/config';
2
2
  import { appIdentity } from '@app/config/identity';
3
3
  import { wrapInRequestContext } from 'stitchkit/observability';
4
- import { createServer, generateOpenApiDocument, openApiRoute } from 'stitchkit/server';
4
+ import {
5
+ bindProcessSignals,
6
+ createServer,
7
+ generateOpenApiDocument,
8
+ openApiRoute,
9
+ } from 'stitchkit/server';
5
10
  import { createMcpHandler, createMcpHttpRoute } from 'stitchkit/tools';
6
11
  import { prisma } from './lib/db';
7
12
  import { createSurface } from './surface';
@@ -39,33 +44,22 @@ async function main(): Promise<void> {
39
44
  wrapFetch: (fetch) => wrapInRequestContext(fetch),
40
45
  });
41
46
 
42
- const shutdownController = new AbortController();
43
- let shutdownPromise: Promise<void> | undefined;
44
-
45
- function shutdown(): Promise<void> {
46
- if (shutdownPromise) {
47
- shutdownController.abort();
48
- return shutdownPromise;
49
- }
50
-
51
- shutdownPromise = (async () => {
52
- await server.shutdown({
53
- gracePeriodMs: 30_000,
54
- signal: shutdownController.signal,
55
- });
47
+ // The server owns HTTP and Socket.IO; MCP, Prisma and the exit code are the
48
+ // application's and close after the drain. A second signal forces this same
49
+ // shutdown, a third hands the signal back to its default disposition.
50
+ bindProcessSignals(server, {
51
+ shutdown: { gracePeriodMs: 30_000 },
52
+ onComplete: async (result) => {
56
53
  await mcp.close();
57
54
  await prisma.$disconnect();
58
- })();
59
- return shutdownPromise;
60
- }
61
-
62
- const onSignal = () =>
63
- void shutdown().catch((error: unknown) => {
64
- console.error('Shutdown failed', error);
65
- });
55
+ process.exitCode = result.outcome === 'clean' ? 0 : 1;
56
+ },
57
+ onError: (phase, error) => {
58
+ console.error(`Shutdown failed during ${phase}`, error);
59
+ process.exitCode = 1;
60
+ },
61
+ });
66
62
 
67
- process.on('SIGTERM', onSignal);
68
- process.on('SIGINT', onSignal);
69
63
  console.log(`API listening on http://127.0.0.1:${env.API_PORT}`);
70
64
  }
71
65