@offscript/sdk 0.1.5 → 0.1.7

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkHPDLEAAL_cjs = require('./chunk-HPDLEAAL.cjs');
3
+ var chunkM7CHVDW6_cjs = require('./chunk-M7CHVDW6.cjs');
4
4
 
5
5
  // src/types/config.ts
6
6
  var DEFAULT_RECORDING = {
@@ -347,7 +347,7 @@ var ActionRecorder = class {
347
347
  this.scrollState = /* @__PURE__ */ new Map();
348
348
  this.move = [];
349
349
  const r = sink.config.recording;
350
- this.gen = new chunkHPDLEAAL_cjs.SelectorGenerator({ testIdAttributes: r.testIdAttributes, stableAttributes: r.stableAttributes });
350
+ this.gen = new chunkM7CHVDW6_cjs.SelectorGenerator({ testIdAttributes: r.testIdAttributes, stableAttributes: r.stableAttributes });
351
351
  }
352
352
  start() {
353
353
  const d = this.d;
@@ -411,7 +411,7 @@ var ActionRecorder = class {
411
411
  emit(draft, el, extra) {
412
412
  const s = this.sink.sanitizer;
413
413
  const data = {
414
- schemaVersion: chunkHPDLEAAL_cjs.ACTION_SCHEMA_VERSION,
414
+ schemaVersion: chunkM7CHVDW6_cjs.ACTION_SCHEMA_VERSION,
415
415
  type: draft.type,
416
416
  url: s.sanitizeUrl(location.href),
417
417
  viewport: { width: window.innerWidth, height: window.innerHeight },
@@ -672,7 +672,7 @@ function collectContext(reason, captureSensitiveValues = false) {
672
672
  timezone: safe(() => Intl.DateTimeFormat().resolvedOptions().timeZone),
673
673
  online: nav.onLine,
674
674
  visibility: document.visibilityState,
675
- sdkVersion: chunkHPDLEAAL_cjs.SDK_VERSION,
675
+ sdkVersion: chunkM7CHVDW6_cjs.SDK_VERSION,
676
676
  captureSensitiveValues
677
677
  };
678
678
  }
@@ -1533,6 +1533,7 @@ function resolveConfig(input) {
1533
1533
  privacy: resolvePrivacy(input.privacy),
1534
1534
  correlationWindowMs: input.correlationWindowMs ?? 3e3,
1535
1535
  controls: input.controls ?? true,
1536
+ endpoint: input.endpoint,
1536
1537
  persistenceKey: input.persistenceKey,
1537
1538
  onComplete: input.onComplete
1538
1539
  };
@@ -2211,6 +2212,20 @@ var SUCCESS_TEMPLATE = `
2211
2212
  `;
2212
2213
 
2213
2214
  // src/core/OffscriptSDK.ts
2215
+ var TOKEN_STORAGE_KEY = "offscript-session-token";
2216
+ var DRAFT_STORAGE_KEY = "offscript-draft-key";
2217
+ var COMPLETED_TOKEN_STORAGE_KEY = "offscript-completed-token";
2218
+ var RECORDING_SEGMENT_START_QUERY = "offscript_recording_start";
2219
+ function tokenFingerprint(token) {
2220
+ let first = 2166136261;
2221
+ let second = 2654435769;
2222
+ for (let index = 0; index < token.length; index++) {
2223
+ const character = token.charCodeAt(index);
2224
+ first = Math.imul(first ^ character, 16777619);
2225
+ second = Math.imul(second ^ character, 2246822519);
2226
+ }
2227
+ return `${first >>> 0}.${second >>> 0}`;
2228
+ }
2214
2229
  var Offscript = class {
2215
2230
  constructor(config = {}) {
2216
2231
  this.bus = new Emitter();
@@ -2226,6 +2241,7 @@ var Offscript = class {
2226
2241
  this.sequence = 0;
2227
2242
  this.pageId = uid("page_");
2228
2243
  this.submitted = false;
2244
+ this.launchTokenChanged = false;
2229
2245
  this.config = resolveConfig(config);
2230
2246
  this.sanitizer = new DataSanitizer(this.config.privacy);
2231
2247
  }
@@ -2238,18 +2254,90 @@ var Offscript = class {
2238
2254
  async init() {
2239
2255
  this.assertAlive();
2240
2256
  if (typeof window === "undefined") throw new OffscriptError("NOT_SUPPORTED", "O SDK requer um navegador");
2241
- this.initPromise ?? (this.initPromise = this.initializeDraft());
2257
+ this.initPromise ?? (this.initPromise = this.initialize());
2242
2258
  await this.initPromise;
2243
2259
  if (this.restorePromise) await this.restorePromise;
2244
- if (this.config.controls && !this.controls) {
2260
+ if (this.config.controls && this.launchToken && !this.controls) {
2245
2261
  this.controls = new RecordingControls(this);
2246
2262
  this.controls.mount();
2247
2263
  }
2248
2264
  }
2265
+ async initialize() {
2266
+ this.resolveLaunchToken();
2267
+ if (this.launchToken && !this.config.persistenceKey) {
2268
+ this.config.persistenceKey = this.getOrCreateDraftKey();
2269
+ }
2270
+ await this.initializeDraft();
2271
+ }
2272
+ resolveLaunchToken() {
2273
+ const incomingToken = new URLSearchParams(window.location.search).get("offscript_token")?.trim();
2274
+ const previousToken = this.readSessionValue(TOKEN_STORAGE_KEY);
2275
+ const completedToken = this.readSessionValue(COMPLETED_TOKEN_STORAGE_KEY);
2276
+ const legacyCompletion = completedToken === "1" && Boolean(previousToken);
2277
+ const completedFingerprint = legacyCompletion && previousToken ? tokenFingerprint(previousToken) : completedToken;
2278
+ const candidateToken = incomingToken || previousToken || void 0;
2279
+ this.launchTokenChanged = Boolean(incomingToken && previousToken && incomingToken !== previousToken) || Boolean(incomingToken && completedFingerprint && completedFingerprint !== "1" && tokenFingerprint(incomingToken) !== completedFingerprint);
2280
+ if (this.launchTokenChanged) {
2281
+ this.removeSessionValue(COMPLETED_TOKEN_STORAGE_KEY);
2282
+ }
2283
+ if (legacyCompletion && previousToken && !this.launchTokenChanged) {
2284
+ this.writeSessionValue(COMPLETED_TOKEN_STORAGE_KEY, tokenFingerprint(previousToken));
2285
+ this.removeSessionValue(TOKEN_STORAGE_KEY);
2286
+ }
2287
+ const isCompleted = Boolean(candidateToken && completedFingerprint === tokenFingerprint(candidateToken));
2288
+ this.launchToken = isCompleted ? void 0 : candidateToken;
2289
+ if (incomingToken && !isCompleted) this.writeSessionValue(TOKEN_STORAGE_KEY, incomingToken);
2290
+ }
2291
+ getOrCreateDraftKey() {
2292
+ const saved = this.readSessionValue(DRAFT_STORAGE_KEY);
2293
+ if (saved) return saved;
2294
+ const key = uid("draft_");
2295
+ this.writeSessionValue(DRAFT_STORAGE_KEY, key);
2296
+ return key;
2297
+ }
2298
+ readSessionValue(key) {
2299
+ try {
2300
+ return window.sessionStorage.getItem(key);
2301
+ } catch {
2302
+ return null;
2303
+ }
2304
+ }
2305
+ writeSessionValue(key, value) {
2306
+ try {
2307
+ window.sessionStorage.setItem(key, value);
2308
+ } catch {
2309
+ }
2310
+ }
2311
+ removeSessionValue(key) {
2312
+ try {
2313
+ window.sessionStorage.removeItem(key);
2314
+ } catch {
2315
+ }
2316
+ }
2249
2317
  async initializeDraft() {
2250
2318
  if (!this.config.persistenceKey) return;
2251
2319
  this.store = await RecordingStore.open(this.config.persistenceKey);
2320
+ const startsNewSegment = await this.consumeRecordingSegmentMarker();
2321
+ if (this.launchTokenChanged || startsNewSegment) await this.store.clear();
2252
2322
  await this.restoreDraft();
2323
+ if (startsNewSegment) await this.startFreshRecording();
2324
+ }
2325
+ async consumeRecordingSegmentMarker() {
2326
+ const url = new URL(window.location.href);
2327
+ const marker = url.searchParams.get(RECORDING_SEGMENT_START_QUERY);
2328
+ if (!marker) return false;
2329
+ url.searchParams.delete(RECORDING_SEGMENT_START_QUERY);
2330
+ window.history.replaceState(window.history.state, "", url.href);
2331
+ if (!this.launchToken || !globalThis.crypto?.subtle) return false;
2332
+ let fingerprint;
2333
+ try {
2334
+ const tokenBytes = new TextEncoder().encode(this.launchToken);
2335
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", tokenBytes);
2336
+ fingerprint = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
2337
+ } catch {
2338
+ return false;
2339
+ }
2340
+ return marker === fingerprint;
2253
2341
  }
2254
2342
  async restoreDraft() {
2255
2343
  const saved = await this.store.load();
@@ -2289,6 +2377,9 @@ var Offscript = class {
2289
2377
  }
2290
2378
  async doStart() {
2291
2379
  await this.init();
2380
+ await this.startFreshRecording();
2381
+ }
2382
+ async startFreshRecording() {
2292
2383
  if (this.status === "recording" || this.status === "paused") return;
2293
2384
  if (this.completePromise || this.stopPromise) throw new InvalidStateError("Finaliza\xE7\xE3o em andamento");
2294
2385
  await this.store?.clear();
@@ -2358,7 +2449,7 @@ var Offscript = class {
2358
2449
  this.bus.emit("recordingEnd", this.payload);
2359
2450
  return this.payload;
2360
2451
  }
2361
- complete(options) {
2452
+ complete(options = {}) {
2362
2453
  this.assertAlive();
2363
2454
  if (this.completePromise) return this.completePromise;
2364
2455
  if (this.submitted) return Promise.resolve(this.response);
@@ -2367,19 +2458,27 @@ var Offscript = class {
2367
2458
  });
2368
2459
  return this.completePromise;
2369
2460
  }
2370
- async doComplete({ endpoint, token }) {
2461
+ async doComplete(options) {
2462
+ const endpoint = options.endpoint ?? this.config.endpoint;
2463
+ const token = options.token?.trim() || this.launchToken;
2464
+ if (!endpoint) throw new ConfigError("Endpoint HTTP obrigat\xF3rio para envio");
2465
+ if (!token) throw new ConfigError("Token obrigat\xF3rio para envio");
2371
2466
  const url = new URL(endpoint, location.href);
2372
2467
  if (!["https:", "http:"].includes(url.protocol)) throw new ConfigError("Endpoint HTTP inv\xE1lido");
2373
- if (!token?.trim()) throw new ConfigError("Token obrigat\xF3rio para envio");
2374
2468
  const payload = await this.stopRecording();
2375
2469
  try {
2376
2470
  const response = await fetch(url.href, {
2377
2471
  method: "POST",
2378
- headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: `Bearer ${token.trim()}` },
2472
+ headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: `Bearer ${token}` },
2379
2473
  body: JSON.stringify(payload)
2380
2474
  });
2381
2475
  if (!response.ok) throw new OffscriptError("TRANSPORT_FAILED", `Falha ao enviar grava\xE7\xE3o: HTTP ${response.status}`, { status: response.status });
2382
2476
  this.submitted = true;
2477
+ const completedToken = this.launchToken ?? token;
2478
+ this.writeSessionValue(COMPLETED_TOKEN_STORAGE_KEY, tokenFingerprint(completedToken));
2479
+ this.removeSessionValue(TOKEN_STORAGE_KEY);
2480
+ this.removeSessionValue(DRAFT_STORAGE_KEY);
2481
+ this.launchToken = void 0;
2383
2482
  await this.store?.clear();
2384
2483
  const text = await response.text();
2385
2484
  try {
@@ -2389,6 +2488,8 @@ var Offscript = class {
2389
2488
  }
2390
2489
  this.lastError = void 0;
2391
2490
  this.controls?.showSuccess();
2491
+ this.controls?.unmount();
2492
+ this.controls = void 0;
2392
2493
  return this.response;
2393
2494
  } catch (error) {
2394
2495
  const err = error instanceof Error ? error : new Error(String(error));
@@ -2399,6 +2500,7 @@ var Offscript = class {
2399
2500
  }
2400
2501
  async finishRecording() {
2401
2502
  if (this.config.onComplete) return this.config.onComplete();
2503
+ if (this.launchToken) return this.complete();
2402
2504
  return this.stopRecording();
2403
2505
  }
2404
2506
  async discardRecording() {
@@ -2430,7 +2532,7 @@ var Offscript = class {
2430
2532
  this.destroyed = true;
2431
2533
  }
2432
2534
  exportPlaywrightData() {
2433
- return chunkHPDLEAAL_cjs.buildPlaywrightContract({ actions: this.actionLog, contexts: this.contextLog });
2535
+ return chunkM7CHVDW6_cjs.buildPlaywrightContract({ actions: this.actionLog, contexts: this.contextLog });
2434
2536
  }
2435
2537
  getRecordedActions() {
2436
2538
  return this.actionLog;
@@ -2572,7 +2674,7 @@ var Offscript = class {
2572
2674
  this.bus.emit("statusChange", { from, to });
2573
2675
  }
2574
2676
  };
2575
- Offscript.version = chunkHPDLEAAL_cjs.SDK_VERSION;
2677
+ Offscript.version = chunkM7CHVDW6_cjs.SDK_VERSION;
2576
2678
 
2577
2679
  exports.ConfigError = ConfigError;
2578
2680
  exports.DEFAULT_PRIVACY = DEFAULT_PRIVACY;
@@ -2581,5 +2683,5 @@ exports.DataSanitizer = DataSanitizer;
2581
2683
  exports.InvalidStateError = InvalidStateError;
2582
2684
  exports.Offscript = Offscript;
2583
2685
  exports.OffscriptError = OffscriptError;
2584
- //# sourceMappingURL=chunk-VYCDQLP7.cjs.map
2585
- //# sourceMappingURL=chunk-VYCDQLP7.cjs.map
2686
+ //# sourceMappingURL=chunk-7FCA5EJI.cjs.map
2687
+ //# sourceMappingURL=chunk-7FCA5EJI.cjs.map