From 4c8b092ed4dbd74ab5ab6e8d3a1a1f1701c8f587 Mon Sep 17 00:00:00 2001 From: Braden Simpson <727605+bradens@users.noreply.github.com> Date: Thu, 1 May 2025 10:09:04 -0700 Subject: [PATCH 1/3] fix: package exports incorrect --- examples/next/bun.lock | 36 +++ examples/next/next.config.ts | 7 +- examples/next/package.json | 4 +- .../src/app/api/auth/[...nextauth]/route.ts | 25 +++ examples/next/src/app/globals.css | 21 ++ examples/next/src/app/layout.tsx | 5 +- .../[networkId]/tokens/[tokenId]/page.tsx | 61 ++--- examples/next/src/app/providers.tsx | 18 ++ .../components/AnonymousSessionProvider.ts | 14 ++ examples/next/src/components/GlitchText.tsx | 2 +- .../next/src/components/TokenTransactions.tsx | 209 ++++++++++++++++++ examples/next/src/hooks/useCodexSdk.ts | 46 ++++ examples/next/src/lib/auth.ts | 136 ++++++++++++ examples/next/src/lib/sdk.ts | 3 + examples/simple/index.ts | 3 +- package.json | 1 - 16 files changed, 544 insertions(+), 47 deletions(-) create mode 100644 examples/next/src/app/api/auth/[...nextauth]/route.ts create mode 100644 examples/next/src/app/providers.tsx create mode 100644 examples/next/src/components/AnonymousSessionProvider.ts create mode 100644 examples/next/src/components/TokenTransactions.tsx create mode 100644 examples/next/src/hooks/useCodexSdk.ts create mode 100644 examples/next/src/lib/auth.ts create mode 100644 examples/next/src/lib/sdk.ts diff --git a/examples/next/bun.lock b/examples/next/bun.lock index 8df4b9f..c2f2d21 100644 --- a/examples/next/bun.lock +++ b/examples/next/bun.lock @@ -14,10 +14,12 @@ "graphql-tag": "^2.12.6", "lucide-react": "^0.503.0", "next": "15.3.1", + "next-auth": "^4.24.11", "react": "^19.0.0", "react-dom": "^19.0.0", "recharts": "^2.15.3", "tailwind-merge": "^3.2.0", + "zen-observable-ts": "^1.1.0", }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -218,6 +220,8 @@ "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], + "@panva/hkdf": ["@panva/hkdf@1.2.1", "", {}, "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], @@ -344,6 +348,8 @@ "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], + "@types/zen-observable": ["@types/zen-observable@0.8.3", "", {}, "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.31.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.31.1", "@typescript-eslint/type-utils": "8.31.1", "@typescript-eslint/utils": "8.31.1", "@typescript-eslint/visitor-keys": "8.31.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ=="], "@typescript-eslint/parser": ["@typescript-eslint/parser@8.31.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.31.1", "@typescript-eslint/types": "8.31.1", "@typescript-eslint/typescript-estree": "8.31.1", "@typescript-eslint/visitor-keys": "8.31.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q=="], @@ -478,6 +484,8 @@ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="], "cross-inspect": ["cross-inspect@1.0.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A=="], @@ -766,6 +774,8 @@ "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], + "jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], @@ -818,6 +828,8 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "lucide-react": ["lucide-react@0.503.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-HGGkdlPWQ0vTF8jJ5TdIqhQXZi6uh3LnNgfZ8MHiuxFfX3RZeA79r2MW2tHAZKlAVfoNE8esm3p+O6VkIvpj6w=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], @@ -842,10 +854,16 @@ "next": ["next@15.3.1", "", { "dependencies": { "@next/env": "15.3.1", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.1", "@next/swc-darwin-x64": "15.3.1", "@next/swc-linux-arm64-gnu": "15.3.1", "@next/swc-linux-arm64-musl": "15.3.1", "@next/swc-linux-x64-gnu": "15.3.1", "@next/swc-linux-x64-musl": "15.3.1", "@next/swc-win32-arm64-msvc": "15.3.1", "@next/swc-win32-x64-msvc": "15.3.1", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-8+dDV0xNLOgHlyBxP1GwHGVaNXsmp+2NhZEYrXr24GWLHtt27YrBPbPuHvzlhi7kZNYjeJNR93IF5zfFu5UL0g=="], + "next-auth": ["next-auth@4.24.11", "", { "dependencies": { "@babel/runtime": "^7.20.13", "@panva/hkdf": "^1.0.2", "cookie": "^0.7.0", "jose": "^4.15.5", "oauth": "^0.9.15", "openid-client": "^5.4.0", "preact": "^10.6.3", "preact-render-to-string": "^5.1.19", "uuid": "^8.3.2" }, "peerDependencies": { "@auth/core": "0.34.2", "next": "^12.2.5 || ^13 || ^14 || ^15", "nodemailer": "^6.6.5", "react": "^17.0.2 || ^18 || ^19", "react-dom": "^17.0.2 || ^18 || ^19" }, "optionalPeers": ["@auth/core", "nodemailer"] }, "sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw=="], + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "oauth": ["oauth@0.9.15", "", {}, "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + "object-hash": ["object-hash@2.2.0", "", {}, "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw=="], + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], @@ -860,6 +878,10 @@ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], + "oidc-token-hash": ["oidc-token-hash@5.1.0", "", {}, "sha512-y0W+X7Ppo7oZX6eovsRkuzcSM40Bicg2JEJkDJ4irIt1wsYAP5MLSNv+QAogO8xivMffw/9OvV3um1pxXgt1uA=="], + + "openid-client": ["openid-client@5.7.1", "", { "dependencies": { "jose": "^4.15.9", "lru-cache": "^6.0.0", "object-hash": "^2.2.0", "oidc-token-hash": "^5.0.3" } }, "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew=="], + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], @@ -884,6 +906,10 @@ "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], + "preact": ["preact@10.26.5", "", {}, "sha512-fmpDkgfGU6JYux9teDWLhj9mKN55tyepwYbxHgQuIxbWQzgFg5vk7Mrrtfx7xRxq798ynkY4DDDxZr235Kk+4w=="], + + "preact-render-to-string": ["preact-render-to-string@5.2.6", "", { "dependencies": { "pretty-format": "^3.8.0" }, "peerDependencies": { "preact": ">=10" } }, "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw=="], + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], "pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], @@ -1040,6 +1066,8 @@ "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="], "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -1060,8 +1088,14 @@ "ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="], + "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "zen-observable": ["zen-observable@0.8.15", "", {}, "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="], + + "zen-observable-ts": ["zen-observable-ts@1.1.0", "", { "dependencies": { "@types/zen-observable": "0.8.3", "zen-observable": "0.8.15" } }, "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA=="], + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], @@ -1102,6 +1136,8 @@ "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=="], + "preact-render-to-string/pretty-format": ["pretty-format@3.8.0", "", {}, "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="], + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], diff --git a/examples/next/next.config.ts b/examples/next/next.config.ts index b007dcd..eac6e2a 100644 --- a/examples/next/next.config.ts +++ b/examples/next/next.config.ts @@ -3,7 +3,12 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ images: { - domains: ['token-media.defined.fi', 'assets.coingecko.com'], + remotePatterns: [ + { + protocol: 'https', + hostname: 'token-media.defined.fi', + }, + ], }, }; diff --git a/examples/next/package.json b/examples/next/package.json index bfc9d03..d1dafd6 100644 --- a/examples/next/package.json +++ b/examples/next/package.json @@ -19,10 +19,12 @@ "graphql-tag": "^2.12.6", "lucide-react": "^0.503.0", "next": "15.3.1", + "next-auth": "^4.24.11", "react": "^19.0.0", "react-dom": "^19.0.0", "recharts": "^2.15.3", - "tailwind-merge": "^3.2.0" + "tailwind-merge": "^3.2.0", + "zen-observable-ts": "^1.1.0" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/examples/next/src/app/api/auth/[...nextauth]/route.ts b/examples/next/src/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..8c894f3 --- /dev/null +++ b/examples/next/src/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,25 @@ +import NextAuth from "next-auth" +import { authOptions } from "../../../../lib/auth" // Use correct relative path to rule out alias issues + +// Add a log to check if this file is executed +console.log("--- EXECUTING [...nextauth]/route.ts ---"); + +// Log the imported authOptions to verify structure +console.log("--- [...nextauth]/route.ts --- Imported authOptions:", JSON.stringify(authOptions, null, 2)); + +let handler; +let initializationError: Error | null = null; + +try { + handler = NextAuth(authOptions); + console.log("--- [...nextauth]/route.ts --- NextAuth handler initialized successfully."); +} catch (error) { + initializationError = error as Error; + console.error("--- [...nextauth]/route.ts --- ERROR initializing NextAuth handler:", error); + // Optionally re-throw or handle differently if needed + // For now, we'll let requests fail if initialization fails +} + +// Export the handler (or potentially an error handler if init failed) +// Note: If handler is undefined due to error, requests will likely fail +export { handler as GET, handler as POST } \ No newline at end of file diff --git a/examples/next/src/app/globals.css b/examples/next/src/app/globals.css index 7cbfb24..e59d85e 100644 --- a/examples/next/src/app/globals.css +++ b/examples/next/src/app/globals.css @@ -1,6 +1,10 @@ @import "tailwindcss"; @import "tw-animate-css"; +@tailwind base; +@tailwind components; +@tailwind utilities; + @custom-variant dark (&:is(.dark *)); @theme inline { @@ -107,3 +111,20 @@ /* --font-sans: var(--font-geist-sans); */ } } +/* Add this */ +@layer utilities { + @keyframes row-pulse { + 0% { + /* Use a subtle background color from your theme, e.g., primary-foreground or blue-100 */ + /* Adjust opacity as needed */ + background-color: var(--color-gray-900); + } + 100% { + background-color: transparent; /* Slightly more intense color */ + } + } + + .animate-row-pulse { + animation: row-pulse 2s cubic-bezier(0.16, 1, 0.3, 1); /* Match duration with JS timeout */ + } +} \ No newline at end of file diff --git a/examples/next/src/app/layout.tsx b/examples/next/src/app/layout.tsx index f114acc..696c644 100644 --- a/examples/next/src/app/layout.tsx +++ b/examples/next/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { Geist_Mono } from "next/font/google"; import "./globals.css"; +import { Providers } from "./providers"; const geistMono = Geist_Mono({ variable: "--font-geist-mono", @@ -20,7 +21,9 @@ export default function RootLayout({ return ( - {children} + + {children} + ); diff --git a/examples/next/src/app/networks/[networkId]/tokens/[tokenId]/page.tsx b/examples/next/src/app/networks/[networkId]/tokens/[tokenId]/page.tsx index c26399b..52e36ad 100644 --- a/examples/next/src/app/networks/[networkId]/tokens/[tokenId]/page.tsx +++ b/examples/next/src/app/networks/[networkId]/tokens/[tokenId]/page.tsx @@ -3,8 +3,8 @@ import Link from "next/link"; import React, { Suspense } from "react"; import { TokenChart, ChartDataPoint } from "@/components/TokenChart"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import Image from "next/image"; +import { TokenTransactions } from "@/components/TokenTransactions"; // --- Type Definitions --- // Add nested info object for icon URL @@ -129,10 +129,14 @@ async function getTokenPageData(networkIdNum: number, tokenId: string): Promise< // --- Page Component --- export default async function TokenPage({ params }: TokenPageProps) { - const { networkId, tokenId } = await params; - const networkIdNum = parseInt(networkId, 10); + // Extract raw params + const { networkId: rawNetworkId, tokenId: rawTokenId } = await params; - if (isNaN(networkIdNum) || !tokenId) { + // Parse networkId + const networkIdNum = parseInt(rawNetworkId, 10); + + // Validate networkId and rawTokenId presence + if (isNaN(networkIdNum) || !rawTokenId) { return (

Invalid Network or Token ID

@@ -141,8 +145,13 @@ export default async function TokenPage({ params }: TokenPageProps) { ); } + // Decode the token ID + const tokenId = decodeURIComponent(rawTokenId); + + // Fetch data using the decoded token ID const { details, bars, events } = await getTokenPageData(networkIdNum, tokenId); + // Use the decoded tokenId for display if name is missing const tokenName = details?.name || tokenId; const tokenSymbol = details?.symbol ? `(${details.symbol})` : ''; @@ -153,7 +162,7 @@ export default async function TokenPage({ params }: TokenPageProps) {

{tokenName} {tokenSymbol}

- + < Back to Network @@ -168,40 +177,12 @@ export default async function TokenPage({ params }: TokenPageProps) { - {/* Transactions Table - Takes 2 columns */} - - - Recent Transactions - - - {events.length > 0 ? ( - - - - Type - Time - Value (USD) - Tx Hash - - - - {events.map((event) => ( - - {event.eventDisplayType || 'N/A'} - {new Date(event.timestamp * 1000).toLocaleString()} - {event.amountUsd ? `$${event.amountUsd.toFixed(2)}` : 'N/A'} - - {event.transactionHash.substring(0, 8)}... - - - ))} - -
- ) : ( -

No recent transaction data available.

- )} -
-
+ {/* Transactions Table - Replace with Client Component */} + {/* Right Area (Info Panel) - Takes 1 column */} @@ -231,7 +212,7 @@ export default async function TokenPage({ params }: TokenPageProps) { <>

Address: - {details.address} + {tokenId}

{details.description && (

diff --git a/examples/next/src/app/providers.tsx b/examples/next/src/app/providers.tsx new file mode 100644 index 0000000..cc454f3 --- /dev/null +++ b/examples/next/src/app/providers.tsx @@ -0,0 +1,18 @@ +'use client'; + +import { SessionProvider } from 'next-auth/react'; +import React from 'react'; +import { AnonymousSessionProvider } from '../components/AnonymousSessionProvider'; + +interface ProvidersProps { + children: React.ReactNode; +} + +export function Providers({ children }: ProvidersProps) { + // You can add other client-side providers here if needed (e.g., ThemeProvider, QueryClientProvider) + return + + + {children} + ; +} \ No newline at end of file diff --git a/examples/next/src/components/AnonymousSessionProvider.ts b/examples/next/src/components/AnonymousSessionProvider.ts new file mode 100644 index 0000000..8561dda --- /dev/null +++ b/examples/next/src/components/AnonymousSessionProvider.ts @@ -0,0 +1,14 @@ +import { signIn, useSession } from "next-auth/react"; +import { useEffect } from "react"; + +export function AnonymousSessionProvider() { + const { status } = useSession(); + + useEffect(() => { + if (status === "unauthenticated") { + signIn("credentials", { redirect: false }); + } + }, [status]); + + return null; +} \ No newline at end of file diff --git a/examples/next/src/components/GlitchText.tsx b/examples/next/src/components/GlitchText.tsx index 22b02da..5db2872 100644 --- a/examples/next/src/components/GlitchText.tsx +++ b/examples/next/src/components/GlitchText.tsx @@ -72,7 +72,7 @@ export const GlitchText: React.FC = ({ }, [text, charSet, intervalMs, iterationsPerChar]); // Conditionally apply opacity class - const animationClass = isAnimating ? 'opacity-75' : ''; + const animationClass = isAnimating ? 'opacity-50' : ''; return {displayText}; }; \ No newline at end of file diff --git a/examples/next/src/components/TokenTransactions.tsx b/examples/next/src/components/TokenTransactions.tsx new file mode 100644 index 0000000..e702b49 --- /dev/null +++ b/examples/next/src/components/TokenTransactions.tsx @@ -0,0 +1,209 @@ +'use client'; + +import React, { useState, useEffect, useRef } from 'react'; +import { useCodexSdk } from '@/hooks/useCodexSdk'; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { GetTokenEventsQuery, OnTokenEventsCreatedSubscription } from '@codex-data/sdk/dist/sdk/generated/graphql'; +import { ExecutionResult } from 'graphql'; +import { CleanupFunction } from '@codex-data/sdk'; + +// Extract the type for a single event from the query type, handling potential nulls +type RawEventData = NonNullable['items']>[number]; + +// Define the structure for our formatted event data +type TokenEvent = { + id: string; + timestamp: number; + transactionHash: string; + eventDisplayType?: string | null; + amountUsd?: number | null; + uniqueId?: string; // For React key +}; + +interface TokenTransactionsProps { + networkId: number; + tokenId: string; // This is the token address + initialEvents: TokenEvent[]; +} + +const MAX_EVENTS = 500; // Define the maximum number of events to keep + +// Updated helper function to process a single RawEventData object +function formatRawEvent(rawEvent: RawEventData): TokenEvent | null { + if (!rawEvent) return null; + + // TODO: Adjust calculation if needed based on subscription payload + // We might need to fetch token decimals separately or pass them as a prop if required for amountUsd calculation + const decimals = 18; // Placeholder: ideally get this dynamically or pass as prop + const swapValue = parseFloat(rawEvent.token0SwapValueUsd || '0'); + const amount0 = parseFloat(rawEvent.data?.amount0 || '0'); + const calculatedAmountUsd = swapValue * Math.abs(amount0 / (10 ** decimals)); + + return { + id: rawEvent.id, + timestamp: rawEvent.timestamp, + uniqueId: `${rawEvent.id}-${rawEvent.transactionHash}-${rawEvent.blockNumber}-${rawEvent.transactionIndex}-${rawEvent.logIndex}`, + transactionHash: rawEvent.transactionHash, + eventDisplayType: rawEvent.eventDisplayType, + amountUsd: calculatedAmountUsd, + }; +} + +export function TokenTransactions({ networkId, tokenId, initialEvents }: TokenTransactionsProps) { + // Limit initial events + const limitedInitialEvents = initialEvents.slice(0, MAX_EVENTS); + const [events, setEvents] = useState(limitedInitialEvents); + const [newestTimestamp, setNewestTimestamp] = useState(null); // State to track the latest event ID + const { sdk, isLoading, isAuthenticated } = useCodexSdk(); + const newestEventTimeoutRef = useRef(null); // Ref to manage the timeout + const cleanupPromiseRef = useRef | null>(null); // Ref to store the promise + + // Effect to clear the newest event ID after a delay + useEffect(() => { + if (newestTimestamp) { + if (newestEventTimeoutRef.current) { + clearTimeout(newestEventTimeoutRef.current); + } + newestEventTimeoutRef.current = setTimeout(() => { + setNewestTimestamp(null); + newestEventTimeoutRef.current = null; + }, 2000); + } + + // Cleanup timeout on component unmount or if newestTimestamp changes before timeout finishes + return () => { + if (newestEventTimeoutRef.current) { + clearTimeout(newestEventTimeoutRef.current); + } + }; + }, [newestTimestamp]); + + // Effect for subscription + useEffect(() => { + if (!sdk || !isAuthenticated || !networkId || !tokenId) { + return; + } + + + // Define the observer object + const observer = { + next: (result: ExecutionResult) => { + if (result.errors) { + console.error("GraphQL errors:", result.errors); + } + const payload = result.data; + const receivedEvents = payload?.onTokenEventsCreated?.events; + if (Array.isArray(receivedEvents) && receivedEvents.length > 0) { + const rawEvent = receivedEvents[0]; + if (rawEvent) { + const formattedEvent = formatRawEvent(rawEvent as RawEventData); + if (formattedEvent && formattedEvent.uniqueId) { + setNewestTimestamp(formattedEvent.timestamp); + setEvents((prevEvents) => { + const exists = prevEvents.some(ev => ev.uniqueId === formattedEvent.uniqueId); + if (exists) { + return prevEvents; + } else { + const updatedEvents = [formattedEvent, ...prevEvents]; + if (updatedEvents.length > MAX_EVENTS) { + updatedEvents.splice(MAX_EVENTS); + } + return updatedEvents; + } + }); + } + } + } else if (!result.errors) { + console.log("Received subscription payload without data or events."); + } + }, + error: (error: Error) => { + console.error('Subscription transport error:', error); + }, + complete: () => { + console.log('Subscription completed by server.'); + }, + }; + + try { + // Use the correct 2-argument call signature + cleanupPromiseRef.current = sdk.subscriptions.onTokenEventsCreated( + { // Argument 1: Input + input: { networkId: networkId, tokenAddress: tokenId } + }, + observer // Argument 2: Observer object + ); + + // Handle potential errors during promise resolution (optional) + cleanupPromiseRef.current.catch(error => { + console.error("Error obtaining cleanup function promise:", error); + }); + + } catch (error) { + console.error("Failed to initiate subscription call:", error); + } + + // Cleanup: Use the promise stored in the ref + return () => { + const promise = cleanupPromiseRef.current; + if (promise) { + promise.then((cleanup) => { + if (typeof cleanup === 'function') { + cleanup(); + console.log(`Subscription cleanup executed for ${tokenId}`); + } + }).catch(error => { + console.error("Error during subscription cleanup promise execution:", error); + }); + cleanupPromiseRef.current = null; // Clear the ref + } + }; + + }, [sdk, isAuthenticated, networkId, tokenId]); + + return ( + + + Recent Transactions (Live) + + + {isLoading &&

Initializing live updates...

} + {!isLoading && !isAuthenticated &&

Session needed for live updates.

} + {!isLoading && isAuthenticated && events.length === 0 &&

Waiting for live transaction data...

} + {events.length > 0 ? ( + + + + Type + Time + Value (USD) + Tx Hash + + + + {events.map((event) => { + const isNewest = event.timestamp === newestTimestamp; + return ( + + {event.eventDisplayType || 'N/A'} + {new Date(event.timestamp * 1000).toLocaleString()} + {event.amountUsd ? `$${event.amountUsd.toFixed(8)}` : 'N/A'} + + {event.transactionHash?.substring(0, 8) ?? 'N/A'}... + + + ); + })} + +
+ ) : ( + !isLoading && !isAuthenticated && events.length === 0 &&

No initial transaction data found.

+ )} + + + ); +} \ No newline at end of file diff --git a/examples/next/src/hooks/useCodexSdk.ts b/examples/next/src/hooks/useCodexSdk.ts new file mode 100644 index 0000000..3a5a3f4 --- /dev/null +++ b/examples/next/src/hooks/useCodexSdk.ts @@ -0,0 +1,46 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { useSession } from 'next-auth/react'; +import { Codex } from '@codex-data/sdk'; // Adjust this import path if necessary + +// Store the previous token value outside the component rendering lifecycle +// This helps avoid unnecessary SDK re-initializations if the session object reference changes but the token value remains the same. +let previousTokenValue: string | undefined = undefined; + +export function useCodexSdk() { + const { data: session, status } = useSession(); + const [sdkInstance, setSdkInstance] = useState(null); + + const tokenValue = session?.shortLivedToken?.value; + const tokenExpiresAt = session?.shortLivedToken?.expiresAt; + + useEffect(() => { + if (status === 'authenticated' && tokenValue) { + // Only create a new instance if the token value has actually changed since the last successful creation. + if (tokenValue !== previousTokenValue) { + console.log('Token value changed. Creating new Codex instance with token:', tokenValue.substring(0, 10) + '...'); // Log prefix for security + setSdkInstance(new Codex(tokenValue)); // Pass token directly + previousTokenValue = tokenValue; // Update the stored previous token + } else if (!sdkInstance) { + // Handle case where component re-mounts but token is the same - re-initialize if needed + console.log('Re-initializing Codex instance with existing token value.'); + setSdkInstance(new Codex(tokenValue)); + } + } else if (status !== 'loading') { + // If not authenticated or no token, ensure SDK instance is cleared + console.log('Session status:', status, 'Clearing SDK instance.'); + setSdkInstance(null); + previousTokenValue = undefined; // Clear previous token when unauthenticated + } + // Depend only on status and tokenValue. If the session object reference changes + // but tokenValue remains the same, this effect won't re-run unnecessarily. + }, [status, tokenValue]); // sdkInstance removed from dependency array + + return { + sdk: sdkInstance, + isLoading: status === 'loading' || (status === 'authenticated' && !sdkInstance), + isAuthenticated: status === 'authenticated' && !!sdkInstance, + tokenExpiresAt: tokenExpiresAt + }; +} \ No newline at end of file diff --git a/examples/next/src/lib/auth.ts b/examples/next/src/lib/auth.ts new file mode 100644 index 0000000..a0d2555 --- /dev/null +++ b/examples/next/src/lib/auth.ts @@ -0,0 +1,136 @@ +import CredentialsProvider from "next-auth/providers/credentials"; +import { type NextAuthOptions, type Session, type DefaultSession, type User } from "next-auth"; +import { JWT } from "next-auth/jwt"; +import { sdk } from "./sdk"; +import { CreateApiTokensMutation } from "@codex-data/sdk/dist/sdk/generated/graphql"; + +// --- Short-Lived Token Config --- +const TOKEN_EXPIRY_MS = 60 * 60 * 1000; // 1 hour +const REFRESH_BUFFER_MS = 5 * 60 * 1000; // 5 minutes + +// --- Short-Lived Token Interface --- +interface ShortLivedToken { + value: string; + expiresAt: number; +} + +// --- Type Augmentations --- +declare module "next-auth/jwt" { + interface JWT { + shortLivedToken?: ShortLivedToken; + id?: string; // Keep existing ID property + // isGuest?: boolean; // Can add if needed + } +} + +declare module "next-auth" { + // Augment User to include id and potentially isGuest + interface User { + id: string; // Ensure id is present + isGuest?: boolean; + } + // Augment Session + interface Session { + shortLivedToken?: ShortLivedToken; + user: { + id?: string | null; // Keep this structure + isGuest?: boolean | null; + } & DefaultSession["user"]; // Use DefaultSession here + } +} + +// --- Refresh Function --- +async function refreshShortLivedToken(token: JWT): Promise { + const now = Date.now(); + console.log("[refreshShortLivedToken] Checking token:", { hasToken: !!token.shortLivedToken, expiresAt: token.shortLivedToken?.expiresAt, now: now, needsRefresh: token.shortLivedToken ? token.shortLivedToken.expiresAt < now + REFRESH_BUFFER_MS : true }); + + if (token.shortLivedToken && token.shortLivedToken.expiresAt > now + REFRESH_BUFFER_MS) { + console.log("[refreshShortLivedToken] Using existing token."); + return token; + } + + console.log("[refreshShortLivedToken] Generating new token..."); + try { + const result: CreateApiTokensMutation = await sdk.mutations.createApiTokens({ + input: { expiresIn: TOKEN_EXPIRY_MS }, + }); + + if (!result.createApiTokens || !Array.isArray(result.createApiTokens) || result.createApiTokens.length === 0 || !result.createApiTokens[0]?.token) { + console.error("[refreshShortLivedToken] Failed to obtain valid token string from mutation:", result); + delete token.shortLivedToken; + return token; + } + + const apiToken = result.createApiTokens[0]; + token.shortLivedToken = { + value: `Bearer ${apiToken.token}`, + expiresAt: now + TOKEN_EXPIRY_MS, + }; + console.log("[refreshShortLivedToken] Successfully refreshed token in JWT object."); + + } catch (error) { + console.error("[refreshShortLivedToken] Error calling mutation:", error); + delete token.shortLivedToken; + } + console.log("[refreshShortLivedToken] Returning token object:", JSON.stringify(token)); + return token; +} + +// Minimal definition +console.log("--- AUTH.TS --- NEXTAUTH_SECRET loaded:", process.env.NEXTAUTH_SECRET ? 'SET' : 'NOT SET'); + +export const authOptions: NextAuthOptions = { + providers: [ + CredentialsProvider({ + name: "Anonymous", + credentials: {}, + async authorize(_, req) { + console.log("--- Authorizing Anonymous User ---"); + return { + id: crypto.randomUUID(), + name: "Guest", + email: null, + isGuest: true, + }; + }, + }), + ], + session: { + strategy: "jwt", + }, + secret: process.env.NEXTAUTH_SECRET, + callbacks: { + async jwt({ token, user }) { + console.log('--- JWT CALLBACK START ---', { token: JSON.stringify(token), user: JSON.stringify(user) }); + if (user) { + token.id = user.id; + // token.isGuest = user.isGuest; + } + const updatedToken = await refreshShortLivedToken(token); + console.log('--- JWT CALLBACK END --- Returning token:', JSON.stringify(updatedToken)); + return updatedToken; + }, + async session({ session, token }) { + console.log('--- SESSION CALLBACK START ---'); + console.log('--- SESSION token received:', JSON.stringify(token)); + + // Transfer short-lived token + session.shortLivedToken = token.shortLivedToken; + + // Transfer user ID (ensure user object exists) + if (token.id && session.user) { + session.user.id = token.id; + } + // Optionally transfer other JWT fields like isGuest + // if (token.isGuest !== undefined && session.user) { + // session.user.isGuest = token.isGuest; + // } + + console.log('--- SESSION CALLBACK END --- Returning session:', JSON.stringify(session)); + return session; + }, + }, +}; + +// Note: We are not exporting the default handler here. +// That will be done in the [...nextauth] route handler. \ No newline at end of file diff --git a/examples/next/src/lib/sdk.ts b/examples/next/src/lib/sdk.ts new file mode 100644 index 0000000..6b4592d --- /dev/null +++ b/examples/next/src/lib/sdk.ts @@ -0,0 +1,3 @@ +import { Codex } from "@codex-data/sdk"; + +export const sdk = new Codex(process.env.CODEX_API_KEY!); \ No newline at end of file diff --git a/examples/simple/index.ts b/examples/simple/index.ts index 891287d..96f2fbb 100644 --- a/examples/simple/index.ts +++ b/examples/simple/index.ts @@ -1,7 +1,6 @@ import { Codex } from "@codex-data/sdk"; -// import { AlertRecurrence } from "../../dist/sdk/generated/graphql"; -import { AlertRecurrence, Network } from "../../src/resources/graphql"; +import { AlertRecurrence, Network } from "../../dist/sdk/generated/graphql"; const sdk = new Codex(process.env.CODEX_API_KEY || ""); diff --git a/package.json b/package.json index 741b8fe..3832c9e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "build": "bun run fetch:schema && bun run src/scripts/generateGraphql.ts && bun run src/scripts/buildSdk.ts && bun run codegen && bun run lint ./src/sdk --fix && bun run eslint --no-ignore ./src/resources/**/*.graphql --fix && bun run tsc", "fetch:schema": "curl -s https://graph.codex.io/schema/latest.graphql --output src/resources/schema.graphql", "codegen": "graphql-codegen --config codegen.ts", - "prepack": "cp -R src/resources/* dist/resources/", "lint": "eslint --ext .ts src", "test": "jest" }, From 033a5a23237be71d352216abcadebd79bd365fc5 Mon Sep 17 00:00:00 2001 From: Braden Simpson <727605+bradens@users.noreply.github.com> Date: Thu, 1 May 2025 10:17:19 -0700 Subject: [PATCH 2/3] cleanup --- .../src/app/api/auth/[...nextauth]/route.ts | 2 -- examples/next/src/hooks/useCodexSdk.ts | 1 + examples/next/src/lib/auth.ts | 25 +++---------------- 3 files changed, 4 insertions(+), 24 deletions(-) diff --git a/examples/next/src/app/api/auth/[...nextauth]/route.ts b/examples/next/src/app/api/auth/[...nextauth]/route.ts index 8c894f3..249166b 100644 --- a/examples/next/src/app/api/auth/[...nextauth]/route.ts +++ b/examples/next/src/app/api/auth/[...nextauth]/route.ts @@ -8,13 +8,11 @@ console.log("--- EXECUTING [...nextauth]/route.ts ---"); console.log("--- [...nextauth]/route.ts --- Imported authOptions:", JSON.stringify(authOptions, null, 2)); let handler; -let initializationError: Error | null = null; try { handler = NextAuth(authOptions); console.log("--- [...nextauth]/route.ts --- NextAuth handler initialized successfully."); } catch (error) { - initializationError = error as Error; console.error("--- [...nextauth]/route.ts --- ERROR initializing NextAuth handler:", error); // Optionally re-throw or handle differently if needed // For now, we'll let requests fail if initialization fails diff --git a/examples/next/src/hooks/useCodexSdk.ts b/examples/next/src/hooks/useCodexSdk.ts index 3a5a3f4..1d6ae0c 100644 --- a/examples/next/src/hooks/useCodexSdk.ts +++ b/examples/next/src/hooks/useCodexSdk.ts @@ -35,6 +35,7 @@ export function useCodexSdk() { } // Depend only on status and tokenValue. If the session object reference changes // but tokenValue remains the same, this effect won't re-run unnecessarily. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [status, tokenValue]); // sdkInstance removed from dependency array return { diff --git a/examples/next/src/lib/auth.ts b/examples/next/src/lib/auth.ts index a0d2555..8f36ffc 100644 --- a/examples/next/src/lib/auth.ts +++ b/examples/next/src/lib/auth.ts @@ -1,5 +1,5 @@ import CredentialsProvider from "next-auth/providers/credentials"; -import { type NextAuthOptions, type Session, type DefaultSession, type User } from "next-auth"; +import { type NextAuthOptions, type DefaultSession } from "next-auth"; import { JWT } from "next-auth/jwt"; import { sdk } from "./sdk"; import { CreateApiTokensMutation } from "@codex-data/sdk/dist/sdk/generated/graphql"; @@ -42,7 +42,6 @@ declare module "next-auth" { // --- Refresh Function --- async function refreshShortLivedToken(token: JWT): Promise { const now = Date.now(); - console.log("[refreshShortLivedToken] Checking token:", { hasToken: !!token.shortLivedToken, expiresAt: token.shortLivedToken?.expiresAt, now: now, needsRefresh: token.shortLivedToken ? token.shortLivedToken.expiresAt < now + REFRESH_BUFFER_MS : true }); if (token.shortLivedToken && token.shortLivedToken.expiresAt > now + REFRESH_BUFFER_MS) { console.log("[refreshShortLivedToken] Using existing token."); @@ -76,16 +75,12 @@ async function refreshShortLivedToken(token: JWT): Promise { return token; } -// Minimal definition -console.log("--- AUTH.TS --- NEXTAUTH_SECRET loaded:", process.env.NEXTAUTH_SECRET ? 'SET' : 'NOT SET'); - export const authOptions: NextAuthOptions = { providers: [ CredentialsProvider({ name: "Anonymous", credentials: {}, - async authorize(_, req) { - console.log("--- Authorizing Anonymous User ---"); + async authorize() { return { id: crypto.randomUUID(), name: "Guest", @@ -101,19 +96,14 @@ export const authOptions: NextAuthOptions = { secret: process.env.NEXTAUTH_SECRET, callbacks: { async jwt({ token, user }) { - console.log('--- JWT CALLBACK START ---', { token: JSON.stringify(token), user: JSON.stringify(user) }); if (user) { token.id = user.id; // token.isGuest = user.isGuest; } const updatedToken = await refreshShortLivedToken(token); - console.log('--- JWT CALLBACK END --- Returning token:', JSON.stringify(updatedToken)); return updatedToken; }, async session({ session, token }) { - console.log('--- SESSION CALLBACK START ---'); - console.log('--- SESSION token received:', JSON.stringify(token)); - // Transfer short-lived token session.shortLivedToken = token.shortLivedToken; @@ -121,16 +111,7 @@ export const authOptions: NextAuthOptions = { if (token.id && session.user) { session.user.id = token.id; } - // Optionally transfer other JWT fields like isGuest - // if (token.isGuest !== undefined && session.user) { - // session.user.isGuest = token.isGuest; - // } - - console.log('--- SESSION CALLBACK END --- Returning session:', JSON.stringify(session)); return session; }, }, -}; - -// Note: We are not exporting the default handler here. -// That will be done in the [...nextauth] route handler. \ No newline at end of file +}; \ No newline at end of file From c42622fd184311f64abc4ea6e555eb4dbb9b5b52 Mon Sep 17 00:00:00 2001 From: Braden Simpson <727605+bradens@users.noreply.github.com> Date: Thu, 1 May 2025 10:19:32 -0700 Subject: [PATCH 3/3] chore: more cleanup --- examples/next/src/app/api/auth/[...nextauth]/route.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/examples/next/src/app/api/auth/[...nextauth]/route.ts b/examples/next/src/app/api/auth/[...nextauth]/route.ts index 249166b..9f6fd27 100644 --- a/examples/next/src/app/api/auth/[...nextauth]/route.ts +++ b/examples/next/src/app/api/auth/[...nextauth]/route.ts @@ -1,23 +1,12 @@ import NextAuth from "next-auth" import { authOptions } from "../../../../lib/auth" // Use correct relative path to rule out alias issues -// Add a log to check if this file is executed -console.log("--- EXECUTING [...nextauth]/route.ts ---"); - -// Log the imported authOptions to verify structure -console.log("--- [...nextauth]/route.ts --- Imported authOptions:", JSON.stringify(authOptions, null, 2)); - let handler; try { handler = NextAuth(authOptions); - console.log("--- [...nextauth]/route.ts --- NextAuth handler initialized successfully."); } catch (error) { console.error("--- [...nextauth]/route.ts --- ERROR initializing NextAuth handler:", error); - // Optionally re-throw or handle differently if needed - // For now, we'll let requests fail if initialization fails } -// Export the handler (or potentially an error handler if init failed) -// Note: If handler is undefined due to error, requests will likely fail export { handler as GET, handler as POST } \ No newline at end of file