@takeal/cusfront-sdk 0.1.0 → 0.2.8
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/CHANGELOG.md +28 -2
- package/README.md +29 -12
- package/dist/{http-BkZZZI8K.d.cts → http-BkCfOCR0.d.cts} +4 -1
- package/dist/{http-BkZZZI8K.d.ts → http-BkCfOCR0.d.ts} +4 -1
- package/dist/index.cjs +150 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -3
- package/dist/index.d.ts +16 -3
- package/dist/index.js +150 -10
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.cts +4 -1
- package/dist/react/index.d.ts +4 -1
- package/dist/resources/auth.cjs +37 -4
- package/dist/resources/auth.cjs.map +1 -1
- package/dist/resources/auth.d.cts +45 -6
- package/dist/resources/auth.d.ts +45 -6
- package/dist/resources/auth.js +37 -4
- package/dist/resources/auth.js.map +1 -1
- package/dist/resources/balance.cjs +4 -3
- package/dist/resources/balance.cjs.map +1 -1
- package/dist/resources/balance.d.cts +8 -9
- package/dist/resources/balance.d.ts +8 -9
- package/dist/resources/balance.js +4 -3
- package/dist/resources/balance.js.map +1 -1
- package/dist/resources/blog.d.cts +1 -1
- package/dist/resources/blog.d.ts +1 -1
- package/dist/resources/branding.cjs.map +1 -1
- package/dist/resources/branding.d.cts +8 -2
- package/dist/resources/branding.d.ts +8 -2
- package/dist/resources/branding.js.map +1 -1
- package/dist/resources/cards.d.cts +1 -1
- package/dist/resources/cards.d.ts +1 -1
- package/dist/resources/deposits.d.cts +1 -1
- package/dist/resources/deposits.d.ts +1 -1
- package/dist/resources/push.cjs +61 -0
- package/dist/resources/push.cjs.map +1 -0
- package/dist/resources/push.d.cts +79 -0
- package/dist/resources/push.d.ts +79 -0
- package/dist/resources/push.js +58 -0
- package/dist/resources/push.js.map +1 -0
- package/dist/resources/sessions.cjs +26 -0
- package/dist/resources/sessions.cjs.map +1 -0
- package/dist/resources/sessions.d.cts +43 -0
- package/dist/resources/sessions.d.ts +43 -0
- package/dist/resources/sessions.js +24 -0
- package/dist/resources/sessions.js.map +1 -0
- package/dist/resources/subscriptions.d.cts +1 -1
- package/dist/resources/subscriptions.d.ts +1 -1
- package/dist/resources/wallet.cjs +24 -0
- package/dist/resources/wallet.cjs.map +1 -0
- package/dist/resources/wallet.d.cts +39 -0
- package/dist/resources/wallet.d.ts +39 -0
- package/dist/resources/wallet.js +22 -0
- package/dist/resources/wallet.js.map +1 -0
- package/dist/telegram.cjs +150 -10
- package/dist/telegram.cjs.map +1 -1
- package/dist/telegram.d.cts +4 -1
- package/dist/telegram.d.ts +4 -1
- package/dist/telegram.js +150 -10
- package/dist/telegram.js.map +1 -1
- package/package.json +22 -3
package/dist/telegram.cjs
CHANGED
|
@@ -21,6 +21,15 @@ var NetworkError = class extends Error {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
// src/http.ts
|
|
24
|
+
var API_VERSION = "/v1";
|
|
25
|
+
var UNVERSIONED = /* @__PURE__ */ new Set(["/health", "/ready", "/branding", "/favicon.ico"]);
|
|
26
|
+
function versionedPath(path) {
|
|
27
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
28
|
+
const bare = p.split("?")[0];
|
|
29
|
+
if (UNVERSIONED.has(bare)) return p;
|
|
30
|
+
if (bare === API_VERSION || bare.startsWith(`${API_VERSION}/`)) return p;
|
|
31
|
+
return `${API_VERSION}${p}`;
|
|
32
|
+
}
|
|
24
33
|
var HttpClient = class {
|
|
25
34
|
constructor(baseUrl, tokens, fetchImpl) {
|
|
26
35
|
this.baseUrl = baseUrl;
|
|
@@ -77,8 +86,7 @@ var HttpClient = class {
|
|
|
77
86
|
absolute(path) {
|
|
78
87
|
if (path.startsWith("http://") || path.startsWith("https://")) return path;
|
|
79
88
|
const base = this.baseUrl.replace(/\/+$/, "");
|
|
80
|
-
|
|
81
|
-
return `${base}${tail}`;
|
|
89
|
+
return `${base}${versionedPath(path)}`;
|
|
82
90
|
}
|
|
83
91
|
};
|
|
84
92
|
async function parseResponse(resp) {
|
|
@@ -143,6 +151,40 @@ var AuthResource = class {
|
|
|
143
151
|
await Promise.resolve(this.tokens.set(resp.access_token));
|
|
144
152
|
return resp;
|
|
145
153
|
}
|
|
154
|
+
/** Create an end-user account and sign it in. The JWT is stored.
|
|
155
|
+
* `wallet_currency` must be one the deployment offers; omit it to take
|
|
156
|
+
* the deployment default (it can be switched later via `client.wallet`
|
|
157
|
+
* while the wallet is empty).
|
|
158
|
+
* Errors: 400 `validation` / `currency_not_allowed`, 409 email taken. */
|
|
159
|
+
async register(input) {
|
|
160
|
+
const resp = await this.http.post("/auth/register", {
|
|
161
|
+
body: input,
|
|
162
|
+
skipAuth: true
|
|
163
|
+
});
|
|
164
|
+
await Promise.resolve(this.tokens.set(resp.access_token));
|
|
165
|
+
return resp;
|
|
166
|
+
}
|
|
167
|
+
/** Finish a `totp_setup_required` login: send the first code from the
|
|
168
|
+
* authenticator app. The JWT is stored. The response carries ten
|
|
169
|
+
* one-time `backup_codes` that are never returned again, so show them to
|
|
170
|
+
* the user right away and don't keep them on the device. */
|
|
171
|
+
async completeTotpSetup(input) {
|
|
172
|
+
const resp = await this.http.post("/auth/login/totp-setup", {
|
|
173
|
+
body: input,
|
|
174
|
+
skipAuth: true
|
|
175
|
+
});
|
|
176
|
+
await Promise.resolve(this.tokens.set(resp.access_token));
|
|
177
|
+
return resp;
|
|
178
|
+
}
|
|
179
|
+
/** Change the signed-in user's password. Every other session of the
|
|
180
|
+
* account is signed out; this one stays valid.
|
|
181
|
+
* Errors: 400 when the new password fails the policy, 401 when the
|
|
182
|
+
* current one is wrong. */
|
|
183
|
+
async changePassword(input) {
|
|
184
|
+
return this.http.post("/auth/password", {
|
|
185
|
+
body: input
|
|
186
|
+
});
|
|
187
|
+
}
|
|
146
188
|
/** Swap the 2FA method mid-flow. Resolves to `otp_sent` for
|
|
147
189
|
* telegram/email; for TOTP it short-circuits back to the challenge. */
|
|
148
190
|
async switchMethod(input) {
|
|
@@ -179,10 +221,9 @@ var AuthResource = class {
|
|
|
179
221
|
async me() {
|
|
180
222
|
return this.http.get("/auth/me");
|
|
181
223
|
}
|
|
182
|
-
/** Local sign-out.
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* with a future session table. */
|
|
224
|
+
/** Local sign-out: forgets the stored JWT. To end the session on the
|
|
225
|
+
* server as well, revoke it first with `client.sessions.revoke(jti)`
|
|
226
|
+
* (the current one is marked `current: true` in `client.sessions.list()`). */
|
|
186
227
|
async signOut() {
|
|
187
228
|
await Promise.resolve(this.tokens.clear());
|
|
188
229
|
}
|
|
@@ -327,11 +368,12 @@ var BalanceResource = class {
|
|
|
327
368
|
this.http = http;
|
|
328
369
|
}
|
|
329
370
|
/**
|
|
330
|
-
* Fetch the user's wallet balance
|
|
331
|
-
*
|
|
332
|
-
*
|
|
371
|
+
* Fetch the user's wallet balance. Omit `currency` for the wallet's own
|
|
372
|
+
* currency; pass an ISO 4217 code (e.g. `"USD"`) to read another one —
|
|
373
|
+
* the ledger holds a separate balance per currency.
|
|
333
374
|
*/
|
|
334
375
|
async get(currency) {
|
|
376
|
+
if (!currency) return this.http.get("/me/balance");
|
|
335
377
|
const q = new URLSearchParams({ currency }).toString();
|
|
336
378
|
return this.http.get(`/me/balance?${q}`);
|
|
337
379
|
}
|
|
@@ -348,6 +390,25 @@ var BrandingResource = class {
|
|
|
348
390
|
}
|
|
349
391
|
};
|
|
350
392
|
|
|
393
|
+
// src/resources/wallet.ts
|
|
394
|
+
var WalletResource = class {
|
|
395
|
+
constructor(http) {
|
|
396
|
+
this.http = http;
|
|
397
|
+
}
|
|
398
|
+
/** Current wallet currency + the currencies the user may switch to. */
|
|
399
|
+
async get(opts = {}) {
|
|
400
|
+
return this.http.get("/me/wallet", { signal: opts.signal });
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Switch the wallet currency. Fails with `409 wallet_not_empty` while any
|
|
404
|
+
* balance is non-zero, and `400 currency_not_allowed` for a currency the
|
|
405
|
+
* deployment does not offer.
|
|
406
|
+
*/
|
|
407
|
+
async set(currency, opts = {}) {
|
|
408
|
+
return this.http.put("/me/wallet", { body: { currency }, signal: opts.signal });
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
|
|
351
412
|
// src/resources/blog.ts
|
|
352
413
|
var BlogResource = class {
|
|
353
414
|
constructor(http) {
|
|
@@ -401,6 +462,82 @@ var SubscriptionsResource = class {
|
|
|
401
462
|
}
|
|
402
463
|
};
|
|
403
464
|
|
|
465
|
+
// src/resources/sessions.ts
|
|
466
|
+
var SessionsResource = class {
|
|
467
|
+
constructor(http) {
|
|
468
|
+
this.http = http;
|
|
469
|
+
}
|
|
470
|
+
/** All live sessions of the account, this one included. */
|
|
471
|
+
async list() {
|
|
472
|
+
return this.http.get("/me/sessions");
|
|
473
|
+
}
|
|
474
|
+
/** Sign out one session. Works on the current one too; the stored JWT
|
|
475
|
+
* stops working, so follow with `client.auth.signOut()`.
|
|
476
|
+
* 404 when the session is unknown or already signed out. */
|
|
477
|
+
async revoke(jti) {
|
|
478
|
+
await this.http.delete(`/me/sessions/${encodeURIComponent(jti)}`);
|
|
479
|
+
}
|
|
480
|
+
/** Sign out every session except this one. */
|
|
481
|
+
async revokeOthers() {
|
|
482
|
+
return this.http.post("/me/sessions/terminate-others");
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
// src/resources/push.ts
|
|
487
|
+
var PushResource = class {
|
|
488
|
+
constructor(http) {
|
|
489
|
+
this.http = http;
|
|
490
|
+
}
|
|
491
|
+
/** Whether the user is subscribed, plus the VAPID key to subscribe with. */
|
|
492
|
+
async status() {
|
|
493
|
+
return this.http.get("/me/push-subscription");
|
|
494
|
+
}
|
|
495
|
+
/** Store a subscription you created yourself.
|
|
496
|
+
* 409 `push_disabled` when the deployment has no VAPID keys. */
|
|
497
|
+
async save(input) {
|
|
498
|
+
return this.http.put("/me/push-subscription", { body: input });
|
|
499
|
+
}
|
|
500
|
+
/** Delete the stored subscription. Safe when nothing is stored. */
|
|
501
|
+
async remove() {
|
|
502
|
+
await this.http.delete("/me/push-subscription");
|
|
503
|
+
}
|
|
504
|
+
/** Subscribe this browser and store the subscription. Ask for
|
|
505
|
+
* notification permission before calling. Throws when push isn't set up
|
|
506
|
+
* on the deployment. */
|
|
507
|
+
async enable(registration) {
|
|
508
|
+
const { vapid_public_key } = await this.status();
|
|
509
|
+
if (!vapid_public_key) {
|
|
510
|
+
throw new Error("@takeal/cusfront-sdk: push notifications are not enabled on this deployment");
|
|
511
|
+
}
|
|
512
|
+
const sub = await registration.pushManager.subscribe({
|
|
513
|
+
userVisibleOnly: true,
|
|
514
|
+
applicationServerKey: base64UrlToBytes(vapid_public_key)
|
|
515
|
+
});
|
|
516
|
+
const json = sub.toJSON();
|
|
517
|
+
if (!json.endpoint || !json.keys?.p256dh || !json.keys.auth) {
|
|
518
|
+
throw new Error("@takeal/cusfront-sdk: the browser returned an incomplete push subscription");
|
|
519
|
+
}
|
|
520
|
+
return this.save({
|
|
521
|
+
endpoint: json.endpoint,
|
|
522
|
+
keys: { p256dh: json.keys.p256dh, auth: json.keys.auth }
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
/** Unsubscribe this browser and delete the stored subscription. */
|
|
526
|
+
async disable(registration) {
|
|
527
|
+
const sub = await registration.pushManager.getSubscription();
|
|
528
|
+
if (sub) await sub.unsubscribe();
|
|
529
|
+
await this.remove();
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
function base64UrlToBytes(input) {
|
|
533
|
+
const b64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
534
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
535
|
+
const bin = atob(padded);
|
|
536
|
+
const out = new Uint8Array(bin.length);
|
|
537
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
538
|
+
return out;
|
|
539
|
+
}
|
|
540
|
+
|
|
404
541
|
// src/token-store.ts
|
|
405
542
|
function defaultBrowserStore(key = "takeal_jwt") {
|
|
406
543
|
const fallback = inMemoryStore();
|
|
@@ -449,9 +586,12 @@ function createClient(opts) {
|
|
|
449
586
|
deposits: new DepositsResource(http),
|
|
450
587
|
cards: new CardsResource(http),
|
|
451
588
|
balance: new BalanceResource(http),
|
|
589
|
+
wallet: new WalletResource(http),
|
|
452
590
|
branding: new BrandingResource(http),
|
|
453
591
|
blog: new BlogResource(http),
|
|
454
|
-
subscriptions: new SubscriptionsResource(http)
|
|
592
|
+
subscriptions: new SubscriptionsResource(http),
|
|
593
|
+
sessions: new SessionsResource(http),
|
|
594
|
+
push: new PushResource(http)
|
|
455
595
|
};
|
|
456
596
|
}
|
|
457
597
|
function pickDefaultStore() {
|
package/dist/telegram.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/error.ts","../src/http.ts","../src/resources/auth.ts","../src/resources/deposits.ts","../src/resources/cards.ts","../src/resources/balance.ts","../src/resources/branding.ts","../src/resources/blog.ts","../src/resources/subscriptions.ts","../src/token-store.ts","../src/index.ts","../src/telegram.ts"],"names":["ls"],"mappings":"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","file":"telegram.cjs","sourcesContent":["/**\n * Errors surfaced by the SDK. All HTTP failures map onto `ApiError`;\n * network-level / abort / serialisation failures get the generic\n * `NetworkError`. Consumers catch on the discriminator field\n * (`isApiError` / `isNetworkError`) rather than `instanceof` — works\n * across bundler boundaries where multiple copies of the class can\n * coexist.\n */\nexport class ApiError extends Error {\n readonly isApiError = true as const;\n\n constructor(\n /** HTTP status code returned by the Takeal API. */\n public readonly status: number,\n /** Stable machine-readable code (e.g. `\"insufficient_funds\"`,\n * `\"permission_required\"`, `\"validation\"`). Same enum the\n * TypeScript types pin via openapi-typescript. */\n public readonly code: string,\n /** Human-readable message. English; the consumer maps to its\n * own i18n layer before showing to end-users. */\n message: string,\n /** Full parsed response body when available. Carries field-level\n * validation details for `code = \"validation\"`. */\n public readonly body?: unknown,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport class NetworkError extends Error {\n readonly isNetworkError = true as const;\n\n constructor(message: string, public readonly cause?: unknown) {\n super(message);\n this.name = \"NetworkError\";\n }\n}\n\n/** Type guard — preferred over `instanceof` (bundler-safe). */\nexport function isApiError(e: unknown): e is ApiError {\n return (\n typeof e === \"object\" && e !== null && (e as { isApiError?: boolean }).isApiError === true\n );\n}\n\nexport function isNetworkError(e: unknown): e is NetworkError {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as { isNetworkError?: boolean }).isNetworkError === true\n );\n}\n","import { ApiError, NetworkError } from \"./error.js\";\nimport type { TokenStore } from \"./token-store.js\";\n\n/**\n * Internal HTTP client. One per SDK instance; injected into each\n * resource. Responsibilities:\n *\n * - Construct absolute URLs from `baseUrl` + path.\n * - Set `Authorization: Bearer <jwt>` from the `TokenStore`.\n * - Set `Content-Type: application/json` on bodies.\n * - Parse JSON responses + map non-2xx to `ApiError`.\n * - Forward `Idempotency-Key` when the caller passes one.\n * - Surface network failures (DNS, abort, broken pipe) as\n * `NetworkError`.\n *\n * Auto-refresh + retry policies are deliberately NOT in here — they\n * belong to the resource layer (auth.refresh) which has the right\n * context for \"is this refreshable\" decisions.\n */\n\nexport type FetchLike = typeof fetch;\n\nexport interface HttpOptions {\n /** Request body. Will be JSON-serialised if not already a\n * string / FormData / Blob. */\n body?: unknown;\n /** Idempotency key forwarded as the `Idempotency-Key` header.\n * Required by the Takeal API on most write endpoints. */\n idempotencyKey?: string;\n /** Extra headers merged after the SDK's defaults — caller wins. */\n headers?: Record<string, string>;\n /** Bypass the token store for one call (login, refresh). */\n skipAuth?: boolean;\n /** AbortSignal forwarded to fetch. */\n signal?: AbortSignal;\n}\n\nexport class HttpClient {\n constructor(\n private readonly baseUrl: string,\n private readonly tokens: TokenStore,\n private readonly fetchImpl: FetchLike,\n ) {\n if (!baseUrl) throw new Error(\"HttpClient: baseUrl is required\");\n }\n\n async get<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"GET\", path, opts);\n }\n\n async post<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"POST\", path, opts);\n }\n\n async put<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"PUT\", path, opts);\n }\n\n async patch<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"PATCH\", path, opts);\n }\n\n async delete<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"DELETE\", path, opts);\n }\n\n private async request<T>(method: string, path: string, opts: HttpOptions): Promise<T> {\n const url = this.absolute(path);\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n };\n if (opts.body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n if (opts.idempotencyKey) headers[\"Idempotency-Key\"] = opts.idempotencyKey;\n if (!opts.skipAuth) {\n const token = await Promise.resolve(this.tokens.get());\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n }\n Object.assign(headers, opts.headers ?? {});\n\n const init: RequestInit = {\n method,\n headers,\n ...(opts.signal ? { signal: opts.signal } : {}),\n };\n if (opts.body !== undefined) {\n init.body =\n typeof opts.body === \"string\" ? opts.body : JSON.stringify(opts.body);\n }\n\n let resp: Response;\n try {\n resp = await this.fetchImpl(url, init);\n } catch (e) {\n // DNS failure, connection refused, abort — anything before the\n // server returns a status. Map to NetworkError for the consumer.\n throw new NetworkError(\n e instanceof Error ? e.message : \"network error\",\n e,\n );\n }\n\n return parseResponse<T>(resp);\n }\n\n private absolute(path: string): string {\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) return path;\n const base = this.baseUrl.replace(/\\/+$/, \"\");\n const tail = path.startsWith(\"/\") ? path : `/${path}`;\n return `${base}${tail}`;\n }\n}\n\nasync function parseResponse<T>(resp: Response): Promise<T> {\n // Read body once — the Takeal API either returns JSON or an empty body\n // (204 No Content on some DELETEs). Empty body → undefined cast.\n const text = await resp.text();\n let body: unknown;\n if (text.length === 0) {\n body = undefined;\n } else {\n try {\n body = JSON.parse(text);\n } catch {\n // Non-JSON response. On 2xx that's unexpected but not fatal —\n // hand back the raw text under a synthetic field. On error\n // status, fold into the ApiError body.\n body = { raw: text };\n }\n }\n\n if (!resp.ok) {\n const errBody = (body ?? {}) as { code?: string; message?: string };\n throw new ApiError(\n resp.status,\n errBody.code ?? `http_${resp.status}`,\n errBody.message ?? resp.statusText ?? \"request failed\",\n body,\n );\n }\n return body as T;\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { TokenStore } from \"../token-store.js\";\n\n/**\n * Auth resource — `client.auth.*`.\n *\n * Covers the end-user-facing staged auth flow: password login\n * with optional TOTP/OTP step-up. The shape mirrors the responses\n * the Takeal API returns from `/auth/login`, `/auth/login/totp`,\n * `/auth/login/otp/verify`, `/auth/login/2fa/switch`, and `/auth/me`.\n *\n * The login methods stash the JWT in the configured `TokenStore` on\n * success so subsequent `client.*` calls authenticate automatically.\n * Step-up responses (TotpRequired / OtpSent) carry their own short-\n * lived challenge token which the caller passes to the next method\n * — those tokens DO NOT go through the TokenStore (they're not the\n * end-state JWT).\n */\n\nexport interface User {\n id: string;\n email: string;\n role: string;\n is_active: boolean;\n /** True for users auto-provisioned via the Telegram Mini App who still hold\n * a synthetic placeholder email. The client should prompt for a real email\n * and attach it via `auth.linkEmail` — this flips the flag to false. */\n email_pending?: boolean;\n created_at: string;\n updated_at: string;\n}\n\nexport interface LoginInput {\n email: string;\n password: string;\n}\n\n/** Discriminated union — `stage` is the discriminator. */\nexport type LoginResponse = JwtIssued | TotpRequired | TotpSetupRequired;\n\nexport interface JwtIssued {\n stage: \"jwt\";\n access_token: string;\n expires_at: string;\n user: User;\n /** True iff the user's role grants `system.view_hub`.\n * Cusfront ignores this; the operator console uses it to gate `/dashboard`. */\n hub_access?: boolean;\n}\n\nexport interface TotpRequired {\n stage: \"totp_required\";\n challenge_token: string;\n expires_at: string;\n /** Alternate second factors. Pick one with `/2fa/switch`. */\n available_methods: AvailableMethod[];\n}\n\nexport interface TotpSetupRequired {\n stage: \"totp_setup_required\";\n challenge_token: string;\n expires_at: string;\n /** OTPAuth URI rendered as a QR by the consumer. */\n otpauth_url: string;\n /** Same secret base32-encoded — for manual entry alongside QR. */\n secret_base32: string;\n}\n\nexport interface AvailableMethod {\n kind: \"totp\" | \"telegram_otp\" | \"email_otp\";\n /** Short user-facing hint, e.g. `\"Telegram (@user)\"` or `\"e****@example.com\"`. */\n hint?: string;\n}\n\nexport interface TotpVerifyInput {\n challenge_token: string;\n /** 6-digit TOTP code OR `XXXX-XXXX` backup code. */\n code: string;\n}\n\nexport interface OtpVerifyInput {\n challenge_token: string;\n /** 6-digit one-time code delivered via the selected channel. */\n code: string;\n}\n\nexport interface SwitchMethodInput {\n challenge_token: string;\n method: AvailableMethod[\"kind\"];\n}\n\nexport interface OtpSentResponse {\n stage: \"otp_sent\";\n challenge_token: string;\n expires_at: string;\n method: AvailableMethod[\"kind\"];\n hint?: string;\n available_methods: AvailableMethod[];\n}\n\nexport class AuthResource {\n constructor(\n private readonly http: HttpClient,\n private readonly tokens: TokenStore,\n ) {}\n\n /** Password-auth entry. May resolve to a JWT, or to a step-up\n * challenge that needs `verifyTotp` / `verifyOtp` next. */\n async login(input: LoginInput): Promise<LoginResponse> {\n const resp = await this.http.post<LoginResponse>(\"/auth/login\", {\n body: input,\n skipAuth: true,\n });\n if (resp.stage === \"jwt\") {\n await Promise.resolve(this.tokens.set(resp.access_token));\n }\n return resp;\n }\n\n /** Verify a TOTP code (or XXXX-XXXX backup code) against a\n * `totp_required` challenge. On success the JWT is stored. */\n async verifyTotp(input: TotpVerifyInput): Promise<JwtIssued> {\n const resp = await this.http.post<JwtIssued>(\"/auth/login/totp\", {\n body: input,\n skipAuth: true,\n });\n await Promise.resolve(this.tokens.set(resp.access_token));\n return resp;\n }\n\n /** Verify a 6-digit OTP code (Telegram / email) against an\n * `otp_sent` challenge. */\n async verifyOtp(input: OtpVerifyInput): Promise<JwtIssued> {\n const resp = await this.http.post<JwtIssued>(\"/auth/login/otp/verify\", {\n body: input,\n skipAuth: true,\n });\n await Promise.resolve(this.tokens.set(resp.access_token));\n return resp;\n }\n\n /** Swap the 2FA method mid-flow. Resolves to `otp_sent` for\n * telegram/email; for TOTP it short-circuits back to the challenge. */\n async switchMethod(input: SwitchMethodInput): Promise<OtpSentResponse> {\n return this.http.post<OtpSentResponse>(\"/auth/login/2fa/switch\", {\n body: input,\n skipAuth: true,\n });\n }\n\n /** Exchange a signed Telegram Mini App `initData` payload for a session\n * JWT. The server validates the initData HMAC against the deployment's bot\n * token, then find-or-creates the end-user. First-time Telegram users are\n * auto-provisioned with `user.email_pending === true` — prompt them for a\n * real email and call {@link linkEmail}. Stores the JWT on success.\n *\n * Most consumers use the higher-level `fromInitData` / `fromTelegramWebApp`\n * helpers in `@takeal/cusfront-sdk/telegram`; reach for this directly when\n * you already hold a configured client. */\n async exchangeTelegram(input: { initData: string }): Promise<JwtIssued> {\n const resp = await this.http.post<JwtIssued>(\"/auth/telegram/exchange\", {\n body: { init_data: input.initData },\n skipAuth: true,\n });\n await Promise.resolve(this.tokens.set(resp.access_token));\n return resp;\n }\n\n /** Attach a real email to the current user (and clear `email_pending`).\n * Used after a Telegram exchange to satisfy the email requirement; also\n * works for a password user changing their address. 409 if taken. */\n async linkEmail(input: { email: string }): Promise<User> {\n return this.http.post<User>(\"/me/email\", { body: { email: input.email } });\n }\n\n /** Current user — fails 401 when the stored JWT is expired or\n * missing. Useful as a \"do I have a session\" probe on app boot. */\n async me(): Promise<User> {\n return this.http.get<User>(\"/auth/me\");\n }\n\n /** Local sign-out. The SDK doesn't currently call a server-side\n * endpoint (the Takeal API issues stateless JWTs); clearing the\n * store is enough. Server-side session invalidation may land\n * with a future session table. */\n async signOut(): Promise<void> {\n await Promise.resolve(this.tokens.clear());\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CustomerInfo } from \"../types/customer.js\";\n\n/**\n * Deposits resource — `client.deposits.*`.\n *\n * The \"money IN\" surface: an end user tops up their wallet balance via a\n * funder connector. Mirrors the Takeal API's `/me/deposits` routes:\n *\n * POST /me/deposits → initiate\n * GET /me/deposits → list (most recent first)\n * GET /me/deposits/{id} → get\n * POST /me/deposits/{id}/refunds → refund\n *\n * A deposit is rarely terminal on the initiate call: real PSPs return\n * `redirect_required` (3DS / APM redirect) and flip to `confirmed` later via\n * a connector → Takeal API inbound event. Poll `get(id)` or watch the user's\n * webhook stream for the `deposit.confirmed` / `deposit.failed` outcome.\n */\n\n/** Lifecycle of a deposit. `redirect_required` carries `redirect_url`. */\nexport type DepositStatus =\n | \"pending\"\n | \"redirect_required\"\n | \"confirmed\"\n | \"failed\";\n\n/** Top-up rail. The chosen funder decides which it supports. */\nexport type DepositMethod = \"card\" | \"crypto\" | \"bank_transfer\";\n\n/**\n * A deposit record as the Takeal API returns it. Mirrors the `deposits` table; the\n * server-side `id` is the stable handle the SDK polls against. `idempotency_key`\n * and `request_fingerprint` are server-internal and never serialised.\n */\n/** Input for `quote()` — price a cross-currency deposit before paying. */\nexport interface CreateQuoteInput {\n /** Decimal string, e.g. `\"5000.00\"`. */\n amount: string;\n /** ISO 4217 source currency — must differ from the wallet's local currency. */\n currency: string;\n}\n\n/**\n * A rate-locked funding quote: pay `source_amount source_currency`, the\n * wallet is credited `credited_amount credited_currency` (net of the\n * platform's conversion spread). Execute by passing `id` as `quote_id` to\n * `initiate()` before `expires_at`; after that the API returns 409 and a new\n * quote is needed.\n */\nexport interface FundingQuote {\n id: string;\n source_amount: string;\n source_currency: string;\n credited_amount: string;\n credited_currency: string;\n /** Provider rate before spread (credited units per 1 source unit). */\n rate: string;\n spread_bps: number;\n provider: string;\n expires_at: string;\n}\n\nexport interface Deposit {\n id: string;\n user_id: string;\n /** Slug of the funder that handled this deposit, as configured by the deployment. */\n connector_slug: string;\n /** The connector's own reference, populated once it responds. */\n provider_reference: string | null;\n status: DepositStatus;\n /** Decimal serialised as a string to avoid float drift. */\n amount: string;\n currency: string;\n method: DepositMethod;\n /** Present when `status === \"redirect_required\"` — send the user here. */\n redirect_url: string | null;\n failure_reason: string | null;\n /** Final settled amount once confirmed (may differ from `amount` on FX). */\n confirmed_amount: string | null;\n confirmed_at: string | null;\n /** Set on cross-currency deposits: the quote this deposit executed against. */\n quote_id?: string | null;\n /** Locked provider rate (credited units per 1 source unit). */\n fx_rate?: string | null;\n fx_spread_bps?: number | null;\n /** The wallet's local currency the deposit converted into. */\n credited_currency?: string | null;\n /** What the wallet was actually credited, net of spread. */\n credited_amount?: string | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface InitiateDepositInput {\n /** Decimal as a string (`\"100.00\"`) — avoids float-precision loss on the wire. */\n amount: string;\n /** ISO 4217 code, e.g. `\"USD\"`. */\n currency: string;\n method: DepositMethod;\n /**\n * Optional. Slug of a specific funder to route through. Omit to\n * let the Takeal API pick the first active funder. Unknown slug → 400; empty\n * funder list → 503.\n */\n funder_slug?: string;\n /** Provider-specific extras. The mock funder reads `mock_scenario`. */\n metadata?: Record<string, string>;\n /** Structured billing details — real PSPs require these for 3DS / compliance. */\n customer?: CustomerInfo;\n /**\n * Required by the Takeal API on this write endpoint. Same key + body replays the\n * original deposit; same key + different body returns 409. Supply a stable\n * UUID per logical attempt so a retried network call is safe.\n */\n idempotencyKey: string;\n /**\n * Required when `currency` differs from the wallet's local currency: a\n * fresh quote id from `quote()`. Cross-currency deposits without one are\n * rejected with 400; expired quotes with 409.\n */\n quote_id?: string;\n}\n\nexport interface CreateDepositRefundInput {\n /** Omit for a full refund of the original confirmed amount; same currency. */\n amount?: string;\n /** Human-readable reason, e.g. `\"customer_request\"`. */\n reason?: string;\n metadata?: Record<string, string>;\n /** Required. Replays are keyed on this. */\n idempotencyKey: string;\n}\n\n/** A refund row as the Takeal API returns it (`refunds` table, deposit-targeted). */\nexport interface Refund {\n id: string;\n target_type: string;\n deposit_id?: string;\n payment_id?: string;\n connector_slug: string;\n amount: string;\n currency: string;\n reason: string;\n status: string;\n provider_refund_reference?: string;\n failure_reason?: string;\n requestor_type: string;\n requestor_id: string;\n created_at: string;\n updated_at: string;\n}\n\nexport class DepositsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Initiate a top-up. Resolves to the freshly-created `Deposit`, whose\n * `status` may already be `confirmed` (synchronous rails / mock) or\n * `redirect_required` (3DS / APM — forward the user to `redirect_url`).\n */\n /**\n * Price a cross-currency deposit BEFORE paying. The rate is locked\n * server-side until `expires_at`; deposits in the local currency need no\n * quote (the API answers 400 `no_quote_needed`).\n */\n async quote(input: CreateQuoteInput): Promise<FundingQuote> {\n return this.http.post<FundingQuote>(\"/me/deposits/quotes\", { body: input });\n }\n\n async initiate(input: InitiateDepositInput): Promise<Deposit> {\n const { idempotencyKey, ...body } = input;\n return this.http.post<Deposit>(\"/me/deposits\", {\n body,\n idempotencyKey,\n });\n }\n\n /** Fetch one deposit by id — the poll target while a redirect resolves. */\n async get(id: string): Promise<Deposit> {\n return this.http.get<Deposit>(`/me/deposits/${encodeURIComponent(id)}`);\n }\n\n /** List the caller's deposits, most recent first. */\n async list(): Promise<Deposit[]> {\n return this.http.get<Deposit[]>(\"/me/deposits\");\n }\n\n /**\n * Refund a previously-confirmed deposit. Synchronous when the\n * connector settles inline; otherwise the row stays `pending` and flips\n * later via the inbound `deposit.refunded` event.\n */\n async refund(\n depositId: string,\n input: CreateDepositRefundInput,\n ): Promise<Refund> {\n const { idempotencyKey, ...body } = input;\n return this.http.post<Refund>(\n `/me/deposits/${encodeURIComponent(depositId)}/refunds`,\n { body, idempotencyKey },\n );\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CustomerInfo } from \"../types/customer.js\";\n\n/**\n * Cards resource — `client.cards.*`.\n *\n * The end-user \"money OUT\" surface: a user issues themselves a card backed by\n * their wallet balance via an issuer connector. Mirrors the Takeal API's\n * `/me/cards` routes:\n *\n * POST /me/cards → create\n * GET /me/cards → list (most recent first)\n * GET /me/cards/{id} → get\n * GET /me/cards/{id}/balance → balance (prepaid remaining)\n * POST /me/cards/{id}/freeze → freeze\n * POST /me/cards/{id}/unfreeze → unfreeze\n * POST /me/cards/{id}/terminate → terminate (one-way)\n *\n * The lifecycle actions are ownership-gated server-side: a caller can only\n * freeze / unfreeze / terminate a card that belongs to them (else 404).\n *\n * ## What is intentionally NOT here\n *\n * Card-data reveal (PAN / CVV) is a separate, security-sensitive flow with its\n * own re-auth + rate-limit + audit contract and is intentionally\n * NOT part of this resource (tracked separately).\n *\n * Today only PREPAID is wired end-to-end; CREDIT and GIFT return 400 from\n * the Takeal API until their issuer flows land.\n */\n\n/** Card product. Only `prepaid` is fully implemented today. */\nexport type CardType = \"credit\" | \"prepaid\" | \"gift\";\n\n/**\n * Card lifecycle state.\n *\n * `pending_payment` is a transient state: the row exists but the\n * per-card issuance-fee debit has not yet succeeded; such cards have no\n * provider reference and no user-visible side effects.\n */\nexport type CardStatus =\n | \"pending_payment\"\n | \"active\"\n | \"frozen\"\n | \"terminated\"\n | \"redeemed\"\n | \"failed\";\n\n/**\n * A card record as the Takeal API returns it. Mirrors the `cards` table. Note the\n * SDK never receives the full PAN or CVV here — only `last4` + expiry. The\n * gift-card `redemption_code` is returned exactly once (on create) and\n * scrubbed from subsequent list/get responses.\n */\nexport interface Card {\n id: string;\n user_id: string;\n card_type: CardType;\n /** Slug of the issuer that minted this card, as configured by the deployment. */\n connector_slug: string;\n /** The connector's own reference, populated once it responds. */\n provider_reference: string | null;\n status: CardStatus;\n /** Last four digits of the PAN — safe to display. */\n last4: string | null;\n expiry_month: number | null;\n expiry_year: number | null;\n /** Gift cards only, present once on create then scrubbed. */\n redemption_code?: string;\n /** Decimal as a string. */\n initial_amount: string | null;\n currency: string;\n failure_reason: string | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface CreateCardInput {\n /** `prepaid` (the only fully-wired type today), `credit`, or `gift`. */\n type: CardType;\n /** Decimal as a string. The prepaid load amount drained from wallet balance. */\n initial_amount?: string;\n /** ISO 4217 code, e.g. `\"USD\"`. */\n currency: string;\n /**\n * Optional. Slug of a specific issuer to mint with. Omit to let\n * the Takeal API pick the first active issuer. Unknown slug → 400; empty issuer\n * list → 503.\n */\n issuer_slug?: string;\n metadata?: Record<string, string>;\n /** Structured billing details — real issuers require these for 3DS / KYC. */\n customer?: CustomerInfo;\n /**\n * Required by the Takeal API on this write endpoint. Same key + body replays the\n * original card; same key + different body returns 409.\n */\n idempotencyKey: string;\n}\n\n/** Remaining balance of a prepaid card. */\nexport interface CardBalance {\n amount: string;\n currency: string;\n}\n\n/** Re-auth gate for {@link CardsResource.reveal}. */\nexport interface RevealCardInput {\n /** The user's account password — mandatory re-auth. */\n password: string;\n /** TOTP code; required only when the user has TOTP enrolled. */\n totpCode?: string;\n}\n\n/**\n * Full card data from a successful reveal. **Security**: never persist this —\n * keep it in volatile memory only, clear it within `expires_in_seconds`, and\n * never write it to localStorage / logs (the API marks the response no-store).\n */\nexport interface RevealedCard {\n pan: string;\n cvv: string;\n expiry_month: number;\n expiry_year: number;\n holder_name: string;\n /** Display window before the client should auto-clear the data. */\n expires_in_seconds: number;\n}\n\nexport class CardsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Issue a card backed by the user's wallet balance. Resolves to the new\n * `Card`. On a ledger failure after provider creation, the Takeal API rolls the row\n * to `failed` (never an orphaned active card); inspect `status` /\n * `failure_reason` on the result.\n */\n async create(input: CreateCardInput): Promise<Card> {\n const { idempotencyKey, ...body } = input;\n return this.http.post<Card>(\"/me/cards\", {\n body,\n idempotencyKey,\n });\n }\n\n /** Fetch one card by id. */\n async get(id: string): Promise<Card> {\n return this.http.get<Card>(`/me/cards/${encodeURIComponent(id)}`);\n }\n\n /** List the caller's cards, most recent first. */\n async list(): Promise<Card[]> {\n return this.http.get<Card[]>(\"/me/cards\");\n }\n\n /**\n * Remaining balance of a prepaid card. `currency` is required by the Takeal API and\n * forwarded as a query param.\n */\n async balance(id: string, currency: string): Promise<CardBalance> {\n const q = new URLSearchParams({ currency }).toString();\n return this.http.get<CardBalance>(\n `/me/cards/${encodeURIComponent(id)}/balance?${q}`,\n );\n }\n\n /**\n * Freeze the caller's own card. Reversible via {@link unfreeze}. The optional\n * `reason` is recorded on the audit trail. Resolves to the updated card.\n * 404 if the card isn't the caller's; 501 if the issuer can't freeze.\n */\n async freeze(id: string, reason?: string): Promise<Card> {\n return this.http.post<Card>(\n `/me/cards/${encodeURIComponent(id)}/freeze`,\n { body: { reason } },\n );\n }\n\n /**\n * Reveal the FULL PAN + CVV for the caller's own card. Re-auth gated\n * (password, + TOTP when the user has it enrolled) and rate-limited\n * server-side. The Takeal API never persists this data and marks the\n * response no-store; the SDK returns it verbatim and holds nothing.\n *\n * **Consumer security duties** (the SDK can't enforce these for you):\n * keep the result in volatile memory only, never write it to\n * localStorage / logs, and clear it within `expires_in_seconds`.\n *\n * 401 bad re-auth · 403 not your card · 429 rate-limited · 501 connector\n * has no sensitive-data endpoint · 503 provider error.\n */\n async reveal(id: string, input: RevealCardInput): Promise<RevealedCard> {\n return this.http.post<RevealedCard>(\n `/me/cards/${encodeURIComponent(id)}/reveal`,\n { body: { password: input.password, totp_code: input.totpCode } },\n );\n }\n\n /** Unfreeze a previously-frozen card. Idempotent on an already-active card. */\n async unfreeze(id: string): Promise<Card> {\n return this.http.post<Card>(\n `/me/cards/${encodeURIComponent(id)}/unfreeze`,\n { body: {} },\n );\n }\n\n /**\n * Terminate the caller's own card. **One-way** — a terminated card cannot be\n * reactivated. The optional `reason` is audited. Idempotent on an\n * already-terminated card.\n */\n async terminate(id: string, reason?: string): Promise<Card> {\n return this.http.post<Card>(\n `/me/cards/${encodeURIComponent(id)}/terminate`,\n { body: { reason } },\n );\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Balance resource — `client.balance.*`.\n *\n * The user's wallet balance, tracked in the ledger. Mirrors\n * the Takeal API's `GET /me/balance?currency=<code>` route. Balance is per-currency:\n * the endpoint requires a `currency` query param and returns the amount held\n * in that currency.\n */\n\n/** Wallet balance for one currency. `amount` is a decimal string. */\nexport interface Balance {\n amount: string;\n currency: string;\n}\n\nexport class BalanceResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Fetch the user's wallet balance for `currency` (ISO 4217, e.g. `\"USD\"`).\n * Required — the ledger holds a separate balance per currency, so there is\n * no \"total\" without one.\n */\n async get(currency: string): Promise<Balance> {\n const q = new URLSearchParams({ currency }).toString();\n return this.http.get<Balance>(`/me/balance?${q}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Branding resource — `client.branding.*`.\n *\n * Runtime white-label config published by the deployment at `GET /branding`\n * (public, no auth). Lets a Cusfront re-theme itself on the fly — platform\n * name, logo, favicon and the label used for the end-user's balance — without\n * a rebuild. Pairs with the build-time `BrandConfig`: the server-side values\n * win whenever both are present.\n */\n\n/** Public brand config of the deployment. All strings; empty = use the client default. */\nexport interface Branding {\n /** Platform display name (e.g. the white-label brand). */\n platform_name: string;\n /** Name of the merchant-facing portal. */\n merchant_portal_name: string;\n /** Logo image — absolute URL or `data:` URI. Empty → client default. */\n logo_url: string;\n /** Favicon — absolute URL or `data:` URI. Empty → client default. */\n favicon_url: string;\n /** User-facing name of the balance, e.g. `\"Wallet\"` or `\"Acme Wallet\"`.\n * Display-only: the `balance` API shape never changes with it. */\n wallet_label: string;\n}\n\nexport class BrandingResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Fetch the deployment's public brand config. Safe to call before login. */\n async get(opts: { signal?: AbortSignal } = {}): Promise<Branding> {\n return this.http.get<Branding>(\"/branding\", { skipAuth: true, signal: opts.signal });\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Blog resource — `client.blog.*`.\n *\n * Posts are public: these calls work before the user logs in, which is what\n * a marketing page or a Mini App landing screen needs.\n *\n * A post arrives as a **structured document**, not as HTML. `body_blocks` is\n * a flat list of typed nodes; map each `type` onto your own component and the\n * post inherits your site's styling. `body_markdown` is there too if you'd\n * rather run your own renderer.\n *\n * ```ts\n * const { posts } = await client.blog.list({ perPage: 5 });\n * const post = await client.blog.get(posts[0].slug);\n *\n * post.body_blocks.map((b) => {\n * switch (b.type) {\n * case \"heading\": return <Heading level={b.level}>{b.text}</Heading>;\n * case \"paragraph\": return <P>{b.text}</P>;\n * case \"image\": return <Figure src={b.url} alt={b.alt} caption={b.caption} />;\n * case \"list\": return <List ordered={b.ordered} items={b.items} />;\n * case \"quote\": return <Quote>{b.text}</Quote>;\n * case \"code\": return <Code lang={b.lang}>{b.text}</Code>;\n * case \"divider\": return <Hr />;\n * }\n * });\n * ```\n *\n * Inline emphasis (`**bold**`, `[link](url)`) is left as Markdown inside\n * block text — every renderer already knows what to do with it.\n */\n\n/** One node of a post body. Discriminated on `type`. */\nexport type BlogBlock =\n | { type: \"heading\"; level: number; text: string }\n | { type: \"paragraph\"; text: string }\n | { type: \"image\"; url: string; alt?: string; caption?: string }\n | { type: \"list\"; ordered: boolean; items: string[] }\n | { type: \"quote\"; text: string }\n | { type: \"code\"; lang?: string; text: string }\n | { type: \"divider\" };\n\nexport interface BlogPost {\n /** Stable public key — link by this. */\n slug: string;\n title: string;\n /** Teaser for cards; falls back to the first paragraph. */\n excerpt: string;\n /** Image URL, relative to the API origin. Absent when no cover is set. */\n cover_url?: string;\n /** Raw Markdown, for consumers that bring their own renderer. */\n body_markdown: string;\n /** The recommended input for rendering — see the module docs. */\n body_blocks: BlogBlock[];\n tags: string[];\n /** Present only when the post declares one. */\n locale?: string;\n /** Rough read time in minutes (minimum 1). */\n reading_minutes: number;\n published_at: string | null;\n updated_at: string;\n}\n\nexport interface BlogListInput {\n /** 1-based. Default 1. */\n page?: number;\n /** 1..=50. Default 10. */\n perPage?: number;\n /** Only posts carrying this tag. */\n tag?: string;\n /** Only posts in this locale. */\n locale?: string;\n}\n\nexport interface BlogList {\n posts: BlogPost[];\n total: number;\n page: number;\n per_page: number;\n}\n\nexport class BlogResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Published posts, newest first. No authentication required. */\n async list(input: BlogListInput = {}): Promise<BlogList> {\n const q = new URLSearchParams();\n if (input.page) q.set(\"page\", String(input.page));\n if (input.perPage) q.set(\"per_page\", String(input.perPage));\n if (input.tag) q.set(\"tag\", input.tag);\n if (input.locale) q.set(\"locale\", input.locale);\n const qs = q.toString();\n return this.http.get<BlogList>(`/blog/posts${qs ? `?${qs}` : \"\"}`, {\n skipAuth: true,\n });\n }\n\n /** One post by slug. No authentication required. */\n async get(slug: string): Promise<BlogPost> {\n return this.http.get<BlogPost>(`/blog/posts/${encodeURIComponent(slug)}`, {\n skipAuth: true,\n });\n }\n\n /**\n * Absolute URL for an image path returned inside a post (`cover_url`, or an\n * image block's `url`). Handy when the app renders on a different origin\n * than the API.\n */\n imageUrl(baseUrl: string, path: string): string {\n if (/^https?:\\/\\//i.test(path)) return path;\n return `${baseUrl.replace(/\\/$/, \"\")}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Subscriptions resource — `client.subscriptions.*`.\n *\n * Which channels the signed-in user agreed to receive announcements on.\n * `available` tells you which toggles to render: a deployment with no\n * Telegram bot configured can't deliver there, so offering the switch would\n * be a lie.\n *\n * ```ts\n * const { channels, available } = await client.subscriptions.get();\n * await client.subscriptions.set([...channels, \"telegram\"]);\n * ```\n *\n * Unrelated to paid/VIP tiers — this is only about announcements.\n */\n\nexport type BroadcastChannel = \"email\" | \"telegram\" | (string & {});\n\nexport interface Subscriptions {\n /** Channels the user currently receives announcements on. */\n channels: BroadcastChannel[];\n /** Channels this deployment can actually deliver on. */\n available: BroadcastChannel[];\n}\n\nexport class SubscriptionsResource {\n constructor(private readonly http: HttpClient) {}\n\n async get(): Promise<Subscriptions> {\n return this.http.get<Subscriptions>(\"/me/subscriptions\");\n }\n\n /**\n * Replace the whole set — this is a PUT, not a merge. Pass `[]` to opt out\n * of everything.\n */\n async set(channels: BroadcastChannel[]): Promise<Subscriptions> {\n return this.http.put<Subscriptions>(\"/me/subscriptions\", {\n body: { channels },\n });\n }\n}\n","/**\n * Pluggable storage for the JWT.\n *\n * Default behaviour by environment:\n * - browser → `localStorage` (synchronous, persists across reloads)\n * - Node / SSR / worker → in-memory (no global state to leak)\n * - mobile (Capacitor / RN) → consumer must inject Keychain /\n * EncryptedSharedPreferences via `createClient({ tokenStore })`\n *\n * The store is intentionally tiny — three methods, no eviction\n * policy, no encryption. Encryption is the consumer's call (mobile\n * adapters wrap platform-native secure storage). Persistence shape\n * is opaque to the SDK; tokens are passed through verbatim.\n */\nexport interface TokenStore {\n get(): string | null | Promise<string | null>;\n set(token: string): void | Promise<void>;\n clear(): void | Promise<void>;\n}\n\n/** Sync `localStorage`-backed store. Falls through to in-memory when\n * `window.localStorage` is unavailable (private mode quota, SSR). */\nexport function defaultBrowserStore(key = \"takeal_jwt\"): TokenStore {\n const fallback = inMemoryStore();\n // Probe once at construction — avoid the try/catch on every call.\n let usable = false;\n try {\n if (typeof globalThis !== \"undefined\" && \"localStorage\" in globalThis) {\n const ls = (globalThis as { localStorage: Storage }).localStorage;\n const probe = \"__takeal_probe__\";\n ls.setItem(probe, \"1\");\n ls.removeItem(probe);\n usable = true;\n }\n } catch {\n usable = false;\n }\n if (!usable) return fallback;\n const ls = (globalThis as { localStorage: Storage }).localStorage;\n return {\n get: () => ls.getItem(key),\n set: (token) => ls.setItem(key, token),\n clear: () => ls.removeItem(key),\n };\n}\n\n/** In-memory store. Use for SSR / tests / when persistence isn't\n * desired (e.g. ephemeral kiosk sessions). */\nexport function inMemoryStore(): TokenStore {\n let value: string | null = null;\n return {\n get: () => value,\n set: (token) => {\n value = token;\n },\n clear: () => {\n value = null;\n },\n };\n}\n","/**\n * `@takeal/cusfront-sdk` — typed client for the Takeal end-user API.\n *\n * Entry point: `createClient({ baseUrl, brand?, tokenStore?, fetch? })`.\n * Resources are accessed off the returned client (`client.auth.login`,\n * `client.cards.list`, …). Sub-exports under `@takeal/cusfront-sdk/<resource>`\n * publish each resource independently so a Cusfront only pulls what\n * it imports.\n *\n * Brand-neutral by design. No customer / deployment names embedded.\n * Brand swap happens at runtime via `BrandConfig`.\n */\n\nimport { HttpClient, type FetchLike } from \"./http.js\";\nimport { AuthResource } from \"./resources/auth.js\";\nimport { DepositsResource } from \"./resources/deposits.js\";\nimport { CardsResource } from \"./resources/cards.js\";\nimport { BalanceResource } from \"./resources/balance.js\";\nimport { BrandingResource } from \"./resources/branding.js\";\nimport { BlogResource } from \"./resources/blog.js\";\nimport { SubscriptionsResource } from \"./resources/subscriptions.js\";\nimport {\n defaultBrowserStore,\n inMemoryStore,\n type TokenStore,\n} from \"./token-store.js\";\nimport type { BrandConfig } from \"./brand.js\";\n\nexport type { BrandConfig } from \"./brand.js\";\nexport { ApiError, NetworkError, isApiError, isNetworkError } from \"./error.js\";\nexport { defaultBrowserStore, inMemoryStore, type TokenStore } from \"./token-store.js\";\n\n// Re-export resource types so consumers can `import { Deposit } from\n// \"@takeal/cusfront-sdk\"` without reaching into sub-paths.\nexport type { Address, CustomerInfo } from \"./types/customer.js\";\nexport type {\n Deposit,\n DepositStatus,\n DepositMethod,\n InitiateDepositInput,\n CreateDepositRefundInput,\n Refund,\n CreateQuoteInput, FundingQuote } from \"./resources/deposits.js\";\nexport type {\n Card,\n CardType,\n CardStatus,\n CreateCardInput,\n CardBalance,\n RevealCardInput,\n RevealedCard,\n} from \"./resources/cards.js\";\nexport type { Balance } from \"./resources/balance.js\";\nexport type { Branding } from \"./resources/branding.js\";\nexport type { BlogPost, BlogBlock, BlogList, BlogListInput } from \"./resources/blog.js\";\nexport type {\n Subscriptions,\n BroadcastChannel,\n} from \"./resources/subscriptions.js\";\n\nexport interface CreateClientOptions {\n /** Absolute origin of the Takeal API deployment, no trailing slash.\n * e.g. `\"https://api.takeal.example.com\"`. */\n baseUrl: string;\n /** Runtime brand config. Optional; consumer renders its own brand\n * if omitted. */\n brand?: BrandConfig;\n /** Token persistence. Defaults to `defaultBrowserStore()` when\n * `window.localStorage` is present, else `inMemoryStore()`. */\n tokenStore?: TokenStore;\n /** Override the `fetch` implementation — useful for Node < 18,\n * React Native < 0.74, MSW intercept layers, etc. */\n fetch?: FetchLike;\n /** When true, the SDK runs every response through a zod schema\n * before handing it to the caller. Requires `zod` >= 3.22 as a\n * peer dep. Off by default; types-only validation is sufficient\n * for the steady-state case. */\n validate?: boolean;\n}\n\nexport interface CusfrontClient {\n /** Read-only brand config — pass through from createClient args. */\n readonly brand: BrandConfig | undefined;\n /** Auth resource: login, refresh, current user, logout. */\n readonly auth: AuthResource;\n /** Deposits (money IN via a funder connector): initiate, get, list, refund. */\n readonly deposits: DepositsResource;\n /** Cards (money OUT via an issuer connector): create, get, list, balance. */\n readonly cards: CardsResource;\n /** Wallet balance lookup, per currency. */\n readonly balance: BalanceResource;\n /** Runtime white-label config (`GET /branding`, public): names, logo, wallet label. */\n readonly branding: BrandingResource;\n /** Public blog posts, returned as structured blocks to render in your own style. */\n readonly blog: BlogResource;\n /** The user's announcement channel subscriptions. */\n readonly subscriptions: SubscriptionsResource;\n /** Direct access to the token store (e.g. for an explicit sign-out\n * on Capacitor's lifecycle \"app pausing\" event). */\n readonly tokens: TokenStore;\n}\n\n/**\n * Build a new client. Stateless across calls — multiple clients can\n * coexist (e.g. an admin Cusfront with a different baseUrl than the\n * end-user one). Each gets its own `TokenStore`.\n *\n * `validate: true` is honoured by individual resources that ship\n * matching zod schemas; resources without a schema ignore it.\n */\nexport function createClient(opts: CreateClientOptions): CusfrontClient {\n const tokens = opts.tokenStore ?? pickDefaultStore();\n const fetchImpl = opts.fetch ?? defaultFetch();\n const http = new HttpClient(opts.baseUrl, tokens, fetchImpl);\n\n return {\n brand: opts.brand,\n tokens,\n auth: new AuthResource(http, tokens),\n deposits: new DepositsResource(http),\n cards: new CardsResource(http),\n balance: new BalanceResource(http),\n branding: new BrandingResource(http),\n blog: new BlogResource(http),\n subscriptions: new SubscriptionsResource(http),\n };\n}\n\nfunction pickDefaultStore(): TokenStore {\n if (typeof globalThis !== \"undefined\" && \"localStorage\" in globalThis) {\n return defaultBrowserStore();\n }\n return inMemoryStore();\n}\n\nfunction defaultFetch(): FetchLike {\n if (typeof globalThis !== \"undefined\" && typeof globalThis.fetch === \"function\") {\n // Bind to globalThis so `this` is correct inside the implementation\n // (some polyfills choke on a detached reference).\n return globalThis.fetch.bind(globalThis);\n }\n throw new Error(\n \"@takeal/cusfront-sdk: native fetch is not available in this runtime. \" +\n \"Pass a polyfill via createClient({ fetch }).\",\n );\n}\n","/**\n * `@takeal/cusfront-sdk/telegram` — Telegram Mini App adapter.\n *\n * A Mini App receives a signed `initData` string from the Telegram client\n * (`window.Telegram.WebApp.initData`). This module turns that string into an\n * authenticated SDK client:\n *\n * import { fromTelegramWebApp } from \"@takeal/cusfront-sdk/telegram\";\n * const client = await fromTelegramWebApp({ baseUrl: \"https://api.example.com\" });\n * const me = await client.auth.me(); // me.email_pending? prompt for email\n *\n * Signature validation: the HMAC over `initData` can only be verified with the\n * bot token, which lives on the server. So the **authoritative** check happens\n * server-side at `POST /auth/telegram/exchange`. Here we only do a structural,\n * fail-fast well-formedness check (`hash` + `auth_date` present, not stale)\n * before spending a network round-trip on an obviously-bad payload.\n */\n\nimport {\n createClient,\n type CreateClientOptions,\n type CusfrontClient,\n} from \"./index.js\";\nimport type { JwtIssued } from \"./resources/auth.js\";\n\n/** The Telegram `user` object embedded (URL-encoded JSON) in initData. */\nexport interface TelegramUser {\n id: number;\n first_name?: string;\n last_name?: string;\n username?: string;\n language_code?: string;\n photo_url?: string;\n is_premium?: boolean;\n}\n\n/** Structurally-parsed initData. `raw` is the original string passed to the\n * server verbatim — the server re-derives the HMAC from it, so we never\n * re-serialise. */\nexport interface ParsedInitData {\n raw: string;\n params: Record<string, string>;\n hash?: string;\n auth_date?: number;\n query_id?: string;\n user?: TelegramUser;\n}\n\n/** Thrown by {@link assertWellFormed} when initData is structurally invalid or\n * stale. A signature mismatch is NOT detectable here (no bot token) — that\n * surfaces as a 401 `ApiError` from the exchange call instead. */\nexport class InitDataError extends Error {\n constructor(\n message: string,\n readonly reason:\n | \"empty\"\n | \"missing_hash\"\n | \"missing_auth_date\"\n | \"bad_user\"\n | \"stale\",\n ) {\n super(message);\n this.name = \"InitDataError\";\n }\n}\n\n/** Parse a raw `initData` query string into its fields (best-effort — does\n * not validate). `user` is JSON-decoded when present and parseable. */\nexport function parseInitData(initData: string): ParsedInitData {\n const params: Record<string, string> = {};\n const sp = new URLSearchParams(initData);\n for (const [k, v] of sp.entries()) params[k] = v;\n\n let user: TelegramUser | undefined;\n if (params.user) {\n try {\n user = JSON.parse(params.user) as TelegramUser;\n } catch {\n user = undefined;\n }\n }\n\n const authDateRaw = params.auth_date;\n const auth_date =\n authDateRaw && /^\\d+$/.test(authDateRaw) ? Number(authDateRaw) : undefined;\n\n return {\n raw: initData,\n params,\n ...(params.hash ? { hash: params.hash } : {}),\n ...(auth_date !== undefined ? { auth_date } : {}),\n ...(params.query_id ? { query_id: params.query_id } : {}),\n ...(user ? { user } : {}),\n };\n}\n\nexport interface WellFormedOptions {\n /** Reject initData whose `auth_date` is older than this many seconds.\n * Defaults to 86400 (24h) — match or stay under the server's\n * `auth.telegram.initdata_max_age_secs`. Pass 0 to skip the freshness\n * check client-side (the server still enforces its own window). */\n maxAgeSeconds?: number;\n /** Injectable clock (unix seconds) for testing. Defaults to `Date.now()`. */\n nowUnix?: number;\n}\n\n/** Fail-fast structural check: `hash` present, `auth_date` present + a valid\n * `user`, and (optionally) not stale. Throws {@link InitDataError}. Does NOT\n * verify the HMAC — only the server can. */\nexport function assertWellFormed(\n initData: string,\n opts: WellFormedOptions = {},\n): ParsedInitData {\n if (!initData) throw new InitDataError(\"initData is empty\", \"empty\");\n const parsed = parseInitData(initData);\n if (!parsed.hash)\n throw new InitDataError(\"initData is missing `hash`\", \"missing_hash\");\n if (parsed.auth_date === undefined)\n throw new InitDataError(\n \"initData is missing a valid `auth_date`\",\n \"missing_auth_date\",\n );\n if (!parsed.user || typeof parsed.user.id !== \"number\")\n throw new InitDataError(\n \"initData is missing a valid `user`\",\n \"bad_user\",\n );\n\n const maxAge = opts.maxAgeSeconds ?? 86_400;\n if (maxAge > 0) {\n const now = opts.nowUnix ?? Math.floor(Date.now() / 1000);\n if (now - parsed.auth_date > maxAge)\n throw new InitDataError(\n \"initData is stale (auth_date older than the freshness window)\",\n \"stale\",\n );\n }\n return parsed;\n}\n\nexport interface FromInitDataOptions extends WellFormedOptions {\n /** Skip the client-side well-formedness check and let the server be the\n * sole judge. Default false — the fail-fast check saves a round-trip on\n * obviously-bad input. */\n skipWellFormedCheck?: boolean;\n}\n\n/**\n * Build an authenticated client from a raw `initData` string.\n *\n * 1. (unless skipped) structurally validate the payload — throws\n * {@link InitDataError} on malformed/stale input.\n * 2. exchange it at `POST /auth/telegram/exchange` — the server validates the\n * HMAC; a bad signature throws a 401 `ApiError`.\n * 3. store the returned JWT and return the ready-to-use client.\n *\n * Read `client.auth.me()` (or call `client.auth.exchangeTelegram` directly for\n * the raw session) to check `email_pending` and prompt for an email.\n */\nexport async function fromInitData(\n initData: string,\n config: CreateClientOptions,\n opts: FromInitDataOptions = {},\n): Promise<CusfrontClient> {\n if (!opts.skipWellFormedCheck) assertWellFormed(initData, opts);\n const client = createClient(config);\n await client.auth.exchangeTelegram({ initData });\n return client;\n}\n\n/** Read `window.Telegram.WebApp.initData` if running inside a Telegram Mini\n * App. Returns null when absent or empty (e.g. opened outside Telegram). */\nexport function readWebAppInitData(): string | null {\n const tg = (\n globalThis as unknown as {\n Telegram?: { WebApp?: { initData?: string } };\n }\n ).Telegram;\n const data = tg?.WebApp?.initData;\n return data && data.length > 0 ? data : null;\n}\n\n/**\n * Convenience entry for a Mini App: read `initData` from the Telegram WebApp\n * SDK and exchange it. Throws if not running inside a Telegram Mini App.\n */\nexport async function fromTelegramWebApp(\n config: CreateClientOptions,\n opts: FromInitDataOptions = {},\n): Promise<CusfrontClient> {\n const initData = readWebAppInitData();\n if (!initData)\n throw new InitDataError(\n \"not running inside a Telegram Mini App (window.Telegram.WebApp.initData is empty)\",\n \"empty\",\n );\n return fromInitData(initData, config, opts);\n}\n\n/** Convenience accessor for the typed exchange session (incl. `email_pending`)\n * when you need the envelope rather than just the client. */\nexport type TelegramExchangeSession = JwtIssued;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/error.ts","../src/http.ts","../src/resources/auth.ts","../src/resources/deposits.ts","../src/resources/cards.ts","../src/resources/balance.ts","../src/resources/branding.ts","../src/resources/wallet.ts","../src/resources/blog.ts","../src/resources/subscriptions.ts","../src/resources/sessions.ts","../src/resources/push.ts","../src/token-store.ts","../src/index.ts","../src/telegram.ts"],"names":["ls"],"mappings":"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","file":"telegram.cjs","sourcesContent":["/**\n * Errors surfaced by the SDK. All HTTP failures map onto `ApiError`;\n * network-level / abort / serialisation failures get the generic\n * `NetworkError`. Consumers catch on the discriminator field\n * (`isApiError` / `isNetworkError`) rather than `instanceof` — works\n * across bundler boundaries where multiple copies of the class can\n * coexist.\n */\nexport class ApiError extends Error {\n readonly isApiError = true as const;\n\n constructor(\n /** HTTP status code returned by the Takeal API. */\n public readonly status: number,\n /** Stable machine-readable code (e.g. `\"insufficient_funds\"`,\n * `\"permission_required\"`, `\"validation\"`). Same enum the\n * TypeScript types pin via openapi-typescript. */\n public readonly code: string,\n /** Human-readable message. English; the consumer maps to its\n * own i18n layer before showing to end-users. */\n message: string,\n /** Full parsed response body when available. Carries field-level\n * validation details for `code = \"validation\"`. */\n public readonly body?: unknown,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport class NetworkError extends Error {\n readonly isNetworkError = true as const;\n\n constructor(message: string, public readonly cause?: unknown) {\n super(message);\n this.name = \"NetworkError\";\n }\n}\n\n/** Type guard — preferred over `instanceof` (bundler-safe). */\nexport function isApiError(e: unknown): e is ApiError {\n return (\n typeof e === \"object\" && e !== null && (e as { isApiError?: boolean }).isApiError === true\n );\n}\n\nexport function isNetworkError(e: unknown): e is NetworkError {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as { isNetworkError?: boolean }).isNetworkError === true\n );\n}\n","import { ApiError, NetworkError } from \"./error.js\";\nimport type { TokenStore } from \"./token-store.js\";\n\n/**\n * Internal HTTP client. One per SDK instance; injected into each\n * resource. Responsibilities:\n *\n * - Construct absolute URLs from `baseUrl` + API version + path.\n * Resources pass contract paths (`/me/deposits`); the `/v1` prefix is\n * added here, in one place. Only the deployment-level endpoints\n * (`/ready`, `/branding`, …) stay unversioned.\n * - Set `Authorization: Bearer <jwt>` from the `TokenStore`.\n * - Set `Content-Type: application/json` on bodies.\n * - Parse JSON responses + map non-2xx to `ApiError`.\n * - Forward `Idempotency-Key` when the caller passes one.\n * - Surface network failures (DNS, abort, broken pipe) as\n * `NetworkError`.\n *\n * Auto-refresh + retry policies are deliberately NOT in here — they\n * belong to the resource layer (auth.refresh) which has the right\n * context for \"is this refreshable\" decisions.\n */\n\nexport type FetchLike = typeof fetch;\n\n/** Current public contract revision of the Takeal API. */\nexport const API_VERSION = \"/v1\";\n\n/** Host-level endpoints that are not part of a versioned contract. */\nconst UNVERSIONED = new Set([\"/health\", \"/ready\", \"/branding\", \"/favicon.ico\"]);\n\n/**\n * `/me/deposits` → `/v1/me/deposits`. Already-versioned paths and the\n * unversioned ops endpoints pass through untouched.\n */\nexport function versionedPath(path: string): string {\n const p = path.startsWith(\"/\") ? path : `/${path}`;\n const bare = p.split(\"?\")[0]!;\n if (UNVERSIONED.has(bare)) return p;\n if (bare === API_VERSION || bare.startsWith(`${API_VERSION}/`)) return p;\n return `${API_VERSION}${p}`;\n}\n\nexport interface HttpOptions {\n /** Request body. Will be JSON-serialised if not already a\n * string / FormData / Blob. */\n body?: unknown;\n /** Idempotency key forwarded as the `Idempotency-Key` header.\n * Required by the Takeal API on most write endpoints. */\n idempotencyKey?: string;\n /** Extra headers merged after the SDK's defaults — caller wins. */\n headers?: Record<string, string>;\n /** Bypass the token store for one call (login, refresh). */\n skipAuth?: boolean;\n /** AbortSignal forwarded to fetch. */\n signal?: AbortSignal;\n}\n\nexport class HttpClient {\n constructor(\n private readonly baseUrl: string,\n private readonly tokens: TokenStore,\n private readonly fetchImpl: FetchLike,\n ) {\n if (!baseUrl) throw new Error(\"HttpClient: baseUrl is required\");\n }\n\n async get<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"GET\", path, opts);\n }\n\n async post<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"POST\", path, opts);\n }\n\n async put<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"PUT\", path, opts);\n }\n\n async patch<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"PATCH\", path, opts);\n }\n\n async delete<T>(path: string, opts: HttpOptions = {}): Promise<T> {\n return this.request<T>(\"DELETE\", path, opts);\n }\n\n private async request<T>(method: string, path: string, opts: HttpOptions): Promise<T> {\n const url = this.absolute(path);\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n };\n if (opts.body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n if (opts.idempotencyKey) headers[\"Idempotency-Key\"] = opts.idempotencyKey;\n if (!opts.skipAuth) {\n const token = await Promise.resolve(this.tokens.get());\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n }\n Object.assign(headers, opts.headers ?? {});\n\n const init: RequestInit = {\n method,\n headers,\n ...(opts.signal ? { signal: opts.signal } : {}),\n };\n if (opts.body !== undefined) {\n init.body =\n typeof opts.body === \"string\" ? opts.body : JSON.stringify(opts.body);\n }\n\n let resp: Response;\n try {\n resp = await this.fetchImpl(url, init);\n } catch (e) {\n // DNS failure, connection refused, abort — anything before the\n // server returns a status. Map to NetworkError for the consumer.\n throw new NetworkError(\n e instanceof Error ? e.message : \"network error\",\n e,\n );\n }\n\n return parseResponse<T>(resp);\n }\n\n private absolute(path: string): string {\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) return path;\n const base = this.baseUrl.replace(/\\/+$/, \"\");\n return `${base}${versionedPath(path)}`;\n }\n}\n\nasync function parseResponse<T>(resp: Response): Promise<T> {\n // Read body once — the Takeal API either returns JSON or an empty body\n // (204 No Content on some DELETEs). Empty body → undefined cast.\n const text = await resp.text();\n let body: unknown;\n if (text.length === 0) {\n body = undefined;\n } else {\n try {\n body = JSON.parse(text);\n } catch {\n // Non-JSON response. On 2xx that's unexpected but not fatal —\n // hand back the raw text under a synthetic field. On error\n // status, fold into the ApiError body.\n body = { raw: text };\n }\n }\n\n if (!resp.ok) {\n const errBody = (body ?? {}) as { code?: string; message?: string };\n throw new ApiError(\n resp.status,\n errBody.code ?? `http_${resp.status}`,\n errBody.message ?? resp.statusText ?? \"request failed\",\n body,\n );\n }\n return body as T;\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { TokenStore } from \"../token-store.js\";\n\n/**\n * Auth resource — `client.auth.*`.\n *\n * Covers the end-user-facing staged auth flow: password login\n * with optional TOTP/OTP step-up. The shape mirrors the responses\n * the Takeal API returns from `/auth/login`, `/auth/login/totp`,\n * `/auth/login/otp/verify`, `/auth/login/2fa/switch`, and `/auth/me`.\n *\n * The login methods stash the JWT in the configured `TokenStore` on\n * success so subsequent `client.*` calls authenticate automatically.\n * Step-up responses (TotpRequired / OtpSent) carry their own short-\n * lived challenge token which the caller passes to the next method\n * — those tokens DO NOT go through the TokenStore (they're not the\n * end-state JWT).\n */\n\nexport interface User {\n id: string;\n email: string;\n role: string;\n is_active: boolean;\n /** True for users auto-provisioned via the Telegram Mini App who still hold\n * a synthetic placeholder email. The client should prompt for a real email\n * and attach it via `auth.linkEmail` — this flips the flag to false. */\n email_pending?: boolean;\n created_at: string;\n updated_at: string;\n /** ISO 4217 code the user's wallet is held in (their own choice, else the\n * deployment default). Present on `GET /auth/me`. */\n wallet_currency?: string;\n}\n\nexport interface LoginInput {\n email: string;\n password: string;\n}\n\n/** Discriminated union — `stage` is the discriminator. */\nexport type LoginResponse = JwtIssued | TotpRequired | TotpSetupRequired;\n\nexport interface JwtIssued {\n stage: \"jwt\";\n access_token: string;\n expires_at: string;\n user: User;\n /** True iff the user's role grants `system.view_hub`.\n * Cusfront ignores this; the operator console uses it to gate `/dashboard`. */\n hub_access?: boolean;\n}\n\nexport interface TotpRequired {\n stage: \"totp_required\";\n challenge_token: string;\n expires_at: string;\n /** Alternate second factors. Pick one with `/2fa/switch`. */\n available_methods: AvailableMethod[];\n}\n\nexport interface TotpSetupRequired {\n stage: \"totp_setup_required\";\n challenge_token: string;\n expires_at: string;\n /** OTPAuth URI rendered as a QR by the consumer. */\n otpauth_url: string;\n /** Same secret base32-encoded — for manual entry alongside QR. */\n secret_base32: string;\n}\n\nexport interface AvailableMethod {\n kind: \"totp\" | \"telegram_otp\" | \"email_otp\";\n /** Short user-facing hint, e.g. `\"Telegram (@user)\"` or `\"e****@example.com\"`. */\n hint?: string;\n}\n\nexport interface TotpVerifyInput {\n challenge_token: string;\n /** 6-digit TOTP code OR `XXXX-XXXX` backup code. */\n code: string;\n}\n\nexport interface OtpVerifyInput {\n challenge_token: string;\n /** 6-digit one-time code delivered via the selected channel. */\n code: string;\n}\n\nexport interface SwitchMethodInput {\n challenge_token: string;\n method: AvailableMethod[\"kind\"];\n}\n\nexport interface RegisterInput {\n email: string;\n password: string;\n /** ISO 4217 code for the new wallet; must be offered by the deployment. */\n wallet_currency?: string;\n}\n\n/** A signed-in session without the login `stage` marker — what\n * `register` returns. */\nexport type Session = Omit<JwtIssued, \"stage\">;\n\nexport interface TotpSetupComplete extends Session {\n /** Ten one-time `XXXX-XXXX` codes, returned only this once. */\n backup_codes: string[];\n}\n\nexport interface ChangePasswordInput {\n current_password: string;\n /** At least 12 characters with a lower-case letter, an upper-case letter\n * and a digit; must differ from the current password. */\n new_password: string;\n}\n\nexport interface OtpSentResponse {\n stage: \"otp_sent\";\n challenge_token: string;\n expires_at: string;\n method: AvailableMethod[\"kind\"];\n hint?: string;\n available_methods: AvailableMethod[];\n}\n\nexport class AuthResource {\n constructor(\n private readonly http: HttpClient,\n private readonly tokens: TokenStore,\n ) {}\n\n /** Password-auth entry. May resolve to a JWT, or to a step-up\n * challenge that needs `verifyTotp` / `verifyOtp` next. */\n async login(input: LoginInput): Promise<LoginResponse> {\n const resp = await this.http.post<LoginResponse>(\"/auth/login\", {\n body: input,\n skipAuth: true,\n });\n if (resp.stage === \"jwt\") {\n await Promise.resolve(this.tokens.set(resp.access_token));\n }\n return resp;\n }\n\n /** Verify a TOTP code (or XXXX-XXXX backup code) against a\n * `totp_required` challenge. On success the JWT is stored. */\n async verifyTotp(input: TotpVerifyInput): Promise<JwtIssued> {\n const resp = await this.http.post<JwtIssued>(\"/auth/login/totp\", {\n body: input,\n skipAuth: true,\n });\n await Promise.resolve(this.tokens.set(resp.access_token));\n return resp;\n }\n\n /** Verify a 6-digit OTP code (Telegram / email) against an\n * `otp_sent` challenge. */\n async verifyOtp(input: OtpVerifyInput): Promise<JwtIssued> {\n const resp = await this.http.post<JwtIssued>(\"/auth/login/otp/verify\", {\n body: input,\n skipAuth: true,\n });\n await Promise.resolve(this.tokens.set(resp.access_token));\n return resp;\n }\n\n /** Create an end-user account and sign it in. The JWT is stored.\n * `wallet_currency` must be one the deployment offers; omit it to take\n * the deployment default (it can be switched later via `client.wallet`\n * while the wallet is empty).\n * Errors: 400 `validation` / `currency_not_allowed`, 409 email taken. */\n async register(input: RegisterInput): Promise<Session> {\n const resp = await this.http.post<Session>(\"/auth/register\", {\n body: input,\n skipAuth: true,\n });\n await Promise.resolve(this.tokens.set(resp.access_token));\n return resp;\n }\n\n /** Finish a `totp_setup_required` login: send the first code from the\n * authenticator app. The JWT is stored. The response carries ten\n * one-time `backup_codes` that are never returned again, so show them to\n * the user right away and don't keep them on the device. */\n async completeTotpSetup(input: TotpVerifyInput): Promise<TotpSetupComplete> {\n const resp = await this.http.post<TotpSetupComplete>(\"/auth/login/totp-setup\", {\n body: input,\n skipAuth: true,\n });\n await Promise.resolve(this.tokens.set(resp.access_token));\n return resp;\n }\n\n /** Change the signed-in user's password. Every other session of the\n * account is signed out; this one stays valid.\n * Errors: 400 when the new password fails the policy, 401 when the\n * current one is wrong. */\n async changePassword(input: ChangePasswordInput): Promise<{ revoked_sessions: number }> {\n return this.http.post<{ revoked_sessions: number }>(\"/auth/password\", {\n body: input,\n });\n }\n\n /** Swap the 2FA method mid-flow. Resolves to `otp_sent` for\n * telegram/email; for TOTP it short-circuits back to the challenge. */\n async switchMethod(input: SwitchMethodInput): Promise<OtpSentResponse> {\n return this.http.post<OtpSentResponse>(\"/auth/login/2fa/switch\", {\n body: input,\n skipAuth: true,\n });\n }\n\n /** Exchange a signed Telegram Mini App `initData` payload for a session\n * JWT. The server validates the initData HMAC against the deployment's bot\n * token, then find-or-creates the end-user. First-time Telegram users are\n * auto-provisioned with `user.email_pending === true` — prompt them for a\n * real email and call {@link linkEmail}. Stores the JWT on success.\n *\n * Most consumers use the higher-level `fromInitData` / `fromTelegramWebApp`\n * helpers in `@takeal/cusfront-sdk/telegram`; reach for this directly when\n * you already hold a configured client. */\n async exchangeTelegram(input: { initData: string }): Promise<JwtIssued> {\n const resp = await this.http.post<JwtIssued>(\"/auth/telegram/exchange\", {\n body: { init_data: input.initData },\n skipAuth: true,\n });\n await Promise.resolve(this.tokens.set(resp.access_token));\n return resp;\n }\n\n /** Attach a real email to the current user (and clear `email_pending`).\n * Used after a Telegram exchange to satisfy the email requirement; also\n * works for a password user changing their address. 409 if taken. */\n async linkEmail(input: { email: string }): Promise<User> {\n return this.http.post<User>(\"/me/email\", { body: { email: input.email } });\n }\n\n /** Current user — fails 401 when the stored JWT is expired or\n * missing. Useful as a \"do I have a session\" probe on app boot. */\n async me(): Promise<User> {\n return this.http.get<User>(\"/auth/me\");\n }\n\n /** Local sign-out: forgets the stored JWT. To end the session on the\n * server as well, revoke it first with `client.sessions.revoke(jti)`\n * (the current one is marked `current: true` in `client.sessions.list()`). */\n async signOut(): Promise<void> {\n await Promise.resolve(this.tokens.clear());\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CustomerInfo } from \"../types/customer.js\";\n\n/**\n * Deposits resource — `client.deposits.*`.\n *\n * The \"money IN\" surface: an end user tops up their wallet balance via a\n * funder connector. Mirrors the Takeal API's `/me/deposits` routes:\n *\n * POST /me/deposits → initiate\n * GET /me/deposits → list (most recent first)\n * GET /me/deposits/{id} → get\n * POST /me/deposits/{id}/refunds → refund\n *\n * A deposit is rarely terminal on the initiate call: real PSPs return\n * `redirect_required` (3DS / APM redirect) and flip to `confirmed` later via\n * a connector → Takeal API inbound event. Poll `get(id)` or watch the user's\n * webhook stream for the `deposit.confirmed` / `deposit.failed` outcome.\n */\n\n/** Lifecycle of a deposit. `redirect_required` carries `redirect_url`. */\nexport type DepositStatus =\n | \"pending\"\n | \"redirect_required\"\n | \"confirmed\"\n | \"failed\";\n\n/** Top-up rail. The chosen funder decides which it supports. */\nexport type DepositMethod = \"card\" | \"crypto\" | \"bank_transfer\";\n\n/**\n * A deposit record as the Takeal API returns it. Mirrors the `deposits` table; the\n * server-side `id` is the stable handle the SDK polls against. `idempotency_key`\n * and `request_fingerprint` are server-internal and never serialised.\n */\n/** Input for `quote()` — price a cross-currency deposit before paying. */\nexport interface CreateQuoteInput {\n /** Decimal string, e.g. `\"5000.00\"`. */\n amount: string;\n /** ISO 4217 source currency — must differ from the wallet's local currency. */\n currency: string;\n}\n\n/**\n * A rate-locked funding quote: pay `source_amount source_currency`, the\n * wallet is credited `credited_amount credited_currency` (net of the\n * platform's conversion spread). Execute by passing `id` as `quote_id` to\n * `initiate()` before `expires_at`; after that the API returns 409 and a new\n * quote is needed.\n */\nexport interface FundingQuote {\n id: string;\n source_amount: string;\n source_currency: string;\n credited_amount: string;\n credited_currency: string;\n /** Provider rate before spread (credited units per 1 source unit). */\n rate: string;\n spread_bps: number;\n provider: string;\n expires_at: string;\n}\n\nexport interface Deposit {\n id: string;\n user_id: string;\n /** Slug of the funder that handled this deposit, as configured by the deployment. */\n connector_slug: string;\n /** The connector's own reference, populated once it responds. */\n provider_reference: string | null;\n status: DepositStatus;\n /** Decimal serialised as a string to avoid float drift. */\n amount: string;\n currency: string;\n method: DepositMethod;\n /** Present when `status === \"redirect_required\"` — send the user here. */\n redirect_url: string | null;\n failure_reason: string | null;\n /** Final settled amount once confirmed (may differ from `amount` on FX). */\n confirmed_amount: string | null;\n confirmed_at: string | null;\n /** Set on cross-currency deposits: the quote this deposit executed against. */\n quote_id?: string | null;\n /** Locked provider rate (credited units per 1 source unit). */\n fx_rate?: string | null;\n fx_spread_bps?: number | null;\n /** The wallet's local currency the deposit converted into. */\n credited_currency?: string | null;\n /** What the wallet was actually credited, net of spread. */\n credited_amount?: string | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface InitiateDepositInput {\n /** Decimal as a string (`\"100.00\"`) — avoids float-precision loss on the wire. */\n amount: string;\n /** ISO 4217 code, e.g. `\"USD\"`. */\n currency: string;\n method: DepositMethod;\n /**\n * Optional. Slug of a specific funder to route through. Omit to\n * let the Takeal API pick the first active funder. Unknown slug → 400; empty\n * funder list → 503.\n */\n funder_slug?: string;\n /** Provider-specific extras. The mock funder reads `mock_scenario`. */\n metadata?: Record<string, string>;\n /** Structured billing details — real PSPs require these for 3DS / compliance. */\n customer?: CustomerInfo;\n /**\n * Required by the Takeal API on this write endpoint. Same key + body replays the\n * original deposit; same key + different body returns 409. Supply a stable\n * UUID per logical attempt so a retried network call is safe.\n */\n idempotencyKey: string;\n /**\n * Required when `currency` differs from the wallet's local currency: a\n * fresh quote id from `quote()`. Cross-currency deposits without one are\n * rejected with 400; expired quotes with 409.\n */\n quote_id?: string;\n}\n\nexport interface CreateDepositRefundInput {\n /** Omit for a full refund of the original confirmed amount; same currency. */\n amount?: string;\n /** Human-readable reason, e.g. `\"customer_request\"`. */\n reason?: string;\n metadata?: Record<string, string>;\n /** Required. Replays are keyed on this. */\n idempotencyKey: string;\n}\n\n/** A refund row as the Takeal API returns it (`refunds` table, deposit-targeted). */\nexport interface Refund {\n id: string;\n target_type: string;\n deposit_id?: string;\n payment_id?: string;\n connector_slug: string;\n amount: string;\n currency: string;\n reason: string;\n status: string;\n provider_refund_reference?: string;\n failure_reason?: string;\n requestor_type: string;\n requestor_id: string;\n created_at: string;\n updated_at: string;\n}\n\nexport class DepositsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Initiate a top-up. Resolves to the freshly-created `Deposit`, whose\n * `status` may already be `confirmed` (synchronous rails / mock) or\n * `redirect_required` (3DS / APM — forward the user to `redirect_url`).\n */\n /**\n * Price a cross-currency deposit BEFORE paying. The rate is locked\n * server-side until `expires_at`; deposits in the local currency need no\n * quote (the API answers 400 `no_quote_needed`).\n */\n async quote(input: CreateQuoteInput): Promise<FundingQuote> {\n return this.http.post<FundingQuote>(\"/me/deposits/quotes\", { body: input });\n }\n\n async initiate(input: InitiateDepositInput): Promise<Deposit> {\n const { idempotencyKey, ...body } = input;\n return this.http.post<Deposit>(\"/me/deposits\", {\n body,\n idempotencyKey,\n });\n }\n\n /** Fetch one deposit by id — the poll target while a redirect resolves. */\n async get(id: string): Promise<Deposit> {\n return this.http.get<Deposit>(`/me/deposits/${encodeURIComponent(id)}`);\n }\n\n /** List the caller's deposits, most recent first. */\n async list(): Promise<Deposit[]> {\n return this.http.get<Deposit[]>(\"/me/deposits\");\n }\n\n /**\n * Refund a previously-confirmed deposit. Synchronous when the\n * connector settles inline; otherwise the row stays `pending` and flips\n * later via the inbound `deposit.refunded` event.\n */\n async refund(\n depositId: string,\n input: CreateDepositRefundInput,\n ): Promise<Refund> {\n const { idempotencyKey, ...body } = input;\n return this.http.post<Refund>(\n `/me/deposits/${encodeURIComponent(depositId)}/refunds`,\n { body, idempotencyKey },\n );\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CustomerInfo } from \"../types/customer.js\";\n\n/**\n * Cards resource — `client.cards.*`.\n *\n * The end-user \"money OUT\" surface: a user issues themselves a card backed by\n * their wallet balance via an issuer connector. Mirrors the Takeal API's\n * `/me/cards` routes:\n *\n * POST /me/cards → create\n * GET /me/cards → list (most recent first)\n * GET /me/cards/{id} → get\n * GET /me/cards/{id}/balance → balance (prepaid remaining)\n * POST /me/cards/{id}/freeze → freeze\n * POST /me/cards/{id}/unfreeze → unfreeze\n * POST /me/cards/{id}/terminate → terminate (one-way)\n *\n * The lifecycle actions are ownership-gated server-side: a caller can only\n * freeze / unfreeze / terminate a card that belongs to them (else 404).\n *\n * ## What is intentionally NOT here\n *\n * Card-data reveal (PAN / CVV) is a separate, security-sensitive flow with its\n * own re-auth + rate-limit + audit contract and is intentionally\n * NOT part of this resource (tracked separately).\n *\n * Today only PREPAID is wired end-to-end; CREDIT and GIFT return 400 from\n * the Takeal API until their issuer flows land.\n */\n\n/** Card product. Only `prepaid` is fully implemented today. */\nexport type CardType = \"credit\" | \"prepaid\" | \"gift\";\n\n/**\n * Card lifecycle state.\n *\n * `pending_payment` is a transient state: the row exists but the\n * per-card issuance-fee debit has not yet succeeded; such cards have no\n * provider reference and no user-visible side effects.\n */\nexport type CardStatus =\n | \"pending_payment\"\n | \"active\"\n | \"frozen\"\n | \"terminated\"\n | \"redeemed\"\n | \"failed\";\n\n/**\n * A card record as the Takeal API returns it. Mirrors the `cards` table. Note the\n * SDK never receives the full PAN or CVV here — only `last4` + expiry. The\n * gift-card `redemption_code` is returned exactly once (on create) and\n * scrubbed from subsequent list/get responses.\n */\nexport interface Card {\n id: string;\n user_id: string;\n card_type: CardType;\n /** Slug of the issuer that minted this card, as configured by the deployment. */\n connector_slug: string;\n /** The connector's own reference, populated once it responds. */\n provider_reference: string | null;\n status: CardStatus;\n /** Last four digits of the PAN — safe to display. */\n last4: string | null;\n expiry_month: number | null;\n expiry_year: number | null;\n /** Gift cards only, present once on create then scrubbed. */\n redemption_code?: string;\n /** Decimal as a string. */\n initial_amount: string | null;\n currency: string;\n failure_reason: string | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface CreateCardInput {\n /** `prepaid` (the only fully-wired type today), `credit`, or `gift`. */\n type: CardType;\n /** Decimal as a string. The prepaid load amount drained from wallet balance. */\n initial_amount?: string;\n /** ISO 4217 code, e.g. `\"USD\"`. */\n currency: string;\n /**\n * Optional. Slug of a specific issuer to mint with. Omit to let\n * the Takeal API pick the first active issuer. Unknown slug → 400; empty issuer\n * list → 503.\n */\n issuer_slug?: string;\n metadata?: Record<string, string>;\n /** Structured billing details — real issuers require these for 3DS / KYC. */\n customer?: CustomerInfo;\n /**\n * Required by the Takeal API on this write endpoint. Same key + body replays the\n * original card; same key + different body returns 409.\n */\n idempotencyKey: string;\n}\n\n/** Remaining balance of a prepaid card. */\nexport interface CardBalance {\n amount: string;\n currency: string;\n}\n\n/** Re-auth gate for {@link CardsResource.reveal}. */\nexport interface RevealCardInput {\n /** The user's account password — mandatory re-auth. */\n password: string;\n /** TOTP code; required only when the user has TOTP enrolled. */\n totpCode?: string;\n}\n\n/**\n * Full card data from a successful reveal. **Security**: never persist this —\n * keep it in volatile memory only, clear it within `expires_in_seconds`, and\n * never write it to localStorage / logs (the API marks the response no-store).\n */\nexport interface RevealedCard {\n pan: string;\n cvv: string;\n expiry_month: number;\n expiry_year: number;\n holder_name: string;\n /** Display window before the client should auto-clear the data. */\n expires_in_seconds: number;\n}\n\nexport class CardsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Issue a card backed by the user's wallet balance. Resolves to the new\n * `Card`. On a ledger failure after provider creation, the Takeal API rolls the row\n * to `failed` (never an orphaned active card); inspect `status` /\n * `failure_reason` on the result.\n */\n async create(input: CreateCardInput): Promise<Card> {\n const { idempotencyKey, ...body } = input;\n return this.http.post<Card>(\"/me/cards\", {\n body,\n idempotencyKey,\n });\n }\n\n /** Fetch one card by id. */\n async get(id: string): Promise<Card> {\n return this.http.get<Card>(`/me/cards/${encodeURIComponent(id)}`);\n }\n\n /** List the caller's cards, most recent first. */\n async list(): Promise<Card[]> {\n return this.http.get<Card[]>(\"/me/cards\");\n }\n\n /**\n * Remaining balance of a prepaid card. `currency` is required by the Takeal API and\n * forwarded as a query param.\n */\n async balance(id: string, currency: string): Promise<CardBalance> {\n const q = new URLSearchParams({ currency }).toString();\n return this.http.get<CardBalance>(\n `/me/cards/${encodeURIComponent(id)}/balance?${q}`,\n );\n }\n\n /**\n * Freeze the caller's own card. Reversible via {@link unfreeze}. The optional\n * `reason` is recorded on the audit trail. Resolves to the updated card.\n * 404 if the card isn't the caller's; 501 if the issuer can't freeze.\n */\n async freeze(id: string, reason?: string): Promise<Card> {\n return this.http.post<Card>(\n `/me/cards/${encodeURIComponent(id)}/freeze`,\n { body: { reason } },\n );\n }\n\n /**\n * Reveal the FULL PAN + CVV for the caller's own card. Re-auth gated\n * (password, + TOTP when the user has it enrolled) and rate-limited\n * server-side. The Takeal API never persists this data and marks the\n * response no-store; the SDK returns it verbatim and holds nothing.\n *\n * **Consumer security duties** (the SDK can't enforce these for you):\n * keep the result in volatile memory only, never write it to\n * localStorage / logs, and clear it within `expires_in_seconds`.\n *\n * 401 bad re-auth · 403 not your card · 429 rate-limited · 501 connector\n * has no sensitive-data endpoint · 503 provider error.\n */\n async reveal(id: string, input: RevealCardInput): Promise<RevealedCard> {\n return this.http.post<RevealedCard>(\n `/me/cards/${encodeURIComponent(id)}/reveal`,\n { body: { password: input.password, totp_code: input.totpCode } },\n );\n }\n\n /** Unfreeze a previously-frozen card. Idempotent on an already-active card. */\n async unfreeze(id: string): Promise<Card> {\n return this.http.post<Card>(\n `/me/cards/${encodeURIComponent(id)}/unfreeze`,\n { body: {} },\n );\n }\n\n /**\n * Terminate the caller's own card. **One-way** — a terminated card cannot be\n * reactivated. The optional `reason` is audited. Idempotent on an\n * already-terminated card.\n */\n async terminate(id: string, reason?: string): Promise<Card> {\n return this.http.post<Card>(\n `/me/cards/${encodeURIComponent(id)}/terminate`,\n { body: { reason } },\n );\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Balance resource — `client.balance.*`.\n *\n * The user's wallet balance, tracked in the ledger. Mirrors the Takeal API's\n * `GET /me/balance[?currency=<code>]` route. Balances are per-currency; with\n * no `currency` the wallet's own currency is returned (see `client.wallet`).\n */\n\n/** Wallet balance for one currency. `amount` is a decimal string. */\nexport interface Balance {\n amount: string;\n currency: string;\n}\n\nexport class BalanceResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Fetch the user's wallet balance. Omit `currency` for the wallet's own\n * currency; pass an ISO 4217 code (e.g. `\"USD\"`) to read another one —\n * the ledger holds a separate balance per currency.\n */\n async get(currency?: string): Promise<Balance> {\n if (!currency) return this.http.get<Balance>(\"/me/balance\");\n const q = new URLSearchParams({ currency }).toString();\n return this.http.get<Balance>(`/me/balance?${q}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Branding resource — `client.branding.*`.\n *\n * Runtime white-label config published by the deployment at `GET /branding`\n * (public, no auth). Lets a Cusfront re-theme itself on the fly — platform\n * name, logo, favicon, brand colours and the label used for the end-user's balance — without\n * a rebuild. Pairs with the build-time `BrandConfig`: the server-side values\n * win whenever both are present.\n */\n\n/** Public brand config of the deployment. All strings; empty = use the client default. */\nexport interface Branding {\n /** Platform display name (e.g. the white-label brand). */\n platform_name: string;\n /** Name of the merchant-facing portal. */\n merchant_portal_name: string;\n /** Logo image — absolute URL or `data:` URI. Empty → client default. */\n logo_url: string;\n /** Favicon — absolute URL or `data:` URI. Empty → client default. */\n favicon_url: string;\n /** User-facing name of the balance, e.g. `\"Wallet\"` or `\"Acme Wallet\"`.\n * Display-only: the `balance` API shape never changes with it. */\n wallet_label: string;\n /** Primary brand colour as `#rrggbb`. Empty → client default palette. */\n primary_color: string;\n /** Secondary brand colour as `#rrggbb`. Empty → client default palette. */\n secondary_color: string;\n /** Accent colour as `#rrggbb`. Empty → client default palette. */\n accent_color: string;\n}\n\nexport class BrandingResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Fetch the deployment's public brand config. Safe to call before login. */\n async get(opts: { signal?: AbortSignal } = {}): Promise<Branding> {\n return this.http.get<Branding>(\"/branding\", { skipAuth: true, signal: opts.signal });\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Wallet resource — `client.wallet.*`.\n *\n * Which currency the user's wallet is held in. Deposits in any other\n * currency are converted on funding (quote first, see `client.deposits`);\n * cards issued in another currency are paid from the wallet with an FX leg\n * at issuance. A user may switch currency only while every balance is zero\n * and only to a currency the deployment offers (`allowed`).\n */\n\n/** The user's wallet currency and what they may switch to. */\nexport interface Wallet {\n /** ISO 4217 code the wallet is held in. */\n currency: string;\n /** `true` when chosen by the user (or set by an operator), `false` when it\n * is the deployment default. */\n explicit: boolean;\n /** Currencies accepted by `set()`. */\n allowed: string[];\n}\n\nexport class WalletResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Current wallet currency + the currencies the user may switch to. */\n async get(opts: { signal?: AbortSignal } = {}): Promise<Wallet> {\n return this.http.get<Wallet>(\"/me/wallet\", { signal: opts.signal });\n }\n\n /**\n * Switch the wallet currency. Fails with `409 wallet_not_empty` while any\n * balance is non-zero, and `400 currency_not_allowed` for a currency the\n * deployment does not offer.\n */\n async set(currency: string, opts: { signal?: AbortSignal } = {}): Promise<Wallet> {\n return this.http.put<Wallet>(\"/me/wallet\", { body: { currency }, signal: opts.signal });\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Blog resource — `client.blog.*`.\n *\n * Posts are public: these calls work before the user logs in, which is what\n * a marketing page or a Mini App landing screen needs.\n *\n * A post arrives as a **structured document**, not as HTML. `body_blocks` is\n * a flat list of typed nodes; map each `type` onto your own component and the\n * post inherits your site's styling. `body_markdown` is there too if you'd\n * rather run your own renderer.\n *\n * ```ts\n * const { posts } = await client.blog.list({ perPage: 5 });\n * const post = await client.blog.get(posts[0].slug);\n *\n * post.body_blocks.map((b) => {\n * switch (b.type) {\n * case \"heading\": return <Heading level={b.level}>{b.text}</Heading>;\n * case \"paragraph\": return <P>{b.text}</P>;\n * case \"image\": return <Figure src={b.url} alt={b.alt} caption={b.caption} />;\n * case \"list\": return <List ordered={b.ordered} items={b.items} />;\n * case \"quote\": return <Quote>{b.text}</Quote>;\n * case \"code\": return <Code lang={b.lang}>{b.text}</Code>;\n * case \"divider\": return <Hr />;\n * }\n * });\n * ```\n *\n * Inline emphasis (`**bold**`, `[link](url)`) is left as Markdown inside\n * block text — every renderer already knows what to do with it.\n */\n\n/** One node of a post body. Discriminated on `type`. */\nexport type BlogBlock =\n | { type: \"heading\"; level: number; text: string }\n | { type: \"paragraph\"; text: string }\n | { type: \"image\"; url: string; alt?: string; caption?: string }\n | { type: \"list\"; ordered: boolean; items: string[] }\n | { type: \"quote\"; text: string }\n | { type: \"code\"; lang?: string; text: string }\n | { type: \"divider\" };\n\nexport interface BlogPost {\n /** Stable public key — link by this. */\n slug: string;\n title: string;\n /** Teaser for cards; falls back to the first paragraph. */\n excerpt: string;\n /** Image URL, relative to the API origin. Absent when no cover is set. */\n cover_url?: string;\n /** Raw Markdown, for consumers that bring their own renderer. */\n body_markdown: string;\n /** The recommended input for rendering — see the module docs. */\n body_blocks: BlogBlock[];\n tags: string[];\n /** Present only when the post declares one. */\n locale?: string;\n /** Rough read time in minutes (minimum 1). */\n reading_minutes: number;\n published_at: string | null;\n updated_at: string;\n}\n\nexport interface BlogListInput {\n /** 1-based. Default 1. */\n page?: number;\n /** 1..=50. Default 10. */\n perPage?: number;\n /** Only posts carrying this tag. */\n tag?: string;\n /** Only posts in this locale. */\n locale?: string;\n}\n\nexport interface BlogList {\n posts: BlogPost[];\n total: number;\n page: number;\n per_page: number;\n}\n\nexport class BlogResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Published posts, newest first. No authentication required. */\n async list(input: BlogListInput = {}): Promise<BlogList> {\n const q = new URLSearchParams();\n if (input.page) q.set(\"page\", String(input.page));\n if (input.perPage) q.set(\"per_page\", String(input.perPage));\n if (input.tag) q.set(\"tag\", input.tag);\n if (input.locale) q.set(\"locale\", input.locale);\n const qs = q.toString();\n return this.http.get<BlogList>(`/blog/posts${qs ? `?${qs}` : \"\"}`, {\n skipAuth: true,\n });\n }\n\n /** One post by slug. No authentication required. */\n async get(slug: string): Promise<BlogPost> {\n return this.http.get<BlogPost>(`/blog/posts/${encodeURIComponent(slug)}`, {\n skipAuth: true,\n });\n }\n\n /**\n * Absolute URL for an image path returned inside a post (`cover_url`, or an\n * image block's `url`). Handy when the app renders on a different origin\n * than the API.\n */\n imageUrl(baseUrl: string, path: string): string {\n if (/^https?:\\/\\//i.test(path)) return path;\n return `${baseUrl.replace(/\\/$/, \"\")}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Subscriptions resource — `client.subscriptions.*`.\n *\n * Which channels the signed-in user agreed to receive announcements on.\n * `available` tells you which toggles to render: a deployment with no\n * Telegram bot configured can't deliver there, so offering the switch would\n * be a lie.\n *\n * ```ts\n * const { channels, available } = await client.subscriptions.get();\n * await client.subscriptions.set([...channels, \"telegram\"]);\n * ```\n *\n * Unrelated to paid/VIP tiers — this is only about announcements.\n */\n\nexport type BroadcastChannel = \"email\" | \"telegram\" | (string & {});\n\nexport interface Subscriptions {\n /** Channels the user currently receives announcements on. */\n channels: BroadcastChannel[];\n /** Channels this deployment can actually deliver on. */\n available: BroadcastChannel[];\n}\n\nexport class SubscriptionsResource {\n constructor(private readonly http: HttpClient) {}\n\n async get(): Promise<Subscriptions> {\n return this.http.get<Subscriptions>(\"/me/subscriptions\");\n }\n\n /**\n * Replace the whole set — this is a PUT, not a merge. Pass `[]` to opt out\n * of everything.\n */\n async set(channels: BroadcastChannel[]): Promise<Subscriptions> {\n return this.http.put<Subscriptions>(\"/me/subscriptions\", {\n body: { channels },\n });\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Sessions resource — `client.sessions.*`.\n *\n * Every device or browser the user is signed in on. Lets a settings screen\n * show \"where you're signed in\" and sign one or all of them out.\n *\n * ```ts\n * const sessions = await client.sessions.list();\n * const others = sessions.filter((s) => !s.current);\n * await client.sessions.revokeOthers();\n * ```\n */\n\nexport interface UserSession {\n /** Session id; pass it to `revoke`. */\n jti: string;\n issued_at: string;\n expires_at: string;\n last_seen_at: string;\n /** Client IP recorded for the session, if known. */\n remote_ip?: string | null;\n /** Browser or app that opened the session, if known. */\n user_agent?: string | null;\n /** `true` for the session this client is using. */\n current: boolean;\n}\n\nexport class SessionsResource {\n constructor(private readonly http: HttpClient) {}\n\n /** All live sessions of the account, this one included. */\n async list(): Promise<UserSession[]> {\n return this.http.get<UserSession[]>(\"/me/sessions\");\n }\n\n /** Sign out one session. Works on the current one too; the stored JWT\n * stops working, so follow with `client.auth.signOut()`.\n * 404 when the session is unknown or already signed out. */\n async revoke(jti: string): Promise<void> {\n await this.http.delete<void>(`/me/sessions/${encodeURIComponent(jti)}`);\n }\n\n /** Sign out every session except this one. */\n async revokeOthers(): Promise<{ revoked_sessions: number }> {\n return this.http.post<{ revoked_sessions: number }>(\"/me/sessions/terminate-others\");\n }\n}\n","import type { HttpClient } from \"../http.js\";\n\n/**\n * Push resource — `client.push.*`.\n *\n * Web Push for the signed-in user. The API keeps one subscription per user\n * (the newest wins) and sends a notification for the user's own events:\n * a confirmed deposit, a card transaction and so on.\n *\n * The usual browser flow is one call:\n *\n * ```ts\n * const reg = await navigator.serviceWorker.ready;\n * if ((await Notification.requestPermission()) === \"granted\") {\n * await client.push.enable(reg);\n * }\n * ```\n *\n * Your service worker shows the notification: the payload is JSON with\n * `title`, `body` and `url` (where a click should lead).\n */\n\nexport interface PushStatus {\n /** `true` when a subscription is stored for this user. */\n subscribed: boolean;\n /** Host of the stored endpoint, e.g. `fcm.googleapis.com`. */\n endpoint_host?: string | null;\n /** VAPID public key (URL-safe base64) for `pushManager.subscribe`.\n * `null` when push is not set up on this deployment. */\n vapid_public_key?: string | null;\n}\n\nexport interface PushSubscriptionInput {\n /** `PushSubscription.endpoint`; must be https. */\n endpoint: string;\n keys: {\n /** URL-safe base64. */\n p256dh: string;\n /** URL-safe base64. */\n auth: string;\n };\n}\n\n/** The part of `ServiceWorkerRegistration` the SDK needs. Typed\n * structurally so the core stays free of DOM lib types. */\nexport interface PushCapableRegistration {\n pushManager: {\n getSubscription(): Promise<{ unsubscribe(): Promise<boolean> } | null>;\n subscribe(options: {\n userVisibleOnly: boolean;\n applicationServerKey: Uint8Array;\n }): Promise<{ toJSON(): { endpoint?: string; keys?: Record<string, string> } }>;\n };\n}\n\nexport class PushResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Whether the user is subscribed, plus the VAPID key to subscribe with. */\n async status(): Promise<PushStatus> {\n return this.http.get<PushStatus>(\"/me/push-subscription\");\n }\n\n /** Store a subscription you created yourself.\n * 409 `push_disabled` when the deployment has no VAPID keys. */\n async save(input: PushSubscriptionInput): Promise<PushStatus> {\n return this.http.put<PushStatus>(\"/me/push-subscription\", { body: input });\n }\n\n /** Delete the stored subscription. Safe when nothing is stored. */\n async remove(): Promise<void> {\n await this.http.delete<void>(\"/me/push-subscription\");\n }\n\n /** Subscribe this browser and store the subscription. Ask for\n * notification permission before calling. Throws when push isn't set up\n * on the deployment. */\n async enable(registration: PushCapableRegistration): Promise<PushStatus> {\n const { vapid_public_key } = await this.status();\n if (!vapid_public_key) {\n throw new Error(\"@takeal/cusfront-sdk: push notifications are not enabled on this deployment\");\n }\n const sub = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: base64UrlToBytes(vapid_public_key),\n });\n const json = sub.toJSON();\n if (!json.endpoint || !json.keys?.p256dh || !json.keys.auth) {\n throw new Error(\"@takeal/cusfront-sdk: the browser returned an incomplete push subscription\");\n }\n return this.save({\n endpoint: json.endpoint,\n keys: { p256dh: json.keys.p256dh, auth: json.keys.auth },\n });\n }\n\n /** Unsubscribe this browser and delete the stored subscription. */\n async disable(registration: PushCapableRegistration): Promise<void> {\n const sub = await registration.pushManager.getSubscription();\n if (sub) await sub.unsubscribe();\n await this.remove();\n }\n}\n\n/** URL-safe base64 (padding optional) → bytes. */\nexport function base64UrlToBytes(input: string): Uint8Array {\n const b64 = input.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = b64 + \"=\".repeat((4 - (b64.length % 4)) % 4);\n const bin = atob(padded);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n","/**\n * Pluggable storage for the JWT.\n *\n * Default behaviour by environment:\n * - browser → `localStorage` (synchronous, persists across reloads)\n * - Node / SSR / worker → in-memory (no global state to leak)\n * - mobile (Capacitor / RN) → consumer must inject Keychain /\n * EncryptedSharedPreferences via `createClient({ tokenStore })`\n *\n * The store is intentionally tiny — three methods, no eviction\n * policy, no encryption. Encryption is the consumer's call (mobile\n * adapters wrap platform-native secure storage). Persistence shape\n * is opaque to the SDK; tokens are passed through verbatim.\n */\nexport interface TokenStore {\n get(): string | null | Promise<string | null>;\n set(token: string): void | Promise<void>;\n clear(): void | Promise<void>;\n}\n\n/** Sync `localStorage`-backed store. Falls through to in-memory when\n * `window.localStorage` is unavailable (private mode quota, SSR). */\nexport function defaultBrowserStore(key = \"takeal_jwt\"): TokenStore {\n const fallback = inMemoryStore();\n // Probe once at construction — avoid the try/catch on every call.\n let usable = false;\n try {\n if (typeof globalThis !== \"undefined\" && \"localStorage\" in globalThis) {\n const ls = (globalThis as { localStorage: Storage }).localStorage;\n const probe = \"__takeal_probe__\";\n ls.setItem(probe, \"1\");\n ls.removeItem(probe);\n usable = true;\n }\n } catch {\n usable = false;\n }\n if (!usable) return fallback;\n const ls = (globalThis as { localStorage: Storage }).localStorage;\n return {\n get: () => ls.getItem(key),\n set: (token) => ls.setItem(key, token),\n clear: () => ls.removeItem(key),\n };\n}\n\n/** In-memory store. Use for SSR / tests / when persistence isn't\n * desired (e.g. ephemeral kiosk sessions). */\nexport function inMemoryStore(): TokenStore {\n let value: string | null = null;\n return {\n get: () => value,\n set: (token) => {\n value = token;\n },\n clear: () => {\n value = null;\n },\n };\n}\n","/**\n * `@takeal/cusfront-sdk` — typed client for the Takeal end-user API.\n *\n * Entry point: `createClient({ baseUrl, brand?, tokenStore?, fetch? })`.\n * Resources are accessed off the returned client (`client.auth.login`,\n * `client.cards.list`, …). Sub-exports under `@takeal/cusfront-sdk/<resource>`\n * publish each resource independently so a Cusfront only pulls what\n * it imports.\n *\n * Brand-neutral by design. No customer / deployment names embedded.\n * Brand swap happens at runtime via `BrandConfig`.\n */\n\nimport { HttpClient, type FetchLike } from \"./http.js\";\nimport { AuthResource } from \"./resources/auth.js\";\nimport { DepositsResource } from \"./resources/deposits.js\";\nimport { CardsResource } from \"./resources/cards.js\";\nimport { BalanceResource } from \"./resources/balance.js\";\nimport { BrandingResource } from \"./resources/branding.js\";\nimport { WalletResource } from \"./resources/wallet.js\";\nimport { BlogResource } from \"./resources/blog.js\";\nimport { SubscriptionsResource } from \"./resources/subscriptions.js\";\nimport { SessionsResource } from \"./resources/sessions.js\";\nimport { PushResource } from \"./resources/push.js\";\nimport {\n defaultBrowserStore,\n inMemoryStore,\n type TokenStore,\n} from \"./token-store.js\";\nimport type { BrandConfig } from \"./brand.js\";\n\nexport type { BrandConfig } from \"./brand.js\";\nexport { ApiError, NetworkError, isApiError, isNetworkError } from \"./error.js\";\nexport { defaultBrowserStore, inMemoryStore, type TokenStore } from \"./token-store.js\";\n\n// Re-export resource types so consumers can `import { Deposit } from\n// \"@takeal/cusfront-sdk\"` without reaching into sub-paths.\nexport type { Address, CustomerInfo } from \"./types/customer.js\";\nexport type {\n Deposit,\n DepositStatus,\n DepositMethod,\n InitiateDepositInput,\n CreateDepositRefundInput,\n Refund,\n CreateQuoteInput, FundingQuote } from \"./resources/deposits.js\";\nexport type {\n Card,\n CardType,\n CardStatus,\n CreateCardInput,\n CardBalance,\n RevealCardInput,\n RevealedCard,\n} from \"./resources/cards.js\";\nexport type { Balance } from \"./resources/balance.js\";\nexport type { Branding } from \"./resources/branding.js\";\nexport type { Wallet } from \"./resources/wallet.js\";\nexport type { BlogPost, BlogBlock, BlogList, BlogListInput } from \"./resources/blog.js\";\nexport type {\n Subscriptions,\n BroadcastChannel,\n} from \"./resources/subscriptions.js\";\nexport type {\n User,\n LoginInput,\n LoginResponse,\n JwtIssued,\n TotpRequired,\n TotpSetupRequired,\n OtpSentResponse,\n RegisterInput,\n Session,\n TotpSetupComplete,\n ChangePasswordInput,\n} from \"./resources/auth.js\";\nexport type { UserSession } from \"./resources/sessions.js\";\nexport type {\n PushStatus,\n PushSubscriptionInput,\n PushCapableRegistration,\n} from \"./resources/push.js\";\n\nexport interface CreateClientOptions {\n /** Absolute origin of the Takeal API deployment, no trailing slash.\n * e.g. `\"https://api.takeal.example.com\"`. */\n baseUrl: string;\n /** Runtime brand config. Optional; consumer renders its own brand\n * if omitted. */\n brand?: BrandConfig;\n /** Token persistence. Defaults to `defaultBrowserStore()` when\n * `window.localStorage` is present, else `inMemoryStore()`. */\n tokenStore?: TokenStore;\n /** Override the `fetch` implementation — useful for Node < 18,\n * React Native < 0.74, MSW intercept layers, etc. */\n fetch?: FetchLike;\n /** When true, the SDK runs every response through a zod schema\n * before handing it to the caller. Requires `zod` >= 3.22 as a\n * peer dep. Off by default; types-only validation is sufficient\n * for the steady-state case. */\n validate?: boolean;\n}\n\nexport interface CusfrontClient {\n /** Read-only brand config — pass through from createClient args. */\n readonly brand: BrandConfig | undefined;\n /** Auth resource: login, refresh, current user, logout. */\n readonly auth: AuthResource;\n /** Deposits (money IN via a funder connector): initiate, get, list, refund. */\n readonly deposits: DepositsResource;\n /** Cards (money OUT via an issuer connector): create, get, list, balance. */\n readonly cards: CardsResource;\n /** Wallet balance lookup (defaults to the wallet's own currency). */\n readonly balance: BalanceResource;\n /** The wallet's currency: read it, switch it while the wallet is empty. */\n readonly wallet: WalletResource;\n /** Runtime white-label config (`GET /branding`, public): names, logo, wallet label. */\n readonly branding: BrandingResource;\n /** Public blog posts, returned as structured blocks to render in your own style. */\n readonly blog: BlogResource;\n /** The user's announcement channel subscriptions. */\n readonly subscriptions: SubscriptionsResource;\n /** Where the user is signed in: list sessions, sign one or all others out. */\n readonly sessions: SessionsResource;\n /** Web Push subscription for the signed-in user. */\n readonly push: PushResource;\n /** Direct access to the token store (e.g. for an explicit sign-out\n * on Capacitor's lifecycle \"app pausing\" event). */\n readonly tokens: TokenStore;\n}\n\n/**\n * Build a new client. Stateless across calls — multiple clients can\n * coexist (e.g. an admin Cusfront with a different baseUrl than the\n * end-user one). Each gets its own `TokenStore`.\n *\n * `validate: true` is honoured by individual resources that ship\n * matching zod schemas; resources without a schema ignore it.\n */\nexport function createClient(opts: CreateClientOptions): CusfrontClient {\n const tokens = opts.tokenStore ?? pickDefaultStore();\n const fetchImpl = opts.fetch ?? defaultFetch();\n const http = new HttpClient(opts.baseUrl, tokens, fetchImpl);\n\n return {\n brand: opts.brand,\n tokens,\n auth: new AuthResource(http, tokens),\n deposits: new DepositsResource(http),\n cards: new CardsResource(http),\n balance: new BalanceResource(http),\n wallet: new WalletResource(http),\n branding: new BrandingResource(http),\n blog: new BlogResource(http),\n subscriptions: new SubscriptionsResource(http),\n sessions: new SessionsResource(http),\n push: new PushResource(http),\n };\n}\n\nfunction pickDefaultStore(): TokenStore {\n if (typeof globalThis !== \"undefined\" && \"localStorage\" in globalThis) {\n return defaultBrowserStore();\n }\n return inMemoryStore();\n}\n\nfunction defaultFetch(): FetchLike {\n if (typeof globalThis !== \"undefined\" && typeof globalThis.fetch === \"function\") {\n // Bind to globalThis so `this` is correct inside the implementation\n // (some polyfills choke on a detached reference).\n return globalThis.fetch.bind(globalThis);\n }\n throw new Error(\n \"@takeal/cusfront-sdk: native fetch is not available in this runtime. \" +\n \"Pass a polyfill via createClient({ fetch }).\",\n );\n}\n","/**\n * `@takeal/cusfront-sdk/telegram` — Telegram Mini App adapter.\n *\n * A Mini App receives a signed `initData` string from the Telegram client\n * (`window.Telegram.WebApp.initData`). This module turns that string into an\n * authenticated SDK client:\n *\n * import { fromTelegramWebApp } from \"@takeal/cusfront-sdk/telegram\";\n * const client = await fromTelegramWebApp({ baseUrl: \"https://api.example.com\" });\n * const me = await client.auth.me(); // me.email_pending? prompt for email\n *\n * Signature validation: the HMAC over `initData` can only be verified with the\n * bot token, which lives on the server. So the **authoritative** check happens\n * server-side at `POST /auth/telegram/exchange`. Here we only do a structural,\n * fail-fast well-formedness check (`hash` + `auth_date` present, not stale)\n * before spending a network round-trip on an obviously-bad payload.\n */\n\nimport {\n createClient,\n type CreateClientOptions,\n type CusfrontClient,\n} from \"./index.js\";\nimport type { JwtIssued } from \"./resources/auth.js\";\n\n/** The Telegram `user` object embedded (URL-encoded JSON) in initData. */\nexport interface TelegramUser {\n id: number;\n first_name?: string;\n last_name?: string;\n username?: string;\n language_code?: string;\n photo_url?: string;\n is_premium?: boolean;\n}\n\n/** Structurally-parsed initData. `raw` is the original string passed to the\n * server verbatim — the server re-derives the HMAC from it, so we never\n * re-serialise. */\nexport interface ParsedInitData {\n raw: string;\n params: Record<string, string>;\n hash?: string;\n auth_date?: number;\n query_id?: string;\n user?: TelegramUser;\n}\n\n/** Thrown by {@link assertWellFormed} when initData is structurally invalid or\n * stale. A signature mismatch is NOT detectable here (no bot token) — that\n * surfaces as a 401 `ApiError` from the exchange call instead. */\nexport class InitDataError extends Error {\n constructor(\n message: string,\n readonly reason:\n | \"empty\"\n | \"missing_hash\"\n | \"missing_auth_date\"\n | \"bad_user\"\n | \"stale\",\n ) {\n super(message);\n this.name = \"InitDataError\";\n }\n}\n\n/** Parse a raw `initData` query string into its fields (best-effort — does\n * not validate). `user` is JSON-decoded when present and parseable. */\nexport function parseInitData(initData: string): ParsedInitData {\n const params: Record<string, string> = {};\n const sp = new URLSearchParams(initData);\n for (const [k, v] of sp.entries()) params[k] = v;\n\n let user: TelegramUser | undefined;\n if (params.user) {\n try {\n user = JSON.parse(params.user) as TelegramUser;\n } catch {\n user = undefined;\n }\n }\n\n const authDateRaw = params.auth_date;\n const auth_date =\n authDateRaw && /^\\d+$/.test(authDateRaw) ? Number(authDateRaw) : undefined;\n\n return {\n raw: initData,\n params,\n ...(params.hash ? { hash: params.hash } : {}),\n ...(auth_date !== undefined ? { auth_date } : {}),\n ...(params.query_id ? { query_id: params.query_id } : {}),\n ...(user ? { user } : {}),\n };\n}\n\nexport interface WellFormedOptions {\n /** Reject initData whose `auth_date` is older than this many seconds.\n * Defaults to 86400 (24h) — match or stay under the server's\n * `auth.telegram.initdata_max_age_secs`. Pass 0 to skip the freshness\n * check client-side (the server still enforces its own window). */\n maxAgeSeconds?: number;\n /** Injectable clock (unix seconds) for testing. Defaults to `Date.now()`. */\n nowUnix?: number;\n}\n\n/** Fail-fast structural check: `hash` present, `auth_date` present + a valid\n * `user`, and (optionally) not stale. Throws {@link InitDataError}. Does NOT\n * verify the HMAC — only the server can. */\nexport function assertWellFormed(\n initData: string,\n opts: WellFormedOptions = {},\n): ParsedInitData {\n if (!initData) throw new InitDataError(\"initData is empty\", \"empty\");\n const parsed = parseInitData(initData);\n if (!parsed.hash)\n throw new InitDataError(\"initData is missing `hash`\", \"missing_hash\");\n if (parsed.auth_date === undefined)\n throw new InitDataError(\n \"initData is missing a valid `auth_date`\",\n \"missing_auth_date\",\n );\n if (!parsed.user || typeof parsed.user.id !== \"number\")\n throw new InitDataError(\n \"initData is missing a valid `user`\",\n \"bad_user\",\n );\n\n const maxAge = opts.maxAgeSeconds ?? 86_400;\n if (maxAge > 0) {\n const now = opts.nowUnix ?? Math.floor(Date.now() / 1000);\n if (now - parsed.auth_date > maxAge)\n throw new InitDataError(\n \"initData is stale (auth_date older than the freshness window)\",\n \"stale\",\n );\n }\n return parsed;\n}\n\nexport interface FromInitDataOptions extends WellFormedOptions {\n /** Skip the client-side well-formedness check and let the server be the\n * sole judge. Default false — the fail-fast check saves a round-trip on\n * obviously-bad input. */\n skipWellFormedCheck?: boolean;\n}\n\n/**\n * Build an authenticated client from a raw `initData` string.\n *\n * 1. (unless skipped) structurally validate the payload — throws\n * {@link InitDataError} on malformed/stale input.\n * 2. exchange it at `POST /auth/telegram/exchange` — the server validates the\n * HMAC; a bad signature throws a 401 `ApiError`.\n * 3. store the returned JWT and return the ready-to-use client.\n *\n * Read `client.auth.me()` (or call `client.auth.exchangeTelegram` directly for\n * the raw session) to check `email_pending` and prompt for an email.\n */\nexport async function fromInitData(\n initData: string,\n config: CreateClientOptions,\n opts: FromInitDataOptions = {},\n): Promise<CusfrontClient> {\n if (!opts.skipWellFormedCheck) assertWellFormed(initData, opts);\n const client = createClient(config);\n await client.auth.exchangeTelegram({ initData });\n return client;\n}\n\n/** Read `window.Telegram.WebApp.initData` if running inside a Telegram Mini\n * App. Returns null when absent or empty (e.g. opened outside Telegram). */\nexport function readWebAppInitData(): string | null {\n const tg = (\n globalThis as unknown as {\n Telegram?: { WebApp?: { initData?: string } };\n }\n ).Telegram;\n const data = tg?.WebApp?.initData;\n return data && data.length > 0 ? data : null;\n}\n\n/**\n * Convenience entry for a Mini App: read `initData` from the Telegram WebApp\n * SDK and exchange it. Throws if not running inside a Telegram Mini App.\n */\nexport async function fromTelegramWebApp(\n config: CreateClientOptions,\n opts: FromInitDataOptions = {},\n): Promise<CusfrontClient> {\n const initData = readWebAppInitData();\n if (!initData)\n throw new InitDataError(\n \"not running inside a Telegram Mini App (window.Telegram.WebApp.initData is empty)\",\n \"empty\",\n );\n return fromInitData(initData, config, opts);\n}\n\n/** Convenience accessor for the typed exchange session (incl. `email_pending`)\n * when you need the envelope rather than just the client. */\nexport type TelegramExchangeSession = JwtIssued;\n"]}
|
package/dist/telegram.d.cts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { CreateClientOptions, CusfrontClient } from './index.cjs';
|
|
2
2
|
import { JwtIssued } from './resources/auth.cjs';
|
|
3
|
-
import './http-
|
|
3
|
+
import './http-BkCfOCR0.cjs';
|
|
4
4
|
import './resources/deposits.cjs';
|
|
5
5
|
import './customer-CoxPwe5o.cjs';
|
|
6
6
|
import './resources/cards.cjs';
|
|
7
7
|
import './resources/balance.cjs';
|
|
8
8
|
import './resources/branding.cjs';
|
|
9
|
+
import './resources/wallet.cjs';
|
|
9
10
|
import './resources/blog.cjs';
|
|
10
11
|
import './resources/subscriptions.cjs';
|
|
12
|
+
import './resources/sessions.cjs';
|
|
13
|
+
import './resources/push.cjs';
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* `@takeal/cusfront-sdk/telegram` — Telegram Mini App adapter.
|