fix: added fallback for creating org at onboarding if clerk webhook comes late / fails
This commit is contained in:
@@ -1 +1 @@
|
||||
AUTUMN_SECRET_KEY=am_sk_test_RCM3U5M8ptWm6AWhE68hTeVn0sACxX6JE0zpHJi3SV # Example Org
|
||||
AUTUMN_SECRET_KEY=am_sk_test_8bDtE5xZ3pLO4Pl1yQvpKc91fYAvdNTVZ2vOkR5jNe # Example Org
|
||||
569
example/package-lock.json
generated
569
example/package-lock.json
generated
@@ -12,6 +12,7 @@
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"autumn-js": "^0.0.7",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.483.0",
|
||||
@@ -48,6 +49,134 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@better-auth/utils": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.2.4.tgz",
|
||||
"integrity": "sha512-ayiX87Xd5sCHEplAdeMgwkA0FgnXsEZBgDn890XHHwSWNqqRZDYOq3uj2Ei2leTv1I2KbG5HHn60Ah1i2JWZjQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"typescript": "^5.8.2",
|
||||
"uncrypto": "^0.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@better-fetch/fetch": {
|
||||
"version": "1.1.18",
|
||||
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.18.tgz",
|
||||
"integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@clerk/backend": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-1.29.2.tgz",
|
||||
"integrity": "sha512-mBvGyHjNj/t2X2y0Dn1V1EgsffhgNH1TJhB98k40dHxVxvosY9QdgCDMtru/Q1uZ7EXNOzYqzcB5FzAKCxFRZw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@clerk/shared": "^3.7.3",
|
||||
"@clerk/types": "^4.55.0",
|
||||
"cookie": "1.0.2",
|
||||
"snakecase-keys": "8.0.1",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svix": "^1.62.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"svix": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@clerk/clerk-react": {
|
||||
"version": "5.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.29.0.tgz",
|
||||
"integrity": "sha512-S8wenyl5R/8YmUT1tElQZdmHe/MASM9JDJRKqhy0kVYXdKzjhuwTBgT+m3hXl3zdq/Gwi3hgv7pRnQWpQisutQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@clerk/shared": "^3.7.3",
|
||||
"@clerk/types": "^4.55.0",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@clerk/nextjs": {
|
||||
"version": "6.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-6.17.0.tgz",
|
||||
"integrity": "sha512-ik+UU/cKZgC5pafJJ9oct0BUHvytUqof+r1RjFb71xU1TM7EOeL5XYafVxh+hlgwsE4jmrw+FVYe4DXDcyPeTQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@clerk/backend": "^1.29.2",
|
||||
"@clerk/clerk-react": "^5.29.0",
|
||||
"@clerk/shared": "^3.7.3",
|
||||
"@clerk/types": "^4.55.0",
|
||||
"server-only": "0.0.1",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "^13.5.7 || ^14.2.25 || ^15.2.3",
|
||||
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@clerk/shared": {
|
||||
"version": "3.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-3.7.3.tgz",
|
||||
"integrity": "sha512-IMpz1bgZZzlxNLyFliE0GrA3NT1Wgidl2CBORkE2S/YUSCH4ge8EPg5tfQq9Ja6d17TfarkzEafrm1b/BHxSWg==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@clerk/types": "^4.55.0",
|
||||
"dequal": "2.0.3",
|
||||
"glob-to-regexp": "0.4.1",
|
||||
"js-cookie": "3.0.5",
|
||||
"std-env": "^3.8.1",
|
||||
"swr": "^2.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@clerk/types": {
|
||||
"version": "4.55.0",
|
||||
"resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.55.0.tgz",
|
||||
"integrity": "sha512-MJc/zo9vJOq1mY37RbRjrZ883AKe9gitlYFyVB3R+ChKm0uBl2Mm8R2gkYy1GGKYvqBm27GJooWHxdcM1Yv1eQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "3.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz",
|
||||
@@ -257,6 +386,13 @@
|
||||
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@hexagon/base64": {
|
||||
"version": "1.1.28",
|
||||
"resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz",
|
||||
"integrity": "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
@@ -684,6 +820,13 @@
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@levischuck/tiny-cbor": {
|
||||
"version": "0.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz",
|
||||
"integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.7.tgz",
|
||||
@@ -841,6 +984,29 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/ciphers": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.6.0.tgz",
|
||||
"integrity": "sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
||||
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^14.21.3 || >=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -889,6 +1055,69 @@
|
||||
"node": ">=12.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-android": {
|
||||
"version": "2.3.16",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.16.tgz",
|
||||
"integrity": "sha512-a1viIv3bIahXNssrOIkXZIlI2ePpZaNmR30d4aBL99mu2rO+mT9D6zBsp7H6eROWGtmwv0Ionp5olJurIo09dw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.3.15",
|
||||
"asn1js": "^3.0.5",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-ecc": {
|
||||
"version": "2.3.15",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.3.15.tgz",
|
||||
"integrity": "sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.3.15",
|
||||
"@peculiar/asn1-x509": "^2.3.15",
|
||||
"asn1js": "^3.0.5",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-rsa": {
|
||||
"version": "2.3.15",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.3.15.tgz",
|
||||
"integrity": "sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.3.15",
|
||||
"@peculiar/asn1-x509": "^2.3.15",
|
||||
"asn1js": "^3.0.5",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-schema": {
|
||||
"version": "2.3.15",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz",
|
||||
"integrity": "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"asn1js": "^3.0.5",
|
||||
"pvtsutils": "^1.3.6",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-x509": {
|
||||
"version": "2.3.15",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.15.tgz",
|
||||
"integrity": "sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.3.15",
|
||||
"asn1js": "^3.0.5",
|
||||
"pvtsutils": "^1.3.6",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
||||
@@ -1392,6 +1621,32 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@simplewebauthn/browser": {
|
||||
"version": "13.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.1.0.tgz",
|
||||
"integrity": "sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@simplewebauthn/server": {
|
||||
"version": "13.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.1.1.tgz",
|
||||
"integrity": "sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@hexagon/base64": "^1.1.27",
|
||||
"@levischuck/tiny-cbor": "^0.2.2",
|
||||
"@peculiar/asn1-android": "^2.3.10",
|
||||
"@peculiar/asn1-ecc": "^2.3.8",
|
||||
"@peculiar/asn1-rsa": "^2.3.8",
|
||||
"@peculiar/asn1-schema": "^2.3.8",
|
||||
"@peculiar/asn1-x509": "^2.3.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/counter": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||
@@ -2350,6 +2605,21 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/asn1js": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.6.tgz",
|
||||
"integrity": "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"pvtsutils": "^1.3.6",
|
||||
"pvutils": "^1.1.3",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ast-types-flow": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
|
||||
@@ -2367,6 +2637,18 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/autumn-js": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/autumn-js/-/autumn-js-0.0.7.tgz",
|
||||
"integrity": "sha512-sk+i5aMzB1xPi3N/4PD00k1cS9FlR/0xkZ2mqOyksCD23CcaczmRir45o6zzhNFQ2Q1K1icUwRyljwlW3RHWTQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@clerk/nextjs": "^6.16.0",
|
||||
"better-auth": "^1.2.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||
@@ -2410,6 +2692,38 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/better-auth": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.2.7.tgz",
|
||||
"integrity": "sha512-2hCB263GSrgetsMUZw8vv9O1e4S4AlYJW3P4e8bX9u3Q3idv4u9BzDFCblpTLuL4YjYovghMCN0vurAsctXOAQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@better-auth/utils": "0.2.4",
|
||||
"@better-fetch/fetch": "^1.1.18",
|
||||
"@noble/ciphers": "^0.6.0",
|
||||
"@noble/hashes": "^1.6.1",
|
||||
"@simplewebauthn/browser": "^13.0.0",
|
||||
"@simplewebauthn/server": "^13.0.0",
|
||||
"better-call": "^1.0.8",
|
||||
"defu": "^6.1.4",
|
||||
"jose": "^5.9.6",
|
||||
"kysely": "^0.27.6",
|
||||
"nanostores": "^0.11.3",
|
||||
"zod": "^3.24.1"
|
||||
}
|
||||
},
|
||||
"node_modules/better-call": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.0.8.tgz",
|
||||
"integrity": "sha512-/PV8JLqDRUN7JyBPbklVsS/8E4SO3pnf8hbpa8B7xrBrr+BBYpeOAxoqtnsyk/pRs35vNB4MZx8cn9dBuNlLDA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@better-fetch/fetch": "^1.1.4",
|
||||
"rou3": "^0.5.1",
|
||||
"set-cookie-parser": "^2.7.1",
|
||||
"uncrypto": "^0.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@@ -2621,6 +2935,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
|
||||
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -2640,7 +2964,6 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/damerau-levenshtein": {
|
||||
@@ -2765,6 +3088,23 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/defu": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
||||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
@@ -2794,6 +3134,17 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dot-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
|
||||
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"no-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -3717,6 +4068,13 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-to-regexp": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
|
||||
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||
@@ -4357,6 +4715,26 @@
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
|
||||
"integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -4436,6 +4814,16 @@
|
||||
"json-buffer": "3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/kysely": {
|
||||
"version": "0.27.6",
|
||||
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz",
|
||||
"integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/language-subtag-registry": {
|
||||
"version": "0.3.23",
|
||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
|
||||
@@ -4744,6 +5132,16 @@
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lower-case": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-react": {
|
||||
"version": "0.483.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.483.0.tgz",
|
||||
@@ -4753,6 +5151,19 @@
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/map-obj": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
|
||||
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -4835,6 +5246,22 @@
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/nanostores": {
|
||||
"version": "0.11.4",
|
||||
"resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.11.4.tgz",
|
||||
"integrity": "sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -4934,6 +5361,17 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/no-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"lower-case": "^2.0.2",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
@@ -5255,6 +5693,26 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pvtsutils": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz",
|
||||
"integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pvutils": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz",
|
||||
"integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
@@ -5473,6 +5931,13 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rou3": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/rou3/-/rou3-0.5.1.tgz",
|
||||
"integrity": "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/rspack-resolver": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/rspack-resolver/-/rspack-resolver-1.2.2.tgz",
|
||||
@@ -5597,6 +6062,20 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/server-only": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz",
|
||||
"integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/set-cookie-parser": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
|
||||
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
@@ -5795,6 +6274,32 @@
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/snake-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
|
||||
"integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dot-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/snakecase-keys": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-8.0.1.tgz",
|
||||
"integrity": "sha512-Sj51kE1zC7zh6TDlNNz0/Jn1n5HiHdoQErxO8jLtnyrkJW/M5PrI7x05uDgY3BO7OUQYKCvmeMurW6BPUdwEOw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"map-obj": "^4.1.0",
|
||||
"snake-case": "^3.0.4",
|
||||
"type-fest": "^4.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/sonner": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.1.tgz",
|
||||
@@ -5821,6 +6326,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/std-env": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
|
||||
"integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
@@ -6014,6 +6526,20 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/swr": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-2.3.3.tgz",
|
||||
"integrity": "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.0.2.tgz",
|
||||
@@ -6153,6 +6679,19 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.0.tgz",
|
||||
"integrity": "sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/typed-array-buffer": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
|
||||
@@ -6235,7 +6774,6 @@
|
||||
"version": "5.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
|
||||
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -6264,6 +6802,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/uncrypto": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz",
|
||||
"integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
@@ -6324,6 +6869,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
||||
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
@@ -6451,6 +7006,16 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.24.3",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz",
|
||||
"integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"autumn-js": "^0.0.7",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.483.0",
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import { Autumn } from "@/sdk/autumn";
|
||||
|
||||
// ONLY 3 ENDPOINTS NEEDED TO GET STARTED
|
||||
|
||||
// Entitled: Check if your user should be allowed to use a feature
|
||||
export const entitled = async ({
|
||||
customerId,
|
||||
featureId,
|
||||
}: {
|
||||
customerId: string;
|
||||
featureId: string;
|
||||
}) => {
|
||||
const response = await fetch(`https://api.useautumn.com/v1/entitled`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.AUTUMN_SECRET_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
customer_id: customerId,
|
||||
feature_id: featureId,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
return data.allowed;
|
||||
};
|
||||
|
||||
//Events: send a usage event to Autumn to track a user's usage of a feature
|
||||
export const sendEvent = async ({
|
||||
customerId,
|
||||
featureId,
|
||||
}: {
|
||||
customerId: string;
|
||||
featureId: string;
|
||||
}) => {
|
||||
await fetch("https://api.useautumn.com/v1/events", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.AUTUMN_SECRET_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
customer_id: customerId,
|
||||
feature_id: featureId,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
//Attach: get a checkout URL from Autumn so the user can upgrade
|
||||
export const attachProduct = async ({
|
||||
customerId,
|
||||
productId,
|
||||
}: {
|
||||
customerId: string;
|
||||
productId: string;
|
||||
}) => {
|
||||
const response = await fetch(`https://api.useautumn.com/v1/attach`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.AUTUMN_SECRET_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
customer_id: customerId,
|
||||
product_id: productId,
|
||||
force_checkout: true,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (response.status !== 200) {
|
||||
throw new Error(data.message || "Failed to attach pro product");
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
// ADDITIONAL ENDPOINT TO FETCH CUSTOMER DETAILS
|
||||
|
||||
export const getOrCreateCustomer = async (customerId: string) => {
|
||||
const response = await fetch(`https://api.useautumn.com/v1/customers`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.AUTUMN_SECRET_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: customerId,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getCustomer = async (customerId: string) => {
|
||||
const autumn = new Autumn();
|
||||
|
||||
const data = await autumn.customers.get(customerId);
|
||||
const { entitlements, invoices } = data;
|
||||
return data;
|
||||
};
|
||||
27
example/src/app/demo.tsx
Normal file
27
example/src/app/demo.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
// <div className="text-2xl font-bold">{customer?.name}</div>
|
||||
// <button
|
||||
// onClick={async () => {
|
||||
// await attach({
|
||||
// productId: "pro-example",
|
||||
// });
|
||||
// }}
|
||||
// >
|
||||
// Upgrade to pro
|
||||
// </button>
|
||||
|
||||
// import Application from "@/components/application";
|
||||
// import CustomerDetailsExample from "@/components/billing";
|
||||
// import Intro from "@/components/introduction";
|
||||
|
||||
// export default function Home() {
|
||||
// return (
|
||||
// <div className="min-h-screen w-full p-6 flex flex-col gap-8 max-w-7xl mx-auto">
|
||||
// <Intro />
|
||||
|
||||
// <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
// <Application />
|
||||
// <CustomerDetailsExample />
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { AutumnProvider } from "autumn-js/next";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
@@ -25,12 +26,20 @@ export default function RootLayout({
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
<AutumnProvider
|
||||
customerId="123"
|
||||
customerData={{
|
||||
name: "ayush",
|
||||
email: "ayush@example.com",
|
||||
}}
|
||||
>
|
||||
<Toaster position="top-right" />
|
||||
{children}
|
||||
</body>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<Toaster position="top-right" />
|
||||
{children}
|
||||
</body>
|
||||
</AutumnProvider>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,40 +1,21 @@
|
||||
"use client";
|
||||
|
||||
// import { getOrCreateCustomer } from "./autumn-functions";
|
||||
// import { useState } from "react";
|
||||
// import { useEffect } from "react";
|
||||
import Intro from "@/components/introduction";
|
||||
|
||||
// import { Autumn } from "useautumn";
|
||||
// import CustomerDetailsExample from "@/components/billing";
|
||||
// import Application from "@/components/application";
|
||||
|
||||
// Replace this with your internal user ID
|
||||
import { useAutumn } from "autumn-js/next";
|
||||
|
||||
export default function Home() {
|
||||
// const [customerData, setCustomerData] = useState<any>(null);
|
||||
|
||||
// const fetchCustomer = async () => {
|
||||
// const customer = await getOrCreateCustomer(CUSTOMER_ID);
|
||||
// setCustomerData(customer);
|
||||
// };
|
||||
|
||||
// useEffect(() => {
|
||||
// fetchCustomer();
|
||||
// }, []);
|
||||
|
||||
// if (!customerData) {
|
||||
// return <></>;
|
||||
// }
|
||||
|
||||
const { customer, attach } = useAutumn();
|
||||
return (
|
||||
<div className="min-h-screen w-full p-6 flex flex-col gap-8 max-w-7xl mx-auto">
|
||||
<Intro />
|
||||
|
||||
{/* <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<Application customerId={CUSTOMER_ID} fetchCustomer={fetchCustomer} />
|
||||
<CustomerDetailsExample customerData={customerData} />
|
||||
</div> */}
|
||||
<div className="h-screen w-full flex flex-col gap-4 items-center justify-center">
|
||||
<div className="text-2xl font-bold">{customer?.name}</div>
|
||||
<button
|
||||
onClick={async () => {
|
||||
await attach({
|
||||
productId: "pro-example",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Upgrade
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { sendEvent } from "@/app/autumn-functions";
|
||||
import { entitled } from "@/app/autumn-functions";
|
||||
import { useAutumn } from "autumn-js/next";
|
||||
import { MessageSquare } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export default function Application({
|
||||
customerId,
|
||||
fetchCustomer,
|
||||
}: {
|
||||
customerId: string;
|
||||
fetchCustomer: () => void;
|
||||
}) {
|
||||
export default function Application() {
|
||||
const { entitled, sendEvent, refetch } = useAutumn();
|
||||
|
||||
const sendMessageClicked = async (featureId: string) => {
|
||||
const allowed = await entitled({
|
||||
customerId,
|
||||
const { allowed } = await entitled({
|
||||
featureId,
|
||||
});
|
||||
|
||||
@@ -23,10 +16,11 @@ export default function Application({
|
||||
}
|
||||
|
||||
await sendEvent({
|
||||
customerId,
|
||||
featureId,
|
||||
});
|
||||
|
||||
await refetch();
|
||||
|
||||
toast.success(`${featureId} used!`);
|
||||
};
|
||||
|
||||
@@ -61,21 +55,10 @@ export default function Application({
|
||||
<button
|
||||
className="w-full bg-purple-600 hover:bg-purple-700 transition-colors"
|
||||
onClick={async () => {
|
||||
await sendMessageClicked("message-credits");
|
||||
await fetchCustomer();
|
||||
await sendMessageClicked("chat-messages");
|
||||
}}
|
||||
>
|
||||
Use Standard Message
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="w-full bg-purple-600 hover:bg-purple-700 transition-colors"
|
||||
onClick={async () => {
|
||||
await sendMessageClicked("premium-credits");
|
||||
await fetchCustomer();
|
||||
}}
|
||||
>
|
||||
Use Claude Message
|
||||
Use Chat Message
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,49 +1,40 @@
|
||||
"use client";
|
||||
|
||||
import { attachProduct } from "@/app/autumn-functions";
|
||||
import { CreditCard } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { useAutumn } from "autumn-js/next";
|
||||
export default function CustomerDetailsExample() {
|
||||
const { customer, attach, openBillingPortal } = useAutumn();
|
||||
const productId = "pro-example";
|
||||
|
||||
export default function CustomerDetailsExample({
|
||||
customerData,
|
||||
}: {
|
||||
customerData: any;
|
||||
}) {
|
||||
const { customer, entitlements, products } = customerData;
|
||||
|
||||
const getEntitlement = (featureId: string) => {
|
||||
return entitlements.find(
|
||||
return customer?.features.find(
|
||||
(entitlement: any) => entitlement.feature_id === featureId
|
||||
);
|
||||
};
|
||||
|
||||
const upgradeClicked = async () => {
|
||||
try {
|
||||
const res = await attachProduct({
|
||||
customerId: customer.id,
|
||||
productId: "pro",
|
||||
await attach({
|
||||
productId,
|
||||
});
|
||||
window.open(res.checkout_url, "_blank");
|
||||
} catch (error: any) {
|
||||
toast.error(`${error}`);
|
||||
toast.error(`${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
const buyExtraCreditsClicked = async () => {
|
||||
const manageBillingClicked = async () => {
|
||||
try {
|
||||
const res = await attachProduct({
|
||||
customerId: customer.id,
|
||||
productId: "extra-credits",
|
||||
});
|
||||
window.open(res.checkout_url, "_blank");
|
||||
await openBillingPortal();
|
||||
} catch (error: any) {
|
||||
toast.error(`${error}`);
|
||||
toast.error(`${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
const messageCredits = getEntitlement("message-credits");
|
||||
const premiumCredits = getEntitlement("premium-credits");
|
||||
const hasPro = products.length > 0 && products[0].id === "pro";
|
||||
const messageCredits = getEntitlement("chat-messages");
|
||||
|
||||
const hasPro =
|
||||
customer?.products?.length && customer?.products[0].id === productId;
|
||||
|
||||
return (
|
||||
<div className="border rounded-lg bg-white overflow-hidden flex flex-col">
|
||||
@@ -66,21 +57,16 @@ export default function CustomerDetailsExample({
|
||||
<div className="flex items-center justify-between py-2 border-b">
|
||||
<span className="text-sm font-medium">Customer ID</span>
|
||||
<span className="text-sm font-mono bg-stone-50 px-2 py-1 rounded">
|
||||
{customer.id}
|
||||
{customer?.id}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between py-2 border-b">
|
||||
<span className="text-sm font-medium">Standard Messages Remaining</span>
|
||||
<span className="text-sm font-medium">Chat Messages Remaining</span>
|
||||
<span className="text-sm font-mono bg-stone-50 px-2 py-1 rounded">
|
||||
{messageCredits?.balance || 0}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between py-2 border-b">
|
||||
<span className="text-sm font-medium">Premium Messages Remaining</span>
|
||||
<span className="text-sm font-mono bg-stone-50 px-2 py-1 rounded">
|
||||
{premiumCredits?.balance || 0}
|
||||
{messageCredits?.unlimited
|
||||
? "Unlimited"
|
||||
: messageCredits?.balance || 0}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -101,24 +87,16 @@ export default function CustomerDetailsExample({
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 p-6 pt-0">
|
||||
<div className="w-full pt-0">
|
||||
{!hasPro && (
|
||||
<button
|
||||
className="w-full"
|
||||
onClick={upgradeClicked}
|
||||
>
|
||||
Upgrade to Pro
|
||||
<button className="w-full" onClick={upgradeClicked}>
|
||||
<div className="w-full pt-0">Upgrade to Pro</div>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full pt-0">
|
||||
<button
|
||||
className="w-full"
|
||||
onClick={buyExtraCreditsClicked}
|
||||
>
|
||||
Buy Extra Premium Credits
|
||||
<div className="w-full pt-0">
|
||||
<button className="w-full" onClick={manageBillingClicked}>
|
||||
Manage Billing
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,361 +0,0 @@
|
||||
import { CreateRewardProgram, ErrCode } from "@autumn/shared";
|
||||
|
||||
export default class AutumnError extends Error {
|
||||
message: string;
|
||||
code: string;
|
||||
|
||||
constructor({ message, code }: { message: string; code: string }) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.message} (code: ${this.code})`;
|
||||
}
|
||||
}
|
||||
|
||||
export class Autumn {
|
||||
private apiKey: string;
|
||||
public headers: Record<string, string>;
|
||||
public baseUrl: string;
|
||||
|
||||
constructor(apiKey?: string, baseUrl?: string) {
|
||||
this.apiKey = apiKey || process.env.AUTUMN_SECRET_KEY || "";
|
||||
|
||||
this.headers = {
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
this.baseUrl = "https://api.useautumn.com/v1";
|
||||
// this.baseUrl = baseUrl || "http://localhost:8080/v1";
|
||||
}
|
||||
|
||||
async get(path: string) {
|
||||
const response = await fetch(`${this.baseUrl}${path}`, {
|
||||
headers: this.headers,
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async post(path: string, body: any) {
|
||||
const response = await fetch(`${this.baseUrl}${path}`, {
|
||||
method: "POST",
|
||||
headers: this.headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (response.status != 200) {
|
||||
let error: any;
|
||||
try {
|
||||
error = await response.json();
|
||||
} catch (error) {
|
||||
throw new AutumnError({
|
||||
message: "Failed to parse Autumn API error response",
|
||||
code: ErrCode.InternalError,
|
||||
});
|
||||
}
|
||||
|
||||
throw new AutumnError({
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
});
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async delete(
|
||||
path: string,
|
||||
{
|
||||
deleteInStripe = false,
|
||||
}: {
|
||||
deleteInStripe?: boolean;
|
||||
} = {}
|
||||
) {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}${path}?${deleteInStripe ? "delete_in_stripe=true" : ""}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: this.headers,
|
||||
}
|
||||
);
|
||||
|
||||
if (response.status != 200) {
|
||||
let error: any;
|
||||
try {
|
||||
error = await response.json();
|
||||
} catch (error) {
|
||||
throw new AutumnError({
|
||||
message: "Failed to parse Autumn API error response",
|
||||
code: ErrCode.InternalError,
|
||||
});
|
||||
}
|
||||
|
||||
throw new AutumnError({
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
});
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async createCustomer({
|
||||
id,
|
||||
email,
|
||||
name,
|
||||
fingerprint,
|
||||
}: {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
fingerprint?: string;
|
||||
}) {
|
||||
const data = await this.post("/customers", {
|
||||
id,
|
||||
email,
|
||||
name,
|
||||
fingerprint,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async attach({
|
||||
customerId,
|
||||
productId,
|
||||
options,
|
||||
}: {
|
||||
customerId: string;
|
||||
productId: string;
|
||||
options?: any;
|
||||
}) {
|
||||
const data = await this.post(`/attach`, {
|
||||
customer_id: customerId,
|
||||
product_id: productId,
|
||||
options,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async sendEvent({
|
||||
customerId,
|
||||
eventName,
|
||||
properties,
|
||||
customer_data,
|
||||
idempotency_key,
|
||||
}: {
|
||||
customerId: string;
|
||||
eventName: string;
|
||||
properties?: any;
|
||||
customer_data?: any;
|
||||
idempotency_key?: string;
|
||||
}) {
|
||||
const data = await this.post(`/events`, {
|
||||
customer_id: customerId,
|
||||
event_name: eventName,
|
||||
properties,
|
||||
customer_data,
|
||||
idempotency_key,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async entitled({
|
||||
customerId,
|
||||
featureId,
|
||||
quantity,
|
||||
customer_data,
|
||||
}: {
|
||||
customerId: string;
|
||||
featureId: string;
|
||||
quantity?: number;
|
||||
customer_data?: any;
|
||||
}) {
|
||||
const data = await this.post(`/entitled`, {
|
||||
customer_id: customerId,
|
||||
feature_id: featureId,
|
||||
quantity,
|
||||
customer_data,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
customers = {
|
||||
get: async (customerId: string) => {
|
||||
const data = await this.get(`/customers/${customerId}`);
|
||||
return data;
|
||||
},
|
||||
|
||||
create: async (customer: { id: string; email: string; name: string }) => {
|
||||
const data = await this.post(`/customers`, customer);
|
||||
return data;
|
||||
},
|
||||
delete: async (
|
||||
customerId: string,
|
||||
{
|
||||
deleteInStripe = false,
|
||||
}: {
|
||||
deleteInStripe?: boolean;
|
||||
} = {}
|
||||
) => {
|
||||
const data = await this.delete(`/customers/${customerId}`, {
|
||||
deleteInStripe,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
entities = {
|
||||
create: async (
|
||||
customerId: string,
|
||||
entity:
|
||||
| {
|
||||
id: string;
|
||||
name: string;
|
||||
featureId: string;
|
||||
}
|
||||
| {
|
||||
id: string;
|
||||
name: string;
|
||||
featureId: string;
|
||||
}[]
|
||||
) => {
|
||||
let entities = Array.isArray(entity) ? entity : [entity];
|
||||
const data = await this.post(
|
||||
`/customers/${customerId}/entities`,
|
||||
entities.map((e: any) => {
|
||||
return {
|
||||
id: e.id,
|
||||
name: e.name,
|
||||
feature_id: e.featureId,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
list: async (customerId: string) => {
|
||||
const data = await this.get(`/customers/${customerId}/entities`);
|
||||
return data;
|
||||
},
|
||||
|
||||
delete: async (customerId: string, entityId: string) => {
|
||||
const data = await this.delete(
|
||||
`/customers/${customerId}/entities/${entityId}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
products = {
|
||||
update: async (productId: string, product: any) => {
|
||||
if (product.items && typeof product.items === "object") {
|
||||
product.items = Object.values(product.items);
|
||||
}
|
||||
const data = await this.post(`/products/${productId}`, product);
|
||||
return data;
|
||||
},
|
||||
|
||||
get: async (
|
||||
productId: string,
|
||||
{ v1Schema = false }: { v1Schema?: boolean } = {}
|
||||
) => {
|
||||
const data = await this.get(
|
||||
`/products/${productId}?${v1Schema ? "schemaVersion=1" : ""}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
|
||||
create: async (product: any) => {
|
||||
const data = await this.post(`/products`, product);
|
||||
return data;
|
||||
},
|
||||
|
||||
delete: async (productId: string) => {
|
||||
const data = await this.delete(`/products/${productId}`);
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
rewards = {
|
||||
create: async (reward: any) => {
|
||||
const data = await this.post(`/rewards`, reward);
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
rewardPrograms = {
|
||||
create: async (rewardProgram: CreateRewardProgram) => {
|
||||
const data = await this.post(`/reward_programs`, rewardProgram);
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
referrals = {
|
||||
createCode: async ({
|
||||
customerId,
|
||||
referralId,
|
||||
}: {
|
||||
customerId: string;
|
||||
referralId: string;
|
||||
}) => {
|
||||
const data = await this.post(`/referrals/code`, {
|
||||
customer_id: customerId,
|
||||
program_id: referralId,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
redeem: async ({
|
||||
customerId,
|
||||
code,
|
||||
}: {
|
||||
customerId: string;
|
||||
code: string;
|
||||
}) => {
|
||||
const data = await this.post(`/referrals/redeem`, {
|
||||
customer_id: customerId,
|
||||
code,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
redemptions = {
|
||||
get: async ({ redemptionId }: { redemptionId: string }) => {
|
||||
const data = await this.get(`/redemptions/${redemptionId}`);
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
events = {
|
||||
send: async ({
|
||||
customerId,
|
||||
featureId,
|
||||
value,
|
||||
properties,
|
||||
}: {
|
||||
customerId: string;
|
||||
featureId: string;
|
||||
value: number;
|
||||
properties?: any;
|
||||
}) => {
|
||||
const data = await this.post(`/events`, {
|
||||
customer_id: customerId,
|
||||
feature_id: featureId,
|
||||
value,
|
||||
properties,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
initStripe = async () => {
|
||||
await this.post(`/products/all/init_stripe`, {});
|
||||
};
|
||||
}
|
||||
57
server/src/external/webhooks/clerkWebhooks.ts
vendored
57
server/src/external/webhooks/clerkWebhooks.ts
vendored
@@ -258,16 +258,32 @@ export const handleClerkWebhook = async (req: any, res: any) => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleOrgCreated = async (sb: SupabaseClient, eventData: any) => {
|
||||
export const handleOrgCreated = async (
|
||||
sb: SupabaseClient,
|
||||
eventData: {
|
||||
id: string;
|
||||
slug: string;
|
||||
created_at: number;
|
||||
}
|
||||
) => {
|
||||
console.log(
|
||||
`Handling organization.created: ${eventData.slug} (${eventData.id})`
|
||||
);
|
||||
|
||||
try {
|
||||
// 1. Create svix webhoooks
|
||||
const { sandboxApp, liveApp } = await initOrgSvixApps({
|
||||
slug: eventData.slug,
|
||||
id: eventData.id,
|
||||
});
|
||||
// // Check if org already exists
|
||||
// let org = await OrgService.getFullOrg({
|
||||
// sb,
|
||||
// orgId: eventData.id,
|
||||
// errorIfNotFound: false,
|
||||
// });
|
||||
|
||||
// if (org) {
|
||||
// console.log(
|
||||
// `handleOrgCreated: Org already exists: ${eventData.slug} (${eventData.id})`
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 2. Insert org
|
||||
await OrgService.insert({
|
||||
@@ -282,16 +298,39 @@ const handleOrgCreated = async (sb: SupabaseClient, eventData: any) => {
|
||||
live_pkey: generatePublishableKey(AppEnv.Live),
|
||||
created_at: eventData.created_at,
|
||||
svix_config: {
|
||||
sandbox_app_id: sandboxApp.id,
|
||||
live_app_id: liveApp.id,
|
||||
sandbox_app_id: "",
|
||||
live_app_id: "",
|
||||
},
|
||||
config: {} as any,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Inserted org ${eventData.id}`);
|
||||
} catch (error) {
|
||||
|
||||
// 1. Create svix webhoooks
|
||||
const { sandboxApp, liveApp } = await initOrgSvixApps({
|
||||
slug: eventData.slug,
|
||||
id: eventData.id,
|
||||
});
|
||||
|
||||
await OrgService.update({
|
||||
sb,
|
||||
orgId: eventData.id,
|
||||
updates: {
|
||||
svix_config: { sandbox_app_id: sandboxApp.id, live_app_id: liveApp.id },
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Created svix webhooks for org ${eventData.id}`);
|
||||
} catch (error: any) {
|
||||
if (error?.data && error.data.code == "23505") {
|
||||
console.error(
|
||||
`Org ${eventData.id} already exists in Supabase -- skipping creationg`
|
||||
);
|
||||
return;
|
||||
}
|
||||
console.error("Failed to insert org", error);
|
||||
return;
|
||||
}
|
||||
|
||||
const batch = [];
|
||||
|
||||
@@ -53,6 +53,7 @@ apiRouter.use((req: any, res: any, next: any) => {
|
||||
let skipUrls = ["/v1/customers/all/search"];
|
||||
res.on("finish", () => {
|
||||
try {
|
||||
req.logtail.flush();
|
||||
if (skipUrls.includes(req.originalUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,12 @@ import { productRouter } from "./products/internalProductRouter.js";
|
||||
import { devRouter } from "./dev/devRouter.js";
|
||||
import { cusRouter } from "./customers/internalCusRouter.js";
|
||||
import { testRouter } from "./test/testRouter.js";
|
||||
import { createClerkCli } from "../external/clerkUtils.js";
|
||||
import { ErrCode } from "@autumn/shared";
|
||||
import RecaseError, { handleRequestError } from "@/utils/errorUtils.js";
|
||||
import { STATUS_CODES } from "http";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
import { handleOrgCreated } from "@/external/webhooks/clerkWebhooks.js";
|
||||
|
||||
const mainRouter = Router();
|
||||
|
||||
@@ -15,6 +21,51 @@ mainRouter.get("", (req: any, res) => {
|
||||
res.status(200).json({ message: "Hello World" });
|
||||
});
|
||||
|
||||
mainRouter.post("/organization", withAuth, async (req: any, res) => {
|
||||
try {
|
||||
let { orgId } = req.body;
|
||||
|
||||
let userId = req.userId;
|
||||
let clerk = createClerkCli();
|
||||
|
||||
let org = await clerk.organizations.getOrganization({
|
||||
organizationId: orgId,
|
||||
});
|
||||
|
||||
if (!org) {
|
||||
throw new RecaseError({
|
||||
message: "Organization not found",
|
||||
code: ErrCode.OrgNotFound,
|
||||
statusCode: StatusCodes.NOT_FOUND,
|
||||
});
|
||||
}
|
||||
|
||||
const memberships = await clerk.users.getOrganizationMembershipList({
|
||||
userId: userId,
|
||||
});
|
||||
|
||||
let userIsAdmin = memberships.data.some((m) => m.organization.id === orgId);
|
||||
|
||||
if (!userIsAdmin) {
|
||||
throw new RecaseError({
|
||||
message: "User is not an admin of this organization",
|
||||
code: ErrCode.OrgNotFound,
|
||||
statusCode: StatusCodes.NOT_FOUND,
|
||||
});
|
||||
}
|
||||
|
||||
handleOrgCreated(req.sb, {
|
||||
id: orgId,
|
||||
slug: org.slug || "",
|
||||
created_at: Date.now(),
|
||||
});
|
||||
|
||||
res.status(200).json({ message: "Success" });
|
||||
} catch (error: any) {
|
||||
handleRequestError({ error, req, res, action: "create org" });
|
||||
}
|
||||
});
|
||||
|
||||
mainRouter.use("/users", withAuth, userRouter);
|
||||
mainRouter.use("/organization", withOrgAuth, orgRouter);
|
||||
mainRouter.use("/features", withOrgAuth, featureRouter);
|
||||
|
||||
@@ -12,6 +12,7 @@ import { OrgService } from "./OrgService.js";
|
||||
import { createStripeCli } from "@/external/stripe/utils.js";
|
||||
import { AppEnv } from "@autumn/shared";
|
||||
import { nullish } from "@/utils/genUtils.js";
|
||||
import { handleOrgCreated } from "@/external/webhooks/clerkWebhooks.js";
|
||||
|
||||
export const orgRouter = express.Router();
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import Step from "@/components/general/OnboardingStep";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useAxiosInstance } from "@/services/useAxiosInstance";
|
||||
import { useEnv } from "@/utils/envUtils";
|
||||
import { useOrganization, useOrganizationList } from "@clerk/clerk-react";
|
||||
import { Building } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
@@ -15,6 +17,8 @@ export const CreateOrgStep = ({
|
||||
pollForOrg: () => Promise<void>;
|
||||
}) => {
|
||||
const { organization: org } = useOrganization();
|
||||
let env = useEnv();
|
||||
let axios = useAxiosInstance({ env });
|
||||
const { createOrganization, setActive } = useOrganizationList();
|
||||
|
||||
const [isExploding, setIsExploding] = useState(false);
|
||||
@@ -37,6 +41,11 @@ export const CreateOrgStep = ({
|
||||
name: fields.name,
|
||||
});
|
||||
|
||||
// Create org in Autumn
|
||||
await axios.post("/organization", {
|
||||
orgId: org.id,
|
||||
});
|
||||
|
||||
await setActive({ organization: org.id });
|
||||
// await pollForOrg();
|
||||
toast.success(`Created your organization: ${org.name}`);
|
||||
|
||||
Reference in New Issue
Block a user