@salla.sa/embedded-sdk 0.2.3 → 0.2.5

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/esm/index.js CHANGED
@@ -1,44 +1,52 @@
1
- const o = "embedded::", v = {
1
+ const o = "embedded::", C = {
2
2
  /** Initialize handshake - iframe signals it's ready to receive context */
3
3
  INIT: `${o}iframe.ready`,
4
- /** Request iframe resize */
5
- RESIZE: `${o}iframe.resize`,
6
4
  /** App signals it's fully loaded and ready */
7
5
  READY: `${o}ready`,
8
6
  /** App requests to be destroyed and navigate away */
9
7
  DESTROY: `${o}destroy`
10
- }, x = {
8
+ }, O = {
11
9
  /** Context data provision */
12
10
  PROVIDE: `${o}context.provide`,
13
11
  /** Theme change notification */
14
12
  THEME_CHANGE: `${o}theme.change`
15
- }, g = {
13
+ }, h = {
16
14
  /** Set loading state */
17
15
  LOADING: `${o}ui.loading`,
16
+ /** Set breadcrumbs visibility state */
17
+ BREADCRUMBS: `${o}ui.breadcrumbs`,
18
18
  /** Show toast notification */
19
19
  TOAST: `${o}ui.toast`,
20
20
  /** Show confirm dialog (async request) */
21
21
  CONFIRM: `${o}ui.confirm`,
22
22
  /** Confirm dialog response (from host) */
23
23
  CONFIRM_RESPONSE: `${o}ui.confirm.response`
24
- }, K = {}, U = {
24
+ }, G = {}, V = {
25
25
  /** Request token refresh (re-renders iframe with new token) */
26
26
  REFRESH: `${o}auth.refresh`
27
- }, m = {
27
+ }, b = {
28
28
  /** Navigate using React Router (SPA navigation) */
29
29
  NAVIGATE: `${o}page.navigate`,
30
30
  /** Redirect using window.location (full page reload) */
31
31
  REDIRECT: `${o}page.redirect`,
32
32
  /** Set page title */
33
33
  SET_TITLE: `${o}page.setTitle`
34
- }, S = {
34
+ }, l = {
35
35
  /** Set primary action button in navbar */
36
36
  SET_ACTION: `${o}nav.setAction`,
37
37
  /** Clear the primary action button */
38
38
  CLEAR_ACTION: `${o}nav.clearAction`,
39
39
  /** Notification when action button is clicked (host → iframe) */
40
- ACTION_CLICK: `${o}nav.actionClick`
41
- }, p = {
40
+ ACTION_CLICK: `${o}nav.actionClick`,
41
+ /** Add one sub-navigation item (iframe → host) */
42
+ ADD_ITEM: `${o}nav.addItem`,
43
+ /** Ack with generated opaque id (host → iframe; request response) */
44
+ ADD_ITEM_RESPONSE: `${o}nav.addItem.response`,
45
+ UPDATE_ITEM: `${o}nav.updateItem`,
46
+ REMOVE_ITEM: `${o}nav.removeItem`,
47
+ /** Injected sub-nav item clicked (host → iframe) */
48
+ ITEM_CLICK: `${o}nav.itemClick`
49
+ }, g = {
42
50
  /** Create checkout flow */
43
51
  CREATE: `${o}checkout.create`,
44
52
  /** Checkout response from host */
@@ -46,92 +54,113 @@ const o = "embedded::", v = {
46
54
  /** Get available addons for the app */
47
55
  GET_ADDONS: `${o}checkout.getAddons`,
48
56
  /** Get addons response from host */
49
- GET_ADDONS_RESPONSE: `${o}checkout.getAddons.response`
50
- }, N = K.version || "", X = 1e4, W = [
57
+ GET_ADDONS_RESPONSE: `${o}checkout.getAddons.response`,
58
+ /** Reset checkout cache on host */
59
+ RESET_CACHE: `${o}checkout.resetCache`
60
+ }, R = G.version || "", K = 1e4, B = [
51
61
  "localhost",
52
62
  "merchants.workers.dev",
53
63
  "s.salla.sa",
54
64
  ".salla.group",
55
65
  ".salla.sa"
56
- ];
57
- let A = {
66
+ ], X = /* @__PURE__ */ new Set([
67
+ "ar",
68
+ // Arabic
69
+ "he",
70
+ // Hebrew
71
+ "fa",
72
+ // Persian / Farsi
73
+ "ur",
74
+ // Urdu
75
+ "ps",
76
+ // Pashto
77
+ "sd",
78
+ // Sindhi
79
+ "yi"
80
+ // Yiddish
81
+ ]);
82
+ function W(t) {
83
+ const e = (t ?? "ar").toLowerCase().split(/[-_]/)[0];
84
+ return X.has(e) ? "rtl" : "ltr";
85
+ }
86
+ let S = {
58
87
  showVersion: !0,
59
88
  debug: !1
60
89
  };
61
90
  function Y(t) {
62
- A = { ...A, ...t };
91
+ S = { ...S, ...t };
63
92
  }
64
- function D(t) {
93
+ function L(t) {
65
94
  return `%c${t}`;
66
95
  }
67
- function L(t, e = "#fff") {
96
+ function x(t, e = "#fff") {
68
97
  return `background-color: ${t}; color: ${e}; padding: 2px 6px; border-radius: 3px; font-weight: 500; font-size: 11px;`;
69
98
  }
70
- function b(t, ...e) {
71
- if (t === "debug" && !A.debug)
99
+ function y(t, ...e) {
100
+ if (t === "debug" && !S.debug)
72
101
  return;
73
102
  const r = [], i = [];
74
- r.push(D("EmbeddedSDK")), i.push(L("#10b981", "#fff")), A.showVersion && (r.push(D(`v${N}`)), i.push(L("#6b7280", "#fff")));
103
+ r.push(L("EmbeddedSDK")), i.push(x("#10b981", "#fff")), S.showVersion && (r.push(L(`v${R}`)), i.push(x("#6b7280", "#fff")));
75
104
  const n = r.join("").trim();
76
105
  (console[t] || console.log)(n, ...i, ...e);
77
106
  }
78
107
  const a = {
79
108
  log: (...t) => {
80
- b("log", ...t);
109
+ y("log", ...t);
81
110
  },
82
111
  warn: (...t) => {
83
- b("warn", ...t);
112
+ y("warn", ...t);
84
113
  },
85
114
  error: (...t) => {
86
- b("error", ...t);
115
+ y("error", ...t);
87
116
  },
88
117
  info: (...t) => {
89
- b("info", ...t);
118
+ y("info", ...t);
90
119
  },
91
120
  debug: (...t) => {
92
- b("debug", ...t);
121
+ y("debug", ...t);
93
122
  }
94
123
  };
95
- function B(t) {
124
+ function Q(t) {
96
125
  try {
97
126
  const r = new URL(t).hostname;
98
- return W.some((i) => i.startsWith(".") ? r.endsWith(i) || r === i.slice(1) : r === i || r.startsWith(`${i}:`));
127
+ return B.some((i) => i.startsWith(".") ? r.endsWith(i) || r === i.slice(1) : r === i || r.startsWith(`${i}:`));
99
128
  } catch {
100
129
  return !1;
101
130
  }
102
131
  }
103
- function Z() {
132
+ function J() {
104
133
  return typeof window > "u" || window.parent === window ? null : window.parent;
105
134
  }
106
135
  function u(t, e, r = "*", i, n) {
107
- const s = Z();
136
+ const s = J();
108
137
  if (!s) {
109
138
  a.warn("Not running in an iframe, cannot post to host");
110
139
  return;
111
140
  }
112
- const c = {
141
+ const d = {
113
142
  event: t,
114
143
  payload: e || {},
115
144
  timestamp: Date.now(),
116
145
  source: "embedded-app",
117
146
  ...i && { requestId: i },
118
147
  metadata: {
119
- version: N
148
+ version: R
120
149
  }
121
150
  };
122
- s.postMessage(c, r);
151
+ s.postMessage(d, r);
123
152
  }
124
- const l = /* @__PURE__ */ new Map();
125
- let R = !1;
126
- function V(t) {
127
- if (process.env.NODE_ENV === "production" && !B(t.origin))
153
+ const p = /* @__PURE__ */ new Map();
154
+ let A = !1;
155
+ function j(t) {
156
+ if (process.env.NODE_ENV === "production" && !Q(t.origin))
128
157
  return;
129
158
  const e = t.data;
130
159
  if (!e || typeof e.event != "string" || !e.payload || typeof e.timestamp != "number" || !e.source) {
131
160
  a.warn("Invalid message structure received:", e);
132
161
  return;
133
162
  }
134
- const r = l.get(e.event);
163
+ const r = p.get(e.event);
135
164
  r && r.forEach((n) => {
136
165
  try {
137
166
  n(e);
@@ -139,7 +168,7 @@ function V(t) {
139
168
  a.error("Error in message handler:", s);
140
169
  }
141
170
  });
142
- const i = l.get("*");
171
+ const i = p.get("*");
143
172
  i && i.forEach((n) => {
144
173
  try {
145
174
  n(e);
@@ -148,87 +177,87 @@ function V(t) {
148
177
  }
149
178
  });
150
179
  }
151
- function Q() {
152
- R || typeof window > "u" || (window.addEventListener("message", V), R = !0);
180
+ function Z() {
181
+ A || typeof window > "u" || (window.addEventListener("message", j), A = !0);
153
182
  }
154
- function y(t, e) {
155
- Q(), l.has(t) || l.set(t, /* @__PURE__ */ new Set());
156
- const r = l.get(t);
183
+ function m(t, e) {
184
+ Z(), p.has(t) || p.set(t, /* @__PURE__ */ new Set());
185
+ const r = p.get(t);
157
186
  return r.add(e), () => {
158
- r.delete(e), r.size === 0 && l.delete(t);
187
+ r.delete(e), r.size === 0 && p.delete(t);
159
188
  };
160
189
  }
161
- function J(t, e = X) {
190
+ function ee(t, e = K) {
162
191
  return new Promise((r, i) => {
163
192
  const n = setTimeout(() => {
164
193
  s(), i(new Error(`[EmbeddedSDK] Timeout waiting for "${t}" message`));
165
- }, e), s = y(t, (c) => {
166
- clearTimeout(n), s(), r(c);
194
+ }, e), s = m(t, (d) => {
195
+ clearTimeout(n), s(), r(d);
167
196
  });
168
197
  });
169
198
  }
170
- function ee() {
171
- l.clear(), R && typeof window < "u" && (window.removeEventListener("message", V), R = !1);
172
- }
173
199
  function te() {
200
+ p.clear(), A && typeof window < "u" && (window.removeEventListener("message", j), A = !1);
201
+ }
202
+ function re() {
174
203
  return typeof window > "u" ? !1 : window.parent !== window;
175
204
  }
176
- function re(t, e, r) {
205
+ function ie(t, e, r) {
177
206
  const i = {
178
207
  event: t,
179
208
  payload: e,
180
209
  timestamp: Date.now(),
181
210
  source: "merchant-dashboard",
182
211
  ...r,
183
- metadata: { version: N, synthetic: !0 }
184
- }, n = l.get(t);
185
- n == null || n.forEach((s) => {
212
+ metadata: { version: R, synthetic: !0 }
213
+ };
214
+ p.get(t)?.forEach((s) => {
186
215
  try {
187
216
  s(i);
188
- } catch (c) {
189
- a.error("Error in message handler:", c);
217
+ } catch (d) {
218
+ a.error("Error in message handler:", d);
190
219
  }
191
220
  });
192
221
  }
193
- const h = /* @__PURE__ */ new Map(), ie = 3e4;
194
- function H() {
222
+ const E = /* @__PURE__ */ new Map(), ne = 3e4;
223
+ function F() {
195
224
  const t = Date.now(), e = Math.random().toString(36).slice(2, 9);
196
225
  return `req_${t}_${e}`;
197
226
  }
198
- function j(t, e = {}, r = ie) {
199
- const i = H();
227
+ function $(t, e = {}, r = ne) {
228
+ const i = F();
200
229
  return new Promise((n, s) => {
201
- const c = setTimeout(() => {
202
- h.get(i) && (h.delete(i), s(
230
+ const d = setTimeout(() => {
231
+ E.get(i) && (E.delete(i), s(
203
232
  new Error(
204
233
  `[EmbeddedSDK] Request "${t}" timed out after ${r}ms`
205
234
  )
206
235
  ));
207
236
  }, r);
208
- h.set(i, {
237
+ E.set(i, {
209
238
  resolve: n,
210
239
  reject: s,
211
- timeout: c,
240
+ timeout: d,
212
241
  event: t
213
242
  }), u(t, e, "*", i);
214
243
  });
215
244
  }
216
- function F(t, e, r) {
217
- const i = h.get(t);
245
+ function D(t, e, r) {
246
+ const i = E.get(t);
218
247
  if (!i) {
219
248
  a.warn(`Received response for unknown request: ${t}`);
220
249
  return;
221
250
  }
222
- clearTimeout(i.timeout), h.delete(t), i.resolve(e);
251
+ clearTimeout(i.timeout), E.delete(t), i.resolve(e);
223
252
  }
224
- function ne(t = "SDK cleanup") {
225
- h.forEach((e, r) => {
253
+ function se(t = "SDK cleanup") {
254
+ E.forEach((e, r) => {
226
255
  clearTimeout(e.timeout), e.reject(
227
256
  new Error(`[EmbeddedSDK] Request ${r} cancelled: ${t}`)
228
257
  );
229
- }), h.clear();
258
+ }), E.clear();
230
259
  }
231
- function I() {
260
+ function w() {
232
261
  const t = /* @__PURE__ */ new Set();
233
262
  return {
234
263
  subscribe(e) {
@@ -253,41 +282,40 @@ function I() {
253
282
  }
254
283
  };
255
284
  }
256
- const se = "https://api.salla.dev";
285
+ const ae = "https://api.salla.dev";
257
286
  class T extends Error {
258
287
  constructor(e, r, i) {
259
288
  super(e), this.status = r, this.response = i, this.name = "ApiError";
260
289
  }
261
290
  }
262
- async function ae(t, e = {}) {
263
- const { method: r = "GET", headers: i = {}, body: n, timeout: s = 3e4 } = e, c = `${se}${t}`, C = new AbortController(), _ = setTimeout(() => {
264
- C.abort();
291
+ async function oe(t, e = {}) {
292
+ const { method: r = "GET", headers: i = {}, body: n, timeout: s = 3e4 } = e, d = `${ae}${t}`, N = new AbortController(), M = setTimeout(() => {
293
+ N.abort();
265
294
  }, s);
266
295
  try {
267
- const d = await fetch(c, {
296
+ const c = await fetch(d, {
268
297
  method: r,
269
298
  headers: {
270
299
  "Content-Type": "application/json",
271
300
  ...i
272
301
  },
273
302
  body: n ? JSON.stringify(n) : void 0,
274
- signal: C.signal
303
+ signal: N.signal
275
304
  });
276
- clearTimeout(_);
277
- let w;
278
- const $ = d.headers.get("content-type");
279
- if ($ != null && $.includes("application/json") ? w = await d.json() : w = await d.text(), !d.ok)
305
+ clearTimeout(M);
306
+ let I;
307
+ if (c.headers.get("content-type")?.includes("application/json") ? I = await c.json() : I = await c.text(), !c.ok)
280
308
  throw new T(
281
- `API request failed: ${d.statusText}`,
282
- d.status,
283
- w
309
+ `API request failed: ${c.statusText}`,
310
+ c.status,
311
+ I
284
312
  );
285
- return w;
286
- } catch (d) {
287
- throw clearTimeout(_), d instanceof T ? d : d instanceof Error ? d.name === "AbortError" ? new T(`Request timeout after ${s}ms`) : new T(`Request failed: ${d.message}`) : new T("Unknown error occurred");
313
+ return I;
314
+ } catch (c) {
315
+ throw clearTimeout(M), c instanceof T ? c : c instanceof Error ? c.name === "AbortError" ? new T(`Request timeout after ${s}ms`) : new T(`Request failed: ${c.message}`) : new T("Unknown error occurred");
288
316
  }
289
317
  }
290
- function O(t) {
318
+ function _(t) {
291
319
  return {
292
320
  isVerified: !1,
293
321
  isError: !0,
@@ -295,18 +323,18 @@ function O(t) {
295
323
  data: null
296
324
  };
297
325
  }
298
- async function oe(t) {
326
+ async function ue(t) {
299
327
  const { token: e, appId: r, refreshOnError: i = !0 } = t;
300
328
  if (!e) {
301
329
  const n = "Token is required. Provide it as a parameter or in URL as ?token=XXX";
302
- return a.error("Error in introspect:", n), O(n);
330
+ return a.error("Error in introspect:", n), _(n);
303
331
  }
304
332
  if (!r) {
305
333
  const n = "App ID is required. Provide it as a parameter or in URL as ?app_id=XXX";
306
- return a.error("Error in introspect:", n), O(n);
334
+ return a.error("Error in introspect:", n), _(n);
307
335
  }
308
336
  try {
309
- const n = await ae(
337
+ const n = await oe(
310
338
  "/exchange-authority/v1/introspect",
311
339
  {
312
340
  method: "POST",
@@ -329,12 +357,12 @@ async function oe(t) {
329
357
  data: s ? n.data : null
330
358
  };
331
359
  } catch (n) {
332
- i && (G().ui.toast.error((n == null ? void 0 : n.toString()) ?? "Introspect error"), u(U.REFRESH, {})), a.error("Error in introspect:", n);
360
+ i && (H().ui.toast.error(n?.toString() ?? "Introspect error"), u(V.REFRESH, {})), a.error("Error in introspect:", n);
333
361
  const s = n instanceof Error ? n.message : n;
334
- return O(s);
362
+ return _(s);
335
363
  }
336
364
  }
337
- function ue(t) {
365
+ function de(t) {
338
366
  return {
339
367
  /**
340
368
  * Get the token from the URL query parameter.
@@ -369,7 +397,7 @@ function ue(t) {
369
397
  * ```
370
398
  */
371
399
  refresh() {
372
- u(U.REFRESH, {});
400
+ u(V.REFRESH, {});
373
401
  },
374
402
  /**
375
403
  * Introspect (verify) a short-lived token with Salla's API.
@@ -380,7 +408,7 @@ function ue(t) {
380
408
  */
381
409
  async introspect(e = {}) {
382
410
  const r = e.token ?? this.getToken() ?? "", i = e.appId ?? this.getAppId() ?? "";
383
- return oe({
411
+ return ue({
384
412
  token: r,
385
413
  appId: i,
386
414
  refreshOnError: e.refreshOnError
@@ -399,7 +427,7 @@ function q(t, e) {
399
427
  const r = [];
400
428
  return typeof t != "object" || t === null ? (r.push(`${e} must be an object`), r) : ((typeof t.type != "string" || t.type.trim() === "") && r.push(`${e} must have a valid type`), (typeof t.slug != "string" || t.slug.trim() === "") && r.push(`${e} must have a valid slug`), t.quantity !== void 0 && (typeof t.quantity != "number" || t.quantity < 1) && r.push(`${e} must have a quantity >= 1`), r);
401
429
  }
402
- function de(t) {
430
+ function le(t) {
403
431
  const e = [];
404
432
  if (typeof t != "object" || t === null)
405
433
  return e.push("Checkout options must be an object"), { valid: !1, errors: e };
@@ -414,18 +442,18 @@ function de(t) {
414
442
  return e.push(...n), { valid: e.length === 0, errors: e };
415
443
  }
416
444
  return Array.isArray(t.items) ? t.items.length === 0 ? (e.push("At least one item is required"), { valid: !1, errors: e }) : (t.items.forEach((n, s) => {
417
- const c = q(
445
+ const d = q(
418
446
  n,
419
447
  `Item at index ${s}`
420
448
  );
421
- e.push(...c);
449
+ e.push(...d);
422
450
  }), { valid: e.length === 0, errors: e }) : (e.push("Checkout items must be an array"), { valid: !1, errors: e });
423
451
  }
424
- function le(t) {
452
+ function fe(t) {
425
453
  const e = [];
426
454
  return t.path === void 0 || t.path === null ? e.push("Navigation path is required") : typeof t.path != "string" ? e.push("Navigation path must be a string") : t.path.trim() === "" && e.push("Navigation path cannot be empty"), t.replace !== void 0 && typeof t.replace != "boolean" && e.push("Navigation replace option must be a boolean"), { valid: e.length === 0, errors: e };
427
455
  }
428
- function fe(t) {
456
+ function he(t) {
429
457
  const e = [];
430
458
  if (t.url === void 0 || t.url === null)
431
459
  e.push("Redirect URL is required");
@@ -441,7 +469,7 @@ function fe(t) {
441
469
  }
442
470
  return { valid: e.length === 0, errors: e };
443
471
  }
444
- function he(t) {
472
+ function pe(t) {
445
473
  const e = [];
446
474
  return t.title ? typeof t.title != "string" && e.push("Nav action title must be a string") : e.push("Nav action title is required"), t.value ? typeof t.value != "string" && e.push("Nav action value must be a string") : e.push("Nav action value is required"), t.subTitle !== void 0 && t.subTitle !== null && typeof t.subTitle != "string" && e.push("Nav action subTitle must be a string"), t.icon !== void 0 && t.icon !== null && typeof t.icon != "string" && e.push("Nav action icon must be a string"), t.disabled !== void 0 && t.disabled !== null && typeof t.disabled != "boolean" && e.push("Nav action disabled must be a boolean"), t.extendedActions !== void 0 && t.extendedActions !== null && (Array.isArray(t.extendedActions) ? t.extendedActions.forEach((r, i) => {
447
475
  if (typeof r != "object" || r === null) {
@@ -462,11 +490,38 @@ function he(t) {
462
490
  );
463
491
  }) : e.push("Nav action extendedActions must be an array")), { valid: e.length === 0, errors: e };
464
492
  }
465
- const M = ["danger", "warning", "info"];
493
+ function me(t) {
494
+ const e = [];
495
+ if (typeof t != "object" || t === null)
496
+ return e.push("Nav addItem expects an object item"), { valid: !1, errors: e };
497
+ const r = t;
498
+ return ["title", "value", "url"].forEach((i) => {
499
+ (typeof r[i] != "string" || !String(r[i]).trim()) && e.push(`Sub-nav addItem "${i}" must be non-empty string`);
500
+ }), r.disabled !== void 0 && typeof r.disabled != "boolean" && e.push('Sub-nav addItem "disabled" must be boolean'), r.active !== void 0 && typeof r.active != "boolean" && e.push('Sub-nav addItem "active" must be boolean'), { valid: e.length === 0, errors: e };
501
+ }
466
502
  function ge(t) {
467
503
  const e = [];
468
- return t.title === void 0 || t.title === null ? e.push("Confirm dialog title is required") : typeof t.title != "string" ? e.push("Confirm dialog title must be a string") : t.title.trim() === "" && e.push("Confirm dialog title cannot be empty"), t.message === void 0 || t.message === null ? e.push("Confirm dialog message is required") : typeof t.message != "string" ? e.push("Confirm dialog message must be a string") : t.message.trim() === "" && e.push("Confirm dialog message cannot be empty"), t.confirmText !== void 0 && t.confirmText !== null && typeof t.confirmText != "string" && e.push("Confirm dialog confirmText must be a string"), t.cancelText !== void 0 && t.cancelText !== null && typeof t.cancelText != "string" && e.push("Confirm dialog cancelText must be a string"), t.variant !== void 0 && t.variant !== null && (typeof t.variant != "string" || !M.includes(t.variant)) && e.push(
469
- `Invalid confirm variant "${t.variant}". Expected: ${M.join(" | ")}`
504
+ if (typeof t != "object" || t === null)
505
+ return e.push("Nav updateItem expects an object item"), { valid: !1, errors: e };
506
+ const r = t;
507
+ if (typeof r.id != "string" || !r.id.trim())
508
+ return e.push('Sub-nav updateItem requires string "id"'), { valid: !1, errors: e };
509
+ let i = 0;
510
+ return r.title !== void 0 && i++, r.value !== void 0 && i++, r.url !== void 0 && i++, r.disabled !== void 0 && i++, r.active !== void 0 && i++, i === 0 ? (e.push(
511
+ "Sub-nav updateItem must include at least one of title, value, url, disabled, active"
512
+ ), { valid: !1, errors: e }) : (["title", "value", "url"].forEach((n) => {
513
+ r[n] !== void 0 && (typeof r[n] != "string" || !r[n].trim()) && e.push(`Sub-nav updateItem "${n}" must be non-empty`);
514
+ }), r.disabled !== void 0 && typeof r.disabled != "boolean" && e.push('Sub-nav updateItem "disabled" must be boolean'), r.active !== void 0 && typeof r.active != "boolean" && e.push('Sub-nav updateItem "active" must be boolean'), { valid: e.length === 0, errors: e });
515
+ }
516
+ function Ee(t) {
517
+ const e = [];
518
+ return (typeof t != "string" || !t.trim()) && e.push("Nav removeItem id must be non-empty string"), { valid: e.length === 0, errors: e };
519
+ }
520
+ const z = ["danger", "warning", "info"];
521
+ function be(t) {
522
+ const e = [];
523
+ return t.title === void 0 || t.title === null ? e.push("Confirm dialog title is required") : typeof t.title != "string" ? e.push("Confirm dialog title must be a string") : t.title.trim() === "" && e.push("Confirm dialog title cannot be empty"), t.message === void 0 || t.message === null ? e.push("Confirm dialog message is required") : typeof t.message != "string" ? e.push("Confirm dialog message must be a string") : t.message.trim() === "" && e.push("Confirm dialog message cannot be empty"), t.confirmText !== void 0 && t.confirmText !== null && typeof t.confirmText != "string" && e.push("Confirm dialog confirmText must be a string"), t.cancelText !== void 0 && t.cancelText !== null && typeof t.cancelText != "string" && e.push("Confirm dialog cancelText must be a string"), t.variant !== void 0 && t.variant !== null && (typeof t.variant != "string" || !z.includes(t.variant)) && e.push(
524
+ `Invalid confirm variant "${t.variant}". Expected: ${z.join(" | ")}`
470
525
  ), { valid: e.length === 0, errors: e };
471
526
  }
472
527
  function f(t, e) {
@@ -476,136 +531,161 @@ function f(t, e) {
476
531
  `)
477
532
  );
478
533
  }
479
- function me() {
534
+ function ve() {
535
+ return { resize: (i) => {
536
+ }, autoResize: () => {
537
+ }, stopAutoResize: () => {
538
+ } };
539
+ }
540
+ function ye() {
541
+ const { resize: t, autoResize: e, stopAutoResize: r } = ve();
480
542
  return {
481
- /**
482
- * Navigate to a path using React Router (SPA navigation).
483
- */
484
- navigate(t, e) {
485
- const r = le({ path: t, ...e });
486
- if (!r.valid) {
487
- f(m.NAVIGATE, r.errors);
543
+ navigate(i, n) {
544
+ const s = fe({ path: i, ...n });
545
+ if (!s.valid) {
546
+ f(b.NAVIGATE, s.errors);
488
547
  return;
489
548
  }
490
- u(m.NAVIGATE, {
491
- path: t,
492
- state: e == null ? void 0 : e.state,
493
- replace: e == null ? void 0 : e.replace
549
+ u(b.NAVIGATE, {
550
+ path: i,
551
+ state: n?.state,
552
+ replace: n?.replace
494
553
  });
495
554
  },
496
- /**
497
- * Redirect to a URL (full page reload).
498
- */
499
- redirect(t) {
500
- const e = fe({ url: t });
501
- if (!e.valid) {
502
- f(m.REDIRECT, e.errors);
555
+ redirect(i) {
556
+ const n = he({ url: i });
557
+ if (!n.valid) {
558
+ f(b.REDIRECT, n.errors);
503
559
  return;
504
560
  }
505
- u(m.REDIRECT, { url: t });
561
+ u(b.REDIRECT, { url: i });
506
562
  },
507
- /**
508
- * Navigate to a path - auto-detects internal vs external.
509
- */
510
- navTo(t, e) {
511
- if (t.startsWith("http://") || t.startsWith("https://")) {
512
- this.redirect(t);
513
- return;
514
- }
515
- this.navigate(t, e);
516
- },
517
- /**
518
- * Update the iframe height.
519
- */
520
- resize(t) {
521
- if (typeof t != "number" || t < 0) {
522
- f(v.RESIZE, [
523
- "Height must be a non-negative number"
524
- ]);
563
+ navTo(i, n) {
564
+ if (i.startsWith("http://") || i.startsWith("https://")) {
565
+ this.redirect(i);
525
566
  return;
526
567
  }
527
- u(v.RESIZE, { height: t });
568
+ this.navigate(i, n);
528
569
  },
529
- /**
530
- * Auto-resize iframe to content height.
531
- */
532
- autoResize() {
533
- const t = document.documentElement.scrollHeight;
534
- this.resize(t);
535
- },
536
- /**
537
- * Set the page title in the host document.
538
- */
539
- setTitle(t) {
540
- if (typeof t != "string" || !t.trim()) {
541
- f(m.SET_TITLE, [
570
+ setTitle(i) {
571
+ if (typeof i != "string" || !i.trim()) {
572
+ f(b.SET_TITLE, [
542
573
  "Title must be a non-empty string"
543
574
  ]);
544
575
  return;
545
576
  }
546
- u(m.SET_TITLE, { title: t });
547
- }
577
+ u(b.SET_TITLE, { title: i });
578
+ },
579
+ resize: t,
580
+ autoResize: e,
581
+ stopAutoResize: r
548
582
  };
549
583
  }
550
- function pe() {
551
- const t = I();
552
- return y(S.ACTION_CLICK, (e) => {
553
- t.notify(e.payload.value);
554
- }), {
555
- setAction(e) {
556
- var i;
557
- const r = he(e);
558
- if (!r.valid) {
559
- f(S.SET_ACTION, r.errors);
584
+ function Te() {
585
+ const t = w(), e = w(), r = [];
586
+ return r.push(
587
+ m(l.ACTION_CLICK, (i) => {
588
+ t.notify(i.payload.value);
589
+ })
590
+ ), r.push(
591
+ m(l.ADD_ITEM_RESPONSE, (i) => {
592
+ const n = i.payload.item;
593
+ i.requestId && n && typeof n.id == "string" && typeof n.value == "string" && D(i.requestId, n);
594
+ })
595
+ ), r.push(
596
+ m(l.ITEM_CLICK, (i) => {
597
+ e.notify(i.payload);
598
+ })
599
+ ), {
600
+ setAction(i) {
601
+ const n = pe(i);
602
+ if (!n.valid) {
603
+ f(l.SET_ACTION, n.errors);
560
604
  return;
561
605
  }
562
- u(S.SET_ACTION, {
563
- title: e.title,
564
- value: e.value,
565
- subTitle: e.subTitle,
566
- icon: e.icon,
567
- disabled: e.disabled,
568
- extendedActions: (i = e.extendedActions) == null ? void 0 : i.map((n) => ({
569
- title: n.title,
570
- value: n.value,
571
- subTitle: n.subTitle,
572
- icon: n.icon,
573
- disabled: n.disabled
606
+ u(l.SET_ACTION, {
607
+ title: i.title,
608
+ value: i.value,
609
+ subTitle: i.subTitle,
610
+ icon: i.icon,
611
+ disabled: i.disabled,
612
+ extendedActions: i.extendedActions?.map((s) => ({
613
+ title: s.title,
614
+ value: s.value,
615
+ subTitle: s.subTitle,
616
+ icon: s.icon,
617
+ disabled: s.disabled
574
618
  }))
575
619
  });
576
620
  },
577
621
  clearAction() {
578
- u(S.CLEAR_ACTION, {});
622
+ u(l.CLEAR_ACTION, {});
623
+ },
624
+ onActionClick(i) {
625
+ return t.subscribe(i);
626
+ },
627
+ addNavItem(i) {
628
+ const n = me(i);
629
+ return n.valid ? $(l.ADD_ITEM, { item: i }, 2e3) : (f(l.ADD_ITEM, n.errors), Promise.reject(new Error(n.errors[0])));
579
630
  },
580
- onActionClick(e) {
581
- return t.subscribe(e);
631
+ updateNavItem(i) {
632
+ const n = ge(i);
633
+ if (!n.valid) {
634
+ f(l.UPDATE_ITEM, n.errors);
635
+ return;
636
+ }
637
+ u(l.UPDATE_ITEM, { item: i });
638
+ },
639
+ removeNavItem(i) {
640
+ const n = Ee(i);
641
+ if (!n.valid) {
642
+ f(l.REMOVE_ITEM, n.errors);
643
+ return;
644
+ }
645
+ u(l.REMOVE_ITEM, { id: i });
646
+ },
647
+ onNavItemClick(i) {
648
+ return e.subscribe(i);
649
+ },
650
+ destroy() {
651
+ r.forEach((i) => i()), r.length = 0, t.clear(), e.clear();
582
652
  }
583
653
  };
584
654
  }
585
- function Ee() {
655
+ function we() {
586
656
  return {
587
657
  /**
588
658
  * Show loading indicator.
589
659
  */
590
660
  show() {
591
- u(g.LOADING, { action: "show" });
661
+ u(h.LOADING, { action: "show" });
592
662
  },
593
663
  /**
594
664
  * Hide loading indicator.
595
665
  */
596
666
  hide() {
597
- u(g.LOADING, { action: "hide" });
667
+ u(h.LOADING, { action: "hide" });
598
668
  }
599
669
  };
600
670
  }
601
- function ye() {
671
+ function Ie() {
672
+ return {
673
+ hide() {
674
+ u(h.BREADCRUMBS, { action: "hide" });
675
+ },
676
+ show() {
677
+ u(h.BREADCRUMBS, { action: "show" });
678
+ }
679
+ };
680
+ }
681
+ function Se() {
602
682
  const t = (e) => {
603
683
  const r = ce(e);
604
684
  if (!r.valid) {
605
- f(g.TOAST, r.errors);
685
+ f(h.TOAST, r.errors);
606
686
  return;
607
687
  }
608
- u(g.TOAST, {
688
+ u(h.TOAST, {
609
689
  type: e.type,
610
690
  message: e.message,
611
691
  duration: e.duration
@@ -642,29 +722,30 @@ function ye() {
642
722
  }
643
723
  };
644
724
  }
645
- function be() {
725
+ function Ae() {
646
726
  return async (t) => {
647
- const e = ge(t);
648
- return e.valid ? j(g.CONFIRM, {
727
+ const e = be(t);
728
+ return e.valid ? $(h.CONFIRM, {
649
729
  title: t.title,
650
730
  message: t.message,
651
731
  confirmText: t.confirmText ?? "Confirm",
652
732
  cancelText: t.cancelText ?? "Cancel",
653
733
  variant: t.variant ?? "info"
654
- }) : (f(g.CONFIRM, e.errors), Promise.reject(new Error(e.errors.join(", "))));
734
+ }) : (f(h.CONFIRM, e.errors), Promise.reject(new Error(e.errors.join(", "))));
655
735
  };
656
736
  }
657
- function Te() {
737
+ function Re() {
658
738
  return {
659
- loading: Ee(),
660
- toast: ye(),
661
- confirm: be()
739
+ loading: we(),
740
+ breadcrumbs: Ie(),
741
+ toast: Se(),
742
+ confirm: Ae()
662
743
  };
663
744
  }
664
- function ve() {
665
- const t = I(), e = [];
745
+ function Ne() {
746
+ const t = w(), e = [];
666
747
  return e.push(
667
- y(p.RESPONSE, (r) => {
748
+ m(g.RESPONSE, (r) => {
668
749
  t.notify({
669
750
  success: r.payload.success,
670
751
  order_id: r.payload.order_id,
@@ -674,10 +755,10 @@ function ve() {
674
755
  });
675
756
  })
676
757
  ), e.push(
677
- y(
678
- p.GET_ADDONS_RESPONSE,
758
+ m(
759
+ g.GET_ADDONS_RESPONSE,
679
760
  (r) => {
680
- r.requestId && F(r.requestId, {
761
+ r.requestId && D(r.requestId, {
681
762
  success: r.payload.success,
682
763
  addons: r.payload.addons,
683
764
  error: r.payload.error
@@ -686,21 +767,21 @@ function ve() {
686
767
  )
687
768
  ), {
688
769
  create(r, i) {
689
- const n = Array.isArray(r) ? r : [r], s = de({ items: n });
770
+ const n = Array.isArray(r) ? r : [r], s = le({ items: n });
690
771
  if (!s.valid)
691
- throw f(p.CREATE, s.errors), new Error(s.errors[0]);
772
+ throw f(g.CREATE, s.errors), new Error(s.errors[0]);
692
773
  u(
693
- p.CREATE,
774
+ g.CREATE,
694
775
  {
695
- items: n.map((c) => ({
696
- type: c.type,
697
- slug: c.slug,
698
- quantity: c.quantity ?? 1
776
+ items: n.map((d) => ({
777
+ type: d.type,
778
+ slug: d.slug,
779
+ quantity: d.quantity ?? 1
699
780
  })),
700
- ...(i == null ? void 0 : i.context) !== void 0 && { context: i.context }
781
+ ...i?.context !== void 0 && { context: i.context }
701
782
  },
702
783
  "*",
703
- H()
784
+ F()
704
785
  );
705
786
  },
706
787
  onResult(r) {
@@ -708,8 +789,8 @@ function ve() {
708
789
  },
709
790
  async getAddons() {
710
791
  try {
711
- return await j(
712
- p.GET_ADDONS,
792
+ return await $(
793
+ g.GET_ADDONS,
713
794
  {},
714
795
  3e4
715
796
  );
@@ -723,23 +804,27 @@ function ve() {
723
804
  };
724
805
  }
725
806
  },
807
+ resetCache() {
808
+ u(g.RESET_CACHE, {}, "*");
809
+ },
726
810
  destroy() {
727
811
  e.forEach((r) => r()), e.length = 0, t.clear();
728
812
  }
729
813
  };
730
814
  }
731
- const z = {
815
+ const P = {
732
816
  theme: "light",
817
+ dir: "rtl",
733
818
  width: 0,
734
819
  locale: "ar",
735
820
  currency: "SAR"
736
821
  };
737
- class we {
822
+ class Ce {
738
823
  constructor() {
739
- this.initialized = !1, this.initializing = !1, this.debugMode = !1, this.appReady = !1, this.layout = { ...z }, this.postInitHooks = [], this.themeSubscription = I(), this.initSubscription = I(), this.auth = ue(), this.page = me(), this.nav = pe(), this.ui = Te(), this.checkout = ve(), this.registerPostInitHook((e) => {
824
+ this.initialized = !1, this.initializing = !1, this.debugMode = !1, this.appReady = !1, this.layout = { ...P }, this.postInitHooks = [], this.themeSubscription = w(), this.initSubscription = w(), this.auth = de(), this.page = ye(), this.nav = Te(), this.ui = Re(), this.checkout = Ne(), this.registerPostInitHook((e) => {
740
825
  const r = e.payload.pendingCheckoutResult;
741
826
  r && (a.debug("Dispatching pending checkout result:", r), queueMicrotask(() => {
742
- re(p.RESPONSE, {
827
+ ie(g.RESPONSE, {
743
828
  success: r.success,
744
829
  status: r.status,
745
830
  error: r.error,
@@ -759,10 +844,10 @@ class we {
759
844
  * Set up core event listeners.
760
845
  */
761
846
  setupListeners() {
762
- y(x.THEME_CHANGE, (e) => {
847
+ m(O.THEME_CHANGE, (e) => {
763
848
  this.layout.theme = e.payload.theme, a.debug("Theme changed:", e.payload.theme), this.themeSubscription.notify(e.payload.theme);
764
- }), y(g.CONFIRM_RESPONSE, (e) => {
765
- a.debug("Received confirm response:", e), e.requestId && F(e.requestId, { confirmed: e.payload.confirmed });
849
+ }), m(h.CONFIRM_RESPONSE, (e) => {
850
+ a.debug("Received confirm response:", e), e.requestId && D(e.requestId, { confirmed: e.payload.confirmed });
766
851
  });
767
852
  }
768
853
  /**
@@ -811,7 +896,7 @@ class we {
811
896
  a.warn("Cannot signal ready before init() is called");
812
897
  return;
813
898
  }
814
- this.appReady = !0, u(v.READY, {}), a.debug("Sent ready signal to host");
899
+ this.appReady = !0, u(C.READY, {}), a.debug("Sent ready signal to host");
815
900
  }
816
901
  /**
817
902
  * Initialize the SDK and establish connection with the host.
@@ -825,21 +910,22 @@ class we {
825
910
  i(), r({ layout: { ...n.layout } });
826
911
  });
827
912
  });
828
- this.initializing = !0, this.debugMode = e.debug ?? !1, Y({ debug: this.debugMode }), te() || a.warn("Not running in an iframe. Some features may not work."), a.debug("Initializing SDK...");
913
+ this.initializing = !0, this.debugMode = e.debug ?? !1, Y({ debug: this.debugMode }), re() || a.warn("Not running in an iframe. Some features may not work."), a.debug("Initializing SDK...");
829
914
  try {
830
- u(v.INIT, {
915
+ u(C.INIT, {
831
916
  height: document.documentElement.scrollHeight
832
917
  }), a.debug("Sent iframe.ready message, waiting for context...");
833
- const r = await J(
834
- x.PROVIDE
918
+ const r = await ee(
919
+ O.PROVIDE
835
920
  );
836
921
  a.debug("Received context from host:", r);
837
922
  const { layout: i } = r.payload;
838
923
  return this.layout = {
839
- theme: (i == null ? void 0 : i.theme) ?? "light",
840
- width: (i == null ? void 0 : i.width) ?? 0,
841
- locale: (i == null ? void 0 : i.locale) ?? "ar",
842
- currency: (i == null ? void 0 : i.currency) ?? "SAR"
924
+ theme: i?.theme ?? "light",
925
+ dir: i?.dir ?? W(i?.locale),
926
+ width: i?.width ?? 0,
927
+ locale: i?.locale ?? "ar",
928
+ currency: i?.currency ?? "SAR"
843
929
  }, this.postInitHooks.forEach((n) => {
844
930
  try {
845
931
  n(r);
@@ -855,23 +941,23 @@ class we {
855
941
  * Destroy the SDK instance and clean up resources.
856
942
  */
857
943
  destroy() {
858
- a.debug("Destroying SDK instance"), this.initialized && (u(v.DESTROY, {}), a.debug("Sent destroy event to host")), this.checkout.destroy(), ne("SDK destroyed"), ee(), this.themeSubscription.clear(), this.initSubscription.clear(), this.postInitHooks = [], this.initialized = !1, this.initializing = !1, this.appReady = !1, this.layout = { ...z };
944
+ a.debug("Destroying SDK instance"), this.initialized && (u(C.DESTROY, {}), a.debug("Sent destroy event to host")), this.checkout.destroy(), this.nav.destroy(), se("SDK destroyed"), te(), this.themeSubscription.clear(), this.initSubscription.clear(), this.postInitHooks = [], this.initialized = !1, this.initializing = !1, this.appReady = !1, this.layout = { ...P };
859
945
  }
860
946
  }
861
- let E = null;
862
- function G() {
863
- return E || (E = new we()), E;
947
+ let v = null;
948
+ function H() {
949
+ return v || (v = new Ce()), v;
864
950
  }
865
- function Se() {
866
- E && (E.destroy(), E = null);
951
+ function $e() {
952
+ v && (v.destroy(), v = null);
867
953
  }
868
- const P = G(), Ae = N;
869
- typeof window < "u" && (window.salla = window.salla || window.Salla || {}, window.Salla = window.salla, window.salla.embedded || (window.salla.embedded = P), window.Salla.embedded || (window.Salla.embedded = P));
954
+ const U = H(), De = R;
955
+ typeof window < "u" && (window.salla = window.salla || window.Salla || {}, window.Salla = window.salla, window.salla.embedded || (window.salla.embedded = U), window.Salla.embedded || (window.Salla.embedded = U));
870
956
  export {
871
- we as EmbeddedApp,
872
- P as embedded,
873
- G as getEmbeddedApp,
874
- Se as resetEmbeddedApp,
875
- Ae as version
957
+ Ce as EmbeddedApp,
958
+ U as embedded,
959
+ H as getEmbeddedApp,
960
+ $e as resetEmbeddedApp,
961
+ De as version
876
962
  };
877
963
  //# sourceMappingURL=index.js.map