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