@deflectbot/deflect-sdk 1.4.5 → 1.4.6
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.d.ts +2 -0
- package/dist/index.esm.js +22 -12
- package/dist/index.js +22 -12
- package/dist/index.min.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export declare class DeflectClient {
|
|
|
26
26
|
private isWarmupInProgress;
|
|
27
27
|
private hasWarmupError;
|
|
28
28
|
private warmupPromise;
|
|
29
|
+
private scriptFetchPromise;
|
|
29
30
|
private pulseReporter;
|
|
30
31
|
private getTokenPromise;
|
|
31
32
|
private lastErrorTime;
|
|
@@ -47,6 +48,7 @@ export declare class DeflectClient {
|
|
|
47
48
|
private tryWarmup;
|
|
48
49
|
private validateActionId;
|
|
49
50
|
private prefetchNextScript;
|
|
51
|
+
private fetchScriptOnce;
|
|
50
52
|
private isTestMode;
|
|
51
53
|
/** Get a challenge token for this client's actionId */
|
|
52
54
|
getToken(): Promise<string>;
|
package/dist/index.esm.js
CHANGED
|
@@ -11,6 +11,7 @@ class DeflectClient {
|
|
|
11
11
|
this.isWarmupInProgress = false;
|
|
12
12
|
this.hasWarmupError = false;
|
|
13
13
|
this.warmupPromise = null;
|
|
14
|
+
this.scriptFetchPromise = null;
|
|
14
15
|
// Guards against infinite loading
|
|
15
16
|
this.getTokenPromise = null;
|
|
16
17
|
this.lastErrorTime = 0;
|
|
@@ -93,14 +94,11 @@ class DeflectClient {
|
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
96
|
this.isWarmupInProgress = true;
|
|
96
|
-
this.
|
|
97
|
+
const fetchPromise = this.fetchScriptOnce();
|
|
97
98
|
this.warmupPromise = (async () => {
|
|
98
99
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.config.scriptUrl,
|
|
102
|
-
this.config.extraArgs
|
|
103
|
-
);
|
|
100
|
+
const script = await fetchPromise;
|
|
101
|
+
this.scriptCache = script;
|
|
104
102
|
this.hasWarmupError = false;
|
|
105
103
|
this.recordFetchSuccess();
|
|
106
104
|
} catch {
|
|
@@ -127,6 +125,23 @@ class DeflectClient {
|
|
|
127
125
|
});
|
|
128
126
|
}
|
|
129
127
|
}
|
|
128
|
+
fetchScriptOnce() {
|
|
129
|
+
if (!this.scriptFetchPromise) {
|
|
130
|
+
this.incrementFetchCount();
|
|
131
|
+
this.scriptFetchPromise = fetchScript(
|
|
132
|
+
this.config.actionId,
|
|
133
|
+
this.config.scriptUrl,
|
|
134
|
+
this.config.extraArgs
|
|
135
|
+
).then((script) => {
|
|
136
|
+
this.scriptFetchPromise = null;
|
|
137
|
+
return script;
|
|
138
|
+
}).catch((error) => {
|
|
139
|
+
this.scriptFetchPromise = null;
|
|
140
|
+
throw error;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return this.scriptFetchPromise;
|
|
144
|
+
}
|
|
130
145
|
isTestMode() {
|
|
131
146
|
if (this.config.actionId === "PULSE_TEST" || this.config.actionId === "SENTRY_TEST") {
|
|
132
147
|
throw new Error("PULSE_TEST: This is a test error to verify Pulse integration is working");
|
|
@@ -179,12 +194,7 @@ class DeflectClient {
|
|
|
179
194
|
script = this.scriptCache;
|
|
180
195
|
this.scriptCache = null;
|
|
181
196
|
} else {
|
|
182
|
-
this.
|
|
183
|
-
script = await fetchScript(
|
|
184
|
-
this.config.actionId,
|
|
185
|
-
this.config.scriptUrl,
|
|
186
|
-
this.config.extraArgs
|
|
187
|
-
);
|
|
197
|
+
script = await this.fetchScriptOnce();
|
|
188
198
|
}
|
|
189
199
|
return this.executeScript(script);
|
|
190
200
|
} catch (error) {
|
package/dist/index.js
CHANGED
|
@@ -255,6 +255,7 @@
|
|
|
255
255
|
this.isWarmupInProgress = false;
|
|
256
256
|
this.hasWarmupError = false;
|
|
257
257
|
this.warmupPromise = null;
|
|
258
|
+
this.scriptFetchPromise = null;
|
|
258
259
|
// Guards against infinite loading
|
|
259
260
|
this.getTokenPromise = null;
|
|
260
261
|
this.lastErrorTime = 0;
|
|
@@ -340,14 +341,11 @@
|
|
|
340
341
|
return;
|
|
341
342
|
}
|
|
342
343
|
this.isWarmupInProgress = true;
|
|
343
|
-
this.
|
|
344
|
+
const fetchPromise = this.fetchScriptOnce();
|
|
344
345
|
this.warmupPromise = (async () => {
|
|
345
346
|
try {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
this.config.scriptUrl,
|
|
349
|
-
this.config.extraArgs
|
|
350
|
-
);
|
|
347
|
+
const script = await fetchPromise;
|
|
348
|
+
this.scriptCache = script;
|
|
351
349
|
this.hasWarmupError = false;
|
|
352
350
|
this.recordFetchSuccess();
|
|
353
351
|
} catch {
|
|
@@ -374,6 +372,23 @@
|
|
|
374
372
|
});
|
|
375
373
|
}
|
|
376
374
|
}
|
|
375
|
+
fetchScriptOnce() {
|
|
376
|
+
if (!this.scriptFetchPromise) {
|
|
377
|
+
this.incrementFetchCount();
|
|
378
|
+
this.scriptFetchPromise = fetchScript(
|
|
379
|
+
this.config.actionId,
|
|
380
|
+
this.config.scriptUrl,
|
|
381
|
+
this.config.extraArgs
|
|
382
|
+
).then((script) => {
|
|
383
|
+
this.scriptFetchPromise = null;
|
|
384
|
+
return script;
|
|
385
|
+
}).catch((error) => {
|
|
386
|
+
this.scriptFetchPromise = null;
|
|
387
|
+
throw error;
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
return this.scriptFetchPromise;
|
|
391
|
+
}
|
|
377
392
|
isTestMode() {
|
|
378
393
|
if (this.config.actionId === "PULSE_TEST" || this.config.actionId === "SENTRY_TEST") {
|
|
379
394
|
throw new Error("PULSE_TEST: This is a test error to verify Pulse integration is working");
|
|
@@ -426,12 +441,7 @@
|
|
|
426
441
|
script = this.scriptCache;
|
|
427
442
|
this.scriptCache = null;
|
|
428
443
|
} else {
|
|
429
|
-
this.
|
|
430
|
-
script = await fetchScript(
|
|
431
|
-
this.config.actionId,
|
|
432
|
-
this.config.scriptUrl,
|
|
433
|
-
this.config.extraArgs
|
|
434
|
-
);
|
|
444
|
+
script = await this.fetchScriptOnce();
|
|
435
445
|
}
|
|
436
446
|
return this.executeScript(script);
|
|
437
447
|
} catch (error) {
|
package/dist/index.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use strict";(()=>{var p={endpoint:"https://service.yabadabado.top/pulse",projectId:"deflect-sdk",deploymentId:"688529b539803661332b3f70",service:"deflect-sdk",release:"unknown"},k={name:"deflect-js-sdk",version:p.release||"unknown",language:"javascript"},m=class{constructor(e){this.config={...p,...e,endpoint:(e?.endpoint||p.endpoint).replace(/\/$/,"")},this.enabled=!!(this.config.endpoint&&this.config.projectId&&this.config.deploymentId)}captureException(e,t={}){if(!this.enabled||typeof fetch!="function")return;let r=this.buildErrorEvent(e,t);fetch(`${this.config.endpoint}/capture`,{method:"POST",headers:{"Content-Type":"application/json",project_id:this.config.projectId},body:JSON.stringify(r),keepalive:!0}).catch(()=>{})}buildErrorEvent(e,t){let r=this.normalizeError(e),i=this.config.environment||typeof window<"u"&&window.location.hostname||"unknown",o=typeof navigator>"u"?void 0:{name:navigator.userAgent||"browser",version:navigator.appVersion},s=typeof navigator>"u"?void 0:{name:navigator.platform},a=typeof window>"u"?void 0:{model:`${window.screen.width}x${window.screen.height}`,arch:typeof navigator<"u"?navigator.platform:void 0},b=typeof window>"u"?void 0:{method:"GET",url:window.location.href,headers:typeof navigator<"u"?{"User-Agent":navigator.userAgent,...typeof document<"u"&&document.referrer?{Referer:document.referrer}:{}}:void 0};return{event_type:"error",event_id:typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():Math.random().toString(16).slice(2)+Date.now().toString(16),deployment_id:this.config.deploymentId,project_id:this.config.projectId,environment:i,service:this.config.service,timestamp:new Date().toISOString(),release:this.config.release,sdk:{...k,version:this.config.release||k.version},tags:t.tags,context:t.context,error:{level:t.level||"error",message:r.message,exception:this.buildExceptionPayload(r),request:b,runtime:o,os:s,device:a}}}normalizeError(e){if(e instanceof Error)return e;let t=typeof e=="string"?e:"Unknown error";return new Error(t)}buildExceptionPayload(e){let t=this.parseStack(e);return{type:e.name||"Error",value:e.message,stacktrace:t.length?{frames:t}:void 0}}parseStack(e){if(!e.stack)return[];let t=[],r=e.stack.split(`
|
|
2
|
-
`).slice(1);for(let i of r){let o=i.trim().replace(/^at\s+/,""),s=o.includes("(")&&o.endsWith(")"),a=s?o.slice(0,o.indexOf("(")).trim():"",c=(s?o.slice(o.indexOf("(")+1,o.length-1):o).split(":"),u=c[0]||void 0,S=c.length>1?Number(c[1]):void 0,T=c.length>2?Number(c[2]):void 0;u&&t.push({filename:u,abs_path:u,function:a||void 0,lineno:Number.isFinite(S)?S:void 0,colno:Number.isFinite(T)?T:void 0,in_app:!u.includes("node_modules")})}return t}},g=m;function x(n,e,t){let r=e||"https://js.deflect.bot/main.js",i=new URL(r),o=i.searchParams;if(o.set("action_id",n),o.set("_",Date.now().toString()),t&&typeof t=="object"){for(let s in t)if(Object.prototype.hasOwnProperty.call(t,s)){let a=t[s];o.set(s,String(a))}}return i.toString()}async function l(n,e,t){let r=x(n,e,t),i=await fetch(r,{cache:"no-store",mode:"cors",credentials:"omit"}),o=await i.text(),s=_(o);if(s)throw s;return{content:o,sessionId:i.headers.get("session_id")||void 0}}function _(n){try{let e=JSON.parse(n);if(e.success===!1||e.error){let t=e.error||"Script fetch failed",r=new Error(t);return(t==="action_does_not_exist"||t.includes("invalid action"))&&(r.isUserError=!0),r}}catch(e){if(!(e instanceof SyntaxError))throw e}return null}function w(n){let e=new Blob([n],{type:"text/javascript"});return URL.createObjectURL(e)}function E(n){return new Promise((e,t)=>{let r=document.createElement("script");r.type="module",r.src=n,r.onload=()=>e(r),r.onerror=()=>t(new Error("Script failed to load")),document.head.appendChild(r)})}function v(n,e=1e4){return new Promise((t,r)=>{let i=setInterval(()=>{typeof window<"u"&&typeof window.Deflect?.[n]=="function"&&(clearInterval(i),t())},50);setTimeout(()=>{clearInterval(i),r(new Error(`Timeout: ${n} did not become available within ${e/1e3} seconds`))},e)})}async function I(n){if(typeof window>"u"||typeof window.Deflect?.[n]!="function")throw new Error(`${n} not available on window.Deflect`);return window.Deflect[n]()}function y(n,e,t){URL.revokeObjectURL(n),e.remove(),typeof window<"u"&&window.Deflect?.[t]&&delete window.Deflect[t]}var d=2e3,F=5,h=15,f=6e4,C=class n{constructor(e,t){this.scriptCache=null;this.isWarmupInProgress=!1;this.hasWarmupError=!1;this.warmupPromise=null;this.getTokenPromise=null;this.lastErrorTime=0;this.consecutiveErrorCount=0;this.fetchCountInWindow=0;this.fetchWindowStart=0;if(!e.actionId?.trim())throw new Error("actionId is required and cannot be empty");this.validateActionId(e.actionId),this.config={prefetch:!0,...e},this.pulseReporter=t||new g(n.resolvePulseConfig()),this.config.prefetch!==!1&&!this.isTestMode()&&this.scheduleWarmup()}getActionId(){return this.config.actionId}scheduleWarmup(){typeof window>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>this.tryWarmup(),{once:!0}):setTimeout(()=>this.tryWarmup(),100))}static resolvePulseConfig(){let e=typeof window<"u"&&typeof window.Deflect=="object"&&window.Deflect?.pulseConfig&&typeof window.Deflect.pulseConfig=="object"?window.Deflect.pulseConfig:{};return{...e,environment:e.environment||(typeof window<"u"?window.location.hostname:void 0)}}reportError(e,t,r){this.pulseReporter.captureException(e,{tags:t,context:r})}isInErrorCooldown(){if(this.consecutiveErrorCount===0)return!1;let e=Math.min(d*Math.pow(2,this.consecutiveErrorCount-1),3e4);return Date.now()-this.lastErrorTime<e}isRateLimited(){let e=Date.now();return e-this.fetchWindowStart>f?(this.fetchCountInWindow=0,this.fetchWindowStart=e,!1):this.fetchCountInWindow>=h}hasExceededMaxErrors(){return this.consecutiveErrorCount>=F}recordFetchSuccess(){this.consecutiveErrorCount=0,this.lastErrorTime=0}recordFetchError(){this.consecutiveErrorCount++,this.lastErrorTime=Date.now()}incrementFetchCount(){let e=Date.now();e-this.fetchWindowStart>f&&(this.fetchCountInWindow=0,this.fetchWindowStart=e),this.fetchCountInWindow++}async tryWarmup(){this.config.prefetch===!1||this.isWarmupInProgress||this.scriptCache||this.hasWarmupError||this.isRateLimited()||this.isInErrorCooldown()||this.hasExceededMaxErrors()||(this.isWarmupInProgress=!0,this.incrementFetchCount(),this.warmupPromise=(async()=>{try{this.scriptCache=await l(this.config.actionId,this.config.scriptUrl,this.config.extraArgs),this.hasWarmupError=!1,this.recordFetchSuccess()}catch{this.hasWarmupError=!0,this.recordFetchError()}finally{this.isWarmupInProgress=!1}})(),await this.warmupPromise.catch(()=>{}))}validateActionId(e){let t=e.trim();if(!/^[a-zA-Z0-9/_-]+$/.test(t))throw new Error("Invalid actionId format: contains disallowed characters");return encodeURIComponent(t)}prefetchNextScript(){!this.hasWarmupError&&this.config.prefetch!==!1&&this.tryWarmup().catch(()=>{})}isTestMode(){if(this.config.actionId==="PULSE_TEST"||this.config.actionId==="SENTRY_TEST")throw new Error("PULSE_TEST: This is a test error to verify Pulse integration is working");return this.config.actionId==="t/FFFFFFFFFFFFF/111111111"||this.config.actionId==="t/FFFFFFFFFFFFF/000000000"}async getToken(){if(this.getTokenPromise)return this.getTokenPromise;this.getTokenPromise=this.getTokenInternal();try{return await this.getTokenPromise}finally{this.getTokenPromise=null}}async getTokenInternal(){try{if(this.isTestMode())return"TESTTOKEN";if(this.hasExceededMaxErrors())throw new Error(`Too many consecutive errors (${this.consecutiveErrorCount}). Create a new client or wait before retrying.`);if(this.isRateLimited())throw new Error(`Rate limit exceeded: ${h} requests per minute. Please wait before retrying.`);if(this.isInErrorCooldown()){let r=Math.min(d*Math.pow(2,this.consecutiveErrorCount-1),3e4)-(Date.now()-this.lastErrorTime);throw new Error(`In error cooldown. Please wait ${Math.ceil(r/1e3)} seconds before retrying.`)}let e;return this.warmupPromise&&await this.warmupPromise.catch(()=>{}),this.scriptCache&&!this.isWarmupInProgress?(e=this.scriptCache,this.scriptCache=null):(this.incrementFetchCount(),e=await l(this.config.actionId,this.config.scriptUrl,this.config.extraArgs)),this.executeScript(e)}catch(e){let t=e instanceof Error?e.message:"";t.includes("cooldown")||t.includes("Rate limit")||t.includes("Too many consecutive")||this.recordFetchError();let i=e&&typeof e=="object"&&"isUserError"in e&&e.isUserError===!0;throw this.reportError(e,{deflect_sdk_error:"true",deflect_user_error:i?"true":"false",method:"getToken",action_id:this.config.actionId,has_cache:this.scriptCache!==null?"true":"false",has_warmup_error:this.hasWarmupError?"true":"false",consecutive_errors:this.consecutiveErrorCount.toString(),stage:"call"},{actionId:this.config.actionId,hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError,consecutiveErrorCount:this.consecutiveErrorCount,fetchCountInWindow:this.fetchCountInWindow}),e}}async executeScript(e){e.sessionId&&typeof window<"u"&&(window.Deflect=window.Deflect||{},window.Deflect.sessionId=e.sessionId);let t=w(e.content),r=null;try{r=await E(t),await v("getChallengeToken");let i=await I("getChallengeToken");return this.recordFetchSuccess(),this.prefetchNextScript(),i}catch(i){throw this.reportError(i,{deflect_sdk_error:"true",method:"executeScript",stage:"load_or_execute",action_id:this.config.actionId},{hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError}),i}finally{r?y(t,r,"getChallengeToken"):URL.revokeObjectURL(t)}}async warmup(){try{return this.config.prefetch===!1?!1:(await this.tryWarmup(),this.scriptCache!==null)}catch{return!1}}clearCache(){this.scriptCache=null}resetErrorState(){this.hasWarmupError=!1,this.consecutiveErrorCount=0,this.lastErrorTime=0,this.getTokenPromise=null}getStatus(){return{actionId:this.config.actionId,isRateLimited:this.isRateLimited(),isInCooldown:this.isInErrorCooldown(),consecutiveErrors:this.consecutiveErrorCount,fetchesInWindow:this.fetchCountInWindow,canFetch:!this.isRateLimited()&&!this.isInErrorCooldown()&&!this.hasExceededMaxErrors()}}async injectToken(e){if(!e||!e.target||!(e.target instanceof HTMLFormElement))throw new Error("injectToken: must be called from a form submit event");e.preventDefault();let t=e.target,r=await this.getToken();Array.from(t.querySelectorAll('input[name="deflect_token"]')).forEach(o=>o.remove());let i=document.createElement("input");i.type="hidden",i.name="deflect_token",i.value=r,t.appendChild(i),t.submit()}},P=class{constructor(){this.config=null;this.scriptCache=null;this.isWarmupInProgress=!1;this.hasWarmupError=!1;this.warmupPromise=null;this.getTokenPromise=null;this.lastErrorTime=0;this.consecutiveErrorCount=0;this.fetchCountInWindow=0;this.fetchWindowStart=0;this.initializeGlobalState(),this.pulseReporter=new g(this.resolvePulseConfig()),this.setupAutomaticWarmup()}initializeGlobalState(){typeof window>"u"||(window.Deflect=window.Deflect||{})}setupAutomaticWarmup(){typeof window>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>this.tryWarmup()):setTimeout(()=>this.tryWarmup(),100))}resolvePulseConfig(){let e=typeof window<"u"&&typeof window.Deflect=="object"&&window.Deflect?.pulseConfig&&typeof window.Deflect.pulseConfig=="object"?window.Deflect.pulseConfig:{};return{...e,environment:e.environment||(typeof window<"u"?window.location.hostname:void 0)}}reportError(e,t,r){this.pulseReporter.captureException(e,{tags:t,context:r})}isInErrorCooldown(){if(this.consecutiveErrorCount===0)return!1;let e=Math.min(d*Math.pow(2,this.consecutiveErrorCount-1),3e4);return Date.now()-this.lastErrorTime<e}isRateLimited(){let e=Date.now();return e-this.fetchWindowStart>f?(this.fetchCountInWindow=0,this.fetchWindowStart=e,!1):this.fetchCountInWindow>=h}hasExceededMaxErrors(){return this.consecutiveErrorCount>=F}recordFetchSuccess(){this.consecutiveErrorCount=0,this.lastErrorTime=0}recordFetchError(){this.consecutiveErrorCount++,this.lastErrorTime=Date.now()}incrementFetchCount(){let e=Date.now();e-this.fetchWindowStart>f&&(this.fetchCountInWindow=0,this.fetchWindowStart=e),this.fetchCountInWindow++}async tryWarmup(){!this.config?.actionId||this.config.prefetch===!1||this.isWarmupInProgress||this.scriptCache||this.hasWarmupError||this.isRateLimited()||this.isInErrorCooldown()||this.hasExceededMaxErrors()||(this.validateActionId(this.config.actionId),this.isWarmupInProgress=!0,this.incrementFetchCount(),this.warmupPromise=(async()=>{try{this.scriptCache=await l(this.config.actionId,this.config.scriptUrl,this.config.extraArgs),this.hasWarmupError=!1,this.recordFetchSuccess()}catch{this.hasWarmupError=!0,this.recordFetchError()}finally{this.isWarmupInProgress=!1}})(),await this.warmupPromise.catch(()=>{}))}validateActionId(e){let t=e.trim();if(!/^[a-zA-Z0-9/_-]+$/.test(t))throw new Error("Invalid actionId format: contains disallowed characters");return encodeURIComponent(t)}prefetchNextScript(){!this.hasWarmupError&&this.config?.prefetch!==!1&&this.tryWarmup().catch(()=>{})}isTestMode(){if(this.config?.actionId==="PULSE_TEST"||this.config?.actionId==="SENTRY_TEST")throw new Error("PULSE_TEST: This is a test error to verify Pulse integration is working");return this.config?.actionId==="t/FFFFFFFFFFFFF/111111111"||this.config?.actionId==="t/FFFFFFFFFFFFF/000000000"}configure(e){try{if(!e.actionId?.trim())throw new Error("actionId is required and cannot be empty");if(this.validateActionId(e.actionId),this.config?.actionId===e.actionId&&this.config.prefetch===e.prefetch&&this.config.scriptUrl===e.scriptUrl)return;this.config?.actionId!==e.actionId&&(this.hasWarmupError=!1,this.consecutiveErrorCount=0,this.lastErrorTime=0),this.scriptCache=null,this.getTokenPromise=null,this.config={prefetch:!0,...e},typeof window<"u"&&(window.Deflect.actionId=e.actionId),!this.isTestMode()&&this.config.prefetch!==!1&&this.tryWarmup()}catch(t){let r=t&&typeof t=="object"&&"isUserError"in t&&t.isUserError===!0;throw this.reportError(t,{deflect_sdk_error:"true",deflect_user_error:r?"true":"false",method:"configure",action_id:e?.actionId||"unknown"},{actionId:e?.actionId,hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError}),t}}async getToken(){if(this.getTokenPromise)return this.getTokenPromise;this.getTokenPromise=this.getTokenInternal();try{return await this.getTokenPromise}finally{this.getTokenPromise=null}}async getTokenInternal(){try{if(!this.config?.actionId)throw new Error("Must call configure() before getToken()");if(this.validateActionId(this.config.actionId),this.isTestMode())return"TESTTOKEN";if(this.hasExceededMaxErrors())throw new Error(`Too many consecutive errors (${this.consecutiveErrorCount}). Call configure() with a new actionId or wait before retrying.`);if(this.isRateLimited())throw new Error(`Rate limit exceeded: ${h} requests per minute. Please wait before retrying.`);if(this.isInErrorCooldown()){let r=Math.min(d*Math.pow(2,this.consecutiveErrorCount-1),3e4)-(Date.now()-this.lastErrorTime);throw new Error(`In error cooldown. Please wait ${Math.ceil(r/1e3)} seconds before retrying.`)}let e;return this.warmupPromise&&await this.warmupPromise.catch(()=>{}),this.scriptCache&&!this.isWarmupInProgress?(e=this.scriptCache,this.scriptCache=null):(this.incrementFetchCount(),e=await l(this.config.actionId,this.config.scriptUrl,this.config.extraArgs)),this.executeScript(e)}catch(e){let t=e instanceof Error?e.message:"";t.includes("cooldown")||t.includes("Rate limit")||t.includes("Too many consecutive")||this.recordFetchError();let i=e&&typeof e=="object"&&"isUserError"in e&&e.isUserError===!0;throw this.reportError(e,{deflect_sdk_error:"true",deflect_user_error:i?"true":"false",method:"getToken",action_id:this.config?.actionId||"unknown",has_cache:this.scriptCache!==null?"true":"false",has_warmup_error:this.hasWarmupError?"true":"false",consecutive_errors:this.consecutiveErrorCount.toString(),stage:"call"},{actionId:this.config?.actionId,hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError,consecutiveErrorCount:this.consecutiveErrorCount,fetchCountInWindow:this.fetchCountInWindow}),e}}async executeScript(e){e.sessionId&&typeof window<"u"&&(window.Deflect.sessionId=e.sessionId);let t=w(e.content),r=null;try{r=await E(t),await v("getChallengeToken");let i=await I("getChallengeToken");return this.recordFetchSuccess(),this.prefetchNextScript(),i}catch(i){throw this.reportError(i,{deflect_sdk_error:"true",method:"executeScript",stage:"load_or_execute",action_id:this.config?.actionId||"unknown"},{hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError}),i}finally{r?y(t,r,"getChallengeToken"):URL.revokeObjectURL(t)}}async warmup(){if(!this.config?.actionId)return!1;try{return this.config.prefetch===!1?!1:(await this.tryWarmup(),this.scriptCache!==null)}catch{return!1}}clearCache(){this.scriptCache=null}resetErrorState(){this.hasWarmupError=!1,this.consecutiveErrorCount=0,this.lastErrorTime=0,this.getTokenPromise=null}getStatus(){return{isRateLimited:this.isRateLimited(),isInCooldown:this.isInErrorCooldown(),consecutiveErrors:this.consecutiveErrorCount,fetchesInWindow:this.fetchCountInWindow,canFetch:!this.isRateLimited()&&!this.isInErrorCooldown()&&!this.hasExceededMaxErrors()}}async injectToken(e){if(!e||!e.target||!(e.target instanceof HTMLFormElement))throw new Error("injectToken: must be called from a form submit event");e.preventDefault();let t=e.target,r=await this.getToken();Array.from(t.querySelectorAll('input[name="deflect_token"]')).forEach(o=>o.remove());let i=document.createElement("input");i.type="hidden",i.name="deflect_token",i.value=r,t.appendChild(i),t.submit()}createClient(e){return new C(e,this.pulseReporter)}},W=new P;typeof window<"u"&&(window.Deflect=W);var $=W;})();
|
|
2
|
+
`).slice(1);for(let i of r){let o=i.trim().replace(/^at\s+/,""),s=o.includes("(")&&o.endsWith(")"),a=s?o.slice(0,o.indexOf("(")).trim():"",c=(s?o.slice(o.indexOf("(")+1,o.length-1):o).split(":"),l=c[0]||void 0,S=c.length>1?Number(c[1]):void 0,T=c.length>2?Number(c[2]):void 0;l&&t.push({filename:l,abs_path:l,function:a||void 0,lineno:Number.isFinite(S)?S:void 0,colno:Number.isFinite(T)?T:void 0,in_app:!l.includes("node_modules")})}return t}},g=m;function x(n,e,t){let r=e||"https://js.deflect.bot/main.js",i=new URL(r),o=i.searchParams;if(o.set("action_id",n),o.set("_",Date.now().toString()),t&&typeof t=="object"){for(let s in t)if(Object.prototype.hasOwnProperty.call(t,s)){let a=t[s];o.set(s,String(a))}}return i.toString()}async function u(n,e,t){let r=x(n,e,t),i=await fetch(r,{cache:"no-store",mode:"cors",credentials:"omit"}),o=await i.text(),s=_(o);if(s)throw s;return{content:o,sessionId:i.headers.get("session_id")||void 0}}function _(n){try{let e=JSON.parse(n);if(e.success===!1||e.error){let t=e.error||"Script fetch failed",r=new Error(t);return(t==="action_does_not_exist"||t.includes("invalid action"))&&(r.isUserError=!0),r}}catch(e){if(!(e instanceof SyntaxError))throw e}return null}function w(n){let e=new Blob([n],{type:"text/javascript"});return URL.createObjectURL(e)}function E(n){return new Promise((e,t)=>{let r=document.createElement("script");r.type="module",r.src=n,r.onload=()=>e(r),r.onerror=()=>t(new Error("Script failed to load")),document.head.appendChild(r)})}function v(n,e=1e4){return new Promise((t,r)=>{let i=setInterval(()=>{typeof window<"u"&&typeof window.Deflect?.[n]=="function"&&(clearInterval(i),t())},50);setTimeout(()=>{clearInterval(i),r(new Error(`Timeout: ${n} did not become available within ${e/1e3} seconds`))},e)})}async function I(n){if(typeof window>"u"||typeof window.Deflect?.[n]!="function")throw new Error(`${n} not available on window.Deflect`);return window.Deflect[n]()}function y(n,e,t){URL.revokeObjectURL(n),e.remove(),typeof window<"u"&&window.Deflect?.[t]&&delete window.Deflect[t]}var d=2e3,F=5,h=15,f=6e4,C=class n{constructor(e,t){this.scriptCache=null;this.isWarmupInProgress=!1;this.hasWarmupError=!1;this.warmupPromise=null;this.scriptFetchPromise=null;this.getTokenPromise=null;this.lastErrorTime=0;this.consecutiveErrorCount=0;this.fetchCountInWindow=0;this.fetchWindowStart=0;if(!e.actionId?.trim())throw new Error("actionId is required and cannot be empty");this.validateActionId(e.actionId),this.config={prefetch:!0,...e},this.pulseReporter=t||new g(n.resolvePulseConfig()),this.config.prefetch!==!1&&!this.isTestMode()&&this.scheduleWarmup()}getActionId(){return this.config.actionId}scheduleWarmup(){typeof window>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>this.tryWarmup(),{once:!0}):setTimeout(()=>this.tryWarmup(),100))}static resolvePulseConfig(){let e=typeof window<"u"&&typeof window.Deflect=="object"&&window.Deflect?.pulseConfig&&typeof window.Deflect.pulseConfig=="object"?window.Deflect.pulseConfig:{};return{...e,environment:e.environment||(typeof window<"u"?window.location.hostname:void 0)}}reportError(e,t,r){this.pulseReporter.captureException(e,{tags:t,context:r})}isInErrorCooldown(){if(this.consecutiveErrorCount===0)return!1;let e=Math.min(d*Math.pow(2,this.consecutiveErrorCount-1),3e4);return Date.now()-this.lastErrorTime<e}isRateLimited(){let e=Date.now();return e-this.fetchWindowStart>f?(this.fetchCountInWindow=0,this.fetchWindowStart=e,!1):this.fetchCountInWindow>=h}hasExceededMaxErrors(){return this.consecutiveErrorCount>=F}recordFetchSuccess(){this.consecutiveErrorCount=0,this.lastErrorTime=0}recordFetchError(){this.consecutiveErrorCount++,this.lastErrorTime=Date.now()}incrementFetchCount(){let e=Date.now();e-this.fetchWindowStart>f&&(this.fetchCountInWindow=0,this.fetchWindowStart=e),this.fetchCountInWindow++}async tryWarmup(){if(this.config.prefetch===!1||this.isWarmupInProgress||this.scriptCache||this.hasWarmupError||this.isRateLimited()||this.isInErrorCooldown()||this.hasExceededMaxErrors())return;this.isWarmupInProgress=!0;let e=this.fetchScriptOnce();this.warmupPromise=(async()=>{try{let t=await e;this.scriptCache=t,this.hasWarmupError=!1,this.recordFetchSuccess()}catch{this.hasWarmupError=!0,this.recordFetchError()}finally{this.isWarmupInProgress=!1}})(),await this.warmupPromise.catch(()=>{})}validateActionId(e){let t=e.trim();if(!/^[a-zA-Z0-9/_-]+$/.test(t))throw new Error("Invalid actionId format: contains disallowed characters");return encodeURIComponent(t)}prefetchNextScript(){!this.hasWarmupError&&this.config.prefetch!==!1&&this.tryWarmup().catch(()=>{})}fetchScriptOnce(){return this.scriptFetchPromise||(this.incrementFetchCount(),this.scriptFetchPromise=u(this.config.actionId,this.config.scriptUrl,this.config.extraArgs).then(e=>(this.scriptFetchPromise=null,e)).catch(e=>{throw this.scriptFetchPromise=null,e})),this.scriptFetchPromise}isTestMode(){if(this.config.actionId==="PULSE_TEST"||this.config.actionId==="SENTRY_TEST")throw new Error("PULSE_TEST: This is a test error to verify Pulse integration is working");return this.config.actionId==="t/FFFFFFFFFFFFF/111111111"||this.config.actionId==="t/FFFFFFFFFFFFF/000000000"}async getToken(){if(this.getTokenPromise)return this.getTokenPromise;this.getTokenPromise=this.getTokenInternal();try{return await this.getTokenPromise}finally{this.getTokenPromise=null}}async getTokenInternal(){try{if(this.isTestMode())return"TESTTOKEN";if(this.hasExceededMaxErrors())throw new Error(`Too many consecutive errors (${this.consecutiveErrorCount}). Create a new client or wait before retrying.`);if(this.isRateLimited())throw new Error(`Rate limit exceeded: ${h} requests per minute. Please wait before retrying.`);if(this.isInErrorCooldown()){let r=Math.min(d*Math.pow(2,this.consecutiveErrorCount-1),3e4)-(Date.now()-this.lastErrorTime);throw new Error(`In error cooldown. Please wait ${Math.ceil(r/1e3)} seconds before retrying.`)}let e;return this.warmupPromise&&await this.warmupPromise.catch(()=>{}),this.scriptCache&&!this.isWarmupInProgress?(e=this.scriptCache,this.scriptCache=null):e=await this.fetchScriptOnce(),this.executeScript(e)}catch(e){let t=e instanceof Error?e.message:"";t.includes("cooldown")||t.includes("Rate limit")||t.includes("Too many consecutive")||this.recordFetchError();let i=e&&typeof e=="object"&&"isUserError"in e&&e.isUserError===!0;throw this.reportError(e,{deflect_sdk_error:"true",deflect_user_error:i?"true":"false",method:"getToken",action_id:this.config.actionId,has_cache:this.scriptCache!==null?"true":"false",has_warmup_error:this.hasWarmupError?"true":"false",consecutive_errors:this.consecutiveErrorCount.toString(),stage:"call"},{actionId:this.config.actionId,hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError,consecutiveErrorCount:this.consecutiveErrorCount,fetchCountInWindow:this.fetchCountInWindow}),e}}async executeScript(e){e.sessionId&&typeof window<"u"&&(window.Deflect=window.Deflect||{},window.Deflect.sessionId=e.sessionId);let t=w(e.content),r=null;try{r=await E(t),await v("getChallengeToken");let i=await I("getChallengeToken");return this.recordFetchSuccess(),this.prefetchNextScript(),i}catch(i){throw this.reportError(i,{deflect_sdk_error:"true",method:"executeScript",stage:"load_or_execute",action_id:this.config.actionId},{hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError}),i}finally{r?y(t,r,"getChallengeToken"):URL.revokeObjectURL(t)}}async warmup(){try{return this.config.prefetch===!1?!1:(await this.tryWarmup(),this.scriptCache!==null)}catch{return!1}}clearCache(){this.scriptCache=null}resetErrorState(){this.hasWarmupError=!1,this.consecutiveErrorCount=0,this.lastErrorTime=0,this.getTokenPromise=null}getStatus(){return{actionId:this.config.actionId,isRateLimited:this.isRateLimited(),isInCooldown:this.isInErrorCooldown(),consecutiveErrors:this.consecutiveErrorCount,fetchesInWindow:this.fetchCountInWindow,canFetch:!this.isRateLimited()&&!this.isInErrorCooldown()&&!this.hasExceededMaxErrors()}}async injectToken(e){if(!e||!e.target||!(e.target instanceof HTMLFormElement))throw new Error("injectToken: must be called from a form submit event");e.preventDefault();let t=e.target,r=await this.getToken();Array.from(t.querySelectorAll('input[name="deflect_token"]')).forEach(o=>o.remove());let i=document.createElement("input");i.type="hidden",i.name="deflect_token",i.value=r,t.appendChild(i),t.submit()}},P=class{constructor(){this.config=null;this.scriptCache=null;this.isWarmupInProgress=!1;this.hasWarmupError=!1;this.warmupPromise=null;this.getTokenPromise=null;this.lastErrorTime=0;this.consecutiveErrorCount=0;this.fetchCountInWindow=0;this.fetchWindowStart=0;this.initializeGlobalState(),this.pulseReporter=new g(this.resolvePulseConfig()),this.setupAutomaticWarmup()}initializeGlobalState(){typeof window>"u"||(window.Deflect=window.Deflect||{})}setupAutomaticWarmup(){typeof window>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>this.tryWarmup()):setTimeout(()=>this.tryWarmup(),100))}resolvePulseConfig(){let e=typeof window<"u"&&typeof window.Deflect=="object"&&window.Deflect?.pulseConfig&&typeof window.Deflect.pulseConfig=="object"?window.Deflect.pulseConfig:{};return{...e,environment:e.environment||(typeof window<"u"?window.location.hostname:void 0)}}reportError(e,t,r){this.pulseReporter.captureException(e,{tags:t,context:r})}isInErrorCooldown(){if(this.consecutiveErrorCount===0)return!1;let e=Math.min(d*Math.pow(2,this.consecutiveErrorCount-1),3e4);return Date.now()-this.lastErrorTime<e}isRateLimited(){let e=Date.now();return e-this.fetchWindowStart>f?(this.fetchCountInWindow=0,this.fetchWindowStart=e,!1):this.fetchCountInWindow>=h}hasExceededMaxErrors(){return this.consecutiveErrorCount>=F}recordFetchSuccess(){this.consecutiveErrorCount=0,this.lastErrorTime=0}recordFetchError(){this.consecutiveErrorCount++,this.lastErrorTime=Date.now()}incrementFetchCount(){let e=Date.now();e-this.fetchWindowStart>f&&(this.fetchCountInWindow=0,this.fetchWindowStart=e),this.fetchCountInWindow++}async tryWarmup(){!this.config?.actionId||this.config.prefetch===!1||this.isWarmupInProgress||this.scriptCache||this.hasWarmupError||this.isRateLimited()||this.isInErrorCooldown()||this.hasExceededMaxErrors()||(this.validateActionId(this.config.actionId),this.isWarmupInProgress=!0,this.incrementFetchCount(),this.warmupPromise=(async()=>{try{this.scriptCache=await u(this.config.actionId,this.config.scriptUrl,this.config.extraArgs),this.hasWarmupError=!1,this.recordFetchSuccess()}catch{this.hasWarmupError=!0,this.recordFetchError()}finally{this.isWarmupInProgress=!1}})(),await this.warmupPromise.catch(()=>{}))}validateActionId(e){let t=e.trim();if(!/^[a-zA-Z0-9/_-]+$/.test(t))throw new Error("Invalid actionId format: contains disallowed characters");return encodeURIComponent(t)}prefetchNextScript(){!this.hasWarmupError&&this.config?.prefetch!==!1&&this.tryWarmup().catch(()=>{})}isTestMode(){if(this.config?.actionId==="PULSE_TEST"||this.config?.actionId==="SENTRY_TEST")throw new Error("PULSE_TEST: This is a test error to verify Pulse integration is working");return this.config?.actionId==="t/FFFFFFFFFFFFF/111111111"||this.config?.actionId==="t/FFFFFFFFFFFFF/000000000"}configure(e){try{if(!e.actionId?.trim())throw new Error("actionId is required and cannot be empty");if(this.validateActionId(e.actionId),this.config?.actionId===e.actionId&&this.config.prefetch===e.prefetch&&this.config.scriptUrl===e.scriptUrl)return;this.config?.actionId!==e.actionId&&(this.hasWarmupError=!1,this.consecutiveErrorCount=0,this.lastErrorTime=0),this.scriptCache=null,this.getTokenPromise=null,this.config={prefetch:!0,...e},typeof window<"u"&&(window.Deflect.actionId=e.actionId),!this.isTestMode()&&this.config.prefetch!==!1&&this.tryWarmup()}catch(t){let r=t&&typeof t=="object"&&"isUserError"in t&&t.isUserError===!0;throw this.reportError(t,{deflect_sdk_error:"true",deflect_user_error:r?"true":"false",method:"configure",action_id:e?.actionId||"unknown"},{actionId:e?.actionId,hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError}),t}}async getToken(){if(this.getTokenPromise)return this.getTokenPromise;this.getTokenPromise=this.getTokenInternal();try{return await this.getTokenPromise}finally{this.getTokenPromise=null}}async getTokenInternal(){try{if(!this.config?.actionId)throw new Error("Must call configure() before getToken()");if(this.validateActionId(this.config.actionId),this.isTestMode())return"TESTTOKEN";if(this.hasExceededMaxErrors())throw new Error(`Too many consecutive errors (${this.consecutiveErrorCount}). Call configure() with a new actionId or wait before retrying.`);if(this.isRateLimited())throw new Error(`Rate limit exceeded: ${h} requests per minute. Please wait before retrying.`);if(this.isInErrorCooldown()){let r=Math.min(d*Math.pow(2,this.consecutiveErrorCount-1),3e4)-(Date.now()-this.lastErrorTime);throw new Error(`In error cooldown. Please wait ${Math.ceil(r/1e3)} seconds before retrying.`)}let e;return this.warmupPromise&&await this.warmupPromise.catch(()=>{}),this.scriptCache&&!this.isWarmupInProgress?(e=this.scriptCache,this.scriptCache=null):(this.incrementFetchCount(),e=await u(this.config.actionId,this.config.scriptUrl,this.config.extraArgs)),this.executeScript(e)}catch(e){let t=e instanceof Error?e.message:"";t.includes("cooldown")||t.includes("Rate limit")||t.includes("Too many consecutive")||this.recordFetchError();let i=e&&typeof e=="object"&&"isUserError"in e&&e.isUserError===!0;throw this.reportError(e,{deflect_sdk_error:"true",deflect_user_error:i?"true":"false",method:"getToken",action_id:this.config?.actionId||"unknown",has_cache:this.scriptCache!==null?"true":"false",has_warmup_error:this.hasWarmupError?"true":"false",consecutive_errors:this.consecutiveErrorCount.toString(),stage:"call"},{actionId:this.config?.actionId,hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError,consecutiveErrorCount:this.consecutiveErrorCount,fetchCountInWindow:this.fetchCountInWindow}),e}}async executeScript(e){e.sessionId&&typeof window<"u"&&(window.Deflect.sessionId=e.sessionId);let t=w(e.content),r=null;try{r=await E(t),await v("getChallengeToken");let i=await I("getChallengeToken");return this.recordFetchSuccess(),this.prefetchNextScript(),i}catch(i){throw this.reportError(i,{deflect_sdk_error:"true",method:"executeScript",stage:"load_or_execute",action_id:this.config?.actionId||"unknown"},{hasCache:this.scriptCache!==null,hasWarmupError:this.hasWarmupError}),i}finally{r?y(t,r,"getChallengeToken"):URL.revokeObjectURL(t)}}async warmup(){if(!this.config?.actionId)return!1;try{return this.config.prefetch===!1?!1:(await this.tryWarmup(),this.scriptCache!==null)}catch{return!1}}clearCache(){this.scriptCache=null}resetErrorState(){this.hasWarmupError=!1,this.consecutiveErrorCount=0,this.lastErrorTime=0,this.getTokenPromise=null}getStatus(){return{isRateLimited:this.isRateLimited(),isInCooldown:this.isInErrorCooldown(),consecutiveErrors:this.consecutiveErrorCount,fetchesInWindow:this.fetchCountInWindow,canFetch:!this.isRateLimited()&&!this.isInErrorCooldown()&&!this.hasExceededMaxErrors()}}async injectToken(e){if(!e||!e.target||!(e.target instanceof HTMLFormElement))throw new Error("injectToken: must be called from a form submit event");e.preventDefault();let t=e.target,r=await this.getToken();Array.from(t.querySelectorAll('input[name="deflect_token"]')).forEach(o=>o.remove());let i=document.createElement("input");i.type="hidden",i.name="deflect_token",i.value=r,t.appendChild(i),t.submit()}createClient(e){return new C(e,this.pulseReporter)}},W=new P;typeof window<"u"&&(window.Deflect=W);var $=W;})();
|
package/package.json
CHANGED