@tuwaio/quasar-sdk 0.1.7 → 0.1.9

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
@@ -22,6 +22,7 @@ It operates strictly on the server (Node.js, Next.js Server Actions, or Edge fun
22
22
  ## ✨ Key Features
23
23
 
24
24
  - **☁️ Cloud Sync**: Automatically persist pending and terminal transaction states to the Quasar Database for cross-device history.
25
+ - **⚡ Native Webhook Local Dev Relay**: Stream production webhooks directly to your local machine via CLI with zero tunnels (no ngrok/cloudflared required).
25
26
  - **🔐 Headless SIWX (CAIP-122) Auth Ready**: Seamlessly pairs with `@tuwaio/sdk/siwx/server` for strict cryptographic verification of user sessions before allowing database writes.
26
27
  - **⚡ Edge Ready**: Uses `ofetch` and lightweight cryptography to run seamlessly in Cloudflare Workers and Vercel Edge.
27
28
  - **📦 InMemory Sync**: Perfectly pairs with `@tuwaio/sdk/pulsar` (`createTxInMemoryStore`) to fetch history and hydrate local React states.
@@ -38,6 +39,87 @@ _Note: `ofetch` and `@tuwaio/pulsar-core` are required peer dependencies. The `@
38
39
 
39
40
  ---
40
41
 
42
+ ## ⚡ Quasar Webhook Local Dev Relay (Native CLI)
43
+
44
+ Testing Web3 webhooks locally against live cloud indexers usually requires spinning up temporary third-party tunnels (`ngrok`, `cloudflared`), pasting ephemeral URLs into dashboard forms, and restarting your workflow when tunnels expire.
45
+
46
+ The **Quasar SDK CLI** provides a zero-tunnel local development relay. When you configure a `localhost` webhook endpoint in the Quasar Dashboard, Quasar Cloud streams incoming events to your local machine via real-time Server-Sent Events (SSE).
47
+
48
+ ### 1. Zero-Config Local Development
49
+
50
+ Add your webhook signing secret from the Quasar Dashboard to `.env.local` or `.env`:
51
+
52
+ ```env
53
+ # Signing secret copied from the Quasar Dashboard webhook endpoint
54
+ QUASAR_WEBHOOK_SECRET=whsec_...
55
+
56
+ # Optional Quasar API base URL (defaults to https://api.tuwa.io)
57
+ NEXT_PUBLIC_QUASAR_BASE_URL=https://api.tuwa.io
58
+ ```
59
+
60
+ Run the relay listener in your terminal:
61
+
62
+ ```bash
63
+ npx @tuwaio/quasar-sdk listen
64
+ ```
65
+
66
+ The CLI automatically reads `QUASAR_WEBHOOK_SECRET` and starts forwarding webhook payloads to the default Cosmos Playground endpoint (`http://localhost:3000/api/webhooks/quasar`).
67
+
68
+ ### 2. Custom Forwarding & CLI Options
69
+
70
+ ```bash
71
+ # Forward to a custom port or path
72
+ npx @tuwaio/quasar-sdk listen --forward-to http://localhost:8080/api/webhooks
73
+
74
+ # Provide secret explicitly via flags
75
+ npx @tuwaio/quasar-sdk listen --secret whsec_... --forward-to http://localhost:3000/api/webhooks/quasar
76
+
77
+ # Specify custom .env file
78
+ npx @tuwaio/quasar-sdk listen --env-file .env.development
79
+ ```
80
+
81
+ | Flag | Shorthand | Description | Default |
82
+ | :------------- | :-------- | :-------------------------------------------- | :------------------------------------------ |
83
+ | `--secret` | `-s` | Webhook endpoint signing secret (`whsec_...`) | `QUASAR_WEBHOOK_SECRET` |
84
+ | `--forward-to` | `-f` | Local destination endpoint | `http://localhost:3000/api/webhooks/quasar` |
85
+ | `--api-url` | `-a` | Quasar Cloud API base URL | `https://api.tuwa.io` |
86
+ | `--env-file` | `-e` | Custom path to `.env` file | Auto-detected (`.env.local`, `.env`) |
87
+ | `--help` | `-h` | Display help instructions | — |
88
+ | `--version` | `-v` | Display CLI version | — |
89
+
90
+ ### 3. Local Webhook Route Handler (Next.js Example)
91
+
92
+ ```typescript
93
+ // app/api/webhooks/quasar/route.ts
94
+ import { NextResponse } from 'next/server';
95
+ import crypto from 'node:crypto';
96
+
97
+ export async function POST(req: Request) {
98
+ const secret = process.env.QUASAR_WEBHOOK_SECRET;
99
+ if (!secret) {
100
+ return NextResponse.json({ error: 'Server misconfigured' }, { status: 500 });
101
+ }
102
+
103
+ const rawBody = await req.text();
104
+ const signature = req.headers.get('x-quasar-signature');
105
+ const event = req.headers.get('x-quasar-event');
106
+
107
+ // Verify HMAC-SHA256 signature
108
+ const expectedSignature = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
109
+
110
+ if (signature !== expectedSignature) {
111
+ return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
112
+ }
113
+
114
+ const payload = JSON.parse(rawBody);
115
+ console.log(`[Webhook Received] ${event}:`, payload);
116
+
117
+ return NextResponse.json({ received: true });
118
+ }
119
+ ```
120
+
121
+ ---
122
+
41
123
  ## 🚀 Quick Start (Node.js / Edge)
42
124
 
43
125
  This is a basic example of how to interact with the Quasar Cloud directly from your secure backend environments (like Next.js API Routes, Server Actions, or NestJS).
package/dist/cli.cjs ADDED
@@ -0,0 +1,342 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/cli.ts
32
+ var cli_exports = {};
33
+ __export(cli_exports, {
34
+ CLI_VERSION: () => CLI_VERSION,
35
+ DEFAULT_API_URL: () => DEFAULT_API_URL,
36
+ DEFAULT_FORWARD_URL: () => DEFAULT_FORWARD_URL,
37
+ handleSseMessage: () => handleSseMessage,
38
+ loadEnv: () => loadEnv,
39
+ main: () => main,
40
+ parseArgs: () => parseArgs,
41
+ parseEnvFile: () => parseEnvFile
42
+ });
43
+ module.exports = __toCommonJS(cli_exports);
44
+ var fs = __toESM(require("fs"), 1);
45
+ var path = __toESM(require("path"), 1);
46
+ var DEFAULT_FORWARD_URL = "http://localhost:3000/api/webhooks/quasar";
47
+ var DEFAULT_API_URL = "https://api.tuwa.io";
48
+ var CLI_VERSION = "0.1.8";
49
+ function parseEnvFile(content) {
50
+ const env = {};
51
+ const lines = content.split("\n");
52
+ for (const line of lines) {
53
+ const trimmed = line.trim();
54
+ if (!trimmed || trimmed.startsWith("#")) continue;
55
+ const equalsIdx = trimmed.indexOf("=");
56
+ if (equalsIdx <= 0) continue;
57
+ const key = trimmed.slice(0, equalsIdx).trim();
58
+ let val = trimmed.slice(equalsIdx + 1).trim();
59
+ if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
60
+ val = val.slice(1, -1);
61
+ }
62
+ env[key] = val;
63
+ }
64
+ return env;
65
+ }
66
+ function loadEnv(customPath) {
67
+ const cwd = process.cwd();
68
+ if (customPath) {
69
+ const fullPath = path.isAbsolute(customPath) ? customPath : path.join(cwd, customPath);
70
+ if (fs.existsSync(fullPath)) {
71
+ return parseEnvFile(fs.readFileSync(fullPath, "utf8"));
72
+ }
73
+ console.warn(`\x1B[33m[warn]\x1B[0m Specified env file not found: ${customPath}`);
74
+ return {};
75
+ }
76
+ const candidates = [".env.local", ".env.development", ".env"];
77
+ for (const candidate of candidates) {
78
+ const filePath = path.join(cwd, candidate);
79
+ if (fs.existsSync(filePath)) {
80
+ return parseEnvFile(fs.readFileSync(filePath, "utf8"));
81
+ }
82
+ }
83
+ return {};
84
+ }
85
+ function parseArgs(args) {
86
+ const options = {};
87
+ const cleanArgs = [...args];
88
+ if (cleanArgs.length > 0 && !cleanArgs[0].startsWith("-")) {
89
+ options.command = cleanArgs.shift();
90
+ }
91
+ for (let i = 0; i < cleanArgs.length; i++) {
92
+ const arg = cleanArgs[i];
93
+ if (arg === "--help" || arg === "-h") {
94
+ options.help = true;
95
+ } else if (arg === "--version" || arg === "-v") {
96
+ options.version = true;
97
+ } else if (arg === "--secret" || arg === "-s") {
98
+ options.secret = cleanArgs[++i];
99
+ } else if (arg === "--forward-to" || arg === "-f") {
100
+ options.forwardTo = cleanArgs[++i];
101
+ } else if (arg === "--api-url" || arg === "-a") {
102
+ options.apiUrl = cleanArgs[++i];
103
+ } else if (arg === "--env-file" || arg === "-e") {
104
+ options.envFile = cleanArgs[++i];
105
+ }
106
+ }
107
+ return options;
108
+ }
109
+ function printHelp() {
110
+ console.log(`
111
+ \x1B[1m\x1B[36m\u26A1 Quasar Webhook Local Dev Relay\x1B[0m
112
+ Stream production Quasar Cloud webhooks directly to your local dev machine.
113
+ Zero tunnels, zero third-party proxies, zero friction.
114
+
115
+ \x1B[1mUSAGE\x1B[0m
116
+ $ npx @tuwaio/quasar-sdk listen [options]
117
+
118
+ \x1B[1mCOMMANDS\x1B[0m
119
+ listen Connect to Quasar Cloud SSE and forward events locally
120
+
121
+ \x1B[1mOPTIONS\x1B[0m
122
+ -s, --secret <secret> Webhook signing secret (whsec_...) [or QUASAR_WEBHOOK_SECRET]
123
+ -f, --forward-to <url> Local endpoint to forward to (default: ${DEFAULT_FORWARD_URL})
124
+ -a, --api-url <url> Quasar Cloud API base URL (default: ${DEFAULT_API_URL})
125
+ -e, --env-file <path> Custom path to .env file
126
+ -v, --version Show version number
127
+ -h, --help Show help details
128
+
129
+ \x1B[1mZERO-CONFIG SETUP\x1B[0m
130
+ Add to your local .env or .env.local:
131
+ QUASAR_WEBHOOK_SECRET=whsec_...
132
+ NEXT_PUBLIC_QUASAR_BASE_URL=https://api.tuwa.io # (optional)
133
+
134
+ Then simply run:
135
+ $ npx @tuwaio/quasar-sdk listen
136
+ `);
137
+ }
138
+ async function runListen(options) {
139
+ const { secret, forwardTo, apiUrl } = options;
140
+ const cleanApiUrl = apiUrl.replace(/\/+$/, "");
141
+ const listenUrl = `${cleanApiUrl}/v1/engine/webhooks/listen?secret=${encodeURIComponent(secret)}`;
142
+ console.log(`
143
+ \x1B[36m\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\x1B[0m
144
+ \x1B[36m\u2502\x1B[0m \x1B[1m\x1B[36m\u26A1 Quasar Webhook Local Dev Relay\x1B[0m \x1B[36m\u2502\x1B[0m
145
+ \x1B[36m\u2502\x1B[0m Forwarding to: \x1B[32m${forwardTo.padEnd(44)}\x1B[0m\x1B[36m\u2502\x1B[0m
146
+ \x1B[36m\u2502\x1B[0m Quasar Cloud: \x1B[34m${cleanApiUrl.padEnd(44)}\x1B[0m\x1B[36m\u2502\x1B[0m
147
+ \x1B[36m\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\x1B[0m
148
+ `);
149
+ let reconnectDelay = 1e3;
150
+ let isShuttingDown = false;
151
+ let activeAbortController = null;
152
+ const cleanup = () => {
153
+ isShuttingDown = true;
154
+ if (activeAbortController) {
155
+ activeAbortController.abort();
156
+ }
157
+ console.log("\n\x1B[33m[relay]\x1B[0m Disconnected. Bye!");
158
+ process.exit(0);
159
+ };
160
+ process.on("SIGINT", cleanup);
161
+ process.on("SIGTERM", cleanup);
162
+ while (!isShuttingDown) {
163
+ try {
164
+ activeAbortController = new AbortController();
165
+ console.log(`\x1B[90mConnecting to Quasar Cloud SSE stream...\x1B[0m`);
166
+ const response = await fetch(listenUrl, {
167
+ method: "GET",
168
+ headers: {
169
+ Accept: "text/event-stream",
170
+ "Cache-Control": "no-cache"
171
+ },
172
+ signal: activeAbortController.signal
173
+ });
174
+ if (!response.ok) {
175
+ if (response.status === 401) {
176
+ console.error(
177
+ `\x1B[31m\u2716 Unauthorized (401):\x1B[0m Invalid webhook signing secret. Check your QUASAR_WEBHOOK_SECRET.`
178
+ );
179
+ process.exit(1);
180
+ }
181
+ if (response.status === 404) {
182
+ console.error(
183
+ `\x1B[31m\u2716 Endpoint Not Found (404):\x1B[0m No webhook endpoint found matching this signing secret.`
184
+ );
185
+ process.exit(1);
186
+ }
187
+ const errText = await response.text();
188
+ throw new Error(`HTTP ${response.status} ${response.statusText}: ${errText}`);
189
+ }
190
+ if (!response.body) {
191
+ throw new Error("No readable stream returned by server.");
192
+ }
193
+ console.log(`\x1B[32m\u2714 Connected!\x1B[0m Ready and listening for events...`);
194
+ reconnectDelay = 1e3;
195
+ const reader = response.body.getReader();
196
+ const decoder = new TextDecoder("utf-8");
197
+ let buffer = "";
198
+ while (!isShuttingDown) {
199
+ const { done, value } = await reader.read();
200
+ if (done) break;
201
+ buffer += decoder.decode(value, { stream: true });
202
+ const lines = buffer.split("\n");
203
+ buffer = lines.pop() || "";
204
+ let currentEvent = "message";
205
+ let currentData = "";
206
+ for (const line of lines) {
207
+ const trimmed = line.trim();
208
+ if (!trimmed) {
209
+ if (currentData) {
210
+ await handleSseMessage(currentEvent, currentData, forwardTo);
211
+ currentEvent = "message";
212
+ currentData = "";
213
+ }
214
+ continue;
215
+ }
216
+ if (trimmed.startsWith("event:")) {
217
+ currentEvent = trimmed.slice(6).trim();
218
+ } else if (trimmed.startsWith("data:")) {
219
+ const dataLine = trimmed.slice(5).trim();
220
+ currentData = currentData ? `${currentData}
221
+ ${dataLine}` : dataLine;
222
+ }
223
+ }
224
+ }
225
+ } catch (err) {
226
+ if (isShuttingDown) break;
227
+ const message = err instanceof Error ? err.message : String(err);
228
+ console.warn(`\x1B[33m[warn]\x1B[0m Connection lost (${message}). Reconnecting in ${reconnectDelay}ms...`);
229
+ await new Promise((resolve) => setTimeout(resolve, reconnectDelay));
230
+ reconnectDelay = Math.min(reconnectDelay * 2, 15e3);
231
+ }
232
+ }
233
+ }
234
+ async function handleSseMessage(event, rawData, forwardTo) {
235
+ if (event === "ping" || rawData === ":keepalive" || rawData.startsWith(":")) {
236
+ return;
237
+ }
238
+ try {
239
+ const payload = JSON.parse(rawData);
240
+ if (event === "connected") {
241
+ return;
242
+ }
243
+ if (event === "payload" || event === "webhook" || event === "message") {
244
+ const dataObj = payload;
245
+ const deliveryId = dataObj.deliveryId || dataObj.id || "";
246
+ const eventType = dataObj.event || dataObj.eventType || dataObj.action || "webhook";
247
+ const forwardedData = dataObj.data !== void 0 ? dataObj.data : dataObj.payload !== void 0 ? dataObj.payload : dataObj;
248
+ const signature = dataObj.signature || "";
249
+ const startTime = Date.now();
250
+ const timeStr = (/* @__PURE__ */ new Date()).toLocaleTimeString();
251
+ try {
252
+ const res = await fetch(forwardTo, {
253
+ method: "POST",
254
+ headers: {
255
+ "Content-Type": "application/json",
256
+ "x-quasar-signature": signature,
257
+ "x-quasar-event": eventType,
258
+ "x-quasar-delivery-id": deliveryId
259
+ },
260
+ body: JSON.stringify(forwardedData)
261
+ });
262
+ const duration = Date.now() - startTime;
263
+ if (res.ok) {
264
+ console.log(
265
+ `\x1B[90m${timeStr}\x1B[0m \x1B[32m[${res.status} OK]\x1B[0m \x1B[1m${eventType}\x1B[0m \u2794 ${forwardTo} \x1B[90m(${duration}ms)\x1B[0m`
266
+ );
267
+ } else {
268
+ console.warn(
269
+ `\x1B[90m${timeStr}\x1B[0m \x1B[31m[${res.status} ${res.statusText}]\x1B[0m \x1B[1m${eventType}\x1B[0m \u2794 ${forwardTo} \x1B[90m(${duration}ms)\x1B[0m`
270
+ );
271
+ }
272
+ } catch (postErr) {
273
+ const errMsg = postErr instanceof Error ? postErr.message : String(postErr);
274
+ console.error(
275
+ `\x1B[90m${timeStr}\x1B[0m \x1B[31m[FAIL]\x1B[0m \x1B[1m${eventType}\x1B[0m \u2794 Could not reach ${forwardTo}: ${errMsg}`
276
+ );
277
+ console.error(` \x1B[33mTip: Make sure your local application is running on ${forwardTo}\x1B[0m`);
278
+ }
279
+ }
280
+ } catch {
281
+ }
282
+ }
283
+ async function main() {
284
+ const rawArgs = process.argv.slice(2);
285
+ const options = parseArgs(rawArgs);
286
+ if (options.help || rawArgs.length === 0 && !options.version) {
287
+ printHelp();
288
+ return;
289
+ }
290
+ if (options.version) {
291
+ console.log(`@tuwaio/quasar-sdk v${CLI_VERSION}`);
292
+ return;
293
+ }
294
+ if (options.command !== "listen") {
295
+ console.error(`\x1B[31m\u2716 Unknown command:\x1B[0m "${options.command}". Did you mean "listen"?`);
296
+ console.log(`Run \x1B[1mnpx @tuwaio/quasar-sdk --help\x1B[0m for available commands.`);
297
+ process.exit(1);
298
+ }
299
+ const env = loadEnv(options.envFile);
300
+ const secret = options.secret || process.env.QUASAR_WEBHOOK_SECRET || env.QUASAR_WEBHOOK_SECRET;
301
+ const forwardTo = options.forwardTo || process.env.QUASAR_WEBHOOK_FORWARD_TO || env.QUASAR_WEBHOOK_FORWARD_TO || DEFAULT_FORWARD_URL;
302
+ const apiUrl = options.apiUrl || process.env.NEXT_PUBLIC_QUASAR_BASE_URL || env.NEXT_PUBLIC_QUASAR_BASE_URL || process.env.QUASAR_BASE_URL || env.QUASAR_BASE_URL || DEFAULT_API_URL;
303
+ if (!secret) {
304
+ console.error(`
305
+ \x1B[31m\u2716 Missing Webhook Signing Secret\x1B[0m
306
+ The local relay requires your webhook endpoint signing secret (starting with whsec_).
307
+
308
+ \x1B[1mHow to fix:\x1B[0m
309
+ 1. Provide via command-line argument:
310
+ $ npx @tuwaio/quasar-sdk listen --secret whsec_...
311
+
312
+ 2. Or add to your local .env / .env.local file:
313
+ QUASAR_WEBHOOK_SECRET=whsec_...
314
+ `);
315
+ process.exit(1);
316
+ }
317
+ await runListen({
318
+ secret,
319
+ forwardTo,
320
+ apiUrl
321
+ });
322
+ }
323
+ if (typeof process !== "undefined" && process.argv && process.argv[1]) {
324
+ const isCli = process.argv[1].endsWith("cli.js") || process.argv[1].endsWith("cli.cjs") || process.argv[1].endsWith("cli.ts");
325
+ if (isCli) {
326
+ main().catch((err) => {
327
+ console.error("\x1B[31mFatal error:\x1B[0m", err);
328
+ process.exit(1);
329
+ });
330
+ }
331
+ }
332
+ // Annotate the CommonJS export names for ESM import in node:
333
+ 0 && (module.exports = {
334
+ CLI_VERSION,
335
+ DEFAULT_API_URL,
336
+ DEFAULT_FORWARD_URL,
337
+ handleSseMessage,
338
+ loadEnv,
339
+ main,
340
+ parseArgs,
341
+ parseEnvFile
342
+ });
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var siwxReact=require('@tuwaio/siwx-react'),ofetch=require('ofetch');var a="https://api.tuwa.io",c="/v1/engine/pulsar/sync",u="/v1/engine/pulsar/history";var i=class extends Error{status;originalError;constructor(r,e,t){super(r),this.name="QuasarSDKError",this.status=e,this.originalError=t;}},n=class{secretKey;internalSecret;baseUrl;timeout;constructor(r){if(!r.secretKey)throw new Error("[Quasar SDK] Missing API Key. Provide a secretKey starting with sk_live_.");this.secretKey=r.secretKey,this.internalSecret=r.internalSecret,this.baseUrl=r.baseUrl||a,this.timeout=r.timeout||1e4;}async request(r,e={}){try{return await ofetch.ofetch(r,{baseURL:this.baseUrl,timeout:this.timeout,...e,headers:{"Content-Type":"application/json","x-tuwa-secret-key":this.secretKey,...this.internalSecret?{"x-internal-secret":this.internalSecret}:{},...e.headers}})}catch(t){throw this.buildError(t)}}buildError(r){let e=r,t=e.statusCode??e.response?.status,p=(e.data??e.response?._data)?.error??e.message??"Unknown Error";return (t===401||t===403)&&console.error("\u{1F6A8} [Quasar SDK] Auth Error. Check your Secret Key and scopes."),new i(`[Quasar SDK] Request Failed (${t}): ${p}`,t,e)}};var o=class{constructor(r){this.client=r;}async syncCreate(r,e){return this.client.request(c,{method:"POST",body:{...r,appName:e}})}async getHistory(r={}){return this.client.request(u,{method:"GET",query:{page:r.page??1,limit:r.limit??10,chainId:r.chainId,status:r.status,txKey:r.txKey,appName:r.appName,walletAddress:r.walletAddress}})}};async function Q(s){if(!siwxReact.useSiwxSessionStore.getState().session)throw new Error("[QuasarSDK] No SIWX Session found. User must be signed in.");let e=s||a;try{let t=await fetch(`${e}/v1/engine/monitoring/health`,{method:"GET",cache:"no-store"});if(!t.ok)throw new Error(`[QuasarSDK] API Health check failed with status: ${t.status}`)}catch(t){throw new Error("[QuasarSDK] Quasar Cloud Engine is currently unreachable.",{cause:t})}}var l=class{client;pulsar;constructor(r){this.client=new n(r),this.pulsar=new o(this.client);}};
2
- exports.BASE_API_URL=a;exports.PULSAR_HISTORY_ENDPOINT=u;exports.PULSAR_SYNC_ENDPOINT=c;exports.PulsarModule=o;exports.Quasar=l;exports.QuasarSDKError=i;exports.preFlightTxCheck=Q;
1
+ 'use strict';var siwxReact=require('@tuwaio/siwx-react'),ofetch=require('ofetch'),pulsarCore=require('@tuwaio/pulsar-core');var o="https://api.tuwa.io",c="/v1/engine/pulsar/sync",u="/v1/engine/pulsar/history";var n=class extends Error{status;originalError;constructor(r,e,t){super(r),this.name="QuasarSDKError",this.status=e,this.originalError=t;}},i=class{secretKey;internalSecret;baseUrl;timeout;constructor(r){if(!r.secretKey)throw new Error("[Quasar SDK] Missing API Key. Provide a secretKey starting with sk_live_.");this.secretKey=r.secretKey,this.internalSecret=r.internalSecret,this.baseUrl=r.baseUrl||o,this.timeout=r.timeout||1e4;}async request(r,e={}){try{return await ofetch.ofetch(r,{baseURL:this.baseUrl,timeout:this.timeout,...e,headers:{"Content-Type":"application/json","x-tuwa-secret-key":this.secretKey,...this.internalSecret?{"x-internal-secret":this.internalSecret}:{},...e.headers}})}catch(t){throw this.buildError(t)}}buildError(r){let e=r,t=e.statusCode??e.response?.status,p=(e.data??e.response?._data)?.error??e.message??"Unknown Error";return (t===401||t===403)&&console.error("\u{1F6A8} [Quasar SDK] Auth Error. Check your Secret Key and scopes."),new n(`[Quasar SDK] Request Failed (${t}): ${p}`,t,e)}};var a=class{constructor(r){this.client=r;}async syncCreate(r,e){return this.client.request(c,{method:"POST",body:{...r,appName:e}})}async getHistory(r={}){return this.client.request(u,{method:"GET",query:{page:r.page??1,limit:r.limit??10,chainId:r.chainId,status:r.status,txKey:r.txKey,appName:r.appName,walletAddress:r.walletAddress}})}};async function A(s){if(!siwxReact.useSiwxSessionStore.getState().session)throw new Error("[QuasarSDK] No SIWX Session found. User must be signed in.");let e=s||o;try{let t=await fetch(`${e}/v1/engine/monitoring/health`,{method:"GET",cache:"no-store"});if(!t.ok)throw new Error(`[QuasarSDK] API Health check failed with status: ${t.status}`)}catch(t){throw new Error("[QuasarSDK] Quasar Cloud Engine is currently unreachable.",{cause:t})}}var l=class{client;pulsar;constructor(r){this.client=new i(r),this.pulsar=new a(this.client);}};
2
+ Object.defineProperty(exports,"TransactionStatus",{enumerable:true,get:function(){return pulsarCore.TransactionStatus}});Object.defineProperty(exports,"TransactionTracker",{enumerable:true,get:function(){return pulsarCore.TransactionTracker}});exports.BASE_API_URL=o;exports.PULSAR_HISTORY_ENDPOINT=u;exports.PULSAR_SYNC_ENDPOINT=c;exports.PulsarModule=a;exports.Quasar=l;exports.QuasarSDKError=n;exports.preFlightTxCheck=A;
package/dist/index.d.cts CHANGED
@@ -1,13 +1,12 @@
1
1
  import { FetchOptions } from 'ofetch';
2
2
  import { Transaction } from '@tuwaio/pulsar-core';
3
- export { Transaction, UpdatableTransactionFields } from '@tuwaio/pulsar-core';
3
+ export { Transaction, TransactionStatus, TransactionTracker, UpdatableTransactionFields } from '@tuwaio/pulsar-core';
4
4
 
5
5
  /**
6
6
  * @module types
7
7
  * @description Shared type definitions for the Quasar SDK.
8
8
  * Contains configuration interfaces, query parameters, and authentication structures.
9
9
  */
10
-
11
10
  /**
12
11
  * Configuration options for initializing the {@link Quasar} SDK client.
13
12
  *
package/dist/index.d.ts CHANGED
@@ -1,13 +1,12 @@
1
1
  import { FetchOptions } from 'ofetch';
2
2
  import { Transaction } from '@tuwaio/pulsar-core';
3
- export { Transaction, UpdatableTransactionFields } from '@tuwaio/pulsar-core';
3
+ export { Transaction, TransactionStatus, TransactionTracker, UpdatableTransactionFields } from '@tuwaio/pulsar-core';
4
4
 
5
5
  /**
6
6
  * @module types
7
7
  * @description Shared type definitions for the Quasar SDK.
8
8
  * Contains configuration interfaces, query parameters, and authentication structures.
9
9
  */
10
-
11
10
  /**
12
11
  * Configuration options for initializing the {@link Quasar} SDK client.
13
12
  *
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {useSiwxSessionStore}from'@tuwaio/siwx-react';import {ofetch}from'ofetch';var a="https://api.tuwa.io",c="/v1/engine/pulsar/sync",u="/v1/engine/pulsar/history";var i=class extends Error{status;originalError;constructor(r,e,t){super(r),this.name="QuasarSDKError",this.status=e,this.originalError=t;}},n=class{secretKey;internalSecret;baseUrl;timeout;constructor(r){if(!r.secretKey)throw new Error("[Quasar SDK] Missing API Key. Provide a secretKey starting with sk_live_.");this.secretKey=r.secretKey,this.internalSecret=r.internalSecret,this.baseUrl=r.baseUrl||a,this.timeout=r.timeout||1e4;}async request(r,e={}){try{return await ofetch(r,{baseURL:this.baseUrl,timeout:this.timeout,...e,headers:{"Content-Type":"application/json","x-tuwa-secret-key":this.secretKey,...this.internalSecret?{"x-internal-secret":this.internalSecret}:{},...e.headers}})}catch(t){throw this.buildError(t)}}buildError(r){let e=r,t=e.statusCode??e.response?.status,p=(e.data??e.response?._data)?.error??e.message??"Unknown Error";return (t===401||t===403)&&console.error("\u{1F6A8} [Quasar SDK] Auth Error. Check your Secret Key and scopes."),new i(`[Quasar SDK] Request Failed (${t}): ${p}`,t,e)}};var o=class{constructor(r){this.client=r;}async syncCreate(r,e){return this.client.request(c,{method:"POST",body:{...r,appName:e}})}async getHistory(r={}){return this.client.request(u,{method:"GET",query:{page:r.page??1,limit:r.limit??10,chainId:r.chainId,status:r.status,txKey:r.txKey,appName:r.appName,walletAddress:r.walletAddress}})}};async function Q(s){if(!useSiwxSessionStore.getState().session)throw new Error("[QuasarSDK] No SIWX Session found. User must be signed in.");let e=s||a;try{let t=await fetch(`${e}/v1/engine/monitoring/health`,{method:"GET",cache:"no-store"});if(!t.ok)throw new Error(`[QuasarSDK] API Health check failed with status: ${t.status}`)}catch(t){throw new Error("[QuasarSDK] Quasar Cloud Engine is currently unreachable.",{cause:t})}}var l=class{client;pulsar;constructor(r){this.client=new n(r),this.pulsar=new o(this.client);}};
2
- export{a as BASE_API_URL,u as PULSAR_HISTORY_ENDPOINT,c as PULSAR_SYNC_ENDPOINT,o as PulsarModule,l as Quasar,i as QuasarSDKError,Q as preFlightTxCheck};
1
+ import {useSiwxSessionStore}from'@tuwaio/siwx-react';import {ofetch}from'ofetch';export{TransactionStatus,TransactionTracker}from'@tuwaio/pulsar-core';var o="https://api.tuwa.io",c="/v1/engine/pulsar/sync",u="/v1/engine/pulsar/history";var n=class extends Error{status;originalError;constructor(r,e,t){super(r),this.name="QuasarSDKError",this.status=e,this.originalError=t;}},i=class{secretKey;internalSecret;baseUrl;timeout;constructor(r){if(!r.secretKey)throw new Error("[Quasar SDK] Missing API Key. Provide a secretKey starting with sk_live_.");this.secretKey=r.secretKey,this.internalSecret=r.internalSecret,this.baseUrl=r.baseUrl||o,this.timeout=r.timeout||1e4;}async request(r,e={}){try{return await ofetch(r,{baseURL:this.baseUrl,timeout:this.timeout,...e,headers:{"Content-Type":"application/json","x-tuwa-secret-key":this.secretKey,...this.internalSecret?{"x-internal-secret":this.internalSecret}:{},...e.headers}})}catch(t){throw this.buildError(t)}}buildError(r){let e=r,t=e.statusCode??e.response?.status,p=(e.data??e.response?._data)?.error??e.message??"Unknown Error";return (t===401||t===403)&&console.error("\u{1F6A8} [Quasar SDK] Auth Error. Check your Secret Key and scopes."),new n(`[Quasar SDK] Request Failed (${t}): ${p}`,t,e)}};var a=class{constructor(r){this.client=r;}async syncCreate(r,e){return this.client.request(c,{method:"POST",body:{...r,appName:e}})}async getHistory(r={}){return this.client.request(u,{method:"GET",query:{page:r.page??1,limit:r.limit??10,chainId:r.chainId,status:r.status,txKey:r.txKey,appName:r.appName,walletAddress:r.walletAddress}})}};async function A(s){if(!useSiwxSessionStore.getState().session)throw new Error("[QuasarSDK] No SIWX Session found. User must be signed in.");let e=s||o;try{let t=await fetch(`${e}/v1/engine/monitoring/health`,{method:"GET",cache:"no-store"});if(!t.ok)throw new Error(`[QuasarSDK] API Health check failed with status: ${t.status}`)}catch(t){throw new Error("[QuasarSDK] Quasar Cloud Engine is currently unreachable.",{cause:t})}}var l=class{client;pulsar;constructor(r){this.client=new i(r),this.pulsar=new a(this.client);}};
2
+ export{o as BASE_API_URL,u as PULSAR_HISTORY_ENDPOINT,c as PULSAR_SYNC_ENDPOINT,a as PulsarModule,l as Quasar,n as QuasarSDKError,A as preFlightTxCheck};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuwaio/quasar-sdk",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
@@ -23,6 +23,9 @@
23
23
  "dist",
24
24
  "socket.json"
25
25
  ],
26
+ "bin": {
27
+ "quasar-sdk": "./dist/cli.cjs"
28
+ },
26
29
  "keywords": [
27
30
  "tuwa",
28
31
  "web3",
@@ -31,7 +34,7 @@
31
34
  "solana",
32
35
  "wagmi",
33
36
  "viem",
34
- "gill",
37
+ "@solana/kit",
35
38
  "wallet-standard",
36
39
  "wallet",
37
40
  "wallet-connect",
@@ -80,11 +83,11 @@
80
83
  }
81
84
  ],
82
85
  "peerDependencies": {
83
- "@tuwaio/pulsar-core": "^0.6.11",
86
+ "@tuwaio/pulsar-core": ">=0.7",
84
87
  "ofetch": "^1.5.1",
85
- "@tuwaio/siwx-react": "^0.2.3",
86
- "@tuwaio/siwx-core": "^0.2.2",
87
- "@tuwaio/siwx-server": "^0.2.2"
88
+ "@tuwaio/siwx-react": ">=0.3",
89
+ "@tuwaio/siwx-core": ">=0.3",
90
+ "@tuwaio/siwx-server": ">=0.3"
88
91
  },
89
92
  "peerDependenciesMeta": {
90
93
  "@tuwaio/pulsar-core": {
@@ -104,17 +107,17 @@
104
107
  }
105
108
  },
106
109
  "devDependencies": {
107
- "@tuwaio/pulsar-core": "^0.6.12",
110
+ "@tuwaio/pulsar-core": "^0.7.0",
108
111
  "ofetch": "^1.5.1",
109
112
  "tsup": "^8.5.1",
110
113
  "typescript": "6.0.3",
111
- "@tuwaio/siwx-react": "^0.2.3",
112
- "@tuwaio/siwx-core": "^0.2.2",
113
- "@tuwaio/siwx-server": "^0.2.2"
114
+ "@tuwaio/siwx-react": "^0.3.0",
115
+ "@tuwaio/siwx-core": "^0.3.0",
116
+ "@tuwaio/siwx-server": "^0.3.0"
114
117
  },
115
118
  "scripts": {
116
119
  "start": "tsup src/index.ts --watch",
117
120
  "build": "tsup",
118
- "test": "node --import tsx --test src/__tests__/*.test.ts"
121
+ "test": "vitest run"
119
122
  }
120
123
  }