{"_id":"@ajentify/routed-api","_rev":"4-c79b8772cd6e1b9b4f9ef2ff21a2ba32","name":"@ajentify/routed-api","dist-tags":{"latest":"0.4.1"},"versions":{"0.2.0":{"name":"@ajentify/routed-api","version":"0.2.0","keywords":["aws","cdk","lambda","api-gateway","serverless","construct","routing"],"license":"MIT","_id":"@ajentify/routed-api@0.2.0","maintainers":[{"name":"ajentify","email":"purpledevilai@gmail.com"}],"homepage":"https://github.com/ajentify/routed-api#readme","bugs":{"url":"https://github.com/ajentify/routed-api/issues"},"dist":{"shasum":"ba2d0ded6fff10fd890e7a30614762b8c122ebb8","tarball":"https://registry.npmjs.org/@ajentify/routed-api/-/routed-api-0.2.0.tgz","fileCount":11,"integrity":"sha512-zxYqcwDkpo1M8VGU8sct9q61u5Iwk7EmJrEIfABZJ8hFYSooh7UgwS8orkoXVL/k2/mad10a+xeP0ZCiApfaVw==","signatures":[{"sig":"MEQCIHZ6m4IxIspysdXkQlkR7y82h20sgfYYj/qG5etqFH4dAiAgZyYebtfIw47rOUgomRXuVtjADARHWQBzul8r6jqIrA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":60166},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","typecheck":"tsc -p tsconfig.json --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"ajentify","email":"purpledevilai@gmail.com"},"repository":{"url":"git+https://github.com/ajentify/routed-api.git","type":"git"},"_npmVersion":"10.9.0","description":"Reusable RoutedApi CDK construct: routes.json -> Lambdas + HTTP API + CORS + (optional) Route53 domain. Supports per-lambda and single-lambda deployment modes.","directories":{},"_nodeVersion":"23.3.0","_hasShrinkwrap":false,"devDependencies":{"constructs":"^10.0.0","typescript":"^5.4.0","@types/node":"^20.11.0","aws-cdk-lib":"^2.150.0","@types/aws-lambda":"^8.10.161"},"peerDependencies":{"constructs":"^10.0.0","aws-cdk-lib":"^2.150.0"},"_npmOperationalInternal":{"tmp":"tmp/routed-api_0.2.0_1782540358746_0.08131818514954947","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ajentify/routed-api","version":"0.3.0","keywords":["aws","cdk","lambda","api-gateway","serverless","construct","routing"],"license":"MIT","_id":"@ajentify/routed-api@0.3.0","maintainers":[{"name":"ajentify","email":"purpledevilai@gmail.com"}],"homepage":"https://github.com/ajentify/routed-api#readme","bugs":{"url":"https://github.com/ajentify/routed-api/issues"},"dist":{"shasum":"ec6112e3ee590ebf0fca29d4c0889a224a1ede23","tarball":"https://registry.npmjs.org/@ajentify/routed-api/-/routed-api-0.3.0.tgz","fileCount":11,"integrity":"sha512-c7OVNsdMKBNhH+YyQ3tUMtKgKrCPMua0fJGhLB3b3MrTFMUm21F4aH3ndM8PvLGyla78v6uwfGsPgGe7PAY13g==","signatures":[{"sig":"MEUCIQCTSMT5zqKC1lwrvJtx7QpNLEZLQEwzRxneSsgJGUY6bAIgbYEkSv2K4vCYgvGmajKWpj59LeWb127M9ZoTtVrBlbQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":62362},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","typecheck":"tsc -p tsconfig.json --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"ajentify","email":"purpledevilai@gmail.com"},"repository":{"url":"git+https://github.com/ajentify/routed-api.git","type":"git"},"_npmVersion":"10.9.0","description":"Reusable RoutedApi CDK construct: routes.json -> Lambdas + HTTP API + CORS + (optional) Route53 domain. Supports per-lambda and single-lambda deployment modes.","directories":{},"_nodeVersion":"23.3.0","_hasShrinkwrap":false,"devDependencies":{"constructs":"^10.0.0","typescript":"^5.4.0","@types/node":"^20.11.0","aws-cdk-lib":"^2.150.0","@types/aws-lambda":"^8.10.161"},"peerDependencies":{"constructs":"^10.0.0","aws-cdk-lib":"^2.150.0"},"_npmOperationalInternal":{"tmp":"tmp/routed-api_0.3.0_1782546988590_0.9797294010167603","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ajentify/routed-api","version":"0.4.0","keywords":["aws","cdk","lambda","api-gateway","serverless","construct","routing"],"license":"MIT","_id":"@ajentify/routed-api@0.4.0","maintainers":[{"name":"ajentify","email":"purpledevilai@gmail.com"}],"homepage":"https://github.com/ajentify/routed-api#readme","bugs":{"url":"https://github.com/ajentify/routed-api/issues"},"dist":{"shasum":"e5821ec7fed184f2a4fdd7e980c144fc04ed89c9","tarball":"https://registry.npmjs.org/@ajentify/routed-api/-/routed-api-0.4.0.tgz","fileCount":11,"integrity":"sha512-opDOF2EdfmcnsRuhfBXmAEHnPqEqja64dtxpnAoaV3zqNMK4/1DWDDMRQfPGnQk4hzvqBhLWhDLnh2adrCEGSw==","signatures":[{"sig":"MEUCIAyfCJOAaeDvdT5CQO4SiDEhIvf6COL4xr16QXZQoXkTAiEA9m7VU2h0/s1pMPHqmo3OX4Viioe/p/exUve1+byFTyo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69205},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","typecheck":"tsc -p tsconfig.json --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"ajentify","email":"purpledevilai@gmail.com"},"repository":{"url":"git+https://github.com/ajentify/routed-api.git","type":"git"},"_npmVersion":"10.9.0","description":"Reusable RoutedApi CDK construct: routes.json -> Lambdas + HTTP API + CORS + (optional) Route53 domain. Supports per-lambda and single-lambda deployment modes.","directories":{},"_nodeVersion":"23.3.0","_hasShrinkwrap":false,"devDependencies":{"constructs":"^10.0.0","typescript":"^5.4.0","@types/node":"^20.11.0","aws-cdk-lib":"^2.150.0","@types/aws-lambda":"^8.10.161"},"peerDependencies":{"constructs":"^10.0.0","aws-cdk-lib":"^2.150.0"},"_npmOperationalInternal":{"tmp":"tmp/routed-api_0.4.0_1782560916273_0.7596179887644978","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@ajentify/routed-api","version":"0.4.1","description":"Reusable RoutedApi CDK construct: routes.json -> Lambdas + HTTP API + CORS + (optional) Route53 domain. Supports per-lambda and single-lambda deployment modes.","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","typecheck":"tsc -p tsconfig.json --noEmit","prepublishOnly":"npm run build"},"keywords":["aws","cdk","lambda","api-gateway","serverless","construct","routing"],"peerDependencies":{"aws-cdk-lib":"^2.150.0","constructs":"^10.0.0"},"devDependencies":{"@types/aws-lambda":"^8.10.161","@types/node":"^20.11.0","aws-cdk-lib":"^2.150.0","constructs":"^10.0.0","typescript":"^5.4.0"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/ajentify/routed-api.git"},"_id":"@ajentify/routed-api@0.4.1","bugs":{"url":"https://github.com/ajentify/routed-api/issues"},"homepage":"https://github.com/ajentify/routed-api#readme","_nodeVersion":"23.3.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-N6CiWJfs6AnHa+TsD0Zzbi0O/QP+UBBnmj+zuia3eOWUULLeQeLDnyLxQsJyRk5X7oGpEPzOoooXrBilSgCMOA==","shasum":"96d46edca891545696df7a605763e566246ee8bd","tarball":"https://registry.npmjs.org/@ajentify/routed-api/-/routed-api-0.4.1.tgz","fileCount":9,"unpackedSize":65555,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBA5E7VSFPg8Ex8GTP6vb2N0oyhG4lYpR06Xv1bdUHBeAiBks3EVLO45oL8OQRoVFgJOtH5gG3Iz6RpYzx+/ofd90A=="}]},"_npmUser":{"name":"ajentify","email":"purpledevilai@gmail.com"},"directories":{},"maintainers":[{"name":"ajentify","email":"purpledevilai@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/routed-api_0.4.1_1782561856027_0.6544808624776461"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-27T06:05:58.579Z","modified":"2026-06-27T12:04:16.402Z","0.2.0":"2026-06-27T06:05:58.891Z","0.3.0":"2026-06-27T07:56:28.723Z","0.4.0":"2026-06-27T11:48:36.433Z","0.4.1":"2026-06-27T12:04:16.227Z"},"bugs":{"url":"https://github.com/ajentify/routed-api/issues"},"license":"MIT","homepage":"https://github.com/ajentify/routed-api#readme","keywords":["aws","cdk","lambda","api-gateway","serverless","construct","routing"],"repository":{"type":"git","url":"git+https://github.com/ajentify/routed-api.git"},"description":"Reusable RoutedApi CDK construct: routes.json -> Lambdas + HTTP API + CORS + (optional) Route53 domain. Supports per-lambda and single-lambda deployment modes.","maintainers":[{"name":"ajentify","email":"purpledevilai@gmail.com"}],"readme":"# @ajentify/routed-api\n\nA reusable CDK construct that takes a `routes.json` + a folder of TypeScript\nhandler files and gives you:\n\n- Lambdas per route **or** a single-lambda router (configurable via `deploymentMode`)\n- DynamoDB permissions wired up declaratively\n- An HTTP API (API Gateway v2) with CORS\n- An optional Route53 + ACM custom domain\n- Everything else in your CDK stack stays exactly as you write it\n\nNo build step, no codegen, no separate deploy tool. Drop it into any CDK stack.\n\n## Why HTTP API v2?\n\nHTTP APIs are ~70% cheaper than REST APIs, have native CORS, and are perfectly\nadequate for typical app backends. The construct hides API-Gateway-isms behind a\nsingle `routes.json`.\n\n## Install\n\n```bash\nnpm install @ajentify/routed-api\n```\n\nPeer dependencies (your CDK app must already have these):\n\n```bash\nnpm install aws-cdk-lib constructs\n```\n\n## Minimum usage\n\n```ts\nimport * as cdk from 'aws-cdk-lib';\nimport * as dynamodb from 'aws-cdk-lib/aws-dynamodb';\nimport * as path from 'node:path';\nimport { RoutedApi } from '@ajentify/routed-api';\n\nexport class MyStack extends cdk.Stack {\n  constructor(scope: Construct, id: string, props?: cdk.StackProps) {\n    super(scope, id, props);\n\n    const todosTable = new dynamodb.Table(this, 'TodosTable', {\n      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },\n      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,\n    });\n\n    const api = new RoutedApi(this, 'TodoApi', {\n      routesFile: path.join(__dirname, 'routes.json'),\n      lambdaSrcDir: path.join(__dirname, 'lambda'),\n      tables: { todos: todosTable },\n      cors: { origins: ['http://localhost:3000'] },\n    });\n\n    new cdk.CfnOutput(this, 'ApiUrl', { value: api.url });\n  }\n}\n```\n\n## routes.json\n\n```json\n{\n  \"defaultMemoryMb\": 256,\n  \"defaultTimeoutSeconds\": 15,\n  \"defaultEnvironment\": { \"LOG_LEVEL\": \"info\" },\n  \"defaultTableAccess\": { \"todos\": \"readWrite\" },\n\n  \"routes\": [\n    {\n      \"path\": \"/todos\",\n      \"method\": \"GET\",\n      \"handler\": \"todos/list.ts\",\n      \"tables\": { \"todos\": \"read\" }\n    },\n    {\n      \"path\": \"/todos\",\n      \"method\": \"POST\",\n      \"handler\": \"todos/create.ts\"\n    },\n    {\n      \"path\": \"/todos/{id}\",\n      \"method\": \"DELETE\",\n      \"handler\": \"todos/delete.ts\"\n    }\n  ]\n}\n```\n\n### Route fields\n\n| Field            | Type                                                             | Default                                  |\n| ---------------- | ---------------------------------------------------------------- | ---------------------------------------- |\n| `path`           | string (e.g. `\"/todos\"`, `\"/todos/{id}\"`)                        | required                                 |\n| `method`         | `\"GET\" \\| \"POST\" \\| \"PUT\" \\| \"PATCH\" \\| \"DELETE\" \\| ... \\| \"ANY\"` | required                                 |\n| `handler`        | path to `.ts` file, relative to `lambdaSrcDir`                   | required                                 |\n| `export`         | exported function name in that file                              | `\"handler\"`                              |\n| `memoryMb`       | number                                                           | `defaultMemoryMb`                        |\n| `timeoutSeconds` | number                                                           | `defaultTimeoutSeconds`                  |\n| `environment`    | `Record<string,string>`                                          | `{}`                                     |\n| `tables`         | `string[]` or `Record<string, \"read\"\\|\"write\"\\|\"readWrite\">`     | inherits `defaultTableAccess` from props |\n\n### Default table access\n\nPass one of:\n\n- `\"allReadWrite\"` — every route can read & write every table you pass in **(default)**\n- `\"allRead\"` — every route gets read-only on every table\n- `\"none\"` — no table access unless the route asks\n- `Record<string, \"read\"|\"write\"|\"readWrite\">` — explicit per-table defaults\n\nFor every grant, the lambda also receives `${NAME}_TABLE_NAME` as an env var\n(e.g. `TODOS_TABLE_NAME`).\n\n### Custom IAM policies\n\nUse the `policies` prop to attach additional IAM permissions beyond DynamoDB\ntable access — for example SES, S3, SQS, or any other AWS service:\n\n```ts\nimport * as iam from 'aws-cdk-lib/aws-iam';\n\nnew RoutedApi(this, 'MyApi', {\n  // ...\n  policies: [\n    new iam.PolicyStatement({\n      actions: ['ses:SendEmail', 'ses:SendRawEmail'],\n      resources: ['*'],\n    }),\n    new iam.PolicyStatement({\n      actions: ['s3:GetObject'],\n      resources: ['arn:aws:s3:::my-bucket/*'],\n    }),\n  ],\n});\n```\n\nIn `single-lambda` mode, policies are attached to the single router function.\nIn `lambda-per-route` mode, policies are attached to every function.\n\n### Environment variables from a `.env` file\n\nInstead of passing a large `defaultEnvironment` object inline, point to a\n`.env` file with the `envFile` prop:\n\n```ts\nnew RoutedApi(this, 'MyApi', {\n  envFile: path.join(__dirname, '.env'),\n  // ...\n});\n```\n\nThe file uses standard `KEY=VALUE` syntax with build-time variable substitution:\n\n```env\n# Static values\nCOOKIE_NAME=my_app_refresh\n\n# Substitute from CDK build-time process.env, with fallback defaults\nJWT_SECRET=${JWT_SECRET:-dev-secret-change-in-production}\nAPI_BASE_URL=${API_BASE_URL:-http://localhost:3000}\n\n# No fallback — empty string if unset\nGOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-}\n```\n\nVariables from the env file are merged with (and overridden by)\n`defaultEnvironment` and per-route `environment` settings.\n\n### CORS\n\n```ts\ncors: {\n  origins: ['http://localhost:3000', 'https://app.example.com'],\n  // methods, headers, allowCredentials, maxAgeSeconds are all optional\n}\n// or pass false to disable preflight entirely\n```\n\nSensible defaults are applied — `Content-Type`, `Authorization`, `X-Api-Key`,\n`X-Amz-Date`, `X-Amz-Security-Token`, `X-Requested-With`.\n\n### Custom domain (Route53 + ACM)\n\n```ts\ndomain: {\n  recordName: 'api.example.com',\n  hostedZoneName: 'example.com',\n  certificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/abcd',\n  // hostedZoneId optional — if omitted the zone is looked up by name\n}\n```\n\n> ACM cert must be in the **same region** as the API (HTTP API uses regional\n> endpoints, not edge-optimized). If you need an edge cert, you'd typically\n> front the API with CloudFront instead.\n\n## Handlers\n\nEach handler is a normal `APIGatewayProxyHandlerV2`. The construct uses CDK's\n`NodejsFunction`, so esbuild compiles your TypeScript automatically — no build\nstep needed.\n\n```ts\n// lambda/todos/list.ts\nimport { APIGatewayProxyHandlerV2 } from 'aws-lambda';\nimport { DynamoDBClient } from '@aws-sdk/client-dynamodb';\nimport { DynamoDBDocumentClient, ScanCommand } from '@aws-sdk/lib-dynamodb';\n\nconst ddb = DynamoDBDocumentClient.from(new DynamoDBClient({}));\n\nexport const handler: APIGatewayProxyHandlerV2 = async () => {\n  const out = await ddb.send(new ScanCommand({ TableName: process.env.TODOS_TABLE_NAME! }));\n  return {\n    statusCode: 200,\n    headers: { 'content-type': 'application/json' },\n    body: JSON.stringify({ items: out.Items ?? [] }),\n  };\n};\n```\n\nYour CDK app should have `@aws-sdk/*` packages and `aws-lambda` types installed:\n\n```bash\nnpm install --save-dev @types/aws-lambda\nnpm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb\n```\n\n(`@aws-sdk/*` is `external` in the bundle — Lambda's Node 20 runtime already\nincludes it.)\n\n## What about non-API stuff?\n\nJust keep writing CDK normally. `RoutedApi` is one block in your stack — add\nSES identities, processing lambdas, EventBridge rules, S3 buckets, whatever,\nbefore or after it.\n\n```ts\nnew RoutedApi(this, 'Api', { ... });\n\nnew lambda.Function(this, 'BackgroundProcessor', { ... });  // totally fine\nnew ses.EmailIdentity(this, 'EmailIdentity', { ... });      // also fine\n```\n\n## Worked example\n\nSee `example/` in this folder:\n\n- `example/routes.json` — the routes file\n- `example/lambda/todos/{list,create,delete}.ts` — handler files\n- `example/example-stack.ts` — the CDK stack\n","readmeFilename":"README.md"}