diff --git a/.cursor/rules/convex_rules.mdc b/.cursor/rules/convex_rules.mdc
index 1d98480..58f1e3a 100644
--- a/.cursor/rules/convex_rules.mdc
+++ b/.cursor/rules/convex_rules.mdc
@@ -180,7 +180,7 @@ Note: `paginationOpts` is an object with the following properties:
## Schema guidelines
- Always define your schema in `convex/schema.ts`.
-- Always import the schema definition functions from `convex/server`:
+- Always import the schema definition functions from `convex/server`.
- System fields are automatically added to all documents and are prefixed with an underscore. The two system fields that are automatically added to all documents are `_creationTime` which has the validator `v.number()` and `_id` which has the validator `v.id(tableName)`.
- Always include all index fields in the index name. For example, if an index is defined as `["field1", "field2"]`, the index name should be "by_field1_and_field2".
- Index fields must be queried in the same order they are defined. If you want to be able to query by "field1" then "field2" and by "field2" then "field1", you must create separate indexes.
@@ -480,8 +480,8 @@ import OpenAI from "openai";
import { internal } from "./_generated/api";
/**
- * Create a user with a given name.
- */
+ * Create a user with a given name.
+ */
export const createUser = mutation({
args: {
name: v.string(),
@@ -493,8 +493,8 @@ export const createUser = mutation({
});
/**
- * Create a channel with a given name.
- */
+ * Create a channel with a given name.
+ */
export const createChannel = mutation({
args: {
name: v.string(),
@@ -506,8 +506,8 @@ export const createChannel = mutation({
});
/**
- * List the 10 most recent messages from a channel in descending creation order.
- */
+ * List the 10 most recent messages from a channel in descending creation order.
+ */
export const listMessages = query({
args: {
channelId: v.id("channels"),
@@ -532,8 +532,8 @@ export const listMessages = query({
});
/**
- * Send a message to a channel and schedule a response from the AI.
- */
+ * Send a message to a channel and schedule a response from the AI.
+ */
export const sendMessage = mutation({
args: {
channelId: v.id("channels"),
@@ -672,5 +672,4 @@ export default defineSchema({
export default function App() {
return
Hello World
;
}
-```
-
+```
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1fdba7a..0c9e507 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 0.1.2
+
+- Fix updateSubscriptionQuantity: we now pass in STRIPE_SECRET_KEY explicitly.
+component context did not have access to process.env
+
## 0.1.1
- Update docs
diff --git a/package-lock.json b/package-lock.json
index 857e1c6..90da3ea 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,11 +9,10 @@
"version": "0.1.1",
"license": "Apache-2.0",
"dependencies": {
- "@clerk/clerk-react": "^5.57.0",
- "@vercel/analytics": "^1.5.0",
"stripe": "^20.0.0"
},
"devDependencies": {
+ "@clerk/clerk-react": "^5.57.0",
"@convex-dev/eslint-plugin": "^1.0.0",
"@edge-runtime/vm": "^5.0.0",
"@eslint/eslintrc": "^3.3.1",
@@ -21,6 +20,7 @@
"@types/node": "^20.19.25",
"@types/react": "^18.3.27",
"@types/react-dom": "^18.3.7",
+ "@vercel/analytics": "^1.5.0",
"@vitejs/plugin-react": "^5.1.1",
"chokidar-cli": "3.0.0",
"convex": "1.29.3",
@@ -372,6 +372,7 @@
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.57.0.tgz",
"integrity": "sha512-GCBFF03HjEWvx58myjauJ7NrwTqhxHdetjWWxVM3YJGPOsAVXg4WuquL/hyn8KDuduCYSkRin4Hg6+QVP1NXAg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@clerk/shared": "^3.36.0",
@@ -389,6 +390,7 @@
"version": "3.36.0",
"resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-3.36.0.tgz",
"integrity": "sha512-Yp4tL/x/iVft40DnxBjT/g/kQilZ+i9mYrqC1Lk6fUnfZV8t7E54GX19JtJSSONzjHsH6sCv3BmJaF1f7Eomkw==",
+ "dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -419,6 +421,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@convex-dev/eslint-plugin": {
@@ -2412,6 +2415,7 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.5.0.tgz",
"integrity": "sha512-MYsBzfPki4gthY5HnYN7jgInhAZ7Ac1cYDoRWFomwGHWEX7odTEzbtg9kf/QSo7XEsEAqlQugA6gJ2WS2DEa3g==",
+ "dev": true,
"license": "MPL-2.0",
"peerDependencies": {
"@remix-run/react": "^2",
@@ -3547,6 +3551,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -4389,6 +4394,7 @@
"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==",
+ "dev": true,
"license": "BSD-2-Clause"
},
"node_modules/globals": {
@@ -5159,6 +5165,7 @@
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
@@ -5168,6 +5175,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
@@ -5351,6 +5359,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
@@ -6333,6 +6342,7 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
@@ -6345,6 +6355,7 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
@@ -6677,6 +6688,7 @@
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
@@ -6946,6 +6958,7 @@
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
"integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
+ "dev": true,
"license": "MIT"
},
"node_modules/stop-iteration-iterator": {
@@ -7194,6 +7207,7 @@
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/swr/-/swr-2.3.4.tgz",
"integrity": "sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"dequal": "^2.0.3",
@@ -7338,6 +7352,7 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
"license": "0BSD"
},
"node_modules/tunnel": {
@@ -7623,6 +7638,7 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "dev": true,
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
diff --git a/package.json b/package.json
index f4216f3..a05d0e1 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"bugs": {
"url": "https://github.com/get-convex/stripe/issues"
},
- "version": "0.1.1",
+ "version": "0.1.2",
"license": "Apache-2.0",
"keywords": [
"convex",
diff --git a/src/client/index.ts b/src/client/index.ts
index 5dedd24..bd0bbaa 100644
--- a/src/client/index.ts
+++ b/src/client/index.ts
@@ -54,10 +54,11 @@ export class StripeSubscriptions {
quantity: number;
},
) {
- // Delegate to the component's public action
+ // Delegate to the component's public action, passing the API key
await ctx.runAction(this.component.public.updateSubscriptionQuantity, {
stripeSubscriptionId: args.stripeSubscriptionId,
quantity: args.quantity,
+ apiKey: this.apiKey,
});
return null;
diff --git a/src/component/_generated/component.ts b/src/component/_generated/component.ts
index 7a6ae0f..135a751 100644
--- a/src/component/_generated/component.ts
+++ b/src/component/_generated/component.ts
@@ -387,7 +387,7 @@ export type ComponentApi =
updateSubscriptionQuantity: FunctionReference<
"action",
"internal",
- { quantity: number; stripeSubscriptionId: string },
+ { apiKey: string; quantity: number; stripeSubscriptionId: string },
null,
Name
>;
diff --git a/src/component/public.ts b/src/component/public.ts
index 2df9331..3e68048 100644
--- a/src/component/public.ts
+++ b/src/component/public.ts
@@ -302,23 +302,17 @@ export const updateSubscriptionMetadata = mutation({
/**
* Update subscription quantity (for seat-based pricing).
* This will update both Stripe and the local database.
- * STRIPE_SECRET_KEY must be set as an environment variable.
+ * STRIPE_SECRET_KEY must be provided as a parameter.
*/
export const updateSubscriptionQuantity = action({
args: {
stripeSubscriptionId: v.string(),
quantity: v.number(),
+ apiKey: v.string(),
},
returns: v.null(),
handler: async (ctx, args) => {
- const apiKey = process.env.STRIPE_SECRET_KEY;
- if (!apiKey) {
- throw new Error(
- "STRIPE_SECRET_KEY must be provided as an environment variable",
- );
- }
-
- const stripe = new StripeSDK(apiKey);
+ const stripe = new StripeSDK(args.apiKey);
// Get the subscription from Stripe to find the subscription item ID
const subscription = await stripe.subscriptions.retrieve(