@mygigsters/card-sdk 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
- import h from "airwallex-payment-elements";
2
- class g {
1
+ import m from "airwallex-payment-elements";
2
+ class y {
3
3
  constructor(t) {
4
4
  this.baseUrl = t.replace(/\/+$/, "");
5
5
  }
@@ -12,69 +12,61 @@ class g {
12
12
  * @param {object} [extraHeaders] - Additional headers
13
13
  * @returns {Promise<object>}
14
14
  */
15
- async _post(t, e, i = null, o = {}) {
16
- const s = {
15
+ async _post(t, e, o = null, r = {}) {
16
+ const i = {
17
17
  "Content-Type": "application/json",
18
- ...o
18
+ ...r
19
19
  };
20
- i && (s.Authorization = i.startsWith("Basic ") || i.startsWith("Bearer ") ? i : `Bearer ${i}`);
21
- const r = await fetch(`${this.baseUrl}/api/v1${t}`, {
20
+ o && (i.Authorization = o.startsWith("Basic ") || o.startsWith("Bearer ") ? o : `Bearer ${o}`);
21
+ const s = await fetch(`${this.baseUrl}/api/v1${t}`, {
22
22
  method: "POST",
23
- headers: s,
23
+ headers: i,
24
24
  body: JSON.stringify(e)
25
- }), c = await r.text();
26
- let n = null;
27
- if (c && c.trim().length > 0)
25
+ }), n = await s.text();
26
+ let a = null;
27
+ if (n && n.trim().length > 0)
28
28
  try {
29
- n = JSON.parse(c);
29
+ a = JSON.parse(n);
30
30
  } catch {
31
- n = null;
31
+ a = null;
32
32
  }
33
- if (!r.ok) {
34
- const l = n && (n.message || n.error) || c || r.statusText || `HTTP ${r.status}`;
33
+ if (!s.ok) {
34
+ const l = a && (a.message || a.error) || n || s.statusText || `HTTP ${s.status}`;
35
35
  throw new Error(l);
36
36
  }
37
- return n ?? {};
37
+ return a ?? {};
38
38
  }
39
- // ── Public methods ────────────────────────────────────────────────────────
40
39
  /**
41
- * Authenticate using apiKey and apiSecret via /api/v1/sdk-initialization.
42
- * Mirrors BeneficiaryAPI authentication architecture.
43
- *
44
- * @param {string} apiKey - UUID-style API key
45
- * @param {string} apiSecret - One-time API secret
46
- * @returns {Promise<{ token: string, clientId: string, expiresIn: number, tokenType: string }>}
40
+ * Makes a JSON GET request.
41
+ * @param {string} path - API path (appended to baseUrl + /api/v1)
42
+ * @param {string|null} [token] - Optional Bearer token
43
+ * @param {object} [extraHeaders] - Additional headers
44
+ * @returns {Promise<object>}
47
45
  */
48
- async authenticate(t, e) {
49
- const i = btoa(`${t}:${e}`), o = await fetch(`${this.baseUrl}/api/v1/sdk-initialization`, {
50
- method: "POST",
51
- headers: {
52
- "Content-Type": "application/json",
53
- "x-api-version": "1.1",
54
- Authorization: `Basic ${i}`
55
- }
56
- }), s = await o.text();
57
- let r = null;
46
+ async _get(t, e = null, o = {}) {
47
+ const r = {
48
+ "Content-Type": "application/json",
49
+ ...o
50
+ };
51
+ e && (r.Authorization = e.startsWith("Basic ") || e.startsWith("Bearer ") ? e : `Bearer ${e}`);
52
+ const i = await fetch(`${this.baseUrl}/api/v1${t}`, {
53
+ method: "GET",
54
+ headers: r
55
+ }), s = await i.text();
56
+ let n = null;
58
57
  if (s && s.trim().length > 0)
59
58
  try {
60
- r = JSON.parse(s);
59
+ n = JSON.parse(s);
61
60
  } catch {
62
- r = null;
61
+ n = null;
63
62
  }
64
- if (!o.ok) {
65
- const c = r && (r.message || r.error) || s || o.statusText || `HTTP ${o.status}`;
66
- throw new Error(c);
63
+ if (!i.ok) {
64
+ const a = n && (n.message || n.error) || s || i.statusText || `HTTP ${i.status}`;
65
+ throw new Error(a);
67
66
  }
68
- if (!r?.success || !r?.data?.token)
69
- throw new Error("Authentication failed: Unexpected response from server");
70
- return {
71
- token: r.data.token,
72
- clientId: r.data.clientId,
73
- expiresIn: r.data.expiresIn,
74
- tokenType: r.data.tokenType,
75
- paymentsIndia: r.data.paymentsIndia || !1
76
- };
67
+ return n ?? {};
77
68
  }
69
+ // ── Public methods ────────────────────────────────────────────────────────
78
70
  /**
79
71
  * Retrieve a client secret for Airwallex card element initialization.
80
72
  *
@@ -86,23 +78,23 @@ class g {
86
78
  * @param {string|null} [token] - Bearer token if authenticated
87
79
  * @returns {Promise<{ clientSecret: string }>}
88
80
  */
89
- async getClientSecret(t, e, i = null) {
81
+ async getClientSecret(t, e, o = null) {
90
82
  console.log("🔐 CardAPI.getClientSecret()", {
91
83
  customerId: t,
92
84
  accountId: e,
93
- hasToken: !!i
85
+ hasToken: !!o
94
86
  });
95
- const o = await this._post(
87
+ const r = await this._post(
96
88
  "/customer/client-secret",
97
89
  {
98
90
  customerId: t,
99
91
  accountId: e
100
92
  },
101
- i
102
- ), s = o.client_secret || o.clientSecret || o?.data?.client_secret || o?.data?.clientSecret;
103
- if (!s)
93
+ o
94
+ ), i = r.client_secret || r.clientSecret || r?.data?.client_secret || r?.data?.clientSecret;
95
+ if (!i)
104
96
  throw new Error("Failed to retrieve client secret from server");
105
- return { clientSecret: s };
97
+ return { clientSecret: i };
106
98
  }
107
99
  /**
108
100
  * Save the payment consent after Airwallex createPaymentConsent succeeds.
@@ -115,16 +107,45 @@ class g {
115
107
  * @param {string|null} [token] - Bearer token if authenticated
116
108
  * @returns {Promise<object>}
117
109
  */
118
- async saveConsent(t, e, i = null) {
110
+ async saveConsent(t, e, o = null) {
119
111
  return this._post(
120
112
  "/customer/save-consent",
121
113
  {
122
114
  customerId: t,
123
115
  paymentConsentId: e
124
116
  },
125
- i
117
+ o
126
118
  );
127
119
  }
120
+ /**
121
+ * Fetch profile details to verify user identity (myGigsterId).
122
+ *
123
+ * GET /api/v1/client/profile
124
+ * Response schema: { success: true, status: 200, data: { myGigsterId: "..." } }
125
+ *
126
+ * @param {string|null} [token] - Bearer token if authenticated
127
+ * @returns {Promise<{ myGigsterId: string, data: object, raw: object }>}
128
+ */
129
+ async profileDetails(t = null) {
130
+ console.log("👤 CardAPI.profileDetails() calling /client/profile", { hasToken: !!t });
131
+ let e = null;
132
+ try {
133
+ e = await this._get("/client/profile", t);
134
+ } catch (r) {
135
+ if (r.message && (r.message.includes("405") || r.message.includes("Method Not Allowed")))
136
+ e = await this._post("/client/profile", {}, t);
137
+ else
138
+ throw r;
139
+ }
140
+ const o = e?.data?.myGigsterId || e?.data?.mygigsterId || e?.accountId;
141
+ if (!o)
142
+ throw new Error("Failed to retrieve myGigsterId from profile API response");
143
+ return {
144
+ myGigsterId: o,
145
+ data: e?.data || e,
146
+ raw: e
147
+ };
148
+ }
128
149
  }
129
150
  const p = {
130
151
  close: `<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -134,7 +155,7 @@ const p = {
134
155
  <path stroke-linecap="round" stroke-linejoin="round" d="M20 6L9 17l-5-5"/>
135
156
  </svg>`
136
157
  };
137
- class b {
158
+ class w {
138
159
  constructor(t, e) {
139
160
  this.shadowRoot = t, this.callbacks = e, this.state = {
140
161
  loading: !0,
@@ -200,21 +221,21 @@ class b {
200
221
  `, this._attachListeners();
201
222
  }
202
223
  _attachListeners() {
203
- this.shadowRoot.querySelectorAll(".mc-close-btn, #mc-close-btn").forEach((o) => {
204
- o.addEventListener("click", (s) => {
205
- s.preventDefault(), s.stopPropagation(), this.callbacks.onClose();
224
+ this.shadowRoot.querySelectorAll(".mc-close-btn, #mc-close-btn").forEach((r) => {
225
+ r.addEventListener("click", (i) => {
226
+ i.preventDefault(), i.stopPropagation(), this.callbacks.onClose();
206
227
  });
207
228
  });
208
229
  const e = this.shadowRoot.querySelector("#mc-backdrop") || this.shadowRoot.querySelector(".mc-backdrop");
209
- e && e.addEventListener("click", (o) => {
210
- o.target === e && (o.preventDefault(), o.stopPropagation(), this.callbacks.onClose());
230
+ e && e.addEventListener("click", (r) => {
231
+ r.target === e && (r.preventDefault(), r.stopPropagation(), this.callbacks.onClose());
211
232
  });
212
- const i = this.shadowRoot.querySelector("#mc-submit-btn");
213
- i && i.addEventListener("click", (o) => {
214
- o.preventDefault(), o.stopPropagation(), this.callbacks.onSubmit();
215
- }), this.shadowRoot.addEventListener("click", (o) => {
216
- const s = o.target;
217
- s && (s.closest(".mc-close-btn") || s.closest("#mc-close-btn")) && (o.preventDefault(), o.stopPropagation(), this.callbacks.onClose());
233
+ const o = this.shadowRoot.querySelector("#mc-submit-btn");
234
+ o && o.addEventListener("click", (r) => {
235
+ r.preventDefault(), r.stopPropagation(), this.callbacks.onSubmit();
236
+ }), this.shadowRoot.addEventListener("click", (r) => {
237
+ const i = r.target;
238
+ i && (i.closest(".mc-close-btn") || i.closest("#mc-close-btn") || i.closest(".mc-dismiss-btn") || i.closest("#mc-dismiss-btn")) && (r.preventDefault(), r.stopPropagation(), this.callbacks.onClose());
218
239
  });
219
240
  }
220
241
  // ── Surgical state patches (safe after card mount) ──────────────────────
@@ -224,8 +245,8 @@ class b {
224
245
  */
225
246
  setCardLoaded() {
226
247
  this.state.cardLoaded = !0, this.state.loading = !1;
227
- const t = this.shadowRoot.querySelector("#mc-loading"), e = this.shadowRoot.querySelector("#mc-card-wrapper"), i = this.shadowRoot.querySelector("#mc-submit-btn");
228
- t && (t.style.display = "none"), e && (e.style.display = "block"), i && (i.style.display = "flex");
248
+ const t = this.shadowRoot.querySelector("#mc-loading"), e = this.shadowRoot.querySelector("#mc-card-wrapper"), o = this.shadowRoot.querySelector("#mc-submit-btn");
249
+ t && (t.style.display = "none"), e && (e.style.display = "block"), o && (o.style.display = "flex");
229
250
  }
230
251
  /**
231
252
  * Mark the Airwallex card as mounted — after this, no full re-renders.
@@ -261,18 +282,45 @@ class b {
261
282
  e && (t ? (e.textContent = t, e.style.display = "block") : (e.textContent = "", e.style.display = "none"));
262
283
  }
263
284
  /**
264
- * Show an initialization error when the SDK fails to load.
285
+ * Show an initialization error when the SDK fails to load or verification fails.
286
+ * Replaces the modal body with a production-grade error card.
265
287
  * Only safe to call BEFORE the card element is mounted.
266
288
  */
267
- showInitError(t) {
289
+ showInitError(t, e = "Verification Failed") {
268
290
  this.state.loading = !1, this.state.error = t;
269
- const e = this.shadowRoot.querySelector("#mc-loading");
270
- e && (e.innerHTML = `
271
- <div style="text-align:center; padding: 12px 0;">
272
- <p style="color:#ef4444; font-size:14px; font-weight:600; margin-bottom:8px;">${this._escapeHtml(t)}</p>
273
- <p style="color:#94a3b8; font-size:13px;">Please check your configuration credentials and try again.</p>
291
+ const o = this.shadowRoot.querySelector(".mc-modal");
292
+ if (!o) return;
293
+ o.innerHTML = `
294
+ <button class="mc-close-btn" aria-label="Close" id="mc-close-btn" type="button">${p.close}</button>
295
+
296
+ <div class="mc-body">
297
+ <div class="mc-error-wrap">
298
+ <div class="mc-error-icon">
299
+ <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2">
300
+ <circle cx="12" cy="12" r="10" stroke="#ef4444"/>
301
+ <line x1="12" y1="8" x2="12" y2="12" stroke="#ef4444"/>
302
+ <line x1="12" y1="16" x2="12.01" y2="16" stroke="#ef4444"/>
303
+ </svg>
304
+ </div>
305
+ <h2 class="mc-error-title">${this._escapeHtml(e)}</h2>
306
+ <div class="mc-error-detail">${this._escapeHtml(t)}</div>
307
+ <p class="mc-error-sub">SDK initialization has been blocked. Please verify your credentials and try again.</p>
308
+ <button class="mc-dismiss-btn" id="mc-dismiss-btn" type="button">Close</button>
274
309
  </div>
275
- `);
310
+ </div>
311
+
312
+ <div class="mc-powered-by">
313
+ Powered by <a href="https://mygigsters.com.au" target="_blank" rel="noopener">MyGigsters</a>
314
+ </div>
315
+ `, o.querySelectorAll(".mc-close-btn, #mc-close-btn").forEach((i) => {
316
+ i.addEventListener("click", (s) => {
317
+ s.preventDefault(), s.stopPropagation(), this.callbacks.onClose();
318
+ });
319
+ });
320
+ const r = o.querySelector("#mc-dismiss-btn");
321
+ r && r.addEventListener("click", (i) => {
322
+ i.preventDefault(), i.stopPropagation(), this.callbacks.onClose();
323
+ });
276
324
  }
277
325
  /**
278
326
  * Replace the entire modal body with a success state.
@@ -296,12 +344,12 @@ class b {
296
344
  <div class="mc-powered-by">
297
345
  Powered by <a href="https://mygigsters.com.au" target="_blank" rel="noopener">MyGigsters</a>
298
346
  </div>
299
- `, e.querySelectorAll(".mc-close-btn, #mc-close-btn").forEach((i) => {
300
- i.addEventListener("click", (o) => {
301
- o.preventDefault(), o.stopPropagation(), this.callbacks.onClose();
347
+ `, e.querySelectorAll(".mc-close-btn, #mc-close-btn").forEach((o) => {
348
+ o.addEventListener("click", (r) => {
349
+ r.preventDefault(), r.stopPropagation(), this.callbacks.onClose();
302
350
  });
303
- }), e.querySelector("#mc-done-btn")?.addEventListener("click", (i) => {
304
- i.preventDefault(), i.stopPropagation(), this.callbacks.onClose();
351
+ }), e.querySelector("#mc-done-btn")?.addEventListener("click", (o) => {
352
+ o.preventDefault(), o.stopPropagation(), this.callbacks.onClose();
305
353
  }));
306
354
  }
307
355
  // ── Helpers ─────────────────────────────────────────────────────────────
@@ -315,7 +363,7 @@ class b {
315
363
  t && (t.innerHTML = ""), this._cardMounted = !1;
316
364
  }
317
365
  }
318
- const y = `
366
+ const x = `
319
367
  /* ── Reset inside shadow DOM ───────────────────────────────────────────────── */
320
368
  *, *::before, *::after {
321
369
  box-sizing: border-box;
@@ -585,6 +633,79 @@ const y = `
585
633
  animation: mc-fade-in 0.2s ease;
586
634
  }
587
635
 
636
+ /* ── Error state (init / verification failure) ─────────────────────────────── */
637
+ .mc-error-wrap {
638
+ text-align: center;
639
+ padding: 30px 20px 16px;
640
+ animation: mc-fade-in 0.3s ease;
641
+ }
642
+
643
+ .mc-error-icon {
644
+ width: 56px;
645
+ height: 56px;
646
+ border-radius: 50%;
647
+ background: rgba(239, 68, 68, 0.15);
648
+ border: 2px solid rgba(239, 68, 68, 0.4);
649
+ display: flex;
650
+ align-items: center;
651
+ justify-content: center;
652
+ margin: 0 auto 16px;
653
+ }
654
+
655
+ .mc-error-icon svg {
656
+ width: 28px;
657
+ height: 28px;
658
+ color: #ef4444;
659
+ }
660
+
661
+ .mc-error-title {
662
+ font-size: 20px;
663
+ font-weight: 700;
664
+ color: #f8fafc;
665
+ margin: 0 0 8px;
666
+ }
667
+
668
+ .mc-error-detail {
669
+ font-size: 13px;
670
+ color: #fca5a5;
671
+ background: rgba(239, 68, 68, 0.1);
672
+ border: 1px solid rgba(239, 68, 68, 0.25);
673
+ border-radius: 8px;
674
+ padding: 10px 14px;
675
+ margin: 0 0 12px;
676
+ word-break: break-word;
677
+ line-height: 1.45;
678
+ }
679
+
680
+ .mc-error-sub {
681
+ font-size: 13px;
682
+ color: #94a3b8;
683
+ margin: 0 0 20px;
684
+ line-height: 1.4;
685
+ }
686
+
687
+ .mc-dismiss-btn {
688
+ display: inline-flex;
689
+ align-items: center;
690
+ justify-content: center;
691
+ padding: 11px 36px;
692
+ background: #ef4444;
693
+ color: #fff;
694
+ border: none;
695
+ border-radius: 8px;
696
+ font-size: 14px;
697
+ font-weight: 600;
698
+ cursor: pointer;
699
+ font-family: inherit;
700
+ transition: all 0.2s ease;
701
+ box-shadow: 0 4px 12px rgba(239, 68, 68, 0.35);
702
+ }
703
+
704
+ .mc-dismiss-btn:hover {
705
+ background: #dc2626;
706
+ transform: translateY(-1px);
707
+ }
708
+
588
709
  /* ── Success state ─────────────────────────────────────────────────────────── */
589
710
  .mc-success-wrap {
590
711
  text-align: center;
@@ -744,6 +865,37 @@ const y = `
744
865
  color: #dc2626;
745
866
  }
746
867
 
868
+ [data-theme='light'] .mc-error-icon {
869
+ background: #fef2f2;
870
+ border-color: #fecaca;
871
+ }
872
+
873
+ [data-theme='light'] .mc-error-icon svg {
874
+ color: #dc2626;
875
+ }
876
+
877
+ [data-theme='light'] .mc-error-title {
878
+ color: #0f172a;
879
+ }
880
+
881
+ [data-theme='light'] .mc-error-detail {
882
+ background: #fff5f5;
883
+ border-color: #fed7d7;
884
+ color: #c53030;
885
+ }
886
+
887
+ [data-theme='light'] .mc-error-sub {
888
+ color: #64748b;
889
+ }
890
+
891
+ [data-theme='light'] .mc-dismiss-btn {
892
+ background: #dc2626;
893
+ }
894
+
895
+ [data-theme='light'] .mc-dismiss-btn:hover {
896
+ background: #b91c1c;
897
+ }
898
+
747
899
  [data-theme='light'] .mc-success-icon {
748
900
  background: #f0fdf4;
749
901
  border-color: #bbf7d0;
@@ -772,19 +924,19 @@ const y = `
772
924
  [data-theme='light'] .mc-powered-by a:hover {
773
925
  color: #4f46e5;
774
926
  }
775
- `, f = {
776
- dev: "http://3.108.128.110:5000",
777
- // ← Comment this line when dev server is removed
927
+ `, g = {
928
+ dev: "http://localhost:5000",
929
+ // ← Remote dev server (uncomment to use)
778
930
  demo: "https://qa-payments.mygigsters.com.au",
779
931
  // QA Demo environment
780
932
  prod: "https://prod-payments.mygigsters.com.au"
781
933
  // Production environment
782
- }, w = {
934
+ }, v = {
783
935
  dev: "demo",
784
936
  demo: "demo",
785
937
  prod: "prod"
786
938
  };
787
- class m {
939
+ class f {
788
940
  constructor() {
789
941
  this.config = null, this.api = null, this.renderer = null, this.host = null, this.shadowRoot = null, this.cardElement = null, this.clientSecret = null, this.authToken = null, this.tokenExpiresAt = null, this.airwallexClientId = null, this.isInitialized = !1, this.isSubmitting = !1, this._handleKeyDown = this._handleKeyDown.bind(this);
790
942
  }
@@ -792,91 +944,113 @@ class m {
792
944
  // PUBLIC: init
793
945
  // ─────────────────────────────────────────────────────────────────────────
794
946
  /**
795
- * Initialize the Card SDK.
947
+ * Initialize the Card SDK using a pre-fetched token from GET /api/v1/client/me.
948
+ *
949
+ * ── FLOW B — Pre-fetched Token ─────────────────────────────────────────────
950
+ * 1. Call GET /api/v1/client/me on your server or frontend using Basic Auth:
951
+ * Authorization: Basic base64(apiKey:apiSecret)
952
+ * 2. Extract `token` and `myGigsterId` from the response `data`.
953
+ * 3. Pass `token` and `myGigsterId` directly to `MygigstersCard.init()`.
954
+ *
955
+ * try {
956
+ * await MygigstersCard.init({
957
+ * containerId: 'card-mount',
958
+ * token: resolvedToken, // ← from /client/me (no apiKey/apiSecret here!)
959
+ * customerId: customerId,
960
+ * myGigsterId: myGigsterId,
961
+ * env: env,
962
+ * mode: 'dark',
963
+ * onSuccess: (res) => console.log('Card saved!', res),
964
+ * });
965
+ * } catch (err) {
966
+ * console.error(err);
967
+ * }
796
968
  *
797
- * @param {object} config
798
- * @param {string} config.apiKey - API key (required)
799
- * @param {string} config.apiSecret - API secret (required)
800
- * @param {string} config.customerId - Customer ID (required)
801
- * @param {string} [config.myGigsterId]- MyGigster ID (required from frontend)
802
- * @param {string} [config.accountId] - Account ID (legacy alias for myGigsterId)
803
- * @param {string} config.containerId - ID of the DOM container
804
- * @param {'dev'|'demo'|'prod'} [config.env='demo'] - Environment ("dev" | "demo" | "prod")
805
- * @param {string} [config.baseUrl] - Custom base URL override
806
- * @param {'light'|'dark'} [config.mode='dark']- UI theme
807
- * @param {function} [config.onSuccess] - Callback on successful card save
808
- * @param {function} [config.onError] - Callback on error
809
- * @param {function} [config.onClose] - Callback when modal closes
969
+ * @param {object} config
970
+ * @param {string} config.token - Pre-fetched Bearer token from GET /client/me (required)
971
+ * @param {string} config.customerId - Airwallex Customer ID (required)
972
+ * @param {string} [config.myGigsterId] - MyGigster ID from /client/me (required)
973
+ * @param {string} [config.accountId] - Alias for myGigsterId
974
+ * @param {string} config.containerId - ID of the DOM container (required)
975
+ * @param {'dev'|'demo'|'prod'} [config.env='demo'] - Environment
976
+ * @param {string} [config.baseUrl] - Custom base URL override
977
+ * @param {'light'|'dark'} [config.mode='dark'] - UI theme
978
+ * @param {function} [config.onSuccess] - Callback on successful card save
979
+ * @param {function} [config.onError] - Callback on error
980
+ * @param {function} [config.onClose] - Callback when modal closes
810
981
  */
811
982
  async init(t) {
812
983
  try {
813
984
  if (!t)
814
985
  throw new Error("Configuration object is required for MygigstersCard.init()");
815
- if (!t.apiKey) throw new Error("apiKey is required");
816
- if (!t.apiSecret) throw new Error("apiSecret is required");
986
+ if (!t.token)
987
+ throw new Error(
988
+ "token is required. Call GET /api/v1/client/me first to get the token, then pass it to MygigstersCard.init()"
989
+ );
817
990
  if (!t.customerId) throw new Error("customerId is required");
818
- const e = t.myGigsterId || t.accountId;
819
- if (!e) throw new Error("myGigsterId is required");
820
991
  if (!t.containerId) throw new Error("containerId is required");
992
+ const e = t.myGigsterId || t.accountId;
993
+ if (!e)
994
+ throw new Error(
995
+ "myGigsterId is required. Pass myGigsterId returned by GET /api/v1/client/me"
996
+ );
821
997
  if (!document.getElementById(t.containerId))
822
998
  throw new Error(`Container element with ID '${t.containerId}' not found`);
823
- let o = t.env || "demo";
824
- if (o === "qa" && (o = "demo"), !f[o])
825
- throw new Error(`Unknown env "${o}". Use "dev", "demo", or "prod".`);
826
- const s = t.baseUrl || f[o];
827
- this.config = {
999
+ let r = t.env || "demo";
1000
+ if (r === "qa" && (r = "demo"), !g[r])
1001
+ throw new Error(`Unknown env "${r}". Use "dev", "demo", or "prod".`);
1002
+ const i = t.baseUrl || g[r];
1003
+ this.api = new y(i), this.authToken = t.token, this.config = {
828
1004
  mode: "dark",
829
1005
  onSuccess: () => {
830
1006
  },
831
- onError: (l) => console.error("MyGigsters Card SDK Error:", l),
1007
+ onError: (h) => console.error("MyGigsters Card SDK Error:", h),
832
1008
  onClose: () => {
833
1009
  },
834
1010
  ...t,
835
1011
  myGigsterId: e,
836
1012
  accountId: e,
837
- env: o,
838
- baseUrl: s
1013
+ env: r,
1014
+ baseUrl: i
839
1015
  };
840
- const r = document.getElementById("mygigsters-card-sdk-host");
841
- r?.parentNode && r.parentNode.removeChild(r), this.api = new g(this.config.baseUrl), this.host = document.createElement("div"), this.host.id = "mygigsters-card-sdk-host", this.host.style.cssText = "display:block;position:fixed;top:0;left:0;right:0;bottom:0;width:100vw;height:100vh;z-index:2147483647;pointer-events:auto;", this.shadowRoot = this.host.attachShadow({ mode: "closed" });
842
- const c = document.createElement("style");
843
- c.textContent = y, this.shadowRoot.appendChild(c);
844
- const n = document.createElement("div");
845
- n.id = "mc-theme-container", n.setAttribute(
1016
+ const s = document.getElementById("mygigsters-card-sdk-host");
1017
+ s?.parentNode && s.parentNode.removeChild(s), this.host = document.createElement("div"), this.host.id = "mygigsters-card-sdk-host", this.host.style.cssText = "display:block;position:fixed;top:0;left:0;right:0;bottom:0;width:100vw;height:100vh;z-index:2147483647;pointer-events:auto;", this.shadowRoot = this.host.attachShadow({ mode: "closed" });
1018
+ const n = document.createElement("style");
1019
+ n.textContent = x, this.shadowRoot.appendChild(n);
1020
+ const a = document.createElement("div");
1021
+ a.id = "mc-theme-container", a.setAttribute(
846
1022
  "data-theme",
847
1023
  this.config.mode === "light" ? "light" : "dark"
848
- ), this.shadowRoot.appendChild(n), document.body.appendChild(this.host), this.renderer = new b(this.shadowRoot, {
1024
+ ), this.shadowRoot.appendChild(a), document.body.appendChild(this.host), this.renderer = new w(this.shadowRoot, {
849
1025
  onClose: () => this.handleClose(),
850
1026
  onSubmit: () => this.handleSubmit()
851
- }), this.renderer.render(), this.isInitialized = !0, this.show(), window.addEventListener("keydown", this._handleKeyDown), await this.authenticate(), await this._initializeCard();
1027
+ }), this.renderer.render(), this.isInitialized = !0, this.show(), window.addEventListener("keydown", this._handleKeyDown);
1028
+ const l = this.authToken ? `Bearer ${this.authToken}` : null;
1029
+ console.info("[MyGigsters Card SDK] Verifying myGigsterId via profileDetails API...");
1030
+ const u = (await this.api.profileDetails(l))?.myGigsterId;
1031
+ if (!u)
1032
+ throw new Error(
1033
+ "Verification failed: Profile API response did not contain a valid myGigsterId."
1034
+ );
1035
+ if (String(u).trim() !== String(e).trim()) {
1036
+ const h = new Error(
1037
+ "Security check failed: The provided myGigsterId does not match the authenticated client profile. SDK initialization blocked."
1038
+ );
1039
+ throw h.code = "MYGIGSTER_ID_MISMATCH", h;
1040
+ }
1041
+ console.info("[MyGigsters Card SDK] myGigsterId verified successfully."), console.info(`[MyGigsters Card SDK] Initialized in "${r}" mode → ${i}`), await this._initializeCard();
852
1042
  } catch (e) {
853
- throw this.renderer && this.renderer.showInitError(e.message || "Initialization failed"), this.config?.onError && this.config.onError(e), e;
1043
+ if (this.renderer) {
1044
+ const o = e.code === "MYGIGSTER_ID_MISMATCH" ? "Security Verification Failed" : "Initialization Failed";
1045
+ this.renderer.showInitError(e.message || "Initialization failed", o);
1046
+ }
1047
+ throw this.config?.onError && this.config.onError(e), e;
854
1048
  }
855
1049
  }
856
1050
  _handleKeyDown(t) {
857
1051
  t.key === "Escape" && this.isInitialized && this.handleClose();
858
1052
  }
859
1053
  // ─────────────────────────────────────────────────────────────────────────
860
- // PUBLIC: authenticate
861
- // ─────────────────────────────────────────────────────────────────────────
862
- async authenticate() {
863
- try {
864
- console.info(
865
- `[MyGigsters Card SDK] Authenticating in "${this.config.env}" mode → ${this.config.baseUrl}`
866
- );
867
- const t = await this.api.authenticate(
868
- this.config.apiKey,
869
- this.config.apiSecret
870
- );
871
- this.authToken = t.token, this.airwallexClientId = t.clientId, t.expiresIn && (this.tokenExpiresAt = Date.now() + t.expiresIn * 1e3), console.info("[MyGigsters Card SDK] Authentication successful."), (this.config.env === "demo" || this.config.env === "dev") && console.info(`ℹ️ Connected to [${this.config.env.toUpperCase()}] backend.`);
872
- } catch (t) {
873
- const e = t.message || "";
874
- throw e.includes("401") || e.toLowerCase().includes("unauthorized") ? new Error(
875
- "Invalid API credentials: Please check your apiKey and apiSecret."
876
- ) : new Error(`Authentication failed: ${e}`);
877
- }
878
- }
879
- // ─────────────────────────────────────────────────────────────────────────
880
1054
  // HANDLERS
881
1055
  // ─────────────────────────────────────────────────────────────────────────
882
1056
  handleClose() {
@@ -892,7 +1066,7 @@ class m {
892
1066
  if (!this.isSubmitting && this.renderer.state.cardComplete) {
893
1067
  this.isSubmitting = !0, this.renderer.setSubmitting(!0), this.renderer.setError("");
894
1068
  try {
895
- const e = (await h.createPaymentConsent({
1069
+ const e = (await m.createPaymentConsent({
896
1070
  customer_id: this.config.customerId,
897
1071
  client_secret: this.clientSecret,
898
1072
  currency: "AUD",
@@ -902,11 +1076,11 @@ class m {
902
1076
  })).payment_consent_id;
903
1077
  if (!e)
904
1078
  throw new Error("Failed to create payment consent from card element");
905
- const i = this.config.apiKey && this.config.apiSecret ? `Basic ${btoa(`${this.config.apiKey}:${this.config.apiSecret}`)}` : this.authToken ? `Bearer ${this.authToken}` : null, s = {
1079
+ const o = this.authToken ? `Bearer ${this.authToken}` : null, i = {
906
1080
  ...await this.api.saveConsent(
907
1081
  this.config.customerId,
908
1082
  e,
909
- i
1083
+ o
910
1084
  ),
911
1085
  paymentConsentId: e,
912
1086
  customerId: this.config.customerId,
@@ -915,7 +1089,7 @@ class m {
915
1089
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
916
1090
  event: "card.saved"
917
1091
  };
918
- this.renderer.showSuccess(s), this.config?.onSuccess && this.config.onSuccess(s);
1092
+ this.renderer.showSuccess(i), this.config?.onSuccess && this.config.onSuccess(i);
919
1093
  } catch (t) {
920
1094
  const e = t.message || "Payment could not be completed. Please check your card details and try again.";
921
1095
  this.renderer.setError(e), this.renderer.setSubmitting(!1), this.config?.onError && this.config.onError(t);
@@ -929,38 +1103,38 @@ class m {
929
1103
  // ─────────────────────────────────────────────────────────────────────────
930
1104
  async _initializeCard() {
931
1105
  try {
932
- const t = this.config.apiKey && this.config.apiSecret ? `Basic ${btoa(`${this.config.apiKey}:${this.config.apiSecret}`)}` : this.authToken ? `Bearer ${this.authToken}` : null, { clientSecret: e } = await this.api.getClientSecret(
1106
+ const t = this.authToken ? `Bearer ${this.authToken}` : null, { clientSecret: e } = await this.api.getClientSecret(
933
1107
  this.config.customerId,
934
1108
  this.config.accountId,
935
1109
  t
936
1110
  );
937
- this.clientSecret = e, await h.loadAirwallex();
938
- const i = {
939
- env: w[this.config.env] || "demo",
1111
+ this.clientSecret = e, await m.loadAirwallex();
1112
+ const o = {
1113
+ env: v[this.config.env] || "demo",
940
1114
  origin: window.location.origin
941
1115
  };
942
- this.airwallexClientId && (i.clientId = this.airwallexClientId), h.init(i);
943
- const o = this.config.mode === "light", s = {
944
- color: o ? "#0f172a" : "#ffffff",
1116
+ this.airwallexClientId && (o.clientId = this.airwallexClientId), m.init(o);
1117
+ const r = this.config.mode === "light", i = {
1118
+ color: r ? "#0f172a" : "#ffffff",
945
1119
  fontSize: "15px",
946
1120
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
947
1121
  "::placeholder": {
948
- color: o ? "#94a3b8" : "rgba(255, 255, 255, 0.45)",
1122
+ color: r ? "#94a3b8" : "rgba(255, 255, 255, 0.45)",
949
1123
  fontSize: "15px"
950
1124
  }
951
- }, r = h.createElement("card", {
952
- style: { base: s }
1125
+ }, s = m.createElement("card", {
1126
+ style: { base: i }
953
1127
  });
954
- this.cardElement = r, this.renderer.setCardLoaded(), await new Promise((n) => setTimeout(n, 0));
955
- const c = this.shadowRoot.querySelector("#card-root");
956
- if (!c) throw new Error("Card mount point not found");
1128
+ this.cardElement = s, this.renderer.setCardLoaded(), await new Promise((a) => setTimeout(a, 0));
1129
+ const n = this.shadowRoot.querySelector("#card-root");
1130
+ if (!n) throw new Error("Card mount point not found");
957
1131
  try {
958
- r.mount(c);
1132
+ s.mount(n);
959
1133
  } catch {
960
- r.mount("#card-root");
1134
+ s.mount("#card-root");
961
1135
  }
962
- this.renderer.markCardMounted(), r.on("change", (n) => {
963
- const l = n?.detail?.complete || !1;
1136
+ this.renderer.markCardMounted(), s.on("change", (a) => {
1137
+ const l = a?.detail?.complete || !1;
964
1138
  this.renderer.setCardComplete(l);
965
1139
  });
966
1140
  } catch (t) {
@@ -999,24 +1173,24 @@ class m {
999
1173
  t?.parentNode && t.parentNode.removeChild(t), this.isInitialized = !1, this.isSubmitting = !1, this.config = null, this.api = null, this.renderer = null, this.host = null, this.shadowRoot = null, this.cardElement = null, this.clientSecret = null, this.authToken = null, this.tokenExpiresAt = null, this.airwallexClientId = null;
1000
1174
  }
1001
1175
  }
1002
- let a = null;
1003
- const u = {
1004
- init: async (d) => (a && (a.destroy(), a = null), a = new m(), await a.init(d), a),
1176
+ let c = null;
1177
+ const b = {
1178
+ init: async (d) => (c && (c.destroy(), c = null), c = new f(), await c.init(d), c),
1005
1179
  show: () => {
1006
- a?.show();
1180
+ c?.show();
1007
1181
  },
1008
1182
  hide: () => {
1009
- a?.hide();
1183
+ c?.hide();
1010
1184
  },
1011
1185
  destroy: () => {
1012
- a && (a.destroy(), a = null);
1186
+ c && (c.destroy(), c = null);
1013
1187
  },
1014
1188
  setTheme: (d) => {
1015
- a?.setTheme(d);
1189
+ c?.setTheme(d);
1016
1190
  },
1017
- getInstance: () => a
1191
+ getInstance: () => c
1018
1192
  };
1019
- typeof window < "u" && (window.MygigstersCard = u, window.MygigstersCardSDK = m, document.addEventListener("DOMContentLoaded", () => {
1193
+ typeof window < "u" && (window.MygigstersCard = b, window.MygigstersCardSDK = f, document.addEventListener("DOMContentLoaded", () => {
1020
1194
  const d = document.querySelector(
1021
1195
  'script[data-mygigsters-config][src*="card-sdk"]'
1022
1196
  );
@@ -1030,9 +1204,9 @@ typeof window < "u" && (window.MygigstersCard = u, window.MygigstersCardSDK = m,
1030
1204
  console.error("Failed to parse MyGigsters Card SDK config:", t);
1031
1205
  }
1032
1206
  }));
1033
- typeof window < "u" && (window.MygigstersCard = u, window.MygigstersCardSDK = m);
1207
+ typeof window < "u" && (window.MygigstersCard = b, window.MygigstersCardSDK = f);
1034
1208
  export {
1035
- u as MygigstersCard,
1036
- m as MygigstersCardSDK,
1037
- m as default
1209
+ b as MygigstersCard,
1210
+ f as MygigstersCardSDK,
1211
+ f as default
1038
1212
  };