@tbookdev/vault-node 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/dist/index.cjs ADDED
@@ -0,0 +1,198 @@
1
+ 'use strict';
2
+
3
+ var crypto = require('crypto');
4
+
5
+ // src/webhooks.ts
6
+ var WebhookVerificationError = class extends Error {
7
+ code;
8
+ constructor(code, message) {
9
+ super(message);
10
+ this.name = "WebhookVerificationError";
11
+ this.code = code;
12
+ }
13
+ };
14
+ var DEFAULT_TOLERANCE_SECONDS = 300;
15
+ var WebhookVerifier = class {
16
+ secret;
17
+ toleranceSeconds;
18
+ constructor(secret, toleranceSeconds = DEFAULT_TOLERANCE_SECONDS) {
19
+ if (!secret) {
20
+ throw new Error("Webhook secret is required for verification");
21
+ }
22
+ this.secret = secret;
23
+ this.toleranceSeconds = toleranceSeconds;
24
+ }
25
+ /**
26
+ * Verify a webhook payload and return the parsed event.
27
+ *
28
+ * @param body - Raw request body (string or Buffer)
29
+ * @param signatureHeader - Value of the `X-TBook-Signature` header
30
+ * @returns The verified and parsed webhook event
31
+ *
32
+ * @throws {WebhookVerificationError} If verification fails
33
+ */
34
+ verify(body, signatureHeader) {
35
+ if (!signatureHeader) {
36
+ throw new WebhookVerificationError(
37
+ "MISSING_SIGNATURE",
38
+ "Missing X-TBook-Signature header"
39
+ );
40
+ }
41
+ const bodyStr = typeof body === "string" ? body : body.toString("utf-8");
42
+ const parts = signatureHeader.split(",");
43
+ const timestampStr = parts.find((p) => p.startsWith("t="))?.slice(2);
44
+ const signatureHex = parts.find((p) => p.startsWith("v1="))?.slice(3);
45
+ if (!timestampStr || !signatureHex) {
46
+ throw new WebhookVerificationError(
47
+ "INVALID_SIGNATURE_FORMAT",
48
+ "Invalid signature header format. Expected: t=timestamp,v1=hex_signature"
49
+ );
50
+ }
51
+ const timestamp = parseInt(timestampStr, 10);
52
+ if (isNaN(timestamp)) {
53
+ throw new WebhookVerificationError(
54
+ "INVALID_TIMESTAMP",
55
+ "Invalid timestamp in signature header"
56
+ );
57
+ }
58
+ const nowSeconds = Date.now() / 1e3;
59
+ const futureSkew = timestamp - nowSeconds;
60
+ if (futureSkew > this.toleranceSeconds) {
61
+ throw new WebhookVerificationError(
62
+ "TIMESTAMP_FUTURE",
63
+ `Webhook timestamp is ${Math.floor(futureSkew)}s in the future (max ${this.toleranceSeconds}s). This may indicate clock skew or a forged request.`
64
+ );
65
+ }
66
+ const age = Math.abs(nowSeconds - timestamp);
67
+ if (age > this.toleranceSeconds) {
68
+ throw new WebhookVerificationError(
69
+ "TIMESTAMP_EXPIRED",
70
+ `Webhook timestamp is ${Math.floor(age)}s old (max ${this.toleranceSeconds}s). This may indicate a replay attack or clock skew.`
71
+ );
72
+ }
73
+ const signedContent = `${timestamp}.${bodyStr}`;
74
+ const expectedHex = crypto.createHmac("sha256", this.secret).update(signedContent).digest("hex");
75
+ const expectedBuf = Buffer.from(expectedHex, "hex");
76
+ const actualBuf = Buffer.from(signatureHex, "hex");
77
+ if (expectedBuf.length !== actualBuf.length || !crypto.timingSafeEqual(expectedBuf, actualBuf)) {
78
+ throw new WebhookVerificationError(
79
+ "INVALID_SIGNATURE",
80
+ "Webhook signature verification failed. The payload may have been tampered with."
81
+ );
82
+ }
83
+ try {
84
+ return JSON.parse(bodyStr);
85
+ } catch {
86
+ throw new WebhookVerificationError(
87
+ "INVALID_PAYLOAD",
88
+ "Failed to parse webhook payload as JSON"
89
+ );
90
+ }
91
+ }
92
+ };
93
+
94
+ // src/client.ts
95
+ var DEFAULT_API_BASE_URL = "https://rwa-api.tbook.com";
96
+ var DEFAULT_VAULT_ID = "rcUSDP";
97
+ var TBookVaultServer = class {
98
+ secretKey;
99
+ apiBaseUrl;
100
+ /** Webhook verification helper. */
101
+ webhooks;
102
+ constructor(options) {
103
+ if (!options.secretKey) {
104
+ throw new Error("secretKey is required for TBookVaultServer");
105
+ }
106
+ this.secretKey = options.secretKey;
107
+ this.apiBaseUrl = options.apiBaseUrl ?? DEFAULT_API_BASE_URL;
108
+ this.webhooks = new WebhookVerifier(options.webhookSecret ?? "");
109
+ }
110
+ // ── API Methods ──
111
+ /**
112
+ * Fetch vault state.
113
+ *
114
+ * @param vaultId - Vault identifier (defaults to rcUSDP)
115
+ */
116
+ async getVaultInfo(vaultId = DEFAULT_VAULT_ID) {
117
+ return this.get(`/v1/vaults/${vaultId}`);
118
+ }
119
+ /**
120
+ * Fetch a user's vault account.
121
+ *
122
+ * @param pubkey - Solana public key string
123
+ * @param vaultId - Vault identifier (defaults to rcUSDP)
124
+ */
125
+ async getUserAccount(pubkey, vaultId = DEFAULT_VAULT_ID) {
126
+ return this.get(`/v1/vaults/${vaultId}/users/${pubkey}`);
127
+ }
128
+ /** Fetch current share price and APY. */
129
+ async getSharePrice(vaultId = DEFAULT_VAULT_ID) {
130
+ return this.get(`/v1/vaults/${vaultId}/price`);
131
+ }
132
+ /** List all available vaults. */
133
+ async listVaults() {
134
+ return this.get("/v1/vaults");
135
+ }
136
+ // ── Webhook Management ──
137
+ /** Register a new webhook endpoint. */
138
+ async registerWebhook(url, events) {
139
+ return this.post("/v1/webhooks", { url, events });
140
+ }
141
+ /** List registered webhooks. */
142
+ async listWebhooks() {
143
+ return this.get("/v1/webhooks");
144
+ }
145
+ /** Remove a webhook. */
146
+ async removeWebhook(id) {
147
+ return this.delete(`/v1/webhooks/${id}`);
148
+ }
149
+ /** Poll events (alternative to push webhooks). */
150
+ async pollEvents(options) {
151
+ const params = new URLSearchParams();
152
+ if (options?.after) params.set("after", options.after);
153
+ if (options?.types) params.set("types", options.types.join(","));
154
+ if (options?.limit) params.set("limit", String(options.limit));
155
+ const qs = params.toString();
156
+ return this.get(`/v1/events${qs ? `?${qs}` : ""}`);
157
+ }
158
+ // ── HTTP Helpers ──
159
+ async get(path) {
160
+ const res = await fetch(`${this.apiBaseUrl}${path}`, {
161
+ headers: this.headers()
162
+ });
163
+ return this.handleResponse(res);
164
+ }
165
+ async post(path, body) {
166
+ const res = await fetch(`${this.apiBaseUrl}${path}`, {
167
+ method: "POST",
168
+ headers: { ...this.headers(), "Content-Type": "application/json" },
169
+ body: JSON.stringify(body)
170
+ });
171
+ return this.handleResponse(res);
172
+ }
173
+ async delete(path) {
174
+ const res = await fetch(`${this.apiBaseUrl}${path}`, {
175
+ method: "DELETE",
176
+ headers: this.headers()
177
+ });
178
+ return this.handleResponse(res);
179
+ }
180
+ headers() {
181
+ return { "x-api-key": this.secretKey };
182
+ }
183
+ async handleResponse(res) {
184
+ const data = await res.json();
185
+ if (!res.ok) {
186
+ throw new Error(
187
+ `TBook API error (${res.status}): ${data.error ?? JSON.stringify(data)}`
188
+ );
189
+ }
190
+ return data;
191
+ }
192
+ };
193
+
194
+ exports.TBookVaultServer = TBookVaultServer;
195
+ exports.WebhookVerificationError = WebhookVerificationError;
196
+ exports.WebhookVerifier = WebhookVerifier;
197
+ //# sourceMappingURL=index.cjs.map
198
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/webhooks.ts","../src/client.ts"],"names":["createHmac","timingSafeEqual"],"mappings":";;;;;AAgCO,IAAM,wBAAA,GAAN,cAAuC,KAAA,CAAM;AAAA,EACzC,IAAA;AAAA,EAET,WAAA,CAAY,MAAc,OAAA,EAAiB;AACzC,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,0BAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF;AAGA,IAAM,yBAAA,GAA4B,GAAA;AAQ3B,IAAM,kBAAN,MAAsB;AAAA,EACV,MAAA;AAAA,EACA,gBAAA;AAAA,EAEjB,WAAA,CAAY,MAAA,EAAgB,gBAAA,GAAmB,yBAAA,EAA2B;AACxE,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,MAAM,6CAA6C,CAAA;AAAA,IAC/D;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,gBAAA,GAAmB,gBAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAA,CAAO,MAAuB,eAAA,EAAuC;AACnE,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA,MAAM,IAAI,wBAAA;AAAA,QACR,mBAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,OAAO,IAAA,KAAS,WAAW,IAAA,GAAO,IAAA,CAAK,SAAS,OAAO,CAAA;AAGvE,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,KAAA,CAAM,GAAG,CAAA;AACvC,IAAA,MAAM,YAAA,GAAe,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,CAAW,IAAI,CAAC,CAAA,EAAG,KAAA,CAAM,CAAC,CAAA;AACnE,IAAA,MAAM,YAAA,GAAe,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,CAAW,KAAK,CAAC,CAAA,EAAG,KAAA,CAAM,CAAC,CAAA;AAEpE,IAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,YAAA,EAAc;AAClC,MAAA,MAAM,IAAI,wBAAA;AAAA,QACR,0BAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GAAY,QAAA,CAAS,YAAA,EAAc,EAAE,CAAA;AAC3C,IAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,MAAA,MAAM,IAAI,wBAAA;AAAA,QACR,mBAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAGA,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,GAAA;AAChC,IAAA,MAAM,aAAa,SAAA,GAAY,UAAA;AAC/B,IAAA,IAAI,UAAA,GAAa,KAAK,gBAAA,EAAkB;AACtC,MAAA,MAAM,IAAI,wBAAA;AAAA,QACR,kBAAA;AAAA,QACA,wBAAwB,IAAA,CAAK,KAAA,CAAM,UAAU,CAAC,CAAA,qBAAA,EAAwB,KAAK,gBAAgB,CAAA,qDAAA;AAAA,OAE7F;AAAA,IACF;AAGA,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,UAAA,GAAa,SAAS,CAAA;AAC3C,IAAA,IAAI,GAAA,GAAM,KAAK,gBAAA,EAAkB;AAC/B,MAAA,MAAM,IAAI,wBAAA;AAAA,QACR,mBAAA;AAAA,QACA,wBAAwB,IAAA,CAAK,KAAA,CAAM,GAAG,CAAC,CAAA,WAAA,EAAc,KAAK,gBAAgB,CAAA,oDAAA;AAAA,OAE5E;AAAA,IACF;AAGA,IAAA,MAAM,aAAA,GAAgB,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA;AAC7C,IAAA,MAAM,WAAA,GAAcA,iBAAA,CAAW,QAAA,EAAU,IAAA,CAAK,MAAM,EACjD,MAAA,CAAO,aAAa,CAAA,CACpB,MAAA,CAAO,KAAK,CAAA;AAGf,IAAA,MAAM,WAAA,GAAc,MAAA,CAAO,IAAA,CAAK,WAAA,EAAa,KAAK,CAAA;AAClD,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,YAAA,EAAc,KAAK,CAAA;AAEjD,IAAA,IAAI,WAAA,CAAY,WAAW,SAAA,CAAU,MAAA,IAAU,CAACC,sBAAA,CAAgB,WAAA,EAAa,SAAS,CAAA,EAAG;AACvF,MAAA,MAAM,IAAI,wBAAA;AAAA,QACR,mBAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAGA,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,IAC3B,CAAA,CAAA,MAAQ;AACN,MAAA,MAAM,IAAI,wBAAA;AAAA,QACR,iBAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAAA,EACF;AACF;;;AC1IA,IAAM,oBAAA,GAAuB,2BAAA;AAC7B,IAAM,gBAAA,GAAmB,QAAA;AAoBlB,IAAM,mBAAN,MAAuB;AAAA,EACX,SAAA;AAAA,EACA,UAAA;AAAA;AAAA,EAGR,QAAA;AAAA,EAET,YAAY,OAAA,EAAkC;AAC5C,IAAA,IAAI,CAAC,QAAQ,SAAA,EAAW;AACtB,MAAA,MAAM,IAAI,MAAM,4CAA4C,CAAA;AAAA,IAC9D;AACA,IAAA,IAAA,CAAK,YAAY,OAAA,CAAQ,SAAA;AACzB,IAAA,IAAA,CAAK,UAAA,GAAa,QAAQ,UAAA,IAAc,oBAAA;AAGxC,IAAA,IAAA,CAAK,QAAA,GAAW,IAAI,eAAA,CAAgB,OAAA,CAAQ,iBAAiB,EAAE,CAAA;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,YAAA,CAAa,OAAA,GAAkB,gBAAA,EAAkB;AACrD,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,WAAA,EAAc,OAAO,CAAA,CAAE,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,cAAA,CAAe,MAAA,EAAgB,OAAA,GAAkB,gBAAA,EAAkB;AACvE,IAAA,OAAO,KAAK,GAAA,CAAI,CAAA,WAAA,EAAc,OAAO,CAAA,OAAA,EAAU,MAAM,CAAA,CAAE,CAAA;AAAA,EACzD;AAAA;AAAA,EAGA,MAAM,aAAA,CAAc,OAAA,GAAkB,gBAAA,EAAkB;AACtD,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,WAAA,EAAc,OAAO,CAAA,MAAA,CAAQ,CAAA;AAAA,EAC/C;AAAA;AAAA,EAGA,MAAM,UAAA,GAAa;AACjB,IAAA,OAAO,IAAA,CAAK,IAAI,YAAY,CAAA;AAAA,EAC9B;AAAA;AAAA;AAAA,EAKA,MAAM,eAAA,CAAgB,GAAA,EAAa,MAAA,EAAkB;AACnD,IAAA,OAAO,KAAK,IAAA,CAAK,cAAA,EAAgB,EAAE,GAAA,EAAK,QAAQ,CAAA;AAAA,EAClD;AAAA;AAAA,EAGA,MAAM,YAAA,GAAe;AACnB,IAAA,OAAO,IAAA,CAAK,IAAI,cAAc,CAAA;AAAA,EAChC;AAAA;AAAA,EAGA,MAAM,cAAc,EAAA,EAAY;AAC9B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,CAAA,aAAA,EAAgB,EAAE,CAAA,CAAE,CAAA;AAAA,EACzC;AAAA;AAAA,EAGA,MAAM,WAAW,OAAA,EAAgE;AAC/E,IAAA,MAAM,MAAA,GAAS,IAAI,eAAA,EAAgB;AACnC,IAAA,IAAI,SAAS,KAAA,EAAO,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,QAAQ,KAAK,CAAA;AACrD,IAAA,IAAI,OAAA,EAAS,OAAO,MAAA,CAAO,GAAA,CAAI,SAAS,OAAA,CAAQ,KAAA,CAAM,IAAA,CAAK,GAAG,CAAC,CAAA;AAC/D,IAAA,IAAI,OAAA,EAAS,OAAO,MAAA,CAAO,GAAA,CAAI,SAAS,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAC,CAAA;AAC7D,IAAA,MAAM,EAAA,GAAK,OAAO,QAAA,EAAS;AAC3B,IAAA,OAAO,IAAA,CAAK,IAAI,CAAA,UAAA,EAAa,EAAA,GAAK,IAAI,EAAE,CAAA,CAAA,GAAK,EAAE,CAAA,CAAE,CAAA;AAAA,EACnD;AAAA;AAAA,EAIA,MAAc,IAAI,IAAA,EAA4B;AAC5C,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,UAAU,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI;AAAA,MACnD,OAAA,EAAS,KAAK,OAAA;AAAQ,KACvB,CAAA;AACD,IAAA,OAAO,IAAA,CAAK,eAAe,GAAG,CAAA;AAAA,EAChC;AAAA,EAEA,MAAc,IAAA,CAAK,IAAA,EAAc,IAAA,EAAyB;AACxD,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,UAAU,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI;AAAA,MACnD,MAAA,EAAQ,MAAA;AAAA,MACR,SAAS,EAAE,GAAG,KAAK,OAAA,EAAQ,EAAG,gBAAgB,kBAAA,EAAmB;AAAA,MACjE,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI;AAAA,KAC1B,CAAA;AACD,IAAA,OAAO,IAAA,CAAK,eAAe,GAAG,CAAA;AAAA,EAChC;AAAA,EAEA,MAAc,OAAO,IAAA,EAA4B;AAC/C,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,UAAU,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI;AAAA,MACnD,MAAA,EAAQ,QAAA;AAAA,MACR,OAAA,EAAS,KAAK,OAAA;AAAQ,KACvB,CAAA;AACD,IAAA,OAAO,IAAA,CAAK,eAAe,GAAG,CAAA;AAAA,EAChC;AAAA,EAEQ,OAAA,GAAkC;AACxC,IAAA,OAAO,EAAE,WAAA,EAAa,IAAA,CAAK,SAAA,EAAU;AAAA,EACvC;AAAA,EAEA,MAAc,eAAe,GAAA,EAA6B;AACxD,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,iBAAA,EAAoB,IAAI,MAAM,CAAA,GAAA,EAAM,KAAK,KAAA,IAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,OACxE;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACF","file":"index.cjs","sourcesContent":["/**\n * Webhook signature verification for inbound events.\n *\n * Verifies HMAC-SHA256 signatures to ensure events are genuinely\n * from the TBook API and haven't been tampered with.\n *\n * @module webhooks\n *\n * @example\n * ```typescript\n * import { TBookVaultServer } from \"@tbookdev/vault-node\";\n *\n * const tbook = new TBookVaultServer({\n * secretKey: \"tbk_secret_...\",\n * webhookSecret: \"whsec_...\",\n * });\n *\n * app.post(\"/webhook\", (req, res) => {\n * const event = tbook.webhooks.verify(\n * req.body,\n * req.headers[\"x-tbook-signature\"],\n * );\n * console.log(event.type, event.data);\n * res.json({ received: true });\n * });\n * ```\n */\n\nimport { createHmac, timingSafeEqual } from \"crypto\";\nimport type { WebhookEvent } from \"./types.js\";\n\n/** Error thrown when webhook verification fails. */\nexport class WebhookVerificationError extends Error {\n readonly code: string;\n\n constructor(code: string, message: string) {\n super(message);\n this.name = \"WebhookVerificationError\";\n this.code = code;\n }\n}\n\n/** Default tolerance for timestamp validation (5 minutes). */\nconst DEFAULT_TOLERANCE_SECONDS = 300;\n\n/**\n * Webhook verification helper.\n *\n * Create an instance with your webhook secret, then call `verify()`\n * on each incoming webhook request.\n */\nexport class WebhookVerifier {\n private readonly secret: string;\n private readonly toleranceSeconds: number;\n\n constructor(secret: string, toleranceSeconds = DEFAULT_TOLERANCE_SECONDS) {\n if (!secret) {\n throw new Error(\"Webhook secret is required for verification\");\n }\n this.secret = secret;\n this.toleranceSeconds = toleranceSeconds;\n }\n\n /**\n * Verify a webhook payload and return the parsed event.\n *\n * @param body - Raw request body (string or Buffer)\n * @param signatureHeader - Value of the `X-TBook-Signature` header\n * @returns The verified and parsed webhook event\n *\n * @throws {WebhookVerificationError} If verification fails\n */\n verify(body: string | Buffer, signatureHeader: string): WebhookEvent {\n if (!signatureHeader) {\n throw new WebhookVerificationError(\n \"MISSING_SIGNATURE\",\n \"Missing X-TBook-Signature header\",\n );\n }\n\n const bodyStr = typeof body === \"string\" ? body : body.toString(\"utf-8\");\n\n // Parse signature header: \"t=timestamp,v1=hex_signature\"\n const parts = signatureHeader.split(\",\");\n const timestampStr = parts.find((p) => p.startsWith(\"t=\"))?.slice(2);\n const signatureHex = parts.find((p) => p.startsWith(\"v1=\"))?.slice(3);\n\n if (!timestampStr || !signatureHex) {\n throw new WebhookVerificationError(\n \"INVALID_SIGNATURE_FORMAT\",\n \"Invalid signature header format. Expected: t=timestamp,v1=hex_signature\",\n );\n }\n\n const timestamp = parseInt(timestampStr, 10);\n if (isNaN(timestamp)) {\n throw new WebhookVerificationError(\n \"INVALID_TIMESTAMP\",\n \"Invalid timestamp in signature header\",\n );\n }\n\n // Reject timestamps too far in the future (> 5 minutes)\n const nowSeconds = Date.now() / 1000;\n const futureSkew = timestamp - nowSeconds;\n if (futureSkew > this.toleranceSeconds) {\n throw new WebhookVerificationError(\n \"TIMESTAMP_FUTURE\",\n `Webhook timestamp is ${Math.floor(futureSkew)}s in the future (max ${this.toleranceSeconds}s). ` +\n \"This may indicate clock skew or a forged request.\",\n );\n }\n\n // Check timestamp tolerance (prevent replay attacks)\n const age = Math.abs(nowSeconds - timestamp);\n if (age > this.toleranceSeconds) {\n throw new WebhookVerificationError(\n \"TIMESTAMP_EXPIRED\",\n `Webhook timestamp is ${Math.floor(age)}s old (max ${this.toleranceSeconds}s). ` +\n \"This may indicate a replay attack or clock skew.\",\n );\n }\n\n // Compute expected signature\n const signedContent = `${timestamp}.${bodyStr}`;\n const expectedHex = createHmac(\"sha256\", this.secret)\n .update(signedContent)\n .digest(\"hex\");\n\n // Timing-safe comparison to prevent timing attacks\n const expectedBuf = Buffer.from(expectedHex, \"hex\");\n const actualBuf = Buffer.from(signatureHex, \"hex\");\n\n if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) {\n throw new WebhookVerificationError(\n \"INVALID_SIGNATURE\",\n \"Webhook signature verification failed. The payload may have been tampered with.\",\n );\n }\n\n // Parse and return the event\n try {\n return JSON.parse(bodyStr) as WebhookEvent;\n } catch {\n throw new WebhookVerificationError(\n \"INVALID_PAYLOAD\",\n \"Failed to parse webhook payload as JSON\",\n );\n }\n }\n}\n","/**\n * Server-side TBook Vault API client.\n *\n * Provides authenticated access to the TBook API for server-side\n * use cases: reading vault state, user accounts, and managing webhooks.\n *\n * @module client\n */\n\nimport { WebhookVerifier } from \"./webhooks.js\";\nimport type { TBookVaultServerOptions } from \"./types.js\";\n\nconst DEFAULT_API_BASE_URL = \"https://rwa-api.tbook.com\";\nconst DEFAULT_VAULT_ID = \"rcUSDP\";\n\n/**\n * Server SDK client for TBook Vault Gateway.\n *\n * ```typescript\n * import { TBookVaultServer } from \"@tbookdev/vault-node\";\n *\n * const vault = new TBookVaultServer({\n * secretKey: \"tbk_secret_...\",\n * webhookSecret: \"whsec_...\",\n * });\n *\n * // Server-side reads\n * const info = await vault.getVaultInfo();\n *\n * // Webhook verification\n * const event = vault.webhooks.verify(body, signature);\n * ```\n */\nexport class TBookVaultServer {\n private readonly secretKey: string;\n private readonly apiBaseUrl: string;\n\n /** Webhook verification helper. */\n readonly webhooks: WebhookVerifier;\n\n constructor(options: TBookVaultServerOptions) {\n if (!options.secretKey) {\n throw new Error(\"secretKey is required for TBookVaultServer\");\n }\n this.secretKey = options.secretKey;\n this.apiBaseUrl = options.apiBaseUrl ?? DEFAULT_API_BASE_URL;\n\n // Initialize webhook verifier (will throw if secret is missing when used)\n this.webhooks = new WebhookVerifier(options.webhookSecret ?? \"\");\n }\n\n // ── API Methods ──\n\n /**\n * Fetch vault state.\n *\n * @param vaultId - Vault identifier (defaults to rcUSDP)\n */\n async getVaultInfo(vaultId: string = DEFAULT_VAULT_ID) {\n return this.get(`/v1/vaults/${vaultId}`);\n }\n\n /**\n * Fetch a user's vault account.\n *\n * @param pubkey - Solana public key string\n * @param vaultId - Vault identifier (defaults to rcUSDP)\n */\n async getUserAccount(pubkey: string, vaultId: string = DEFAULT_VAULT_ID) {\n return this.get(`/v1/vaults/${vaultId}/users/${pubkey}`);\n }\n\n /** Fetch current share price and APY. */\n async getSharePrice(vaultId: string = DEFAULT_VAULT_ID) {\n return this.get(`/v1/vaults/${vaultId}/price`);\n }\n\n /** List all available vaults. */\n async listVaults() {\n return this.get(\"/v1/vaults\");\n }\n\n // ── Webhook Management ──\n\n /** Register a new webhook endpoint. */\n async registerWebhook(url: string, events: string[]) {\n return this.post(\"/v1/webhooks\", { url, events });\n }\n\n /** List registered webhooks. */\n async listWebhooks() {\n return this.get(\"/v1/webhooks\");\n }\n\n /** Remove a webhook. */\n async removeWebhook(id: string) {\n return this.delete(`/v1/webhooks/${id}`);\n }\n\n /** Poll events (alternative to push webhooks). */\n async pollEvents(options?: { after?: string; types?: string[]; limit?: number }) {\n const params = new URLSearchParams();\n if (options?.after) params.set(\"after\", options.after);\n if (options?.types) params.set(\"types\", options.types.join(\",\"));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n const qs = params.toString();\n return this.get(`/v1/events${qs ? `?${qs}` : \"\"}`);\n }\n\n // ── HTTP Helpers ──\n\n private async get(path: string): Promise<any> {\n const res = await fetch(`${this.apiBaseUrl}${path}`, {\n headers: this.headers(),\n });\n return this.handleResponse(res);\n }\n\n private async post(path: string, body: any): Promise<any> {\n const res = await fetch(`${this.apiBaseUrl}${path}`, {\n method: \"POST\",\n headers: { ...this.headers(), \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return this.handleResponse(res);\n }\n\n private async delete(path: string): Promise<any> {\n const res = await fetch(`${this.apiBaseUrl}${path}`, {\n method: \"DELETE\",\n headers: this.headers(),\n });\n return this.handleResponse(res);\n }\n\n private headers(): Record<string, string> {\n return { \"x-api-key\": this.secretKey };\n }\n\n private async handleResponse(res: Response): Promise<any> {\n const data = await res.json();\n if (!res.ok) {\n throw new Error(\n `TBook API error (${res.status}): ${data.error ?? JSON.stringify(data)}`,\n );\n }\n return data;\n }\n}\n"]}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Types for the TBook Vault server SDK.
3
+ *
4
+ * @module types
5
+ */
6
+ /** Options for initializing the server SDK client. */
7
+ interface TBookVaultServerOptions {
8
+ /** Secret API key (tbk_secret_*). Required for webhook management. */
9
+ secretKey: string;
10
+ /** Webhook signing secret (whsec_*). Required for verifying inbound events. */
11
+ webhookSecret?: string;
12
+ /** Base URL of the TBook API. Defaults to production. */
13
+ apiBaseUrl?: string;
14
+ }
15
+ /** A verified webhook event. */
16
+ interface WebhookEvent<T = any> {
17
+ /** Unique event ID (evt_*). */
18
+ id: string;
19
+ /** Event type (e.g. "vault.deposit_epoch.settled"). */
20
+ type: WebhookEventType;
21
+ /** Event payload. */
22
+ data: T;
23
+ /** ISO timestamp of event creation. */
24
+ created: string;
25
+ }
26
+ /** Known webhook event types. */
27
+ type WebhookEventType = "vault.deposit_epoch.frozen" | "vault.deposit_epoch.settled" | "vault.deposit_epoch.rolled_back" | "vault.redeem_epoch.frozen" | "vault.redeem_epoch.settled" | "vault.redeem_epoch.rolled_back" | "vault.price.updated" | "vault.paused" | "vault.unpaused" | string;
28
+ /** Payload for deposit epoch settled events. */
29
+ interface DepositEpochSettledPayload {
30
+ epoch: number;
31
+ totalDepositUsdc: string;
32
+ settledSharesMinted: string;
33
+ sharePrice: string;
34
+ userCount: number;
35
+ }
36
+ /** Payload for redeem epoch settled events. */
37
+ interface RedeemEpochSettledPayload {
38
+ epoch: number;
39
+ totalRedeemShares: string;
40
+ settledUsdcForRedeems: string;
41
+ userCount: number;
42
+ }
43
+ /** Payload for price updated events. */
44
+ interface PriceUpdatedPayload {
45
+ price: string;
46
+ apy: string;
47
+ date: string;
48
+ }
49
+
50
+ /**
51
+ * Webhook signature verification for inbound events.
52
+ *
53
+ * Verifies HMAC-SHA256 signatures to ensure events are genuinely
54
+ * from the TBook API and haven't been tampered with.
55
+ *
56
+ * @module webhooks
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * import { TBookVaultServer } from "@tbookdev/vault-node";
61
+ *
62
+ * const tbook = new TBookVaultServer({
63
+ * secretKey: "tbk_secret_...",
64
+ * webhookSecret: "whsec_...",
65
+ * });
66
+ *
67
+ * app.post("/webhook", (req, res) => {
68
+ * const event = tbook.webhooks.verify(
69
+ * req.body,
70
+ * req.headers["x-tbook-signature"],
71
+ * );
72
+ * console.log(event.type, event.data);
73
+ * res.json({ received: true });
74
+ * });
75
+ * ```
76
+ */
77
+
78
+ /** Error thrown when webhook verification fails. */
79
+ declare class WebhookVerificationError extends Error {
80
+ readonly code: string;
81
+ constructor(code: string, message: string);
82
+ }
83
+ /**
84
+ * Webhook verification helper.
85
+ *
86
+ * Create an instance with your webhook secret, then call `verify()`
87
+ * on each incoming webhook request.
88
+ */
89
+ declare class WebhookVerifier {
90
+ private readonly secret;
91
+ private readonly toleranceSeconds;
92
+ constructor(secret: string, toleranceSeconds?: number);
93
+ /**
94
+ * Verify a webhook payload and return the parsed event.
95
+ *
96
+ * @param body - Raw request body (string or Buffer)
97
+ * @param signatureHeader - Value of the `X-TBook-Signature` header
98
+ * @returns The verified and parsed webhook event
99
+ *
100
+ * @throws {WebhookVerificationError} If verification fails
101
+ */
102
+ verify(body: string | Buffer, signatureHeader: string): WebhookEvent;
103
+ }
104
+
105
+ /**
106
+ * Server-side TBook Vault API client.
107
+ *
108
+ * Provides authenticated access to the TBook API for server-side
109
+ * use cases: reading vault state, user accounts, and managing webhooks.
110
+ *
111
+ * @module client
112
+ */
113
+
114
+ /**
115
+ * Server SDK client for TBook Vault Gateway.
116
+ *
117
+ * ```typescript
118
+ * import { TBookVaultServer } from "@tbookdev/vault-node";
119
+ *
120
+ * const vault = new TBookVaultServer({
121
+ * secretKey: "tbk_secret_...",
122
+ * webhookSecret: "whsec_...",
123
+ * });
124
+ *
125
+ * // Server-side reads
126
+ * const info = await vault.getVaultInfo();
127
+ *
128
+ * // Webhook verification
129
+ * const event = vault.webhooks.verify(body, signature);
130
+ * ```
131
+ */
132
+ declare class TBookVaultServer {
133
+ private readonly secretKey;
134
+ private readonly apiBaseUrl;
135
+ /** Webhook verification helper. */
136
+ readonly webhooks: WebhookVerifier;
137
+ constructor(options: TBookVaultServerOptions);
138
+ /**
139
+ * Fetch vault state.
140
+ *
141
+ * @param vaultId - Vault identifier (defaults to rcUSDP)
142
+ */
143
+ getVaultInfo(vaultId?: string): Promise<any>;
144
+ /**
145
+ * Fetch a user's vault account.
146
+ *
147
+ * @param pubkey - Solana public key string
148
+ * @param vaultId - Vault identifier (defaults to rcUSDP)
149
+ */
150
+ getUserAccount(pubkey: string, vaultId?: string): Promise<any>;
151
+ /** Fetch current share price and APY. */
152
+ getSharePrice(vaultId?: string): Promise<any>;
153
+ /** List all available vaults. */
154
+ listVaults(): Promise<any>;
155
+ /** Register a new webhook endpoint. */
156
+ registerWebhook(url: string, events: string[]): Promise<any>;
157
+ /** List registered webhooks. */
158
+ listWebhooks(): Promise<any>;
159
+ /** Remove a webhook. */
160
+ removeWebhook(id: string): Promise<any>;
161
+ /** Poll events (alternative to push webhooks). */
162
+ pollEvents(options?: {
163
+ after?: string;
164
+ types?: string[];
165
+ limit?: number;
166
+ }): Promise<any>;
167
+ private get;
168
+ private post;
169
+ private delete;
170
+ private headers;
171
+ private handleResponse;
172
+ }
173
+
174
+ export { type DepositEpochSettledPayload, type PriceUpdatedPayload, type RedeemEpochSettledPayload, TBookVaultServer, type TBookVaultServerOptions, type WebhookEvent, type WebhookEventType, WebhookVerificationError, WebhookVerifier };
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Types for the TBook Vault server SDK.
3
+ *
4
+ * @module types
5
+ */
6
+ /** Options for initializing the server SDK client. */
7
+ interface TBookVaultServerOptions {
8
+ /** Secret API key (tbk_secret_*). Required for webhook management. */
9
+ secretKey: string;
10
+ /** Webhook signing secret (whsec_*). Required for verifying inbound events. */
11
+ webhookSecret?: string;
12
+ /** Base URL of the TBook API. Defaults to production. */
13
+ apiBaseUrl?: string;
14
+ }
15
+ /** A verified webhook event. */
16
+ interface WebhookEvent<T = any> {
17
+ /** Unique event ID (evt_*). */
18
+ id: string;
19
+ /** Event type (e.g. "vault.deposit_epoch.settled"). */
20
+ type: WebhookEventType;
21
+ /** Event payload. */
22
+ data: T;
23
+ /** ISO timestamp of event creation. */
24
+ created: string;
25
+ }
26
+ /** Known webhook event types. */
27
+ type WebhookEventType = "vault.deposit_epoch.frozen" | "vault.deposit_epoch.settled" | "vault.deposit_epoch.rolled_back" | "vault.redeem_epoch.frozen" | "vault.redeem_epoch.settled" | "vault.redeem_epoch.rolled_back" | "vault.price.updated" | "vault.paused" | "vault.unpaused" | string;
28
+ /** Payload for deposit epoch settled events. */
29
+ interface DepositEpochSettledPayload {
30
+ epoch: number;
31
+ totalDepositUsdc: string;
32
+ settledSharesMinted: string;
33
+ sharePrice: string;
34
+ userCount: number;
35
+ }
36
+ /** Payload for redeem epoch settled events. */
37
+ interface RedeemEpochSettledPayload {
38
+ epoch: number;
39
+ totalRedeemShares: string;
40
+ settledUsdcForRedeems: string;
41
+ userCount: number;
42
+ }
43
+ /** Payload for price updated events. */
44
+ interface PriceUpdatedPayload {
45
+ price: string;
46
+ apy: string;
47
+ date: string;
48
+ }
49
+
50
+ /**
51
+ * Webhook signature verification for inbound events.
52
+ *
53
+ * Verifies HMAC-SHA256 signatures to ensure events are genuinely
54
+ * from the TBook API and haven't been tampered with.
55
+ *
56
+ * @module webhooks
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * import { TBookVaultServer } from "@tbookdev/vault-node";
61
+ *
62
+ * const tbook = new TBookVaultServer({
63
+ * secretKey: "tbk_secret_...",
64
+ * webhookSecret: "whsec_...",
65
+ * });
66
+ *
67
+ * app.post("/webhook", (req, res) => {
68
+ * const event = tbook.webhooks.verify(
69
+ * req.body,
70
+ * req.headers["x-tbook-signature"],
71
+ * );
72
+ * console.log(event.type, event.data);
73
+ * res.json({ received: true });
74
+ * });
75
+ * ```
76
+ */
77
+
78
+ /** Error thrown when webhook verification fails. */
79
+ declare class WebhookVerificationError extends Error {
80
+ readonly code: string;
81
+ constructor(code: string, message: string);
82
+ }
83
+ /**
84
+ * Webhook verification helper.
85
+ *
86
+ * Create an instance with your webhook secret, then call `verify()`
87
+ * on each incoming webhook request.
88
+ */
89
+ declare class WebhookVerifier {
90
+ private readonly secret;
91
+ private readonly toleranceSeconds;
92
+ constructor(secret: string, toleranceSeconds?: number);
93
+ /**
94
+ * Verify a webhook payload and return the parsed event.
95
+ *
96
+ * @param body - Raw request body (string or Buffer)
97
+ * @param signatureHeader - Value of the `X-TBook-Signature` header
98
+ * @returns The verified and parsed webhook event
99
+ *
100
+ * @throws {WebhookVerificationError} If verification fails
101
+ */
102
+ verify(body: string | Buffer, signatureHeader: string): WebhookEvent;
103
+ }
104
+
105
+ /**
106
+ * Server-side TBook Vault API client.
107
+ *
108
+ * Provides authenticated access to the TBook API for server-side
109
+ * use cases: reading vault state, user accounts, and managing webhooks.
110
+ *
111
+ * @module client
112
+ */
113
+
114
+ /**
115
+ * Server SDK client for TBook Vault Gateway.
116
+ *
117
+ * ```typescript
118
+ * import { TBookVaultServer } from "@tbookdev/vault-node";
119
+ *
120
+ * const vault = new TBookVaultServer({
121
+ * secretKey: "tbk_secret_...",
122
+ * webhookSecret: "whsec_...",
123
+ * });
124
+ *
125
+ * // Server-side reads
126
+ * const info = await vault.getVaultInfo();
127
+ *
128
+ * // Webhook verification
129
+ * const event = vault.webhooks.verify(body, signature);
130
+ * ```
131
+ */
132
+ declare class TBookVaultServer {
133
+ private readonly secretKey;
134
+ private readonly apiBaseUrl;
135
+ /** Webhook verification helper. */
136
+ readonly webhooks: WebhookVerifier;
137
+ constructor(options: TBookVaultServerOptions);
138
+ /**
139
+ * Fetch vault state.
140
+ *
141
+ * @param vaultId - Vault identifier (defaults to rcUSDP)
142
+ */
143
+ getVaultInfo(vaultId?: string): Promise<any>;
144
+ /**
145
+ * Fetch a user's vault account.
146
+ *
147
+ * @param pubkey - Solana public key string
148
+ * @param vaultId - Vault identifier (defaults to rcUSDP)
149
+ */
150
+ getUserAccount(pubkey: string, vaultId?: string): Promise<any>;
151
+ /** Fetch current share price and APY. */
152
+ getSharePrice(vaultId?: string): Promise<any>;
153
+ /** List all available vaults. */
154
+ listVaults(): Promise<any>;
155
+ /** Register a new webhook endpoint. */
156
+ registerWebhook(url: string, events: string[]): Promise<any>;
157
+ /** List registered webhooks. */
158
+ listWebhooks(): Promise<any>;
159
+ /** Remove a webhook. */
160
+ removeWebhook(id: string): Promise<any>;
161
+ /** Poll events (alternative to push webhooks). */
162
+ pollEvents(options?: {
163
+ after?: string;
164
+ types?: string[];
165
+ limit?: number;
166
+ }): Promise<any>;
167
+ private get;
168
+ private post;
169
+ private delete;
170
+ private headers;
171
+ private handleResponse;
172
+ }
173
+
174
+ export { type DepositEpochSettledPayload, type PriceUpdatedPayload, type RedeemEpochSettledPayload, TBookVaultServer, type TBookVaultServerOptions, type WebhookEvent, type WebhookEventType, WebhookVerificationError, WebhookVerifier };
package/dist/index.js ADDED
@@ -0,0 +1,194 @@
1
+ import { createHmac, timingSafeEqual } from 'crypto';
2
+
3
+ // src/webhooks.ts
4
+ var WebhookVerificationError = class extends Error {
5
+ code;
6
+ constructor(code, message) {
7
+ super(message);
8
+ this.name = "WebhookVerificationError";
9
+ this.code = code;
10
+ }
11
+ };
12
+ var DEFAULT_TOLERANCE_SECONDS = 300;
13
+ var WebhookVerifier = class {
14
+ secret;
15
+ toleranceSeconds;
16
+ constructor(secret, toleranceSeconds = DEFAULT_TOLERANCE_SECONDS) {
17
+ if (!secret) {
18
+ throw new Error("Webhook secret is required for verification");
19
+ }
20
+ this.secret = secret;
21
+ this.toleranceSeconds = toleranceSeconds;
22
+ }
23
+ /**
24
+ * Verify a webhook payload and return the parsed event.
25
+ *
26
+ * @param body - Raw request body (string or Buffer)
27
+ * @param signatureHeader - Value of the `X-TBook-Signature` header
28
+ * @returns The verified and parsed webhook event
29
+ *
30
+ * @throws {WebhookVerificationError} If verification fails
31
+ */
32
+ verify(body, signatureHeader) {
33
+ if (!signatureHeader) {
34
+ throw new WebhookVerificationError(
35
+ "MISSING_SIGNATURE",
36
+ "Missing X-TBook-Signature header"
37
+ );
38
+ }
39
+ const bodyStr = typeof body === "string" ? body : body.toString("utf-8");
40
+ const parts = signatureHeader.split(",");
41
+ const timestampStr = parts.find((p) => p.startsWith("t="))?.slice(2);
42
+ const signatureHex = parts.find((p) => p.startsWith("v1="))?.slice(3);
43
+ if (!timestampStr || !signatureHex) {
44
+ throw new WebhookVerificationError(
45
+ "INVALID_SIGNATURE_FORMAT",
46
+ "Invalid signature header format. Expected: t=timestamp,v1=hex_signature"
47
+ );
48
+ }
49
+ const timestamp = parseInt(timestampStr, 10);
50
+ if (isNaN(timestamp)) {
51
+ throw new WebhookVerificationError(
52
+ "INVALID_TIMESTAMP",
53
+ "Invalid timestamp in signature header"
54
+ );
55
+ }
56
+ const nowSeconds = Date.now() / 1e3;
57
+ const futureSkew = timestamp - nowSeconds;
58
+ if (futureSkew > this.toleranceSeconds) {
59
+ throw new WebhookVerificationError(
60
+ "TIMESTAMP_FUTURE",
61
+ `Webhook timestamp is ${Math.floor(futureSkew)}s in the future (max ${this.toleranceSeconds}s). This may indicate clock skew or a forged request.`
62
+ );
63
+ }
64
+ const age = Math.abs(nowSeconds - timestamp);
65
+ if (age > this.toleranceSeconds) {
66
+ throw new WebhookVerificationError(
67
+ "TIMESTAMP_EXPIRED",
68
+ `Webhook timestamp is ${Math.floor(age)}s old (max ${this.toleranceSeconds}s). This may indicate a replay attack or clock skew.`
69
+ );
70
+ }
71
+ const signedContent = `${timestamp}.${bodyStr}`;
72
+ const expectedHex = createHmac("sha256", this.secret).update(signedContent).digest("hex");
73
+ const expectedBuf = Buffer.from(expectedHex, "hex");
74
+ const actualBuf = Buffer.from(signatureHex, "hex");
75
+ if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) {
76
+ throw new WebhookVerificationError(
77
+ "INVALID_SIGNATURE",
78
+ "Webhook signature verification failed. The payload may have been tampered with."
79
+ );
80
+ }
81
+ try {
82
+ return JSON.parse(bodyStr);
83
+ } catch {
84
+ throw new WebhookVerificationError(
85
+ "INVALID_PAYLOAD",
86
+ "Failed to parse webhook payload as JSON"
87
+ );
88
+ }
89
+ }
90
+ };
91
+
92
+ // src/client.ts
93
+ var DEFAULT_API_BASE_URL = "https://rwa-api.tbook.com";
94
+ var DEFAULT_VAULT_ID = "rcUSDP";
95
+ var TBookVaultServer = class {
96
+ secretKey;
97
+ apiBaseUrl;
98
+ /** Webhook verification helper. */
99
+ webhooks;
100
+ constructor(options) {
101
+ if (!options.secretKey) {
102
+ throw new Error("secretKey is required for TBookVaultServer");
103
+ }
104
+ this.secretKey = options.secretKey;
105
+ this.apiBaseUrl = options.apiBaseUrl ?? DEFAULT_API_BASE_URL;
106
+ this.webhooks = new WebhookVerifier(options.webhookSecret ?? "");
107
+ }
108
+ // ── API Methods ──
109
+ /**
110
+ * Fetch vault state.
111
+ *
112
+ * @param vaultId - Vault identifier (defaults to rcUSDP)
113
+ */
114
+ async getVaultInfo(vaultId = DEFAULT_VAULT_ID) {
115
+ return this.get(`/v1/vaults/${vaultId}`);
116
+ }
117
+ /**
118
+ * Fetch a user's vault account.
119
+ *
120
+ * @param pubkey - Solana public key string
121
+ * @param vaultId - Vault identifier (defaults to rcUSDP)
122
+ */
123
+ async getUserAccount(pubkey, vaultId = DEFAULT_VAULT_ID) {
124
+ return this.get(`/v1/vaults/${vaultId}/users/${pubkey}`);
125
+ }
126
+ /** Fetch current share price and APY. */
127
+ async getSharePrice(vaultId = DEFAULT_VAULT_ID) {
128
+ return this.get(`/v1/vaults/${vaultId}/price`);
129
+ }
130
+ /** List all available vaults. */
131
+ async listVaults() {
132
+ return this.get("/v1/vaults");
133
+ }
134
+ // ── Webhook Management ──
135
+ /** Register a new webhook endpoint. */
136
+ async registerWebhook(url, events) {
137
+ return this.post("/v1/webhooks", { url, events });
138
+ }
139
+ /** List registered webhooks. */
140
+ async listWebhooks() {
141
+ return this.get("/v1/webhooks");
142
+ }
143
+ /** Remove a webhook. */
144
+ async removeWebhook(id) {
145
+ return this.delete(`/v1/webhooks/${id}`);
146
+ }
147
+ /** Poll events (alternative to push webhooks). */
148
+ async pollEvents(options) {
149
+ const params = new URLSearchParams();
150
+ if (options?.after) params.set("after", options.after);
151
+ if (options?.types) params.set("types", options.types.join(","));
152
+ if (options?.limit) params.set("limit", String(options.limit));
153
+ const qs = params.toString();
154
+ return this.get(`/v1/events${qs ? `?${qs}` : ""}`);
155
+ }
156
+ // ── HTTP Helpers ──
157
+ async get(path) {
158
+ const res = await fetch(`${this.apiBaseUrl}${path}`, {
159
+ headers: this.headers()
160
+ });
161
+ return this.handleResponse(res);
162
+ }
163
+ async post(path, body) {
164
+ const res = await fetch(`${this.apiBaseUrl}${path}`, {
165
+ method: "POST",
166
+ headers: { ...this.headers(), "Content-Type": "application/json" },
167
+ body: JSON.stringify(body)
168
+ });
169
+ return this.handleResponse(res);
170
+ }
171
+ async delete(path) {
172
+ const res = await fetch(`${this.apiBaseUrl}${path}`, {
173
+ method: "DELETE",
174
+ headers: this.headers()
175
+ });
176
+ return this.handleResponse(res);
177
+ }
178
+ headers() {
179
+ return { "x-api-key": this.secretKey };
180
+ }
181
+ async handleResponse(res) {
182
+ const data = await res.json();
183
+ if (!res.ok) {
184
+ throw new Error(
185
+ `TBook API error (${res.status}): ${data.error ?? JSON.stringify(data)}`
186
+ );
187
+ }
188
+ return data;
189
+ }
190
+ };
191
+
192
+ export { TBookVaultServer, WebhookVerificationError, WebhookVerifier };
193
+ //# sourceMappingURL=index.js.map
194
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/webhooks.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Webhook signature verification for inbound events.\n *\n * Verifies HMAC-SHA256 signatures to ensure events are genuinely\n * from the TBook API and haven't been tampered with.\n *\n * @module webhooks\n *\n * @example\n * ```typescript\n * import { TBookVaultServer } from \"@tbookdev/vault-node\";\n *\n * const tbook = new TBookVaultServer({\n * secretKey: \"tbk_secret_...\",\n * webhookSecret: \"whsec_...\",\n * });\n *\n * app.post(\"/webhook\", (req, res) => {\n * const event = tbook.webhooks.verify(\n * req.body,\n * req.headers[\"x-tbook-signature\"],\n * );\n * console.log(event.type, event.data);\n * res.json({ received: true });\n * });\n * ```\n */\n\nimport { createHmac, timingSafeEqual } from \"crypto\";\nimport type { WebhookEvent } from \"./types.js\";\n\n/** Error thrown when webhook verification fails. */\nexport class WebhookVerificationError extends Error {\n readonly code: string;\n\n constructor(code: string, message: string) {\n super(message);\n this.name = \"WebhookVerificationError\";\n this.code = code;\n }\n}\n\n/** Default tolerance for timestamp validation (5 minutes). */\nconst DEFAULT_TOLERANCE_SECONDS = 300;\n\n/**\n * Webhook verification helper.\n *\n * Create an instance with your webhook secret, then call `verify()`\n * on each incoming webhook request.\n */\nexport class WebhookVerifier {\n private readonly secret: string;\n private readonly toleranceSeconds: number;\n\n constructor(secret: string, toleranceSeconds = DEFAULT_TOLERANCE_SECONDS) {\n if (!secret) {\n throw new Error(\"Webhook secret is required for verification\");\n }\n this.secret = secret;\n this.toleranceSeconds = toleranceSeconds;\n }\n\n /**\n * Verify a webhook payload and return the parsed event.\n *\n * @param body - Raw request body (string or Buffer)\n * @param signatureHeader - Value of the `X-TBook-Signature` header\n * @returns The verified and parsed webhook event\n *\n * @throws {WebhookVerificationError} If verification fails\n */\n verify(body: string | Buffer, signatureHeader: string): WebhookEvent {\n if (!signatureHeader) {\n throw new WebhookVerificationError(\n \"MISSING_SIGNATURE\",\n \"Missing X-TBook-Signature header\",\n );\n }\n\n const bodyStr = typeof body === \"string\" ? body : body.toString(\"utf-8\");\n\n // Parse signature header: \"t=timestamp,v1=hex_signature\"\n const parts = signatureHeader.split(\",\");\n const timestampStr = parts.find((p) => p.startsWith(\"t=\"))?.slice(2);\n const signatureHex = parts.find((p) => p.startsWith(\"v1=\"))?.slice(3);\n\n if (!timestampStr || !signatureHex) {\n throw new WebhookVerificationError(\n \"INVALID_SIGNATURE_FORMAT\",\n \"Invalid signature header format. Expected: t=timestamp,v1=hex_signature\",\n );\n }\n\n const timestamp = parseInt(timestampStr, 10);\n if (isNaN(timestamp)) {\n throw new WebhookVerificationError(\n \"INVALID_TIMESTAMP\",\n \"Invalid timestamp in signature header\",\n );\n }\n\n // Reject timestamps too far in the future (> 5 minutes)\n const nowSeconds = Date.now() / 1000;\n const futureSkew = timestamp - nowSeconds;\n if (futureSkew > this.toleranceSeconds) {\n throw new WebhookVerificationError(\n \"TIMESTAMP_FUTURE\",\n `Webhook timestamp is ${Math.floor(futureSkew)}s in the future (max ${this.toleranceSeconds}s). ` +\n \"This may indicate clock skew or a forged request.\",\n );\n }\n\n // Check timestamp tolerance (prevent replay attacks)\n const age = Math.abs(nowSeconds - timestamp);\n if (age > this.toleranceSeconds) {\n throw new WebhookVerificationError(\n \"TIMESTAMP_EXPIRED\",\n `Webhook timestamp is ${Math.floor(age)}s old (max ${this.toleranceSeconds}s). ` +\n \"This may indicate a replay attack or clock skew.\",\n );\n }\n\n // Compute expected signature\n const signedContent = `${timestamp}.${bodyStr}`;\n const expectedHex = createHmac(\"sha256\", this.secret)\n .update(signedContent)\n .digest(\"hex\");\n\n // Timing-safe comparison to prevent timing attacks\n const expectedBuf = Buffer.from(expectedHex, \"hex\");\n const actualBuf = Buffer.from(signatureHex, \"hex\");\n\n if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) {\n throw new WebhookVerificationError(\n \"INVALID_SIGNATURE\",\n \"Webhook signature verification failed. The payload may have been tampered with.\",\n );\n }\n\n // Parse and return the event\n try {\n return JSON.parse(bodyStr) as WebhookEvent;\n } catch {\n throw new WebhookVerificationError(\n \"INVALID_PAYLOAD\",\n \"Failed to parse webhook payload as JSON\",\n );\n }\n }\n}\n","/**\n * Server-side TBook Vault API client.\n *\n * Provides authenticated access to the TBook API for server-side\n * use cases: reading vault state, user accounts, and managing webhooks.\n *\n * @module client\n */\n\nimport { WebhookVerifier } from \"./webhooks.js\";\nimport type { TBookVaultServerOptions } from \"./types.js\";\n\nconst DEFAULT_API_BASE_URL = \"https://rwa-api.tbook.com\";\nconst DEFAULT_VAULT_ID = \"rcUSDP\";\n\n/**\n * Server SDK client for TBook Vault Gateway.\n *\n * ```typescript\n * import { TBookVaultServer } from \"@tbookdev/vault-node\";\n *\n * const vault = new TBookVaultServer({\n * secretKey: \"tbk_secret_...\",\n * webhookSecret: \"whsec_...\",\n * });\n *\n * // Server-side reads\n * const info = await vault.getVaultInfo();\n *\n * // Webhook verification\n * const event = vault.webhooks.verify(body, signature);\n * ```\n */\nexport class TBookVaultServer {\n private readonly secretKey: string;\n private readonly apiBaseUrl: string;\n\n /** Webhook verification helper. */\n readonly webhooks: WebhookVerifier;\n\n constructor(options: TBookVaultServerOptions) {\n if (!options.secretKey) {\n throw new Error(\"secretKey is required for TBookVaultServer\");\n }\n this.secretKey = options.secretKey;\n this.apiBaseUrl = options.apiBaseUrl ?? DEFAULT_API_BASE_URL;\n\n // Initialize webhook verifier (will throw if secret is missing when used)\n this.webhooks = new WebhookVerifier(options.webhookSecret ?? \"\");\n }\n\n // ── API Methods ──\n\n /**\n * Fetch vault state.\n *\n * @param vaultId - Vault identifier (defaults to rcUSDP)\n */\n async getVaultInfo(vaultId: string = DEFAULT_VAULT_ID) {\n return this.get(`/v1/vaults/${vaultId}`);\n }\n\n /**\n * Fetch a user's vault account.\n *\n * @param pubkey - Solana public key string\n * @param vaultId - Vault identifier (defaults to rcUSDP)\n */\n async getUserAccount(pubkey: string, vaultId: string = DEFAULT_VAULT_ID) {\n return this.get(`/v1/vaults/${vaultId}/users/${pubkey}`);\n }\n\n /** Fetch current share price and APY. */\n async getSharePrice(vaultId: string = DEFAULT_VAULT_ID) {\n return this.get(`/v1/vaults/${vaultId}/price`);\n }\n\n /** List all available vaults. */\n async listVaults() {\n return this.get(\"/v1/vaults\");\n }\n\n // ── Webhook Management ──\n\n /** Register a new webhook endpoint. */\n async registerWebhook(url: string, events: string[]) {\n return this.post(\"/v1/webhooks\", { url, events });\n }\n\n /** List registered webhooks. */\n async listWebhooks() {\n return this.get(\"/v1/webhooks\");\n }\n\n /** Remove a webhook. */\n async removeWebhook(id: string) {\n return this.delete(`/v1/webhooks/${id}`);\n }\n\n /** Poll events (alternative to push webhooks). */\n async pollEvents(options?: { after?: string; types?: string[]; limit?: number }) {\n const params = new URLSearchParams();\n if (options?.after) params.set(\"after\", options.after);\n if (options?.types) params.set(\"types\", options.types.join(\",\"));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n const qs = params.toString();\n return this.get(`/v1/events${qs ? `?${qs}` : \"\"}`);\n }\n\n // ── HTTP Helpers ──\n\n private async get(path: string): Promise<any> {\n const res = await fetch(`${this.apiBaseUrl}${path}`, {\n headers: this.headers(),\n });\n return this.handleResponse(res);\n }\n\n private async post(path: string, body: any): Promise<any> {\n const res = await fetch(`${this.apiBaseUrl}${path}`, {\n method: \"POST\",\n headers: { ...this.headers(), \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return this.handleResponse(res);\n }\n\n private async delete(path: string): Promise<any> {\n const res = await fetch(`${this.apiBaseUrl}${path}`, {\n method: \"DELETE\",\n headers: this.headers(),\n });\n return this.handleResponse(res);\n }\n\n private headers(): Record<string, string> {\n return { \"x-api-key\": this.secretKey };\n }\n\n private async handleResponse(res: Response): Promise<any> {\n const data = await res.json();\n if (!res.ok) {\n throw new Error(\n `TBook API error (${res.status}): ${data.error ?? JSON.stringify(data)}`,\n );\n }\n return data;\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@tbookdev/vault-node",
3
+ "version": "0.1.0",
4
+ "description": "TBook Vault server SDK — webhook verification, server-side API client for Node.js backends",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/index.d.cts",
18
+ "default": "./dist/index.cjs"
19
+ }
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "devDependencies": {
27
+ "@types/node": "^20.14.0",
28
+ "tsup": "^8.3.0",
29
+ "typescript": "^5.7.0",
30
+ "vitest": "^2.1.0"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/tbook-dev/vault-gateway-sdk"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "dev": "tsup --watch",
42
+ "test": "vitest run",
43
+ "lint": "tsc --noEmit",
44
+ "clean": "rm -rf dist"
45
+ }
46
+ }