@yourroad/sdk 0.1.1 → 0.1.2

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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  var k = Object.defineProperty;
2
- var A = (s, t, e) => t in s ? k(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
3
- var o = (s, t, e) => A(s, typeof t != "symbol" ? t + "" : t, e);
4
- const S = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/bootstrap-embed-access";
2
+ var S = (s, t, e) => t in s ? k(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
3
+ var i = (s, t, e) => S(s, typeof t != "symbol" ? t + "" : t, e);
4
+ const O = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/bootstrap-embed-access";
5
5
  function I(s) {
6
6
  if (typeof s != "object" || s === null || Array.isArray(s)) throw new Error("Invalid bootstrap response.");
7
7
  const { iframeUrl: t, expiresAt: e } = s;
@@ -17,8 +17,8 @@ function I(s) {
17
17
  throw new Error("Invalid bootstrap response.");
18
18
  return { iframeUrl: t, expiresAt: e };
19
19
  }
20
- async function O(s, t) {
21
- const e = await fetch(S, {
20
+ async function j(s, t) {
21
+ const e = await fetch(O, {
22
22
  method: "POST",
23
23
  headers: { "Content-Type": "application/json" },
24
24
  body: JSON.stringify(s),
@@ -29,45 +29,53 @@ async function O(s, t) {
29
29
  if (!e.ok) throw new Error("Bootstrap request was unsuccessful.");
30
30
  return I(await e.json());
31
31
  }
32
- const y = (s) => Object.fromEntries(Object.entries(s ?? {}).filter(([, t]) => t !== void 0));
33
- function m(s, t) {
34
- const e = { ...s, ...y(t) };
32
+ const v = (s) => Object.fromEntries(Object.entries(s ?? {}).filter(([, t]) => t !== void 0));
33
+ function g(s, t) {
34
+ const e = { ...s, ...v(t) };
35
35
  for (const r of ["vehicle", "dealer", "page"])
36
- t[r] !== void 0 && (e[r] = { ...s[r], ...y(t[r]) });
36
+ t[r] !== void 0 && (e[r] = { ...s[r], ...v(t[r]) });
37
37
  return e;
38
38
  }
39
- const u = (s) => m({}, s ?? {}), d = 1;
40
- function R(s) {
39
+ const f = (s) => g({}, s ?? {}), u = 1;
40
+ function T(s) {
41
41
  const t = new URL(s);
42
42
  if (t.protocol !== "https:" && t.protocol !== "http:") throw new TypeError("The iframe URL must use HTTP(S).");
43
43
  return t.origin;
44
44
  }
45
- const v = (s) => {
45
+ const x = (s) => {
46
46
  if (s === null || typeof s != "object") return !1;
47
47
  const t = Object.getPrototypeOf(s);
48
48
  return t === Object.prototype || t === null;
49
- }, j = (s) => v(s) ? s.source === "yourroad.embed" && s.version === d && s.type === "ready" && s.payload === void 0 && (s.requestId === void 0 || typeof s.requestId == "string") : !1, T = (s) => v(s) && Object.keys(s).length === 3 && s.source === "yourroad.embed" && s.version === d && s.type === "journey_session_restart";
50
- class _ {
51
- constructor(t, e, r, i, a) {
52
- o(this, "ready", !1);
53
- o(this, "started", !1);
54
- o(this, "handleMessage", (t) => {
49
+ }, _ = (s) => x(s) ? s.source === "yourroad.embed" && s.version === u && s.type === "ready" && s.payload === void 0 && (s.requestId === void 0 || typeof s.requestId == "string") : !1, m = (s, t) => x(s) && Object.keys(s).length === 3 && s.source === "yourroad.embed" && s.version === u && s.type === t;
50
+ class N {
51
+ constructor(t, e, r, o, a, n = () => {
52
+ }) {
53
+ i(this, "ready", !1);
54
+ i(this, "started", !1);
55
+ i(this, "readinessSettled", !1);
56
+ i(this, "readiness");
57
+ i(this, "resolveReadiness");
58
+ i(this, "rejectReadiness");
59
+ i(this, "handleMessage", (t) => {
55
60
  if (t.origin !== this.trustedRuntimeOrigin) return;
56
61
  const e = this.iframe.contentWindow;
57
62
  if (!(e === null || t.source !== e)) {
58
63
  if (this.ready) {
59
- T(t.data) && this.onJourneySessionRestart();
64
+ m(t.data, "journey_session_restart") ? this.onJourneySessionRestart() : m(t.data, "journey_reset") && this.onJourneyReset();
60
65
  return;
61
66
  }
62
- j(t.data) && (this.ready = !0, this.post({ source: "yourroad.sdk", version: d, type: "ack" }), this.post({
67
+ _(t.data) && (this.ready = !0, this.post({ source: "yourroad.sdk", version: u, type: "ack" }), this.post({
63
68
  source: "yourroad.sdk",
64
- version: d,
69
+ version: u,
65
70
  type: "context",
66
- payload: u(this.getCurrentContext())
67
- }), this.sendJourneySession(this.getJourneySessionId()));
71
+ payload: f(this.getCurrentContext())
72
+ }), this.sendJourneySession(this.getJourneySessionId()), this.readinessSettled = !0, this.resolveReadiness());
68
73
  }
69
74
  });
70
- this.iframe = t, this.trustedRuntimeOrigin = e, this.getCurrentContext = r, this.getJourneySessionId = i, this.onJourneySessionRestart = a;
75
+ this.iframe = t, this.trustedRuntimeOrigin = e, this.getCurrentContext = r, this.getJourneySessionId = o, this.onJourneySessionRestart = a, this.onJourneyReset = n, this.readiness = new Promise((l, d) => {
76
+ this.resolveReadiness = l, this.rejectReadiness = d;
77
+ }), this.readiness.catch(() => {
78
+ });
71
79
  }
72
80
  start() {
73
81
  this.started || (window.addEventListener("message", this.handleMessage), this.started = !0);
@@ -75,16 +83,22 @@ class _ {
75
83
  contextUpdated(t) {
76
84
  this.ready && this.post({
77
85
  source: "yourroad.sdk",
78
- version: d,
86
+ version: u,
79
87
  type: "context_updated",
80
- payload: u(t)
88
+ payload: f(t)
81
89
  });
82
90
  }
91
+ whenReady() {
92
+ return this.readiness;
93
+ }
94
+ failReadiness(t) {
95
+ this.readinessSettled || (this.readinessSettled = !0, this.rejectReadiness(t));
96
+ }
83
97
  destroy() {
84
- this.started && window.removeEventListener("message", this.handleMessage), this.started = !1, this.ready = !1;
98
+ this.started && window.removeEventListener("message", this.handleMessage), this.started = !1, this.ready = !1, this.failReadiness(new Error("The runtime bridge was destroyed before it became ready."));
85
99
  }
86
100
  sendJourneySession(t) {
87
- this.ready && this.post({ source: "yourroad.sdk", version: d, type: "journey_session", payload: { sessionId: t } });
101
+ this.ready && this.post({ source: "yourroad.sdk", version: u, type: "journey_session", payload: { sessionId: t } });
88
102
  }
89
103
  post(t) {
90
104
  const e = this.iframe.contentWindow;
@@ -95,16 +109,16 @@ class _ {
95
109
  }
96
110
  }
97
111
  }
98
- class h extends Error {
99
- constructor(e, r, i) {
100
- super(r, i);
101
- o(this, "name", "YourRoadError");
112
+ class p extends Error {
113
+ constructor(e, r, o) {
114
+ super(r, o);
115
+ i(this, "name", "YourRoadError");
102
116
  this.code = e;
103
117
  }
104
118
  }
105
- class N {
119
+ class C {
106
120
  constructor() {
107
- o(this, "listeners", /* @__PURE__ */ new Map());
121
+ i(this, "listeners", /* @__PURE__ */ new Map());
108
122
  }
109
123
  on(t, e) {
110
124
  const r = this.listeners.get(t) ?? /* @__PURE__ */ new Set();
@@ -112,18 +126,19 @@ class N {
112
126
  }
113
127
  emit(t, e) {
114
128
  var r;
115
- (r = this.listeners.get(t)) == null || r.forEach((i) => i(e));
129
+ (r = this.listeners.get(t)) == null || r.forEach((o) => o(e));
116
130
  }
117
131
  clear() {
118
132
  this.listeners.clear();
119
133
  }
120
134
  }
121
- class C {
135
+ class J {
122
136
  constructor() {
123
- o(this, "previous", null);
137
+ i(this, "previous", null);
124
138
  }
125
139
  capture() {
126
- this.previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
140
+ var t;
141
+ (t = this.previous) != null && t.isConnected || (this.previous = document.activeElement instanceof HTMLElement ? document.activeElement : null);
127
142
  }
128
143
  moveTo(t) {
129
144
  t.focus();
@@ -135,9 +150,9 @@ class C {
135
150
  }
136
151
  class L {
137
152
  constructor() {
138
- o(this, "saved");
139
- o(this, "scrollX", 0);
140
- o(this, "scrollY", 0);
153
+ i(this, "saved");
154
+ i(this, "scrollX", 0);
155
+ i(this, "scrollY", 0);
141
156
  }
142
157
  lock() {
143
158
  if (this.saved) return;
@@ -148,17 +163,18 @@ class L {
148
163
  this.saved && (Object.assign(document.body.style, this.saved), this.saved = void 0, window.scrollTo(this.scrollX, this.scrollY));
149
164
  }
150
165
  }
151
- class D {
166
+ class P {
152
167
  constructor(t, e) {
153
- o(this, "element");
168
+ i(this, "element");
154
169
  this.element = document.createElement("iframe"), this.element.dataset.yourroadFrame = "", this.element.title = "YourRoad pre-approval", this.element.src = t, this.element.addEventListener("error", e, { once: !0 });
155
170
  }
156
171
  destroy() {
157
172
  this.element.remove();
158
173
  }
159
174
  }
160
- const Y = 2147483e3, B = `
161
- [data-yourroad-overlay-root] { all: initial; position: fixed; inset: 0; z-index: ${Y}; display: block; font-family: system-ui, sans-serif; color: #111; }
175
+ const q = 2147483e3, D = `
176
+ [data-yourroad-overlay-root] { all: initial; position: fixed; inset: 0; z-index: ${q}; display: block; font-family: system-ui, sans-serif; color: #111; }
177
+ [data-yourroad-overlay-root][hidden] { display: none; pointer-events: none; }
162
178
  [data-yourroad-scrim] { all: initial; position: absolute; inset: 0; display: block; background: rgba(0, 0, 0, .55); }
163
179
  [data-yourroad-panel] { all: initial; box-sizing: border-box; position: absolute; inset-block: 0; inset-inline-end: 0; display: flex; flex-direction: column; width: min(520px, 92vw); height: 100vh; height: 100dvh; padding-block-start: calc(max(12px, env(safe-area-inset-top)) + 56px); overflow: hidden; border-radius: 24px 0 0 24px; background: #fff; box-shadow: -8px 0 30px rgba(0,0,0,.2); }
164
180
  [data-yourroad-close] { all: unset; box-sizing: border-box; position: absolute; z-index: 1; inset-block-start: max(12px, env(safe-area-inset-top)); inset-inline-end: max(12px, env(safe-area-inset-right)); width: 44px; height: 44px; display: grid; place-items: center; border-radius: 999px; background: #fff; color: #111; box-shadow: 0 1px 8px rgba(0,0,0,.25); cursor: pointer; font: 28px/1 system-ui, sans-serif; }
@@ -166,41 +182,53 @@ const Y = 2147483e3, B = `
166
182
  [data-yourroad-frame] { all: initial; box-sizing: border-box; display: block; flex: 1 1 auto; min-height: 0; width: 100%; border: 0; background: #fff; }
167
183
  @media (max-width: 600px) { [data-yourroad-panel] { inset-block-start: auto; inset-block-end: 0; inset-inline-end: 0; width: 100vw; max-width: none; height: 92vh; height: 92dvh; border-radius: 24px 24px 0 0; box-shadow: 0 -8px 30px rgba(0,0,0,.2); } }
168
184
  `;
169
- function K() {
185
+ function Y() {
170
186
  const s = document.head.querySelector("style[data-yourroad-sdk]");
171
187
  if (s) return s;
172
188
  const t = document.createElement("style");
173
- return t.dataset.yourroadSdk = "", t.textContent = B, document.head.append(t), t;
189
+ return t.dataset.yourroadSdk = "", t.textContent = D, document.head.append(t), t;
174
190
  }
175
- class P {
191
+ class M {
176
192
  constructor(t, e, r) {
177
- o(this, "root");
178
- o(this, "closeButton");
179
- o(this, "iframe");
180
- o(this, "abort", new AbortController());
181
- K(), this.root = document.createElement("div"), this.root.dataset.yourroadOverlayRoot = "", this.root.setAttribute("role", "dialog"), this.root.setAttribute("aria-modal", "true"), this.root.setAttribute("aria-label", "YourRoad pre-approval");
182
- const i = document.createElement("div");
183
- i.dataset.yourroadScrim = "";
193
+ i(this, "root");
194
+ i(this, "closeButton");
195
+ i(this, "iframe");
196
+ i(this, "abort", new AbortController());
197
+ i(this, "visible", !1);
198
+ Y(), this.root = document.createElement("div"), this.root.dataset.yourroadOverlayRoot = "", this.root.setAttribute("aria-label", "YourRoad pre-approval"), this.hide();
199
+ const o = document.createElement("div");
200
+ o.dataset.yourroadScrim = "";
184
201
  const a = document.createElement("div");
185
202
  a.dataset.yourroadPanel = "", this.closeButton = document.createElement("button"), this.closeButton.type = "button", this.closeButton.dataset.yourroadClose = "", this.closeButton.setAttribute("aria-label", "Close YourRoad");
186
203
  const n = document.createElementNS("http://www.w3.org/2000/svg", "svg");
187
204
  n.setAttribute("viewBox", "0 0 24 24"), n.setAttribute("width", "24"), n.setAttribute("height", "24"), n.setAttribute("fill", "none"), n.setAttribute("stroke", "currentColor"), n.setAttribute("stroke-width", "2"), n.setAttribute("stroke-linecap", "round"), n.setAttribute("aria-hidden", "true");
188
- const c = document.createElementNS("http://www.w3.org/2000/svg", "path");
189
- c.setAttribute("d", "M6 6l12 12M18 6L6 18"), n.append(c), this.closeButton.append(n), this.iframe = new D(t, r), a.append(this.closeButton, this.iframe.element), this.root.append(i, a);
190
- const l = this.abort.signal;
191
- i.addEventListener("click", e, { signal: l }), this.closeButton.addEventListener("click", e, { signal: l }), document.addEventListener("keydown", (E) => {
192
- E.key === "Escape" && e();
193
- }, { signal: l });
205
+ const l = document.createElementNS("http://www.w3.org/2000/svg", "path");
206
+ l.setAttribute("d", "M6 6l12 12M18 6L6 18"), n.append(l), this.closeButton.append(n), this.iframe = new P(t, r), a.append(this.closeButton, this.iframe.element), this.root.append(o, a);
207
+ const d = this.abort.signal;
208
+ o.addEventListener("click", e, { signal: d }), this.closeButton.addEventListener("click", e, { signal: d }), document.addEventListener("keydown", (h) => {
209
+ this.visible && h.key === "Escape" && e();
210
+ }, { signal: d });
194
211
  }
195
212
  mount() {
196
213
  document.body.append(this.root);
197
214
  }
215
+ show() {
216
+ return this.visible ? !1 : (this.visible = !0, this.root.hidden = !1, this.root.inert = !1, this.root.removeAttribute("aria-hidden"), this.root.setAttribute("role", "dialog"), this.root.setAttribute("aria-modal", "true"), !0);
217
+ }
218
+ hide() {
219
+ if (!this.visible && this.root.hidden) return !1;
220
+ const t = this.visible;
221
+ return this.visible = !1, this.root.hidden = !0, this.root.inert = !0, this.root.setAttribute("aria-hidden", "true"), this.root.removeAttribute("role"), this.root.removeAttribute("aria-modal"), t;
222
+ }
223
+ isVisible() {
224
+ return this.visible;
225
+ }
198
226
  destroy() {
199
227
  var t;
200
228
  this.abort.abort(), this.iframe.destroy(), this.root.remove(), document.querySelector("[data-yourroad-overlay-root]") || (t = document.head.querySelector("style[data-yourroad-sdk]")) == null || t.remove();
201
229
  }
202
230
  }
203
- const p = "yr_journey_session_pre_approval_v1", f = (s) => typeof s == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s);
231
+ const y = "yr_journey_session_pre_approval_v1", b = (s) => typeof s == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s);
204
232
  function U() {
205
233
  try {
206
234
  return globalThis.localStorage;
@@ -208,10 +236,10 @@ function U() {
208
236
  return;
209
237
  }
210
238
  }
211
- function J(s = U()) {
239
+ function B(s = U()) {
212
240
  const t = () => {
213
241
  try {
214
- s == null || s.removeItem(p);
242
+ s == null || s.removeItem(y);
215
243
  } catch {
216
244
  }
217
245
  };
@@ -219,12 +247,12 @@ function J(s = U()) {
219
247
  read() {
220
248
  let e;
221
249
  try {
222
- e = (s == null ? void 0 : s.getItem(p)) ?? null;
250
+ e = (s == null ? void 0 : s.getItem(y)) ?? null;
223
251
  } catch {
224
252
  return;
225
253
  }
226
254
  if (e !== null) {
227
- if (!f(e)) {
255
+ if (!b(e)) {
228
256
  t();
229
257
  return;
230
258
  }
@@ -232,20 +260,20 @@ function J(s = U()) {
232
260
  }
233
261
  },
234
262
  write(e) {
235
- if (f(e))
263
+ if (b(e))
236
264
  try {
237
- s == null || s.setItem(p, e);
265
+ s == null || s.setItem(y, e);
238
266
  } catch {
239
267
  }
240
268
  },
241
269
  clear: t
242
270
  };
243
271
  }
244
- const q = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/create-embed-journey-session", M = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/probe-embed-journey-session", w = (s) => {
272
+ const K = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/create-embed-journey-session", V = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/probe-embed-journey-session", E = (s) => {
245
273
  if (s === null || typeof s != "object") return !1;
246
274
  const t = Object.getPrototypeOf(s);
247
275
  return t === Object.prototype || t === null;
248
- }, x = (s) => typeof s == "string" && s.trim() !== "" && !Number.isNaN(Date.parse(s)), g = (s, t) => ({
276
+ }, A = (s) => typeof s == "string" && s.trim() !== "" && !Number.isNaN(Date.parse(s)), R = (s, t) => ({
249
277
  method: "POST",
250
278
  headers: { "Content-Type": "application/json" },
251
279
  body: JSON.stringify(s),
@@ -253,121 +281,191 @@ const q = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/create-embed-jo
253
281
  cache: "no-store",
254
282
  signal: t
255
283
  });
256
- async function b(s, t) {
257
- const e = await fetch(q, g({ partnerKey: s, surface: "pre-approval" }, t));
284
+ async function w(s, t) {
285
+ const e = await fetch(K, R({ partnerKey: s, surface: "pre-approval" }, t));
258
286
  if (e.status !== 201) throw new Error("Journey session creation was unsuccessful.");
259
287
  const r = await e.json();
260
- if (!w(r) || !f(r.sessionId) || !x(r.expiresAt)) throw new Error("Invalid journey session response.");
288
+ if (!E(r) || !b(r.sessionId) || !A(r.expiresAt)) throw new Error("Invalid journey session response.");
261
289
  return r.sessionId;
262
290
  }
263
291
  async function F(s, t) {
264
- const e = await fetch(M, g({ partnerKey: s, surface: "pre-approval", sessionId: t })), r = await e.json();
265
- if (!w(r)) throw new Error("Invalid journey session probe response.");
266
- if (e.status === 200 && r.status === "resumable" && r.sessionId === t && x(r.expiresAt))
292
+ const e = await fetch(V, R({ partnerKey: s, surface: "pre-approval", sessionId: t })), r = await e.json();
293
+ if (!E(r)) throw new Error("Invalid journey session probe response.");
294
+ if (e.status === 200 && r.status === "resumable" && r.sessionId === t && A(r.expiresAt))
267
295
  return { status: "resumable", sessionId: t };
268
296
  if (e.status === 410 && r.status === "expired" && r.code === "SESSION_EXPIRED") return { status: "expired" };
269
297
  if (e.status === 404 && r.status === "invalid" && r.code === "SESSION_INVALID") return { status: "invalid" };
270
298
  throw new Error("Journey session probe was unsuccessful.");
271
299
  }
272
300
  class X {
273
- constructor(t, e = J()) {
274
- o(this, "state", { kind: "cold" });
275
- o(this, "restart");
301
+ constructor(t, e = B()) {
302
+ i(this, "state", { kind: "cold" });
303
+ i(this, "restart");
304
+ i(this, "generation", 0);
276
305
  this.partnerKey = t, this.marker = e;
277
306
  const r = e.read();
278
307
  if (!r) return;
279
- const i = this.probe(r);
280
- this.state = { kind: "probing", completion: i };
308
+ const o = this.probe(r, this.generation);
309
+ this.state = { kind: "probing", completion: o };
281
310
  }
282
311
  async resolveForOpen(t) {
283
- if (this.state.kind === "probing" && await this.state.completion, this.state.kind === "probe_failed") throw new Error("Journey session validity could not be established.");
312
+ const e = this.generation;
313
+ if (this.state.kind === "probing" && await this.state.completion, e !== this.generation) throw new Error("Journey session operation was superseded.");
314
+ if (this.state.kind === "probe_failed") throw new Error("Journey session validity could not be established.");
284
315
  if (this.state.kind === "active" || this.state.kind === "expired") return this.state.sessionId;
285
- const e = await b(this.partnerKey, t);
286
- return this.marker.write(e), this.state = { kind: "active", sessionId: e }, e;
316
+ const r = await w(this.partnerKey, t);
317
+ if (e !== this.generation) throw new Error("Journey session operation was superseded.");
318
+ return this.marker.write(r), this.state = { kind: "active", sessionId: r }, r;
287
319
  }
288
320
  restartExpired(t) {
289
321
  if (this.state.kind !== "expired") return;
290
322
  if (this.restart) return this.restart;
291
- const e = b(this.partnerKey, t).then((r) => (this.marker.write(r), this.state = { kind: "active", sessionId: r }, r)).finally(() => {
292
- this.restart === e && (this.restart = void 0);
323
+ const e = this.generation, r = w(this.partnerKey, t).then((o) => {
324
+ if (e !== this.generation) throw new Error("Journey session operation was superseded.");
325
+ return this.marker.write(o), this.state = { kind: "active", sessionId: o }, o;
326
+ }).finally(() => {
327
+ this.restart === r && (this.restart = void 0);
293
328
  });
294
- return this.restart = e, e;
329
+ return this.restart = r, r;
330
+ }
331
+ resetForNewJourney() {
332
+ this.generation += 1, this.restart = void 0, this.marker.clear(), this.state = { kind: "cold" };
333
+ }
334
+ invalidatePendingOperations() {
335
+ this.generation += 1, this.restart = void 0;
295
336
  }
296
- async probe(t) {
337
+ async probe(t, e) {
297
338
  try {
298
- const e = await F(this.partnerKey, t);
299
- e.status === "resumable" ? this.state = { kind: "active", sessionId: t } : e.status === "expired" ? (this.marker.clear(), this.state = { kind: "expired", sessionId: t }) : (this.marker.clear(), this.state = { kind: "cold" });
339
+ const r = await F(this.partnerKey, t);
340
+ if (e !== this.generation) return;
341
+ r.status === "resumable" ? this.state = { kind: "active", sessionId: t } : r.status === "expired" ? (this.marker.clear(), this.state = { kind: "expired", sessionId: t }) : (this.marker.clear(), this.state = { kind: "cold" });
300
342
  } catch {
301
- this.state = { kind: "probe_failed" };
343
+ e === this.generation && (this.state = { kind: "probe_failed" });
302
344
  }
303
345
  }
304
346
  }
305
347
  class z {
306
348
  constructor(t) {
307
- o(this, "events", new N());
308
- o(this, "scroll", new L());
309
- o(this, "focus", new C());
310
- o(this, "overlay");
311
- o(this, "bridge");
312
- o(this, "context", {});
313
- o(this, "destroyed", !1);
314
- o(this, "opening");
315
- o(this, "bootstrapAbort");
316
- o(this, "restartAbort");
317
- o(this, "session");
349
+ i(this, "events", new C());
350
+ i(this, "scroll", new L());
351
+ i(this, "focus", new J());
352
+ i(this, "overlay");
353
+ i(this, "bridge");
354
+ i(this, "context", {});
355
+ i(this, "destroyed", !1);
356
+ i(this, "preparing");
357
+ i(this, "mounting");
358
+ i(this, "wantsVisible", !1);
359
+ i(this, "visibilityRequest", 0);
360
+ i(this, "bootstrapAbort");
361
+ i(this, "restartAbort");
362
+ i(this, "resetting");
363
+ i(this, "session");
318
364
  this.config = t, this.session = new X(t.partnerKey);
319
365
  }
320
366
  async open(t) {
321
- if (this.assertUsable(), !t || t.surface !== "pre-approval") throw this.fail("INVALID_SURFACE", 'The only supported surface is "pre-approval".');
322
- if (this.overlay) return;
323
- if (this.opening) return this.opening;
324
- this.context = u(t.context);
367
+ this.assertUsable(), this.validateOptions(t), this.adoptContext(t);
368
+ const e = ++this.visibilityRequest;
369
+ if (this.wantsVisible = !0, this.overlay) {
370
+ this.show();
371
+ return;
372
+ }
373
+ try {
374
+ await this.ensureMounted(t.surface);
375
+ } catch (r) {
376
+ throw this.visibilityRequest === e && (this.wantsVisible = !1), r;
377
+ }
378
+ }
379
+ async prepare(t) {
380
+ if (this.assertUsable(), this.validateOptions(t), this.adoptContext(t), this.bridge) return this.bridge.whenReady();
381
+ if (this.preparing) return this.preparing;
382
+ const e = this.performPrepare(t.surface);
383
+ return this.preparing = e, e;
384
+ }
385
+ async ensureMounted(t) {
386
+ if (this.overlay) {
387
+ this.wantsVisible && this.show();
388
+ return;
389
+ }
390
+ if (this.mounting) return this.mounting;
325
391
  const e = new AbortController();
326
392
  this.bootstrapAbort = e;
327
- const r = this.performOpen(t.surface, e);
328
- return this.opening = r, r;
393
+ const r = this.performMount(t, e);
394
+ return this.mounting = r, r;
329
395
  }
330
396
  updateContext(t) {
331
397
  var e;
332
- this.assertUsable(), this.context = m(this.context, t), (e = this.bridge) == null || e.contextUpdated(this.context);
398
+ this.assertUsable(), this.context = g(this.context, t), (e = this.bridge) == null || e.contextUpdated(this.context);
333
399
  }
334
400
  close() {
335
- var t, e;
336
- this.assertUsable(), this.bootstrapAbort && (this.bootstrapAbort.abort(), this.bootstrapAbort = void 0, this.opening = void 0), (t = this.restartAbort) == null || t.abort(), this.restartAbort = void 0, this.overlay && ((e = this.bridge) == null || e.destroy(), this.bridge = void 0, this.overlay.destroy(), this.overlay = void 0, this.scroll.unlock(), this.focus.restore(), this.events.emit("closed", void 0));
401
+ var t;
402
+ this.assertUsable(), this.visibilityRequest += 1, this.wantsVisible = !1, (t = this.overlay) != null && t.hide() && (this.scroll.unlock(), this.focus.restore(), this.events.emit("closed", void 0));
337
403
  }
338
404
  on(t, e) {
339
405
  return this.assertUsable(), this.events.on(t, e);
340
406
  }
341
407
  destroy() {
342
- this.destroyed || (this.close(), this.events.clear(), this.context = {}, this.destroyed = !0);
408
+ var t, e, r, o;
409
+ this.destroyed || (this.visibilityRequest += 1, this.wantsVisible = !1, (t = this.bootstrapAbort) == null || t.abort(), this.bootstrapAbort = void 0, (e = this.restartAbort) == null || e.abort(), this.restartAbort = void 0, this.session.invalidatePendingOperations(), (r = this.bridge) == null || r.destroy(), this.bridge = void 0, (o = this.overlay) == null || o.destroy(), this.overlay = void 0, this.scroll.unlock(), this.focus.restore(), this.events.clear(), this.context = {}, this.destroyed = !0);
343
410
  }
344
- async performOpen(t, e) {
345
- var r, i;
411
+ async performPrepare(t) {
412
+ var e;
346
413
  try {
347
- const [a, n] = await Promise.all([
348
- O({ partnerKey: this.config.partnerKey, surface: t }, e.signal),
414
+ await this.ensureMounted(t), await ((e = this.bridge) == null ? void 0 : e.whenReady());
415
+ } catch (r) {
416
+ if (!this.destroyed) throw r;
417
+ } finally {
418
+ this.preparing = void 0;
419
+ }
420
+ }
421
+ async performMount(t, e, r) {
422
+ var o, a;
423
+ try {
424
+ const [n, l] = await Promise.all([
425
+ j({ partnerKey: this.config.partnerKey, surface: t }, e.signal),
349
426
  this.session.resolveForOpen(e.signal)
350
- ]), { iframeUrl: c } = a;
427
+ ]), { iframeUrl: d } = n;
351
428
  if (e.signal.aborted || this.destroyed || this.bootstrapAbort !== e) return;
352
- this.focus.capture();
353
429
  try {
354
- this.overlay = new P(c, () => this.close(), () => this.fail("IFRAME_LOAD_FAILED", "The embedded experience failed to load.")), this.bridge = new _(
355
- this.overlay.iframe.element,
356
- R(c),
357
- () => u(this.context),
358
- () => n,
359
- () => this.restartExpiredSession(this.bridge)
360
- ), this.bridge.start(), this.overlay.mount(), this.scroll.lock(), this.focus.moveTo(this.overlay.closeButton), this.events.emit("opened", void 0);
361
- } catch (l) {
362
- throw (r = this.bridge) == null || r.destroy(), this.bridge = void 0, (i = this.overlay) == null || i.destroy(), this.overlay = void 0, this.scroll.unlock(), this.focus.restore(), this.fail("OVERLAY_CREATION_FAILED", "The YourRoad overlay could not be created.", l);
430
+ const h = new M(d, () => this.close(), () => this.runtimeFailed());
431
+ this.overlay = h;
432
+ const c = new N(
433
+ h.iframe.element,
434
+ T(d),
435
+ () => f(this.context),
436
+ () => l,
437
+ () => this.restartExpiredSession(c),
438
+ () => this.resetJourneyRuntime(c, t)
439
+ );
440
+ this.bridge = c, c.start(), h.mount(), this.wantsVisible && this.show(r === void 0 || this.visibilityRequest !== r);
441
+ } catch (h) {
442
+ throw (o = this.bridge) == null || o.destroy(), this.bridge = void 0, (a = this.overlay) == null || a.destroy(), this.overlay = void 0, this.scroll.unlock(), this.focus.restore(), this.fail("OVERLAY_CREATION_FAILED", "The YourRoad overlay could not be created.", h);
363
443
  }
364
- } catch (a) {
444
+ } catch (n) {
365
445
  if (e.signal.aborted) return;
366
- throw a instanceof h ? a : this.fail("BOOTSTRAP_FAILED", "The YourRoad experience could not be started securely.", a);
446
+ throw n instanceof p ? n : this.fail("BOOTSTRAP_FAILED", "The YourRoad experience could not be started securely.", n);
367
447
  } finally {
368
- this.bootstrapAbort === e && (this.bootstrapAbort = void 0, this.opening = void 0);
448
+ this.bootstrapAbort === e && (this.bootstrapAbort = void 0, this.mounting = void 0);
369
449
  }
370
450
  }
451
+ show(t = !0) {
452
+ var e;
453
+ (e = this.overlay) != null && e.show() && (this.focus.capture(), this.scroll.lock(), this.focus.moveTo(this.overlay.closeButton), t && this.events.emit("opened", void 0));
454
+ }
455
+ runtimeFailed() {
456
+ var r, o, a, n;
457
+ const t = this.fail("IFRAME_LOAD_FAILED", "The embedded experience failed to load.");
458
+ (r = this.bridge) == null || r.failReadiness(t), (o = this.bridge) == null || o.destroy(), this.bridge = void 0;
459
+ const e = ((a = this.overlay) == null ? void 0 : a.isVisible()) ?? !1;
460
+ (n = this.overlay) == null || n.destroy(), this.overlay = void 0, e && (this.scroll.unlock(), this.focus.restore());
461
+ }
462
+ validateOptions(t) {
463
+ if (!t || t.surface !== "pre-approval") throw this.fail("INVALID_SURFACE", 'The only supported surface is "pre-approval".');
464
+ }
465
+ adoptContext(t) {
466
+ var e;
467
+ t.context !== void 0 && (this.context = f(t.context), (e = this.bridge) == null || e.contextUpdated(this.context));
468
+ }
371
469
  restartExpiredSession(t) {
372
470
  if (this.destroyed || t === void 0 || t !== this.bridge || this.restartAbort) return;
373
471
  const e = new AbortController();
@@ -377,33 +475,55 @@ class z {
377
475
  this.restartAbort = void 0;
378
476
  return;
379
477
  }
380
- r.then((i) => {
381
- !this.destroyed && !e.signal.aborted && this.bridge === t && t.sendJourneySession(i);
478
+ r.then((o) => {
479
+ !this.destroyed && !e.signal.aborted && this.bridge === t && t.sendJourneySession(o);
382
480
  }).catch(() => {
383
481
  }).finally(() => {
384
482
  this.restartAbort === e && (this.restartAbort = void 0);
385
483
  });
386
484
  }
485
+ resetJourneyRuntime(t, e) {
486
+ if (this.destroyed || t !== this.bridge || this.resetting) return;
487
+ const r = this.performJourneyReset(e);
488
+ this.resetting = r, r.catch(() => {
489
+ }).finally(() => {
490
+ this.resetting === r && (this.resetting = void 0);
491
+ });
492
+ }
493
+ async performJourneyReset(t) {
494
+ var a, n, l, d, h;
495
+ const e = (a = this.overlay) != null && a.isVisible() ? this.visibilityRequest : void 0;
496
+ if ((n = this.bootstrapAbort) == null || n.abort(), this.bootstrapAbort = void 0, this.mounting = void 0, (l = this.restartAbort) == null || l.abort(), this.restartAbort = void 0, this.session.resetForNewJourney(), (d = this.bridge) == null || d.destroy(), this.bridge = void 0, (h = this.overlay) == null || h.destroy(), this.overlay = void 0, this.destroyed) return;
497
+ const r = new AbortController();
498
+ this.bootstrapAbort = r;
499
+ const o = this.performMount(t, r, e);
500
+ this.mounting = o;
501
+ try {
502
+ await o;
503
+ } catch (c) {
504
+ throw !this.destroyed && !this.overlay && (this.scroll.unlock(), this.focus.restore()), c;
505
+ }
506
+ }
387
507
  assertUsable() {
388
- if (this.destroyed) throw new h("DESTROYED", "This YourRoad SDK instance has been destroyed.");
508
+ if (this.destroyed) throw new p("DESTROYED", "This YourRoad SDK instance has been destroyed.");
389
509
  }
390
510
  fail(t, e, r) {
391
- const i = new h(t, e, r === void 0 ? void 0 : { cause: r });
392
- return this.events.emit("error", i), i;
511
+ const o = new p(t, e, r === void 0 ? void 0 : { cause: r });
512
+ return this.events.emit("error", o), o;
393
513
  }
394
514
  }
395
- function V(s) {
515
+ function $(s) {
396
516
  return new z(s);
397
517
  }
398
- class W {
518
+ class H {
399
519
  static init(t) {
400
520
  if (!t || typeof t.partnerKey != "string" || t.partnerKey.trim() === "")
401
- throw new h("INVALID_INITIALISATION", "partnerKey must be a non-empty string.");
402
- return V({ partnerKey: t.partnerKey });
521
+ throw new p("INVALID_INITIALISATION", "partnerKey must be a non-empty string.");
522
+ return $({ partnerKey: t.partnerKey });
403
523
  }
404
524
  }
405
525
  export {
406
- W as YourRoad,
407
- h as YourRoadError
526
+ H as YourRoad,
527
+ p as YourRoadError
408
528
  };
409
529
  //# sourceMappingURL=index.js.map