postex-auth-sdk-stage 2.3.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -101,7 +101,7 @@ Accepts either a direct email string or an identifier object.
101
101
 
102
102
  ```typescript
103
103
  async getStatus(
104
- identifier: string | { email?: string; mobileNumber?: string }
104
+ identifier: string | { email?: string; mobileNumber?: string; username?: string }
105
105
  ): Promise<AuthStatusResponse>
106
106
  ```
107
107
 
@@ -110,6 +110,7 @@ async getStatus(
110
110
  - `auth.getStatus('user@example.com')`
111
111
  - `auth.getStatus({ email: 'user@example.com' })`
112
112
  - `auth.getStatus({ mobileNumber: '03011266254' })`
113
+ - `auth.getStatus({ username: 'user123' })`
113
114
 
114
115
  **Returns:**
115
116
 
@@ -126,10 +127,17 @@ Start the authentication process. Returns either a WebAuthn challenge or confirm
126
127
 
127
128
  ```typescript
128
129
  async initiateAuth(
129
- identifier: string | { email?: string; mobileNumber?: string }
130
+ identifier: string | { email?: string; mobileNumber?: string; username?: string }
130
131
  ): Promise<InitiateAuthResponse>
131
132
  ```
132
133
 
134
+ **Supported input forms:**
135
+
136
+ - `auth.initiateAuth('user@example.com')`
137
+ - `auth.initiateAuth({ email: 'user@example.com' })`
138
+ - `auth.initiateAuth({ mobileNumber: '03011266254' })`
139
+ - `auth.initiateAuth({ username: 'user123' })`
140
+
133
141
  **Returns:**
134
142
 
135
143
  - `status`: `'webauthn_challenge'` | `'otp_sent'`
@@ -140,11 +148,11 @@ async initiateAuth(
140
148
  #### initiateOTP()
141
149
 
142
150
  Start OTP authentication directly via `/otp/initiate`.
143
- Requires at least one identifier: `email` or `mobileNumber`.
151
+ Requires at least one identifier: `email`, `mobileNumber`, or `username`.
144
152
 
145
153
  ```typescript
146
154
  async initiateOTP(
147
- identifier: string | { email?: string; mobileNumber?: string }
155
+ identifier: string | { email?: string; mobileNumber?: string; username?: string }
148
156
  ): Promise<{
149
157
  message?: string;
150
158
  }>
@@ -153,11 +161,12 @@ async initiateOTP(
153
161
  **Supported input forms:**
154
162
  - `auth.initiateOTP({ email: 'user@example.com' })`
155
163
  - `auth.initiateOTP({ mobileNumber: '03011266254' })`
156
- - `auth.initiateOTP({ email: 'user@example.com' })`
164
+ - `auth.initiateOTP({ username: 'user123' })`
157
165
 
158
166
  **Validation:**
159
167
 
160
- - Throws an error when both `email` and `mobileNumber` are missing/empty.
168
+ - Throws an error when `email`, `mobileNumber`, and `username` are all missing/empty.
169
+ - `username` is trimmed, must be 64 characters or fewer, and must not contain control characters.
161
170
 
162
171
  ---
163
172
 
package/dist/auth.d.ts CHANGED
@@ -2,6 +2,7 @@ type AuthEntity = "xstak" | "postex" | "callcourier" | "postexglobal" | "postexs
2
2
  type AuthIdentifierInput = string | {
3
3
  email?: string;
4
4
  mobileNumber?: string;
5
+ username?: string;
5
6
  realm?: string;
6
7
  };
7
8
  interface RealmOptions {
@@ -126,6 +127,7 @@ export declare class AuthSDK {
126
127
  private assertNoControlChars;
127
128
  private validateEmail;
128
129
  private validateMobileNumber;
130
+ private validateUsername;
129
131
  private validateOTP;
130
132
  private validateMagicLinkToken;
131
133
  private validateRealm;
@@ -153,8 +155,8 @@ export declare class AuthSDK {
153
155
  */
154
156
  initiateAuth(identifier: AuthIdentifierInput, options?: RealmOptions): Promise<InitiateAuthResponse>;
155
157
  /**
156
- * POST /otp/initiate - Direct OTP initiation using email or mobile number.
157
- * Requires at least one identifier: email or mobileNumber.
158
+ * POST /otp/initiate - Direct OTP initiation using email, mobile number, or username.
159
+ * Requires at least one identifier: email, mobileNumber, or username.
158
160
  */
159
161
  initiateOTP(identifier: AuthIdentifierInput, options?: RealmOptions): Promise<OTPInitiateResponse>;
160
162
  /**
@@ -1,15 +1,15 @@
1
- function R() {
1
+ function O() {
2
2
  return typeof window < "u" && typeof window.PublicKeyCredential < "u" && typeof navigator < "u" && typeof navigator.credentials < "u";
3
3
  }
4
- async function M() {
5
- if (!R()) return !1;
4
+ async function j() {
5
+ if (!O()) return !1;
6
6
  try {
7
7
  return await PublicKeyCredential.isConditionalMediationAvailable?.() ?? !1;
8
8
  } catch {
9
9
  return !1;
10
10
  }
11
11
  }
12
- function O(o) {
12
+ function N(o) {
13
13
  const e = new Uint8Array(o);
14
14
  let r = "";
15
15
  for (let t = 0; t < e.byteLength; t++)
@@ -21,115 +21,115 @@ function C(o) {
21
21
  throw new Error("Invalid base64: expected non-empty string");
22
22
  const e = o.replace(/\s/g, "").replace(/-/g, "+").replace(/_/g, "/"), r = e.length % 4, t = r > 0 ? e + "=".repeat(4 - r) : e;
23
23
  try {
24
- const s = atob(t), n = new Uint8Array(s.length);
25
- for (let a = 0; a < s.length; a++)
26
- n[a] = s.charCodeAt(a);
27
- return n.buffer;
24
+ const n = atob(t), s = new Uint8Array(n.length);
25
+ for (let a = 0; a < n.length; a++)
26
+ s[a] = n.charCodeAt(a);
27
+ return s.buffer;
28
28
  } catch {
29
29
  throw new Error(
30
30
  "Invalid base64: string is not correctly encoded. Check challenge/credentialId from server."
31
31
  );
32
32
  }
33
33
  }
34
- function h(o) {
35
- return O(o).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
34
+ function p(o) {
35
+ return N(o).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
36
36
  }
37
- function j(o) {
37
+ function H(o) {
38
38
  return /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(
39
39
  o
40
40
  );
41
41
  }
42
- function H(o) {
42
+ function J(o) {
43
43
  const e = o.replace(/-/g, ""), r = new Uint8Array(e.length / 2);
44
44
  for (let t = 0; t < r.length; t++)
45
45
  r[t] = parseInt(e.substr(t * 2, 2), 16);
46
46
  return r.buffer;
47
47
  }
48
- function P(o) {
48
+ function b(o) {
49
49
  if (!o || typeof o != "string")
50
50
  throw new Error("Invalid input: expected non-empty string");
51
- return j(o) ? H(o) : C(o);
51
+ return H(o) ? J(o) : C(o);
52
52
  }
53
53
  function k(o) {
54
54
  return new TextEncoder().encode(o).buffer;
55
55
  }
56
- function J(o) {
56
+ function F(o) {
57
57
  return String.fromCharCode(...o);
58
58
  }
59
- const F = "xpay_webauthn", W = 1, u = "passkey_data", E = "passkey_email", _ = "passkey_mobile_number";
60
- function m() {
59
+ const G = "xpay_webauthn", W = 1, u = "passkey_data", E = "passkey_email", _ = "passkey_mobile_number";
60
+ function y() {
61
61
  return new Promise((o, e) => {
62
- const r = indexedDB.open(F, W);
62
+ const r = indexedDB.open(G, W);
63
63
  r.onerror = () => e(r.error), r.onsuccess = () => o(r.result), r.onupgradeneeded = () => {
64
64
  const t = r.result;
65
65
  t.objectStoreNames.contains(u) || t.createObjectStore(u);
66
66
  };
67
67
  });
68
68
  }
69
- async function G() {
69
+ async function Y() {
70
70
  try {
71
- const o = await m();
71
+ const o = await y();
72
72
  return new Promise((e, r) => {
73
- const t = o.transaction(u, "readonly"), n = t.objectStore(u).get(E);
74
- n.onerror = () => r(n.error), n.onsuccess = () => e(n.result ?? null), t.oncomplete = () => o.close();
73
+ const t = o.transaction(u, "readonly"), s = t.objectStore(u).get(E);
74
+ s.onerror = () => r(s.error), s.onsuccess = () => e(s.result ?? null), t.oncomplete = () => o.close();
75
75
  });
76
76
  } catch {
77
77
  return null;
78
78
  }
79
79
  }
80
- async function Y(o) {
80
+ async function V(o) {
81
81
  try {
82
- const e = await m();
82
+ const e = await y();
83
83
  return new Promise((r, t) => {
84
- const s = e.transaction(u, "readwrite"), a = s.objectStore(u).put(o, E);
85
- a.onerror = () => t(a.error), a.onsuccess = () => r(), s.oncomplete = () => e.close();
84
+ const n = e.transaction(u, "readwrite"), a = n.objectStore(u).put(o, E);
85
+ a.onerror = () => t(a.error), a.onsuccess = () => r(), n.oncomplete = () => e.close();
86
86
  });
87
87
  } catch {
88
88
  }
89
89
  }
90
- async function V() {
90
+ async function X() {
91
91
  try {
92
- const o = await m();
92
+ const o = await y();
93
93
  return new Promise((e, r) => {
94
- const t = o.transaction(u, "readwrite"), n = t.objectStore(u).delete(E);
95
- n.onerror = () => r(n.error), n.onsuccess = () => e(), t.oncomplete = () => o.close();
94
+ const t = o.transaction(u, "readwrite"), s = t.objectStore(u).delete(E);
95
+ s.onerror = () => r(s.error), s.onsuccess = () => e(), t.oncomplete = () => o.close();
96
96
  });
97
97
  } catch {
98
98
  }
99
99
  }
100
- async function X() {
100
+ async function Z() {
101
101
  try {
102
- const o = await m();
102
+ const o = await y();
103
103
  return new Promise((e, r) => {
104
- const t = o.transaction(u, "readonly"), n = t.objectStore(u).get(_);
105
- n.onerror = () => r(n.error), n.onsuccess = () => e(n.result ?? null), t.oncomplete = () => o.close();
104
+ const t = o.transaction(u, "readonly"), s = t.objectStore(u).get(_);
105
+ s.onerror = () => r(s.error), s.onsuccess = () => e(s.result ?? null), t.oncomplete = () => o.close();
106
106
  });
107
107
  } catch {
108
108
  return null;
109
109
  }
110
110
  }
111
- async function Z(o) {
111
+ async function Q(o) {
112
112
  try {
113
- const e = await m();
113
+ const e = await y();
114
114
  return new Promise((r, t) => {
115
- const s = e.transaction(u, "readwrite"), a = s.objectStore(u).put(o, _);
116
- a.onerror = () => t(a.error), a.onsuccess = () => r(), s.oncomplete = () => e.close();
115
+ const n = e.transaction(u, "readwrite"), a = n.objectStore(u).put(o, _);
116
+ a.onerror = () => t(a.error), a.onsuccess = () => r(), n.oncomplete = () => e.close();
117
117
  });
118
118
  } catch {
119
119
  }
120
120
  }
121
- async function Q() {
121
+ async function ee() {
122
122
  try {
123
- const o = await m();
123
+ const o = await y();
124
124
  return new Promise((e, r) => {
125
- const t = o.transaction(u, "readwrite"), n = t.objectStore(u).delete(_);
126
- n.onerror = () => r(n.error), n.onsuccess = () => e(), t.oncomplete = () => o.close();
125
+ const t = o.transaction(u, "readwrite"), s = t.objectStore(u).delete(_);
126
+ s.onerror = () => r(s.error), s.onsuccess = () => e(), t.oncomplete = () => o.close();
127
127
  });
128
128
  } catch {
129
129
  }
130
130
  }
131
131
  const S = "dpop_private_key", A = "dpop_public_key_jwk";
132
- function N(o) {
132
+ function K(o) {
133
133
  if (!o || typeof o != "object") return !1;
134
134
  const e = o;
135
135
  return e.kty === "EC" && e.crv === "P-256" && typeof e.x == "string" && typeof e.y == "string";
@@ -139,7 +139,7 @@ class g extends Error {
139
139
  super(e), this.name = "DPoPProofGenerationError";
140
140
  }
141
141
  }
142
- function ee(o) {
142
+ function te(o) {
143
143
  return {
144
144
  kty: "EC",
145
145
  crv: "P-256",
@@ -147,7 +147,7 @@ function ee(o) {
147
147
  y: o.y
148
148
  };
149
149
  }
150
- async function K(o) {
150
+ async function q(o) {
151
151
  const e = JSON.stringify({
152
152
  crv: o.crv,
153
153
  kty: o.kty,
@@ -157,47 +157,47 @@ async function K(o) {
157
157
  "SHA-256",
158
158
  new TextEncoder().encode(e)
159
159
  );
160
- return h(r);
160
+ return p(r);
161
161
  }
162
- async function te(o) {
162
+ async function re(o) {
163
163
  try {
164
- const e = await m();
164
+ const e = await y();
165
165
  return new Promise((r, t) => {
166
- const s = e.transaction(u, "readwrite"), a = s.objectStore(u).put(o, S);
167
- a.onerror = () => t(a.error), a.onsuccess = () => r(), s.oncomplete = () => e.close();
166
+ const n = e.transaction(u, "readwrite"), a = n.objectStore(u).put(o, S);
167
+ a.onerror = () => t(a.error), a.onsuccess = () => r(), n.oncomplete = () => e.close();
168
168
  });
169
169
  } catch (e) {
170
170
  console.error("Failed to store DPoP private key:", e);
171
171
  }
172
172
  }
173
- async function re(o) {
173
+ async function se(o) {
174
174
  try {
175
- const e = await m();
175
+ const e = await y();
176
176
  return new Promise((r, t) => {
177
- const s = e.transaction(u, "readwrite"), a = s.objectStore(u).put(o, A);
178
- a.onerror = () => t(a.error), a.onsuccess = () => r(), s.oncomplete = () => e.close();
177
+ const n = e.transaction(u, "readwrite"), a = n.objectStore(u).put(o, A);
178
+ a.onerror = () => t(a.error), a.onsuccess = () => r(), n.oncomplete = () => e.close();
179
179
  });
180
180
  } catch (e) {
181
181
  console.error("Failed to store DPoP public key JWK:", e);
182
182
  }
183
183
  }
184
- async function q() {
184
+ async function $() {
185
185
  try {
186
- const o = await m();
186
+ const o = await y();
187
187
  return new Promise((e, r) => {
188
- const t = o.transaction(u, "readonly"), n = t.objectStore(u).get(S);
189
- n.onerror = () => r(n.error), n.onsuccess = () => e(n.result ?? null), t.oncomplete = () => o.close();
188
+ const t = o.transaction(u, "readonly"), s = t.objectStore(u).get(S);
189
+ s.onerror = () => r(s.error), s.onsuccess = () => e(s.result ?? null), t.oncomplete = () => o.close();
190
190
  });
191
191
  } catch {
192
192
  return null;
193
193
  }
194
194
  }
195
- async function $() {
195
+ async function U() {
196
196
  try {
197
- const o = await m();
197
+ const o = await y();
198
198
  return new Promise((e, r) => {
199
- const t = o.transaction(u, "readonly"), n = t.objectStore(u).get(A);
200
- n.onerror = () => r(n.error), n.onsuccess = () => e(n.result ?? null), t.oncomplete = () => o.close();
199
+ const t = o.transaction(u, "readonly"), s = t.objectStore(u).get(A);
200
+ s.onerror = () => r(s.error), s.onsuccess = () => e(s.result ?? null), t.oncomplete = () => o.close();
201
201
  });
202
202
  } catch {
203
203
  return null;
@@ -205,10 +205,10 @@ async function $() {
205
205
  }
206
206
  async function T() {
207
207
  try {
208
- const o = await m();
208
+ const o = await y();
209
209
  return new Promise((e, r) => {
210
- const t = o.transaction(u, "readwrite"), s = t.objectStore(u);
211
- s.delete(S), s.delete(A), t.onerror = () => r(t.error), t.oncomplete = () => {
210
+ const t = o.transaction(u, "readwrite"), n = t.objectStore(u);
211
+ n.delete(S), n.delete(A), t.onerror = () => r(t.error), t.oncomplete = () => {
212
212
  o.close(), e();
213
213
  };
214
214
  });
@@ -224,27 +224,27 @@ async function ne() {
224
224
  !1,
225
225
  // Private key is non-extractable
226
226
  ["sign", "verify"]
227
- ), e = await crypto.subtle.exportKey("jwk", o.publicKey), r = ee(e), t = await K(r);
228
- return await te(o.privateKey), await re(r), { publicKey: r, thumbprint: t };
227
+ ), e = await crypto.subtle.exportKey("jwk", o.publicKey), r = te(e), t = await q(r);
228
+ return await re(o.privateKey), await se(r), { publicKey: r, thumbprint: t };
229
229
  }
230
- async function se() {
231
- const o = await q(), e = await $();
232
- return o && N(e) ? {
230
+ async function oe() {
231
+ const o = await $(), e = await U();
232
+ return o && K(e) ? {
233
233
  publicKey: e,
234
- thumbprint: await K(e)
234
+ thumbprint: await q(e)
235
235
  } : ((o || e) && await T(), ne());
236
236
  }
237
- async function oe(o, e, r) {
237
+ async function ae(o, e, r) {
238
238
  try {
239
- const t = await q(), s = await $();
240
- if (!t || !N(s))
239
+ const t = await $(), n = await U();
240
+ if (!t || !K(n))
241
241
  throw new g(
242
242
  "DPoP key material is unavailable or invalid"
243
243
  );
244
- const n = {
244
+ const s = {
245
245
  typ: "dpop+jwt",
246
246
  alg: "ES256",
247
- jwk: s
247
+ jwk: n
248
248
  // Public key in JWK format
249
249
  }, a = new URL(
250
250
  e,
@@ -256,73 +256,73 @@ async function oe(o, e, r) {
256
256
  iat: Math.floor(Date.now() / 1e3)
257
257
  };
258
258
  if (r) {
259
- const z = new TextEncoder().encode(r), L = await crypto.subtle.digest("SHA-256", z);
260
- c.ath = h(L);
259
+ const L = new TextEncoder().encode(r), M = await crypto.subtle.digest("SHA-256", L);
260
+ c.ath = p(M);
261
261
  }
262
- const d = h(
263
- new TextEncoder().encode(JSON.stringify(n)).buffer
264
- ), i = h(
262
+ const d = p(
263
+ new TextEncoder().encode(JSON.stringify(s)).buffer
264
+ ), i = p(
265
265
  new TextEncoder().encode(JSON.stringify(c)).buffer
266
- ), p = `${d}.${i}`, f = await crypto.subtle.sign(
266
+ ), m = `${d}.${i}`, f = await crypto.subtle.sign(
267
267
  {
268
268
  name: "ECDSA",
269
269
  hash: { name: "SHA-256" }
270
270
  },
271
271
  t,
272
- new TextEncoder().encode(p)
273
- ), w = h(f);
272
+ new TextEncoder().encode(m)
273
+ ), w = p(f);
274
274
  return `${d}.${i}.${w}`;
275
275
  } catch (t) {
276
276
  throw console.error("Failed to generate DPoP proof:", t), t instanceof g ? t : new g("Failed to generate DPoP proof");
277
277
  }
278
278
  }
279
279
  const B = {
280
- isWebAuthnSupported: R,
281
- isConditionalUISupported: M,
282
- arrayBufferToBase64: O,
280
+ isWebAuthnSupported: O,
281
+ isConditionalUISupported: j,
282
+ arrayBufferToBase64: N,
283
283
  base64ToArrayBuffer: C,
284
- arrayBufferToBase64url: h,
285
- base64urlToArrayBuffer: P,
284
+ arrayBufferToBase64url: p,
285
+ base64urlToArrayBuffer: b,
286
286
  stringToArrayBuffer: k,
287
- uint8ArrayToString: J,
288
- getPasskeyEmail: G,
289
- setPasskeyEmail: Y,
290
- clearPasskeyEmail: V,
291
- getPasskeyMobileNumber: X,
292
- setPasskeyMobileNumber: Z,
293
- clearPasskeyMobileNumber: Q
287
+ uint8ArrayToString: F,
288
+ getPasskeyEmail: Y,
289
+ setPasskeyEmail: V,
290
+ clearPasskeyEmail: X,
291
+ getPasskeyMobileNumber: Z,
292
+ setPasskeyMobileNumber: Q,
293
+ clearPasskeyMobileNumber: ee
294
294
  };
295
295
  typeof window < "u" && (window.WebAuthn = B);
296
- const ae = typeof window < "u" ? window : globalThis;
297
- ae.WebAuthn = B;
298
- const b = "postex-auth-token", ie = "postexglobal", ce = {
296
+ const ie = typeof window < "u" ? window : globalThis;
297
+ ie.WebAuthn = B;
298
+ const P = "postex-auth-token", ce = "postexglobal", le = {
299
299
  xstak: "https://auth-stage.xstak.com/public/v1",
300
300
  postex: "https://auth-stage.postex.pk/public/v1",
301
301
  callcourier: "https://auth-stage.callcourier.com.pk/public/v1",
302
302
  postexglobal: "https://auth-stage.postexglobal.com/public/v1",
303
303
  postexsa: "https://auth-stage.postex.sa/public/v1"
304
- }, le = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/, ue = /^\+[1-9]\d{6,14}$/, de = /^\d{6}$/, he = /^[A-Za-z0-9_-]{16,512}$/, pe = /[\u0000-\u001F\u007F-\u009F]/, ye = /[A-Za-z]/, me = /[\u0400-\u04FF]/, v = 254, x = 16, I = 64;
305
- class fe extends Error {
304
+ }, ue = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/, de = /^\+[1-9]\d{6,14}$/, he = /^\d{6}$/, pe = /^[A-Za-z0-9_-]{16,512}$/, me = /[\u0000-\u001F\u007F-\u009F]/, ye = /[A-Za-z]/, fe = /[\u0400-\u04FF]/, v = 254, x = 16, I = 64, D = 64;
305
+ class we extends Error {
306
306
  constructor(e, r, t) {
307
307
  super(t ?? `Request failed with status ${e}`), this.response = { status: e, data: r }, this.name = "AuthSDKFetchError";
308
308
  }
309
309
  }
310
- class y extends Error {
310
+ class h extends Error {
311
311
  constructor(e, r, t = "invalid_input") {
312
312
  super(r), this.field = e, this.code = t, this.name = "SDKValidationError";
313
313
  }
314
314
  }
315
- const D = "auth_sdk_refresh_token";
316
- class U {
315
+ const R = "auth_sdk_refresh_token";
316
+ class z {
317
317
  constructor(e) {
318
318
  this.config = e, this.dpopInitializationPromise = this.createDPoPInitializationPromise();
319
319
  }
320
320
  getBaseUrl() {
321
- const e = this.config.appId ?? ie;
322
- return ce[e];
321
+ const e = this.config.appId ?? ce;
322
+ return le[e];
323
323
  }
324
324
  async initializeDPoPState() {
325
- await se();
325
+ await oe();
326
326
  }
327
327
  async ensureDPoPInitialized() {
328
328
  await this.dpopInitializationPromise;
@@ -337,17 +337,17 @@ class U {
337
337
  this.dpopInitializationPromise = this.createDPoPInitializationPromise();
338
338
  }
339
339
  async getRequiredDPoPProof(e, r, t) {
340
- return await this.ensureDPoPInitialized(), oe(e.toUpperCase(), r, t);
340
+ return await this.ensureDPoPInitialized(), ae(e.toUpperCase(), r, t);
341
341
  }
342
342
  containsControlChars(e) {
343
- return pe.test(e);
343
+ return me.test(e);
344
344
  }
345
345
  hasMixedLatinAndCyrillic(e) {
346
- return ye.test(e) && me.test(e);
346
+ return ye.test(e) && fe.test(e);
347
347
  }
348
348
  assertNoControlChars(e, r) {
349
349
  if (this.containsControlChars(r))
350
- throw new y(
350
+ throw new h(
351
351
  e,
352
352
  `${e} must not contain control characters`
353
353
  );
@@ -355,46 +355,57 @@ class U {
355
355
  validateEmail(e, r = "email") {
356
356
  const t = e.trim();
357
357
  if (!t)
358
- throw new y(r, `${r} is required`);
358
+ throw new h(r, `${r} is required`);
359
359
  if (t.length > v)
360
- throw new y(
360
+ throw new h(
361
361
  r,
362
362
  `${r} must be ${v} characters or fewer`
363
363
  );
364
364
  this.assertNoControlChars(r, t);
365
- const [s = ""] = t.split("@");
366
- if (this.hasMixedLatinAndCyrillic(s))
367
- throw new y(
365
+ const [n = ""] = t.split("@");
366
+ if (this.hasMixedLatinAndCyrillic(n))
367
+ throw new h(
368
368
  r,
369
369
  `${r} must not mix Latin and Cyrillic characters in the local part`
370
370
  );
371
- if (!le.test(t))
372
- throw new y(r, `${r} must be a valid email`);
371
+ if (!ue.test(t))
372
+ throw new h(r, `${r} must be a valid email`);
373
373
  return t;
374
374
  }
375
375
  validateMobileNumber(e, r = "mobileNumber") {
376
376
  const t = e.trim();
377
377
  if (!t)
378
- throw new y(r, `${r} is required`);
378
+ throw new h(r, `${r} is required`);
379
379
  if (t.length > x)
380
- throw new y(
380
+ throw new h(
381
381
  r,
382
382
  `${r} must be ${x} characters or fewer`
383
383
  );
384
- if (this.assertNoControlChars(r, t), !ue.test(t))
385
- throw new y(r, `${r} must be in E.164 format`);
384
+ if (this.assertNoControlChars(r, t), !de.test(t))
385
+ throw new h(r, `${r} must be in E.164 format`);
386
386
  return t;
387
387
  }
388
+ validateUsername(e, r = "username") {
389
+ const t = e.trim();
390
+ if (!t)
391
+ throw new h(r, `${r} is required`);
392
+ if (t.length > I)
393
+ throw new h(
394
+ r,
395
+ `${r} must be ${I} characters or fewer`
396
+ );
397
+ return this.assertNoControlChars(r, t), t;
398
+ }
388
399
  validateOTP(e, r = "otp") {
389
400
  const t = e.trim();
390
- if (this.assertNoControlChars(r, t), !de.test(t))
391
- throw new y(r, `${r} must be a 6-digit code`);
401
+ if (this.assertNoControlChars(r, t), !he.test(t))
402
+ throw new h(r, `${r} must be a 6-digit code`);
392
403
  return t;
393
404
  }
394
405
  validateMagicLinkToken(e, r = "token") {
395
406
  const t = e.trim();
396
- if (this.assertNoControlChars(r, t), !he.test(t))
397
- throw new y(
407
+ if (this.assertNoControlChars(r, t), !pe.test(t))
408
+ throw new h(
398
409
  r,
399
410
  `${r} must be 16-512 URL-safe characters`
400
411
  );
@@ -403,10 +414,10 @@ class U {
403
414
  validateRealm(e) {
404
415
  const r = e?.trim();
405
416
  if (r) {
406
- if (this.assertNoControlChars("realm", r), r.length > I)
407
- throw new y(
417
+ if (this.assertNoControlChars("realm", r), r.length > D)
418
+ throw new h(
408
419
  "realm",
409
- `realm must be ${I} characters or fewer`
420
+ `realm must be ${D} characters or fewer`
410
421
  );
411
422
  return r;
412
423
  }
@@ -414,7 +425,8 @@ class U {
414
425
  normalizeAndValidateIdentifier(e) {
415
426
  return typeof e == "string" ? { email: this.validateEmail(e) } : {
416
427
  email: e.email ? this.validateEmail(e.email) : void 0,
417
- mobileNumber: e.mobileNumber ? this.validateMobileNumber(e.mobileNumber) : void 0
428
+ mobileNumber: e.mobileNumber ? this.validateMobileNumber(e.mobileNumber) : void 0,
429
+ username: e.username ? this.validateUsername(e.username) : void 0
418
430
  };
419
431
  }
420
432
  normalizeAuthIdentifier(e) {
@@ -425,20 +437,20 @@ class U {
425
437
  return this.validateRealm(t);
426
438
  }
427
439
  buildAuthRequestBody(e, r) {
428
- const t = this.normalizeAuthIdentifier(e), s = this.extractRealm(e, r);
440
+ const t = this.normalizeAuthIdentifier(e), n = this.extractRealm(e, r);
429
441
  return {
430
442
  ...t,
431
- ...s ? { realm: s } : {}
443
+ ...n ? { realm: n } : {}
432
444
  };
433
445
  }
434
446
  buildUrl(e, r) {
435
- const t = this.getBaseUrl().replace(/\/$/, ""), s = e.startsWith("/") ? e : `/${e}`, n = `${t}${s}`;
436
- if (!r || Object.keys(r).length === 0) return n;
447
+ const t = this.getBaseUrl().replace(/\/$/, ""), n = e.startsWith("/") ? e : `/${e}`, s = `${t}${n}`;
448
+ if (!r || Object.keys(r).length === 0) return s;
437
449
  const a = new URLSearchParams(r).toString();
438
- return `${n}?${a}`;
450
+ return `${s}?${a}`;
439
451
  }
440
452
  async request(e, r, t) {
441
- const s = this.buildUrl(r, t?.params), n = {
453
+ const n = this.buildUrl(r, t?.params), s = {
442
454
  "Content-Type": "application/json",
443
455
  Accept: "application/json",
444
456
  "X-API-Key": this.config.apiKey ?? "",
@@ -446,19 +458,19 @@ class U {
446
458
  }, a = {
447
459
  method: e,
448
460
  credentials: "include",
449
- headers: n
461
+ headers: s
450
462
  };
451
463
  t?.body !== void 0 && t?.body !== null && (a.body = JSON.stringify(t.body));
452
- const l = await fetch(s, a);
464
+ const l = await fetch(n, a);
453
465
  if (!l.ok) {
454
466
  let i;
455
467
  try {
456
- const p = await l.text();
457
- i = p ? JSON.parse(p) : void 0;
468
+ const m = await l.text();
469
+ i = m ? JSON.parse(m) : void 0;
458
470
  } catch {
459
471
  i = void 0;
460
472
  }
461
- throw l.status === 401 && (await this.clearTokens(), await T(), this.resetDPoPInitialization()), new fe(l.status, i);
473
+ throw l.status === 401 && (await this.clearTokens(), await T(), this.resetDPoPInitialization()), new we(l.status, i);
462
474
  }
463
475
  const c = await l.text();
464
476
  return { data: c ? JSON.parse(c) : {} };
@@ -470,12 +482,12 @@ class U {
470
482
  * @param url - Full request URL
471
483
  */
472
484
  async getRequestAuthHeaders(e, r) {
473
- const t = localStorage.getItem(b);
485
+ const t = localStorage.getItem(P);
474
486
  if (!t) return {};
475
- const s = r.startsWith("http") ? r : `${this.getBaseUrl()}${r}`, n = await this.getRequiredDPoPProof(e, s, t);
487
+ const n = r.startsWith("http") ? r : `${this.getBaseUrl()}${r}`, s = await this.getRequiredDPoPProof(e, n, t);
476
488
  return {
477
489
  Authorization: `Bearer ${t}`,
478
- DPoP: n
490
+ DPoP: s
479
491
  };
480
492
  }
481
493
  /**
@@ -483,10 +495,10 @@ class U {
483
495
  * Returns no_session | session_found | webauthn_ready per PostEx Auth BFF spec.
484
496
  */
485
497
  async getStatus(e, r) {
486
- const t = this.normalizeAuthIdentifier(e), s = this.extractRealm(e, r), n = {};
487
- t.email && (n.email = t.email), t.mobileNumber && (n.mobileNumber = t.mobileNumber), s && (n.realm = s);
498
+ const t = this.normalizeAuthIdentifier(e), n = this.extractRealm(e, r), s = {};
499
+ t.email && (s.email = t.email), t.mobileNumber && (s.mobileNumber = t.mobileNumber), t.username && (s.username = t.username), n && (s.realm = n);
488
500
  const a = await this.request("GET", "/auth/status", {
489
- params: n
501
+ params: s
490
502
  });
491
503
  return a.data.data ?? a.data;
492
504
  }
@@ -495,34 +507,34 @@ class U {
495
507
  * Sets auth_session cookie when otp_sent.
496
508
  */
497
509
  async initiateAuth(e, r) {
498
- const t = this.buildAuthRequestBody(e, r), s = await this.request("POST", "/auth/initiate", {
510
+ const t = this.buildAuthRequestBody(e, r), n = await this.request("POST", "/auth/initiate", {
499
511
  body: t
500
- }), n = s.data.data ?? s.data;
512
+ }), s = n.data.data ?? n.data;
501
513
  return {
502
- status: n.status,
503
- challenge: n.challenge,
504
- credentialIds: n.credentialIds,
505
- rp: n.rp
514
+ status: s.status,
515
+ challenge: s.challenge,
516
+ credentialIds: s.credentialIds,
517
+ rp: s.rp
506
518
  };
507
519
  }
508
520
  /**
509
- * POST /otp/initiate - Direct OTP initiation using email or mobile number.
510
- * Requires at least one identifier: email or mobileNumber.
521
+ * POST /otp/initiate - Direct OTP initiation using email, mobile number, or username.
522
+ * Requires at least one identifier: email, mobileNumber, or username.
511
523
  */
512
524
  async initiateOTP(e, r) {
513
- const t = this.normalizeAuthIdentifier(e), s = this.extractRealm(e, r), n = t.email, a = t.mobileNumber;
514
- if (!n && !a)
515
- throw new y(
525
+ const t = this.normalizeAuthIdentifier(e), n = this.extractRealm(e, r), s = t.email, a = t.mobileNumber, l = t.username;
526
+ if (!s && !a && !l)
527
+ throw new h(
516
528
  "identifier",
517
- "Either mobileNumber or email is required"
529
+ "Either mobileNumber, email, or username is required"
518
530
  );
519
- const l = {};
520
- n && (l.email = n), a && (l.mobileNumber = a), s && (l.realm = s);
521
- const d = (await this.request("POST", "/otp/initiate", {
522
- body: l
531
+ const c = {};
532
+ s && (c.email = s), a && (c.mobileNumber = a), l && (c.username = l), n && (c.realm = n);
533
+ const i = (await this.request("POST", "/otp/initiate", {
534
+ body: c
523
535
  })).data;
524
536
  return {
525
- message: d.message ?? d.data?.message
537
+ message: i.message ?? i.data?.message
526
538
  };
527
539
  }
528
540
  /**
@@ -533,10 +545,10 @@ class U {
533
545
  const r = this.validateOTP(e), t = await this.getRequiredDPoPProof(
534
546
  "POST",
535
547
  `${this.getBaseUrl()}/otp/verify`
536
- ), s = await this.request("POST", "/otp/verify", {
548
+ ), n = await this.request("POST", "/otp/verify", {
537
549
  body: { otp: r },
538
550
  headers: { DPoP: t }
539
- }), n = s.data.data ?? s.data, a = n.AuthenticationResult ?? n, l = a.access_token ?? a.accessToken ?? a.AccessToken, c = a.refresh_token ?? a.refreshToken ?? a.RefreshToken, d = a.expires_in ?? a.expiresIn, i = a.token_type ?? a.tokenType;
551
+ }), s = n.data.data ?? n.data, a = s.AuthenticationResult ?? s, l = a.access_token ?? a.accessToken ?? a.AccessToken, c = a.refresh_token ?? a.refreshToken ?? a.RefreshToken, d = a.expires_in ?? a.expiresIn, i = a.token_type ?? a.tokenType;
540
552
  return l && await this.storeTokens({
541
553
  accessToken: l,
542
554
  refreshToken: c,
@@ -572,22 +584,22 @@ class U {
572
584
  mobileNumber: e,
573
585
  otp: r
574
586
  }) {
575
- const t = this.validateMobileNumber(e), s = this.validateOTP(r), n = await this.getRequiredDPoPProof(
587
+ const t = this.validateMobileNumber(e), n = this.validateOTP(r), s = await this.getRequiredDPoPProof(
576
588
  "POST",
577
589
  `${this.getBaseUrl()}/otp/signup/verify`
578
590
  ), a = await this.request("POST", "/otp/signup/verify", {
579
- body: { mobileNumber: t, otp: s },
580
- headers: { DPoP: n }
581
- }), l = a.data.data ?? a.data, c = l.AuthenticationResult ?? l, d = c.access_token ?? c.accessToken ?? c.AccessToken, i = c.refresh_token ?? c.refreshToken ?? c.RefreshToken, p = c.expires_in ?? c.expiresIn, f = c.token_type ?? c.tokenType;
591
+ body: { mobileNumber: t, otp: n },
592
+ headers: { DPoP: s }
593
+ }), l = a.data.data ?? a.data, c = l.AuthenticationResult ?? l, d = c.access_token ?? c.accessToken ?? c.AccessToken, i = c.refresh_token ?? c.refreshToken ?? c.RefreshToken, m = c.expires_in ?? c.expiresIn, f = c.token_type ?? c.tokenType;
582
594
  return d && await this.storeTokens({
583
595
  accessToken: d,
584
596
  refreshToken: i,
585
- expiresIn: p,
597
+ expiresIn: m,
586
598
  tokenType: f
587
599
  }), {
588
600
  access_token: d,
589
601
  refresh_token: i,
590
- expires_in: p,
602
+ expires_in: m,
591
603
  token_type: f,
592
604
  verified: c.verified,
593
605
  email: c.email ?? c.Email,
@@ -601,9 +613,9 @@ class U {
601
613
  mobileNumber: e,
602
614
  email: r = ""
603
615
  }) {
604
- const t = this.validateMobileNumber(e), s = r ? this.validateEmail(r) : "", n = await this.request("POST", "/otp/signup/resend", {
605
- body: { email: s, mobileNumber: t }
606
- }), a = n.data.data ?? n.data;
616
+ const t = this.validateMobileNumber(e), n = r ? this.validateEmail(r) : "", s = await this.request("POST", "/otp/signup/resend", {
617
+ body: { email: n, mobileNumber: t }
618
+ }), a = s.data.data ?? s.data;
607
619
  return {
608
620
  success: a.success,
609
621
  message: a.message,
@@ -635,15 +647,15 @@ class U {
635
647
  {
636
648
  body: {}
637
649
  }
638
- ), r = e.data.data ?? e.data, t = r.AuthenticationResult ?? r, s = t.access_token ?? t.accessToken ?? t.AccessToken, n = t.refresh_token ?? t.refreshToken ?? t.RefreshToken, a = t.expires_in ?? t.expiresIn, l = t.token_type ?? t.tokenType;
639
- return s && await this.storeTokens({
640
- accessToken: s,
641
- refreshToken: n,
650
+ ), r = e.data.data ?? e.data, t = r.AuthenticationResult ?? r, n = t.access_token ?? t.accessToken ?? t.AccessToken, s = t.refresh_token ?? t.refreshToken ?? t.RefreshToken, a = t.expires_in ?? t.expiresIn, l = t.token_type ?? t.tokenType;
651
+ return n && await this.storeTokens({
652
+ accessToken: n,
653
+ refreshToken: s,
642
654
  expiresIn: a,
643
655
  tokenType: l
644
656
  }), {
645
- access_token: s,
646
- refresh_token: n,
657
+ access_token: n,
658
+ refresh_token: s,
647
659
  expires_in: a,
648
660
  token_type: l,
649
661
  verified: t.verified,
@@ -663,16 +675,16 @@ class U {
663
675
  }
664
676
  async registerPasskey(e) {
665
677
  const r = this.validateEmail(e), t = await this.initiatePasskeyRegistration();
666
- let s;
678
+ let n;
667
679
  if (t?.user?.id)
668
680
  try {
669
- s = P(t.user.id);
681
+ n = b(t.user.id);
670
682
  } catch {
671
- s = k(t.user.id);
683
+ n = k(t.user.id);
672
684
  }
673
685
  else
674
- s = k(r);
675
- const n = (t.pubKeyCredParams ?? [
686
+ n = k(r);
687
+ const s = (t.pubKeyCredParams ?? [
676
688
  { type: "public-key", alg: -7 },
677
689
  { type: "public-key", alg: -257 }
678
690
  ]).map((w) => ({
@@ -680,19 +692,19 @@ class U {
680
692
  alg: w.alg
681
693
  })), a = t.excludeCredentials?.map((w) => ({
682
694
  type: "public-key",
683
- id: P(w)
695
+ id: b(w)
684
696
  })), l = {
685
- challenge: P(t.challenge),
697
+ challenge: b(t.challenge),
686
698
  rp: {
687
699
  name: t.rp?.name ?? "XPay",
688
700
  id: t.rp?.id ?? window.location.hostname
689
701
  },
690
702
  user: {
691
- id: s,
703
+ id: n,
692
704
  name: t.user?.name ?? r,
693
705
  displayName: t.user?.displayName ?? r
694
706
  },
695
- pubKeyCredParams: n,
707
+ pubKeyCredParams: s,
696
708
  excludeCredentials: a,
697
709
  timeout: t.timeout ?? 6e4,
698
710
  attestation: "direct",
@@ -706,12 +718,12 @@ class U {
706
718
  });
707
719
  if (!c) throw new Error("Credential creation failed");
708
720
  const d = c.response, i = {
709
- clientDataJSON: h(d.clientDataJSON),
710
- attestationObject: h(d.attestationObject),
711
- rawId: h(c.rawId)
721
+ clientDataJSON: p(d.clientDataJSON),
722
+ attestationObject: p(d.attestationObject),
723
+ rawId: p(c.rawId)
712
724
  };
713
725
  if (!i.rawId) throw new Error("Raw ID is required");
714
- const p = await this.getRequiredDPoPProof(
726
+ const m = await this.getRequiredDPoPProof(
715
727
  "POST",
716
728
  `${this.getBaseUrl()}/webauthn/register/challenge`
717
729
  ), f = await this.request(
@@ -719,7 +731,7 @@ class U {
719
731
  "/webauthn/register/challenge",
720
732
  {
721
733
  body: i,
722
- headers: { DPoP: p }
734
+ headers: { DPoP: m }
723
735
  }
724
736
  );
725
737
  return f.data.data ?? f.data;
@@ -732,28 +744,28 @@ class U {
732
744
  rp: r,
733
745
  credentialIds: t
734
746
  }) {
735
- const s = await navigator.credentials.get({
747
+ const n = await navigator.credentials.get({
736
748
  publicKey: {
737
- challenge: P(e),
749
+ challenge: b(e),
738
750
  rpId: r?.host ?? void 0,
739
751
  allowCredentials: t.map((w) => ({
740
752
  type: "public-key",
741
- id: P(w),
753
+ id: b(w),
742
754
  transports: ["internal"]
743
755
  })),
744
756
  timeout: 6e4,
745
757
  userVerification: "required"
746
758
  }
747
759
  });
748
- if (!s) throw new Error("Authentication failed");
749
- const n = s.response, a = {
750
- clientDataJSON: h(n.clientDataJSON),
751
- authenticatorData: h(
752
- n.authenticatorData
760
+ if (!n) throw new Error("Authentication failed");
761
+ const s = n.response, a = {
762
+ clientDataJSON: p(s.clientDataJSON),
763
+ authenticatorData: p(
764
+ s.authenticatorData
753
765
  ),
754
- signature: h(n.signature),
755
- rawId: h(s.rawId),
756
- userHandle: n.userHandle ? h(n.userHandle) : ""
766
+ signature: p(s.signature),
767
+ rawId: p(n.rawId),
768
+ userHandle: s.userHandle ? p(s.userHandle) : ""
757
769
  }, l = await this.getRequiredDPoPProof(
758
770
  "POST",
759
771
  `${this.getBaseUrl()}/webauthn/authenticate/challenge`
@@ -764,14 +776,14 @@ class U {
764
776
  body: a,
765
777
  headers: { DPoP: l }
766
778
  }
767
- ), d = c.data.data ?? c.data, i = d.AuthenticationResult ?? d, p = i.AccessToken ?? i.accessToken ?? i.access_token, f = i.RefreshToken ?? i.refreshToken ?? i.refresh_token;
768
- return p && await this.storeTokens({
769
- accessToken: p,
779
+ ), d = c.data.data ?? c.data, i = d.AuthenticationResult ?? d, m = i.AccessToken ?? i.accessToken ?? i.access_token, f = i.RefreshToken ?? i.refreshToken ?? i.refresh_token;
780
+ return m && await this.storeTokens({
781
+ accessToken: m,
770
782
  refreshToken: f,
771
783
  expiresIn: i.expiresIn ?? i.ExpiresIn,
772
784
  tokenType: i.tokenType ?? i.token_type
773
785
  }), {
774
- access_token: p,
786
+ access_token: m,
775
787
  refresh_token: f,
776
788
  email: i.email,
777
789
  name: i.name ?? i.userName,
@@ -784,9 +796,9 @@ class U {
784
796
  * GET /webauthn/credentials/:username - Get user's passkey status.
785
797
  */
786
798
  async getPasskeyStatus(e) {
787
- const t = `/webauthn/credentials/${encodeURIComponent(e)}`, s = await this.signRequest("GET", t), n = await this.request("GET", t, {
788
- headers: s.headers
789
- }), a = n.data.data ?? n.data;
799
+ const t = `/webauthn/credentials/${encodeURIComponent(e)}`, n = await this.signRequest("GET", t), s = await this.request("GET", t, {
800
+ headers: n.headers
801
+ }), a = s.data.data ?? s.data;
790
802
  return {
791
803
  ...a,
792
804
  hasCredentials: !!(a.hasCredentials ?? a.credentialId)
@@ -796,38 +808,38 @@ class U {
796
808
  * DELETE /webauthn/credentials/:username - Remove passkey.
797
809
  */
798
810
  async removePasskey(e) {
799
- const t = `/webauthn/credentials/${encodeURIComponent(e)}`, s = await this.signRequest("DELETE", t);
811
+ const t = `/webauthn/credentials/${encodeURIComponent(e)}`, n = await this.signRequest("DELETE", t);
800
812
  await this.request("DELETE", t, {
801
- headers: s.headers
813
+ headers: n.headers
802
814
  });
803
815
  }
804
816
  /**
805
817
  * Signs a request with DPoP and Authorization headers (internal use).
806
818
  */
807
819
  async signRequest(e, r, t = {}) {
808
- const s = r.startsWith("http") ? r : `${this.getBaseUrl()}${r}`, n = await this.getRequestAuthHeaders(e, s);
809
- return { ...t, headers: { ...t.headers, ...n } };
820
+ const n = r.startsWith("http") ? r : `${this.getBaseUrl()}${r}`, s = await this.getRequestAuthHeaders(e, n);
821
+ return { ...t, headers: { ...t.headers, ...s } };
810
822
  }
811
823
  /**
812
824
  * Replaces native fetch or Axios with a DPoP-signed version.
813
825
  */
814
826
  async authenticatedFetch(e, r) {
815
- const t = typeof e == "string" ? e : e instanceof URL ? e.toString() : e.url, s = r?.method || "GET", n = await this.signRequest(s, t, {
827
+ const t = typeof e == "string" ? e : e instanceof URL ? e.toString() : e.url, n = r?.method || "GET", s = await this.signRequest(n, t, {
816
828
  headers: r?.headers
817
829
  });
818
- return fetch(e, { ...r, headers: n.headers });
830
+ return fetch(e, { ...r, headers: s.headers });
819
831
  }
820
832
  /**
821
833
  * Store tokens from /webauthn/authenticate (per spec: sessionStorage preferred).
822
834
  */
823
835
  async storeTokens(e) {
824
- localStorage.setItem(b, e.accessToken), e.refreshToken && localStorage.setItem(D, e.refreshToken);
836
+ localStorage.setItem(P, e.accessToken), e.refreshToken && localStorage.setItem(R, e.refreshToken);
825
837
  }
826
838
  /**
827
839
  * Clear stored tokens (call on logout).
828
840
  */
829
841
  async clearTokens() {
830
- localStorage.removeItem(b), localStorage.removeItem(D);
842
+ localStorage.removeItem(P), localStorage.removeItem(R);
831
843
  }
832
844
  /**
833
845
  * POST /auth/refresh - Refresh access token using server-stored refresh token.
@@ -837,13 +849,13 @@ class U {
837
849
  async refreshToken(e) {
838
850
  const r = this.extractRealm(void 0, e), t = await this.request("POST", "/auth/refresh", {
839
851
  body: r ? { realm: r } : {}
840
- }), s = t.data.data ?? t.data, n = s.access_token, a = s.token_type, l = s.expires_in;
841
- return n && await this.storeTokens({
842
- accessToken: n,
852
+ }), n = t.data.data ?? t.data, s = n.access_token, a = n.token_type, l = n.expires_in;
853
+ return s && await this.storeTokens({
854
+ accessToken: s,
843
855
  expiresIn: l,
844
856
  tokenType: a
845
857
  }), {
846
- access_token: n,
858
+ access_token: s,
847
859
  token_type: a,
848
860
  expires_in: l
849
861
  };
@@ -861,28 +873,28 @@ class U {
861
873
  await this.clearTokens();
862
874
  }
863
875
  async getAccessToken() {
864
- return localStorage.getItem(b);
876
+ return localStorage.getItem(P);
865
877
  }
866
878
  }
867
- typeof window < "u" && (window.AuthSDK = U);
868
- const we = typeof window < "u" ? window : globalThis;
869
- we.AuthSDK = U;
879
+ typeof window < "u" && (window.AuthSDK = z);
880
+ const be = typeof window < "u" ? window : globalThis;
881
+ be.AuthSDK = z;
870
882
  export {
871
- U as AuthSDK,
872
- fe as AuthSDKFetchError,
873
- y as SDKValidationError,
874
- O as arrayBufferToBase64,
875
- h as arrayBufferToBase64url,
883
+ z as AuthSDK,
884
+ we as AuthSDKFetchError,
885
+ h as SDKValidationError,
886
+ N as arrayBufferToBase64,
887
+ p as arrayBufferToBase64url,
876
888
  C as base64ToArrayBuffer,
877
- P as base64urlToArrayBuffer,
878
- V as clearPasskeyEmail,
879
- Q as clearPasskeyMobileNumber,
880
- G as getPasskeyEmail,
881
- X as getPasskeyMobileNumber,
882
- M as isConditionalUISupported,
883
- R as isWebAuthnSupported,
884
- Y as setPasskeyEmail,
885
- Z as setPasskeyMobileNumber,
889
+ b as base64urlToArrayBuffer,
890
+ X as clearPasskeyEmail,
891
+ ee as clearPasskeyMobileNumber,
892
+ Y as getPasskeyEmail,
893
+ Z as getPasskeyMobileNumber,
894
+ j as isConditionalUISupported,
895
+ O as isWebAuthnSupported,
896
+ V as setPasskeyEmail,
897
+ Q as setPasskeyMobileNumber,
886
898
  k as stringToArrayBuffer,
887
- J as uint8ArrayToString
899
+ F as uint8ArrayToString
888
900
  };
@@ -1 +1 @@
1
- var PostexAuthSDKStage=(function(d){"use strict";function T(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function N(){if(!T())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function E(s){const e=new Uint8Array(s);let r="";for(let t=0;t<e.byteLength;t++)r+=String.fromCharCode(e[t]);return btoa(r)}function _(s){if(typeof s!="string"||!s)throw new Error("Invalid base64: expected non-empty string");const e=s.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),r=e.length%4,t=r>0?e+"=".repeat(4-r):e;try{const n=atob(t),a=new Uint8Array(n.length);for(let o=0;o<n.length;o++)a[o]=n.charCodeAt(o);return a.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function y(s){return E(s).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function V(s){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(s)}function X(s){const e=s.replace(/-/g,""),r=new Uint8Array(e.length/2);for(let t=0;t<r.length;t++)r[t]=parseInt(e.substr(t*2,2),16);return r.buffer}function b(s){if(!s||typeof s!="string")throw new Error("Invalid input: expected non-empty string");return V(s)?X(s):_(s)}function g(s){return new TextEncoder().encode(s).buffer}function x(s){return String.fromCharCode(...s)}const Z="xpay_webauthn",Q=1,u="passkey_data",S="passkey_email",A="passkey_mobile_number";function f(){return new Promise((s,e)=>{const r=indexedDB.open(Z,Q);r.onerror=()=>e(r.error),r.onsuccess=()=>s(r.result),r.onupgradeneeded=()=>{const t=r.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)}})}async function C(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(S);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function K(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,S);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch{}}async function q(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),a=t.objectStore(u).delete(S);a.onerror=()=>r(a.error),a.onsuccess=()=>e(),t.oncomplete=()=>s.close()})}catch{}}async function $(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(A);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function B(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,A);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch{}}async function M(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),a=t.objectStore(u).delete(A);a.onerror=()=>r(a.error),a.onsuccess=()=>e(),t.oncomplete=()=>s.close()})}catch{}}const v="dpop_private_key",I="dpop_public_key_jwk";function U(s){if(!s||typeof s!="object")return!1;const e=s;return e.kty==="EC"&&e.crv==="P-256"&&typeof e.x=="string"&&typeof e.y=="string"}class D extends Error{constructor(e){super(e),this.name="DPoPProofGenerationError"}}function ee(s){return{kty:"EC",crv:"P-256",x:s.x,y:s.y}}async function z(s){const e=JSON.stringify({crv:s.crv,kty:s.kty,x:s.x,y:s.y}),r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return y(r)}async function te(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,v);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP private key:",e)}}async function re(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,I);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP public key JWK:",e)}}async function L(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(v);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function j(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(I);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function R(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),n=t.objectStore(u);n.delete(v),n.delete(I),t.onerror=()=>r(t.error),t.oncomplete=()=>{s.close(),e()}})}catch{}}async function ae(){const s=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",s.publicKey),r=ee(e),t=await z(r);return await te(s.privateKey),await re(r),{publicKey:r,thumbprint:t}}async function ne(){const s=await L(),e=await j();return s&&U(e)?{publicKey:e,thumbprint:await z(e)}:((s||e)&&await R(),ae())}async function se(s,e,r){try{const t=await L(),n=await j();if(!t||!U(n))throw new D("DPoP key material is unavailable or invalid");const a={typ:"dpop+jwt",alg:"ES256",jwk:n},o=new URL(e,typeof window<"u"?window.location.origin:void 0),l=`${o.origin}${o.pathname}`,c={jti:crypto.randomUUID(),htm:s.toUpperCase(),htu:l,iat:Math.floor(Date.now()/1e3)};if(r){const we=new TextEncoder().encode(r),be=await crypto.subtle.digest("SHA-256",we);c.ath=y(be)}const h=y(new TextEncoder().encode(JSON.stringify(a)).buffer),i=y(new TextEncoder().encode(JSON.stringify(c)).buffer),m=`${h}.${i}`,w=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,new TextEncoder().encode(m)),P=y(w);return`${h}.${i}.${P}`}catch(t){throw console.error("Failed to generate DPoP proof:",t),t instanceof D?t:new D("Failed to generate DPoP proof")}}const H={isWebAuthnSupported:T,isConditionalUISupported:N,arrayBufferToBase64:E,base64ToArrayBuffer:_,arrayBufferToBase64url:y,base64urlToArrayBuffer:b,stringToArrayBuffer:g,uint8ArrayToString:x,getPasskeyEmail:C,setPasskeyEmail:K,clearPasskeyEmail:q,getPasskeyMobileNumber:$,setPasskeyMobileNumber:B,clearPasskeyMobileNumber:M};typeof window<"u"&&(window.WebAuthn=H);const oe=typeof window<"u"?window:globalThis;oe.WebAuthn=H;const k="postex-auth-token",ie="postexglobal",ce={xstak:"https://auth-stage.xstak.com/public/v1",postex:"https://auth-stage.postex.pk/public/v1",callcourier:"https://auth-stage.callcourier.com.pk/public/v1",postexglobal:"https://auth-stage.postexglobal.com/public/v1",postexsa:"https://auth-stage.postex.sa/public/v1"},le=/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,ue=/^\+[1-9]\d{6,14}$/,de=/^\d{6}$/,he=/^[A-Za-z0-9_-]{16,512}$/,ye=/[\u0000-\u001F\u007F-\u009F]/,pe=/[A-Za-z]/,me=/[\u0400-\u04FF]/,J=254,F=16,W=64;class G extends Error{constructor(e,r,t){super(t??`Request failed with status ${e}`),this.response={status:e,data:r},this.name="AuthSDKFetchError"}}class p extends Error{constructor(e,r,t="invalid_input"){super(r),this.field=e,this.code=t,this.name="SDKValidationError"}}const Y="auth_sdk_refresh_token";class O{constructor(e){this.config=e,this.dpopInitializationPromise=this.createDPoPInitializationPromise()}getBaseUrl(){const e=this.config.appId??ie;return ce[e]}async initializeDPoPState(){await ne()}async ensureDPoPInitialized(){await this.dpopInitializationPromise}createDPoPInitializationPromise(){const e=this.initializeDPoPState();return e.catch(r=>{console.warn("[AuthSDK] DPoP initialization failed:",r)}),e}resetDPoPInitialization(){this.dpopInitializationPromise=this.createDPoPInitializationPromise()}async getRequiredDPoPProof(e,r,t){return await this.ensureDPoPInitialized(),se(e.toUpperCase(),r,t)}containsControlChars(e){return ye.test(e)}hasMixedLatinAndCyrillic(e){return pe.test(e)&&me.test(e)}assertNoControlChars(e,r){if(this.containsControlChars(r))throw new p(e,`${e} must not contain control characters`)}validateEmail(e,r="email"){const t=e.trim();if(!t)throw new p(r,`${r} is required`);if(t.length>J)throw new p(r,`${r} must be ${J} characters or fewer`);this.assertNoControlChars(r,t);const[n=""]=t.split("@");if(this.hasMixedLatinAndCyrillic(n))throw new p(r,`${r} must not mix Latin and Cyrillic characters in the local part`);if(!le.test(t))throw new p(r,`${r} must be a valid email`);return t}validateMobileNumber(e,r="mobileNumber"){const t=e.trim();if(!t)throw new p(r,`${r} is required`);if(t.length>F)throw new p(r,`${r} must be ${F} characters or fewer`);if(this.assertNoControlChars(r,t),!ue.test(t))throw new p(r,`${r} must be in E.164 format`);return t}validateOTP(e,r="otp"){const t=e.trim();if(this.assertNoControlChars(r,t),!de.test(t))throw new p(r,`${r} must be a 6-digit code`);return t}validateMagicLinkToken(e,r="token"){const t=e.trim();if(this.assertNoControlChars(r,t),!he.test(t))throw new p(r,`${r} must be 16-512 URL-safe characters`);return t}validateRealm(e){const r=e?.trim();if(r){if(this.assertNoControlChars("realm",r),r.length>W)throw new p("realm",`realm must be ${W} characters or fewer`);return r}}normalizeAndValidateIdentifier(e){return typeof e=="string"?{email:this.validateEmail(e)}:{email:e.email?this.validateEmail(e.email):void 0,mobileNumber:e.mobileNumber?this.validateMobileNumber(e.mobileNumber):void 0}}normalizeAuthIdentifier(e){return this.normalizeAndValidateIdentifier(e)}extractRealm(e,r){const t=r?.realm??(e&&typeof e!="string"?e.realm:void 0);return this.validateRealm(t)}buildAuthRequestBody(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r);return{...t,...n?{realm:n}:{}}}buildUrl(e,r){const t=this.getBaseUrl().replace(/\/$/,""),n=e.startsWith("/")?e:`/${e}`,a=`${t}${n}`;if(!r||Object.keys(r).length===0)return a;const o=new URLSearchParams(r).toString();return`${a}?${o}`}async request(e,r,t){const n=this.buildUrl(r,t?.params),a={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...t?.headers},o={method:e,credentials:"include",headers:a};t?.body!==void 0&&t?.body!==null&&(o.body=JSON.stringify(t.body));const l=await fetch(n,o);if(!l.ok){let i;try{const m=await l.text();i=m?JSON.parse(m):void 0}catch{i=void 0}throw l.status===401&&(await this.clearTokens(),await R(),this.resetDPoPInitialization()),new G(l.status,i)}const c=await l.text();return{data:c?JSON.parse(c):{}}}async getRequestAuthHeaders(e,r){const t=localStorage.getItem(k);if(!t)return{};const n=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,a=await this.getRequiredDPoPProof(e,n,t);return{Authorization:`Bearer ${t}`,DPoP:a}}async getStatus(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r),a={};t.email&&(a.email=t.email),t.mobileNumber&&(a.mobileNumber=t.mobileNumber),n&&(a.realm=n);const o=await this.request("GET","/auth/status",{params:a});return o.data.data??o.data}async initiateAuth(e,r){const t=this.buildAuthRequestBody(e,r),n=await this.request("POST","/auth/initiate",{body:t}),a=n.data.data??n.data;return{status:a.status,challenge:a.challenge,credentialIds:a.credentialIds,rp:a.rp}}async initiateOTP(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r),a=t.email,o=t.mobileNumber;if(!a&&!o)throw new p("identifier","Either mobileNumber or email is required");const l={};a&&(l.email=a),o&&(l.mobileNumber=o),n&&(l.realm=n);const h=(await this.request("POST","/otp/initiate",{body:l})).data;return{message:h.message??h.data?.message}}async verifyOTP(e){const r=this.validateOTP(e),t=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/verify`),n=await this.request("POST","/otp/verify",{body:{otp:r},headers:{DPoP:t}}),a=n.data.data??n.data,o=a.AuthenticationResult??a,l=o.access_token??o.accessToken??o.AccessToken,c=o.refresh_token??o.refreshToken??o.RefreshToken,h=o.expires_in??o.expiresIn,i=o.token_type??o.tokenType;return l&&await this.storeTokens({accessToken:l,refreshToken:c,expiresIn:h,tokenType:i}),{access_token:l,refresh_token:c,expires_in:h,token_type:i,verified:o.verified,email:o.email??o.Email,...o}}async resendOTP(){const e=await this.request("POST","/otp/resend",{}),r=e.data.data??e.data;return{success:r.success,message:r.message,...r}}async verifySignupOTP({mobileNumber:e,otp:r}){const t=this.validateMobileNumber(e),n=this.validateOTP(r),a=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/signup/verify`),o=await this.request("POST","/otp/signup/verify",{body:{mobileNumber:t,otp:n},headers:{DPoP:a}}),l=o.data.data??o.data,c=l.AuthenticationResult??l,h=c.access_token??c.accessToken??c.AccessToken,i=c.refresh_token??c.refreshToken??c.RefreshToken,m=c.expires_in??c.expiresIn,w=c.token_type??c.tokenType;return h&&await this.storeTokens({accessToken:h,refreshToken:i,expiresIn:m,tokenType:w}),{access_token:h,refresh_token:i,expires_in:m,token_type:w,verified:c.verified,email:c.email??c.Email,...c}}async resendSignupOTP({mobileNumber:e,email:r=""}){const t=this.validateMobileNumber(e),n=r?this.validateEmail(r):"",a=await this.request("POST","/otp/signup/resend",{body:{email:n,mobileNumber:t}}),o=a.data.data??a.data;return{success:o.success,message:o.message,...o}}async verifyMagicLink(e){const r=this.validateMagicLinkToken(e);await this.request("GET","/verify/magic-link",{params:{token:r,redirect_mode:"frontend"}})}async completeMagicLink(){const e=await this.request("POST","/verify/magic-link/complete",{body:{}}),r=e.data.data??e.data,t=r.AuthenticationResult??r,n=t.access_token??t.accessToken??t.AccessToken,a=t.refresh_token??t.refreshToken??t.RefreshToken,o=t.expires_in??t.expiresIn,l=t.token_type??t.tokenType;return n&&await this.storeTokens({accessToken:n,refreshToken:a,expiresIn:o,tokenType:l}),{access_token:n,refresh_token:a,expires_in:o,token_type:l,verified:t.verified,email:t.email??t.Email,...t}}async initiatePasskeyRegistration(){const e=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return e.data.data??e.data}async registerPasskey(e){const r=this.validateEmail(e),t=await this.initiatePasskeyRegistration();let n;if(t?.user?.id)try{n=b(t.user.id)}catch{n=g(t.user.id)}else n=g(r);const a=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(P=>({type:"public-key",alg:P.alg})),o=t.excludeCredentials?.map(P=>({type:"public-key",id:b(P)})),l={challenge:b(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:n,name:t.user?.name??r,displayName:t.user?.displayName??r},pubKeyCredParams:a,excludeCredentials:o,timeout:t.timeout??6e4,attestation:"direct",authenticatorSelection:{residentKey:"required",userVerification:"required",authenticatorAttachment:"platform"}},c=await navigator.credentials.create({publicKey:l});if(!c)throw new Error("Credential creation failed");const h=c.response,i={clientDataJSON:y(h.clientDataJSON),attestationObject:y(h.attestationObject),rawId:y(c.rawId)};if(!i.rawId)throw new Error("Raw ID is required");const m=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/register/challenge`),w=await this.request("POST","/webauthn/register/challenge",{body:i,headers:{DPoP:m}});return w.data.data??w.data}async authenticateWithPasskey({challenge:e,rp:r,credentialIds:t}){const n=await navigator.credentials.get({publicKey:{challenge:b(e),rpId:r?.host??void 0,allowCredentials:t.map(P=>({type:"public-key",id:b(P),transports:["internal"]})),timeout:6e4,userVerification:"required"}});if(!n)throw new Error("Authentication failed");const a=n.response,o={clientDataJSON:y(a.clientDataJSON),authenticatorData:y(a.authenticatorData),signature:y(a.signature),rawId:y(n.rawId),userHandle:a.userHandle?y(a.userHandle):""},l=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/authenticate/challenge`),c=await this.request("POST","/webauthn/authenticate/challenge",{body:o,headers:{DPoP:l}}),h=c.data.data??c.data,i=h.AuthenticationResult??h,m=i.AccessToken??i.accessToken??i.access_token,w=i.RefreshToken??i.refreshToken??i.refresh_token;return m&&await this.storeTokens({accessToken:m,refreshToken:w,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type}),{access_token:m,refresh_token:w,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,n=await this.signRequest("GET",t),a=await this.request("GET",t,{headers:n.headers}),o=a.data.data??a.data;return{...o,hasCredentials:!!(o.hasCredentials??o.credentialId)}}async removePasskey(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,n=await this.signRequest("DELETE",t);await this.request("DELETE",t,{headers:n.headers})}async signRequest(e,r,t={}){const n=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,a=await this.getRequestAuthHeaders(e,n);return{...t,headers:{...t.headers,...a}}}async authenticatedFetch(e,r){const t=typeof e=="string"?e:e instanceof URL?e.toString():e.url,n=r?.method||"GET",a=await this.signRequest(n,t,{headers:r?.headers});return fetch(e,{...r,headers:a.headers})}async storeTokens(e){localStorage.setItem(k,e.accessToken),e.refreshToken&&localStorage.setItem(Y,e.refreshToken)}async clearTokens(){localStorage.removeItem(k),localStorage.removeItem(Y)}async refreshToken(e){const r=this.extractRealm(void 0,e),t=await this.request("POST","/auth/refresh",{body:r?{realm:r}:{}}),n=t.data.data??t.data,a=n.access_token,o=n.token_type,l=n.expires_in;return a&&await this.storeTokens({accessToken:a,expiresIn:l,tokenType:o}),{access_token:a,token_type:o,expires_in:l}}async logout(){try{const r=await this.getAccessToken()?await this.signRequest("POST","/auth/logout",{body:{}}):{body:{}};await this.request("POST","/auth/logout",r),await R(),this.resetDPoPInitialization()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(k)}}typeof window<"u"&&(window.AuthSDK=O);const fe=typeof window<"u"?window:globalThis;return fe.AuthSDK=O,d.AuthSDK=O,d.AuthSDKFetchError=G,d.SDKValidationError=p,d.arrayBufferToBase64=E,d.arrayBufferToBase64url=y,d.base64ToArrayBuffer=_,d.base64urlToArrayBuffer=b,d.clearPasskeyEmail=q,d.clearPasskeyMobileNumber=M,d.getPasskeyEmail=C,d.getPasskeyMobileNumber=$,d.isConditionalUISupported=N,d.isWebAuthnSupported=T,d.setPasskeyEmail=K,d.setPasskeyMobileNumber=B,d.stringToArrayBuffer=g,d.uint8ArrayToString=x,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}),d})({});
1
+ var PostexAuthSDKStage=(function(d){"use strict";function T(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function O(){if(!T())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function E(s){const e=new Uint8Array(s);let r="";for(let t=0;t<e.byteLength;t++)r+=String.fromCharCode(e[t]);return btoa(r)}function _(s){if(typeof s!="string"||!s)throw new Error("Invalid base64: expected non-empty string");const e=s.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),r=e.length%4,t=r>0?e+"=".repeat(4-r):e;try{const n=atob(t),a=new Uint8Array(n.length);for(let o=0;o<n.length;o++)a[o]=n.charCodeAt(o);return a.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function y(s){return E(s).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function X(s){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(s)}function Z(s){const e=s.replace(/-/g,""),r=new Uint8Array(e.length/2);for(let t=0;t<r.length;t++)r[t]=parseInt(e.substr(t*2,2),16);return r.buffer}function b(s){if(!s||typeof s!="string")throw new Error("Invalid input: expected non-empty string");return X(s)?Z(s):_(s)}function g(s){return new TextEncoder().encode(s).buffer}function C(s){return String.fromCharCode(...s)}const Q="xpay_webauthn",ee=1,u="passkey_data",S="passkey_email",A="passkey_mobile_number";function f(){return new Promise((s,e)=>{const r=indexedDB.open(Q,ee);r.onerror=()=>e(r.error),r.onsuccess=()=>s(r.result),r.onupgradeneeded=()=>{const t=r.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)}})}async function x(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(S);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function K(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,S);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch{}}async function q(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),a=t.objectStore(u).delete(S);a.onerror=()=>r(a.error),a.onsuccess=()=>e(),t.oncomplete=()=>s.close()})}catch{}}async function $(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(A);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function B(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,A);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch{}}async function U(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),a=t.objectStore(u).delete(A);a.onerror=()=>r(a.error),a.onsuccess=()=>e(),t.oncomplete=()=>s.close()})}catch{}}const v="dpop_private_key",I="dpop_public_key_jwk";function M(s){if(!s||typeof s!="object")return!1;const e=s;return e.kty==="EC"&&e.crv==="P-256"&&typeof e.x=="string"&&typeof e.y=="string"}class D extends Error{constructor(e){super(e),this.name="DPoPProofGenerationError"}}function te(s){return{kty:"EC",crv:"P-256",x:s.x,y:s.y}}async function z(s){const e=JSON.stringify({crv:s.crv,kty:s.kty,x:s.x,y:s.y}),r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return y(r)}async function re(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,v);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP private key:",e)}}async function ae(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,I);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP public key JWK:",e)}}async function L(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(v);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function j(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(I);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function R(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),n=t.objectStore(u);n.delete(v),n.delete(I),t.onerror=()=>r(t.error),t.oncomplete=()=>{s.close(),e()}})}catch{}}async function ne(){const s=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",s.publicKey),r=te(e),t=await z(r);return await re(s.privateKey),await ae(r),{publicKey:r,thumbprint:t}}async function se(){const s=await L(),e=await j();return s&&M(e)?{publicKey:e,thumbprint:await z(e)}:((s||e)&&await R(),ne())}async function oe(s,e,r){try{const t=await L(),n=await j();if(!t||!M(n))throw new D("DPoP key material is unavailable or invalid");const a={typ:"dpop+jwt",alg:"ES256",jwk:n},o=new URL(e,typeof window<"u"?window.location.origin:void 0),l=`${o.origin}${o.pathname}`,c={jti:crypto.randomUUID(),htm:s.toUpperCase(),htu:l,iat:Math.floor(Date.now()/1e3)};if(r){const be=new TextEncoder().encode(r),Pe=await crypto.subtle.digest("SHA-256",be);c.ath=y(Pe)}const h=y(new TextEncoder().encode(JSON.stringify(a)).buffer),i=y(new TextEncoder().encode(JSON.stringify(c)).buffer),p=`${h}.${i}`,w=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,new TextEncoder().encode(p)),P=y(w);return`${h}.${i}.${P}`}catch(t){throw console.error("Failed to generate DPoP proof:",t),t instanceof D?t:new D("Failed to generate DPoP proof")}}const H={isWebAuthnSupported:T,isConditionalUISupported:O,arrayBufferToBase64:E,base64ToArrayBuffer:_,arrayBufferToBase64url:y,base64urlToArrayBuffer:b,stringToArrayBuffer:g,uint8ArrayToString:C,getPasskeyEmail:x,setPasskeyEmail:K,clearPasskeyEmail:q,getPasskeyMobileNumber:$,setPasskeyMobileNumber:B,clearPasskeyMobileNumber:U};typeof window<"u"&&(window.WebAuthn=H);const ie=typeof window<"u"?window:globalThis;ie.WebAuthn=H;const k="postex-auth-token",ce="postexglobal",le={xstak:"https://auth-stage.xstak.com/public/v1",postex:"https://auth-stage.postex.pk/public/v1",callcourier:"https://auth-stage.callcourier.com.pk/public/v1",postexglobal:"https://auth-stage.postexglobal.com/public/v1",postexsa:"https://auth-stage.postex.sa/public/v1"},ue=/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,de=/^\+[1-9]\d{6,14}$/,he=/^\d{6}$/,ye=/^[A-Za-z0-9_-]{16,512}$/,me=/[\u0000-\u001F\u007F-\u009F]/,pe=/[A-Za-z]/,fe=/[\u0400-\u04FF]/,J=254,F=16,W=64,G=64;class Y extends Error{constructor(e,r,t){super(t??`Request failed with status ${e}`),this.response={status:e,data:r},this.name="AuthSDKFetchError"}}class m extends Error{constructor(e,r,t="invalid_input"){super(r),this.field=e,this.code=t,this.name="SDKValidationError"}}const V="auth_sdk_refresh_token";class N{constructor(e){this.config=e,this.dpopInitializationPromise=this.createDPoPInitializationPromise()}getBaseUrl(){const e=this.config.appId??ce;return le[e]}async initializeDPoPState(){await se()}async ensureDPoPInitialized(){await this.dpopInitializationPromise}createDPoPInitializationPromise(){const e=this.initializeDPoPState();return e.catch(r=>{console.warn("[AuthSDK] DPoP initialization failed:",r)}),e}resetDPoPInitialization(){this.dpopInitializationPromise=this.createDPoPInitializationPromise()}async getRequiredDPoPProof(e,r,t){return await this.ensureDPoPInitialized(),oe(e.toUpperCase(),r,t)}containsControlChars(e){return me.test(e)}hasMixedLatinAndCyrillic(e){return pe.test(e)&&fe.test(e)}assertNoControlChars(e,r){if(this.containsControlChars(r))throw new m(e,`${e} must not contain control characters`)}validateEmail(e,r="email"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>J)throw new m(r,`${r} must be ${J} characters or fewer`);this.assertNoControlChars(r,t);const[n=""]=t.split("@");if(this.hasMixedLatinAndCyrillic(n))throw new m(r,`${r} must not mix Latin and Cyrillic characters in the local part`);if(!ue.test(t))throw new m(r,`${r} must be a valid email`);return t}validateMobileNumber(e,r="mobileNumber"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>F)throw new m(r,`${r} must be ${F} characters or fewer`);if(this.assertNoControlChars(r,t),!de.test(t))throw new m(r,`${r} must be in E.164 format`);return t}validateUsername(e,r="username"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>W)throw new m(r,`${r} must be ${W} characters or fewer`);return this.assertNoControlChars(r,t),t}validateOTP(e,r="otp"){const t=e.trim();if(this.assertNoControlChars(r,t),!he.test(t))throw new m(r,`${r} must be a 6-digit code`);return t}validateMagicLinkToken(e,r="token"){const t=e.trim();if(this.assertNoControlChars(r,t),!ye.test(t))throw new m(r,`${r} must be 16-512 URL-safe characters`);return t}validateRealm(e){const r=e?.trim();if(r){if(this.assertNoControlChars("realm",r),r.length>G)throw new m("realm",`realm must be ${G} characters or fewer`);return r}}normalizeAndValidateIdentifier(e){return typeof e=="string"?{email:this.validateEmail(e)}:{email:e.email?this.validateEmail(e.email):void 0,mobileNumber:e.mobileNumber?this.validateMobileNumber(e.mobileNumber):void 0,username:e.username?this.validateUsername(e.username):void 0}}normalizeAuthIdentifier(e){return this.normalizeAndValidateIdentifier(e)}extractRealm(e,r){const t=r?.realm??(e&&typeof e!="string"?e.realm:void 0);return this.validateRealm(t)}buildAuthRequestBody(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r);return{...t,...n?{realm:n}:{}}}buildUrl(e,r){const t=this.getBaseUrl().replace(/\/$/,""),n=e.startsWith("/")?e:`/${e}`,a=`${t}${n}`;if(!r||Object.keys(r).length===0)return a;const o=new URLSearchParams(r).toString();return`${a}?${o}`}async request(e,r,t){const n=this.buildUrl(r,t?.params),a={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...t?.headers},o={method:e,credentials:"include",headers:a};t?.body!==void 0&&t?.body!==null&&(o.body=JSON.stringify(t.body));const l=await fetch(n,o);if(!l.ok){let i;try{const p=await l.text();i=p?JSON.parse(p):void 0}catch{i=void 0}throw l.status===401&&(await this.clearTokens(),await R(),this.resetDPoPInitialization()),new Y(l.status,i)}const c=await l.text();return{data:c?JSON.parse(c):{}}}async getRequestAuthHeaders(e,r){const t=localStorage.getItem(k);if(!t)return{};const n=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,a=await this.getRequiredDPoPProof(e,n,t);return{Authorization:`Bearer ${t}`,DPoP:a}}async getStatus(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r),a={};t.email&&(a.email=t.email),t.mobileNumber&&(a.mobileNumber=t.mobileNumber),t.username&&(a.username=t.username),n&&(a.realm=n);const o=await this.request("GET","/auth/status",{params:a});return o.data.data??o.data}async initiateAuth(e,r){const t=this.buildAuthRequestBody(e,r),n=await this.request("POST","/auth/initiate",{body:t}),a=n.data.data??n.data;return{status:a.status,challenge:a.challenge,credentialIds:a.credentialIds,rp:a.rp}}async initiateOTP(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r),a=t.email,o=t.mobileNumber,l=t.username;if(!a&&!o&&!l)throw new m("identifier","Either mobileNumber, email, or username is required");const c={};a&&(c.email=a),o&&(c.mobileNumber=o),l&&(c.username=l),n&&(c.realm=n);const i=(await this.request("POST","/otp/initiate",{body:c})).data;return{message:i.message??i.data?.message}}async verifyOTP(e){const r=this.validateOTP(e),t=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/verify`),n=await this.request("POST","/otp/verify",{body:{otp:r},headers:{DPoP:t}}),a=n.data.data??n.data,o=a.AuthenticationResult??a,l=o.access_token??o.accessToken??o.AccessToken,c=o.refresh_token??o.refreshToken??o.RefreshToken,h=o.expires_in??o.expiresIn,i=o.token_type??o.tokenType;return l&&await this.storeTokens({accessToken:l,refreshToken:c,expiresIn:h,tokenType:i}),{access_token:l,refresh_token:c,expires_in:h,token_type:i,verified:o.verified,email:o.email??o.Email,...o}}async resendOTP(){const e=await this.request("POST","/otp/resend",{}),r=e.data.data??e.data;return{success:r.success,message:r.message,...r}}async verifySignupOTP({mobileNumber:e,otp:r}){const t=this.validateMobileNumber(e),n=this.validateOTP(r),a=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/signup/verify`),o=await this.request("POST","/otp/signup/verify",{body:{mobileNumber:t,otp:n},headers:{DPoP:a}}),l=o.data.data??o.data,c=l.AuthenticationResult??l,h=c.access_token??c.accessToken??c.AccessToken,i=c.refresh_token??c.refreshToken??c.RefreshToken,p=c.expires_in??c.expiresIn,w=c.token_type??c.tokenType;return h&&await this.storeTokens({accessToken:h,refreshToken:i,expiresIn:p,tokenType:w}),{access_token:h,refresh_token:i,expires_in:p,token_type:w,verified:c.verified,email:c.email??c.Email,...c}}async resendSignupOTP({mobileNumber:e,email:r=""}){const t=this.validateMobileNumber(e),n=r?this.validateEmail(r):"",a=await this.request("POST","/otp/signup/resend",{body:{email:n,mobileNumber:t}}),o=a.data.data??a.data;return{success:o.success,message:o.message,...o}}async verifyMagicLink(e){const r=this.validateMagicLinkToken(e);await this.request("GET","/verify/magic-link",{params:{token:r,redirect_mode:"frontend"}})}async completeMagicLink(){const e=await this.request("POST","/verify/magic-link/complete",{body:{}}),r=e.data.data??e.data,t=r.AuthenticationResult??r,n=t.access_token??t.accessToken??t.AccessToken,a=t.refresh_token??t.refreshToken??t.RefreshToken,o=t.expires_in??t.expiresIn,l=t.token_type??t.tokenType;return n&&await this.storeTokens({accessToken:n,refreshToken:a,expiresIn:o,tokenType:l}),{access_token:n,refresh_token:a,expires_in:o,token_type:l,verified:t.verified,email:t.email??t.Email,...t}}async initiatePasskeyRegistration(){const e=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return e.data.data??e.data}async registerPasskey(e){const r=this.validateEmail(e),t=await this.initiatePasskeyRegistration();let n;if(t?.user?.id)try{n=b(t.user.id)}catch{n=g(t.user.id)}else n=g(r);const a=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(P=>({type:"public-key",alg:P.alg})),o=t.excludeCredentials?.map(P=>({type:"public-key",id:b(P)})),l={challenge:b(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:n,name:t.user?.name??r,displayName:t.user?.displayName??r},pubKeyCredParams:a,excludeCredentials:o,timeout:t.timeout??6e4,attestation:"direct",authenticatorSelection:{residentKey:"required",userVerification:"required",authenticatorAttachment:"platform"}},c=await navigator.credentials.create({publicKey:l});if(!c)throw new Error("Credential creation failed");const h=c.response,i={clientDataJSON:y(h.clientDataJSON),attestationObject:y(h.attestationObject),rawId:y(c.rawId)};if(!i.rawId)throw new Error("Raw ID is required");const p=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/register/challenge`),w=await this.request("POST","/webauthn/register/challenge",{body:i,headers:{DPoP:p}});return w.data.data??w.data}async authenticateWithPasskey({challenge:e,rp:r,credentialIds:t}){const n=await navigator.credentials.get({publicKey:{challenge:b(e),rpId:r?.host??void 0,allowCredentials:t.map(P=>({type:"public-key",id:b(P),transports:["internal"]})),timeout:6e4,userVerification:"required"}});if(!n)throw new Error("Authentication failed");const a=n.response,o={clientDataJSON:y(a.clientDataJSON),authenticatorData:y(a.authenticatorData),signature:y(a.signature),rawId:y(n.rawId),userHandle:a.userHandle?y(a.userHandle):""},l=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/authenticate/challenge`),c=await this.request("POST","/webauthn/authenticate/challenge",{body:o,headers:{DPoP:l}}),h=c.data.data??c.data,i=h.AuthenticationResult??h,p=i.AccessToken??i.accessToken??i.access_token,w=i.RefreshToken??i.refreshToken??i.refresh_token;return p&&await this.storeTokens({accessToken:p,refreshToken:w,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type}),{access_token:p,refresh_token:w,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,n=await this.signRequest("GET",t),a=await this.request("GET",t,{headers:n.headers}),o=a.data.data??a.data;return{...o,hasCredentials:!!(o.hasCredentials??o.credentialId)}}async removePasskey(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,n=await this.signRequest("DELETE",t);await this.request("DELETE",t,{headers:n.headers})}async signRequest(e,r,t={}){const n=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,a=await this.getRequestAuthHeaders(e,n);return{...t,headers:{...t.headers,...a}}}async authenticatedFetch(e,r){const t=typeof e=="string"?e:e instanceof URL?e.toString():e.url,n=r?.method||"GET",a=await this.signRequest(n,t,{headers:r?.headers});return fetch(e,{...r,headers:a.headers})}async storeTokens(e){localStorage.setItem(k,e.accessToken),e.refreshToken&&localStorage.setItem(V,e.refreshToken)}async clearTokens(){localStorage.removeItem(k),localStorage.removeItem(V)}async refreshToken(e){const r=this.extractRealm(void 0,e),t=await this.request("POST","/auth/refresh",{body:r?{realm:r}:{}}),n=t.data.data??t.data,a=n.access_token,o=n.token_type,l=n.expires_in;return a&&await this.storeTokens({accessToken:a,expiresIn:l,tokenType:o}),{access_token:a,token_type:o,expires_in:l}}async logout(){try{const r=await this.getAccessToken()?await this.signRequest("POST","/auth/logout",{body:{}}):{body:{}};await this.request("POST","/auth/logout",r),await R(),this.resetDPoPInitialization()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(k)}}typeof window<"u"&&(window.AuthSDK=N);const we=typeof window<"u"?window:globalThis;return we.AuthSDK=N,d.AuthSDK=N,d.AuthSDKFetchError=Y,d.SDKValidationError=m,d.arrayBufferToBase64=E,d.arrayBufferToBase64url=y,d.base64ToArrayBuffer=_,d.base64urlToArrayBuffer=b,d.clearPasskeyEmail=q,d.clearPasskeyMobileNumber=U,d.getPasskeyEmail=x,d.getPasskeyMobileNumber=$,d.isConditionalUISupported=O,d.isWebAuthnSupported=T,d.setPasskeyEmail=K,d.setPasskeyMobileNumber=B,d.stringToArrayBuffer=g,d.uint8ArrayToString=C,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}),d})({});
@@ -1 +1 @@
1
- (function(d,b){typeof exports=="object"&&typeof module<"u"?b(exports):typeof define=="function"&&define.amd?define(["exports"],b):(d=typeof globalThis<"u"?globalThis:d||self,b(d.PostexAuthSDKStage={}))})(this,(function(d){"use strict";function b(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function O(){if(!b())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function E(a){const e=new Uint8Array(a);let r="";for(let t=0;t<e.byteLength;t++)r+=String.fromCharCode(e[t]);return btoa(r)}function _(a){if(typeof a!="string"||!a)throw new Error("Invalid base64: expected non-empty string");const e=a.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),r=e.length%4,t=r>0?e+"=".repeat(4-r):e;try{const s=atob(t),n=new Uint8Array(s.length);for(let o=0;o<s.length;o++)n[o]=s.charCodeAt(o);return n.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function y(a){return E(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function V(a){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(a)}function X(a){const e=a.replace(/-/g,""),r=new Uint8Array(e.length/2);for(let t=0;t<r.length;t++)r[t]=parseInt(e.substr(t*2,2),16);return r.buffer}function P(a){if(!a||typeof a!="string")throw new Error("Invalid input: expected non-empty string");return V(a)?X(a):_(a)}function k(a){return new TextEncoder().encode(a).buffer}function N(a){return String.fromCharCode(...a)}const Z="xpay_webauthn",Q=1,u="passkey_data",S="passkey_email",A="passkey_mobile_number";function f(){return new Promise((a,e)=>{const r=indexedDB.open(Z,Q);r.onerror=()=>e(r.error),r.onsuccess=()=>a(r.result),r.onupgradeneeded=()=>{const t=r.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)}})}async function C(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(S);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function K(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,S);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch{}}async function q(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),n=t.objectStore(u).delete(S);n.onerror=()=>r(n.error),n.onsuccess=()=>e(),t.oncomplete=()=>a.close()})}catch{}}async function $(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(A);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function B(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,A);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch{}}async function M(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),n=t.objectStore(u).delete(A);n.onerror=()=>r(n.error),n.onsuccess=()=>e(),t.oncomplete=()=>a.close()})}catch{}}const v="dpop_private_key",I="dpop_public_key_jwk";function U(a){if(!a||typeof a!="object")return!1;const e=a;return e.kty==="EC"&&e.crv==="P-256"&&typeof e.x=="string"&&typeof e.y=="string"}class D extends Error{constructor(e){super(e),this.name="DPoPProofGenerationError"}}function ee(a){return{kty:"EC",crv:"P-256",x:a.x,y:a.y}}async function z(a){const e=JSON.stringify({crv:a.crv,kty:a.kty,x:a.x,y:a.y}),r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return y(r)}async function te(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,v);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP private key:",e)}}async function re(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,I);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP public key JWK:",e)}}async function L(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(v);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function j(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(I);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function R(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),s=t.objectStore(u);s.delete(v),s.delete(I),t.onerror=()=>r(t.error),t.oncomplete=()=>{a.close(),e()}})}catch{}}async function ne(){const a=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",a.publicKey),r=ee(e),t=await z(r);return await te(a.privateKey),await re(r),{publicKey:r,thumbprint:t}}async function se(){const a=await L(),e=await j();return a&&U(e)?{publicKey:e,thumbprint:await z(e)}:((a||e)&&await R(),ne())}async function ae(a,e,r){try{const t=await L(),s=await j();if(!t||!U(s))throw new D("DPoP key material is unavailable or invalid");const n={typ:"dpop+jwt",alg:"ES256",jwk:s},o=new URL(e,typeof window<"u"?window.location.origin:void 0),l=`${o.origin}${o.pathname}`,c={jti:crypto.randomUUID(),htm:a.toUpperCase(),htu:l,iat:Math.floor(Date.now()/1e3)};if(r){const we=new TextEncoder().encode(r),be=await crypto.subtle.digest("SHA-256",we);c.ath=y(be)}const h=y(new TextEncoder().encode(JSON.stringify(n)).buffer),i=y(new TextEncoder().encode(JSON.stringify(c)).buffer),m=`${h}.${i}`,w=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,new TextEncoder().encode(m)),g=y(w);return`${h}.${i}.${g}`}catch(t){throw console.error("Failed to generate DPoP proof:",t),t instanceof D?t:new D("Failed to generate DPoP proof")}}const H={isWebAuthnSupported:b,isConditionalUISupported:O,arrayBufferToBase64:E,base64ToArrayBuffer:_,arrayBufferToBase64url:y,base64urlToArrayBuffer:P,stringToArrayBuffer:k,uint8ArrayToString:N,getPasskeyEmail:C,setPasskeyEmail:K,clearPasskeyEmail:q,getPasskeyMobileNumber:$,setPasskeyMobileNumber:B,clearPasskeyMobileNumber:M};typeof window<"u"&&(window.WebAuthn=H);const oe=typeof window<"u"?window:globalThis;oe.WebAuthn=H;const T="postex-auth-token",ie="postexglobal",ce={xstak:"https://auth-stage.xstak.com/public/v1",postex:"https://auth-stage.postex.pk/public/v1",callcourier:"https://auth-stage.callcourier.com.pk/public/v1",postexglobal:"https://auth-stage.postexglobal.com/public/v1",postexsa:"https://auth-stage.postex.sa/public/v1"},le=/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,ue=/^\+[1-9]\d{6,14}$/,de=/^\d{6}$/,he=/^[A-Za-z0-9_-]{16,512}$/,ye=/[\u0000-\u001F\u007F-\u009F]/,pe=/[A-Za-z]/,me=/[\u0400-\u04FF]/,J=254,F=16,W=64;class G extends Error{constructor(e,r,t){super(t??`Request failed with status ${e}`),this.response={status:e,data:r},this.name="AuthSDKFetchError"}}class p extends Error{constructor(e,r,t="invalid_input"){super(r),this.field=e,this.code=t,this.name="SDKValidationError"}}const Y="auth_sdk_refresh_token";class x{constructor(e){this.config=e,this.dpopInitializationPromise=this.createDPoPInitializationPromise()}getBaseUrl(){const e=this.config.appId??ie;return ce[e]}async initializeDPoPState(){await se()}async ensureDPoPInitialized(){await this.dpopInitializationPromise}createDPoPInitializationPromise(){const e=this.initializeDPoPState();return e.catch(r=>{console.warn("[AuthSDK] DPoP initialization failed:",r)}),e}resetDPoPInitialization(){this.dpopInitializationPromise=this.createDPoPInitializationPromise()}async getRequiredDPoPProof(e,r,t){return await this.ensureDPoPInitialized(),ae(e.toUpperCase(),r,t)}containsControlChars(e){return ye.test(e)}hasMixedLatinAndCyrillic(e){return pe.test(e)&&me.test(e)}assertNoControlChars(e,r){if(this.containsControlChars(r))throw new p(e,`${e} must not contain control characters`)}validateEmail(e,r="email"){const t=e.trim();if(!t)throw new p(r,`${r} is required`);if(t.length>J)throw new p(r,`${r} must be ${J} characters or fewer`);this.assertNoControlChars(r,t);const[s=""]=t.split("@");if(this.hasMixedLatinAndCyrillic(s))throw new p(r,`${r} must not mix Latin and Cyrillic characters in the local part`);if(!le.test(t))throw new p(r,`${r} must be a valid email`);return t}validateMobileNumber(e,r="mobileNumber"){const t=e.trim();if(!t)throw new p(r,`${r} is required`);if(t.length>F)throw new p(r,`${r} must be ${F} characters or fewer`);if(this.assertNoControlChars(r,t),!ue.test(t))throw new p(r,`${r} must be in E.164 format`);return t}validateOTP(e,r="otp"){const t=e.trim();if(this.assertNoControlChars(r,t),!de.test(t))throw new p(r,`${r} must be a 6-digit code`);return t}validateMagicLinkToken(e,r="token"){const t=e.trim();if(this.assertNoControlChars(r,t),!he.test(t))throw new p(r,`${r} must be 16-512 URL-safe characters`);return t}validateRealm(e){const r=e?.trim();if(r){if(this.assertNoControlChars("realm",r),r.length>W)throw new p("realm",`realm must be ${W} characters or fewer`);return r}}normalizeAndValidateIdentifier(e){return typeof e=="string"?{email:this.validateEmail(e)}:{email:e.email?this.validateEmail(e.email):void 0,mobileNumber:e.mobileNumber?this.validateMobileNumber(e.mobileNumber):void 0}}normalizeAuthIdentifier(e){return this.normalizeAndValidateIdentifier(e)}extractRealm(e,r){const t=r?.realm??(e&&typeof e!="string"?e.realm:void 0);return this.validateRealm(t)}buildAuthRequestBody(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r);return{...t,...s?{realm:s}:{}}}buildUrl(e,r){const t=this.getBaseUrl().replace(/\/$/,""),s=e.startsWith("/")?e:`/${e}`,n=`${t}${s}`;if(!r||Object.keys(r).length===0)return n;const o=new URLSearchParams(r).toString();return`${n}?${o}`}async request(e,r,t){const s=this.buildUrl(r,t?.params),n={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...t?.headers},o={method:e,credentials:"include",headers:n};t?.body!==void 0&&t?.body!==null&&(o.body=JSON.stringify(t.body));const l=await fetch(s,o);if(!l.ok){let i;try{const m=await l.text();i=m?JSON.parse(m):void 0}catch{i=void 0}throw l.status===401&&(await this.clearTokens(),await R(),this.resetDPoPInitialization()),new G(l.status,i)}const c=await l.text();return{data:c?JSON.parse(c):{}}}async getRequestAuthHeaders(e,r){const t=localStorage.getItem(T);if(!t)return{};const s=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,n=await this.getRequiredDPoPProof(e,s,t);return{Authorization:`Bearer ${t}`,DPoP:n}}async getStatus(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r),n={};t.email&&(n.email=t.email),t.mobileNumber&&(n.mobileNumber=t.mobileNumber),s&&(n.realm=s);const o=await this.request("GET","/auth/status",{params:n});return o.data.data??o.data}async initiateAuth(e,r){const t=this.buildAuthRequestBody(e,r),s=await this.request("POST","/auth/initiate",{body:t}),n=s.data.data??s.data;return{status:n.status,challenge:n.challenge,credentialIds:n.credentialIds,rp:n.rp}}async initiateOTP(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r),n=t.email,o=t.mobileNumber;if(!n&&!o)throw new p("identifier","Either mobileNumber or email is required");const l={};n&&(l.email=n),o&&(l.mobileNumber=o),s&&(l.realm=s);const h=(await this.request("POST","/otp/initiate",{body:l})).data;return{message:h.message??h.data?.message}}async verifyOTP(e){const r=this.validateOTP(e),t=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/verify`),s=await this.request("POST","/otp/verify",{body:{otp:r},headers:{DPoP:t}}),n=s.data.data??s.data,o=n.AuthenticationResult??n,l=o.access_token??o.accessToken??o.AccessToken,c=o.refresh_token??o.refreshToken??o.RefreshToken,h=o.expires_in??o.expiresIn,i=o.token_type??o.tokenType;return l&&await this.storeTokens({accessToken:l,refreshToken:c,expiresIn:h,tokenType:i}),{access_token:l,refresh_token:c,expires_in:h,token_type:i,verified:o.verified,email:o.email??o.Email,...o}}async resendOTP(){const e=await this.request("POST","/otp/resend",{}),r=e.data.data??e.data;return{success:r.success,message:r.message,...r}}async verifySignupOTP({mobileNumber:e,otp:r}){const t=this.validateMobileNumber(e),s=this.validateOTP(r),n=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/signup/verify`),o=await this.request("POST","/otp/signup/verify",{body:{mobileNumber:t,otp:s},headers:{DPoP:n}}),l=o.data.data??o.data,c=l.AuthenticationResult??l,h=c.access_token??c.accessToken??c.AccessToken,i=c.refresh_token??c.refreshToken??c.RefreshToken,m=c.expires_in??c.expiresIn,w=c.token_type??c.tokenType;return h&&await this.storeTokens({accessToken:h,refreshToken:i,expiresIn:m,tokenType:w}),{access_token:h,refresh_token:i,expires_in:m,token_type:w,verified:c.verified,email:c.email??c.Email,...c}}async resendSignupOTP({mobileNumber:e,email:r=""}){const t=this.validateMobileNumber(e),s=r?this.validateEmail(r):"",n=await this.request("POST","/otp/signup/resend",{body:{email:s,mobileNumber:t}}),o=n.data.data??n.data;return{success:o.success,message:o.message,...o}}async verifyMagicLink(e){const r=this.validateMagicLinkToken(e);await this.request("GET","/verify/magic-link",{params:{token:r,redirect_mode:"frontend"}})}async completeMagicLink(){const e=await this.request("POST","/verify/magic-link/complete",{body:{}}),r=e.data.data??e.data,t=r.AuthenticationResult??r,s=t.access_token??t.accessToken??t.AccessToken,n=t.refresh_token??t.refreshToken??t.RefreshToken,o=t.expires_in??t.expiresIn,l=t.token_type??t.tokenType;return s&&await this.storeTokens({accessToken:s,refreshToken:n,expiresIn:o,tokenType:l}),{access_token:s,refresh_token:n,expires_in:o,token_type:l,verified:t.verified,email:t.email??t.Email,...t}}async initiatePasskeyRegistration(){const e=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return e.data.data??e.data}async registerPasskey(e){const r=this.validateEmail(e),t=await this.initiatePasskeyRegistration();let s;if(t?.user?.id)try{s=P(t.user.id)}catch{s=k(t.user.id)}else s=k(r);const n=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(g=>({type:"public-key",alg:g.alg})),o=t.excludeCredentials?.map(g=>({type:"public-key",id:P(g)})),l={challenge:P(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:s,name:t.user?.name??r,displayName:t.user?.displayName??r},pubKeyCredParams:n,excludeCredentials:o,timeout:t.timeout??6e4,attestation:"direct",authenticatorSelection:{residentKey:"required",userVerification:"required",authenticatorAttachment:"platform"}},c=await navigator.credentials.create({publicKey:l});if(!c)throw new Error("Credential creation failed");const h=c.response,i={clientDataJSON:y(h.clientDataJSON),attestationObject:y(h.attestationObject),rawId:y(c.rawId)};if(!i.rawId)throw new Error("Raw ID is required");const m=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/register/challenge`),w=await this.request("POST","/webauthn/register/challenge",{body:i,headers:{DPoP:m}});return w.data.data??w.data}async authenticateWithPasskey({challenge:e,rp:r,credentialIds:t}){const s=await navigator.credentials.get({publicKey:{challenge:P(e),rpId:r?.host??void 0,allowCredentials:t.map(g=>({type:"public-key",id:P(g),transports:["internal"]})),timeout:6e4,userVerification:"required"}});if(!s)throw new Error("Authentication failed");const n=s.response,o={clientDataJSON:y(n.clientDataJSON),authenticatorData:y(n.authenticatorData),signature:y(n.signature),rawId:y(s.rawId),userHandle:n.userHandle?y(n.userHandle):""},l=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/authenticate/challenge`),c=await this.request("POST","/webauthn/authenticate/challenge",{body:o,headers:{DPoP:l}}),h=c.data.data??c.data,i=h.AuthenticationResult??h,m=i.AccessToken??i.accessToken??i.access_token,w=i.RefreshToken??i.refreshToken??i.refresh_token;return m&&await this.storeTokens({accessToken:m,refreshToken:w,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type}),{access_token:m,refresh_token:w,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,s=await this.signRequest("GET",t),n=await this.request("GET",t,{headers:s.headers}),o=n.data.data??n.data;return{...o,hasCredentials:!!(o.hasCredentials??o.credentialId)}}async removePasskey(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,s=await this.signRequest("DELETE",t);await this.request("DELETE",t,{headers:s.headers})}async signRequest(e,r,t={}){const s=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,n=await this.getRequestAuthHeaders(e,s);return{...t,headers:{...t.headers,...n}}}async authenticatedFetch(e,r){const t=typeof e=="string"?e:e instanceof URL?e.toString():e.url,s=r?.method||"GET",n=await this.signRequest(s,t,{headers:r?.headers});return fetch(e,{...r,headers:n.headers})}async storeTokens(e){localStorage.setItem(T,e.accessToken),e.refreshToken&&localStorage.setItem(Y,e.refreshToken)}async clearTokens(){localStorage.removeItem(T),localStorage.removeItem(Y)}async refreshToken(e){const r=this.extractRealm(void 0,e),t=await this.request("POST","/auth/refresh",{body:r?{realm:r}:{}}),s=t.data.data??t.data,n=s.access_token,o=s.token_type,l=s.expires_in;return n&&await this.storeTokens({accessToken:n,expiresIn:l,tokenType:o}),{access_token:n,token_type:o,expires_in:l}}async logout(){try{const r=await this.getAccessToken()?await this.signRequest("POST","/auth/logout",{body:{}}):{body:{}};await this.request("POST","/auth/logout",r),await R(),this.resetDPoPInitialization()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(T)}}typeof window<"u"&&(window.AuthSDK=x);const fe=typeof window<"u"?window:globalThis;fe.AuthSDK=x,d.AuthSDK=x,d.AuthSDKFetchError=G,d.SDKValidationError=p,d.arrayBufferToBase64=E,d.arrayBufferToBase64url=y,d.base64ToArrayBuffer=_,d.base64urlToArrayBuffer=P,d.clearPasskeyEmail=q,d.clearPasskeyMobileNumber=M,d.getPasskeyEmail=C,d.getPasskeyMobileNumber=$,d.isConditionalUISupported=O,d.isWebAuthnSupported=b,d.setPasskeyEmail=K,d.setPasskeyMobileNumber=B,d.stringToArrayBuffer=k,d.uint8ArrayToString=N,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(d,b){typeof exports=="object"&&typeof module<"u"?b(exports):typeof define=="function"&&define.amd?define(["exports"],b):(d=typeof globalThis<"u"?globalThis:d||self,b(d.PostexAuthSDKStage={}))})(this,(function(d){"use strict";function b(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function N(){if(!b())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function E(a){const e=new Uint8Array(a);let r="";for(let t=0;t<e.byteLength;t++)r+=String.fromCharCode(e[t]);return btoa(r)}function _(a){if(typeof a!="string"||!a)throw new Error("Invalid base64: expected non-empty string");const e=a.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),r=e.length%4,t=r>0?e+"=".repeat(4-r):e;try{const s=atob(t),n=new Uint8Array(s.length);for(let o=0;o<s.length;o++)n[o]=s.charCodeAt(o);return n.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function y(a){return E(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function X(a){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(a)}function Z(a){const e=a.replace(/-/g,""),r=new Uint8Array(e.length/2);for(let t=0;t<r.length;t++)r[t]=parseInt(e.substr(t*2,2),16);return r.buffer}function P(a){if(!a||typeof a!="string")throw new Error("Invalid input: expected non-empty string");return X(a)?Z(a):_(a)}function k(a){return new TextEncoder().encode(a).buffer}function O(a){return String.fromCharCode(...a)}const Q="xpay_webauthn",ee=1,u="passkey_data",S="passkey_email",A="passkey_mobile_number";function f(){return new Promise((a,e)=>{const r=indexedDB.open(Q,ee);r.onerror=()=>e(r.error),r.onsuccess=()=>a(r.result),r.onupgradeneeded=()=>{const t=r.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)}})}async function C(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(S);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function K(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,S);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch{}}async function q(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),n=t.objectStore(u).delete(S);n.onerror=()=>r(n.error),n.onsuccess=()=>e(),t.oncomplete=()=>a.close()})}catch{}}async function $(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(A);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function B(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,A);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch{}}async function U(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),n=t.objectStore(u).delete(A);n.onerror=()=>r(n.error),n.onsuccess=()=>e(),t.oncomplete=()=>a.close()})}catch{}}const v="dpop_private_key",I="dpop_public_key_jwk";function M(a){if(!a||typeof a!="object")return!1;const e=a;return e.kty==="EC"&&e.crv==="P-256"&&typeof e.x=="string"&&typeof e.y=="string"}class D extends Error{constructor(e){super(e),this.name="DPoPProofGenerationError"}}function te(a){return{kty:"EC",crv:"P-256",x:a.x,y:a.y}}async function z(a){const e=JSON.stringify({crv:a.crv,kty:a.kty,x:a.x,y:a.y}),r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return y(r)}async function re(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,v);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP private key:",e)}}async function ne(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,I);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP public key JWK:",e)}}async function L(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(v);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function j(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(I);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function R(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),s=t.objectStore(u);s.delete(v),s.delete(I),t.onerror=()=>r(t.error),t.oncomplete=()=>{a.close(),e()}})}catch{}}async function se(){const a=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",a.publicKey),r=te(e),t=await z(r);return await re(a.privateKey),await ne(r),{publicKey:r,thumbprint:t}}async function ae(){const a=await L(),e=await j();return a&&M(e)?{publicKey:e,thumbprint:await z(e)}:((a||e)&&await R(),se())}async function oe(a,e,r){try{const t=await L(),s=await j();if(!t||!M(s))throw new D("DPoP key material is unavailable or invalid");const n={typ:"dpop+jwt",alg:"ES256",jwk:s},o=new URL(e,typeof window<"u"?window.location.origin:void 0),l=`${o.origin}${o.pathname}`,c={jti:crypto.randomUUID(),htm:a.toUpperCase(),htu:l,iat:Math.floor(Date.now()/1e3)};if(r){const be=new TextEncoder().encode(r),Pe=await crypto.subtle.digest("SHA-256",be);c.ath=y(Pe)}const h=y(new TextEncoder().encode(JSON.stringify(n)).buffer),i=y(new TextEncoder().encode(JSON.stringify(c)).buffer),p=`${h}.${i}`,w=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,new TextEncoder().encode(p)),g=y(w);return`${h}.${i}.${g}`}catch(t){throw console.error("Failed to generate DPoP proof:",t),t instanceof D?t:new D("Failed to generate DPoP proof")}}const H={isWebAuthnSupported:b,isConditionalUISupported:N,arrayBufferToBase64:E,base64ToArrayBuffer:_,arrayBufferToBase64url:y,base64urlToArrayBuffer:P,stringToArrayBuffer:k,uint8ArrayToString:O,getPasskeyEmail:C,setPasskeyEmail:K,clearPasskeyEmail:q,getPasskeyMobileNumber:$,setPasskeyMobileNumber:B,clearPasskeyMobileNumber:U};typeof window<"u"&&(window.WebAuthn=H);const ie=typeof window<"u"?window:globalThis;ie.WebAuthn=H;const T="postex-auth-token",ce="postexglobal",le={xstak:"https://auth-stage.xstak.com/public/v1",postex:"https://auth-stage.postex.pk/public/v1",callcourier:"https://auth-stage.callcourier.com.pk/public/v1",postexglobal:"https://auth-stage.postexglobal.com/public/v1",postexsa:"https://auth-stage.postex.sa/public/v1"},ue=/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,de=/^\+[1-9]\d{6,14}$/,he=/^\d{6}$/,ye=/^[A-Za-z0-9_-]{16,512}$/,me=/[\u0000-\u001F\u007F-\u009F]/,pe=/[A-Za-z]/,fe=/[\u0400-\u04FF]/,J=254,F=16,W=64,G=64;class Y extends Error{constructor(e,r,t){super(t??`Request failed with status ${e}`),this.response={status:e,data:r},this.name="AuthSDKFetchError"}}class m extends Error{constructor(e,r,t="invalid_input"){super(r),this.field=e,this.code=t,this.name="SDKValidationError"}}const V="auth_sdk_refresh_token";class x{constructor(e){this.config=e,this.dpopInitializationPromise=this.createDPoPInitializationPromise()}getBaseUrl(){const e=this.config.appId??ce;return le[e]}async initializeDPoPState(){await ae()}async ensureDPoPInitialized(){await this.dpopInitializationPromise}createDPoPInitializationPromise(){const e=this.initializeDPoPState();return e.catch(r=>{console.warn("[AuthSDK] DPoP initialization failed:",r)}),e}resetDPoPInitialization(){this.dpopInitializationPromise=this.createDPoPInitializationPromise()}async getRequiredDPoPProof(e,r,t){return await this.ensureDPoPInitialized(),oe(e.toUpperCase(),r,t)}containsControlChars(e){return me.test(e)}hasMixedLatinAndCyrillic(e){return pe.test(e)&&fe.test(e)}assertNoControlChars(e,r){if(this.containsControlChars(r))throw new m(e,`${e} must not contain control characters`)}validateEmail(e,r="email"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>J)throw new m(r,`${r} must be ${J} characters or fewer`);this.assertNoControlChars(r,t);const[s=""]=t.split("@");if(this.hasMixedLatinAndCyrillic(s))throw new m(r,`${r} must not mix Latin and Cyrillic characters in the local part`);if(!ue.test(t))throw new m(r,`${r} must be a valid email`);return t}validateMobileNumber(e,r="mobileNumber"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>F)throw new m(r,`${r} must be ${F} characters or fewer`);if(this.assertNoControlChars(r,t),!de.test(t))throw new m(r,`${r} must be in E.164 format`);return t}validateUsername(e,r="username"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>W)throw new m(r,`${r} must be ${W} characters or fewer`);return this.assertNoControlChars(r,t),t}validateOTP(e,r="otp"){const t=e.trim();if(this.assertNoControlChars(r,t),!he.test(t))throw new m(r,`${r} must be a 6-digit code`);return t}validateMagicLinkToken(e,r="token"){const t=e.trim();if(this.assertNoControlChars(r,t),!ye.test(t))throw new m(r,`${r} must be 16-512 URL-safe characters`);return t}validateRealm(e){const r=e?.trim();if(r){if(this.assertNoControlChars("realm",r),r.length>G)throw new m("realm",`realm must be ${G} characters or fewer`);return r}}normalizeAndValidateIdentifier(e){return typeof e=="string"?{email:this.validateEmail(e)}:{email:e.email?this.validateEmail(e.email):void 0,mobileNumber:e.mobileNumber?this.validateMobileNumber(e.mobileNumber):void 0,username:e.username?this.validateUsername(e.username):void 0}}normalizeAuthIdentifier(e){return this.normalizeAndValidateIdentifier(e)}extractRealm(e,r){const t=r?.realm??(e&&typeof e!="string"?e.realm:void 0);return this.validateRealm(t)}buildAuthRequestBody(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r);return{...t,...s?{realm:s}:{}}}buildUrl(e,r){const t=this.getBaseUrl().replace(/\/$/,""),s=e.startsWith("/")?e:`/${e}`,n=`${t}${s}`;if(!r||Object.keys(r).length===0)return n;const o=new URLSearchParams(r).toString();return`${n}?${o}`}async request(e,r,t){const s=this.buildUrl(r,t?.params),n={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...t?.headers},o={method:e,credentials:"include",headers:n};t?.body!==void 0&&t?.body!==null&&(o.body=JSON.stringify(t.body));const l=await fetch(s,o);if(!l.ok){let i;try{const p=await l.text();i=p?JSON.parse(p):void 0}catch{i=void 0}throw l.status===401&&(await this.clearTokens(),await R(),this.resetDPoPInitialization()),new Y(l.status,i)}const c=await l.text();return{data:c?JSON.parse(c):{}}}async getRequestAuthHeaders(e,r){const t=localStorage.getItem(T);if(!t)return{};const s=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,n=await this.getRequiredDPoPProof(e,s,t);return{Authorization:`Bearer ${t}`,DPoP:n}}async getStatus(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r),n={};t.email&&(n.email=t.email),t.mobileNumber&&(n.mobileNumber=t.mobileNumber),t.username&&(n.username=t.username),s&&(n.realm=s);const o=await this.request("GET","/auth/status",{params:n});return o.data.data??o.data}async initiateAuth(e,r){const t=this.buildAuthRequestBody(e,r),s=await this.request("POST","/auth/initiate",{body:t}),n=s.data.data??s.data;return{status:n.status,challenge:n.challenge,credentialIds:n.credentialIds,rp:n.rp}}async initiateOTP(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r),n=t.email,o=t.mobileNumber,l=t.username;if(!n&&!o&&!l)throw new m("identifier","Either mobileNumber, email, or username is required");const c={};n&&(c.email=n),o&&(c.mobileNumber=o),l&&(c.username=l),s&&(c.realm=s);const i=(await this.request("POST","/otp/initiate",{body:c})).data;return{message:i.message??i.data?.message}}async verifyOTP(e){const r=this.validateOTP(e),t=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/verify`),s=await this.request("POST","/otp/verify",{body:{otp:r},headers:{DPoP:t}}),n=s.data.data??s.data,o=n.AuthenticationResult??n,l=o.access_token??o.accessToken??o.AccessToken,c=o.refresh_token??o.refreshToken??o.RefreshToken,h=o.expires_in??o.expiresIn,i=o.token_type??o.tokenType;return l&&await this.storeTokens({accessToken:l,refreshToken:c,expiresIn:h,tokenType:i}),{access_token:l,refresh_token:c,expires_in:h,token_type:i,verified:o.verified,email:o.email??o.Email,...o}}async resendOTP(){const e=await this.request("POST","/otp/resend",{}),r=e.data.data??e.data;return{success:r.success,message:r.message,...r}}async verifySignupOTP({mobileNumber:e,otp:r}){const t=this.validateMobileNumber(e),s=this.validateOTP(r),n=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/signup/verify`),o=await this.request("POST","/otp/signup/verify",{body:{mobileNumber:t,otp:s},headers:{DPoP:n}}),l=o.data.data??o.data,c=l.AuthenticationResult??l,h=c.access_token??c.accessToken??c.AccessToken,i=c.refresh_token??c.refreshToken??c.RefreshToken,p=c.expires_in??c.expiresIn,w=c.token_type??c.tokenType;return h&&await this.storeTokens({accessToken:h,refreshToken:i,expiresIn:p,tokenType:w}),{access_token:h,refresh_token:i,expires_in:p,token_type:w,verified:c.verified,email:c.email??c.Email,...c}}async resendSignupOTP({mobileNumber:e,email:r=""}){const t=this.validateMobileNumber(e),s=r?this.validateEmail(r):"",n=await this.request("POST","/otp/signup/resend",{body:{email:s,mobileNumber:t}}),o=n.data.data??n.data;return{success:o.success,message:o.message,...o}}async verifyMagicLink(e){const r=this.validateMagicLinkToken(e);await this.request("GET","/verify/magic-link",{params:{token:r,redirect_mode:"frontend"}})}async completeMagicLink(){const e=await this.request("POST","/verify/magic-link/complete",{body:{}}),r=e.data.data??e.data,t=r.AuthenticationResult??r,s=t.access_token??t.accessToken??t.AccessToken,n=t.refresh_token??t.refreshToken??t.RefreshToken,o=t.expires_in??t.expiresIn,l=t.token_type??t.tokenType;return s&&await this.storeTokens({accessToken:s,refreshToken:n,expiresIn:o,tokenType:l}),{access_token:s,refresh_token:n,expires_in:o,token_type:l,verified:t.verified,email:t.email??t.Email,...t}}async initiatePasskeyRegistration(){const e=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return e.data.data??e.data}async registerPasskey(e){const r=this.validateEmail(e),t=await this.initiatePasskeyRegistration();let s;if(t?.user?.id)try{s=P(t.user.id)}catch{s=k(t.user.id)}else s=k(r);const n=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(g=>({type:"public-key",alg:g.alg})),o=t.excludeCredentials?.map(g=>({type:"public-key",id:P(g)})),l={challenge:P(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:s,name:t.user?.name??r,displayName:t.user?.displayName??r},pubKeyCredParams:n,excludeCredentials:o,timeout:t.timeout??6e4,attestation:"direct",authenticatorSelection:{residentKey:"required",userVerification:"required",authenticatorAttachment:"platform"}},c=await navigator.credentials.create({publicKey:l});if(!c)throw new Error("Credential creation failed");const h=c.response,i={clientDataJSON:y(h.clientDataJSON),attestationObject:y(h.attestationObject),rawId:y(c.rawId)};if(!i.rawId)throw new Error("Raw ID is required");const p=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/register/challenge`),w=await this.request("POST","/webauthn/register/challenge",{body:i,headers:{DPoP:p}});return w.data.data??w.data}async authenticateWithPasskey({challenge:e,rp:r,credentialIds:t}){const s=await navigator.credentials.get({publicKey:{challenge:P(e),rpId:r?.host??void 0,allowCredentials:t.map(g=>({type:"public-key",id:P(g),transports:["internal"]})),timeout:6e4,userVerification:"required"}});if(!s)throw new Error("Authentication failed");const n=s.response,o={clientDataJSON:y(n.clientDataJSON),authenticatorData:y(n.authenticatorData),signature:y(n.signature),rawId:y(s.rawId),userHandle:n.userHandle?y(n.userHandle):""},l=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/authenticate/challenge`),c=await this.request("POST","/webauthn/authenticate/challenge",{body:o,headers:{DPoP:l}}),h=c.data.data??c.data,i=h.AuthenticationResult??h,p=i.AccessToken??i.accessToken??i.access_token,w=i.RefreshToken??i.refreshToken??i.refresh_token;return p&&await this.storeTokens({accessToken:p,refreshToken:w,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type}),{access_token:p,refresh_token:w,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,s=await this.signRequest("GET",t),n=await this.request("GET",t,{headers:s.headers}),o=n.data.data??n.data;return{...o,hasCredentials:!!(o.hasCredentials??o.credentialId)}}async removePasskey(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,s=await this.signRequest("DELETE",t);await this.request("DELETE",t,{headers:s.headers})}async signRequest(e,r,t={}){const s=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,n=await this.getRequestAuthHeaders(e,s);return{...t,headers:{...t.headers,...n}}}async authenticatedFetch(e,r){const t=typeof e=="string"?e:e instanceof URL?e.toString():e.url,s=r?.method||"GET",n=await this.signRequest(s,t,{headers:r?.headers});return fetch(e,{...r,headers:n.headers})}async storeTokens(e){localStorage.setItem(T,e.accessToken),e.refreshToken&&localStorage.setItem(V,e.refreshToken)}async clearTokens(){localStorage.removeItem(T),localStorage.removeItem(V)}async refreshToken(e){const r=this.extractRealm(void 0,e),t=await this.request("POST","/auth/refresh",{body:r?{realm:r}:{}}),s=t.data.data??t.data,n=s.access_token,o=s.token_type,l=s.expires_in;return n&&await this.storeTokens({accessToken:n,expiresIn:l,tokenType:o}),{access_token:n,token_type:o,expires_in:l}}async logout(){try{const r=await this.getAccessToken()?await this.signRequest("POST","/auth/logout",{body:{}}):{body:{}};await this.request("POST","/auth/logout",r),await R(),this.resetDPoPInitialization()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(T)}}typeof window<"u"&&(window.AuthSDK=x);const we=typeof window<"u"?window:globalThis;we.AuthSDK=x,d.AuthSDK=x,d.AuthSDKFetchError=Y,d.SDKValidationError=m,d.arrayBufferToBase64=E,d.arrayBufferToBase64url=y,d.base64ToArrayBuffer=_,d.base64urlToArrayBuffer=P,d.clearPasskeyEmail=q,d.clearPasskeyMobileNumber=U,d.getPasskeyEmail=C,d.getPasskeyMobileNumber=$,d.isConditionalUISupported=N,d.isWebAuthnSupported=b,d.setPasskeyEmail=K,d.setPasskeyMobileNumber=B,d.stringToArrayBuffer=k,d.uint8ArrayToString=O,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postex-auth-sdk-stage",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "PostEx Auth SDK for authentication flows: OTP, magic links, passkeys, and token management",
5
5
  "main": "./dist/postex-auth-sdk-stage.umd.js",
6
6
  "module": "./dist/postex-auth-sdk-stage.es.js",