@yourroad/sdk 0.1.0 → 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,8 +1,8 @@
1
- var E = Object.defineProperty;
2
- var k = (s, t, e) => t in s ? E(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
3
- var o = (s, t, e) => k(s, typeof t != "symbol" ? t + "" : t, e);
4
- const S = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/bootstrap-embed-access";
5
- function A(s) {
1
+ var k = Object.defineProperty;
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
+ 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;
8
8
  if (typeof t != "string" || t.trim() === "") throw new Error("Invalid bootstrap response.");
@@ -17,8 +17,8 @@ function A(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),
@@ -27,47 +27,55 @@ async function O(s, t) {
27
27
  signal: t
28
28
  });
29
29
  if (!e.ok) throw new Error("Bootstrap request was unsuccessful.");
30
- return A(await e.json());
30
+ return I(await e.json());
31
31
  }
32
- const f = (s) => Object.fromEntries(Object.entries(s ?? {}).filter(([, t]) => t !== void 0));
33
- function b(s, t) {
34
- const e = { ...s, ...f(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], ...f(t[r]) });
36
+ t[r] !== void 0 && (e[r] = { ...s[r], ...v(t[r]) });
37
37
  return e;
38
38
  }
39
- const h = (s) => b({}, s ?? {}), a = 1;
40
- function I(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 m = (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
- }, R = (s) => m(s) ? s.source === "yourroad.embed" && s.version === a && s.type === "ready" && s.payload === void 0 && (s.requestId === void 0 || typeof s.requestId == "string") : !1, j = (s) => m(s) && Object.keys(s).length === 3 && s.source === "yourroad.embed" && s.version === a && s.type === "journey_session_restart";
50
- class T {
51
- constructor(t, e, r, i, n) {
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
- j(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
- R(t.data) && (this.ready = !0, this.post({ source: "yourroad.sdk", version: a, 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: a,
69
+ version: u,
65
70
  type: "context",
66
- payload: h(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 = n;
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 T {
75
83
  contextUpdated(t) {
76
84
  this.ready && this.post({
77
85
  source: "yourroad.sdk",
78
- version: a,
86
+ version: u,
79
87
  type: "context_updated",
80
- payload: h(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: a, 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 T {
95
109
  }
96
110
  }
97
111
  }
98
- class l 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 _ {
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 _ {
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 N {
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();
@@ -133,11 +148,11 @@ class N {
133
148
  (t = this.previous) != null && t.isConnected && this.previous.focus(), this.previous = null;
134
149
  }
135
150
  }
136
- class C {
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,66 +163,83 @@ class C {
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 L {
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 D = 2147483e3, Y = `
161
- [data-yourroad-overlay-root] { all: initial; position: fixed; inset: 0; z-index: ${D}; 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
- [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; background: #fff; box-shadow: -8px 0 30px rgba(0,0,0,.2); }
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; }
165
181
  [data-yourroad-close]:focus-visible { outline: 3px solid #1769e0; outline-offset: 2px; }
166
- [data-yourroad-frame] { all: initial; box-sizing: border-box; display: block; width: 100%; height: 100%; border: 0; background: #fff; }
167
- @media (max-width: 600px) { [data-yourroad-panel] { width: 100vw; max-width: none; } }
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; }
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 = Y, document.head.append(t), t;
189
+ return t.dataset.yourroadSdk = "", t.textContent = D, document.head.append(t), t;
174
190
  }
175
- class U {
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 = "";
184
- const n = document.createElement("div");
185
- n.dataset.yourroadPanel = "", this.closeButton = document.createElement("button"), this.closeButton.type = "button", this.closeButton.dataset.yourroadClose = "", this.closeButton.setAttribute("aria-label", "Close YourRoad"), this.closeButton.textContent = "×", this.iframe = new L(t, r), n.append(this.closeButton, this.iframe.element), this.root.append(i, n);
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 = "";
201
+ const a = document.createElement("div");
202
+ a.dataset.yourroadPanel = "", this.closeButton = document.createElement("button"), this.closeButton.type = "button", this.closeButton.dataset.yourroadClose = "", this.closeButton.setAttribute("aria-label", "Close YourRoad");
203
+ const n = document.createElementNS("http://www.w3.org/2000/svg", "svg");
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");
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);
186
207
  const d = this.abort.signal;
187
- i.addEventListener("click", e, { signal: d }), this.closeButton.addEventListener("click", e, { signal: d }), document.addEventListener("keydown", (c) => {
188
- c.key === "Escape" && e();
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();
189
210
  }, { signal: d });
190
211
  }
191
212
  mount() {
192
213
  document.body.append(this.root);
193
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
+ }
194
226
  destroy() {
195
227
  var t;
196
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();
197
229
  }
198
230
  }
199
- const u = "yr_journey_session_pre_approval_v1", p = (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);
200
- function B() {
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);
232
+ function U() {
201
233
  try {
202
234
  return globalThis.localStorage;
203
235
  } catch {
204
236
  return;
205
237
  }
206
238
  }
207
- function P(s = B()) {
239
+ function B(s = U()) {
208
240
  const t = () => {
209
241
  try {
210
- s == null || s.removeItem(u);
242
+ s == null || s.removeItem(y);
211
243
  } catch {
212
244
  }
213
245
  };
@@ -215,12 +247,12 @@ function P(s = B()) {
215
247
  read() {
216
248
  let e;
217
249
  try {
218
- e = (s == null ? void 0 : s.getItem(u)) ?? null;
250
+ e = (s == null ? void 0 : s.getItem(y)) ?? null;
219
251
  } catch {
220
252
  return;
221
253
  }
222
254
  if (e !== null) {
223
- if (!p(e)) {
255
+ if (!b(e)) {
224
256
  t();
225
257
  return;
226
258
  }
@@ -228,20 +260,20 @@ function P(s = B()) {
228
260
  }
229
261
  },
230
262
  write(e) {
231
- if (p(e))
263
+ if (b(e))
232
264
  try {
233
- s == null || s.setItem(u, e);
265
+ s == null || s.setItem(y, e);
234
266
  } catch {
235
267
  }
236
268
  },
237
269
  clear: t
238
270
  };
239
271
  }
240
- const J = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/create-embed-journey-session", q = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/probe-embed-journey-session", v = (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) => {
241
273
  if (s === null || typeof s != "object") return !1;
242
274
  const t = Object.getPrototypeOf(s);
243
275
  return t === Object.prototype || t === null;
244
- }, w = (s) => typeof s == "string" && s.trim() !== "" && !Number.isNaN(Date.parse(s)), x = (s, t) => ({
276
+ }, A = (s) => typeof s == "string" && s.trim() !== "" && !Number.isNaN(Date.parse(s)), R = (s, t) => ({
245
277
  method: "POST",
246
278
  headers: { "Content-Type": "application/json" },
247
279
  body: JSON.stringify(s),
@@ -249,121 +281,191 @@ const J = "https://tsajlkcfcvjqqjxfigbw.supabase.co/functions/v1/create-embed-jo
249
281
  cache: "no-store",
250
282
  signal: t
251
283
  });
252
- async function y(s, t) {
253
- const e = await fetch(J, x({ 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));
254
286
  if (e.status !== 201) throw new Error("Journey session creation was unsuccessful.");
255
287
  const r = await e.json();
256
- if (!v(r) || !p(r.sessionId) || !w(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.");
257
289
  return r.sessionId;
258
290
  }
259
- async function M(s, t) {
260
- const e = await fetch(q, x({ partnerKey: s, surface: "pre-approval", sessionId: t })), r = await e.json();
261
- if (!v(r)) throw new Error("Invalid journey session probe response.");
262
- if (e.status === 200 && r.status === "resumable" && r.sessionId === t && w(r.expiresAt))
291
+ async function F(s, t) {
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))
263
295
  return { status: "resumable", sessionId: t };
264
296
  if (e.status === 410 && r.status === "expired" && r.code === "SESSION_EXPIRED") return { status: "expired" };
265
297
  if (e.status === 404 && r.status === "invalid" && r.code === "SESSION_INVALID") return { status: "invalid" };
266
298
  throw new Error("Journey session probe was unsuccessful.");
267
299
  }
268
- class F {
269
- constructor(t, e = P()) {
270
- o(this, "state", { kind: "cold" });
271
- o(this, "restart");
300
+ class X {
301
+ constructor(t, e = B()) {
302
+ i(this, "state", { kind: "cold" });
303
+ i(this, "restart");
304
+ i(this, "generation", 0);
272
305
  this.partnerKey = t, this.marker = e;
273
306
  const r = e.read();
274
307
  if (!r) return;
275
- const i = this.probe(r);
276
- this.state = { kind: "probing", completion: i };
308
+ const o = this.probe(r, this.generation);
309
+ this.state = { kind: "probing", completion: o };
277
310
  }
278
311
  async resolveForOpen(t) {
279
- 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.");
280
315
  if (this.state.kind === "active" || this.state.kind === "expired") return this.state.sessionId;
281
- const e = await y(this.partnerKey, t);
282
- 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;
283
319
  }
284
320
  restartExpired(t) {
285
321
  if (this.state.kind !== "expired") return;
286
322
  if (this.restart) return this.restart;
287
- const e = y(this.partnerKey, t).then((r) => (this.marker.write(r), this.state = { kind: "active", sessionId: r }, r)).finally(() => {
288
- 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);
289
328
  });
290
- 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" };
291
333
  }
292
- async probe(t) {
334
+ invalidatePendingOperations() {
335
+ this.generation += 1, this.restart = void 0;
336
+ }
337
+ async probe(t, e) {
293
338
  try {
294
- const e = await M(this.partnerKey, t);
295
- 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" });
296
342
  } catch {
297
- this.state = { kind: "probe_failed" };
343
+ e === this.generation && (this.state = { kind: "probe_failed" });
298
344
  }
299
345
  }
300
346
  }
301
- class X {
347
+ class z {
302
348
  constructor(t) {
303
- o(this, "events", new _());
304
- o(this, "scroll", new C());
305
- o(this, "focus", new N());
306
- o(this, "overlay");
307
- o(this, "bridge");
308
- o(this, "context", {});
309
- o(this, "destroyed", !1);
310
- o(this, "opening");
311
- o(this, "bootstrapAbort");
312
- o(this, "restartAbort");
313
- o(this, "session");
314
- this.config = t, this.session = new F(t.partnerKey);
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");
364
+ this.config = t, this.session = new X(t.partnerKey);
315
365
  }
316
366
  async open(t) {
317
- if (this.assertUsable(), !t || t.surface !== "pre-approval") throw this.fail("INVALID_SURFACE", 'The only supported surface is "pre-approval".');
318
- if (this.overlay) return;
319
- if (this.opening) return this.opening;
320
- this.context = h(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;
321
391
  const e = new AbortController();
322
392
  this.bootstrapAbort = e;
323
- const r = this.performOpen(t.surface, e);
324
- return this.opening = r, r;
393
+ const r = this.performMount(t, e);
394
+ return this.mounting = r, r;
325
395
  }
326
396
  updateContext(t) {
327
397
  var e;
328
- this.assertUsable(), this.context = b(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);
329
399
  }
330
400
  close() {
331
- var t, e;
332
- 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));
333
403
  }
334
404
  on(t, e) {
335
405
  return this.assertUsable(), this.events.on(t, e);
336
406
  }
337
407
  destroy() {
338
- 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);
339
410
  }
340
- async performOpen(t, e) {
341
- var r, i;
411
+ async performPrepare(t) {
412
+ var e;
413
+ try {
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;
342
423
  try {
343
- const [n, d] = await Promise.all([
344
- O({ partnerKey: this.config.partnerKey, surface: t }, e.signal),
424
+ const [n, l] = await Promise.all([
425
+ j({ partnerKey: this.config.partnerKey, surface: t }, e.signal),
345
426
  this.session.resolveForOpen(e.signal)
346
- ]), { iframeUrl: c } = n;
427
+ ]), { iframeUrl: d } = n;
347
428
  if (e.signal.aborted || this.destroyed || this.bootstrapAbort !== e) return;
348
- this.focus.capture();
349
429
  try {
350
- this.overlay = new U(c, () => this.close(), () => this.fail("IFRAME_LOAD_FAILED", "The embedded experience failed to load.")), this.bridge = new T(
351
- this.overlay.iframe.element,
352
- I(c),
353
- () => h(this.context),
354
- () => d,
355
- () => this.restartExpiredSession(this.bridge)
356
- ), this.bridge.start(), this.overlay.mount(), this.scroll.lock(), this.focus.moveTo(this.overlay.closeButton), this.events.emit("opened", void 0);
357
- } catch (g) {
358
- 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.", g);
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);
359
443
  }
360
444
  } catch (n) {
361
445
  if (e.signal.aborted) return;
362
- throw n instanceof l ? n : this.fail("BOOTSTRAP_FAILED", "The YourRoad experience could not be started securely.", n);
446
+ throw n instanceof p ? n : this.fail("BOOTSTRAP_FAILED", "The YourRoad experience could not be started securely.", n);
363
447
  } finally {
364
- this.bootstrapAbort === e && (this.bootstrapAbort = void 0, this.opening = void 0);
448
+ this.bootstrapAbort === e && (this.bootstrapAbort = void 0, this.mounting = void 0);
365
449
  }
366
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
+ }
367
469
  restartExpiredSession(t) {
368
470
  if (this.destroyed || t === void 0 || t !== this.bridge || this.restartAbort) return;
369
471
  const e = new AbortController();
@@ -373,33 +475,55 @@ class X {
373
475
  this.restartAbort = void 0;
374
476
  return;
375
477
  }
376
- r.then((i) => {
377
- !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);
378
480
  }).catch(() => {
379
481
  }).finally(() => {
380
482
  this.restartAbort === e && (this.restartAbort = void 0);
381
483
  });
382
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
+ }
383
507
  assertUsable() {
384
- if (this.destroyed) throw new l("DESTROYED", "This YourRoad SDK instance has been destroyed.");
508
+ if (this.destroyed) throw new p("DESTROYED", "This YourRoad SDK instance has been destroyed.");
385
509
  }
386
510
  fail(t, e, r) {
387
- const i = new l(t, e, r === void 0 ? void 0 : { cause: r });
388
- 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;
389
513
  }
390
514
  }
391
- function z(s) {
392
- return new X(s);
515
+ function $(s) {
516
+ return new z(s);
393
517
  }
394
- class $ {
518
+ class H {
395
519
  static init(t) {
396
520
  if (!t || typeof t.partnerKey != "string" || t.partnerKey.trim() === "")
397
- throw new l("INVALID_INITIALISATION", "partnerKey must be a non-empty string.");
398
- return z({ partnerKey: t.partnerKey });
521
+ throw new p("INVALID_INITIALISATION", "partnerKey must be a non-empty string.");
522
+ return $({ partnerKey: t.partnerKey });
399
523
  }
400
524
  }
401
525
  export {
402
- $ as YourRoad,
403
- l as YourRoadError
526
+ H as YourRoad,
527
+ p as YourRoadError
404
528
  };
405
529
  //# sourceMappingURL=index.js.map