@skinramp/ts-sdk 0.0.3 → 0.0.5
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 +21 -0
- package/dist/index.d.mts +75 -3
- package/dist/index.mjs +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ bun add @skinramp/ts-sdk
|
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
|
+
### Create a Payment
|
|
20
|
+
|
|
19
21
|
```typescript
|
|
20
22
|
import Skinramp from "@skinramp/ts-sdk";
|
|
21
23
|
|
|
@@ -28,6 +30,25 @@ const paymentId = await skinramp.payments.create({
|
|
|
28
30
|
});
|
|
29
31
|
```
|
|
30
32
|
|
|
33
|
+
### Verify Webhooks
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { Webhook } from "@skinramp/ts-sdk";
|
|
37
|
+
|
|
38
|
+
const webhook = new Webhook("whsec_...");
|
|
39
|
+
|
|
40
|
+
// In your webhook handler
|
|
41
|
+
const event = webhook.verify(rawBody, {
|
|
42
|
+
"webhook-id": req.headers["webhook-id"],
|
|
43
|
+
"webhook-timestamp": req.headers["webhook-timestamp"],
|
|
44
|
+
"webhook-signature": req.headers["webhook-signature"],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// event is typed as WebhookEvent<PaymentData>
|
|
48
|
+
console.log(event.type); // "payment.paid"
|
|
49
|
+
console.log(event.data); // { _id, amount, status, ... }
|
|
50
|
+
```
|
|
51
|
+
|
|
31
52
|
## License
|
|
32
53
|
|
|
33
54
|
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { GenericId } from "convex/values";
|
|
2
2
|
|
|
3
3
|
//#region src/client.d.ts
|
|
4
4
|
|
|
@@ -22,8 +22,80 @@ declare class Skinramp {
|
|
|
22
22
|
amount: number;
|
|
23
23
|
gameId?: "CS2" | "ROBLOX" | "RUST";
|
|
24
24
|
metadata?: Record<string, string | number | boolean>;
|
|
25
|
-
}) => Promise<
|
|
25
|
+
}) => Promise<GenericId<"payments">>;
|
|
26
|
+
get: (paymentId: string) => Promise<{
|
|
27
|
+
_creationTime: number;
|
|
28
|
+
_id: GenericId<"payments">;
|
|
29
|
+
amount: number;
|
|
30
|
+
billingAddress?: {
|
|
31
|
+
city?: string;
|
|
32
|
+
country?: string;
|
|
33
|
+
line1?: string;
|
|
34
|
+
line2?: string;
|
|
35
|
+
name?: string;
|
|
36
|
+
postalCode?: string;
|
|
37
|
+
state?: string;
|
|
38
|
+
};
|
|
39
|
+
cardInfo?: {
|
|
40
|
+
brand?: string;
|
|
41
|
+
last4?: string;
|
|
42
|
+
};
|
|
43
|
+
gameId: "CS2" | "ROBLOX" | "RUST";
|
|
44
|
+
merchantId: GenericId<"merchants">;
|
|
45
|
+
paidAt?: number;
|
|
46
|
+
status: "PENDING" | "PAID" | "FAILED" | "BLOCKED" | "DISPUTED" | "DISPUTE_WON" | "DISPUTE_LOST" | "REFUNDED";
|
|
47
|
+
userInfo?: {
|
|
48
|
+
email?: string;
|
|
49
|
+
name?: string;
|
|
50
|
+
};
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/webhook.d.ts
|
|
56
|
+
declare class WebhookVerificationError extends Error {
|
|
57
|
+
constructor(message: string);
|
|
58
|
+
}
|
|
59
|
+
type WebhookEventType = "payment.created" | "payment.paid" | "payment.failed" | "payment.blocked" | "payment.disputed" | "payment.dispute_won" | "payment.dispute_lost" | "payment.refunded" | "payout.created";
|
|
60
|
+
interface PaymentData {
|
|
61
|
+
_id: string;
|
|
62
|
+
_creationTime: number;
|
|
63
|
+
amount: number;
|
|
64
|
+
status: "PENDING" | "PAID" | "FAILED" | "BLOCKED" | "DISPUTED" | "DISPUTE_WON" | "DISPUTE_LOST" | "REFUNDED";
|
|
65
|
+
gameId: "CS2" | "ROBLOX" | "RUST";
|
|
66
|
+
merchantId: string;
|
|
67
|
+
paidAt?: number;
|
|
68
|
+
cardInfo?: {
|
|
69
|
+
brand?: string;
|
|
70
|
+
last4?: string;
|
|
26
71
|
};
|
|
72
|
+
billingAddress?: {
|
|
73
|
+
name?: string;
|
|
74
|
+
line1?: string;
|
|
75
|
+
line2?: string;
|
|
76
|
+
city?: string;
|
|
77
|
+
state?: string;
|
|
78
|
+
postalCode?: string;
|
|
79
|
+
country?: string;
|
|
80
|
+
};
|
|
81
|
+
userInfo?: {
|
|
82
|
+
name?: string;
|
|
83
|
+
email?: string;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
interface WebhookEvent<T = PaymentData> {
|
|
87
|
+
id: string;
|
|
88
|
+
type: WebhookEventType;
|
|
89
|
+
timestamp: string;
|
|
90
|
+
data: T;
|
|
91
|
+
}
|
|
92
|
+
declare class Webhook {
|
|
93
|
+
private static prefix;
|
|
94
|
+
private readonly key;
|
|
95
|
+
constructor(secret: string);
|
|
96
|
+
verify(payload: string, headers: Record<string, string>): WebhookEvent<PaymentData>;
|
|
97
|
+
private sign;
|
|
98
|
+
private verifyTimestamp;
|
|
27
99
|
}
|
|
28
100
|
//#endregion
|
|
29
|
-
export { Skinramp, Skinramp as default };
|
|
101
|
+
export { type PaymentData, Skinramp, Skinramp as default, Webhook, type WebhookEvent, type WebhookEventType, WebhookVerificationError };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ConvexHttpClient as e}from"convex/browser";import{anyApi as t}from"convex/server";import"
|
|
1
|
+
import{ConvexHttpClient as e}from"convex/browser";import"convex/values";import{anyApi as t}from"convex/server";import*as n from"@stablelib/base64";import*as r from"fast-sha256";const i=t;var a=class{convexHttp;apiKey;constructor(t,n=`https://sync.skinramp.com`){if(!t)throw Error(`API key is required`);this.apiKey=t,this.convexHttp=new e(n)}payments={create:async e=>{if(!this.apiKey)throw Error(`API key is required`);return await this.convexHttp.mutation(i.payments.createPayment,{apiKey:this.apiKey,amount:e.amount,gameId:e.gameId,metadata:e.metadata})},get:async e=>{if(!this.apiKey)throw Error(`API key is required`);return await this.convexHttp.query(i.payments.getPrivatePayment,{apiKey:this.apiKey,paymentId:e})}}},o=class extends Error{constructor(e){super(e),this.name=`WebhookVerificationError`}};function s(e,t){if(e.byteLength!==t.byteLength)return!1;let n=e instanceof DataView?e:new DataView(ArrayBuffer.isView(e)?e.buffer:e),r=t instanceof DataView?t:new DataView(ArrayBuffer.isView(t)?t.buffer:t),i=n.byteLength,a=0;for(let e=0;e<i;e++)a|=n.getUint8(e)^r.getUint8(e);return a===0}var c=class e{static prefix=`whsec_`;key;constructor(t){if(!t)throw Error(`Secret can't be empty.`);t.startsWith(e.prefix)&&(t=t.substring(e.prefix.length)),this.key=n.decode(t)}verify(e,t){let n={};for(let e of Object.keys(t))n[e.toLowerCase()]=t[e];let r=n[`webhook-id`],i=n[`webhook-signature`],a=n[`webhook-timestamp`];if(!i||!r||!a)throw new o(`Missing required headers`);let c=this.verifyTimestamp(a),l=this.sign(r,c,e),u=i.split(` `),d=new TextEncoder;for(let t of u){let[n,r]=t.split(`,`);if(n===`v1`&&s(d.encode(r),d.encode(l)))return JSON.parse(e)}throw new o(`No matching signature found`)}sign(e,t,i){let a=new TextEncoder,o=Math.floor(t.getTime()/1e3),s=a.encode(`${e}.${o}.${i}`);return n.encode(r.hmac(this.key,s))}verifyTimestamp(e){let t=Math.floor(Date.now()/1e3),n=parseInt(e,10);if(isNaN(n))throw new o(`Invalid timestamp header`);if(t-n>300)throw new o(`Message timestamp too old`);if(n>t+300)throw new o(`Message timestamp too new`);return new Date(n*1e3)}};export{a as Skinramp,a as default,c as Webhook,o as WebhookVerificationError};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skinramp/ts-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Skinramp TypeScript SDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://skinramp.com",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
"vitest": "^4.0.16"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"
|
|
35
|
+
"@stablelib/base64": "^2.0.0",
|
|
36
|
+
"convex": "^1.31.2",
|
|
37
|
+
"fast-sha256": "^1.3.0"
|
|
36
38
|
}
|
|
37
39
|
}
|