@stacks/api-toolkit 1.12.0

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.
Files changed (85) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +74 -0
  3. package/bin/api-toolkit-git-info.js +25 -0
  4. package/dist/fastify/cache.d.ts +31 -0
  5. package/dist/fastify/cache.js +63 -0
  6. package/dist/fastify/cache.js.map +1 -0
  7. package/dist/fastify/fastify.d.ts +16 -0
  8. package/dist/fastify/fastify.js +46 -0
  9. package/dist/fastify/fastify.js.map +1 -0
  10. package/dist/fastify/index.d.ts +4 -0
  11. package/dist/fastify/index.js +21 -0
  12. package/dist/fastify/index.js.map +1 -0
  13. package/dist/fastify/openapi.d.ts +13 -0
  14. package/dist/fastify/openapi.js +23 -0
  15. package/dist/fastify/openapi.js.map +1 -0
  16. package/dist/fastify/schemas.d.ts +9 -0
  17. package/dist/fastify/schemas.js +16 -0
  18. package/dist/fastify/schemas.js.map +1 -0
  19. package/dist/helpers/events.d.ts +52 -0
  20. package/dist/helpers/events.js +93 -0
  21. package/dist/helpers/events.js.map +1 -0
  22. package/dist/helpers/index.d.ts +7 -0
  23. package/dist/helpers/index.js +25 -0
  24. package/dist/helpers/index.js.map +1 -0
  25. package/dist/helpers/is-debugging.d.ts +1 -0
  26. package/dist/helpers/is-debugging.js +15 -0
  27. package/dist/helpers/is-debugging.js.map +1 -0
  28. package/dist/helpers/iterators.d.ts +27 -0
  29. package/dist/helpers/iterators.js +74 -0
  30. package/dist/helpers/iterators.js.map +1 -0
  31. package/dist/helpers/serialize-error.d.ts +20 -0
  32. package/dist/helpers/serialize-error.js +135 -0
  33. package/dist/helpers/serialize-error.js.map +1 -0
  34. package/dist/helpers/time.d.ts +54 -0
  35. package/dist/helpers/time.js +121 -0
  36. package/dist/helpers/time.js.map +1 -0
  37. package/dist/helpers/values.d.ts +68 -0
  38. package/dist/helpers/values.js +165 -0
  39. package/dist/helpers/values.js.map +1 -0
  40. package/dist/helpers/worker-thread-init.d.ts +1 -0
  41. package/dist/helpers/worker-thread-init.js +67 -0
  42. package/dist/helpers/worker-thread-init.js.map +1 -0
  43. package/dist/helpers/worker-thread-manager.d.ts +53 -0
  44. package/dist/helpers/worker-thread-manager.js +148 -0
  45. package/dist/helpers/worker-thread-manager.js.map +1 -0
  46. package/dist/index.d.ts +7 -0
  47. package/dist/index.js +24 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/logger/index.d.ts +20 -0
  50. package/dist/logger/index.js +14 -0
  51. package/dist/logger/index.js.map +1 -0
  52. package/dist/postgres/base-pg-store.d.ts +68 -0
  53. package/dist/postgres/base-pg-store.js +109 -0
  54. package/dist/postgres/base-pg-store.js.map +1 -0
  55. package/dist/postgres/connection.d.ts +62 -0
  56. package/dist/postgres/connection.js +126 -0
  57. package/dist/postgres/connection.js.map +1 -0
  58. package/dist/postgres/errors.d.ts +5 -0
  59. package/dist/postgres/errors.js +71 -0
  60. package/dist/postgres/errors.js.map +1 -0
  61. package/dist/postgres/index.d.ts +5 -0
  62. package/dist/postgres/index.js +22 -0
  63. package/dist/postgres/index.js.map +1 -0
  64. package/dist/postgres/migrations.d.ts +47 -0
  65. package/dist/postgres/migrations.js +134 -0
  66. package/dist/postgres/migrations.js.map +1 -0
  67. package/dist/postgres/types.d.ts +14 -0
  68. package/dist/postgres/types.js +48 -0
  69. package/dist/postgres/types.js.map +1 -0
  70. package/dist/profiler/index.d.ts +2 -0
  71. package/dist/profiler/index.js +19 -0
  72. package/dist/profiler/index.js.map +1 -0
  73. package/dist/profiler/inspector-util.d.ts +29 -0
  74. package/dist/profiler/inspector-util.js +268 -0
  75. package/dist/profiler/inspector-util.js.map +1 -0
  76. package/dist/profiler/server.d.ts +6 -0
  77. package/dist/profiler/server.js +186 -0
  78. package/dist/profiler/server.js.map +1 -0
  79. package/dist/server-version/index.d.ts +8 -0
  80. package/dist/server-version/index.js +33 -0
  81. package/dist/server-version/index.js.map +1 -0
  82. package/dist/shutdown-handler/index.d.ts +17 -0
  83. package/dist/shutdown-handler/index.js +82 -0
  84. package/dist/shutdown-handler/index.js.map +1 -0
  85. package/package.json +73 -0
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildProfilerServer = buildProfilerServer;
4
+ const events_1 = require("events");
5
+ const os = require("os");
6
+ const path = require("path");
7
+ const fs = require("fs");
8
+ const helpers_1 = require("../helpers");
9
+ const promises_1 = require("node:stream/promises");
10
+ const logger_1 = require("../logger");
11
+ const fastify_1 = require("fastify");
12
+ const type_provider_typebox_1 = require("@fastify/type-provider-typebox");
13
+ const inspector_util_1 = require("./inspector-util");
14
+ const DurationSchema = type_provider_typebox_1.Type.Number({ minimum: 0 });
15
+ const SamplingIntervalSchema = type_provider_typebox_1.Type.Optional(type_provider_typebox_1.Type.Number({ minimum: 0 }));
16
+ const CpuProfiler = (fastify, options, done) => {
17
+ let existingSession;
18
+ fastify.get('/profile/cpu', {
19
+ schema: {
20
+ querystring: type_provider_typebox_1.Type.Object({
21
+ duration: DurationSchema,
22
+ sampling_interval: SamplingIntervalSchema,
23
+ }),
24
+ },
25
+ }, async (req, res) => {
26
+ if (existingSession) {
27
+ await res.status(409).send({ error: 'Profile session already in progress' });
28
+ return;
29
+ }
30
+ const seconds = req.query.duration;
31
+ const samplingInterval = req.query.sampling_interval;
32
+ const cpuProfiler = (0, inspector_util_1.initCpuProfiling)(samplingInterval);
33
+ existingSession = { instance: cpuProfiler, response: res };
34
+ try {
35
+ const filename = `cpu_${Math.round(Date.now() / 1000)}_${seconds}-seconds.cpuprofile`;
36
+ await cpuProfiler.start();
37
+ const ac = new AbortController();
38
+ const timeoutPromise = (0, helpers_1.timeout)(seconds * 1000, ac);
39
+ await Promise.race([timeoutPromise, (0, events_1.once)(res.raw, 'close')]);
40
+ if (res.raw.writableEnded || res.raw.destroyed) {
41
+ // session was cancelled
42
+ ac.abort();
43
+ return;
44
+ }
45
+ const result = await cpuProfiler.stop();
46
+ const resultString = JSON.stringify(result);
47
+ logger_1.logger.info(`[CpuProfiler] Completed, total profile report JSON string length: ${resultString.length}`);
48
+ await res
49
+ .headers({
50
+ 'Cache-Control': 'no-store',
51
+ 'Transfer-Encoding': 'chunked',
52
+ 'Content-Disposition': `attachment; filename="${filename}"`,
53
+ 'Content-Type': 'application/json; charset=utf-8',
54
+ })
55
+ .send(resultString);
56
+ }
57
+ finally {
58
+ const session = existingSession;
59
+ existingSession = undefined;
60
+ await session?.instance.dispose().catch();
61
+ }
62
+ });
63
+ fastify.get('/profile/cpu/start', {
64
+ schema: {
65
+ querystring: type_provider_typebox_1.Type.Object({
66
+ sampling_interval: SamplingIntervalSchema,
67
+ }),
68
+ },
69
+ }, async (req, res) => {
70
+ if (existingSession) {
71
+ await res.status(409).send({ error: 'Profile session already in progress' });
72
+ return;
73
+ }
74
+ const samplingInterval = req.query.sampling_interval;
75
+ const cpuProfiler = (0, inspector_util_1.initCpuProfiling)(samplingInterval);
76
+ existingSession = { instance: cpuProfiler, response: res };
77
+ await cpuProfiler.start();
78
+ const profilerRunningLogger = setInterval(() => {
79
+ if (existingSession) {
80
+ logger_1.logger.error(`CPU profiler has been enabled for a long time`);
81
+ }
82
+ else {
83
+ clearInterval(profilerRunningLogger);
84
+ }
85
+ }, 10_000).unref();
86
+ await res.send('CPU profiler started');
87
+ });
88
+ fastify.get('/profile/cpu/stop', async (req, res) => {
89
+ if (!existingSession) {
90
+ await res.status(409).send({ error: 'No profile session in progress' });
91
+ return;
92
+ }
93
+ if (existingSession.instance.sessionType !== 'cpu') {
94
+ await res.status(409).send({ error: 'No CPU profile session in progress' });
95
+ return;
96
+ }
97
+ try {
98
+ const elapsedSeconds = existingSession.instance.stopwatch.getElapsedSeconds();
99
+ const timestampSeconds = Math.round(Date.now() / 1000);
100
+ const filename = `cpu_${timestampSeconds}_${elapsedSeconds}-seconds.cpuprofile`;
101
+ const result = await existingSession.instance.stop();
102
+ const resultString = JSON.stringify(result);
103
+ logger_1.logger.info(`[CpuProfiler] Completed, total profile report JSON string length: ${resultString.length}`);
104
+ await res
105
+ .headers({
106
+ 'Cache-Control': 'no-store',
107
+ 'Transfer-Encoding': 'chunked',
108
+ 'Content-Disposition': `attachment; filename="${filename}"`,
109
+ 'Content-Type': 'application/json; charset=utf-8',
110
+ })
111
+ .send(resultString);
112
+ }
113
+ finally {
114
+ const session = existingSession;
115
+ existingSession = undefined;
116
+ await session?.instance.dispose().catch();
117
+ }
118
+ });
119
+ fastify.get('/profile/heap_snapshot', async (req, res) => {
120
+ if (existingSession) {
121
+ await res.status(409).send({ error: 'Profile session already in progress' });
122
+ return;
123
+ }
124
+ const filename = `heap_${Math.round(Date.now() / 1000)}.heapsnapshot`;
125
+ const tmpFile = path.join(os.tmpdir(), filename);
126
+ const fileWriteStream = fs.createWriteStream(tmpFile);
127
+ const heapProfiler = (0, inspector_util_1.initHeapSnapshot)(fileWriteStream);
128
+ existingSession = { instance: heapProfiler, response: res };
129
+ try {
130
+ // Taking a heap snapshot (with current implementation) is a one-shot process ran to get the
131
+ // applications current heap memory usage, rather than something done over time. So start and
132
+ // stop without waiting.
133
+ await heapProfiler.start();
134
+ const result = await heapProfiler.stop();
135
+ logger_1.logger.info(`[HeapProfiler] Completed, total snapshot byte size: ${result.totalSnapshotByteSize}`);
136
+ await (0, promises_1.pipeline)(fs.createReadStream(tmpFile), res.raw);
137
+ await res.headers({
138
+ 'Cache-Control': 'no-store',
139
+ 'Transfer-Encoding': 'chunked',
140
+ 'Content-Disposition': `attachment; filename="${filename}"`,
141
+ 'Content-Type': 'application/json; charset=utf-8',
142
+ });
143
+ }
144
+ finally {
145
+ const session = existingSession;
146
+ existingSession = undefined;
147
+ await session?.instance.dispose().catch();
148
+ try {
149
+ fileWriteStream.destroy();
150
+ }
151
+ catch (_) { }
152
+ try {
153
+ logger_1.logger.info(`[HeapProfiler] Cleaning up tmp file ${tmpFile}`);
154
+ fs.unlinkSync(tmpFile);
155
+ }
156
+ catch (_) { }
157
+ }
158
+ });
159
+ fastify.get('/profile/cancel', async (req, res) => {
160
+ if (!existingSession) {
161
+ await res.status(409).send({ error: 'No existing profile session is exists to cancel' });
162
+ return;
163
+ }
164
+ const session = existingSession;
165
+ await session.instance.stop().catch();
166
+ await session.instance.dispose().catch();
167
+ await session.response.status(500).send('cancelled');
168
+ existingSession = undefined;
169
+ await Promise.resolve();
170
+ await res.send({ ok: 'existing profile session stopped' });
171
+ });
172
+ done();
173
+ };
174
+ /**
175
+ * Creates a Fastify server that controls a CPU profiler.
176
+ * @returns Fastify instance
177
+ */
178
+ async function buildProfilerServer() {
179
+ const fastify = (0, fastify_1.default)({
180
+ trustProxy: true,
181
+ logger: logger_1.PINO_LOGGER_CONFIG,
182
+ }).withTypeProvider();
183
+ await fastify.register(CpuProfiler);
184
+ return fastify;
185
+ }
186
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/profiler/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ interface ServerVersion {
2
+ branch: string;
3
+ commit: string;
4
+ tag: string;
5
+ }
6
+ export declare function getServerVersion(): ServerVersion;
7
+ export declare const SERVER_VERSION: ServerVersion;
8
+ export {};
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SERVER_VERSION = void 0;
4
+ exports.getServerVersion = getServerVersion;
5
+ const node_fs_1 = require("node:fs");
6
+ const is_debugging_1 = require("../helpers/is-debugging");
7
+ function getServerVersion() {
8
+ if (process.env.NODE_ENV === 'test') {
9
+ return {
10
+ branch: 'test',
11
+ commit: '123456',
12
+ tag: 'v0.0.1',
13
+ };
14
+ }
15
+ try {
16
+ const [branch, commit, tag] = (0, node_fs_1.readFileSync)('.git-info', 'utf-8').split('\n');
17
+ return { branch, commit, tag };
18
+ }
19
+ catch (error) {
20
+ // If .git-info file does not exist and we are debugging, return a default version
21
+ const fileNotExists = error.code === 'ENOENT';
22
+ if (fileNotExists && (0, is_debugging_1.isDebugging)()) {
23
+ return {
24
+ branch: 'debugging',
25
+ commit: '123456',
26
+ tag: 'v0.0.1',
27
+ };
28
+ }
29
+ throw error;
30
+ }
31
+ }
32
+ exports.SERVER_VERSION = getServerVersion();
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server-version/index.ts"],"names":[],"mappings":";;;AASA,4CAwBC;AAjCD,qCAAuC;AACvC,0DAAsD;AAQtD,SAAgB,gBAAgB;IAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,OAAO;YACL,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,QAAQ;YAChB,GAAG,EAAE,QAAQ;SACd,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,GAAG,IAAA,sBAAY,EAAC,WAAW,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,kFAAkF;QAClF,MAAM,aAAa,GAAI,KAA+B,CAAC,IAAI,KAAK,QAAQ,CAAC;QACzE,IAAI,aAAa,IAAI,IAAA,0BAAW,GAAE,EAAE,CAAC;YACnC,OAAO;gBACL,MAAM,EAAE,WAAW;gBACnB,MAAM,EAAE,QAAQ;gBAChB,GAAG,EAAE,QAAQ;aACd,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAEY,QAAA,cAAc,GAAG,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,17 @@
1
+ type ShutdownHandler = () => void | PromiseLike<void>;
2
+ type ShutdownConfig = {
3
+ name: string;
4
+ handler: ShutdownHandler;
5
+ forceKillable: boolean;
6
+ forceKillHandler?: ShutdownHandler;
7
+ };
8
+ /**
9
+ * Start a graceful API shutdown.
10
+ */
11
+ export declare function shutdown(): Promise<void>;
12
+ /**
13
+ * Register shutdown handlers for different API components.
14
+ * @param configs - Array of shutdown configurations
15
+ */
16
+ export declare function registerShutdownConfig(...configs: ShutdownConfig[]): void;
17
+ export {};
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shutdown = shutdown;
4
+ exports.registerShutdownConfig = registerShutdownConfig;
5
+ const time_1 = require("../helpers/time");
6
+ const logger_1 = require("../logger");
7
+ const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM'];
8
+ const shutdownConfigs = [];
9
+ let isShuttingDown = false;
10
+ /**
11
+ * Start a graceful API shutdown.
12
+ */
13
+ async function shutdown() {
14
+ if (isShuttingDown) {
15
+ return;
16
+ }
17
+ isShuttingDown = true;
18
+ const timeoutMs = parseInt(process.env['STACKS_SHUTDOWN_FORCE_KILL_TIMEOUT'] ?? '60') * 1000;
19
+ let errorEncountered = false;
20
+ for (const config of shutdownConfigs) {
21
+ try {
22
+ logger_1.logger.info(`Closing ${config.name}...`);
23
+ const gracefulShutdown = await (0, time_1.resolveOrTimeout)(Promise.resolve(config.handler()), timeoutMs, !config.forceKillable, () => logger_1.logger.error(`${config.name} is taking longer than expected to shutdown, possibly hanging indefinitely`));
24
+ if (!gracefulShutdown) {
25
+ if (config.forceKillable && config.forceKillHandler) {
26
+ await Promise.resolve(config.forceKillHandler());
27
+ }
28
+ logger_1.logger.error(`${config.name} was force killed after taking longer than ${timeoutMs}ms to shutdown`);
29
+ }
30
+ else {
31
+ logger_1.logger.info(`${config.name} closed`);
32
+ }
33
+ }
34
+ catch (error) {
35
+ errorEncountered = true;
36
+ logger_1.logger.error(error, `Error running ${config.name} shutdown handler`);
37
+ }
38
+ }
39
+ if (errorEncountered) {
40
+ process.exit(1);
41
+ }
42
+ else {
43
+ logger_1.logger.info('App shutdown successful.');
44
+ process.exit();
45
+ }
46
+ }
47
+ let shutdownSignalsRegistered = false;
48
+ function registerShutdownSignals() {
49
+ if (shutdownSignalsRegistered) {
50
+ return;
51
+ }
52
+ shutdownSignalsRegistered = true;
53
+ SHUTDOWN_SIGNALS.forEach(sig => {
54
+ process.once(sig, () => {
55
+ logger_1.logger.info(`Shutting down... received signal: ${sig}`);
56
+ void shutdown();
57
+ });
58
+ });
59
+ process.once('unhandledRejection', error => {
60
+ logger_1.logger.error(error, 'unhandledRejection');
61
+ logger_1.logger.error('Shutting down... received unhandledRejection.');
62
+ void shutdown();
63
+ });
64
+ process.once('uncaughtException', error => {
65
+ logger_1.logger.error(error, 'uncaughtException');
66
+ logger_1.logger.error('Shutting down... received uncaughtException.');
67
+ void shutdown();
68
+ });
69
+ process.once('beforeExit', () => {
70
+ logger_1.logger.error('Shutting down... received beforeExit.');
71
+ void shutdown();
72
+ });
73
+ }
74
+ /**
75
+ * Register shutdown handlers for different API components.
76
+ * @param configs - Array of shutdown configurations
77
+ */
78
+ function registerShutdownConfig(...configs) {
79
+ registerShutdownSignals();
80
+ shutdownConfigs.push(...configs);
81
+ }
82
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shutdown-handler/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@stacks/api-toolkit",
3
+ "version": "1.12.0",
4
+ "description": "API development toolkit",
5
+ "main": "./dist/index.js",
6
+ "typings": "./dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "rimraf ./dist && tsc --project tsconfig.build.json && copyfiles -u 1 ./src/server-version/*.mjs ./dist",
9
+ "test": "jest --runInBand",
10
+ "lint:eslint": "eslint . --ext .js,.jsx,.ts,.tsx -f unix",
11
+ "lint:prettier": "prettier --check src/**/*.ts",
12
+ "testenv:run": "docker compose -f docker/docker-compose.dev.postgres.yml up",
13
+ "testenv:stop": "docker compose -f docker/docker-compose.dev.postgres.yml down -v -t 0",
14
+ "testenv:logs": "docker compose -f docker/docker-compose.dev.postgres.yml logs -t -f"
15
+ },
16
+ "bin": {
17
+ "api-toolkit-git-info": "./bin/api-toolkit-git-info.js"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/stx-labs/api-toolkit.git"
22
+ },
23
+ "keywords": [
24
+ "api",
25
+ "toolkit"
26
+ ],
27
+ "files": [
28
+ "dist/",
29
+ "bin/"
30
+ ],
31
+ "author": "Stacks Labs",
32
+ "license": "Apache 2.0",
33
+ "bugs": {
34
+ "url": "https://github.com/stx-labs/api-toolkit/issues"
35
+ },
36
+ "homepage": "https://github.com/stx-labs/api-toolkit#readme",
37
+ "prettier": "@stacks/prettier-config",
38
+ "engines": {
39
+ "node": ">=22"
40
+ },
41
+ "devDependencies": {
42
+ "@commitlint/cli": "^17.5.0",
43
+ "@commitlint/config-conventional": "^17.4.4",
44
+ "@stacks/eslint-config": "^1.2.0",
45
+ "@types/jest": "^29.5.14",
46
+ "@typescript-eslint/eslint-plugin": "^5.56.0",
47
+ "@typescript-eslint/parser": "^5.56.0",
48
+ "babel-jest": "^29.5.0",
49
+ "copyfiles": "^2.4.1",
50
+ "eslint": "^8.36.0",
51
+ "eslint-plugin-prettier": "^4.2.1",
52
+ "eslint-plugin-tsdoc": "^0.2.17",
53
+ "husky": "^8.0.3",
54
+ "jest": "^29.7.0",
55
+ "prettier": "^2.8.6",
56
+ "rimraf": "^4.4.1",
57
+ "ts-jest": "^29.3.1",
58
+ "ts-node": "^10.9.2",
59
+ "typescript": "^5.8.2"
60
+ },
61
+ "dependencies": {
62
+ "@fastify/cors": "^8.0.0",
63
+ "@fastify/swagger": "^8.3.1",
64
+ "@fastify/type-provider-typebox": "^3.2.0",
65
+ "@sinclair/typebox": "^0.28.20",
66
+ "@types/node": "^22.14.1",
67
+ "fastify": "^4.3.0",
68
+ "fastify-metrics": "^10.2.0",
69
+ "node-pg-migrate": "^6.2.2",
70
+ "pino": "^8.11.0",
71
+ "postgres": "^3.3.4"
72
+ }
73
+ }