{"_id":"@api-kickstart/api-kickstart","_rev":"17-350930588127bd8c3799c844f6365264","name":"@api-kickstart/api-kickstart","dist-tags":{"latest":"2.5.0"},"versions":{"1.0.0":{"name":"@api-kickstart/api-kickstart","version":"1.0.0","license":"MIT","_id":"@api-kickstart/api-kickstart@1.0.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"291f285ed26f585e9104a06070e26a6fe3d49894","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.0.0.tgz","fileCount":550,"integrity":"sha512-R7vF/2KLvsh57rRdOyWNYKny/QNAYKzE04eQAR0ienZ95UGRVBztfcFg449pGHQ7djjb+DKd3PLzBxeWr8O0Ug==","signatures":[{"sig":"MEQCIGfg8AvN9DzNFk834vpJ6SEhjGlYM08YXfaQqKQEVnrYAiBOyZ+NKbAnojpzghapubg36CDkxbsrgrtZi708iGBPAg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":453022},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"c9e42fb3d1c7b3506e8f7af58c17520274ac3084","scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"jose":"^5.9.6","koa-bodyparser":"^4.4.1","@hono/node-server":"^1.13.0","zod-to-json-schema":"^3.23.5"},"_hasShrinkwrap":false,"devDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0","fastify":"^4.28.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","@types/pg":"^8.11.6","sequelize":"^6.37.0","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","reflect-metadata":"^0.2.2","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","@aws-sdk/client-sqs":"^3.635.0","aws-sdk-client-mock":"^4.1.0","@google-cloud/pubsub":"^4.9.0","@types/koa-bodyparser":"^4.3.12","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","reflect-metadata":"^0.2.2","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependenciesMeta":{"pg":{"optional":true},"joi":{"optional":true},"koa":{"optional":true},"yup":{"optional":true},"zod":{"optional":true},"hono":{"optional":true},"knex":{"optional":true},"mqtt":{"optional":true},"nats":{"optional":true},"pino":{"optional":true},"rxjs":{"optional":true},"bullmq":{"optional":true},"amqplib":{"optional":true},"express":{"optional":true},"fastify":{"optional":true},"ioredis":{"optional":true},"kafkajs":{"optional":true},"mongodb":{"optional":true},"typeorm":{"optional":true},"valibot":{"optional":true},"mongoose":{"optional":true},"sequelize":{"optional":true},"drizzle-orm":{"optional":true},"joi-to-json":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"reflect-metadata":{"optional":true},"@sinclair/typebox":{"optional":true},"@aws-sdk/client-s3":{"optional":true},"@aws-sdk/client-sqs":{"optional":true},"@google-cloud/pubsub":{"optional":true},"@valibot/to-json-schema":{"optional":true},"@nestjs/platform-express":{"optional":true},"@sodaru/yup-to-json-schema":{"optional":true},"@aws-sdk/s3-request-presigner":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.0.0_1786808913673_0.6741816090302959","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@api-kickstart/api-kickstart","version":"1.0.1","license":"MIT","_id":"@api-kickstart/api-kickstart@1.0.1","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"8efbb56084af9ba4ce9deb6a13a4e710ab4630b4","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.0.1.tgz","fileCount":552,"integrity":"sha512-JZ3t1mK4YcZ1CPgOA+8YNafey/fDmWKNnnsTjkvgVCkuwakVO04s4bB5iKeo9kd2l80SDui6n64Iq/vhPa6dHQ==","signatures":[{"sig":"MEUCIQC5TNu7mPLwtsmCvLESQOZotmsHrSGTYWwj+GnJjtih8AIgJTG9VnmwhPStJXXoIMKUxUEbd59qy5aCFN2vyVScPRY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":554229},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"ef94a7e97e1abcd3b44202a464b9e1c955e9c064","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"jose":"^5.9.6","koa-bodyparser":"^4.4.1","@hono/node-server":"^1.13.0","zod-to-json-schema":"^3.23.5"},"_hasShrinkwrap":false,"devDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0","fastify":"^4.28.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","@types/pg":"^8.11.6","sequelize":"^6.37.0","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","reflect-metadata":"^0.2.2","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","@aws-sdk/client-sqs":"^3.635.0","aws-sdk-client-mock":"^4.1.0","@google-cloud/pubsub":"^4.9.0","@types/koa-bodyparser":"^4.3.12","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","reflect-metadata":"^0.2.2","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependenciesMeta":{"pg":{"optional":true},"joi":{"optional":true},"koa":{"optional":true},"yup":{"optional":true},"zod":{"optional":true},"hono":{"optional":true},"knex":{"optional":true},"mqtt":{"optional":true},"nats":{"optional":true},"pino":{"optional":true},"rxjs":{"optional":true},"bullmq":{"optional":true},"amqplib":{"optional":true},"express":{"optional":true},"fastify":{"optional":true},"ioredis":{"optional":true},"kafkajs":{"optional":true},"mongodb":{"optional":true},"typeorm":{"optional":true},"valibot":{"optional":true},"mongoose":{"optional":true},"sequelize":{"optional":true},"drizzle-orm":{"optional":true},"joi-to-json":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"reflect-metadata":{"optional":true},"@sinclair/typebox":{"optional":true},"@aws-sdk/client-s3":{"optional":true},"@aws-sdk/client-sqs":{"optional":true},"@google-cloud/pubsub":{"optional":true},"@valibot/to-json-schema":{"optional":true},"@nestjs/platform-express":{"optional":true},"@sodaru/yup-to-json-schema":{"optional":true},"@aws-sdk/s3-request-presigner":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.0.1_1786978178032_0.40360070321873076","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@api-kickstart/api-kickstart","version":"1.1.0","license":"MIT","_id":"@api-kickstart/api-kickstart@1.1.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"c4c0fde8190a4ddc4118da18366417de3ee69218","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.1.0.tgz","fileCount":552,"integrity":"sha512-6JU+gp08A2ufryH6n3EBCnHb/gds+FmIKl1NWiFSVDWHmlJTTAhGOD0lFpmLiJxq59w5LzRyLhL5hDljy3Dasg==","signatures":[{"sig":"MEUCIQDxsEySMddRqxthFv56sQkk0O22iSohmWjxZQmcSMkXJAIgNegjNcfboUvlQ+GDT6XjUm2cR7ErUWT138cpeJrOPBc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":550513},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"6690ed446dc598ffbe54671cb2f0456c0115870d","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.1.0_1786978783543_0.33815526335939494","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@api-kickstart/api-kickstart","version":"1.1.1","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@1.1.1","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"5c15dd06919d5518b984a30bb95dd94aebd061eb","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.1.1.tgz","fileCount":552,"integrity":"sha512-cj7jC6wu7JK3sztXHqW7d6yb/B2QhQGVskL6CIa+vvujKZAHyWDBvcZfgdIP2ksT66/DdMRTOulrqbFNGWUy+g==","signatures":[{"sig":"MEUCIQDsDncX8YqAbJsxX7D4TxsfH7BqImlBHEGjg3lRpO5Q3AIgX/IibGkWd4J2bBUe0IDX5WQqJ7pLw2qHSx5ReI3OoEg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":551210},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"1daf165a7252086448802b070a2b8607a48ba3a1","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.1.1_1786979236179_0.4381280374676808","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@api-kickstart/api-kickstart","version":"1.1.2","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@1.1.2","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"7ed490149bde5aa19605af476f45ec1cf10511fa","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.1.2.tgz","fileCount":553,"integrity":"sha512-XMBNo5iZK3czegThUpqQsn9Fi0bS6AX9X4XNzjV20jX11lH5niiu7TWQzrnAElDYnT4bQhOyAwJsmvbo7mUn7g==","signatures":[{"sig":"MEQCIGwOz1qiM4Ui2QzpqUwSXO025ITtLdTcFQnjQnfX82fkAiBnboTeEcoZgAPNTw6l224rgz45jjyzQMhCg0f2wo4Ekg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":555331},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"63e29566fd08e38ef392db0c2debe193c973b128","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.1.2_1786979813890_0.9214524705140046","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@api-kickstart/api-kickstart","version":"1.2.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@1.2.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"d336506424b220f718d92b151673712db32b5c3a","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.2.0.tgz","fileCount":557,"integrity":"sha512-lhRw3PO5MkR3b1XZ6868bNPMM7mvtSWTNcMhzNCHs1OBgJDA1B/oz8GWfMuAN1H3cUItJiTdALAMrjg/Fr5Z3w==","signatures":[{"sig":"MEQCIEJy5VlzPxaMZXVHM7ba+E2rJ0NTLcGITzzKshyb0/knAiA2AHS5p+tA3iyT5dcFjQoe7NEsof7ZURbrUHYqJkYXtg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":563655},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"1b1143208f1f940ee54de752da88af816e5d8476","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.2.0_1786980388060_0.6822104209914499","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@api-kickstart/api-kickstart","version":"1.3.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@1.3.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"32dd3477d11ac6d77a0079208fb2b2c03cbb9bce","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.3.0.tgz","fileCount":561,"integrity":"sha512-Ayt5csuj8hbrTc+UdhIp5jbkYM96taHvfLxU7AJgsdgGgJz5FkWN6+1BpiqHM8UIKJU05xbn8uVQrJ9mGQLuGw==","signatures":[{"sig":"MEUCIG+XywTggIqBR+RGcSQ3oRQmAntOogm6zX1zcIVG0CCgAiEA+2XwIV0yVzAHtOrUM+iOBLdjx6MyJ53rRRslM4YuDrg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":589197},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"e0cc6e6c5bfc90ef355bdb4f50ba2d4f1b8edcbf","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.3.0_1786981044763_0.4615821603724535","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@api-kickstart/api-kickstart","version":"1.4.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@1.4.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"95ebbec5cda62a6c0046b8c823f1c906e0213e9f","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.4.0.tgz","fileCount":565,"integrity":"sha512-Ha/itQVQhF5DTyQ1zhJFHs68/3pXfivjQvbpSH43q8venICmNOHloMdxY1LFSNHR4QIuZXZNSoD3ASOhK34RNg==","signatures":[{"sig":"MEUCIBBeYIRhIKVk5KYq7DbQwqfnAZ2u41ftsXc3PxHl4Bv2AiEAxXaH5Jp8RLeW5uo47/HJYJ6eLgj8EUPCPD0E/KWpbbM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":609201},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"f44160e13f5957bbab12a1848b4ae333e68b0ad9","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.4.0_1786981481821_0.2998348804217372","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@api-kickstart/api-kickstart","version":"1.5.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@1.5.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"6d0f134ea306137911506a8825b590d684bf36c9","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.5.0.tgz","fileCount":565,"integrity":"sha512-LgbUlrMaUhIsRSb61x1jREstsKst3bhqJtu6RZpNdujw6HDph7BQSFrxkFApZiztJksdFQMVAcJFSM3jZESFjA==","signatures":[{"sig":"MEQCIF6FLy5eoIajPwLYlAXMZoxFwt/dL6+a4j61IkiQSAeoAiAmD1xXs32O1u5rO+goDycd1XuIOX6U2H7QurST70gCIg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":613480},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"56c5c816c53dce949b20329c679435d8ee6f6570","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.5.0_1786981940243_0.23986482746532078","host":"s3://npm-registry-packages-npm-production"}},"1.6.0":{"name":"@api-kickstart/api-kickstart","version":"1.6.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@1.6.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"52ee089403bdf30bc7f62bb58184b93353de34d6","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.6.0.tgz","fileCount":581,"integrity":"sha512-fFpSJR4L5KnrWtjxm6SRi8zEoXNUCpwCcWfc6xM2uo3O4OehlijLMs15LlJqMX6KvbKivS79zBzEB+OIxrFyJQ==","signatures":[{"sig":"MEQCIH6xJSlYuJEs7z0QOfJWu0VWklsvBhV7cRsrYbvU6/LlAiBBl18ehKKMHsA7VhLOFt/2RoMOU2bZI/otIQLZ3elbzQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":633201},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"13dc6f7e3aa5a9d10ee01e85ca880a07111d3348","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.6.0_1786982505444_0.09469775123446222","host":"s3://npm-registry-packages-npm-production"}},"1.7.0":{"name":"@api-kickstart/api-kickstart","version":"1.7.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@1.7.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"f5163c47d469cb44de04ebe0ea8135b32714b2fa","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-1.7.0.tgz","fileCount":601,"integrity":"sha512-xrAkNiRVIcqTY418dchI4t+kcypdXvrkBOzHxqmBvZgoxoVYDr+6eoS0B3jM3dfG0D9uCImWl9tWrtONZIkhIA==","signatures":[{"sig":"MEQCIDdogN1DW2jmWTX2cI9hSkbip5FIgEkjssqFExAp/a0NAiBvao9bQXiOivi2NmvoFNOt440M0guyn4abxbdClh6n7A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":658952},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"bdb7ab8848f9b4f1060dd76131c28b86ca2990d0","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","jose":"^5.9.6","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_1.7.0_1786983005664_0.282548950919969","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@api-kickstart/api-kickstart","version":"2.0.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@2.0.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"cde118346effaeda0109b59683a4976c2afaa63c","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-2.0.0.tgz","fileCount":625,"integrity":"sha512-Oc4lg92kR/IZlYtb5428PgfXfoFl529lKhtr5W2hF/5LUDuJtJVq7YWzeXiwvREngS9VGeMopxIGFsOpHAw3ww==","signatures":[{"sig":"MEUCIQDzp50MBzxRbUwVTZhk7w8crXJ9s7M3edPUM3GDoM/uUwIgVbDMhkbUdHx2kCIOVlHREt/E2JBlktLyuHOb5zlB9n0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":691626},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"c4e44369ca8a62863215972f75a84832ff518066","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"jose":"^5.9.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"peerDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependenciesMeta":{"pg":{"optional":true},"joi":{"optional":true},"koa":{"optional":true},"yup":{"optional":true},"zod":{"optional":true},"hono":{"optional":true},"knex":{"optional":true},"mqtt":{"optional":true},"nats":{"optional":true},"pino":{"optional":true},"rxjs":{"optional":true},"bullmq":{"optional":true},"amqplib":{"optional":true},"express":{"optional":true},"fastify":{"optional":true},"ioredis":{"optional":true},"kafkajs":{"optional":true},"mongodb":{"optional":true},"typeorm":{"optional":true},"valibot":{"optional":true},"mongoose":{"optional":true},"sequelize":{"optional":true},"drizzle-orm":{"optional":true},"joi-to-json":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"koa-bodyparser":{"optional":true},"reflect-metadata":{"optional":true},"@hono/node-server":{"optional":true},"@sinclair/typebox":{"optional":true},"@aws-sdk/client-s3":{"optional":true},"zod-to-json-schema":{"optional":true},"@aws-sdk/client-sqs":{"optional":true},"@google-cloud/pubsub":{"optional":true},"@valibot/to-json-schema":{"optional":true},"@nestjs/platform-express":{"optional":true},"@sodaru/yup-to-json-schema":{"optional":true},"@aws-sdk/s3-request-presigner":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_2.0.0_1786985469880_0.2372824336812478","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@api-kickstart/api-kickstart","version":"2.1.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@2.1.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"f31803c8595fc540c85d0fceca7d7694737a2470","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-2.1.0.tgz","fileCount":637,"integrity":"sha512-FxqdZkbvwWbdG4KAWBfACvfKE5DtVPbyl2fI94VAeH+4Lif5fLgr+RTYxbrumkQiZOpaKl+OuQsc4FwmeTb7Ow==","signatures":[{"sig":"MEUCIHge6dKAMSXqs6P8sZLAPdQv7vu/A5EceVFUGiNOBZfMAiEAz07ofrIj5HliG+2tIurKZ6qvPqDpslwpM8cH4uIfehM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":749709},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"69314d51851926f7d2c5d35aa0de9906a6d47563","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"jose":"^5.9.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"peerDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependenciesMeta":{"pg":{"optional":true},"joi":{"optional":true},"koa":{"optional":true},"yup":{"optional":true},"zod":{"optional":true},"hono":{"optional":true},"knex":{"optional":true},"mqtt":{"optional":true},"nats":{"optional":true},"pino":{"optional":true},"rxjs":{"optional":true},"bullmq":{"optional":true},"amqplib":{"optional":true},"express":{"optional":true},"fastify":{"optional":true},"ioredis":{"optional":true},"kafkajs":{"optional":true},"mongodb":{"optional":true},"typeorm":{"optional":true},"valibot":{"optional":true},"mongoose":{"optional":true},"sequelize":{"optional":true},"drizzle-orm":{"optional":true},"joi-to-json":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"koa-bodyparser":{"optional":true},"reflect-metadata":{"optional":true},"@hono/node-server":{"optional":true},"@sinclair/typebox":{"optional":true},"@aws-sdk/client-s3":{"optional":true},"zod-to-json-schema":{"optional":true},"@aws-sdk/client-sqs":{"optional":true},"@google-cloud/pubsub":{"optional":true},"@valibot/to-json-schema":{"optional":true},"@nestjs/platform-express":{"optional":true},"@sodaru/yup-to-json-schema":{"optional":true},"@aws-sdk/s3-request-presigner":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_2.1.0_1787065289880_0.8567319207803357","host":"s3://npm-registry-packages-npm-production"}},"2.2.0":{"name":"@api-kickstart/api-kickstart","version":"2.2.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@2.2.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"031ce413c7433f74f120682a07281fa48353d74a","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-2.2.0.tgz","fileCount":637,"integrity":"sha512-u4tzdHpajS7jUmvxGW7tLJMnCKU13N3Y4tUkMhltXERp2SY8uwSBUIqEd+udiwXGkyZATU/qS3WXkQ+pSpSMRg==","signatures":[{"sig":"MEYCIQC/thL4ORHpj5kgaDBZIksUN+XODMOGHtho73MzHmeeMwIhALHaxoJF+ikymadFyx8V8OM9SoqCwSdpNqXRu1M6mLAz","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":762611},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"1dcfbfe72d4a4a21cc9ae431be764d4a7481662d","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"jose":"^5.9.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"peerDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependenciesMeta":{"pg":{"optional":true},"joi":{"optional":true},"koa":{"optional":true},"yup":{"optional":true},"zod":{"optional":true},"hono":{"optional":true},"knex":{"optional":true},"mqtt":{"optional":true},"nats":{"optional":true},"pino":{"optional":true},"rxjs":{"optional":true},"bullmq":{"optional":true},"amqplib":{"optional":true},"express":{"optional":true},"fastify":{"optional":true},"ioredis":{"optional":true},"kafkajs":{"optional":true},"mongodb":{"optional":true},"typeorm":{"optional":true},"valibot":{"optional":true},"mongoose":{"optional":true},"sequelize":{"optional":true},"drizzle-orm":{"optional":true},"joi-to-json":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"koa-bodyparser":{"optional":true},"reflect-metadata":{"optional":true},"@hono/node-server":{"optional":true},"@sinclair/typebox":{"optional":true},"@aws-sdk/client-s3":{"optional":true},"zod-to-json-schema":{"optional":true},"@aws-sdk/client-sqs":{"optional":true},"@google-cloud/pubsub":{"optional":true},"@valibot/to-json-schema":{"optional":true},"@nestjs/platform-express":{"optional":true},"@sodaru/yup-to-json-schema":{"optional":true},"@aws-sdk/s3-request-presigner":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_2.2.0_1787068194017_0.3455884483877405","host":"s3://npm-registry-packages-npm-production"}},"2.3.0":{"name":"@api-kickstart/api-kickstart","version":"2.3.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@2.3.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"49e2adaad83f22a731c02508113296b5d0449db3","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-2.3.0.tgz","fileCount":637,"integrity":"sha512-DM41X06vYZXmuaV6wlTUMivjqcm6jfAXpAjhDJ/J/N51Y5BRTLTFjMf8rkXODRzmCBsPKapx+QOn9IB+XUbxlg==","signatures":[{"sig":"MEQCIA/2bE6PAx5szI8pXL7aSWS8Y3ft8BM2JQElFhiBqx9JAiAkAMtiDEonPFs4kAwAJmUdcBYYVdMNjxTOO7nAe3CNjA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":779883},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"da42546124a17b5d55e391f37632afa46e74eaae","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"jose":"^5.9.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"peerDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependenciesMeta":{"pg":{"optional":true},"joi":{"optional":true},"koa":{"optional":true},"yup":{"optional":true},"zod":{"optional":true},"hono":{"optional":true},"knex":{"optional":true},"mqtt":{"optional":true},"nats":{"optional":true},"pino":{"optional":true},"rxjs":{"optional":true},"bullmq":{"optional":true},"amqplib":{"optional":true},"express":{"optional":true},"fastify":{"optional":true},"ioredis":{"optional":true},"kafkajs":{"optional":true},"mongodb":{"optional":true},"typeorm":{"optional":true},"valibot":{"optional":true},"mongoose":{"optional":true},"sequelize":{"optional":true},"drizzle-orm":{"optional":true},"joi-to-json":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"koa-bodyparser":{"optional":true},"reflect-metadata":{"optional":true},"@hono/node-server":{"optional":true},"@sinclair/typebox":{"optional":true},"@aws-sdk/client-s3":{"optional":true},"zod-to-json-schema":{"optional":true},"@aws-sdk/client-sqs":{"optional":true},"@google-cloud/pubsub":{"optional":true},"@valibot/to-json-schema":{"optional":true},"@nestjs/platform-express":{"optional":true},"@sodaru/yup-to-json-schema":{"optional":true},"@aws-sdk/s3-request-presigner":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_2.3.0_1787069859544_0.4385589337489084","host":"s3://npm-registry-packages-npm-production"}},"2.4.0":{"name":"@api-kickstart/api-kickstart","version":"2.4.0","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"author":{"name":"Lukman Yudokusumo"},"license":"MIT","_id":"@api-kickstart/api-kickstart@2.4.0","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"bin":{"api-kickstart":"bin/api-kickstart.js"},"dist":{"shasum":"9bc6ac91fa449a3c315cecaf8a5ed2fb408c8aca","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-2.4.0.tgz","fileCount":637,"integrity":"sha512-PFfUSpeCupRaY+Ds425aVT/CRXbtOlI7F9+CTHheK3LaO8eO1RLJJw7G3mheY+MUw64Jh5f0K0pf5ho/4J94jg==","signatures":[{"sig":"MEYCIQCZSXv91hktnRWREk/yx+vz8ynJj4rvaixn8sfNBAbVXgIhAKJ/le0TK/BCPKuF5yd9xrJ2agzEbgNgqqJIC2BFp7td","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":789555},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"}},"gitHead":"d945c3a8b30feeb1ee4a7f95f732ecc507377a4d","scripts":{"build":"tsc -p tsconfig.json","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"repository":{"url":"git+https://github.com/lukmmaan/api-kickstart.git","type":"git"},"_npmVersion":"10.9.7","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"jose":"^5.9.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/pg":"^8.11.6","@types/koa":"^2.15.0","typescript":"^5.5.4","@types/node":"^22.5.0","@types/amqplib":"^0.10.5","@types/express":"^4.17.21","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0","@types/koa-bodyparser":"^4.3.12"},"peerDependencies":{"pg":"^8.11.0","joi":"^17.13.3","koa":"^2.15.0","yup":"^1.4.0","zod":"^3.23.0","hono":"^4.6.0","knex":"^3.1.0","mqtt":"^5.10.1","nats":"^2.28.2","pino":"^9.4.0","rxjs":"^7.8.1","bullmq":"^5.12.0","amqplib":"^0.10.4","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","ioredis":"^5.4.1","kafkajs":"^2.2.4","mongodb":"^6.8.0","typeorm":"^0.3.20","valibot":"^1.4.0","mongoose":"^8.6.0","sequelize":"^6.37.0","drizzle-orm":"^0.33.0","joi-to-json":"^5.0.5","@nestjs/core":"^10.4.0","@nestjs/common":"^10.4.0","koa-bodyparser":"^4.4.1","reflect-metadata":"^0.2.2","@hono/node-server":"^1.13.0","@sinclair/typebox":"^0.33.0","@aws-sdk/client-s3":"^3.635.0","zod-to-json-schema":"^3.23.5","@aws-sdk/client-sqs":"^3.635.0","@google-cloud/pubsub":"^4.9.0","@valibot/to-json-schema":"^1.4.0","@nestjs/platform-express":"^10.4.0","@sodaru/yup-to-json-schema":"^2.0.1","@aws-sdk/s3-request-presigner":"^3.635.0"},"peerDependenciesMeta":{"pg":{"optional":true},"joi":{"optional":true},"koa":{"optional":true},"yup":{"optional":true},"zod":{"optional":true},"hono":{"optional":true},"knex":{"optional":true},"mqtt":{"optional":true},"nats":{"optional":true},"pino":{"optional":true},"rxjs":{"optional":true},"bullmq":{"optional":true},"amqplib":{"optional":true},"express":{"optional":true},"fastify":{"optional":true},"ioredis":{"optional":true},"kafkajs":{"optional":true},"mongodb":{"optional":true},"typeorm":{"optional":true},"valibot":{"optional":true},"mongoose":{"optional":true},"sequelize":{"optional":true},"drizzle-orm":{"optional":true},"joi-to-json":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"koa-bodyparser":{"optional":true},"reflect-metadata":{"optional":true},"@hono/node-server":{"optional":true},"@sinclair/typebox":{"optional":true},"@aws-sdk/client-s3":{"optional":true},"zod-to-json-schema":{"optional":true},"@aws-sdk/client-sqs":{"optional":true},"@google-cloud/pubsub":{"optional":true},"@valibot/to-json-schema":{"optional":true},"@nestjs/platform-express":{"optional":true},"@sodaru/yup-to-json-schema":{"optional":true},"@aws-sdk/s3-request-presigner":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/api-kickstart_2.4.0_1787072082944_0.2099112127058831","host":"s3://npm-registry-packages-npm-production"}},"2.5.0":{"name":"@api-kickstart/api-kickstart","version":"2.5.0","description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"homepage":"https://github.com/lukmmaan/api-kickstart#readme","repository":{"type":"git","url":"git+https://github.com/lukmmaan/api-kickstart.git"},"bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"author":{"name":"Lukman Yudokusumo"},"license":"MIT","engines":{"node":">=20"},"publishConfig":{"access":"public"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","bin":{"api-kickstart":"bin/api-kickstart.js"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./errors":{"types":"./dist/errors.d.ts","import":"./dist/errors.js"},"./context":{"types":"./dist/context.d.ts","import":"./dist/context.js"},"./env":{"types":"./dist/env.d.ts","import":"./dist/env.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js"},"./patterns":{"types":"./dist/patterns.d.ts","import":"./dist/patterns.js"},"./dates":{"types":"./dist/dates.d.ts","import":"./dist/dates.js"},"./i18n":{"types":"./dist/i18n.d.ts","import":"./dist/i18n.js"},"./middleware":{"types":"./dist/builtins/index.d.ts","import":"./dist/builtins/index.js"},"./bullmq":{"types":"./dist/adapters/bullmq/index.d.ts","import":"./dist/adapters/bullmq/index.js"},"./drizzle":{"types":"./dist/adapters/drizzle/index.d.ts","import":"./dist/adapters/drizzle/index.js"},"./express":{"types":"./dist/adapters/express/index.d.ts","import":"./dist/adapters/express/index.js"},"./fastify":{"types":"./dist/adapters/fastify/index.d.ts","import":"./dist/adapters/fastify/index.js"},"./hono":{"types":"./dist/adapters/hono/index.d.ts","import":"./dist/adapters/hono/index.js"},"./http":{"types":"./dist/adapters/http/index.d.ts","import":"./dist/adapters/http/index.js"},"./joi":{"types":"./dist/adapters/joi/index.d.ts","import":"./dist/adapters/joi/index.js"},"./kafka":{"types":"./dist/adapters/kafka/index.d.ts","import":"./dist/adapters/kafka/index.js"},"./knex":{"types":"./dist/adapters/knex/index.d.ts","import":"./dist/adapters/knex/index.js"},"./koa":{"types":"./dist/adapters/koa/index.d.ts","import":"./dist/adapters/koa/index.js"},"./memory":{"types":"./dist/adapters/memory/index.d.ts","import":"./dist/adapters/memory/index.js"},"./mongodb":{"types":"./dist/adapters/mongodb/index.d.ts","import":"./dist/adapters/mongodb/index.js"},"./mongoose":{"types":"./dist/adapters/mongoose/index.d.ts","import":"./dist/adapters/mongoose/index.js"},"./mqtt":{"types":"./dist/adapters/mqtt/index.d.ts","import":"./dist/adapters/mqtt/index.js"},"./nats":{"types":"./dist/adapters/nats/index.d.ts","import":"./dist/adapters/nats/index.js"},"./nest":{"types":"./dist/adapters/nest/index.d.ts","import":"./dist/adapters/nest/index.js"},"./pg":{"types":"./dist/adapters/pg/index.d.ts","import":"./dist/adapters/pg/index.js"},"./pino":{"types":"./dist/adapters/pino/index.d.ts","import":"./dist/adapters/pino/index.js"},"./prisma":{"types":"./dist/adapters/prisma/index.d.ts","import":"./dist/adapters/prisma/index.js"},"./pubsub":{"types":"./dist/adapters/pubsub/index.d.ts","import":"./dist/adapters/pubsub/index.js"},"./rabbitmq":{"types":"./dist/adapters/rabbitmq/index.d.ts","import":"./dist/adapters/rabbitmq/index.js"},"./redis":{"types":"./dist/adapters/redis/index.d.ts","import":"./dist/adapters/redis/index.js"},"./redis-stream":{"types":"./dist/adapters/redis-stream/index.d.ts","import":"./dist/adapters/redis-stream/index.js"},"./s3":{"types":"./dist/adapters/s3/index.d.ts","import":"./dist/adapters/s3/index.js"},"./sequelize":{"types":"./dist/adapters/sequelize/index.d.ts","import":"./dist/adapters/sequelize/index.js"},"./sqs":{"types":"./dist/adapters/sqs/index.d.ts","import":"./dist/adapters/sqs/index.js"},"./typebox":{"types":"./dist/adapters/typebox/index.d.ts","import":"./dist/adapters/typebox/index.js"},"./typeorm":{"types":"./dist/adapters/typeorm/index.d.ts","import":"./dist/adapters/typeorm/index.js"},"./valibot":{"types":"./dist/adapters/valibot/index.d.ts","import":"./dist/adapters/valibot/index.js"},"./yup":{"types":"./dist/adapters/yup/index.d.ts","import":"./dist/adapters/yup/index.js"},"./zod":{"types":"./dist/adapters/zod/index.d.ts","import":"./dist/adapters/zod/index.js"}},"scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit","prepack":"cp ../../README.md ./README.md && cp ../../LICENSE ./LICENSE"},"dependencies":{"jose":"^5.9.6"},"peerDependencies":{"@hono/node-server":"^1.13.0","koa-bodyparser":"^4.4.1","zod-to-json-schema":"^3.23.5","bullmq":"^5.12.0","drizzle-orm":"^0.33.0","express":"^4.19.0 || ^5.0.0","fastify":"^4.28.0 || ^5.0.0","hono":"^4.6.0","joi":"^17.13.3","joi-to-json":"^5.0.5","kafkajs":"^2.2.4","knex":"^3.1.0","koa":"^2.15.0","mongodb":"^6.8.0","mongoose":"^8.6.0","mqtt":"^5.10.1","nats":"^2.28.2","@nestjs/common":"^10.4.0","@nestjs/core":"^10.4.0","@nestjs/platform-express":"^10.4.0","reflect-metadata":"^0.2.2","rxjs":"^7.8.1","pg":"^8.11.0","pino":"^9.4.0","@google-cloud/pubsub":"^4.9.0","amqplib":"^0.10.4","ioredis":"^5.4.1","@aws-sdk/client-s3":"^3.635.0","@aws-sdk/s3-request-presigner":"^3.635.0","sequelize":"^6.37.0","@aws-sdk/client-sqs":"^3.635.0","@sinclair/typebox":"^0.33.0","typeorm":"^0.3.20","valibot":"^1.4.0","@valibot/to-json-schema":"^1.4.0","yup":"^1.4.0","@sodaru/yup-to-json-schema":"^2.0.1","zod":"^3.23.0"},"peerDependenciesMeta":{"@hono/node-server":{"optional":true},"koa-bodyparser":{"optional":true},"zod-to-json-schema":{"optional":true},"bullmq":{"optional":true},"drizzle-orm":{"optional":true},"express":{"optional":true},"fastify":{"optional":true},"hono":{"optional":true},"joi":{"optional":true},"joi-to-json":{"optional":true},"kafkajs":{"optional":true},"knex":{"optional":true},"koa":{"optional":true},"mongodb":{"optional":true},"mongoose":{"optional":true},"mqtt":{"optional":true},"nats":{"optional":true},"@nestjs/common":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/platform-express":{"optional":true},"reflect-metadata":{"optional":true},"rxjs":{"optional":true},"pg":{"optional":true},"pino":{"optional":true},"@google-cloud/pubsub":{"optional":true},"amqplib":{"optional":true},"ioredis":{"optional":true},"@aws-sdk/client-s3":{"optional":true},"@aws-sdk/s3-request-presigner":{"optional":true},"sequelize":{"optional":true},"@aws-sdk/client-sqs":{"optional":true},"@sinclair/typebox":{"optional":true},"typeorm":{"optional":true},"valibot":{"optional":true},"@valibot/to-json-schema":{"optional":true},"yup":{"optional":true},"@sodaru/yup-to-json-schema":{"optional":true},"zod":{"optional":true}},"devDependencies":{"typescript":"^5.5.4","@types/node":"^22.5.0","@types/express":"^4.17.21","@types/koa":"^2.15.0","@types/koa-bodyparser":"^4.3.12","@types/pg":"^8.11.6","@types/amqplib":"^0.10.5","better-sqlite3":"^11.3.0","aws-sdk-client-mock":"^4.1.0"},"_id":"@api-kickstart/api-kickstart@2.5.0","gitHead":"8a342e278befc2af404470e864f0b6a56f915156","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-N/KaZye+fPj4sambLkUxxP17+4UGxLmQdIujCA3uTil3n5DsoKTe639lnO0YRR6ZcafKTqA0Tn/mkS9W7DmO2w==","shasum":"ffcde5275c8c1f08ffb36d0ba8952957b676147b","tarball":"https://registry.npmjs.org/@api-kickstart/api-kickstart/-/api-kickstart-2.5.0.tgz","fileCount":637,"unpackedSize":806511,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICqDSF4iwJ+/6gkv9nWmrcWacHNSOnOOpbGLDZvFgO4jAiB8XSuQ5tL7KDZueKHGZSq+oy/55+4ztNk3PRVbIDElgg=="}]},"_npmUser":{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"},"directories":{},"maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/api-kickstart_2.5.0_1787103919500_0.10312734674739321"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-15T15:48:33.429Z","modified":"2026-08-19T01:45:19.808Z","1.0.0":"2026-08-15T15:48:33.809Z","1.0.1":"2026-08-17T14:49:38.175Z","1.1.0":"2026-08-17T14:59:43.687Z","1.1.1":"2026-08-17T15:07:16.338Z","1.1.2":"2026-08-17T15:16:54.033Z","1.2.0":"2026-08-17T15:26:28.214Z","1.3.0":"2026-08-17T15:37:24.914Z","1.4.0":"2026-08-17T15:44:41.977Z","1.5.0":"2026-08-17T15:52:20.418Z","1.6.0":"2026-08-17T16:01:45.597Z","1.7.0":"2026-08-17T16:10:05.819Z","2.0.0":"2026-08-17T16:51:10.032Z","2.1.0":"2026-08-18T15:01:30.051Z","2.2.0":"2026-08-18T15:49:54.173Z","2.3.0":"2026-08-18T16:17:39.701Z","2.4.0":"2026-08-18T16:54:43.099Z","2.5.0":"2026-08-19T01:45:19.660Z"},"bugs":{"url":"https://github.com/lukmmaan/api-kickstart/issues"},"author":{"name":"Lukman Yudokusumo"},"license":"MIT","homepage":"https://github.com/lukmmaan/api-kickstart#readme","keywords":["api","backend","framework","express","fastify","hono","koa","nestjs","auth","authentication","authorization","jwt","oidc","oauth","rbac","validation","zod","middleware","rest","typescript","prisma","postgres","mongodb","rabbitmq","kafka","openapi","swagger"],"repository":{"type":"git","url":"git+https://github.com/lukmmaan/api-kickstart.git"},"description":"Auth, authorization, validation, CORS, error handling, database, and message broker, wired together with sane defaults, swappable everywhere.","maintainers":[{"name":"lukmmaan24","email":"lyudokusumo@gmail.com"}],"readme":"# api-kickstart\n\n> Stop rewriting the same 800 lines on every new project. Auth, authorization, validation, CORS, error handling, database, and message broker — wired together with sane defaults, swappable everywhere.\n\n[![npm version](https://img.shields.io/npm/v/%40api-kickstart%2Fapi-kickstart.svg)](https://www.npmjs.com/package/@api-kickstart/api-kickstart)\n[![CI](https://github.com/lukmmaan/api-kickstart/actions/workflows/ci.yml/badge.svg)](https://github.com/lukmmaan/api-kickstart/actions/workflows/ci.yml)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/%40api-kickstart%2Fapi-kickstart)](https://bundlephobia.com/package/@api-kickstart/api-kickstart)\n[![license](https://img.shields.io/npm/l/%40api-kickstart%2Fapi-kickstart.svg)](./LICENSE)\n[![types](https://img.shields.io/npm/types/%40api-kickstart%2Fapi-kickstart.svg)](https://www.typescriptlang.org/)\n\n---\n\n## The problem\n\nDay 1 and Day 2 of every new backend project look identical:\n\n- Wire up JWT, then refresh tokens, then a blacklist for logout\n- Copy the same `authenticate` and `requireRole` middleware from the last project\n- Copy the CORS config and get it subtly wrong\n- Copy the error handler, the request logger, the graceful shutdown\n- Set up validation, and remember to validate `params` too, not just `body`\n- Write `if (user.role !== 'admin') query.userId = user.id` in forty controllers\n- Connect the database, connect the queue, handle reconnects\n\nNone of it is hard. All of it is tedious, and every copy drifts a little further from the last one. The forty-first controller is the one where somebody forgets the scope filter, and now users can read each other's data.\n\n`api-kickstart` is that layer, written once.\n\n**What it is:** a composition layer over your framework, with pluggable auth strategies, validators, database adapters, and brokers.\n\n**What it is not:** a framework. It doesn't own your app, doesn't own your routes, and can be removed one piece at a time. Every part is opt-in.\n\n---\n\n## Table of contents\n\n- [Install](#install)\n- [60-second start](#60-second-start)\n- [Core concepts](#core-concepts)\n- [Authentication](#authentication)\n  - [JWT](#jwt)\n  - [Password hashing](#password-hashing)\n  - [Session](#session)\n  - [API key](#api-key)\n  - [Basic auth](#basic-auth)\n  - [OAuth / OIDC](#oauth--oidc)\n  - [Multiple strategies](#multiple-strategies)\n  - [Custom strategy](#custom-strategy)\n- [Authorization](#authorization)\n- [Scope: row-level filtering](#scope-row-level-filtering)\n- [Validation](#validation)\n  - [Zod](#zod)\n  - [Joi](#joi)\n  - [Yup](#yup)\n  - [Valibot](#valibot)\n  - [TypeBox](#typebox)\n  - [Writing your own validator](#writing-your-own-validator)\n- [Regex patterns](#regex-patterns)\n- [Date formatting](#date-formatting)\n- [Internationalization (i18n)](#internationalization-i18n)\n- [File uploads](#file-uploads)\n- [Routing](#routing)\n  - [Single route](#single-route)\n  - [Route config reference](#route-config-reference)\n  - [Groups](#groups)\n  - [CRUD shorthand](#crud-shorthand)\n  - [Introspection](#introspection)\n- [CORS](#cors)\n- [Middleware](#middleware)\n  - [Built-ins reference](#built-ins-reference)\n  - [Audit logging](#audit-logging)\n- [Request context](#request-context)\n- [Errors](#errors)\n- [Database adapters](#database-adapters)\n  - [pg](#pg)\n  - [Prisma](#prisma)\n  - [Drizzle](#drizzle)\n  - [Mongoose](#mongoose)\n  - [Knex](#knex)\n  - [TypeORM](#typeorm)\n  - [Sequelize](#sequelize)\n  - [MongoDB driver](#mongodb-driver)\n  - [Transactions](#transactions)\n  - [Writing your own database adapter](#writing-your-own-database-adapter)\n- [Message brokers](#message-brokers)\n  - [RabbitMQ](#rabbitmq)\n  - [Kafka](#kafka)\n  - [Redis Streams](#redis-streams)\n  - [BullMQ](#bullmq)\n  - [AWS SQS](#aws-sqs)\n  - [NATS](#nats)\n  - [MQTT](#mqtt)\n  - [Google Cloud Pub/Sub](#google-cloud-pubsub)\n  - [In-memory (tests)](#in-memory-tests)\n  - [Publishing](#publishing)\n  - [Consuming](#consuming)\n  - [Transactional outbox](#transactional-outbox)\n  - [Writing your own broker adapter](#writing-your-own-broker-adapter)\n  - [Graceful shutdown](#graceful-shutdown)\n- [Storage](#storage)\n  - [Writing your own storage adapter](#writing-your-own-storage-adapter)\n- [Logging](#logging)\n  - [Writing your own logger](#writing-your-own-logger)\n- [Redis-backed stores](#redis-backed-stores)\n- [Distributed locks](#distributed-locks)\n- [Webhooks](#webhooks)\n- [Framework adapters](#framework-adapters)\n  - [Express](#express)\n  - [Fastify](#fastify)\n  - [Hono](#hono)\n  - [Koa](#koa)\n  - [NestJS](#nestjs)\n  - [Node `http`](#node-http)\n  - [Writing your own framework adapter](#writing-your-own-framework-adapter)\n- [Configuration](#configuration)\n- [OpenAPI generation](#openapi-generation)\n- [Health & metrics](#health--metrics)\n- [Scheduled tasks](#scheduled-tasks)\n- [Testing](#testing)\n- [CLI](#cli)\n- [Production checklist](#production-checklist)\n- [FAQ](#faq)\n- [Repository layout](#repository-layout)\n- [Roadmap](#roadmap)\n- [License](#license)\n\n---\n\n## Install\n\n```bash\nnpm install @api-kickstart/api-kickstart\nnpx api-kickstart init\n```\n\n`npm install` gets you the core (routing, auth, authorization, validation dispatch, error handling, middleware, CLI — no framework/database/broker libraries pulled in). `npx api-kickstart init` then walks you through picking a framework, database, broker(s), validator, storage, and logger with a short interactive prompt, and installs **only** the packages you picked — so you don't end up with Express *and* Fastify *and* NestJS, or all five validators, sitting unused in `node_modules`:\n\n```\n$ npx api-kickstart init\napi-kickstart init — pick the pieces of your stack; only what you choose gets installed.\n\nFramework: Which HTTP framework do you want to use?\n  1) Express\n  2) Fastify\n  3) Hono\n  4) Koa\n  5) NestJS\n  6) Plain node:http (no framework package needed)\nEnter a number, or press enter to skip: 1\n\nDatabase: Which database/ORM adapter do you want?\n  ...\nEnter a number, or press enter to skip: 1\n\nValidation: Which validation library do you want?\n  ...\nEnter a number, or press enter to skip: 1\n\nInstalling with npm: express@^4.19.0 || ^5.0.0, pg@^8.11.0, zod@^3.23.0, zod-to-json-schema@^3.23.5\n\nProject structure: Scaffold a folder structure now (controllers, routes, services, models, config, middleware)?\n  1) Layered (config/, models/, services/, controllers/, routes/ — grouped by type)\n  2) Modular by feature (modules/<resource>/ — model, service, controller, routes together)\nEnter a number, or press enter to skip: 1\n\nLanguage: Generate TypeScript or JavaScript?\n  1) TypeScript\n  2) JavaScript\nEnter a number, or press enter to skip: 1\n\nName your resources — one module gets generated per name (comma-separated, plural, e.g. users, posts):\n[users]: users, posts\n\nFields for users — name:type, comma-separated (types: string, number, boolean):\n[name:string]: name:string, email:string, age:number, isActive:boolean\n\nFields for posts — name:type, comma-separated (types: string, number, boolean):\n[name:string]: title:string\n\nAuthentication: Which authentication strategy do you want to scaffold?\n  1) JWT (login/refresh/logout/me routes)\n  2) API key (x-api-key header)\n  3) Both (JWT + API key)\nEnter a number, or press enter to skip: 1\n\nAuthorization: Generate a real roles & scope example (role hierarchy, plus roles enforced on the create route of every resource)?\n  1) Yes\n  2) No\nEnter a number, or press enter to skip: 1\n\nInternationalization: Generate an i18n setup too (in-memory dictionary + locale-detection middleware)?\n  1) Yes\n  2) No\nEnter a number, or press enter to skip: 1\n\nOps endpoints: Add any of these to app.ts?\n  1) Health check (/health)\n  2) Prometheus metrics (/metrics)\n  3) OpenAPI docs (/openapi.json + /docs)\nEnter numbers separated by commas, or press enter to skip: 1,2,3\n\nProduction essentials: Generate graceful shutdown + a scheduled job example (with a distributed lock)?\n  1) Yes\n  2) No\nEnter a number, or press enter to skip: 1\n\nSecurity middleware: Add any of these to app.ts's middleware?\n  1) Request ID header\n  2) Request logger\n  3) Helmet (security headers)\n  4) Compression\n  5) Rate limiting\n  6) Body size limit\n  7) Request timeout\n  8) Idempotency keys\n  9) CSRF protection\nEnter numbers separated by commas, or press enter to skip: 1,3,5\n\nScaffolded 20 file(s) under src/ (2 modules: users, posts) using the \"Layered\" structure.\n```\n\nOnce the stack is installed, `init` asks whether to scaffold a starting folder structure — `config/`, `models/`, `services/`, `controllers/`, `routes/`, `middleware/` (or the model/service/controller/routes four grouped per-feature under `modules/<resource>/` instead) — wired up for the framework, database, and validator you just picked. Then **TypeScript or JavaScript**: pick JavaScript and every file lands as plain `.js`, with every `import type`, interface, and type annotation stripped — not just the extension, the actual file contents change too. Pick TypeScript (the default) and each resource also gets a real `types/` folder — `src/types/users.types.ts`, `src/types/posts.types.ts` — holding the hand-written interface for that resource, imported by its model instead of declared inline (for Modular, the type file sits next to that resource's other files inside `modules/<resource>/` instead of a shared top-level folder, matching the rest of that theme).\n\nName one resource or several, comma-separated (`users, posts, comments`), then **for each one** say what fields it actually has (`name:string, email:string, age:number, isActive:boolean`) — it's not just folders and filenames that get generated, the file *contents* do too: the interface, the SQL/ORM query, the validator schema, and the controller's body cast all use those exact fields, per resource. Leave a fields answer blank and that resource gets a single generic `name: string` field instead.\n\nSix more questions round it out, each independently skippable:\n\n- **Authentication** — JWT, API key, or both. JWT scaffolds `config/auth.ts` with an in-memory user list (so it runs with zero setup — try `admin` / `admin123`) and wires `app.useAuthRoutes()` for real `/auth/login`, `/auth/refresh`, `/auth/logout`, `/auth/me` routes. API key scaffolds an in-memory key map instead (`x-api-key: dev-api-key-change-me`). Picking both generates both and combines them into a single `auth` array.\n- **Authorization** — generates `config/roles.ts` with a real `RoleHierarchy` (`admin` → `editor` → `viewer`) and adds `auth: true, roles: ['admin', 'editor']` to every resource's `POST` (create) route — the `GET` (list) route stays public.\n- **Internationalization** — generates `config/i18n.ts` with a real two-locale dictionary (`en`/`id`) via `createI18n()`, and wires its locale-detection `middleware` into `app.ts` alongside the request timer.\n- **Ops endpoints** — any combination of `app.health()`, `app.metrics()`, and a full `app.openapi({...})` call (serving `/openapi.json` and interactive docs at `/docs`), added straight after `createApp(...)` in `app.ts`.\n- **Production essentials** — generates `config/lock.ts` with the distributed lock that matches your database adapter (`pgLock`/`knexLock`/`mongodbLock`, or `memoryLock` as the single-instance fallback), wires `gracefulShutdown(app)` into `index.ts`, and adds a real `app.schedule('example-job', { interval: '5m', lock }, ...)` block to `app.ts` so you have a working scheduled-job example out of the box.\n- **Security middleware** — any combination of `requestId`, `logger`, `helmet`, `compression`, `rateLimit`, `bodyLimit`, `timeout`, `idempotency`, and `csrf` from `@api-kickstart/api-kickstart/middleware`, each with real default options (`rateLimit({ window: '1m', max: 100 })`, `bodyLimit({ maxBytes: 1_000_000 })`, `timeout({ duration: '30s' })`), added to `app.ts`'s `middleware: [...]` array in that canonical order regardless of the order you picked them in.\n\n`config/`, `app.ts`, and `middleware/requestTimer.middleware.ts` stay shared across every resource and every one of these features. Nothing here ever overwrites a file that already exists in `src/`.\n\n**What actually lands on disk.** For the transcript above — Express, pg, Zod, Layered, `users` (name/email/age/isActive) + `posts` (title), JWT auth, authorization on, i18n on, all three ops endpoints, production essentials on, and `requestId`/`helmet`/`rateLimit` security middleware — you get:\n\n```\nsrc/\n├── config/\n│   ├── env.ts\n│   ├── database.ts\n│   ├── auth.ts\n│   ├── roles.ts\n│   ├── i18n.ts\n│   └── lock.ts\n├── middleware/\n│   └── requestTimer.middleware.ts\n├── types/\n│   ├── users.types.ts\n│   └── posts.types.ts\n├── models/\n│   ├── users.model.ts\n│   └── posts.model.ts\n├── services/\n│   ├── users.service.ts\n│   └── posts.service.ts\n├── controllers/\n│   ├── users.controller.ts\n│   └── posts.controller.ts\n├── routes/\n│   ├── users.routes.ts\n│   ├── posts.routes.ts\n│   └── index.ts\n├── app.ts\n└── index.ts\n```\n\n`src/types/users.types.ts` — the hand-written interface for `users`, in its own file because you're on TypeScript (skip this file entirely on JavaScript):\n\n```ts\nexport interface User {\n  id: string\n  name: string\n  email: string\n  age: number\n  isActive: boolean\n  createdAt: string\n}\n```\n\n`src/models/users.model.ts` — adapter-correct queries for whichever database you picked, built from the exact fields you typed for `users`, importing the interface from `types/` instead of declaring it inline (this is the `pg` version; MongoDB, Knex, TypeORM, and Sequelize each get their own types file too — Mongoose and Drizzle don't, since their ORM already infers real types, so a second hand-written one would just risk drifting out of sync; skipping the database step gets an in-memory `Map`, still with its own types file):\n\n```ts\nimport type { Pool } from 'pg'\nimport type { User } from '../types/users.types.js'\nimport { db } from '../config/database.js'\n\nconst pool = () => db.client as Pool\n\nexport async function listUsers(): Promise<User[]> {\n  const { rows } = await pool().query(\n    'SELECT id, name, email, age, isActive, created_at AS \"createdAt\" FROM users ORDER BY created_at DESC',\n  )\n  return rows\n}\n\nexport async function createUser(data: { name: string; email: string; age: number; isActive: boolean }): Promise<User> {\n  const { rows } = await pool().query(\n    'INSERT INTO users (name, email, age, isActive) VALUES ($1, $2, $3, $4) RETURNING id, name, email, age, isActive, created_at AS \"createdAt\"',\n    [data.name, data.email, data.age, data.isActive],\n  )\n  return rows[0]\n}\n```\n\nThe same file in **JavaScript** — no `types/` file, no `import type`, no annotations, same query and same fields:\n\n```js\nimport { db } from '../config/database.js'\n\nconst pool = () => db.client\n\nexport async function listUsers() {\n  const { rows } = await pool().query(\n    'SELECT id, name, email, age, isActive, created_at AS \"createdAt\" FROM users ORDER BY created_at DESC',\n  )\n  return rows\n}\n\nexport async function createUser(data) {\n  const { rows } = await pool().query(\n    'INSERT INTO users (name, email, age, isActive) VALUES ($1, $2, $3, $4) RETURNING id, name, email, age, isActive, created_at AS \"createdAt\"',\n    [data.name, data.email, data.age, data.isActive],\n  )\n  return rows[0]\n}\n```\n\n`src/routes/users.routes.ts` — the schema comes from whichever validator you picked, one entry per field, correctly typed (Zod here; Joi/Yup/Valibot/TypeBox each get their own real schema built the same way, and skipping validation drops the `body:` key entirely):\n\n```ts\nimport { z } from 'zod'\nimport { app } from '../app.js'\nimport { createUserHandler, listUsersHandler } from '../controllers/users.controller.js'\n\nconst createUserSchema = z.object({ name: z.string(), email: z.string(), age: z.number(), isActive: z.boolean() })\n\napp.route({\n  method: 'GET',\n  path: '/users',\n  auth: false,\n  handler: listUsersHandler,\n})\n\napp.route({\n  method: 'POST',\n  path: '/users',\n  auth: true,\n  roles: ['admin', 'editor'],\n  body: createUserSchema,\n  handler: createUserHandler,\n})\n```\n\n`posts` in the same run only got one field (`title:string`), so its model, schema, and controller only mention `title` — every resource's generated content matches exactly what you told it that resource has. The `auth: true, roles: [...]` on the `POST` route came from answering \"Yes\" to authorization — leave that as `auth: false` with authorization off, same as before.\n\n`src/middleware/requestTimer.middleware.ts` — the one file every scaffold gets regardless of theme, stack, or the auth/authorization/i18n answers, already wired into `app.ts`'s `middleware: [...]`:\n\n```ts\nimport type { Middleware } from '@api-kickstart/api-kickstart'\n\nexport const requestTimer: Middleware = async (ctx, next) => {\n  const start = Date.now()\n  await next()\n  ctx.logger.info({ requestId: ctx.requestId, method: ctx.method, path: ctx.path, ms: Date.now() - start })\n}\n```\n\n`src/config/auth.ts` — this is the JWT version; API key generates an in-memory key map instead, and picking both generates both plus an `auth = [jwtAuth, apiKeyAuth]` array:\n\n```ts\nimport { hashPassword, jwt, verifyPassword } from '@api-kickstart/api-kickstart/auth'\n\n// Replace this in-memory list with a real user lookup (database, etc.) — it's here so\n// the scaffold runs immediately with no setup. Try logging in with admin / admin123.\nconst users = [{ id: '1', username: 'admin', role: 'admin', passwordHash: await hashPassword('admin123') }]\n\nexport const auth = jwt({\n  secret: process.env.JWT_SECRET ?? 'dev-secret-change-me',\n  resolveUser: async (payload) => {\n    const user = users.find((u) => u.id === String(payload.sub))\n    return user ? { id: user.id, role: user.role, username: user.username } : null\n  },\n  verifyCredentials: async ({ username, password }) => {\n    const user = users.find((u) => u.username === username)\n    if (!user) return null\n    const valid = await verifyPassword(password, user.passwordHash)\n    return valid ? { id: user.id, role: user.role, username: user.username } : null\n  },\n})\n```\n\n`src/config/roles.ts` and `src/config/i18n.ts` — generated when you answer yes to authorization / i18n:\n\n```ts\nimport type { RoleHierarchy } from '@api-kickstart/api-kickstart'\n\n// admin inherits editor's access, editor inherits viewer's — adjust to match your app's roles.\nexport const roleHierarchy: RoleHierarchy = {\n  admin: ['editor'],\n  editor: ['viewer'],\n}\n```\n\n```ts\nimport { createI18n } from '@api-kickstart/api-kickstart/i18n'\n\nexport const i18n = createI18n({\n  locales: ['en', 'id'],\n  defaultLocale: 'en',\n  dictionaries: {\n    en: { welcome: 'Welcome, {name}!' },\n    id: { welcome: 'Selamat datang, {name}!' },\n  },\n})\n\n// Usage: i18n.t('welcome', { name: 'World' }) — resolves against the request's detected locale.\n```\n\n`src/config/lock.ts` — generated when production essentials is on; picks the distributed lock that matches your database adapter (this is the `pg` version — Knex and MongoDB get `knexLock`/`mongodbLock` the same way, everything else falls back to `memoryLock`, good for local dev or a single instance):\n\n```ts\nimport type { Pool } from 'pg'\nimport { pgLock } from '@api-kickstart/api-kickstart/pg'\nimport { db } from './database.js'\n\nexport const lock = pgLock(db.client as Pool)\n```\n\n`src/app.ts` ties everything together — framework, validator, db, auth, role hierarchy, and middleware (request timer, then any security middleware you picked in canonical order, then the i18n locale-detector) — calls `useAuthRoutes()` whenever JWT is part of the auth answer, adds a statement per ops endpoint you picked, and appends the scheduled-job example when production essentials is on:\n\n```ts\nimport { createApp } from '@api-kickstart/api-kickstart'\nimport { express } from '@api-kickstart/api-kickstart/express'\nimport { zod } from '@api-kickstart/api-kickstart/zod'\nimport { db } from './config/database.js'\nimport { requestTimer } from './middleware/requestTimer.middleware.js'\nimport { requestId, helmet, rateLimit } from '@api-kickstart/api-kickstart/middleware'\nimport { auth } from './config/auth.js'\nimport { roleHierarchy } from './config/roles.js'\nimport { i18n } from './config/i18n.js'\nimport { lock } from './config/lock.js'\n\nexport const app = createApp({\n  framework: express(),\n  validator: zod(),\n  db,\n  auth,\n  roleHierarchy,\n  middleware: [requestTimer, requestId(), helmet(), rateLimit({ window: '1m', max: 100 }), i18n.middleware],\n})\n\napp.health()\napp.metrics()\napp.openapi({\n  info: { title: 'API', version: '1.0.0' },\n  json: '/openapi.json',\n  serve: '/docs',\n})\n\napp.useAuthRoutes({ login: '/auth/login', refresh: '/auth/refresh', logout: '/auth/logout', me: '/auth/me' })\n\napp.schedule('example-job', { interval: '5m', lock }, async () => {\n  console.log('running example-job')\n})\n```\n\n`src/index.ts` imports `routes/index.ts` (which re-exports every module's routes as a side effect), calls `app.listen()`, and wires `gracefulShutdown(app)` in when production essentials is on:\n\n```ts\nimport { env } from './config/env.js'\nimport { app } from './app.js'\nimport { gracefulShutdown } from '@api-kickstart/api-kickstart'\nimport './routes/index.js'\n\napp.listen(env.port, () => {\n  console.log(`Server listening on http://localhost:${env.port}`)\n})\n\ngracefulShutdown(app)\n```\n\nPick **Modular by feature** instead and the exact same model/service/controller/routes files per resource land under `modules/users/` and `modules/posts/` together, with `app.ts`/`config/`/`middleware/` still shared at the top of `src/`.\n\nEvery adapter you didn't pick is still fully implemented and ready — you can always `import` its subpath later, you just need the underlying library installed first. Picked wrong, or need another one mid-project (e.g. you're adding Kafka six months in)? Run it again any time:\n\n```bash\nnpx api-kickstart add            # walks through every category again\nnpx api-kickstart add broker     # jump straight to one category (framework|database|broker|validation|storage|logging)\n```\n\n`init`/`add` detect npm/yarn/pnpm/bun from whatever lockfile is in the current directory and shell out to the matching install command; both need a real interactive terminal (not piped, not CI) since they prompt. The one adapter neither command installs is Prisma: `db: prisma(client)` takes any object shaped like a `PrismaClient`, and `@prisma/client` has to be generated against *your* schema (`prisma generate`) rather than just installed — do that one yourself.\n\nPrefer to skip the wizard entirely? Every adapter is also listed as an optional peer dependency, so `npm install express pg zod` (or whatever you need) works exactly like installing any other library with peer deps.\n\n---\n\n## 60-second start\n\n```ts\nimport { createApp } from '@api-kickstart/api-kickstart'\nimport { express } from '@api-kickstart/api-kickstart/express'\nimport { jwt } from '@api-kickstart/api-kickstart/auth'\nimport { zod } from '@api-kickstart/api-kickstart/zod'\nimport { prisma } from '@api-kickstart/api-kickstart/prisma'\nimport { z } from 'zod'\n\nconst app = createApp({\n  framework: express(),\n  validator: zod(),\n  db: prisma(prismaClient),\n\n  auth: jwt({\n    secret: env.JWT_SECRET,\n    accessTtl: '15m',\n    refreshTtl: '30d',\n  }),\n\n  cors: 'dev',\n})\n\napp.route({\n  method: 'GET',\n  path: '/orders',\n  auth: true,\n  roles: ['staff', 'manager', 'admin'],\n  scope: 'order',\n  query: z.object({\n    status: z.enum(['open', 'closed']).optional(),\n    limit: z.coerce.number().max(100).default(20),\n  }),\n  handler: async (ctx) => {\n    return ctx.db.order.findMany({\n      where: { ...ctx.scope, ...ctx.query },\n      take: ctx.query.limit,\n    })\n  },\n})\n\napp.listen(3000)\n```\n\nThat gives you: JWT verification, role checking, row-level filtering, query validation, CORS, a JSON error handler, request IDs, and graceful shutdown.\n\n---\n\n## Core concepts\n\nFive ideas. Once you have these, the rest of the docs are reference.\n\n**1. Routes are data, not side effects.**\n`app.route({...})` registers a plain object. Because routes are inspectable, OpenAPI generation, permission audits, and route listings come for free.\n\n**2. Everything is an adapter.**\nAuth strategies, validators, databases, brokers, and frameworks all implement small interfaces. Nothing is hardcoded. If an adapter doesn't exist, writing one is usually under 50 lines — every category below documents the exact interface and links a real one to copy.\n\n**3. One context object.**\nHandlers receive a `ctx` carrying the user, validated input, scope filter, db, broker, logger, and request ID. No juggling `req`, `res`, `next`.\n\n**4. Fail closed.**\nUndefined role in a scope map, missing permission, unknown route config — all deny. Never silently allow. Misconfiguration should break loudly in development, not leak data in production.\n\n**5. Escape hatches everywhere.**\nEvery layer exposes the underlying object: `ctx.raw.req`, `ctx.raw.res`, `ctx.db.$client`. When the abstraction doesn't fit, drop through it instead of fighting it.\n\n---\n\n## Authentication\n\nAuthentication answers *who is this*. It attaches `ctx.user` or fails with `401`.\n\n### JWT\n\n```ts\nimport { jwt } from '@api-kickstart/api-kickstart/auth'\n\njwt({\n  secret: env.JWT_SECRET,          // or `publicKey` / `privateKey` for RS256 / ES256\n  algorithm: 'HS256',              // pinned — tokens with other algs are rejected\n  accessTtl: '15m',\n  refreshTtl: '30d',\n  issuer: 'my-api',\n  audience: 'my-app',\n\n  // where to read the token from, in order\n  from: ['header:authorization', 'cookie:access_token'],\n\n  // called after signature verification, to load the full user\n  resolveUser: async (payload) => db.user.findUnique({ where: { id: payload.sub } }),\n\n  // optional: reject revoked tokens (logout, password change, ban)\n  isRevoked: async (payload) => redis.exists(`revoked:${payload.jti}`),\n\n  // optional: verify username/password for app.useAuthRoutes()'s login endpoint\n  verifyCredentials: async ({ username, password }) => {\n    const user = await db.user.findUnique({ where: { username } })\n    if (!user || !(await verifyPassword(password, user.passwordHash))) return null\n    return user\n  },\n\n  // optional: persist refresh-token state somewhere other than memory (see below)\n  refreshStore: myRefreshStore,\n})\n```\n\n`JwtOptions` reference:\n\n| Field | Type | Required | Notes |\n|---|---|---|---|\n| `secret` | `string` | one of `secret`/`privateKey`+`publicKey` | HMAC secret, for `HS256`/`HS384`/`HS512` |\n| `privateKey` / `publicKey` | key material | for RS/ES algorithms | used for `RS256`/`RS384`/`RS512`/`ES256`/`ES384`/`ES512` |\n| `algorithm` | `string` | no, default `HS256` | pinned — verification rejects tokens signed with any other algorithm |\n| `accessTtl` | `string` | no, default `15m` | duration string: `<n><s\\|m\\|h\\|d>` |\n| `refreshTtl` | `string` | no, default `30d` | same format |\n| `issuer` | `string` | no | set and verified if provided |\n| `audience` | `string` | no | set and verified if provided |\n| `from` | `string[]` | no, default `['header:authorization', 'cookie:access_token']` | checked in order; `header:<name>` expects `Bearer <token>`, `cookie:<name>` reads the cookie value directly |\n| `resolveUser` | `(payload) => Promise<AuthenticatedUser \\| null>` | **yes** | loads the full user record after signature verification passes |\n| `isRevoked` | `(payload) => Promise<boolean>` | no | called before `resolveUser`; return `true` to reject an otherwise-valid token |\n| `verifyCredentials` | `(creds: { username, password }) => Promise<AuthenticatedUser \\| null>` | no | backs `app.useAuthRoutes()`'s `login` endpoint |\n| `refreshStore` | `RefreshStore` | no, default in-memory | persists refresh-token rotation state — see below |\n\nBuilt-in token endpoints, if you want them:\n\n```ts\napp.useAuthRoutes({\n  login:   '/auth/login',     // verify credentials → access + refresh token\n  refresh: '/auth/refresh',   // rotate refresh token\n  logout:  '/auth/logout',    // revoke by jti\n  me:      '/auth/me',\n})\n```\n\nRefresh tokens are **rotated** by default: using one invalidates it and issues a new pair. If a rotated token is used again, the whole family is revoked — that's the standard defense against stolen refresh tokens.\n\nRotation state (which `jti`s exist, which are used, which families are revoked) is tracked by a `RefreshStore`:\n\n```ts\ninterface RefreshRecord {\n  jti: string\n  familyId: string\n  userId: string\n  used: boolean\n}\n\ninterface RefreshStore {\n  save(record: RefreshRecord): Promise<void>\n  get(jti: string): Promise<RefreshRecord | null>\n  markUsed(jti: string): Promise<void>\n  revokeFamily(familyId: string): Promise<void>\n  isRevokedFamily(familyId: string): Promise<boolean>\n}\n```\n\nWithout a `refreshStore` option, `jwt()` uses an **in-memory** one — fine for a single instance, but state (and therefore rotation/revocation) doesn't survive a restart or get shared across instances behind a load balancer. Implement `RefreshStore` against Redis or your database for that.\n\n> Signing and verification use [`jose`](https://github.com/panva/jose) internally. This package handles the flow around tokens; it does not implement its own cryptography.\n\n### Password hashing\n\n```ts\nimport { hashPassword, verifyPassword } from '@api-kickstart/api-kickstart/auth'\n\nconst hash = await hashPassword(plainTextPassword)   // scrypt, node:crypto, no extra dependency\nawait verifyPassword(plainTextPassword, hash)          // constant-time compare\n```\n\n`hashPassword(password, options?)` — `options: { keyLength?: number /* default 64 */; cost?: number /* default 16384, the scrypt CPU/memory cost parameter N */ }`.\n\nUse these in `jwt()`'s `verifyCredentials` or wherever you check a login. `hashPassword` generates a random 16-byte salt per call and encodes the result as `scrypt$<cost>$<salt-hex>$<hash-hex>` — `verifyPassword` reads the cost and salt back out of the stored string, so there's nothing else to persist. `verifyPassword` returns `false` (never throws) for a malformed hash string.\n\n### Session\n\n```ts\nimport { session } from '@api-kickstart/api-kickstart/auth'\n\nsession({\n  store: myStore,                  // required — see SessionStore below\n  cookieName: 'sid',\n  ttl: '7d',\n  rolling: true,                   // refresh expiry on activity\n  cookie: {\n    httpOnly: true,\n    secure: true,\n    sameSite: 'lax',\n  },\n})\n```\n\n`SessionOptions` reference:\n\n| Field | Type | Required | Notes |\n|---|---|---|---|\n| `store` | `SessionStore` | **yes** | see below — the built-in default is only an in-memory `memoryStore()` |\n| `cookieName` | `string` | no, default `'sid'` | |\n| `ttl` | `string` | no, default `7d` | duration string |\n| `rolling` | `boolean` | no | if `true`, every successful `authenticate()` re-writes the record with a fresh `expiresAt` |\n| `cookie.httpOnly` / `.secure` / `.sameSite` | `boolean` / `boolean` / `'strict' \\| 'lax' \\| 'none'` | no | not enforced by `session()` itself — these are yours to apply when you set the cookie in your login route |\n\n`SessionStore` interface:\n\n```ts\ninterface SessionRecord {\n  userId: string\n  data: AuthenticatedUser\n  expiresAt: number\n}\n\ninterface SessionStore {\n  get(sid: string): Promise<SessionRecord | null>\n  set(sid: string, record: SessionRecord): Promise<void>\n  destroy(sid: string): Promise<void>\n}\n```\n\n`memoryStore()` (imported from the same `/auth` subpath) is the built-in in-memory implementation, useful for local dev and tests. For anything that needs to survive a restart or run behind more than one instance, use `redisSessionStore()` from [Redis-backed stores](#redis-backed-stores), or implement `SessionStore` against your own database.\n\nSession IDs are regenerated (`randomUUID()`) every time `create()` is called — i.e. on every login — to prevent session fixation.\n\n### API key\n\n```ts\nimport { apiKey } from '@api-kickstart/api-kickstart/auth'\n\napiKey({\n  from: 'header:x-api-key',\n  resolve: async (key) => db.apiKey.findUnique({ where: { hash: sha256(key) } }),\n})\n```\n\n`ApiKeyOptions` reference:\n\n| Field | Type | Required | Notes |\n|---|---|---|---|\n| `from` | `string` | no, default `'header:x-api-key'` | only `header:<name>` is supported (no cookie source for API keys) |\n| `resolve` | `(key: string) => Promise<AuthenticatedUser \\| null>` | **yes** | return `null` to reject |\n\n`sha256(value)` and `safeCompare(a, b)` are also exported from `/auth` as small helpers — `sha256` for hashing keys before storing/looking them up, `safeCompare` for a constant-time string comparison if you need one outside `resolve`. Rate-limiting a key isn't built into `apiKey()` itself — compose it with the `rateLimit` [route option or middleware](#built-ins-reference) instead, keyed by the resolved user or the raw header value.\n\nStore hashes, never raw keys — the `resolve` signature (receiving the raw key, looking it up by its hash) nudges you toward this.\n\n### Basic auth\n\n```ts\nimport { basic } from '@api-kickstart/api-kickstart/auth'\n\nbasic({ verify: async (user, pass) => checkPassword(user, pass) })\n```\n\n`BasicAuthOptions` reference:\n\n| Field | Type | Required | Notes |\n|---|---|---|---|\n| `verify` | `(username: string, password: string) => Promise<AuthenticatedUser \\| boolean \\| null>` | **yes** | return `false`/`null` to reject; returning `true` authenticates as a minimal placeholder user |\n| `allowInsecure` | `boolean` | no, default `false` | by default, refuses to run over plain (non-TLS) HTTP, detected via the `x-forwarded-proto` header |\n\nIntended for internal tools and health endpoints, not end-user APIs.\n\n### OAuth / OIDC\n\n```ts\nimport { oidc } from '@api-kickstart/api-kickstart/auth'\n\nconst google = oidc({\n  issuer: 'https://accounts.google.com',\n  clientId: env.GOOGLE_CLIENT_ID,\n  clientSecret: env.GOOGLE_CLIENT_SECRET,\n  redirectUri: 'https://api.example.com/auth/callback',\n  scopes: ['openid', 'email', 'profile'],\n  onUser: async (profile) => db.user.upsert({ /* ... */ }),\n})\n\ncreateApp({ auth: google, /* ... */ })\n```\n\n`OidcOptions` reference:\n\n| Field | Type | Required | Notes |\n|---|---|---|---|\n| `issuer` | `string` | **yes** | the identity provider's issuer URL; discovery is fetched from `<issuer>/.well-known/openid-configuration` |\n| `clientId` / `clientSecret` | `string` | **yes** | |\n| `redirectUri` | `string` | **yes** | must match what's registered with the provider |\n| `scopes` | `string[]` | no, default `['openid', 'email', 'profile']` | |\n| `from` | `string[]` | no, default same as `jwt()`'s | where `authenticate()` looks for a bearer access token to verify against the provider's JWKS |\n| `onUser` | `(profile: Record<string, unknown>) => Promise<AuthenticatedUser>` | **yes** | maps the provider's userinfo/ID-token claims to your own user shape |\n\nDiscovery, PKCE (S256), state, and nonce are handled for you. JWKS keys are fetched and cached lazily via `jose`'s remote key set, so rotation on the identity provider's side is picked up automatically without a restart.\n\nWire the redirect flow with the two methods the strategy exposes beyond `authenticate()`:\n\n```ts\napp.route({\n  method: 'GET',\n  path: '/auth/google',\n  auth: false,\n  handler: async (ctx) => {\n    const { url, state, codeVerifier } = await google.authorizationUrl()\n    // stash state + codeVerifier in a session/cookie, then redirect the browser to `url`\n    return { redirect: url }\n  },\n})\n\napp.route({\n  method: 'GET',\n  path: '/auth/google/callback',\n  auth: false,\n  handler: async (ctx) => {\n    const { code } = ctx.query\n    // codeVerifier comes back from wherever you stashed it above\n    const { user, tokens } = await google.handleCallback({ code, codeVerifier })\n    return { user, tokens }\n  },\n})\n```\n\n`authorizationUrl(state?)` returns `{ url, state, nonce, codeVerifier }`; `handleCallback({ code, codeVerifier })` returns `{ user, tokens }` where `tokens` is the provider's raw `{ access_token, id_token?, refresh_token?, token_type, expires_in? }`.\n\nOnce a route uses `auth: true` with the OIDC strategy configured, `authenticate()` validates the bearer token's signature against the same JWKS — useful when the identity provider issues JWT access tokens you want to accept directly on your API.\n\n### Multiple strategies\n\nPass an array. They're tried in order; the first success wins.\n\n```ts\nauth: [\n  jwt({ /* ... */ }),          // mobile and SPA clients\n  session({ /* ... */ }),      // server-rendered admin panel\n  apiKey({ /* ... */ }),       // machine-to-machine\n]\n```\n\nRestrict per route when it matters:\n\n```ts\napp.route({\n  path: '/webhooks/stripe',\n  auth: 'apiKey',        // only this strategy is accepted here\n  // ...\n})\n```\n\n### Custom strategy\n\nEvery strategy is just an object implementing `AuthStrategy`:\n\n```ts\ninterface AuthenticateArgs {\n  headers: Record<string, string | string[] | undefined>\n  cookies: Record<string, string>\n  raw: { req: unknown; res: unknown }\n}\n\ninterface AuthStrategy {\n  name: string\n  authenticate(args: AuthenticateArgs): Promise<AuthenticatedUser | null>\n}\n```\n\n```ts\nconst ldap: AuthStrategy = {\n  name: 'ldap',\n  async authenticate(args) {\n    const header = args.headers.authorization\n    const user = await ldapClient.verify(Array.isArray(header) ? header[0] : header)\n    return user ?? null      // null → try the next strategy\n  },\n}\n```\n\n`AuthenticatedUser` only requires `{ id: string; role?: string }` plus any extra fields you want — it's an open index signature (`[key: string]: unknown`).\n\n---\n\n## Authorization\n\nAuthorization answers *is this allowed*. It runs after authentication and fails with `403`.\n\n### Roles\n\n```ts\napp.route({ path: '/admin/users', roles: ['admin'], /* ... */ })\n```\n\nHierarchies, if you want them:\n\n```ts\ncreateApp({\n  roleHierarchy: {\n    admin:   ['manager'],\n    manager: ['staff'],\n    staff:   [],\n  },\n})\n```\n\nAn `admin` now satisfies `roles: ['staff']` without being listed everywhere.\n\n### Permissions\n\nFiner-grained than roles, and usually what you actually want long term:\n\n```ts\ncreateApp({\n  permissions: {\n    admin:   ['*'],\n    manager: ['order:read', 'order:write', 'report:read'],\n    staff:   ['order:read'],\n  },\n})\n\napp.route({ path: '/orders', permissions: ['order:read'], /* ... */ })\n```\n\nWildcards work per segment: `order:*` grants every order action.\n\n### Ownership\n\nFor rules that depend on the record itself:\n\n```ts\napp.route({\n  method: 'PATCH',\n  path: '/orders/:id',\n  load: (ctx) => ctx.db.order.findUnique({ where: { id: ctx.params.id } }),\n  can: async (ctx, order) => order.createdBy === ctx.user.id || ctx.user.role === 'admin',\n  handler: async (ctx) => { /* ... */ },\n})\n```\n\n`load` runs first, `can` receives the loaded record, and a `404` is returned — not a `403` — when the record doesn't exist, so you don't leak which IDs are real.\n\n---\n\n## Scope: row-level filtering\n\nThis is the piece most auth libraries stop short of, and the one that causes real breaches.\n\nRoles decide whether you can call `GET /orders`. Scope decides **which orders come back**.\n\n```ts\ncreateApp({\n  scope: {\n    order: {\n      admin:   () => ({}),                          // everything\n      manager: (u) => ({ branchId: u.branchId }),   // their branch\n      staff:   (u) => ({ createdBy: u.id }),        // their own\n    },\n    invoice: {\n      admin:   () => ({}),\n      manager: (u) => ({ branchId: u.branchId }),\n      // `staff` is not listed → staff are denied entirely\n    },\n  },\n})\n```\n\nIn a handler:\n\n```ts\nhandler: async (ctx) => ctx.db.order.findMany({ where: ctx.scope })\n```\n\n`ctx.scope` is the filter object for the current user, in your database's own query dialect — the adapter translates it. A scope resolver is `(user: AuthenticatedUser) => ScopeFilter | Promise<ScopeFilter>`, where `ScopeFilter` is an open `{ [key: string]: unknown }`.\n\n### It applies to writes too\n\nFiltering reads while leaving writes open is the most common half-implementation. A `findByIdAndUpdate` with an ID from another tenant will happily succeed.\n\nScope is enforced on `update` and `delete` as well (when using `app.resource()` — see [CRUD shorthand](#crud-shorthand)). A staff member updating someone else's order gets a `404`, because within their scope that row does not exist.\n\n### Fail closed\n\nIf a role isn't defined for a resource, access is denied. There is no implicit \"if unspecified, allow all.\" Getting this backwards is how `{}` ends up meaning \"every row in the table.\"\n\n### Audit mode\n\n```ts\ncreateApp({ scopeAudit: 'warn' })   // 'off' | 'warn' | 'throw'\n```\n\nWhen a route declares `scope`, `ctx.scope` is handed to the handler wrapped so api-kickstart knows whether it was ever actually read. If the handler finishes without touching `ctx.scope` at all — the strongest available signal that the query it ran didn't apply the filter — `'warn'` logs it (with a stack trace) and `'throw'` fails the request outright instead of returning data that was never scoped:\n\n```\n{ requestId: '...', route: 'GET /orders', message: 'Route GET /orders declares scope: \"order\" but the handler never read ctx.scope', stack: '...' }\n```\n\nThis catches the \"forgot to spread `ctx.scope` into the query\" class of bug. It can't catch a handler that reads `ctx.scope` and then ignores it, since there's no way to verify what a raw database call downstream actually did with the value — that would need per-adapter query interception, which isn't implemented. `app.diagnostics().scopeAudit` exposes the configured value, and `npx api-kickstart doctor` fails the `scope-audit-enabled` check when it's left at `'off'`.\n\n### Hierarchies\n\nFor \"a manager sees their own data plus everyone below them\":\n\n```ts\nscope: {\n  order: {\n    manager: async (u) => ({ createdBy: { in: await getSubordinateIds(u.id) } }),\n  },\n}\n```\n\nResolvers can be async, and results are cached per request.\n\n---\n\n## Validation\n\nAdapters exist for Zod, Joi, Yup, Valibot, and TypeBox. Pick one; the route API is identical:\n\n```ts\napp.route({\n  method: 'POST',\n  path: '/orders/:id/items',\n  params: z.object({ id: z.string().uuid() }),\n  query:  z.object({ notify: z.coerce.boolean().default(false) }),\n  body:   z.object({\n    sku: z.string().min(1),\n    qty: z.number().int().positive(),\n  }),\n  headers: z.object({ 'idempotency-key': z.string().optional() }),\n  response: z.object({ id: z.string(), total: z.number() }),\n  handler: async (ctx) => {\n    ctx.params.id    // typed\n    ctx.body.qty     // typed\n  },\n})\n```\n\n**Response validation** runs in development and is skipped in production by default. It catches the case where you accidentally return a password hash.\n\nFailures produce a consistent shape:\n\n```json\n{\n  \"error\": {\n    \"code\": \"VALIDATION_ERROR\",\n    \"message\": \"Request validation failed\",\n    \"details\": [\n      { \"path\": \"body.qty\", \"message\": \"Expected positive integer, received -3\" }\n    ],\n    \"requestId\": \"req_01HXYZ\"\n  }\n}\n```\n\nEvery validator adapter is a zero-argument factory (`zod()`, `joi()`, etc.) implementing:\n\n```ts\ninterface Validator {\n  name: string\n  parse(schema: unknown, value: unknown, path: string): unknown   // throws SchemaValidationError on failure\n  toJsonSchema?(schema: unknown): unknown                          // optional — powers OpenAPI schema output\n}\n```\n\n### Zod\n\n```ts\nimport { zod } from '@api-kickstart/api-kickstart/zod'\nimport { z } from 'zod'\n\ncreateApp({ validator: zod() })\n```\n\n**Types flow through** — `ctx.body`/`ctx.query`/`ctx.params` are fully typed from the Zod schema, no manual interface, no casting. `toJsonSchema` delegates to `zod-to-json-schema` (installed alongside `zod` if you pick it via `npx api-kickstart init`/`add`) with `target: 'openApi3'`. Uses: `zod` (`^3.23.0`).\n\n### Joi\n\n```ts\nimport { joi } from '@api-kickstart/api-kickstart/joi'\nimport Joi from 'joi'\n\ncreateApp({ validator: joi() })\n\napp.route({\n  body: Joi.object({\n    sku: Joi.string().required(),\n    qty: Joi.number().integer().positive(),\n  }),\n  // ...\n})\n```\n\nValidates with `schema.validate(value, { abortEarly: false })` so every field's errors are collected, not just the first. `toJsonSchema` delegates to the `joi-to-json` package. Uses: `joi` (`^17.13.3`), `joi-to-json` (`^5.0.5`) — the second is only needed if you call `toJsonSchema` (i.e. use OpenAPI schema generation).\n\n### Yup\n\n```ts\nimport { yup } from '@api-kickstart/api-kickstart/yup'\nimport { object, string, number } from 'yup'\n\ncreateApp({ validator: yup() })\n\napp.route({\n  body: object({\n    sku: string().min(1).required(),\n    qty: number().integer().positive().required(),\n  }),\n  // ...\n})\n```\n\nValidates with `schema.validateSync(value, { abortEarly: false })`. `toJsonSchema` delegates to `@sodaru/yup-to-json-schema`'s `convertSchema`. Uses: `yup` (`^1.4.0`), `@sodaru/yup-to-json-schema` (`^2.0.1`).\n\n### Valibot\n\n```ts\nimport { valibot } from '@api-kickstart/api-kickstart/valibot'\nimport * as v from 'valibot'\n\ncreateApp({ validator: valibot() })\n\napp.route({\n  body: v.object({\n    sku: v.pipe(v.string(), v.minLength(1)),\n    qty: v.pipe(v.number(), v.integer()),\n  }),\n  // ...\n})\n```\n\nValidates with `v.safeParse(schema, value)`. `toJsonSchema` delegates to `@valibot/to-json-schema`. Types flow through, same as Zod. Uses: `valibot` (`^1.4.0`), `@valibot/to-json-schema` (`^1.4.0`).\n\n### TypeBox\n\n```ts\nimport { typebox } from '@api-kickstart/api-kickstart/typebox'\nimport { Type } from '@sinclair/typebox'\n\ncreateApp({ validator: typebox() })\n\napp.route({\n  body: Type.Object({\n    sku: Type.String({ minLength: 1 }),\n    qty: Type.Integer({ minimum: 1 }),\n  }),\n  // ...\n})\n```\n\nValidates with `@sinclair/typebox/value`'s `Value.Check`/`Value.Errors`. `toJsonSchema` is a trivial passthrough — TypeBox schemas already *are* JSON Schema. Uses: `@sinclair/typebox` (`^0.33.0`).\n\n### Writing your own validator\n\n```ts\nconst myValidator: Validator = {\n  name: 'my-validator',\n  parse(schema, value, path) {\n    const result = mySchemaLib.validate(schema, value)\n    if (!result.success) {\n      throw new SchemaValidationError(result.errors.map((e) => ({ path: e.path, message: e.message })))\n    }\n    return result.value\n  },\n  toJsonSchema(schema) {\n    return mySchemaLib.toJsonSchema(schema)   // optional\n  },\n}\n```\n\n`SchemaValidationError` (from `@api-kickstart/api-kickstart/errors`) takes an array of `{ path: string; message: string }` and is what turns into the `VALIDATION_ERROR` response shown above.\n\n---\n\n## Regex patterns\n\nA small named registry of common validation regexes, framework-independent — plug them into any validator's own pattern/regex support (Zod's `.regex()`, Joi's `.pattern()`, Yup's `.matches()`, Valibot's `regex()`, or TypeBox's `Type.String({ pattern })` via `.source`):\n\n```ts\nimport { patterns } from '@api-kickstart/api-kickstart/patterns'\nimport { z } from 'zod'\n\nconst schema = z.object({\n  email: z.string().regex(patterns.get('email')),\n  sku: z.string().regex(patterns.get('sku')),   // registered below\n})\n```\n\n**112 built in** (`patterns.list()` returns the full sorted list), grouped by category:\n\n| Category | Names |\n|---|---|\n| Identifiers / text case | `email`, `url`, `urlWithoutProtocol`, `domain`, `hostname`, `subdomain`, `slug`, `kebabCase`, `camelCase`, `pascalCase`, `snakeCase`, `constantCase`, `username` |\n| Character classes | `alphanumeric`, `alpha`, `alphaSpaces`, `numeric`, `integer`, `positiveInteger`, `negativeInteger`, `decimal`, `float`, `whitespace`, `noWhitespace` |\n| IDs | `uuid` (v4), `uuidV1`, `uuidV3`, `uuidV5`, `uuidAny`, `nanoid`, `objectId` (MongoDB) |\n| Network | `ipv4`, `ipv6`, `ipv4Cidr`, `ipv6Cidr`, `macAddress`, `port` |\n| Colors | `hexColor`, `rgbColor`, `rgbaColor`, `hslColor` |\n| Security / tokens | `jwt`, `base64`, `base64url`, `md5`, `sha1`, `sha256`, `sha512`, `bearerToken`, `bcryptHash`, `hexadecimal`, `base32`, `base58` |\n| Dates & times | `isoDate`, `isoDateTime`, `isoDateTimeMs`, `isoTime`, `isoWeek`, `usDate`, `euDate`, `dottedDate`, `time24h`, `time12h`, `unixTimestampSeconds`, `unixTimestampMillis`, `yearMonth`, `monthDay`, `cronExpression`, `isoDuration` |\n| Phone / postal / geo | `phone`, `usPhone`, `usPhoneExt`, `ukPhone`, `usZip`, `usZipPlus4`, `canadianPostalCode`, `ukPostalCode`, `latitude`, `longitude`, `geoCoordinate` |\n| Finance / identity | `creditCardVisa`, `creditCardMastercard`, `creditCardAmex`, `creditCardDiscover`, `creditCardGeneric`, `creditCardExpiry`, `cvv`, `iban`, `usSSN`, `usEIN`, `currencyUSD`, `isbn10`, `isbn13` |\n| Dev ecosystem | `semver`, `npmPackageName`, `npmScopedPackageName`, `dockerImageTag`, `gitShortHash`, `gitLongHash`, `environmentVariableName`, `httpHeaderName`, `mimeType` |\n| Misc | `strongPassword`, `htmlTag`, `filePathUnix`, `filePathWindows`, `fileExtension`, `base64Image`, `jsonPointer`, `cssClassName`, `hashtag`, `twitterHandle` |\n\n```ts\ninterface PatternRegistry {\n  get(name: string): RegExp        // throws UnknownPatternError if not registered\n  has(name: string): boolean\n  register(name: string, pattern: RegExp): void\n  list(): string[]                  // sorted names\n}\n```\n\n`patterns` (the default export) is a shared, pre-seeded registry — `register()` on it adds a name process-wide, so it's the right place for names your whole app reuses:\n\n```ts\npatterns.register('sku', /^[A-Z]{3}-\\d{4}$/)\npatterns.register('postalCodeUS', /^\\d{5}(-\\d{4})?$/)\n```\n\nFor an isolated registry instead (e.g. per-module, or in tests where you don't want to leak custom names globally), use `createPatternRegistry()` — starts empty by default, or pass a seed object to start with your own set instead of the built-ins:\n\n```ts\nimport { createPatternRegistry } from '@api-kickstart/api-kickstart/patterns'\n\nconst orderPatterns = createPatternRegistry({ orderId: /^ORD-\\d{6}$/ })\norderPatterns.get('orderId')\n```\n\n`patterns.get('unknown-name')` throws `UnknownPatternError` (a plain `Error`, not an `AppError` — this is a programmer mistake to catch in development, not a request-time validation failure) rather than returning `undefined`, so a typo'd pattern name fails loudly at the call site instead of silently producing a schema that matches nothing (or everything).\n\nSeveral of the built-ins are deliberately loose *shape* checks rather than exhaustive validators — real-world validation for these needs either a live lookup or a dedicated library, not just a regex:\n\n- `phone`/`usPhone`/`ukPhone` — no regex correctly validates every country's numbering plan; use `libphonenumber-js` if you need real validation.\n- `email`/`url` — the same widely-used pattern browsers use for `<input type=\"email\">`/`<input type=\"url\">`, not the full RFC 5322/3986 grammar.\n- `creditCardVisa`/`creditCardMastercard`/`creditCardAmex`/`creditCardDiscover` — check the issuer-prefix and length only, not the Luhn checksum or whether the card actually exists.\n- `usSSN`/`usEIN`/`iban`/`isbn10`/`isbn13` — check format/checksum-adjacent structure, not that the number was actually issued.\n- `cronExpression` — validates the 5-field shape and character set, not that each field's value is in a semantically valid range for its position.\n- `canadianPostalCode` — the letter-exclusion rules follow Canada Post's general pattern, not the full official specification.\n\n---\n\n## Date formatting\n\n```ts\nimport { formatDate, formatDateUTC, formatDateAs, formatDateAsUTC, formatDateForDb, DATE_FORMATS } from '@api-kickstart/api-kickstart/dates'\n\nformatDate(new Date(), 'YYYY-MM-DD HH:mm:ss')      // local time, e.g. '2024-01-05 09:07:03'\nformatDateUTC(new Date(), 'YYYY-MM-DD HH:mm:ss')   // UTC, e.g. '2024-01-05 02:07:03'\nformatDateAs(new Date(), 'usDate')                 // '01/05/2024', via the named DATE_FORMATS below\nformatDateAsUTC(new Date(), 'isoDateTimeTz')       // same presets, UTC fields + '+00:00' offset\nformatDateForDb(new Date(), 'postgres')            // UTC by default, e.g. '2024-01-05 02:07:03.045'\n```\n\n`formatDate(date, pattern)` replaces tokens in `pattern` using the `Date`'s **local** (server) time (same convention as `date-fns`/`dayjs`'s `format()`). `formatDateUTC(date, pattern)` is the same token replacement but reads every field — year, month, day, hour, day-of-week, and the `Z`/`ZZ` offset — off the `Date`'s UTC representation instead, so output is identical no matter what timezone the process runs in. `formatDateAs`/`formatDateAsUTC` are the local/UTC counterparts for the named presets below:\n\n| Token | Meaning | Example |\n|---|---|---|\n| `YYYY` / `YY` | 4-digit / 2-digit year | `2024` / `24` |\n| `MMMM` / `MMM` / `MM` / `M` | full / short month name, or 2-digit / unpadded month number | `January` / `Jan` / `01` / `1` |\n| `DD` / `D` | 2-digit / unpadded day of month | `05` / `5` |\n| `dddd` / `ddd` | full / short day name | `Friday` / `Fri` |\n| `HH` / `H` | 2-digit / unpadded 24-hour | `09` / `9` |\n| `hh` / `h` | 2-digit / unpadded 12-hour | `09` / `9` |\n| `mm` / `m` | 2-digit / unpadded minute | `07` / `7` |\n| `ss` / `s` | 2-digit / unpadded second | `03` / `3` |\n| `SSS` | 3-digit millisecond | `045` |\n| `A` / `a` | uppercase / lowercase `AM`/`PM` | `AM` / `am` |\n| `Z` / `ZZ` | timezone offset, colon / no colon | `+07:00` / `+0700` |\n\nAny character not matching a token (`-`, `/`, `:`, `,`, spaces, literal `T`, ...) passes through unchanged.\n\n`formatDateAs(date, name)` applies one of the named presets in `DATE_FORMATS` instead of writing the token string yourself:\n\n```ts\nDATE_FORMATS.isoDate           // 'YYYY-MM-DD'\nDATE_FORMATS.isoDateTime       // 'YYYY-MM-DDTHH:mm:ss'\nDATE_FORMATS.isoDateTimeMs     // 'YYYY-MM-DDTHH:mm:ss.SSS'\nDATE_FORMATS.isoDateTimeTz     // 'YYYY-MM-DDTHH:mm:ssZ'\nDATE_FORMATS.usDate            // 'MM/DD/YYYY'\nDATE_FORMATS.usDateTime        // 'MM/DD/YYYY hh:mm A'\nDATE_FORMATS.euDate            // 'DD/MM/YYYY'\nDATE_FORMATS.euDateTime        // 'DD/MM/YYYY HH:mm'\nDATE_FORMATS.dottedDate        // 'DD.MM.YYYY'\nDATE_FORMATS.longDate          // 'MMMM D, YYYY'\nDATE_FORMATS.shortDate         // 'MMM D, YYYY'\nDATE_FORMATS.dayMonthYearDashed // 'DD-MM-YYYY'\nDATE_FORMATS.time24            // 'HH:mm:ss'\nDATE_FORMATS.time24Short       // 'HH:mm'\nDATE_FORMATS.time12            // 'hh:mm:ss A'\nDATE_FORMATS.time12Short       // 'hh:mm A'\nDATE_FORMATS.fullDateTime      // 'dddd, MMMM D, YYYY HH:mm:ss'\nDATE_FORMATS.logTimestamp      // 'YYYY-MM-DD HH:mm:ss.SSS'\nDATE_FORMATS.fileNameSafe      // 'YYYY-MM-DD_HH-mm-ss'\n```\n\n`formatDateForDb(date, dialect, options?)` formats a `Date` the way a given database dialect expects it in a raw query or string column, so you're not hand-rolling `toISOString().slice(...)` per adapter:\n\n| `dialect` | Output format | Example (UTC) |\n|---|---|---|\n| `'mysql'` / `'sqlite'` | `YYYY-MM-DD HH:mm:ss` | `2024-01-05 09:07:03` |\n| `'postgres'` / `'mssql'` | `YYYY-MM-DD HH:mm:ss.SSS` | `2024-01-05 09:07:03.045` |\n| `'oracle'` | `DD-MON-YYYY` (uppercase) | `05-JAN-2024` |\n| `'mongodb'` | native `Date.prototype.toISOString()` | `2024-01-05T09:07:03.045Z` |\n\n**`formatDateForDb` defaults to UTC** for every dialect (`mongodb` already did, via `toISOString()`) — a raw date string headed for a database shouldn't silently depend on whatever timezone the server process happens to run in. Pass `{ utc: false }` to opt back into the process's local time instead:\n\n```ts\nformatDateForDb(new Date(), 'mysql')                    // UTC (default)\nformatDateForDb(new Date(), 'mysql', { utc: false })     // local server time\n```\n\nThis is a formatter, not a parameterized-query builder — most adapters in this package (`pg`, `knex`, `mongoose`, ...) accept a native `Date` object directly and don't need string formatting at all; reach for `formatDateForDb` specifically when you're building a raw SQL string or need a DB-shaped string for something other than a bound query parameter (a filename, a log line, a CSV export, a legacy column expecting text).\n\n---\n\n## Internationalization (i18n)\n\nDictionary-based translation, plus a middleware that figures out which locale a client wants — from a query param, a cookie, or the standard `Accept-Language` header — with a configured default when none of them say anything usable.\n\n```ts\nimport { createI18n } from '@api-kickstart/api-kickstart/i18n'\n\nconst i18n = createI18n({\n  locales: ['en', 'id', 'ja'],\n  defaultLocale: 'en',\n  dictionaries: {\n    en: { greeting: 'Hello, {name}!', errors: { notFound: 'Not found' } },\n    id: { greeting: 'Halo, {name}!', errors: { notFound: 'Tidak ditemukan' } },\n    ja: { greeting: 'こんにちは、{name}さん!' },   // falls back to English for keys it doesn't have\n  },\n})\n\ncreateApp({\n  framework: express(),\n  middleware: [i18n.middleware],\n})\n\napp.route({\n  method: 'GET',\n  path: '/greet',\n  auth: false,\n  handler: async (ctx) => ({ message: i18n.t('greeting', { name: ctx.user?.id ?? 'Guest' }) }),\n})\n```\n\n### Locale detection\n\n`I18nOptions` reference:\n\n| Field | Type | Notes |\n|---|---|---|\n| `locales` | `string[]` | **required** — every locale the app actually supports; anything else falls back to `defaultLocale` |\n| `defaultLocale` | `string` | **required** — used when detection finds nothing, or finds a locale not in `locales` |\n| `dictionaries` | `Record<string, TranslationDictionary>` | **required** — one nested key→string tree per locale, see below |\n| `detect` | `('query' \\| 'cookie' \\| 'header')[]` | optional, default `['query', 'cookie', 'header']` — first source that resolves to a supported locale wins |\n| `queryParam` | `string` | optional, default `'lang'` — e.g. `?lang=id` |\n| `cookieName` | `string` | optional, default `'locale'` |\n| `headerName` | `string` | optional, default `'accept-language'` — parsed per the real HTTP spec, including `q=` quality values (`Accept-Language: fr-FR,id;q=0.9,en;q=0.8` picks `id` over `en` if `fr` isn't supported) and region-qualified tags falling back to their base language (`id-ID` matches a configured `id`) |\n\nThe middleware also stamps the resolved locale onto the `content-language` response header, and makes it available anywhere in that request's call stack — including deep inside services or model hooks, the same way `currentUser()` works — via `currentLocale()`:\n\n```ts\nimport { currentLocale } from '@api-kickstart/api-kickstart/i18n'\n\n// deep inside a service, no ctx threaded through\nconst locale = currentLocale()   // 'id', or null outside a request\n```\n\n`i18n.locale()` is the same thing scoped to one `I18n` instance, falling back to `defaultLocale` instead of `null` when called outside a request.\n\n### Translation\n\n```ts\ninterface TranslationDictionary {\n  [key: string]: string | TranslationDictionary\n}\n```\n\nDictionaries nest — `i18n.t('errors.notFound')` looks up `dictionaries[locale].errors.notFound`. Values support `{param}` interpolation:\n\n```ts\ni18n.t('greeting', { name: 'Alice' })            // uses the current request's detected locale\ni18n.t('greeting', { name: 'Alice' }, 'id')       // explicit locale, ignores the request\n```\n\nResolution order for `t(key, params?, locale?)`: the explicit `locale` argument, else `currentLocale()` (the request's detected locale), else `defaultLocale`. If the key is missing in that locale's dictionary, it falls back to `defaultLocale`'s dictionary — so you don't have to translate every string into every locale on day one (see `ja` only having `greeting` in the example above). If the key is missing everywhere, `t()` returns the key itself rather than throwing or returning something empty — the same \"fail visibly, not silently\" instinct as the rest of this package, since a raw key showing up in a response is an obvious, greppable bug.\n\n`i18n.addDictionary(locale, dictionary)` registers a locale after the fact (e.g. loading translations from a database or a CMS at startup instead of hardcoding them).\n\n### Standalone translator\n\nIf you don't need request-based locale detection at all — a broker consumer, a CLI script, a scheduled task — `createTranslator()` gives you just the dictionary/interpolation/fallback logic without the middleware or `Context` dependency:\n\n```ts\nimport { createTranslator } from '@api-kickstart/api-kickstart/i18n'\n\nconst translator = createTranslator({ locales: ['en', 'id'], defaultLocale: 'en', dictionaries })\ntranslator.t('greeting', { name: 'Alice' }, 'id')   // locale must be passed explicitly — no request to detect it from\n```\n\n`createI18n()` is built on top of `createTranslator()` internally, so both share the exact same lookup/interpolation/fallback behavior.\n\n### Where dictionaries come from\n\nPassing a `dictionaries` object (as in every example above) hardcodes your translations into the deploy — fine for a handful of locales, less fine once translators or an admin need to update copy without a release. `TranslationStore` is the pluggable alternative: a **db** table (any SQL dialect via `knex`, or `pg` directly, or `mongodb`), **redis**, or an explicit in-memory **constant** — all behind the same interface:\n\n```ts\ninterface TranslationStore {\n  loadAll(): Promise<Record<string, TranslationDictionary>>\n  set(locale: string, key: string, value: string): Promise<void>\n}\n```\n\n`createTranslatorFromStore(store, options)` / `createI18nFromStore(store, options)` are async versions of `createTranslator`/`createI18n` — same `options` minus `dictionaries`, which gets loaded from the store instead:\n\n```ts\nimport { createI18nFromStore } from '@api-kickstart/api-kickstart/i18n'\nimport { pgTranslationStore } from '@api-kickstart/api-kickstart/pg'\n\nconst store = pgTranslationStore(pgPool)\nawait store.set('en', 'greeting', 'Hello, {name}!')   // e.g. from an admin panel\nawait store.set('id', 'greeting', 'Halo, {name}!')\n\nconst i18n = await createI18nFromStore(store, { locales: ['en', 'id'], defaultLocale: 'en' })\n```\n\n| Factory | Backend | Signature | Storage |\n|---|---|---|---|\n| `pgTranslationStore(pool, options?)` | Postgres | `(pool: Pool, options: PgTranslationStoreOptions = {}) => TranslationStore` | lazily creates a `_api_kickstart_translations(locale, key, value)` table, `PRIMARY KEY (locale, key)` |\n| `knexTranslationStore(client, options?)` | any SQL dialect knex supports | `(client: Knex, options: KnexTranslationStoreOptions = {}) => TranslationStore` | same shape, portable across `mysql`, `sqlite`, `mssql`, and more |\n| `mongodbTranslationStore(db, options?)` | MongoDB | `(db: Db, options: MongodbTranslationStoreOptions = {}) => TranslationStore` | one document per `{ locale, key, value }`, upserted by `set()` |\n| `redisTranslationStore(options)` | Redis | `(options: RedisTranslationStoreOptions) => TranslationStore` | one hash per locale (`<prefix>i18n:<locale>`), dot-path key as the hash field; **requires `locales: string[]`** in `options` — Redis has no cheap \"list every locale\" scan |\n| `memoryTranslationStore(initial?)` | none (in-process) | `(initial: Record<string, TranslationDictionary> = {}) => TranslationStore` | the explicit \"constant\" backend — same effect as passing `dictionaries` directly, but through the `TranslationStore` interface so it's swappable with the others |\n\n`PgTranslationStoreOptions`/`KnexTranslationStoreOptions`: `{ tableName?: string /* default '_api_kickstart_translations' */; ensureTable?: boolean /* default true */ }`. `MongodbTranslationStoreOptions`: `{ collectionName?: string /* default '_api_kickstart_translations' */ }`. Every key is a dot-path (`errors.notFound`), reassembled into a nested `TranslationDictionary` on `loadAll()` via the exported `buildDictionary()`/`setTranslationPath()` helpers, which adapter authors can reuse for a custom store.\n\nLoading happens once, at startup (or whenever you choose to call `loadAll()`/re-run `createI18nFromStore` again) — not per-request, so `i18n.t()` stays synchronous and there's no per-request database round trip.\n\n---\n\n## File uploads\n\n`multipart/form-data` requests are parsed automatically, on every framework adapter — no extra dependency, no per-route setup:\n\n```ts\napp.route({\n  method: 'POST',\n  path: '/avatar',\n  auth: true,\n  handler: async (ctx) => {\n    ctx.body           // the non-file fields, as strings\n    ctx.files.avatar    // UploadedFile[] for a field named \"avatar\"\n\n    const [file] = ctx.files.avatar\n    file.filename       // \"photo.png\"\n    file.contentType    // \"image/png\"\n    file.data            // Buffer\n    file.size\n\n    await ctx.storage?.put(file.filename, file.data, { contentType: file.contentType })\n    return { uploaded: file.filename }\n  },\n})\n```\n\n`UploadedFile` is `{ fieldName: string; filename: string; contentType: string; data: Buffer; size: number }`.\n\nThe non-file fields land in `ctx.body` exactly like a JSON request, so a `body` validator schema still applies to them. Files are buffered fully in memory before the handler runs — fine for avatars and documents; put `bodyLimit()` in front of the route if you need to cap upload size, and stream large files (video, bulk data) through a signed upload URL instead rather than through this path.\n\n---\n\n## Routing\n\n### Single route\n\n```ts\napp.route({\n  method: 'POST',\n  path: '/orders',\n  auth: true,\n  roles: ['staff'],\n  scope: 'order',\n  body: CreateOrderSchema,\n  handler: async (ctx) => { /* ... */ },\n\n  // optional per-route settings\n  rateLimit: { window: '1m', max: 10 },\n  timeout: '10s',\n  idempotent: true,        // dedupe by Idempotency-Key header\n  tags: ['orders'],        // used in OpenAPI output\n  summary: 'Create an order',\n})\n```\n\n### Route config reference\n\nEvery field `app.route({...})` accepts:\n\n| Field | Type | Notes |\n|---|---|---|\n| `method` | `'GET' \\| 'POST' \\| 'PUT' \\| 'PATCH' \\| 'DELETE'` | required |\n| `path` | `string` | required, Express-style (`/orders/:id`) |\n| `auth` | `boolean \\| string \\| string[]` | `true` requires any configured strategy to succeed, `false` skips auth entirely, a","readmeFilename":"README.md"}