{"_id":"@apispects/core","name":"@apispects/core","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"@apispects/core","private":false,"version":"0.0.1","type":"module","main":"dist/apispects.es.js","types":"dist/index.d.ts","scripts":{"dev":"vite","build":"tsc && vite build","preview":"vite preview"},"peerDependencies":{"zod":"^3.25.74"},"devDependencies":{"express":"^5.1.0","typescript":"~5.8.3","vite":"^7.1.2"},"gitHead":"8b98c9d5b5fae2a5b48c7cfb3ef940e771612a71","description":"**One spec → typed router + typed client + typed errors. Zero drift. Superb DX.**","_id":"@apispects/core@0.0.1","_nodeVersion":"20.4.0","_npmVersion":"9.7.2","dist":{"integrity":"sha512-1aIYP78RERfXUhSYjfIoetlHE9eqhgeCFgvfKb2Ml/V6ePvgSLZLjxnjZR+ApB8WRYP8XRszffMLTshh0S/J0g==","shasum":"56ad38a9174530d4ed064b3879be5a2b4fda938b","tarball":"https://registry.npmjs.org/@apispects/core/-/core-0.0.1.tgz","fileCount":4,"unpackedSize":11156,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD2LiK+UzZLi+xtItG8N8x1/fJZJiNGdASumemvtXDyAwIhAO9hCKL1oY9lp1xoChp6tWoK2J3bYpconEWHLOqsrRIr"}]},"_npmUser":{"name":"apispects","email":"djuleayo+apispects@gmail.com"},"directories":{},"maintainers":[{"name":"apispects","email":"djuleayo+apispects@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_0.0.1_1757276917964_0.7975864107471282"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-07T20:28:37.839Z","0.0.1":"2025-09-07T20:28:38.183Z","modified":"2025-09-07T20:28:38.472Z"},"maintainers":[{"name":"apispects","email":"djuleayo+apispects@gmail.com"}],"description":"**One spec → typed router + typed client + typed errors. Zero drift. Superb DX.**","readme":"# APISPECTS\n\n**One spec → typed router + typed client + typed errors. Zero drift. Superb DX.**\n\n* maximum code sharing between nodes\n* fully typed end to end (including errors)\n* uniform error handling\n* generates **router** and **apiClient** and router from same spec(SSOT/contract)\n\nOne SSOT for routes, payloads, errors, and client calls — with superb DX.\n\n**Install**\n\n`npm i @apispects/core`\n\n## Quickstart\n\n1. **Declare your spec**\n\n```ts\nexport const authRouter = {\n  register_post: {\n    bodySchema: registerRequestSchema,\n    responseSchema: z.object({ token: z.string() }),\n    cbErrorSchema: registrationError,\n  },\n  login_post: {\n    bodySchema: loginRequestSchema,\n    responseSchema: z.object({ token: z.string() }),\n    cbErrorSchema: loginErrors,\n  },\n  refreshToken_post: {\n    headerSchema: authHeader,\n    cbErrorSchema: z.null(),\n    responseSchema: z.object({ token: z.string() }),\n  }\n} as const satisfies ApiSpec;\n\nexport const apiSpec = {\n  api: {\n    auth: authRouter,\n    macro: macroRouter\n  }\n} as const satisfies ApiSpec; //key line TS 5 dependent\n``` \n\nDeclare schemas, sastisfy `ApiSpec`, and generate both router and client:\n\n\n```ts\nconst { router: apiRouter } = makeApi(apiSpec, {}, express.Router)\n\n\nexport const registerUser = async (email: string, name: string, password: string) => {\n  const existingUser = await prismaClient.user.findUnique({\n    where: { email }\n  })\n\n  if (existingUser) return 'User with given email already exists';\n\n  const user = await prismaClient.user.create({\n    data: { email, name, \n      passwords: { create: { password: await bcrypt.hash(password, 6) } }\n    },\n  })\n\n  return user\n}\n\n//everything fully types out of the box, autocomplete DX\nmakeController(authRouter.register_post, async ({ body: { email, name, password} }) => {\n  const user = await registerUser(email, name, password);\n  if (typeof user === 'string') return user; // error message\n  return { token: jwtSign({ userId: user.id }) };\n})\n```\n\nand client\n\n```ts\nexport const { apiClient } = makeApi(apiSpec, {\n  baseUrl: 'http://localhost:3033'\n})\n```","readmeFilename":"README.md","_rev":"1-598de3c91816801511d4e59a63a72b44"}