@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.
- package/README.md +10 -20
- package/dist/adapters/nuxt.cjs +3 -3
- package/dist/adapters/nuxt.js +2 -2
- package/dist/adapters/vanilla.cjs +5 -5
- package/dist/adapters/vanilla.js +3 -3
- package/dist/adapters/vue.cjs +3 -3
- package/dist/adapters/vue.js +2 -2
- package/dist/{chunk-6ROP37WI.js → chunk-4EPIPNDL.js} +3 -3
- package/dist/{chunk-6ROP37WI.js.map → chunk-4EPIPNDL.js.map} +1 -1
- package/dist/{chunk-VYCDQLP7.cjs → chunk-7FCA5EJI.cjs} +116 -14
- package/dist/chunk-7FCA5EJI.cjs.map +1 -0
- package/dist/{chunk-XBXFGCUT.js → chunk-LUTOFXSV.js} +111 -9
- package/dist/chunk-LUTOFXSV.js.map +1 -0
- package/dist/{chunk-HPDLEAAL.cjs → chunk-M7CHVDW6.cjs} +3 -3
- package/dist/{chunk-HPDLEAAL.cjs.map → chunk-M7CHVDW6.cjs.map} +1 -1
- package/dist/{chunk-2MY2FWIA.cjs → chunk-OXGIMYKL.cjs} +4 -4
- package/dist/{chunk-2MY2FWIA.cjs.map → chunk-OXGIMYKL.cjs.map} +1 -1
- package/dist/{chunk-V2YYWGIA.js → chunk-ZB5N4KJE.js} +3 -3
- package/dist/{chunk-V2YYWGIA.js.map → chunk-ZB5N4KJE.js.map} +1 -1
- package/dist/core/OffscriptSDK.d.ts +12 -2
- package/dist/index.cjs +20 -20
- package/dist/index.js +3 -3
- package/dist/playwright.cjs +13 -13
- package/dist/playwright.js +1 -1
- package/dist/types/config.d.ts +5 -2
- package/dist/types/events.d.ts +1 -1
- package/dist/types/recording.d.ts +2 -2
- package/docs/api-contract.md +1 -1
- package/docs/architecture.md +3 -3
- package/package.json +2 -2
- package/dist/chunk-VYCDQLP7.cjs.map +0 -1
- package/dist/chunk-XBXFGCUT.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildPlaywrightContract, SDK_VERSION, SelectorGenerator, ACTION_SCHEMA_VERSION } from './chunk-
|
|
1
|
+
import { buildPlaywrightContract, SDK_VERSION, SelectorGenerator, ACTION_SCHEMA_VERSION } from './chunk-4EPIPNDL.js';
|
|
2
2
|
|
|
3
3
|
// src/types/config.ts
|
|
4
4
|
var DEFAULT_RECORDING = {
|
|
@@ -1531,6 +1531,7 @@ function resolveConfig(input) {
|
|
|
1531
1531
|
privacy: resolvePrivacy(input.privacy),
|
|
1532
1532
|
correlationWindowMs: input.correlationWindowMs ?? 3e3,
|
|
1533
1533
|
controls: input.controls ?? true,
|
|
1534
|
+
endpoint: input.endpoint,
|
|
1534
1535
|
persistenceKey: input.persistenceKey,
|
|
1535
1536
|
onComplete: input.onComplete
|
|
1536
1537
|
};
|
|
@@ -2209,6 +2210,20 @@ var SUCCESS_TEMPLATE = `
|
|
|
2209
2210
|
`;
|
|
2210
2211
|
|
|
2211
2212
|
// src/core/OffscriptSDK.ts
|
|
2213
|
+
var TOKEN_STORAGE_KEY = "offscript-session-token";
|
|
2214
|
+
var DRAFT_STORAGE_KEY = "offscript-draft-key";
|
|
2215
|
+
var COMPLETED_TOKEN_STORAGE_KEY = "offscript-completed-token";
|
|
2216
|
+
var RECORDING_SEGMENT_START_QUERY = "offscript_recording_start";
|
|
2217
|
+
function tokenFingerprint(token) {
|
|
2218
|
+
let first = 2166136261;
|
|
2219
|
+
let second = 2654435769;
|
|
2220
|
+
for (let index = 0; index < token.length; index++) {
|
|
2221
|
+
const character = token.charCodeAt(index);
|
|
2222
|
+
first = Math.imul(first ^ character, 16777619);
|
|
2223
|
+
second = Math.imul(second ^ character, 2246822519);
|
|
2224
|
+
}
|
|
2225
|
+
return `${first >>> 0}.${second >>> 0}`;
|
|
2226
|
+
}
|
|
2212
2227
|
var Offscript = class {
|
|
2213
2228
|
constructor(config = {}) {
|
|
2214
2229
|
this.bus = new Emitter();
|
|
@@ -2224,6 +2239,7 @@ var Offscript = class {
|
|
|
2224
2239
|
this.sequence = 0;
|
|
2225
2240
|
this.pageId = uid("page_");
|
|
2226
2241
|
this.submitted = false;
|
|
2242
|
+
this.launchTokenChanged = false;
|
|
2227
2243
|
this.config = resolveConfig(config);
|
|
2228
2244
|
this.sanitizer = new DataSanitizer(this.config.privacy);
|
|
2229
2245
|
}
|
|
@@ -2236,18 +2252,90 @@ var Offscript = class {
|
|
|
2236
2252
|
async init() {
|
|
2237
2253
|
this.assertAlive();
|
|
2238
2254
|
if (typeof window === "undefined") throw new OffscriptError("NOT_SUPPORTED", "O SDK requer um navegador");
|
|
2239
|
-
this.initPromise ?? (this.initPromise = this.
|
|
2255
|
+
this.initPromise ?? (this.initPromise = this.initialize());
|
|
2240
2256
|
await this.initPromise;
|
|
2241
2257
|
if (this.restorePromise) await this.restorePromise;
|
|
2242
|
-
if (this.config.controls && !this.controls) {
|
|
2258
|
+
if (this.config.controls && this.launchToken && !this.controls) {
|
|
2243
2259
|
this.controls = new RecordingControls(this);
|
|
2244
2260
|
this.controls.mount();
|
|
2245
2261
|
}
|
|
2246
2262
|
}
|
|
2263
|
+
async initialize() {
|
|
2264
|
+
this.resolveLaunchToken();
|
|
2265
|
+
if (this.launchToken && !this.config.persistenceKey) {
|
|
2266
|
+
this.config.persistenceKey = this.getOrCreateDraftKey();
|
|
2267
|
+
}
|
|
2268
|
+
await this.initializeDraft();
|
|
2269
|
+
}
|
|
2270
|
+
resolveLaunchToken() {
|
|
2271
|
+
const incomingToken = new URLSearchParams(window.location.search).get("offscript_token")?.trim();
|
|
2272
|
+
const previousToken = this.readSessionValue(TOKEN_STORAGE_KEY);
|
|
2273
|
+
const completedToken = this.readSessionValue(COMPLETED_TOKEN_STORAGE_KEY);
|
|
2274
|
+
const legacyCompletion = completedToken === "1" && Boolean(previousToken);
|
|
2275
|
+
const completedFingerprint = legacyCompletion && previousToken ? tokenFingerprint(previousToken) : completedToken;
|
|
2276
|
+
const candidateToken = incomingToken || previousToken || void 0;
|
|
2277
|
+
this.launchTokenChanged = Boolean(incomingToken && previousToken && incomingToken !== previousToken) || Boolean(incomingToken && completedFingerprint && completedFingerprint !== "1" && tokenFingerprint(incomingToken) !== completedFingerprint);
|
|
2278
|
+
if (this.launchTokenChanged) {
|
|
2279
|
+
this.removeSessionValue(COMPLETED_TOKEN_STORAGE_KEY);
|
|
2280
|
+
}
|
|
2281
|
+
if (legacyCompletion && previousToken && !this.launchTokenChanged) {
|
|
2282
|
+
this.writeSessionValue(COMPLETED_TOKEN_STORAGE_KEY, tokenFingerprint(previousToken));
|
|
2283
|
+
this.removeSessionValue(TOKEN_STORAGE_KEY);
|
|
2284
|
+
}
|
|
2285
|
+
const isCompleted = Boolean(candidateToken && completedFingerprint === tokenFingerprint(candidateToken));
|
|
2286
|
+
this.launchToken = isCompleted ? void 0 : candidateToken;
|
|
2287
|
+
if (incomingToken && !isCompleted) this.writeSessionValue(TOKEN_STORAGE_KEY, incomingToken);
|
|
2288
|
+
}
|
|
2289
|
+
getOrCreateDraftKey() {
|
|
2290
|
+
const saved = this.readSessionValue(DRAFT_STORAGE_KEY);
|
|
2291
|
+
if (saved) return saved;
|
|
2292
|
+
const key = uid("draft_");
|
|
2293
|
+
this.writeSessionValue(DRAFT_STORAGE_KEY, key);
|
|
2294
|
+
return key;
|
|
2295
|
+
}
|
|
2296
|
+
readSessionValue(key) {
|
|
2297
|
+
try {
|
|
2298
|
+
return window.sessionStorage.getItem(key);
|
|
2299
|
+
} catch {
|
|
2300
|
+
return null;
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
writeSessionValue(key, value) {
|
|
2304
|
+
try {
|
|
2305
|
+
window.sessionStorage.setItem(key, value);
|
|
2306
|
+
} catch {
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
removeSessionValue(key) {
|
|
2310
|
+
try {
|
|
2311
|
+
window.sessionStorage.removeItem(key);
|
|
2312
|
+
} catch {
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2247
2315
|
async initializeDraft() {
|
|
2248
2316
|
if (!this.config.persistenceKey) return;
|
|
2249
2317
|
this.store = await RecordingStore.open(this.config.persistenceKey);
|
|
2318
|
+
const startsNewSegment = await this.consumeRecordingSegmentMarker();
|
|
2319
|
+
if (this.launchTokenChanged || startsNewSegment) await this.store.clear();
|
|
2250
2320
|
await this.restoreDraft();
|
|
2321
|
+
if (startsNewSegment) await this.startFreshRecording();
|
|
2322
|
+
}
|
|
2323
|
+
async consumeRecordingSegmentMarker() {
|
|
2324
|
+
const url = new URL(window.location.href);
|
|
2325
|
+
const marker = url.searchParams.get(RECORDING_SEGMENT_START_QUERY);
|
|
2326
|
+
if (!marker) return false;
|
|
2327
|
+
url.searchParams.delete(RECORDING_SEGMENT_START_QUERY);
|
|
2328
|
+
window.history.replaceState(window.history.state, "", url.href);
|
|
2329
|
+
if (!this.launchToken || !globalThis.crypto?.subtle) return false;
|
|
2330
|
+
let fingerprint;
|
|
2331
|
+
try {
|
|
2332
|
+
const tokenBytes = new TextEncoder().encode(this.launchToken);
|
|
2333
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", tokenBytes);
|
|
2334
|
+
fingerprint = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
2335
|
+
} catch {
|
|
2336
|
+
return false;
|
|
2337
|
+
}
|
|
2338
|
+
return marker === fingerprint;
|
|
2251
2339
|
}
|
|
2252
2340
|
async restoreDraft() {
|
|
2253
2341
|
const saved = await this.store.load();
|
|
@@ -2287,6 +2375,9 @@ var Offscript = class {
|
|
|
2287
2375
|
}
|
|
2288
2376
|
async doStart() {
|
|
2289
2377
|
await this.init();
|
|
2378
|
+
await this.startFreshRecording();
|
|
2379
|
+
}
|
|
2380
|
+
async startFreshRecording() {
|
|
2290
2381
|
if (this.status === "recording" || this.status === "paused") return;
|
|
2291
2382
|
if (this.completePromise || this.stopPromise) throw new InvalidStateError("Finaliza\xE7\xE3o em andamento");
|
|
2292
2383
|
await this.store?.clear();
|
|
@@ -2356,7 +2447,7 @@ var Offscript = class {
|
|
|
2356
2447
|
this.bus.emit("recordingEnd", this.payload);
|
|
2357
2448
|
return this.payload;
|
|
2358
2449
|
}
|
|
2359
|
-
complete(options) {
|
|
2450
|
+
complete(options = {}) {
|
|
2360
2451
|
this.assertAlive();
|
|
2361
2452
|
if (this.completePromise) return this.completePromise;
|
|
2362
2453
|
if (this.submitted) return Promise.resolve(this.response);
|
|
@@ -2365,19 +2456,27 @@ var Offscript = class {
|
|
|
2365
2456
|
});
|
|
2366
2457
|
return this.completePromise;
|
|
2367
2458
|
}
|
|
2368
|
-
async doComplete(
|
|
2459
|
+
async doComplete(options) {
|
|
2460
|
+
const endpoint = options.endpoint ?? this.config.endpoint;
|
|
2461
|
+
const token = options.token?.trim() || this.launchToken;
|
|
2462
|
+
if (!endpoint) throw new ConfigError("Endpoint HTTP obrigat\xF3rio para envio");
|
|
2463
|
+
if (!token) throw new ConfigError("Token obrigat\xF3rio para envio");
|
|
2369
2464
|
const url = new URL(endpoint, location.href);
|
|
2370
2465
|
if (!["https:", "http:"].includes(url.protocol)) throw new ConfigError("Endpoint HTTP inv\xE1lido");
|
|
2371
|
-
if (!token?.trim()) throw new ConfigError("Token obrigat\xF3rio para envio");
|
|
2372
2466
|
const payload = await this.stopRecording();
|
|
2373
2467
|
try {
|
|
2374
2468
|
const response = await fetch(url.href, {
|
|
2375
2469
|
method: "POST",
|
|
2376
|
-
headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: `Bearer ${token
|
|
2470
|
+
headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: `Bearer ${token}` },
|
|
2377
2471
|
body: JSON.stringify(payload)
|
|
2378
2472
|
});
|
|
2379
2473
|
if (!response.ok) throw new OffscriptError("TRANSPORT_FAILED", `Falha ao enviar grava\xE7\xE3o: HTTP ${response.status}`, { status: response.status });
|
|
2380
2474
|
this.submitted = true;
|
|
2475
|
+
const completedToken = this.launchToken ?? token;
|
|
2476
|
+
this.writeSessionValue(COMPLETED_TOKEN_STORAGE_KEY, tokenFingerprint(completedToken));
|
|
2477
|
+
this.removeSessionValue(TOKEN_STORAGE_KEY);
|
|
2478
|
+
this.removeSessionValue(DRAFT_STORAGE_KEY);
|
|
2479
|
+
this.launchToken = void 0;
|
|
2381
2480
|
await this.store?.clear();
|
|
2382
2481
|
const text = await response.text();
|
|
2383
2482
|
try {
|
|
@@ -2387,6 +2486,8 @@ var Offscript = class {
|
|
|
2387
2486
|
}
|
|
2388
2487
|
this.lastError = void 0;
|
|
2389
2488
|
this.controls?.showSuccess();
|
|
2489
|
+
this.controls?.unmount();
|
|
2490
|
+
this.controls = void 0;
|
|
2390
2491
|
return this.response;
|
|
2391
2492
|
} catch (error) {
|
|
2392
2493
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
@@ -2397,6 +2498,7 @@ var Offscript = class {
|
|
|
2397
2498
|
}
|
|
2398
2499
|
async finishRecording() {
|
|
2399
2500
|
if (this.config.onComplete) return this.config.onComplete();
|
|
2501
|
+
if (this.launchToken) return this.complete();
|
|
2400
2502
|
return this.stopRecording();
|
|
2401
2503
|
}
|
|
2402
2504
|
async discardRecording() {
|
|
@@ -2573,5 +2675,5 @@ var Offscript = class {
|
|
|
2573
2675
|
Offscript.version = SDK_VERSION;
|
|
2574
2676
|
|
|
2575
2677
|
export { ConfigError, DEFAULT_PRIVACY, DEFAULT_RECORDING, DataSanitizer, InvalidStateError, Offscript, OffscriptError };
|
|
2576
|
-
//# sourceMappingURL=chunk-
|
|
2577
|
-
//# sourceMappingURL=chunk-
|
|
2678
|
+
//# sourceMappingURL=chunk-LUTOFXSV.js.map
|
|
2679
|
+
//# sourceMappingURL=chunk-LUTOFXSV.js.map
|