@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 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 * as convex_values0 from "convex/values";
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<convex_values0.GenericId<"payments">>;
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"convex/values";const n=t;var r=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(n.payments.createPayment,{apiKey:this.apiKey,amount:e.amount,gameId:e.gameId,metadata:e.metadata})}}};export{r as Skinramp,r as default};
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",
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
- "convex": "^1.31.2"
35
+ "@stablelib/base64": "^2.0.0",
36
+ "convex": "^1.31.2",
37
+ "fast-sha256": "^1.3.0"
36
38
  }
37
39
  }