@surgent-dev/surpay-convex 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/package.json +30 -0
- package/src/index.ts +149 -0
- package/src/types.ts +32 -0
- package/tsconfig.json +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# @surgent-dev/surpay-convex
|
|
2
|
+
|
|
3
|
+
Convex integration for Surpay SDK.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @surgent-dev/surpay-convex
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
Step 1: Create `convex/surpay.ts`
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { Surpay } from "@surgent-dev/surpay-convex";
|
|
17
|
+
|
|
18
|
+
const surpay = new Surpay({
|
|
19
|
+
apiKey: process.env.SURPAY_API_KEY!,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const {
|
|
23
|
+
createCheckout,
|
|
24
|
+
getCustomer,
|
|
25
|
+
listCustomers,
|
|
26
|
+
listSubscriptions,
|
|
27
|
+
} = surpay.api();
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Step 2: Set environment variable
|
|
31
|
+
|
|
32
|
+
Add `SURPAY_API_KEY` to your Convex dashboard environment variables.
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Create Checkout
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { api } from "./_generated/api";
|
|
40
|
+
|
|
41
|
+
// Inside a Convex action or from client
|
|
42
|
+
const { data, error } = await ctx.runAction(api.surpay.createCheckout, {
|
|
43
|
+
product_id: "prod_123",
|
|
44
|
+
price_id: "price_123",
|
|
45
|
+
success_url: "https://example.com/success",
|
|
46
|
+
cancel_url: "https://example.com/cancel",
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (error) {
|
|
50
|
+
console.error(error.message);
|
|
51
|
+
} else {
|
|
52
|
+
console.log(data.checkout_url);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Get Customer
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { api } from "./_generated/api";
|
|
60
|
+
|
|
61
|
+
const { data, error } = await ctx.runAction(api.surpay.getCustomer, {
|
|
62
|
+
project_id: "proj_123",
|
|
63
|
+
customer_id: "cust_123",
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### List Subscriptions
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { api } from "./_generated/api";
|
|
71
|
+
|
|
72
|
+
const { data, error } = await ctx.runAction(api.surpay.listSubscriptions, {
|
|
73
|
+
project_id: "proj_123",
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## API Reference
|
|
78
|
+
|
|
79
|
+
| Action | Args | Returns |
|
|
80
|
+
|--------|------|---------|
|
|
81
|
+
| `createCheckout` | `product_id`, `price_id`, `success_url`, `cancel_url` | `{ checkout_url: string, session_id: string }` |
|
|
82
|
+
| `getCustomer` | `project_id`, `customer_id` | `CustomerWithDetails` |
|
|
83
|
+
| `listCustomers` | `project_id` | `Customer[]` |
|
|
84
|
+
| `listSubscriptions` | `project_id` | `Subscription[]` |
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Surpay as SurpayClient } from "@surgent-dev/surpay";
|
|
2
|
+
export type IdentifierOpts = {
|
|
3
|
+
customerId: string;
|
|
4
|
+
customerData?: {
|
|
5
|
+
name?: string;
|
|
6
|
+
email?: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export type SurpayConfig = {
|
|
10
|
+
apiKey: string;
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
identify: (ctx: any) => Promise<IdentifierOpts | null>;
|
|
13
|
+
};
|
|
14
|
+
type PlainError = {
|
|
15
|
+
message: string;
|
|
16
|
+
code?: string;
|
|
17
|
+
};
|
|
18
|
+
export declare class Surpay {
|
|
19
|
+
private client;
|
|
20
|
+
private options;
|
|
21
|
+
constructor(config: SurpayConfig);
|
|
22
|
+
getIdentifierOpts(ctx: any): Promise<IdentifierOpts | null>;
|
|
23
|
+
getAuthParams({ ctx, requireAuth, }: {
|
|
24
|
+
ctx: any;
|
|
25
|
+
requireAuth?: boolean;
|
|
26
|
+
}): Promise<{
|
|
27
|
+
client: SurpayClient;
|
|
28
|
+
identifierOpts: IdentifierOpts | null;
|
|
29
|
+
}>;
|
|
30
|
+
api(): {
|
|
31
|
+
createCheckout: import("convex/server").RegisteredAction<"public", {
|
|
32
|
+
product_id: string;
|
|
33
|
+
price_id: string;
|
|
34
|
+
success_url: string;
|
|
35
|
+
cancel_url: string;
|
|
36
|
+
}, Promise<{
|
|
37
|
+
data: null;
|
|
38
|
+
error: PlainError;
|
|
39
|
+
} | {
|
|
40
|
+
data: import("@surgent-dev/surpay").CreateCheckoutResponse;
|
|
41
|
+
error: null;
|
|
42
|
+
}>>;
|
|
43
|
+
getCustomer: import("convex/server").RegisteredAction<"public", {
|
|
44
|
+
project_id: string;
|
|
45
|
+
customer_id: string;
|
|
46
|
+
}, Promise<{
|
|
47
|
+
data: null;
|
|
48
|
+
error: PlainError;
|
|
49
|
+
} | {
|
|
50
|
+
data: import("@surgent-dev/surpay").CustomerWithDetails;
|
|
51
|
+
error: null;
|
|
52
|
+
}>>;
|
|
53
|
+
listCustomers: import("convex/server").RegisteredAction<"public", {
|
|
54
|
+
project_id: string;
|
|
55
|
+
}, Promise<{
|
|
56
|
+
data: null;
|
|
57
|
+
error: PlainError;
|
|
58
|
+
} | {
|
|
59
|
+
data: import("@surgent-dev/surpay").Customer[];
|
|
60
|
+
error: null;
|
|
61
|
+
}>>;
|
|
62
|
+
listSubscriptions: import("convex/server").RegisteredAction<"public", {
|
|
63
|
+
project_id: string;
|
|
64
|
+
}, Promise<{
|
|
65
|
+
data: null;
|
|
66
|
+
error: PlainError;
|
|
67
|
+
} | {
|
|
68
|
+
data: import("@surgent-dev/surpay").Subscription[];
|
|
69
|
+
error: null;
|
|
70
|
+
}>>;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export * from "./types.js";
|
|
74
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAQ7D,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACxD,CAAC;AAGF,KAAK,UAAU,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAwBrD,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,OAAO,CAAe;gBAElB,MAAM,EAAE,YAAY;IAQ1B,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAI3D,aAAa,CAAC,EAClB,GAAG,EACH,WAAkB,GACnB,EAAE;QACD,GAAG,EAAE,GAAG,CAAC;QACT,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,cAAc,EAAE,cAAc,GAAG,IAAI,CAAA;KAAE,CAAC;IAQ5E,GAAG;;;;;;;kBA1CyC,IAAI;mBAAS,UAAU;;;mBAAxC,IAAI;;;;;;kBAAa,IAAI;mBAAS,UAAU;;;mBAAxC,IAAI;;;;;kBAAa,IAAI;mBAAS,UAAU;;;mBAAxC,IAAI;;;;;kBAAa,IAAI;mBAAS,UAAU;;;mBAAxC,IAAI;;;CAyFhC;AAED,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surpay Convex Integration
|
|
3
|
+
*
|
|
4
|
+
* Provides Convex actions that wrap the Surpay SDK with auth context support.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* // convex/surpay.ts
|
|
9
|
+
* import { Surpay } from "@surgent-dev/surpay-convex";
|
|
10
|
+
*
|
|
11
|
+
* const surpay = new Surpay({
|
|
12
|
+
* apiKey: process.env.SURPAY_API_KEY!,
|
|
13
|
+
* identify: async (ctx) => {
|
|
14
|
+
* const identity = await ctx.auth.getUserIdentity();
|
|
15
|
+
* if (!identity) return null;
|
|
16
|
+
* return {
|
|
17
|
+
* customerId: identity.subject,
|
|
18
|
+
* customerData: { name: identity.name, email: identity.email },
|
|
19
|
+
* };
|
|
20
|
+
* },
|
|
21
|
+
* });
|
|
22
|
+
* export const { createCheckout, getCustomer, listCustomers, listSubscriptions } = surpay.api();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import { actionGeneric } from "convex/server";
|
|
26
|
+
import { Surpay as SurpayClient } from "@surgent-dev/surpay";
|
|
27
|
+
import { CreateCheckoutArgs, GetCustomerArgs, ListCustomersArgs, ListSubscriptionsArgs, } from "./types.js";
|
|
28
|
+
function toPlainError(error) {
|
|
29
|
+
if (error instanceof Error) {
|
|
30
|
+
return { message: error.message, code: error.code };
|
|
31
|
+
}
|
|
32
|
+
return { message: String(error) };
|
|
33
|
+
}
|
|
34
|
+
// Wrap SDK calls to ensure errors are plain objects
|
|
35
|
+
async function wrapSdkCall(fn) {
|
|
36
|
+
try {
|
|
37
|
+
const result = await fn();
|
|
38
|
+
if (result.error) {
|
|
39
|
+
return { data: null, error: toPlainError(result.error) };
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
return { data: null, error: toPlainError(e) };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class Surpay {
|
|
48
|
+
client;
|
|
49
|
+
options;
|
|
50
|
+
constructor(config) {
|
|
51
|
+
this.options = config;
|
|
52
|
+
this.client = new SurpayClient({
|
|
53
|
+
apiKey: config.apiKey,
|
|
54
|
+
baseUrl: config.baseUrl,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async getIdentifierOpts(ctx) {
|
|
58
|
+
return await this.options.identify(ctx);
|
|
59
|
+
}
|
|
60
|
+
async getAuthParams({ ctx, requireAuth = true, }) {
|
|
61
|
+
const identifierOpts = await this.getIdentifierOpts(ctx);
|
|
62
|
+
if (requireAuth && !identifierOpts) {
|
|
63
|
+
throw new Error("No customer identifier found");
|
|
64
|
+
}
|
|
65
|
+
return { client: this.client, identifierOpts };
|
|
66
|
+
}
|
|
67
|
+
api() {
|
|
68
|
+
return {
|
|
69
|
+
createCheckout: actionGeneric({
|
|
70
|
+
args: CreateCheckoutArgs,
|
|
71
|
+
handler: async (ctx, args) => {
|
|
72
|
+
const { client, identifierOpts } = await this.getAuthParams({ ctx });
|
|
73
|
+
// Merge customer info from auth context with checkout args
|
|
74
|
+
const checkoutParams = {
|
|
75
|
+
...args,
|
|
76
|
+
customer_id: identifierOpts.customerId,
|
|
77
|
+
customer_name: identifierOpts.customerData?.name,
|
|
78
|
+
customer_email: identifierOpts.customerData?.email,
|
|
79
|
+
};
|
|
80
|
+
return wrapSdkCall(() => client.checkout.create(checkoutParams));
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
getCustomer: actionGeneric({
|
|
84
|
+
args: GetCustomerArgs,
|
|
85
|
+
handler: async (ctx, args) => {
|
|
86
|
+
const { client, identifierOpts } = await this.getAuthParams({ ctx });
|
|
87
|
+
const customerId = args.customer_id || identifierOpts.customerId;
|
|
88
|
+
return wrapSdkCall(() => client.customers.get(args.project_id, customerId));
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
listCustomers: actionGeneric({
|
|
92
|
+
args: ListCustomersArgs,
|
|
93
|
+
handler: async (ctx, args) => {
|
|
94
|
+
const { client } = await this.getAuthParams({ ctx });
|
|
95
|
+
return wrapSdkCall(() => client.customers.list(args.project_id));
|
|
96
|
+
},
|
|
97
|
+
}),
|
|
98
|
+
listSubscriptions: actionGeneric({
|
|
99
|
+
args: ListSubscriptionsArgs,
|
|
100
|
+
handler: async (ctx, args) => {
|
|
101
|
+
const { client } = await this.getAuthParams({ ctx });
|
|
102
|
+
return wrapSdkCall(() => client.subscriptions.list(args.project_id));
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export * from "./types.js";
|
|
109
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex validators for Surpay action arguments
|
|
3
|
+
*/
|
|
4
|
+
import { Infer } from "convex/values";
|
|
5
|
+
export declare const CreateCheckoutArgs: import("convex/values").VObject<{
|
|
6
|
+
product_id: string;
|
|
7
|
+
price_id: string;
|
|
8
|
+
success_url: string;
|
|
9
|
+
cancel_url: string;
|
|
10
|
+
}, {
|
|
11
|
+
product_id: import("convex/values").VString<string, "required">;
|
|
12
|
+
price_id: import("convex/values").VString<string, "required">;
|
|
13
|
+
success_url: import("convex/values").VString<string, "required">;
|
|
14
|
+
cancel_url: import("convex/values").VString<string, "required">;
|
|
15
|
+
}, "required", "product_id" | "price_id" | "success_url" | "cancel_url">;
|
|
16
|
+
export type CreateCheckoutArgs = Infer<typeof CreateCheckoutArgs>;
|
|
17
|
+
export declare const ListSubscriptionsArgs: import("convex/values").VObject<{
|
|
18
|
+
project_id: string;
|
|
19
|
+
}, {
|
|
20
|
+
project_id: import("convex/values").VString<string, "required">;
|
|
21
|
+
}, "required", "project_id">;
|
|
22
|
+
export type ListSubscriptionsArgs = Infer<typeof ListSubscriptionsArgs>;
|
|
23
|
+
export declare const GetCustomerArgs: import("convex/values").VObject<{
|
|
24
|
+
project_id: string;
|
|
25
|
+
customer_id: string;
|
|
26
|
+
}, {
|
|
27
|
+
project_id: import("convex/values").VString<string, "required">;
|
|
28
|
+
customer_id: import("convex/values").VString<string, "required">;
|
|
29
|
+
}, "required", "project_id" | "customer_id">;
|
|
30
|
+
export type GetCustomerArgs = Infer<typeof GetCustomerArgs>;
|
|
31
|
+
export declare const ListCustomersArgs: import("convex/values").VObject<{
|
|
32
|
+
project_id: string;
|
|
33
|
+
}, {
|
|
34
|
+
project_id: import("convex/values").VString<string, "required">;
|
|
35
|
+
}, "required", "project_id">;
|
|
36
|
+
export type ListCustomersArgs = Infer<typeof ListCustomersArgs>;
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAGzC,eAAO,MAAM,kBAAkB;;;;;;;;;;wEAK7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAGlE,eAAO,MAAM,qBAAqB;;;;4BAEhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAGxE,eAAO,MAAM,eAAe;;;;;;4CAG1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAG5D,eAAO,MAAM,iBAAiB;;;;4BAE5B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex validators for Surpay action arguments
|
|
3
|
+
*/
|
|
4
|
+
import { v } from "convex/values";
|
|
5
|
+
// CreateCheckoutRequest: product_id, price_id, success_url, cancel_url (all required)
|
|
6
|
+
export const CreateCheckoutArgs = v.object({
|
|
7
|
+
product_id: v.string(),
|
|
8
|
+
price_id: v.string(),
|
|
9
|
+
success_url: v.string(),
|
|
10
|
+
cancel_url: v.string(),
|
|
11
|
+
});
|
|
12
|
+
// ListSubscriptions: requires project_id
|
|
13
|
+
export const ListSubscriptionsArgs = v.object({
|
|
14
|
+
project_id: v.string(),
|
|
15
|
+
});
|
|
16
|
+
// GetCustomer: requires project_id and customer_id
|
|
17
|
+
export const GetCustomerArgs = v.object({
|
|
18
|
+
project_id: v.string(),
|
|
19
|
+
customer_id: v.string(),
|
|
20
|
+
});
|
|
21
|
+
// ListCustomers: requires project_id
|
|
22
|
+
export const ListCustomersArgs = v.object({
|
|
23
|
+
project_id: v.string(),
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,CAAC,EAAS,MAAM,eAAe,CAAC;AAEzC,sFAAsF;AACtF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAGH,yCAAyC;AACzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAGH,mDAAmD;AACnD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC;AAGH,qCAAqC;AACrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@surgent-dev/surpay-convex",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@surgent-dev/surpay": "workspace:*"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"convex": "^1.25.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.9.3",
|
|
25
|
+
"convex": "^1.25.0"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surpay Convex Integration
|
|
3
|
+
*
|
|
4
|
+
* Provides Convex actions that wrap the Surpay SDK with auth context support.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* // convex/surpay.ts
|
|
9
|
+
* import { Surpay } from "@surgent-dev/surpay-convex";
|
|
10
|
+
*
|
|
11
|
+
* const surpay = new Surpay({
|
|
12
|
+
* apiKey: process.env.SURPAY_API_KEY!,
|
|
13
|
+
* identify: async (ctx) => {
|
|
14
|
+
* const identity = await ctx.auth.getUserIdentity();
|
|
15
|
+
* if (!identity) return null;
|
|
16
|
+
* return {
|
|
17
|
+
* customerId: identity.subject,
|
|
18
|
+
* customerData: { name: identity.name, email: identity.email },
|
|
19
|
+
* };
|
|
20
|
+
* },
|
|
21
|
+
* });
|
|
22
|
+
* export const { createCheckout, getCustomer, listCustomers, listSubscriptions } = surpay.api();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import { actionGeneric } from "convex/server";
|
|
26
|
+
import { Surpay as SurpayClient } from "@surgent-dev/surpay";
|
|
27
|
+
import {
|
|
28
|
+
CreateCheckoutArgs,
|
|
29
|
+
GetCustomerArgs,
|
|
30
|
+
ListCustomersArgs,
|
|
31
|
+
ListSubscriptionsArgs,
|
|
32
|
+
} from "./types.js";
|
|
33
|
+
|
|
34
|
+
export type IdentifierOpts = {
|
|
35
|
+
customerId: string;
|
|
36
|
+
customerData?: { name?: string; email?: string };
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type SurpayConfig = {
|
|
40
|
+
apiKey: string;
|
|
41
|
+
baseUrl?: string;
|
|
42
|
+
identify: (ctx: any) => Promise<IdentifierOpts | null>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Convex can't serialize class instances - convert errors to plain objects
|
|
46
|
+
type PlainError = { message: string; code?: string };
|
|
47
|
+
|
|
48
|
+
function toPlainError(error: unknown): PlainError {
|
|
49
|
+
if (error instanceof Error) {
|
|
50
|
+
return { message: error.message, code: (error as { code?: string }).code };
|
|
51
|
+
}
|
|
52
|
+
return { message: String(error) };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Wrap SDK calls to ensure errors are plain objects
|
|
56
|
+
async function wrapSdkCall<T>(
|
|
57
|
+
fn: () => Promise<{ data: T; error: null } | { data: null; error: unknown }>
|
|
58
|
+
): Promise<{ data: T; error: null } | { data: null; error: PlainError }> {
|
|
59
|
+
try {
|
|
60
|
+
const result = await fn();
|
|
61
|
+
if (result.error) {
|
|
62
|
+
return { data: null, error: toPlainError(result.error) };
|
|
63
|
+
}
|
|
64
|
+
return result as { data: T; error: null };
|
|
65
|
+
} catch (e) {
|
|
66
|
+
return { data: null, error: toPlainError(e) };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class Surpay {
|
|
71
|
+
private client: SurpayClient;
|
|
72
|
+
private options: SurpayConfig;
|
|
73
|
+
|
|
74
|
+
constructor(config: SurpayConfig) {
|
|
75
|
+
this.options = config;
|
|
76
|
+
this.client = new SurpayClient({
|
|
77
|
+
apiKey: config.apiKey,
|
|
78
|
+
baseUrl: config.baseUrl,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async getIdentifierOpts(ctx: any): Promise<IdentifierOpts | null> {
|
|
83
|
+
return await this.options.identify(ctx);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async getAuthParams({
|
|
87
|
+
ctx,
|
|
88
|
+
requireAuth = true,
|
|
89
|
+
}: {
|
|
90
|
+
ctx: any;
|
|
91
|
+
requireAuth?: boolean;
|
|
92
|
+
}): Promise<{ client: SurpayClient; identifierOpts: IdentifierOpts | null }> {
|
|
93
|
+
const identifierOpts = await this.getIdentifierOpts(ctx);
|
|
94
|
+
if (requireAuth && !identifierOpts) {
|
|
95
|
+
throw new Error("No customer identifier found");
|
|
96
|
+
}
|
|
97
|
+
return { client: this.client, identifierOpts };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
api() {
|
|
101
|
+
return {
|
|
102
|
+
createCheckout: actionGeneric({
|
|
103
|
+
args: CreateCheckoutArgs,
|
|
104
|
+
handler: async (ctx, args) => {
|
|
105
|
+
const { client, identifierOpts } = await this.getAuthParams({ ctx });
|
|
106
|
+
// Merge customer info from auth context with checkout args
|
|
107
|
+
const checkoutParams = {
|
|
108
|
+
...args,
|
|
109
|
+
customer_id: identifierOpts!.customerId,
|
|
110
|
+
customer_name: identifierOpts!.customerData?.name,
|
|
111
|
+
customer_email: identifierOpts!.customerData?.email,
|
|
112
|
+
};
|
|
113
|
+
return wrapSdkCall(() =>
|
|
114
|
+
client.checkout.create(checkoutParams as Parameters<typeof client.checkout.create>[0])
|
|
115
|
+
);
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
|
|
119
|
+
getCustomer: actionGeneric({
|
|
120
|
+
args: GetCustomerArgs,
|
|
121
|
+
handler: async (ctx, args) => {
|
|
122
|
+
const { client, identifierOpts } = await this.getAuthParams({ ctx });
|
|
123
|
+
const customerId = args.customer_id || identifierOpts!.customerId;
|
|
124
|
+
return wrapSdkCall(() =>
|
|
125
|
+
client.customers.get(args.project_id, customerId)
|
|
126
|
+
);
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
|
|
130
|
+
listCustomers: actionGeneric({
|
|
131
|
+
args: ListCustomersArgs,
|
|
132
|
+
handler: async (ctx, args) => {
|
|
133
|
+
const { client } = await this.getAuthParams({ ctx });
|
|
134
|
+
return wrapSdkCall(() => client.customers.list(args.project_id));
|
|
135
|
+
},
|
|
136
|
+
}),
|
|
137
|
+
|
|
138
|
+
listSubscriptions: actionGeneric({
|
|
139
|
+
args: ListSubscriptionsArgs,
|
|
140
|
+
handler: async (ctx, args) => {
|
|
141
|
+
const { client } = await this.getAuthParams({ ctx });
|
|
142
|
+
return wrapSdkCall(() => client.subscriptions.list(args.project_id));
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export * from "./types.js";
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex validators for Surpay action arguments
|
|
3
|
+
*/
|
|
4
|
+
import { v, Infer } from "convex/values";
|
|
5
|
+
|
|
6
|
+
// CreateCheckoutRequest: product_id, price_id, success_url, cancel_url (all required)
|
|
7
|
+
export const CreateCheckoutArgs = v.object({
|
|
8
|
+
product_id: v.string(),
|
|
9
|
+
price_id: v.string(),
|
|
10
|
+
success_url: v.string(),
|
|
11
|
+
cancel_url: v.string(),
|
|
12
|
+
});
|
|
13
|
+
export type CreateCheckoutArgs = Infer<typeof CreateCheckoutArgs>;
|
|
14
|
+
|
|
15
|
+
// ListSubscriptions: requires project_id
|
|
16
|
+
export const ListSubscriptionsArgs = v.object({
|
|
17
|
+
project_id: v.string(),
|
|
18
|
+
});
|
|
19
|
+
export type ListSubscriptionsArgs = Infer<typeof ListSubscriptionsArgs>;
|
|
20
|
+
|
|
21
|
+
// GetCustomer: requires project_id and customer_id
|
|
22
|
+
export const GetCustomerArgs = v.object({
|
|
23
|
+
project_id: v.string(),
|
|
24
|
+
customer_id: v.string(),
|
|
25
|
+
});
|
|
26
|
+
export type GetCustomerArgs = Infer<typeof GetCustomerArgs>;
|
|
27
|
+
|
|
28
|
+
// ListCustomers: requires project_id
|
|
29
|
+
export const ListCustomersArgs = v.object({
|
|
30
|
+
project_id: v.string(),
|
|
31
|
+
});
|
|
32
|
+
export type ListCustomersArgs = Infer<typeof ListCustomersArgs>;
|