From c249e6e65ff99aa6fe3aa60cfebd4ef1c2d8cfc7 Mon Sep 17 00:00:00 2001 From: JosephBFlannery Date: Wed, 10 Dec 2025 12:59:51 -0500 Subject: [PATCH 1/3] chore: use updated scoped server pattern --- generation-based-subscription/README.md | 38 ++------------ generation-based-subscription/bun.lock | 49 ++++--------------- generation-based-subscription/package.json | 6 +-- .../src/app/api/flowglad/[...path]/route.ts | 23 ++++++--- .../src/app/api/usage-events/route.ts | 15 +++++- .../src/lib/flowglad.ts | 25 +++++++--- 6 files changed, 66 insertions(+), 90 deletions(-) diff --git a/generation-based-subscription/README.md b/generation-based-subscription/README.md index 97e0c38..6843318 100644 --- a/generation-based-subscription/README.md +++ b/generation-based-subscription/README.md @@ -26,7 +26,6 @@ This project demonstrates the "Generation-Based Subscription Template Pricing Mo - Node.js >= 18.18.0 - Bun >= 1.3.1 - PostgreSQL database -- `yalc` (for linking local Flowglad packages) - Install globally with `npm install -g yalc` or `bun install -g yalc` ## Getting Started @@ -44,39 +43,14 @@ This will enable all the subscription plans, usage meters, and features defined ### 2. Install Dependencies -**Important:** This project is part of a monorepo. You must install dependencies from the root of the monorepo first, then navigate into this example directory. - -From the root of the monorepo: +Navigate into this project directory and install dependencies: ```bash +cd generation-based-subscription bun install ``` -Then navigate into this example directory: - -```bash -cd examples/generation-based-subscription -``` - -### 3. Link Flowglad Packages - -This example project uses `yalc` to link local Flowglad packages for development. You must link the packages before running the project: - -```bash -bun run link:packages -``` - -This command will: -- Add Flowglad packages to yalc's local registry -- Link them into this project's `node_modules` -- Update dependencies - -**Note:** If you need to unlink packages later (e.g., to use published npm packages), run: -```bash -bun run unlink:packages -``` - -### 4. Set Up Environment Variables +### 3. Set Up Environment Variables Copy the example environment file: @@ -95,7 +69,7 @@ Fill in the required values in `.env.local`: - **`FLOWGLAD_SECRET_KEY`** - Secret key for Flowglad API calls - Get your secret key from: [https://flowglad.com](https://flowglad.com) -### 5. Set Up Database +### 4. Set Up Database Generate and run database migrations: @@ -104,7 +78,7 @@ bun db:generate bun db:migrate ``` -### 6. Start Development Server +### 5. Start Development Server ```bash bun dev @@ -123,8 +97,6 @@ Open [http://localhost:3000](http://localhost:3000) to see the application. - `bun db:generate` - Generate database migrations - `bun db:migrate` - Run database migrations - `bun db:studio` - Open Drizzle Studio (database GUI) -- `bun link:packages` - Link local Flowglad packages using yalc (required before first run) -- `bun unlink:packages` - Unlink Flowglad packages and restore to npm registry versions ## Project Structure diff --git a/generation-based-subscription/bun.lock b/generation-based-subscription/bun.lock index ed6e157..7892d19 100644 --- a/generation-based-subscription/bun.lock +++ b/generation-based-subscription/bun.lock @@ -1,10 +1,11 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "nextjs-starter", "dependencies": { - "@flowglad/nextjs": "0.12.3", + "@flowglad/nextjs": "0.15.0", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-progress": "^1.1.8", "@radix-ui/react-slot": "^1.2.3", @@ -142,17 +143,15 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], - "@flowglad/nextjs": ["@flowglad/nextjs@0.12.3", "", { "dependencies": { "@flowglad/node": "0.22.0", "@flowglad/react": "0.12.3", "@flowglad/server": "0.12.3", "@flowglad/shared": "0.12.3", "@vercel/mcp-adapter": "0.11.1", "zod": "4.1.5" }, "peerDependencies": { "next": "^14.0.3 || ^15.0.0", "react": "^19.0.0 || ^18.0.0" } }, "sha512-r/9hDSPCcsipFJKlMku7g6vtEwIWCMgGRdLcgCLmW01cGn1dJnaS9knOc3SguZSoNq7dK/H5K/UAvz3lPenO8g=="], + "@flowglad/nextjs": ["@flowglad/nextjs@0.15.0", "", { "dependencies": { "@flowglad/node": "0.24.0", "@flowglad/react": "0.15.0", "@flowglad/server": "0.15.0", "@flowglad/shared": "0.15.0", "@vercel/mcp-adapter": "0.11.1", "zod": "4.1.5" }, "peerDependencies": { "next": "^14.0.3 || ^15.0.0 || ^16.0.0", "react": "^19.0.0 || ^18.0.0" } }, "sha512-5CDd1SkH+dwt16QzvLgZVH5ydbO0uu4AXMkZ5hOBGfONmsvGZ6r0bS3dtQQJtHPBkMGZVqwm529JsFHbTD6hdQ=="], - "@flowglad/node": ["@flowglad/node@0.22.0", "", {}, "sha512-ljB7t2HKuTBoxR0ofB6UmJyCunYIVrV27rktWON2IFsnuA88FWYF2xpXSsHtTSKIKAFSEjhmUbOaOxLtU7R8uw=="], + "@flowglad/node": ["@flowglad/node@0.24.0", "", {}, "sha512-P5UhUaYNAGuCT9hLTQC34o+az4hsfMSuSGpYzg9bPQIrRnTkWvJfmyOmE+cGSlaGZCdLNnEwxCwDQr+lVeOyRw=="], - "@flowglad/react": ["@flowglad/react@0.12.3", "", { "dependencies": { "@flowglad/node": "0.22.0", "@flowglad/shared": "0.12.3", "@tanstack/react-query": "5.66.0", "axios": "1.12.0", "clsx": "2.1.1", "date-fns": "4.1.0", "tailwind-merge": "3.0.2", "zod": "4.1.5" }, "peerDependencies": { "react": "^19.0.0 || ^18.0.0" } }, "sha512-33/L9nwfohpm0Ow0XcDg9udE606pxdzqalO11CHpTVHB9YLD8Sa/a64mmIBwuw01Vhb5TqJW8E8vu0Lg28yOxQ=="], + "@flowglad/react": ["@flowglad/react@0.15.0", "", { "dependencies": { "@flowglad/node": "0.24.0", "@flowglad/shared": "0.15.0", "@tanstack/react-query": "5.66.0", "clsx": "2.1.1", "date-fns": "4.1.0", "tailwind-merge": "3.0.2", "zod": "4.1.5" }, "peerDependencies": { "react": "^19.0.0 || ^18.0.0" } }, "sha512-/CkqMI0dpyezn4enQ1F2m0XzoyHZFXRQ0pB3EAcSMj1683/aRgnDaqbqiaT3mt4ieEf3/D8Cxnm4xOs+xfPf0g=="], - "@flowglad/server": ["@flowglad/server@0.12.3", "", { "dependencies": { "@flowglad/node": "0.22.0", "@flowglad/shared": "0.12.3", "@flowglad/types": "0.12.3", "zod": "4.1.5" } }, "sha512-h6S6wRyMzWCSJl9o6Q+jcVhLymNgQ5afOma4QIRpZz5h3+/zrhOu8w2ztrvDwrVKNyx+pLc0lGWHUbLfQAd3fA=="], + "@flowglad/server": ["@flowglad/server@0.15.0", "", { "dependencies": { "@flowglad/node": "0.24.0", "@flowglad/shared": "0.15.0", "zod": "4.1.5" } }, "sha512-XyFRnnx0wl8qOsv+c5kj3+pDxVSGAsoC1YivHTCrGPWGXPCHGhGNsH0XgXxV5BjxjjRuYjb57OkV553WUn/eWQ=="], - "@flowglad/shared": ["@flowglad/shared@0.12.3", "", { "dependencies": { "@flowglad/node": "0.22.0", "@flowglad/types": "0.12.3", "date-fns": "4.1.0", "zod": "4.1.5" } }, "sha512-EpaCPrzkLlR9GR20u5M2mSZkj2BZvV2r6xZ/kAMxPK8QpuTfjYMeaatyq564E5dDw7DaLQA4j56+UR5dIg6GIg=="], - - "@flowglad/types": ["@flowglad/types@0.12.3", "", { "dependencies": { "@flowglad/node": "0.22.0" } }, "sha512-cVAQyEBST238+HKeFpfeFSpvfY8ejYr2WB8jBFWfKm51u3H8/Hxavw8aG84hFf8PKbZO4VSd17qRx7Dh4qaO1g=="], + "@flowglad/shared": ["@flowglad/shared@0.15.0", "", { "dependencies": { "@flowglad/node": "0.24.0", "date-fns": "4.1.0", "zod": "4.1.5" } }, "sha512-6Go6C4JSdloYUcfc98FvVosElhgFegz1tRGW0CFuaf6LPAr442hW/f71HUKouRKrTUD1YMhjoZvPJD+QA7neag=="], "@hexagon/base64": ["@hexagon/base64@1.1.28", "", {}, "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw=="], @@ -522,14 +521,10 @@ "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], - "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], - "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], "axe-core": ["axe-core@4.11.0", "", {}, "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ=="], - "axios": ["axios@1.12.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg=="], - "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -572,8 +567,6 @@ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], - "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], @@ -612,8 +605,6 @@ "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], - "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], - "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], @@ -746,12 +737,8 @@ "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], - "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], - "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], - "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], @@ -950,9 +937,9 @@ "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], @@ -1056,8 +1043,6 @@ "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], - "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], @@ -1318,8 +1303,6 @@ "@vercel/mcp-adapter/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - "accepts/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], - "ajv-formats/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], "body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], @@ -1334,8 +1317,6 @@ "eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], - "express/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], @@ -1346,14 +1327,10 @@ "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], - "send/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], - "sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], - "type-is/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], - "zod-to-json-schema/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@emnapi/core/@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -1382,16 +1359,8 @@ "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "accepts/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - "express/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - - "send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - - "type-is/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], diff --git a/generation-based-subscription/package.json b/generation-based-subscription/package.json index f6e2484..c54c5bf 100644 --- a/generation-based-subscription/package.json +++ b/generation-based-subscription/package.json @@ -17,12 +17,10 @@ "type-check": "tsc --noEmit", "db:generate": "drizzle-kit generate --config=drizzle.config.ts", "db:migrate": "drizzle-kit migrate --config=drizzle.config.ts", - "db:studio": "drizzle-kit studio --config=drizzle.config.ts", - "link:packages": "yalc add @flowglad/nextjs @flowglad/react @flowglad/server @flowglad/shared @flowglad/types && yalc update && bun install --force && yalc update", - "unlink:packages": "yalc remove --all && bun install" + "db:studio": "drizzle-kit studio --config=drizzle.config.ts" }, "dependencies": { - "@flowglad/nextjs": "0.12.3", + "@flowglad/nextjs": "0.15.0", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-progress": "^1.1.8", "@radix-ui/react-slot": "^1.2.3", diff --git a/generation-based-subscription/src/app/api/flowglad/[...path]/route.ts b/generation-based-subscription/src/app/api/flowglad/[...path]/route.ts index a56ad07..3e6bb13 100644 --- a/generation-based-subscription/src/app/api/flowglad/[...path]/route.ts +++ b/generation-based-subscription/src/app/api/flowglad/[...path]/route.ts @@ -1,7 +1,18 @@ -// /api/flowglad/[...path]/route.ts -import { createAppRouterRouteHandler } from '@flowglad/nextjs/server'; -import { flowgladServer } from '@/lib/flowglad'; +import { nextRouteHandler } from '@flowglad/nextjs/server'; +import { flowglad } from '@/lib/flowglad'; +import { auth } from '@/lib/auth'; +import { headers } from 'next/headers'; -const routeHandler = createAppRouterRouteHandler(flowgladServer); - -export { routeHandler as GET, routeHandler as POST }; +export const { GET, POST } = nextRouteHandler({ + flowglad, + getCustomerExternalId: async (req) => { + const session = await auth.api.getSession({ + headers: await headers(), + }); + const userId = session?.user?.id; + if (!userId) { + throw new Error('User not found'); + } + return userId; + }, +}); diff --git a/generation-based-subscription/src/app/api/usage-events/route.ts b/generation-based-subscription/src/app/api/usage-events/route.ts index b16e0ca..0d5dd14 100644 --- a/generation-based-subscription/src/app/api/usage-events/route.ts +++ b/generation-based-subscription/src/app/api/usage-events/route.ts @@ -1,5 +1,7 @@ -import { flowgladServer } from '@/lib/flowglad'; +import { flowglad } from '@/lib/flowglad'; import { findUsagePriceByMeterSlug } from '@/lib/billing-helpers'; +import { auth } from '@/lib/auth'; +import { headers } from 'next/headers'; import { NextResponse } from 'next/server'; import { z } from 'zod'; @@ -48,7 +50,18 @@ export async function POST(request: Request) { transactionId || `usage_${Date.now()}_${Math.random().toString(36).substring(7)}`; + // Get customer ID from session + const session = await auth.api.getSession({ headers: await headers() }); + const userId = session?.user?.id; + if (!userId) { + return NextResponse.json( + { error: 'User not found' }, + { status: 401 } + ); + } + // Get billing information to extract required IDs + const flowgladServer = flowglad(userId); const billing = await flowgladServer.getBilling(); if (!billing.customer) { diff --git a/generation-based-subscription/src/lib/flowglad.ts b/generation-based-subscription/src/lib/flowglad.ts index 1926774..2f932bc 100644 --- a/generation-based-subscription/src/lib/flowglad.ts +++ b/generation-based-subscription/src/lib/flowglad.ts @@ -2,9 +2,22 @@ import { FlowgladServer } from '@flowglad/nextjs/server'; import { auth } from '@/lib/auth'; import { headers } from 'next/headers'; -// Use betterAuth adapter for FlowgladServer -export const flowgladServer = new FlowgladServer({ - betterAuth: { - getSession: async () => auth.api.getSession({ headers: await headers() }), - }, -}); +export const flowglad = (customerExternalId: string) => { + return new FlowgladServer({ + customerExternalId, + getCustomerDetails: async (customerExternalId: string) => { + const session = await auth.api.getSession({ + headers: await headers(), + }); + + if (!session?.user) { + throw new Error('User not authenticated'); + } + + return { + email: session.user.email || '', + name: session.user.name || '', + }; + }, + }); +}; From 35327b089cc5f0515fbad87772a3b88ece36aed9 Mon Sep 17 00:00:00 2001 From: JosephBFlannery Date: Wed, 10 Dec 2025 18:08:13 -0500 Subject: [PATCH 2/3] fix: use correct pattern for usage event creation --- .../src/app/api/usage-events/route.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/generation-based-subscription/src/app/api/usage-events/route.ts b/generation-based-subscription/src/app/api/usage-events/route.ts index 0d5dd14..b2368f4 100644 --- a/generation-based-subscription/src/app/api/usage-events/route.ts +++ b/generation-based-subscription/src/app/api/usage-events/route.ts @@ -99,13 +99,12 @@ export async function POST(request: Request) { ); } - const priceId = usagePrice.id; - const usageMeterId = usagePrice.usageMeterId; + const priceSlug = usagePrice.slug; - if (!usageMeterId) { + if (!priceSlug) { return NextResponse.json( { - error: `Usage price found but missing usageMeterId for meter: ${usageMeterSlug}`, + error: `Usage price found but missing priceSlug for meter: ${usageMeterSlug}`, }, { status: 500 } ); @@ -113,10 +112,10 @@ export async function POST(request: Request) { // Create usage event with all required IDs // Note: customerId is automatically resolved from the session by FlowgladServer + // usageMeterId is automatically resolved from priceId by Flowglad const usageEvent = await flowgladServer.createUsageEvent({ subscriptionId, - priceId, - usageMeterId, + priceSlug, amount: amountNumber, transactionId: finalTransactionId, }); From 18e14ff790c568277613bef11c70d95c53ed641d Mon Sep 17 00:00:00 2001 From: JosephBFlannery Date: Wed, 10 Dec 2025 18:13:35 -0500 Subject: [PATCH 3/3] fix: comment --- generation-based-subscription/src/app/api/usage-events/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generation-based-subscription/src/app/api/usage-events/route.ts b/generation-based-subscription/src/app/api/usage-events/route.ts index b2368f4..ce2ee2d 100644 --- a/generation-based-subscription/src/app/api/usage-events/route.ts +++ b/generation-based-subscription/src/app/api/usage-events/route.ts @@ -112,7 +112,7 @@ export async function POST(request: Request) { // Create usage event with all required IDs // Note: customerId is automatically resolved from the session by FlowgladServer - // usageMeterId is automatically resolved from priceId by Flowglad + // usageMeterId is automatically resolved from priceSlug by Flowglad const usageEvent = await flowgladServer.createUsageEvent({ subscriptionId, priceSlug,