diff --git a/README.md b/README.md
deleted file mode 100644
index 5f93622..0000000
--- a/README.md
+++ /dev/null
@@ -1,27 +0,0 @@
-[English](#english) | [Français](#français)
-
-
-
-# Optave Client SDK
-
-Official SDK repository for integrating with Optave services.
-
-## Available SDKs
-
-| SDK | Language | Documentation |
-|-----|----------|---------------|
-| **Client SDK** | JavaScript / TypeScript | [View Documentation](sdks/javascript/README.md) |
-
----
-
-
-
-# SDK Client Optave
-
-Dépôt officiel des SDK pour l'intégration avec les services Optave.
-
-## SDK disponibles
-
-| SDK | Langage | Documentation |
-|-----|---------|---------------|
-| **Client SDK** | JavaScript / TypeScript | [Voir la documentation](sdks/javascript/README.md) |
diff --git a/sdks/javascript/BUILDING.md b/sdks/javascript/BUILDING.md
index c6d6736..54d53c5 100644
--- a/sdks/javascript/BUILDING.md
+++ b/sdks/javascript/BUILDING.md
@@ -53,8 +53,51 @@ generated/
These files are stable, version-locked, and derived from the AsyncAPI specification. They're ready to use as-is.
+## Build System Architecture
+
+### Platform-Specific Build Targets
+
+- **Webpack**: Bundles to multiple formats (ESM and UMD) with optimization and minification
+- **Target Environments**: Modern JavaScript support (ES6+) without transpilation
+ - **Browser**: Chrome 80+, Firefox 74+, Safari 14.1+, Edge 80+ (`target: 'web'`)
+ - Based on usage of class field declarations and optional chaining operator
+ - Chrome 80+ (February 2020), Firefox 74+ (March 2020), Safari 14.1+ (April 2021), Edge 80+ (February 2020)
+ - **Node.js**: 20.0.0+ (`target: 'node'`)
+- **Output**: Multiple build formats (browser.mjs, server.mjs, browser.umd.js, server.umd.js)
+- **CSP Compliance**: Browser builds exclude AJV and use platform-specific implementations to prevent CSP violations, ensuring compatibility with strict Content Security Policy environments like Salesforce Lightning
+- **Platform Architecture**: Runtime organized under `runtime/core/` (shared) and `runtime/platform/browser/` and `runtime/platform/node/` for environment-specific optimizations
+
+### Build Architecture Principles
+
+**Important**: UMD builds are specifically designed for constrained environments (CSP compliance, Salesforce Lightning) and deliberately exclude certain dependencies regardless of target platform. Server UMD ≠ server ESM in terms of bundling strategy.
+
+Always examine:
+- Build-comparison tests
+- CSP compliance tests
+- `BUILD-TESTING.md` documentation
+
+Before modifying externals configuration.
+
+### External Dependency Resolution
+
+When tests fail due to external dependency resolution (like crypto module), fix the TEST ENVIRONMENT, never change the production build configuration. Mock missing externals in test contexts rather than bundling them into production builds. The test environment should adapt to the build architecture, not vice versa.
+
## Build Scripts
+### Available Build Commands
+
+**Development Build**: `npm run build` or `npm run build:all:dev` - Complete build with validation, analysis, and governance checks
+**Production Build**: `npm run build:all:prod` - Optimized build for production (skips dev-only checks)
+**Full Build**: `npm run build:all:full` - Build with detailed webpack bundles (FULL=1 flag)
+
+All builds compile the SDK using webpack into multiple build targets:
+- `dist/browser.mjs` - Browser ES module
+- `dist/server.mjs` - Server ES module
+- `dist/browser.umd.js` - Browser UMD bundle
+- `dist/server.umd.js` - Server UMD bundle
+
+**Dependencies**: `npm install` - Installs all dependencies
+
### Production Build (Recommended)
```bash
diff --git a/sdks/javascript/README.md b/sdks/javascript/README.md
index 739075b..74a79ed 100644
--- a/sdks/javascript/README.md
+++ b/sdks/javascript/README.md
@@ -75,9 +75,9 @@ The SDK provides four optimized builds, each tailored for specific deployment en
| Build | Module Format | Allows clientSecret | AJV Validation | CSP Safe | Intended Environments | Size (Uncompressed) | Size (Gzipped) |
|-------|---------------|-------------------|----------------|----------|---------------------|-------------------|----------------|
| **Browser ESM** | ES Module | ❌ No | ❌ External Only | ✅ Yes | Modern browsers, Vite, Webpack 5+, bundled apps | ~47KB | ~14KB |
-| **Browser UMD** | UMD | ❌ No | ❌ External Only | ✅ Yes | Salesforce Lightning, CDN, legacy browsers, CSP environments | ~50KB | ~14KB |
+| **Browser UMD** | UMD | ❌ No | ❌ External Only | ✅ Yes | Salesforce Lightning, CDN, legacy browsers, CSP environments | ~54KB | ~15KB |
| **Server ESM** | ES Module | ✅ Yes | ✅ Full AJV | ❌ No | Node.js servers, microservices, backend APIs | ~164KB | ~25KB |
-| **Server UMD** | UMD | ✅ Yes | ❌ CSP-Safe Only | ✅ Yes | Salesforce backend, mixed browser environments, internal tooling | ~55KB | ~16KB |
+| **Server UMD** | UMD | ✅ Yes | ❌ External Only | ✅ Yes | Node.js CommonJS, legacy servers, mixed Node.js environments | ~49KB | ~14KB |
### Build Selection Guide
@@ -100,7 +100,7 @@ The SDK provides four optimized builds, each tailored for specific deployment en
**⚙️ Validation Strategy**
- **Browser builds**: Use lightweight, CSP-safe validation (no AJV)
- **Server ESM**: Includes full AJV schema validation for data integrity
-- **Server UMD**: Uses CSP-safe validation (no AJV) for Salesforce compatibility
+- **Server UMD**: Uses CSP-safe validation (no AJV) for maximum compatibility
- All builds validate required fields and basic payload structure
### Automatic Build Selection
@@ -762,7 +762,7 @@ const interactionParams = {
deviceInfo: "iOS/18.2, iPhone15,3",
deviceType: "mobile",
language: "en-US",
- location: "40.7128,-74.0060", // GPS coordinates
+ location: "US-NY", // province grain (ISO 3166-2); never precise coordinates
medium: "chat", // options: "chat", "voice", "email"
section: "support_page",
},
@@ -844,6 +844,8 @@ The SDK manages a default payload structure that encapsulates session informatio
- **session**: Contains session tracking information including `sessionId`, channel details (browser, deviceInfo, deviceType, etc.), and interface information.
- **request**: Details about the request including `requestId`, context, connections, attributes, scope (with structured conversations and interactions), and settings.
+Typed payload fields are the analytics context vocabulary (conversation identity via `threadId`, pseudonymous `userId`, province-grain `channel.location`, A/B `variant`, and so on). `request.reference` is client-custom labels only. The SDK captures this context; it never emits to the analytics pipeline. See [analytics-payload-field-map.md](../../docs/architecture/analytics-payload-field-map.md).
+
### Merging Strategy
@@ -963,7 +965,7 @@ async function run() {
deviceInfo: "iOS/18.2, iPhone15,3",
deviceType: "mobile",
language: "en-US",
- location: "40.7128,-74.0060", // GPS coordinates
+ location: "US-NY", // province grain (ISO 3166-2); never precise coordinates
medium: "chat", // options: "chat", "voice", "email"
section: "support_page",
},
@@ -1118,8 +1120,8 @@ The SDK provides several static methods and constants for accessing metadata and
import OptaveJavaScriptSDK from '@optave/client-sdk';
// Version information
-const sdkVersion = OptaveJavaScriptSDK.getSdkVersion(); // e.g., "3.2.1"
-const specVersion = OptaveJavaScriptSDK.getSpecVersion(); // e.g., "3.2.1"
+const sdkVersion = OptaveJavaScriptSDK.getSdkVersion(); // e.g., "3.6.0" (SDK implementation version)
+const specVersion = OptaveJavaScriptSDK.getSpecVersion(); // Returns: "1.0.0" (AsyncAPI protocol version - static)
const schemaRef = OptaveJavaScriptSDK.getSchemaRef(); // e.g., "optave.message.v3"
// Constants
diff --git a/sdks/javascript/dist/browser.mjs b/sdks/javascript/dist/browser.mjs
index 375d63f..8dacc5e 100644
--- a/sdks/javascript/dist/browser.mjs
+++ b/sdks/javascript/dist/browser.mjs
@@ -1 +1 @@
-class e extends EventTarget{constructor(){super(),this._events={},this._eventsCount=0}on(e,t){this._events[e]||(this._events[e]=[]),this._events[e].push(t),this._eventsCount++;const s=e=>{e.detail&&Array.isArray(e.detail)?t(...e.detail):t(e.detail||e)};return t._wrapped=s,this.addEventListener(e,s),this}off(e,t){if(this._events[e]){const s=this._events[e].indexOf(t);s>-1&&(this._events[e].splice(s,1),this._eventsCount--,0===this._events[e].length&&delete this._events[e])}return t._wrapped&&(this.removeEventListener(e,t._wrapped),delete t._wrapped),this}removeListener(e,t){return this.off(e,t)}emit(e,...t){const s=new CustomEvent(e,{detail:t});return this.dispatchEvent(s),this}once(e,t){const s=(...r)=>{this.off(e,s),t(...r)};return this.on(e,s)}listenerCount(e){return this._events[e]?this._events[e].length:0}removeAllListeners(e){if(e){if(this._events[e]){const t=this._events[e].length;this._events[e].forEach(t=>{t._wrapped&&(this.removeEventListener(e,t._wrapped),delete t._wrapped)}),delete this._events[e],this._eventsCount=Math.max(0,this._eventsCount-t)}}else{Object.values(this._events).reduce((e,t)=>e+t.length,0);Object.keys(this._events).forEach(e=>this.removeAllListeners(e)),this._eventsCount=0}return this}}const t=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;const s=function(e){return"string"==typeof e&&t.test(e)};const r=function(e){if(!s(e))throw TypeError("Invalid UUID");let t;return Uint8Array.of((t=parseInt(e.slice(0,8),16))>>>24,t>>>16&255,t>>>8&255,255&t,(t=parseInt(e.slice(9,13),16))>>>8,255&t,(t=parseInt(e.slice(14,18),16))>>>8,255&t,(t=parseInt(e.slice(19,23),16))>>>8,255&t,(t=parseInt(e.slice(24,36),16))/1099511627776&255,t/4294967296&255,t>>>24&255,t>>>16&255,t>>>8&255,255&t)},n=[];for(let e=0;e<256;++e)n.push((e+256).toString(16).slice(1));function o(e,t=0){return(n[e[t+0]]+n[e[t+1]]+n[e[t+2]]+n[e[t+3]]+"-"+n[e[t+4]]+n[e[t+5]]+"-"+n[e[t+6]]+n[e[t+7]]+"-"+n[e[t+8]]+n[e[t+9]]+"-"+n[e[t+10]]+n[e[t+11]]+n[e[t+12]]+n[e[t+13]]+n[e[t+14]]+n[e[t+15]]).toLowerCase()}let i;const a=new Uint8Array(16);function c(){if(!i){if("undefined"==typeof crypto||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");i=crypto.getRandomValues.bind(crypto)}return i(a)}function d(e){return 14+(e+64>>>9<<4)+1}function u(e,t){const s=(65535&e)+(65535&t);return(e>>16)+(t>>16)+(s>>16)<<16|65535&s}function l(e,t,s,r,n,o){return u((i=u(u(t,e),u(r,o)))<<(a=n)|i>>>32-a,s);var i,a}function p(e,t,s,r,n,o,i){return l(t&s|~t&r,e,t,n,o,i)}function h(e,t,s,r,n,o,i){return l(t&r|s&~r,e,t,n,o,i)}function m(e,t,s,r,n,o,i){return l(t^s^r,e,t,n,o,i)}function f(e,t,s,r,n,o,i){return l(s^(t|~r),e,t,n,o,i)}const g=function(e){return function(e){const t=new Uint8Array(4*e.length);for(let s=0;s<4*e.length;s++)t[s]=e[s>>2]>>>s%4*8&255;return t}(function(e,t){const s=new Uint32Array(d(t)).fill(0);s.set(e),s[t>>5]|=128<>2]|=(255&e[s])<>>32-t}const I=function(e){const t=[1518500249,1859775393,2400959708,3395469782],s=[1732584193,4023233417,2562383102,271733878,3285377520],r=new Uint8Array(e.length+1);r.set(e),r[e.length]=128;const n=(e=r).length/4+2,o=Math.ceil(n/16),i=new Array(o);for(let t=0;t>>0;d=c,c=a,a=b(o,30)>>>0,o=n,n=i}s[0]=s[0]+n>>>0,s[1]=s[1]+o>>>0,s[2]=s[2]+a>>>0,s[3]=s[3]+c>>>0,s[4]=s[4]+d>>>0}return Uint8Array.of(s[0]>>24,s[0]>>16,s[0]>>8,s[0],s[1]>>24,s[1]>>16,s[1]>>8,s[1],s[2]>>24,s[2]>>16,s[2]>>8,s[2],s[3]>>24,s[3]>>16,s[3]>>8,s[3],s[4]>>24,s[4]>>16,s[4]>>8,s[4])};function w(e,t,s,r){return S(80,I,e,t,s,r)}w.DNS=y,w.URL=E;const A={};function O(e,t,s,r,n=0){if(e.length<16)throw new Error("Random bytes length must be >= 16");if(r){if(n<0||n+16>r.length)throw new RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`)}else r=new Uint8Array(16),n=0;return t??=Date.now(),s??=127*e[6]<<24|e[7]<<16|e[8]<<8|e[9],r[n++]=t/1099511627776&255,r[n++]=t/4294967296&255,r[n++]=t/16777216&255,r[n++]=t/65536&255,r[n++]=t/256&255,r[n++]=255&t,r[n++]=112|s>>>28&15,r[n++]=s>>>20&255,r[n++]=128|s>>>14&63,r[n++]=s>>>6&255,r[n++]=s<<2&255|3&e[10],r[n++]=e[11],r[n++]=e[12],r[n++]=e[13],r[n++]=e[14],r[n++]=e[15],r}const T=function(e,t,s){let r;if(e)r=O(e.random??e.rng?.()??c(),e.msecs,e.seq,t,s);else{const e=Date.now(),n=c();!function(e,t,s){e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=s[6]<<23|s[7]<<16|s[8]<<8|s[9],e.msecs=t):(e.seq=e.seq+1|0,0===e.seq&&e.msecs++)}(A,e,n),r=O(n,A.msecs,A.seq,t,s)}return t??o(r)};function R(e,t,s="validation",r={}){return{instancePath:e,message:t,keyword:s,params:r}}function k(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[R("","must be object","type",{type:"object"})]};const t=[];return e.session?"object"!=typeof e.session?t.push(R("/session","must be object","type",{type:"object"})):void 0!==e.session.sessionId&&"string"!=typeof e.session.sessionId&&t.push(R("/session/sessionId","must be string","type",{type:"string"})):t.push(R("/session","is required","required",{missingProperty:"session"})),e.request?"object"!=typeof e.request?t.push(R("/request","must be object","type",{type:"object"})):(e.request.connections?"object"!=typeof e.request.connections?t.push(R("/request/connections","must be object","type",{type:"object"})):(e.request.connections.threadId?"string"!=typeof e.request.connections.threadId&&t.push(R("/request/connections/threadId","must be string","type",{type:"string"})):t.push(R("/request/connections/threadId","is required","required",{missingProperty:"threadId"})),void 0!==e.request.connections.parentId&&"string"!=typeof e.request.connections.parentId&&t.push(R("/request/connections/parentId","must be string","type",{type:"string"}))):t.push(R("/request/connections","is required","required",{missingProperty:"connections"})),void 0!==e.request.context&&"object"!=typeof e.request.context&&t.push(R("/request/context","must be object","type",{type:"object"})),void 0!==e.request.attributes&&"object"!=typeof e.request.attributes&&t.push(R("/request/attributes","must be object","type",{type:"object"})),void 0!==e.request.scope&&("object"!=typeof e.request.scope?t.push(R("/request/scope","must be object","type",{type:"object"})):void 0!==e.request.scope.conversations&&(Array.isArray(e.request.scope.conversations)||t.push(R("/request/scope/conversations","must be array","type",{type:"array"})))),void 0!==e.request.resources&&("object"!=typeof e.request.resources?t.push(R("/request/resources","must be object","type",{type:"object"})):void 0!==e.request.resources.offers&&(Array.isArray(e.request.resources.offers)||t.push(R("/request/resources/offers","must be array","type",{type:"array"}))))):t.push(R("/request","is required","required",{missingProperty:"request"})),t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function q(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[R("","must be object","type",{type:"object"})]};const t=[];if(e.headers)if("object"!=typeof e.headers)t.push(R("/headers","must be object","type",{type:"object"}));else{if(e.headers.correlationId?"string"!=typeof e.headers.correlationId&&t.push(R("/headers/correlationId","must be string","type",{type:"string"})):t.push(R("/headers/correlationId","is required","required",{missingProperty:"correlationId"})),e.headers.action)if("string"!=typeof e.headers.action)t.push(R("/headers/action","must be string","type",{type:"string"}));else{const s=["adjust","elevate","interaction","customerinteraction","reception","summarize","translate","recommend","insights"];s.includes(e.headers.action)||t.push(R("/headers/action","must be equal to one of the allowed values","enum",{allowedValues:s}))}else t.push(R("/headers/action","is required","required",{missingProperty:"action"}));void 0!==e.headers.identifier&&"string"!=typeof e.headers.identifier&&t.push(R("/headers/identifier","must be string","type",{type:"string"})),void 0!==e.headers.schemaRef&&"string"!=typeof e.headers.schemaRef&&t.push(R("/headers/schemaRef","must be string","type",{type:"string"})),void 0!==e.headers.timestamp&&"string"!=typeof e.headers.timestamp&&t.push(R("/headers/timestamp","must be string","type",{type:"string"}))}else t.push(R("/headers","is required","required",{missingProperty:"headers"}));if(e.payload){if("object"!=typeof e.payload)t.push(R("/payload","must be object","type",{type:"object"}));else if(e.headers&&e.headers.action&&e.payload){const s=e.headers.action;["adjust","elevate","interaction","customerinteraction","customerInteraction","summarize","translate","insights","recommend"].includes(s)&&(e.payload.request?e.payload.request.scope?e.payload.request.scope.conversations?Array.isArray(e.payload.request.scope.conversations)?0===e.payload.request.scope.conversations.length&&t.push(R("/payload/request/scope/conversations",`must be non-empty array for ${s}`,"minItems",{limit:1})):t.push(R("/payload/request/scope/conversations","must be array","type",{type:"array"})):t.push(R("/payload/request/scope/conversations",`is required for ${s}`,"required",{missingProperty:"conversations"})):t.push(R("/payload/request/scope","is required","required",{missingProperty:"scope"})):t.push(R("/payload/request","is required","required",{missingProperty:"request"})))}}else t.push(R("/payload","is required","required",{missingProperty:"payload"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}const C="3.2.3",N=`optave.message.v${C.split(".")[0]}`,U={AUTHENTICATION:"AUTHENTICATION",ORCHESTRATOR:"ORCHESTRATOR",VALIDATION:"VALIDATION",WEBSOCKET:"WEBSOCKET"},P=Object.freeze({MESSAGE:"message",ERROR:"error"}),W=Object.freeze({CONNECTION_OPEN:"connection:open",CONNECTION_CLOSE:"connection:close",CONNECTION_ERROR:"connection:error",MESSAGE_RECEIVED:"message:received",MESSAGE_SENT:"message:sent",ERROR:"error",RESPONSE:"response",LEGACY_ERROR:"error",LEGACY_MESSAGE:"message"}),D=Object.freeze({SUPERPOWER_RESPONSE:"superpower.response",SUPERPOWER_ERROR:"superpower.error"}),M=new Set(["adjust","elevate","interaction","reception","customerInteraction","summarize","translate","recommend","insights"]),L={SPEC_VERSION:C,SCHEMA_REF:N,MAX_PAYLOAD_SIZE:131072,MAX_PAYLOAD_SIZE_KB:128,DEFAULT_REQUEST_TIMEOUT_MS:3e4,ErrorCategory:U,LegacyEvents:P,EVENTS:W,InboundEvents:D,ALLOWED_ACTIONS:M};function j(e){const t=[];if((()=>{if("undefined"!=typeof process&&process.versions,"undefined"!=typeof global){if("window"in global||"document"in global||"undefined"!=typeof process&&process.versions,(!("window"in global)||!("document"in global))&&"undefined"!=typeof process&&process.versions,"window"in global&&global.window)return!0;if("document"in global&&global.document)return!0}try{if("undefined"!=typeof window&&null!==window)return("undefined"==typeof global||"window"in global)&&("undefined"!=typeof global&&"undefined"!=typeof process&&process.versions,!0);if("undefined"!=typeof document&&null!==document)return("undefined"==typeof global||"document"in global)&&("undefined"!=typeof global&&"undefined"!=typeof process&&process.versions,!0)}catch(e){}return"undefined"!=typeof navigator&&"ReactNative"===navigator.product||!("undefined"==typeof global||!global.__expo)||"undefined"!=typeof location&&null!==location||("undefined"!=typeof process&&process.versions,!1)})()&&e.clientSecret){let e=!1,s=!1;try{e=!0===__SALESFORCE_BUILD__}catch(e){}try{s=!1}catch(e){}e||s||t.push({type:"error",code:"CLIENT_SECRET_IN_CLIENT_ENV",message:"clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.",field:"clientSecret"})}return t}const V={BROWSER_ESM:"browser-esm",SERVER_ESM:"server-esm",BROWSER_UMD:"browser-umd",SERVER_UMD:"server-umd"},$={browser:V.BROWSER_ESM,server:V.SERVER_ESM},B={BROWSER:[V.BROWSER_ESM,V.BROWSER_UMD,V.SERVER_UMD],SERVER:[V.SERVER_ESM],UMD:[V.BROWSER_UMD,V.SERVER_UMD],ESM:[V.BROWSER_ESM,V.SERVER_ESM]},K={isValid:e=>Object.values(V).includes(e)||Object.keys($).includes(e),normalize:e=>$[e]?$[e]:Object.values(V).includes(e)?e:"unknown",isBrowser(e){const t=this.normalize(e);return B.BROWSER.includes(t)},isServer(e){const t=this.normalize(e);return B.SERVER.includes(t)},isUMD(e){const t=this.normalize(e);return B.UMD.includes(t)},isESM(e){const t=this.normalize(e);return B.ESM.includes(t)},getInfo(e){return{original:e,normalized:this.normalize(e),valid:this.isValid(e),isBrowser:this.isBrowser(e),isServer:this.isServer(e),isUMD:this.isUMD(e),isESM:this.isESM(e)}}};class z extends Error{constructor({category:e,code:t,message:s,details:r}){super(s),this.name="OptaveError",this.category=e||"UNKNOWN",this.code=t||"UNKNOWN",void 0!==r&&(this.details=r)}}!function(){if("undefined"!=typeof globalThis){globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__=!0;if(!globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__)throw new Error("Security guard initialization failed")}"undefined"!=typeof process&&process.env}(),"undefined"!=typeof window?window.__OPTAVE_SECURITY_GUARDS_BROWSER__=!0:"undefined"!=typeof global&&(global.__OPTAVE_SECURITY_GUARDS_NODE__=!0);const H="3.2.3",F=()=>{const e="browser-esm";return{isBrowser:K.isBrowser(e),isServer:K.isServer(e),buildTarget:e}};let x=!1,G=!1;class Y extends e{options={};wss=null;static defaultPayload={session:{sessionId:"",channel:{browser:"",deviceInfo:"",deviceType:"",language:"",location:"",medium:"chat",metadata:[],section:""},interface:{appVersion:"",category:"",language:"",name:"",type:""}},request:{requestId:"",attributes:{content:"",instruction:"",variant:"A"},connections:{journeyId:"",parentId:"",threadId:""},context:{caseId:"",departmentId:"",operatorId:"",organizationId:"",userId:""},reference:{ids:[{name:"",value:""}],labels:[],tags:[]},resources:{codes:[{id:"",label:"",type:"",value:""}],links:[{expires_at:"",html:!1,id:"",label:"",type:"",url:""}],offers:[]},scope:{accounts:[],appointments:[],assets:[],bookings:[],cases:[],conversations:[],documents:[],events:[],interactions:[],items:[],locations:[],operators:[],orders:[],organizations:[],persons:[],policies:[],products:[{id:""}],properties:[],services:[],subscriptions:[],tickets:[],transactions:[],users:[]},settings:{disableBrowsing:!1,disableSearch:!1,disableSources:!1,disableStream:!0,disableTools:!1,maxResponseLength:0,overrideInterfaceLanguage:"",overrideOutputLanguage:""},a2a:[{id:"",name:"",type:""}],cursor:{since:"",until:""}}};static cleanup(){x=!1,G=!1}constructor(e){if(super(),this.options={...e},function(e){if(void 0===e.strictValidation){const t="undefined"!=typeof process&&process.env?"production":"development";e.strictValidation="production"!==t}if("number"!=typeof e.requestTimeoutMs&&(e.requestTimeoutMs=3e4),"number"!=typeof e.connectionTimeoutMs&&(e.connectionTimeoutMs=3e4),e.logger||(e.logger={debug(){},info(){},warn(){},error(){}}),e.authTransport||(e.authTransport="subprotocol"),void 0===e.authRequired&&(e.authRequired=!0),!e.tokenProvider){let t=e.tokenUrl;if(!t&&"undefined"!=typeof document){const e=document.querySelector('meta[name="optave-token-url"]');e&&e.content&&(t=e.content)}t||(t="/api/optave/ws-ticket"),e.tokenProvider=async()=>{const s={};e.publishableKey&&(s["X-Optave-Publishable-Key"]=e.publishableKey);const r=await fetch(t,{method:"POST",credentials:"include",headers:s});if(!r.ok)throw new Error("Failed to obtain WS token");const n=await r.json();return n.token||n.access_token}}}(this.options),void 0===this.options.cspSafe){const e=F();"server-esm"===e.buildTarget||"server"===e.buildTarget?this.options.cspSafe=!1:("server-umd"===e.buildTarget||"browser-esm"===e.buildTarget||"browser-umd"===e.buildTarget||e.isBrowser||(()=>{const e=F();return"unknown"!==e.buildTarget?e.isBrowser:"undefined"!=typeof window&&void 0!==window.WebSocket})())&&(this.options.cspSafe=!0)}const t=function(e){const t={isValid:!0,errors:[],warnings:[]},s=function(e){const t=[];return e.websocketUrl&&"string"==typeof e.websocketUrl||t.push({type:"warning",code:"MISSING_WEBSOCKET_URL",message:"websocketUrl not provided; openConnection() will emit an error.",field:"websocketUrl"}),t}(e),r=function(e){const t=[];return!e.authenticationUrl||e.clientId&&e.clientSecret||t.push({type:"warning",code:"INCOMPLETE_AUTH_CONFIG",message:"authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.",field:"authentication"}),t}(e),n=[...s,...r,...j(e)];for(const e of n)"error"===e.type?(t.errors.push(e),t.isValid=!1):"warning"===e.type&&t.warnings.push(e);return t}(this.options);if(!t.isValid){const e=t.errors.map(e=>e.message).join("; ");throw new Error(`[Optave SDK] Configuration errors: ${e}`)}t.warnings.forEach(e=>{(this.options?.logger?.warn||console.warn)(`[Optave SDK] ${e.message}`)});try{!function(e,t,s={}){if(!e||"string"!=typeof e)return;const r=K.normalize(t),n=K.isUMD(r),o=K.isBrowser(r);if((n||o)&&e.startsWith("ws://"))throw new Error(`[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in UMD builds. Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. Please use secure WebSocket protocol (wss://) instead. Current URL: ${e}`);if(n&&e.startsWith("wss://")){const t="function"==typeof s.tokenProvider,r=!1===s.authRequired;if(!t&&!r)throw new Error(`[Optave SDK] UMD builds require a tokenProvider function for secure WebSocket connections. In constrained environments like Salesforce Lightning, authentication tokens must be obtained from your backend server. Please provide options.tokenProvider() that returns a valid token, or set options.authRequired = false to disable authentication. Current URL: ${e}`)}}(this.options.websocketUrl,"browser-esm",this.options)}catch(e){throw e}const s=F();this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&s.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&s.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this._pending=new Map,this._deprecatedKeys=new Set,this._silenceDeprecations="undefined"!=typeof process&&"1"===process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS,this.options.cspSafe,this._validatePayload=k,this._validateMessageEnvelope=q}async _ensureWebSocketImpl(){if(this.WebSocketImpl)return this.WebSocketImpl;const e=F();return this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&e.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&e.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this.WebSocketImpl||(e.isBrowser?this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:null:e.isServer&&(this.WebSocketImpl=await this.loadNodeWebSocket())),this.WebSocketImpl}async loadNodeWebSocket(){const e=F();return e.isBrowser?null:"unknown"!==e.buildTarget||"undefined"==typeof window&&"undefined"==typeof document&&"undefined"==typeof navigator&&"undefined"==typeof location?("undefined"==typeof process||process.versions,null):null}static getSdkVersion(){return H}static getSpecVersion(){return C}static getSchemaRef(){return N}static get CONSTANTS(){return L}static get LegacyEvents(){return P}static get InboundEvents(){return D}setSessionId(e){return this.sessionId=e,this}getSessionId(){return this.sessionId||""}validate(e){return this._validatePayload(e).valid}validateEnvelope(e){return this._validateMessageEnvelope(e).valid}validateRequiredFields(e,t){const s=[];switch(e.request?.connections?.threadId||s.push("request.connections.threadId is required"),t){case"adjust":e.request?.attributes?.content||s.push("request.attributes.content is required for adjust"),e.request?.attributes?.instruction||s.push("request.attributes.instruction is required for adjust"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for adjust"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for adjust and must be a non-empty array");break;case"elevate":e.request?.attributes?.content||s.push("request.attributes.content is required for elevate"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for elevate"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for elevate and must be a non-empty array");break;case"translate":case"summarize":case"insights":case"customerinteraction":case"customerInteraction":case"interaction":e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push(`request.scope.conversations is required for ${t} and must be a non-empty array`);break;case"recommend":e.request?.resources?.offers&&Array.isArray(e.request.resources.offers)&&0!==e.request.resources.offers.length||s.push("request.resources.offers is required for recommend and must be a non-empty array"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for recommend and must be a non-empty array")}return{isValid:0===s.length,errors:s}}async authenticate(){if(K.isBrowser("browser-esm"))return this.handleError(U.AUTHENTICATION,"UNSUPPORTED_IN_BROWSER","authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend."),null;let e={grant_type:"client_credentials"};if(!this.options.authenticationUrl)return this.handleError(U.AUTHENTICATION,"INVALID_AUTHENTICATION_URL","Empty or invalid authentication URL"),null;if(!this.options.clientId)return this.handleError(U.AUTHENTICATION,"INVALID_CLIENT_ID","Empty or invalid client ID"),null;e.client_id=this.options.clientId,e.client_secret=this.options.clientSecret;const t=new URLSearchParams(e).toString();let s=this.options.authenticationUrl;s.endsWith("/token")||(s=s.endsWith("/")?s+"token":s+"/token");const r=`${s}?${t}`,n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"}}),o=await n.json();return n.ok?o.access_token:(this.handleError(U.AUTHENTICATION,"INVALID_AUTHENTICATION_RESPONSE",this.formatAuthenticationError(n,o.error,"token endpoint").message,o.error),null)}async openConnection(e){if(!this.options.websocketUrl)return(this.options?.logger?.error||console.error)("[Optave SDK] openConnection aborted: missing websocketUrl"),void this.handleError(U.WEBSOCKET,"INVALID_WEBSOCKET_URL",this.formatWebSocketError(new Error("Invalid WebSocket URL configuration"),{url:this.options.websocketUrl}).message,this.options.websocketUrl);const t=await(async()=>{if("string"==typeof e&&e.length>0)return e;if("function"==typeof this.options.tokenProvider)try{return await this.options.tokenProvider()}catch(e){return this.handleError(U.AUTHENTICATION,"TOKEN_PROVIDER_FAILED",this.formatTokenProviderError(e).message,e),null}return null})();if(await this._ensureWebSocketImpl(),!this.WebSocketImpl)return void this.handleError(U.WEBSOCKET,"NO_WEBSOCKET_IMPL",this.formatWebSocketError(new Error("No WebSocket implementation available"),{environment:"undefined"!=typeof window?"browser":"node"}).message);if(!t&&!1!==this.options.authRequired)return void this.handleError(U.AUTHENTICATION,"MISSING_TOKEN","No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.");const s=new URLSearchParams;this.sessionId&&s.set("OptaveTraceChatSessionId",this.sessionId);try{if("subprotocol"===this.options.authTransport){const e=t?["optave-v1",t]:["optave-v1"];this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl,e)}else{if(t){const e=t.replace(/^Bearer\s+/i,"");s.set("Authorization",e)}this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl),t&&this._warnOnce("_warnedQueryToken",'[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".')}}catch(e){return(this.options?.logger?.error||console.error)("[Optave SDK] WebSocket constructor threw",e),void this.handleError(U.WEBSOCKET,"WEBSOCKET_ERROR",this.formatWebSocketError(e,{url:this.options.websocketUrl}).message,e)}return new Promise((e,t)=>{const s=setTimeout(()=>{const e=this.options.connectionTimeoutMs||3e4,s=this.formatWebSocketError(new Error("Connection timeout"),{timeout:e,url:this.options.websocketUrl}).message;if(this.wss){this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null;try{this.wss.close()}catch(e){}this.wss=null}this.handleError(U.WEBSOCKET,"CONNECTION_TIMEOUT",s),t({category:U.WEBSOCKET,code:"CONNECTION_TIMEOUT",message:s,details:null})},this.options.connectionTimeoutMs||3e4);this.wss.onopen=t=>{clearTimeout(s),this.emit("open",t),e(t)},this.wss.onmessage=e=>{this._handleInbound(e.data)},this.wss.onclose=e=>{clearTimeout(s),this.emit("close",e);for(const[t,s]of this._pending.entries())s.timer&&clearTimeout(s.timer),s._handled=!0,s.reject({category:U.WEBSOCKET,code:"CONNECTION_CLOSED",message:`WebSocket connection closed: ${e.reason||"Connection lost"}`,details:{code:e.code,reason:e.reason,correlationId:t},correlationId:t});this._pending.clear(),this.wss=null},this.wss.onerror=e=>{clearTimeout(s);const r=e.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||"WebSocket connection failed",n={category:U.WEBSOCKET,code:"CONNECTION_ERROR",message:r,details:{originalError:e}};for(const[e,t]of this._pending.entries())t.timer&&clearTimeout(t.timer),t._handled=!0,t.reject({...n,details:{...n.details,correlationId:e},correlationId:e});this._pending.clear(),this.emit("error",n),t(n)}})}_warnOnce(e,t){this[e]||(this[e]=!0,(this.options?.logger?.warn||console.warn)(t))}deprecate(e,t){this._silenceDeprecations||this._deprecatedKeys.has(e)||(this._deprecatedKeys.add(e),(this.options?.logger?.warn||console.warn)(t))}_handleInbound(e){let t;try{t="string"==typeof e?JSON.parse(e):e}catch(e){const t={category:U.WEBSOCKET,code:"INVALID_JSON",message:"Invalid JSON received from server",details:e,timestamp:(new Date).toISOString()};return void this._emitError(t)}const s=t&&t.headers&&t.payload,r="error"===t?.state||"error"===t?.actionType||!!t?.error;if(this.options.strictValidation&&s){const e=this._validateMessageEnvelope(t);e.valid||this.handleError(U.VALIDATION,"INBOUND_ENVELOPE_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Inbound envelope validation failed"),e.errors)}if(r){const e=t?.headers&&t.headers.correlationId||t?.correlationId||null,s={category:U.ORCHESTRATOR,code:t?.error?.code||"REMOTE_ERROR",message:t?.error?.message||t?.message||"Remote error",details:t?.error||t,correlationId:e};if(e&&this._pending.has(e)){const t=this._pending.get(e);t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),t.reject(s)}return void this._emitError(s,t?.action)}const n=t?.headers?.correlationId||t?.correlationId;if(n&&this._pending.has(n)){const e=this._pending.get(n);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(n),e.resolve(t)}this.emit(P.MESSAGE,t),x||(x=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".')),this.emit(D.SUPERPOWER_RESPONSE,t),this.emit(W.RESPONSE,t),t?.action&&this.emit(`message.${t.action}`.toLowerCase(),t),s&&t.headers.schemaRef&&this.emit(t.headers.schemaRef,t)}_emitError(e,t=null){e.timestamp||(e.timestamp=(new Date).toISOString()),this.emit(P.ERROR,e),G||(G=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'));const s=(r=e)&&r.category&&r.code&&r.message?new z(r):"string"==typeof r?new z({category:"UNKNOWN",code:"STRING_ERROR",message:r}):r&&r.isAuthError?new z({category:"AUTHENTICATION",code:r.code||"AUTH_ERROR",message:r.message||"Authentication error",details:r}):r&&r.isWsError?new z({category:"WEBSOCKET",code:r.code||"WS_ERROR",message:r.message||"WebSocket error",details:r}):new z({category:"UNKNOWN",code:"UNCLASSIFIED",message:r&&r.message||String(null!=r?r:"Unknown error"),details:r});var r;this.emit(D.SUPERPOWER_ERROR,s),this.emit(W.ERROR,e)}closeConnection(){this.wss&&(this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null,this.wss.close(),this.wss=null)}selectiveDeepMerge(e,t){if(Array.isArray(e)&&Array.isArray(t))return[...t];const s=e=>null!==e&&"object"==typeof e&&!Array.isArray(e);if(s(e)&&s(t)){const s={...e};for(let r in t)s[r]=r in e?this.selectiveDeepMerge(e[r],t[r]):t[r];return s}return void 0!==t?t:e}isPayloadSizeValid(e){return!!e&&e.length/1024<=L.MAX_PAYLOAD_SIZE_KB}openConnectionAsync(e){return new Promise((t,s)=>{const r=e=>{this.off("error",n),t(e)},n=e=>{this.off("open",r),s(e)};this.once("open",r),this.once("error",n),this.openConnection(e)})}buildPayload(e,t,s){let r=this.selectiveDeepMerge(Y.defaultPayload,s);return s?.request?.variation&&(this.deprecate("payload.request.variation","[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."),r.request.attributes.variant=s.request.variation),s?.request?.content&&!r.request?.attributes?.content&&(r.request.attributes.content=s.request.content,this.deprecate("payload.request.content","[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.")),r.request.attributes.variant&&(r.request.attributes.variant=r.request.attributes.variant.toUpperCase()),r}resolveMessageId(e,t){return`${t}.${e}.v3`.toLowerCase()}buildMessageEnvelope(e,t,s,r={}){const n=(new Date).toISOString(),o=r.correlationId||e?.request?.requestId||T(),i=r.traceId||T(),a=r.idempotencyKey||T(),c=r.timestamp,d={correlationId:o,action:s,schemaRef:N,sdkVersion:H,identifier:t,traceId:i,idempotencyKey:a,timestamp:c,issuedAt:n};return this.options.tenantId&&(d.tenantId=this.options.tenantId),void 0!==r.networkLatencyMs&&(d.networkLatencyMs=r.networkLatencyMs),Object.freeze(d),{action:"message",headers:d,payload:e}}formatValidationErrorMessage(e,t="Validation failed"){if(!e||!Array.isArray(e)||0===e.length)return t;if(1===e.length){const s=e[0],r=s.instancePath||"/",n="/"===r?"root object":r.replace(/^\//,"").replace(/\//g,".");if("required"===s.keyword){const e=s.params?.missingProperty||"unknown field",r="root object"===n?e:n.endsWith(e)?n:n+"."+e;return`${t}: ${"root object"===n?"Required field":"Field"} '${r}' is missing`}if("type"===s.keyword){return`${t}: Field '${n}' must be of type '${s.params?.type||"unknown"}'`}if("additionalProperties"===s.keyword){return`${t}: Field '${n}.${s.params?.additionalProperty||"unknown"}' is not allowed`}if("enum"===s.keyword){const e=s.params?.allowedValues||[];return`${t}: Field '${n}' must be one of: ${Array.isArray(e)?e.join(", "):"unknown values"}`}return`${t}: ${s.message} at '${n}'`}const s=e.filter(e=>"required"===e.keyword),r=e.filter(e=>"type"===e.keyword),n=e.filter(e=>"required"!==e.keyword&&"type"!==e.keyword);let o=t+":";if(s.length>0){o+=` Missing required fields: ${s.map(e=>{const t=(e.instancePath||"/").replace(/^\//,"").replace(/\//g,"."),s=e.params?.missingProperty||"unknown";return""===t?s:`${t}.${s}`}).join(", ")}.`}if(r.length>0){o+=` Type errors in: ${r.slice(0,3).map(e=>`${(e.instancePath||"/").replace(/^\//,"").replace(/\//g,".")||"root"} (expected ${e.params?.type||"unknown"})`).join(", ")}.`,r.length>3&&(o+=` And ${r.length-3} more type errors.`)}return n.length>0&&(o+=` Additional validation errors: ${n.length}.`),o}formatAuthenticationError(e,t,s){let r="Authentication failed";const n=[];return e&&e.status&&(r+=` (HTTP ${e.status})`),t&&("string"==typeof t?r+=`: ${t}`:t.error_description?r+=`: ${t.error_description}`:t.message?r+=`: ${t.message}`:t.error&&(r+=`: ${t.error}`)),e&&401===e.status?(n.push("Verify clientId and clientSecret are correct"),n.push("Ensure credentials match the target environment (dev/staging/production)")):e&&403===e.status?(n.push("Check if your client has the necessary permissions"),n.push("Verify the authentication endpoint URL is correct")):e&&e.status>=500?(n.push("Authentication server error - try again later"),n.push("Contact support if the problem persists")):n.push("Check network connectivity and authentication endpoint configuration"),s&&s.authUrl&&(r+=` (endpoint: ${s.authUrl})`),{message:r,suggestions:n}}formatWebSocketError(e,t){let s="WebSocket connection failed";const r=[],n=e?.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||null;return n&&(s+=`: ${n}`),t&&(t.url&&(s+=` (URL: ${t.url})`),t.timeout&&(s+=` (timeout: ${t.timeout}ms)`)),r.push("Check network connectivity and firewall settings"),r.push("Verify WebSocket URL is correct and accessible"),t&&t.url&&(t.url.startsWith("ws://")&&r.push("Consider using secure WebSocket (wss://) for production"),(t.url.includes("localhost")||t.url.includes("127.0.0.1"))&&r.push("Ensure local server is running if connecting to localhost")),t&&t.timeout&&r.push("Try increasing connection timeout if network is slow"),{message:s,suggestions:r}}formatPayloadSizeError(e,t,s){const r=Math.ceil(e/1024);let n=`Payload too large: ${r}KB exceeds maximum ${t}KB (${r-t}KB over limit)`;const o=[];if(s&&"object"==typeof s){JSON.stringify(s);if(s.request?.scope?.conversations&&Array.isArray(s.request.scope.conversations)){const e=JSON.stringify(s.request.scope.conversations).length,t=Math.ceil(e/1024);t>10&&(o.push(`Consider reducing conversation history - current size: ~${t}KB`),o.push("Remove older messages or summarize conversation context"))}if(s.request?.resources?.offers&&Array.isArray(s.request.resources.offers)){const e=JSON.stringify(s.request.resources.offers).length,t=Math.ceil(e/1024);t>5&&o.push(`Consider reducing product offers data - current size: ~${t}KB`)}if(s.session?.channel?.metadata&&Array.isArray(s.session.channel.metadata)){const e=JSON.stringify(s.session.channel.metadata).length,t=Math.ceil(e/1024);t>2&&o.push(`Consider reducing metadata array - current size: ~${t}KB`)}}return 0===o.length&&(o.push("Remove unused fields from request payload"),o.push("Consider paginating large datasets"),o.push("Use shorter field values where possible")),{message:n,suggestions:o}}formatTokenProviderError(e,t){let s="Failed to obtain WebSocket token from tokenProvider()";const r=[];return e&&(e.message?s+=`: ${e.message}`:"string"==typeof e&&(s+=`: ${e}`),"TypeError"===e.name&&e.message?.includes("fetch")?(r.push("Check if tokenProvider endpoint is accessible"),r.push("Verify CORS settings allow requests to token endpoint")):e.message?.includes("404")||e.message?.includes("Not Found")?(r.push("Verify tokenProvider endpoint URL is correct"),r.push("Ensure backend token endpoint is implemented")):e.message?.includes("401")||e.message?.includes("403")?(r.push("Check authentication/authorization for token endpoint"),r.push("Verify user session or credentials are valid")):e.message?.includes("timeout")&&r.push("Token provider request timed out - check network or server response time")),t&&t.tokenUrl&&(s+=` (endpoint: ${t.tokenUrl})`),0===r.length&&(r.push("Verify tokenProvider function implementation"),r.push("Check backend token endpoint is running and accessible"),r.push("Review browser console for network errors")),{message:s,suggestions:r}}handleError(e,t,s,r=null,n=[],o=null){const i=new z({category:e,code:t,message:s,details:r});n&&(i.suggestions=n),o&&(i.correlationId=o),0===this.listenerCount(P.ERROR)&&0===this.listenerCount(W.ERROR)&&(this.options?.logger?.error||console.error)(`[Optave SDK] ${t}: ${s}`),this._emitError(i)}send(e,t,s){const r=null!=(this.WebSocketImpl&&this.WebSocketImpl.OPEN)?this.WebSocketImpl.OPEN:1;if(!this.wss||this.wss.readyState!==r){const e=this.wss?this.wss.readyState:"no connection";return void this.handleError(U.WEBSOCKET,"WEBSOCKET_NOT_IN_OPEN_STATE",this.formatWebSocketError(new Error("WebSocket not ready for sending"),{readyState:e,action:t}).message)}if(!M.has(t))return void this.handleError(U.VALIDATION,"INVALID_ACTION",`Unsupported action '${t}'. Allowed: ${[...M].join(", ")}`);const n=new Set(["session","request","headers"]);for(const e of Object.keys(s||{}))if(!n.has(e)){const t=[{instancePath:"",keyword:"additionalProperties",params:{additionalProperty:e},message:`must NOT have additional property '${e}'`}];return void this.handleError(U.VALIDATION,"PAYLOAD_SCHEMA_MISMATCH",this.formatValidationErrorMessage(t),t)}const o=this.buildPayload(e,t,s||{}),i=this.validateRequiredFields(o||{},t);if(!i.isValid)return void this.handleError(U.VALIDATION,"REQUIRED_FIELDS_MISSING",`Missing required fields for action '${t}': ${i.errors.join(", ")}`,i.errors);if(this.options.strictValidation){const e=this._validatePayload(o);if(!e.valid)return void this.handleError(U.VALIDATION,"PAYLOAD_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Schema validation failed"),e.errors)}const a=this.buildMessageEnvelope(o,e,t,s?.headers||{}),c=JSON.stringify(a);if(!this.isPayloadSizeValid(c)){const e=c.length;return void this.handleError(U.VALIDATION,"PAYLOAD_TOO_LARGE",this.formatPayloadSizeError(e,L.MAX_PAYLOAD_SIZE_KB,a).message,L.MAX_PAYLOAD_SIZE_KB)}this.wss.send(c)}adjust(e){return this.send("message","adjust",e)}elevate(e){return this.send("message","elevate",e)}interaction(e){return this.send("message","interaction",e)}reception(e){return this.send("message","reception",e)}customerInteraction(e){return this.deprecate("method.customerInteraction","[Deprecation] 'customerInteraction' is deprecated; use 'interaction' instead."),this.send("message","customerInteraction",e)}summarize(e){return this.send("message","summarize",e)}translate(e){return this.send("message","translate",e)}recommend(e){return this.send("message","recommend",e)}insights(e){return this.send("message","insights",e)}_registerPending(e,t,s,r,n){let o=null;s>0&&(o=setTimeout(()=>{if(this._pending.has(e)){const r=this._pending.get(e);r&&!r._handled&&(this._pending.delete(e),r._handled=!0,n({category:U.WEBSOCKET,code:"REQUEST_TIMEOUT",message:`Request timed out after ${s}ms`,details:{correlationId:e,action:t},correlationId:e}))}},s)),this._pending.set(e,{resolve:r,reject:n,timer:o,action:t,_handled:!1})}_promiseSend(e,t,s={},r={}){let n,o,i;const a=new Promise((a,c)=>{o=a,i=c;const d="number"==typeof r.timeoutMs?r.timeoutMs:"number"==typeof r.timeout?r.timeout:this.options.requestTimeoutMs;if(!this.wss||this.wss.readyState!==WebSocket.OPEN){if(d<=0)return void c({category:U.WEBSOCKET,code:"WEBSOCKET_NOT_IN_OPEN_STATE",message:"WebSocket not open",details:null});const r=this.buildPayload(e,t,s),o=this.buildMessageEnvelope(r,e,t,s?.headers||{});return n=o.headers.correlationId,void this._registerPending(n,t,d,a,c)}if(!M.has(t))return void c({category:U.VALIDATION,code:"INVALID_ACTION",message:`Unsupported action '${t}'.`,details:{allowed:[...M]}});const u=new Set(["session","request","headers"]);for(const e of Object.keys(s||{}))if(!u.has(e)){const t=[{instancePath:"",keyword:"additionalProperties",params:{additionalProperty:e},message:`must NOT have additional property '${e}'`}];return void c({category:U.VALIDATION,code:"PAYLOAD_SCHEMA_MISMATCH",message:this.formatValidationErrorMessage(t),details:t})}const l=this.buildPayload(e,t,s),p=this.validateRequiredFields(l,t);if(!p.isValid)return void c({category:U.VALIDATION,code:"REQUIRED_FIELDS_MISSING",message:`Missing required fields for action '${t}'`,details:p.errors});if(this.options.strictValidation){const e=k(l);if(!e.valid)return void c({category:U.VALIDATION,code:"PAYLOAD_SCHEMA_MISMATCH",message:this.formatValidationErrorMessage(e.errors,"Schema validation failed"),details:e.errors})}const h=this.buildMessageEnvelope(l,e,t,s?.headers||{});n=h.headers.correlationId,this._registerPending(n,t,d,a,c);const m=JSON.stringify(h);if(!this.isPayloadSizeValid(m)){const e=m.length,t=this.formatPayloadSizeError(e,L.MAX_PAYLOAD_SIZE_KB,h).message;return void c({category:U.VALIDATION,code:"PAYLOAD_TOO_LARGE",message:t,details:{maxKb:L.MAX_PAYLOAD_SIZE_KB}})}try{this.wss.send(m)}catch(e){if(this._pending.has(n)){const e=this._pending.get(n);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(n)}c({category:U.WEBSOCKET,code:"SEND_FAILED",message:"Failed to send over WebSocket",details:e,correlationId:n})}});return a.correlationId=n,a}adjustAsync(e,t){return this._promiseSend("message","adjust",e,t)}elevateAsync(e,t){return this._promiseSend("message","elevate",e,t)}interactionAsync(e,t){return this._promiseSend("message","interaction",e,t)}receptionAsync(e,t){return this._promiseSend("message","reception",e,t)}customerInteractionAsync(e,t){return this.deprecate("method.customerInteractionAsync","[Deprecation] 'customerInteractionAsync' is deprecated; use 'interactionAsync' instead."),this._promiseSend("message","customerInteraction",e,t)}summarizeAsync(e,t){return this._promiseSend("message","summarize",e,t)}translateAsync(e,t){return this._promiseSend("message","translate",e,t)}recommendAsync(e,t){return this._promiseSend("message","recommend",e,t)}insightsAsync(e,t){return this._promiseSend("message","insights",e,t)}cancelRequest(e){if(this._pending.has(e)){const t=this._pending.get(e);return t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),setTimeout(()=>{t.reject({category:U.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:e},correlationId:e})},0),!0}return!1}cancelPendingRequests(e=!1){if(!this._pending)return 0;const t=this._pending.size,s=[...this._pending.entries()];for(const[t,r]of s)r.timer&&clearTimeout(r.timer),r._handled=!0,e?r.reject({category:U.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled during cleanup",details:{correlationId:t},correlationId:t}):queueMicrotask(()=>{r.reject({category:U.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:t},correlationId:t})});return this._pending.clear(),t}cleanup(){if(this.closeConnection(),this.cancelPendingRequests(!0),this._deprecatedKeys&&this._deprecatedKeys.clear(),void 0!==this._warnedQueryToken&&delete this._warnedQueryToken,this._events)for(const e in this._events)delete this._events[e];this.removeAllListeners(),this._events=null,this._eventsCount=null,this._maxListeners=null;if(this.constructor._preservedJSDOM&&this.constructor._preservedJSDOM.dom)try{const e=this.constructor._preservedJSDOM.dom.window;e&&"function"==typeof e.close&&e.close(),delete this.constructor._preservedJSDOM}catch(e){}this._validatePayload=null,this._validateMessageEnvelope=null,this._emitError=null,this._ensureWebSocketImpl=null,this._handleInbound=null,this._promiseSend=null,this._registerPending=null,this._warnOnce=null,this.options=null,this.WebSocketImpl=null,this.wss=null,this.sessionId=null,this._pending=null,this._deprecatedKeys=null,this._silenceDeprecations=null,this._events=null,this._eventsCount=null,this._maxListeners=null}removeAllListeners(t){try{e.prototype.removeAllListeners.call(this,t)}catch(e){t?this._events&&this._events[t]&&(delete this._events[t],this._eventsCount=Math.max(0,this._eventsCount-1)):(this._events=Object.create(null),this._eventsCount=0)}return this}static get buildFlags(){const e="browser-esm";return{SALESFORCE_BUILD:"undefined"!=typeof __SALESFORCE_BUILD__&&__SALESFORCE_BUILD__,INCLUDE_WS_REQUIRE:!1,SDK_VERSION:"3.2.3",WEBPACK_BUILD_TARGET:e,WEBPACK_BUILD_TARGET_NORMALIZED:K.normalize(e),BUILD_TARGET_INFO:K.getInfo(e)}}}const J=Y;export{J as default};
\ No newline at end of file
+class e extends EventTarget{constructor(){super(),this._events={},this._eventsCount=0}on(e,t){this._events[e]||(this._events[e]=[]),this._events[e].push(t),this._eventsCount++;const s=e=>{e.detail&&Array.isArray(e.detail)?t(...e.detail):t(e.detail||e)};return t._wrapped=s,this.addEventListener(e,s),this}off(e,t){if(this._events[e]){const s=this._events[e].indexOf(t);s>-1&&(this._events[e].splice(s,1),this._eventsCount--,0===this._events[e].length&&delete this._events[e])}return t._wrapped&&(this.removeEventListener(e,t._wrapped),delete t._wrapped),this}removeListener(e,t){return this.off(e,t)}emit(e,...t){const s=new CustomEvent(e,{detail:t});return this.dispatchEvent(s),this}once(e,t){const s=(...r)=>{this.off(e,s),t(...r)};return this.on(e,s)}listenerCount(e){return this._events[e]?this._events[e].length:0}removeAllListeners(e){if(e){if(this._events[e]){const t=this._events[e].length;this._events[e].forEach(t=>{t._wrapped&&(this.removeEventListener(e,t._wrapped),delete t._wrapped)}),delete this._events[e],this._eventsCount=Math.max(0,this._eventsCount-t)}}else Object.keys(this._events).forEach(e=>this.removeAllListeners(e)),this._eventsCount=0;return this}}const t=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;const s=function(e){return"string"==typeof e&&t.test(e)};const r=function(e){if(!s(e))throw TypeError("Invalid UUID");let t;return Uint8Array.of((t=parseInt(e.slice(0,8),16))>>>24,t>>>16&255,t>>>8&255,255&t,(t=parseInt(e.slice(9,13),16))>>>8,255&t,(t=parseInt(e.slice(14,18),16))>>>8,255&t,(t=parseInt(e.slice(19,23),16))>>>8,255&t,(t=parseInt(e.slice(24,36),16))/1099511627776&255,t/4294967296&255,t>>>24&255,t>>>16&255,t>>>8&255,255&t)};const n=[];for(let e=0;e<256;++e)n.push((e+256).toString(16).slice(1));function o(e,t=0){return(n[e[t+0]]+n[e[t+1]]+n[e[t+2]]+n[e[t+3]]+"-"+n[e[t+4]]+n[e[t+5]]+"-"+n[e[t+6]]+n[e[t+7]]+"-"+n[e[t+8]]+n[e[t+9]]+"-"+n[e[t+10]]+n[e[t+11]]+n[e[t+12]]+n[e[t+13]]+n[e[t+14]]+n[e[t+15]]).toLowerCase()}const i=new Uint8Array(16);function a(){return crypto.getRandomValues(i)}function c(e){return 14+(e+64>>>9<<4)+1}function d(e,t){const s=(65535&e)+(65535&t);return(e>>16)+(t>>16)+(s>>16)<<16|65535&s}function u(e,t,s,r,n,o){return d((i=d(d(t,e),d(r,o)))<<(a=n)|i>>>32-a,s);var i,a}function l(e,t,s,r,n,o,i){return u(t&s|~t&r,e,t,n,o,i)}function h(e,t,s,r,n,o,i){return u(t&r|s&~r,e,t,n,o,i)}function p(e,t,s,r,n,o,i){return u(t^s^r,e,t,n,o,i)}function m(e,t,s,r,n,o,i){return u(s^(t|~r),e,t,n,o,i)}const f=function(e){return function(e){const t=new Uint8Array(4*e.length);for(let s=0;s<4*e.length;s++)t[s]=e[s>>2]>>>s%4*8&255;return t}(function(e,t){const s=new Uint32Array(c(t)).fill(0);s.set(e),s[t>>5]|=128<>2]|=(255&e[s])<i.length)throw new RangeError(`UUID byte range ${a}:${a+15} is out of buffer bounds`);for(let e=0;e<16;++e)i[a+e]=u[e];return i}return o(u)}function b(e,t,s,r){return E(48,f,e,t,s,r)}b.DNS=g,b.URL=y;function v(e,t,s,r){switch(e){case 0:return t&s^~t&r;case 1:case 3:return t^s^r;case 2:return t&s^t&r^s&r}}function S(e,t){return e<>>32-t}const _=function(e){const t=[1518500249,1859775393,2400959708,3395469782],s=[1732584193,4023233417,2562383102,271733878,3285377520],r=new Uint8Array(e.length+1);r.set(e),r[e.length]=128;const n=(e=r).length/4+2,o=Math.ceil(n/16),i=new Array(o);for(let t=0;t>>0;d=c,c=a,a=S(o,30)>>>0,o=n,n=i}s[0]=s[0]+n>>>0,s[1]=s[1]+o>>>0,s[2]=s[2]+a>>>0,s[3]=s[3]+c>>>0,s[4]=s[4]+d>>>0}return Uint8Array.of(s[0]>>24,s[0]>>16,s[0]>>8,s[0],s[1]>>24,s[1]>>16,s[1]>>8,s[1],s[2]>>24,s[2]>>16,s[2]>>8,s[2],s[3]>>24,s[3]>>16,s[3]>>8,s[3],s[4]>>24,s[4]>>16,s[4]>>8,s[4])};function w(e,t,s,r){return E(80,_,e,t,s,r)}w.DNS=g,w.URL=y;const I={};function A(e,t,s,r,n=0){if(e.length<16)throw new Error("Random bytes length must be >= 16");if(r){if(n<0||n+16>r.length)throw new RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`)}else r=new Uint8Array(16),n=0;return t??=Date.now(),s??=T(e),r[n++]=t/1099511627776&255,r[n++]=t/4294967296&255,r[n++]=t/16777216&255,r[n++]=t/65536&255,r[n++]=t/256&255,r[n++]=255&t,r[n++]=112|s>>>28&15,r[n++]=s>>>20&255,r[n++]=128|s>>>14&63,r[n++]=s>>>6&255,r[n++]=s<<2&255|3&e[10],r[n++]=e[11],r[n++]=e[12],r[n++]=e[13],r[n++]=e[14],r[n++]=e[15],r}function T(e){return(127&e[6])<<24|e[7]<<16|e[8]<<8|e[9]}const O=function(e,t,s){let r;if(e)r=A(e.random??e.rng?.()??a(),e.msecs,e.seq,t,s);else{const e=Date.now(),n=a();!function(e,t,s){e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=T(s),e.msecs=t):(e.seq=e.seq+1|0,0===e.seq&&e.msecs++)}(I,e,n),r=A(n,I.msecs,I.seq,t,s)}return t??o(r)};function k(e,t,s="validation",r={}){return{instancePath:e,message:t,keyword:s,params:r}}function R(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[k("","must be object","type",{type:"object"})]};const t=[];if(e.session?"object"!=typeof e.session?t.push(k("/session","must be object","type",{type:"object"})):void 0!==e.session.sessionId&&"string"!=typeof e.session.sessionId&&t.push(k("/session/sessionId","must be string","type",{type:"string"})):t.push(k("/session","is required","required",{missingProperty:"session"})),e.request)if("object"!=typeof e.request)t.push(k("/request","must be object","type",{type:"object"}));else{if(e.request.connections)if("object"!=typeof e.request.connections)t.push(k("/request/connections","must be object","type",{type:"object"}));else{e.request.connections.threadId?"string"!=typeof e.request.connections.threadId&&t.push(k("/request/connections/threadId","must be string","type",{type:"string"})):t.push(k("/request/connections/threadId","is required","required",{missingProperty:"threadId"})),void 0!==e.request.connections.parentId&&"string"!=typeof e.request.connections.parentId&&t.push(k("/request/connections/parentId","must be string","type",{type:"string"})),void 0!==e.request.connections.replyId&&"string"!=typeof e.request.connections.replyId&&t.push(k("/request/connections/replyId","must be string","type",{type:"string"}));const{replyTarget:s}=e.request.connections;if(void 0!==s){const e=["ai","self","none"];"string"!=typeof s?t.push(k("/request/connections/replyTarget","must be string","type",{type:"string"})):e.includes(s)||t.push(k("/request/connections/replyTarget","must be equal to one of the allowed values","enum",{allowedValues:e}))}}else t.push(k("/request/connections","is required","required",{missingProperty:"connections"}));if(void 0!==e.request.context&&"object"!=typeof e.request.context&&t.push(k("/request/context","must be object","type",{type:"object"})),void 0!==e.request.attributes&&"object"!=typeof e.request.attributes)t.push(k("/request/attributes","must be object","type",{type:"object"}));else if(e.request.attributes&&"object"==typeof e.request.attributes){const{replyTo:s}=e.request.attributes;if(void 0!==s){const e=["ai","self","none"];"string"!=typeof s?t.push(k("/request/attributes/replyTo","must be string","type",{type:"string"})):e.includes(s)||t.push(k("/request/attributes/replyTo","must be equal to one of the allowed values","enum",{allowedValues:e}))}}void 0!==e.request.scope&&("object"!=typeof e.request.scope?t.push(k("/request/scope","must be object","type",{type:"object"})):void 0!==e.request.scope.conversations&&(Array.isArray(e.request.scope.conversations)||t.push(k("/request/scope/conversations","must be array","type",{type:"array"})))),void 0!==e.request.resources&&("object"!=typeof e.request.resources?t.push(k("/request/resources","must be object","type",{type:"object"})):void 0!==e.request.resources.offers&&(Array.isArray(e.request.resources.offers)||t.push(k("/request/resources/offers","must be array","type",{type:"array"}))))}else t.push(k("/request","is required","required",{missingProperty:"request"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function q(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[k("","must be object","type",{type:"object"})]};const t=[];if(e.headers)if("object"!=typeof e.headers)t.push(k("/headers","must be object","type",{type:"object"}));else{if(e.headers.correlationId?"string"!=typeof e.headers.correlationId&&t.push(k("/headers/correlationId","must be string","type",{type:"string"})):t.push(k("/headers/correlationId","is required","required",{missingProperty:"correlationId"})),e.headers.action)if("string"!=typeof e.headers.action)t.push(k("/headers/action","must be string","type",{type:"string"}));else{const s=["adjust","elevate","interaction","assistant","customerinteraction","reception","summarize","translate","recommend","insights"];s.includes(e.headers.action)||t.push(k("/headers/action","must be equal to one of the allowed values","enum",{allowedValues:s}))}else t.push(k("/headers/action","is required","required",{missingProperty:"action"}));void 0!==e.headers.identifier&&"string"!=typeof e.headers.identifier&&t.push(k("/headers/identifier","must be string","type",{type:"string"})),void 0!==e.headers.schemaRef&&"string"!=typeof e.headers.schemaRef&&t.push(k("/headers/schemaRef","must be string","type",{type:"string"})),void 0!==e.headers.timestamp&&"string"!=typeof e.headers.timestamp&&t.push(k("/headers/timestamp","must be string","type",{type:"string"}))}else t.push(k("/headers","is required","required",{missingProperty:"headers"}));if(e.payload){if("object"!=typeof e.payload)t.push(k("/payload","must be object","type",{type:"object"}));else if(e.headers&&e.headers.action&&e.payload){const{action:s}=e.headers;["adjust","elevate","interaction","assistant","customerinteraction","customerInteraction","summarize","translate","insights","recommend"].includes(s)&&(e.payload.request?e.payload.request.scope?e.payload.request.scope.conversations?Array.isArray(e.payload.request.scope.conversations)?0===e.payload.request.scope.conversations.length&&t.push(k("/payload/request/scope/conversations",`must be non-empty array for ${s}`,"minItems",{limit:1})):t.push(k("/payload/request/scope/conversations","must be array","type",{type:"array"})):t.push(k("/payload/request/scope/conversations",`is required for ${s}`,"required",{missingProperty:"conversations"})):t.push(k("/payload/request/scope","is required","required",{missingProperty:"scope"})):t.push(k("/payload/request","is required","required",{missingProperty:"request"})))}}else t.push(k("/payload","is required","required",{missingProperty:"payload"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}const C=`optave.message.v${"1.0.0".split(".")[0]}`,N={AUTHENTICATION:"AUTHENTICATION",ORCHESTRATOR:"ORCHESTRATOR",VALIDATION:"VALIDATION",WEBSOCKET:"WEBSOCKET"},U=Object.freeze({MESSAGE:"message",ERROR:"error"}),P=Object.freeze({CONNECTION_OPEN:"connection:open",CONNECTION_CLOSE:"connection:close",CONNECTION_ERROR:"connection:error",MESSAGE_RECEIVED:"message:received",MESSAGE_SENT:"message:sent",ERROR:"error",RESPONSE:"response",LEGACY_ERROR:"error",LEGACY_MESSAGE:"message"}),W=Object.freeze({SUPERPOWER_RESPONSE:"superpower.response",SUPERPOWER_ERROR:"superpower.error"}),D=new Set(["adjust","elevate","interaction","assistant","reception","customerInteraction","summarize","translate","recommend","insights"]),L={SPEC_VERSION:"1.0.0",SCHEMA_REF:C,MAX_PAYLOAD_SIZE:131072,MAX_PAYLOAD_SIZE_KB:128,DEFAULT_REQUEST_TIMEOUT_MS:3e4,ErrorCategory:N,LegacyEvents:U,EVENTS:P,InboundEvents:W,ALLOWED_ACTIONS:D};function M(e){const t=[];if((()=>{if("undefined"!=typeof process&&process.versions,"undefined"!=typeof globalThis){if("window"in globalThis||"document"in globalThis||"undefined"!=typeof process&&process.versions,(!("window"in globalThis)||!("document"in globalThis))&&"undefined"!=typeof process&&process.versions,"window"in globalThis&&globalThis.window)return!0;if("document"in globalThis&&globalThis.document)return!0}try{if("undefined"!=typeof window&&null!==window)return("undefined"==typeof globalThis||"window"in globalThis)&&("undefined"!=typeof globalThis&&"undefined"!=typeof process&&process.versions,!0);if("undefined"!=typeof document&&null!==document)return("undefined"==typeof globalThis||"document"in globalThis)&&("undefined"!=typeof globalThis&&"undefined"!=typeof process&&process.versions,!0)}catch(e){}return"undefined"!=typeof navigator&&"ReactNative"===navigator.product||!("undefined"==typeof globalThis||!globalThis.__expo)||void 0!==globalThis.location&&null!==globalThis.location||("undefined"!=typeof process&&process.versions,!1)})()&&e.clientSecret){let e=!1,s=!1;try{e=!0===__SALESFORCE_BUILD__}catch(e){}try{s=!1}catch(e){}e||s||t.push({type:"error",code:"CLIENT_SECRET_IN_CLIENT_ENV",message:"clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.",field:"clientSecret"})}return t}const $=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i,j=/^\s*-?\d{1,3}(?:\.\d+)?\s*,\s*-?\d{1,3}(?:\.\d+)?\s*$/,V=new Set(["email","e-mail","fullname","firstname","lastname","displayname","phone","phonenumber","ssn","dateofbirth","dob","nationalid"]);function B(e,t,s={}){return{instancePath:e,message:t,keyword:"piGuard",params:s}}function K(e,t,s){null!=e&&("string"!=typeof e?Array.isArray(e)?e.forEach((e,r)=>K(e,`${t}/${r}`,s)):"object"==typeof e&&Object.entries(e).forEach(([e,r])=>{V.has(e.toLowerCase())&&s.push(B(`${t}/${e}`,`must not carry direct identifier key '${e}'`,{kind:"identifierKey",key:e})),K(r,`${t}/${e}`,s)}):function(e,t,s){"string"==typeof e&&0!==e.length&&($.test(e)&&s.push(B(t,"must not contain an email address",{kind:"email"})),j.test(e)&&s.push(B(t,"must not contain precise coordinates",{kind:"coordinates"})),function(e){if("string"!=typeof e)return!1;const t=e.trim();return!!(t.includes("\n")&&t.length>40)||!!(t.length>160&&/\s/.test(t)&&/[.!?]/.test(t))}(e)&&s.push(B(t,"must not contain message content or other direct identifiers",{kind:"messageContent"})))}(e,t,s))}function z(e){if(!e||"object"!=typeof e)return{valid:!0,errors:null};const t=[],s=e.session?.channel?.location;return"string"==typeof s&&s&&j.test(s)&&t.push(B("/session/channel/location","must be province grain at most, never precise coordinates",{kind:"coordinates"})),void 0!==e.session?.channel?.metadata&&K(e.session.channel.metadata,"/session/channel/metadata",t),void 0!==e.request?.reference&&K(e.request.reference,"/request/reference",t),t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function H(e){return t=>{const s=e(t);return s.valid?z(t):s}}const F={BROWSER_ESM:"browser-esm",SERVER_ESM:"server-esm",BROWSER_UMD:"browser-umd",SERVER_UMD:"server-umd"},G={browser:F.BROWSER_ESM,server:F.SERVER_ESM},x={BROWSER:[F.BROWSER_ESM,F.BROWSER_UMD],SERVER:[F.SERVER_ESM,F.SERVER_UMD],UMD:[F.BROWSER_UMD,F.SERVER_UMD],ESM:[F.BROWSER_ESM,F.SERVER_ESM]},Y={isValid:e=>Object.values(F).includes(e)||Object.keys(G).includes(e),normalize:e=>G[e]?G[e]:Object.values(F).includes(e)?e:"unknown",isBrowser(e){const t=this.normalize(e);return x.BROWSER.includes(t)},isServer(e){const t=this.normalize(e);return x.SERVER.includes(t)},isUMD(e){const t=this.normalize(e);return x.UMD.includes(t)},isESM(e){const t=this.normalize(e);return x.ESM.includes(t)},getInfo(e){return{original:e,normalized:this.normalize(e),valid:this.isValid(e),isBrowser:this.isBrowser(e),isServer:this.isServer(e),isUMD:this.isUMD(e),isESM:this.isESM(e)}}};class J extends Error{constructor({category:e,code:t,message:s,details:r}){super(s),this.name="OptaveError",this.category=e||"UNKNOWN",this.code=t||"UNKNOWN",void 0!==r&&(this.details=r)}}!function(){if("undefined"!=typeof globalThis){globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__=!0;if(!globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__)throw new Error("Security guard initialization failed")}}(),"undefined"!=typeof window?window.__OPTAVE_SECURITY_GUARDS_BROWSER__=!0:"undefined"!=typeof globalThis&&(globalThis.__OPTAVE_SECURITY_GUARDS_NODE__=!0);const Q="3.6.0",Z=()=>{const e="browser-esm";return{isBrowser:Y.isBrowser(e),isServer:Y.isServer(e),buildTarget:e}};let X=!1,ee=!1;class te extends e{options={};wss=null;static defaultPayload={session:{sessionId:"",channel:{browser:"",deviceInfo:"",deviceType:"",language:"",location:"",medium:"chat",metadata:[],section:""},interface:{appVersion:"",category:"",language:"",name:"",type:""}},request:{requestId:"",attributes:{content:"",instruction:"",variant:"A"},connections:{journeyId:"",parentId:"",replyId:"",threadId:""},context:{caseId:"",departmentId:"",operatorId:"",organizationId:"",userId:""},reference:{ids:[{name:"",value:""}],labels:[],tags:[]},resources:{codes:[{id:"",label:"",type:"",value:""}],links:[{expires_at:"",html:!1,id:"",label:"",type:"",url:""}],offers:[]},scope:{accounts:[],appointments:[],assets:[],bookings:[],cases:[],conversations:[],documents:[],events:[],interactions:[],items:[],locations:[],operators:[],orders:[],organizations:[],persons:[],policies:[],products:[{id:""}],properties:[],services:[],subscriptions:[],tickets:[],transactions:[],users:[]},settings:{disableBrowsing:!1,disableSearch:!1,disableSources:!1,disableStream:!0,disableTools:!1,maxResponseLength:0,overrideInterfaceLanguage:"",overrideOutputLanguage:""},a2a:[{id:"",name:"",type:""}],cursor:{since:"",until:""}}};static cleanup(){X=!1,ee=!1}constructor(e){if(super(),this.options={...e},function(e){if(void 0===e.strictValidation){const t="undefined"!=typeof process&&process.env?"production":"development";e.strictValidation="production"!==t}if("number"!=typeof e.requestTimeoutMs&&(e.requestTimeoutMs=3e4),"number"!=typeof e.connectionTimeoutMs&&(e.connectionTimeoutMs=3e4),e.logger||(e.logger={debug(){},info(){},warn(){},error(){}}),e.authTransport||(e.authTransport="subprotocol"),void 0===e.authRequired&&(e.authRequired=!0),!e.tokenProvider){let t=e.tokenUrl;if(!t&&"undefined"!=typeof document){const e=document.querySelector('meta[name="optave-token-url"]');e&&e.content&&(t=e.content)}t||(t="/api/optave/ws-ticket"),e.tokenProvider=async()=>{const s={};e.publishableKey&&(s["X-Optave-Publishable-Key"]=e.publishableKey);const r=await fetch(t,{method:"POST",credentials:"include",headers:s});if(!r.ok)throw new Error("Failed to obtain WS token");const n=await r.json();return n.token||n.access_token}}}(this.options),void 0===this.options.cspSafe){const e=Z();"server-esm"===e.buildTarget||"server"===e.buildTarget?this.options.cspSafe=!1:("browser-esm"===e.buildTarget||"browser-umd"===e.buildTarget||"server-umd"===e.buildTarget||e.isBrowser||(()=>{const e=Z();return"unknown"!==e.buildTarget?e.isBrowser:"undefined"!=typeof window&&void 0!==window.WebSocket})())&&(this.options.cspSafe=!0)}const t=function(e){const t={isValid:!0,errors:[],warnings:[]},s=function(e){const t=[];return e.websocketUrl&&"string"==typeof e.websocketUrl||t.push({type:"warning",code:"MISSING_WEBSOCKET_URL",message:"websocketUrl not provided; openConnection() will emit an error.",field:"websocketUrl"}),t}(e),r=function(e){const t=[];return!e.authenticationUrl||e.clientId&&e.clientSecret||t.push({type:"warning",code:"INCOMPLETE_AUTH_CONFIG",message:"authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.",field:"authentication"}),t}(e);return[...s,...r,...M(e)].forEach(e=>{"error"===e.type?(t.errors.push(e),t.isValid=!1):"warning"===e.type&&t.warnings.push(e)}),t}(this.options);if(!t.isValid){const e=t.errors.map(e=>e.message).join("; ");throw new Error(`[Optave SDK] Configuration errors: ${e}`)}t.warnings.forEach(e=>{(this.options?.logger?.warn||console.warn)(`[Optave SDK] ${e.message}`)});!function(e,t,s={}){if(!e||"string"!=typeof e)return;const r=Y.normalize(t),n=Y.isBrowser(r);if(n&&e.startsWith("ws://"))throw new Error(`[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in browser builds. Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. Please use secure WebSocket protocol (wss://) instead. Current URL: ${e}`);const o=Y.isUMD(r);if(n&&o&&e.startsWith("wss://")){const t="function"==typeof s.tokenProvider,r=!1===s.authRequired;if(!t&&!r)throw new Error(`[Optave SDK] Browser UMD builds require a tokenProvider function for secure WebSocket connections. In constrained environments like Salesforce Lightning, authentication tokens must be obtained from your backend server. Please provide options.tokenProvider() that returns a valid token, or set options.authRequired = false to disable authentication. Current URL: ${e}`)}}(this.options.websocketUrl,"browser-esm",this.options);const s=Z();this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&s.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&s.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this._pending=new Map,this._deprecatedKeys=new Set,this._silenceDeprecations="undefined"!=typeof process&&"1"===process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS,this.options.cspSafe,this._validatePayload=H(R),this._validateMessageEnvelope=q}async _ensureWebSocketImpl(){if(this.WebSocketImpl)return this.WebSocketImpl;const e=Z();return this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&e.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&e.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this.WebSocketImpl||(e.isBrowser?this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:null:e.isServer&&(this.WebSocketImpl=await this.loadNodeWebSocket())),this.WebSocketImpl}async loadNodeWebSocket(){const e=Z();return e.isBrowser?null:"unknown"!==e.buildTarget||"undefined"==typeof window&&"undefined"==typeof document&&"undefined"==typeof navigator&&void 0===globalThis.location?("undefined"==typeof process||process.versions,null):null}static getSdkVersion(){return Q}static getSpecVersion(){return"1.0.0"}static getSchemaRef(){return C}static get CONSTANTS(){return L}static get LegacyEvents(){return U}static get InboundEvents(){return W}setSessionId(e){return this.sessionId=e,this}getSessionId(){return this.sessionId||""}validate(e){return this._validatePayload(e).valid}validateEnvelope(e){return this._validateMessageEnvelope(e).valid}_validateOutboundPayload(e){return this.options.strictValidation?this._validatePayload(e):z(e)}validateRequiredFields(e,t){const s=[];switch(e.request?.connections?.threadId||s.push("request.connections.threadId is required"),t){case"adjust":e.request?.attributes?.content||s.push("request.attributes.content is required for adjust"),e.request?.attributes?.instruction||s.push("request.attributes.instruction is required for adjust"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for adjust"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for adjust and must be a non-empty array");break;case"elevate":e.request?.attributes?.content||s.push("request.attributes.content is required for elevate"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for elevate"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for elevate and must be a non-empty array");break;case"translate":case"summarize":case"insights":case"customerinteraction":case"customerInteraction":case"interaction":case"assistant":e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push(`request.scope.conversations is required for ${t} and must be a non-empty array`);break;case"recommend":e.request?.resources?.offers&&Array.isArray(e.request.resources.offers)&&0!==e.request.resources.offers.length||s.push("request.resources.offers is required for recommend and must be a non-empty array"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for recommend and must be a non-empty array")}return{isValid:0===s.length,errors:s}}async authenticate(){if(Y.isBrowser("browser-esm"))return this.handleError(N.AUTHENTICATION,"UNSUPPORTED_IN_BROWSER","authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend."),null;const e={grant_type:"client_credentials"};if(!this.options.authenticationUrl)return this.handleError(N.AUTHENTICATION,"INVALID_AUTHENTICATION_URL","Empty or invalid authentication URL"),null;if(!this.options.clientId)return this.handleError(N.AUTHENTICATION,"INVALID_CLIENT_ID","Empty or invalid client ID"),null;e.client_id=this.options.clientId,e.client_secret=this.options.clientSecret;const t=new URLSearchParams(e).toString();let s=this.options.authenticationUrl;s.endsWith("/token")||(s=s.endsWith("/")?`${s}token`:`${s}/token`);const r=`${s}?${t}`,n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"}}),o=await n.json();return n.ok?o.access_token:(this.handleError(N.AUTHENTICATION,"INVALID_AUTHENTICATION_RESPONSE",this.formatAuthenticationError(n,o.error,"token endpoint").message,o.error),null)}async openConnection(e){if(!this.options.websocketUrl)return(this.options?.logger?.error||console.error)("[Optave SDK] openConnection aborted: missing websocketUrl"),void this.handleError(N.WEBSOCKET,"INVALID_WEBSOCKET_URL",this.formatWebSocketError(new Error("Invalid WebSocket URL configuration"),{url:this.options.websocketUrl}).message,this.options.websocketUrl);const t=await(async()=>{if("string"==typeof e&&e.length>0)return e;if("function"==typeof this.options.tokenProvider)try{return await this.options.tokenProvider()}catch(e){return this.handleError(N.AUTHENTICATION,"TOKEN_PROVIDER_FAILED",this.formatTokenProviderError(e).message,e),null}return null})();if(await this._ensureWebSocketImpl(),!this.WebSocketImpl)return void this.handleError(N.WEBSOCKET,"NO_WEBSOCKET_IMPL",this.formatWebSocketError(new Error("No WebSocket implementation available"),{environment:"undefined"!=typeof window?"browser":"node"}).message);if(!t&&!1!==this.options.authRequired)return void this.handleError(N.AUTHENTICATION,"MISSING_TOKEN","No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.");const s=new URLSearchParams;this.sessionId&&s.set("OptaveTraceChatSessionId",this.sessionId);try{if("subprotocol"===this.options.authTransport){const e=t?["optave-v1",t]:["optave-v1"];this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl,e)}else{if(t){const e=t.replace(/^Bearer\s+/i,"");s.set("Authorization",e)}this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl),t&&this._warnOnce("_warnedQueryToken",'[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".')}}catch(e){return(this.options?.logger?.error||console.error)("[Optave SDK] WebSocket constructor threw",e),void this.handleError(N.WEBSOCKET,"WEBSOCKET_ERROR",this.formatWebSocketError(e,{url:this.options.websocketUrl}).message,e)}return new Promise((e,t)=>{const s=setTimeout(()=>{const e=this.options.connectionTimeoutMs||3e4,s=this.formatWebSocketError(new Error("Connection timeout"),{timeout:e,url:this.options.websocketUrl}).message;if(this.wss){this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null;try{this.wss.close()}catch(e){}this.wss=null}this.handleError(N.WEBSOCKET,"CONNECTION_TIMEOUT",s),t(new J({category:N.WEBSOCKET,code:"CONNECTION_TIMEOUT",message:s,details:null}))},this.options.connectionTimeoutMs||3e4);this.wss.onopen=t=>{clearTimeout(s),this.emit("open",t),e(t)},this.wss.onmessage=e=>{this._handleInbound(e.data)},this.wss.onclose=e=>{clearTimeout(s),this.emit("close",e),Array.from(this._pending.entries()).forEach(([t,s])=>{s.timer&&clearTimeout(s.timer),s._handled=!0,s.reject({category:N.WEBSOCKET,code:"CONNECTION_CLOSED",message:`WebSocket connection closed: ${e.reason||"Connection lost"}`,details:{code:e.code,reason:e.reason,correlationId:t},correlationId:t})}),this._pending.clear(),this.wss=null},this.wss.onerror=e=>{clearTimeout(s);const r=e.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||"WebSocket connection failed",n={category:N.WEBSOCKET,code:"CONNECTION_ERROR",message:r,details:{originalError:e}};Array.from(this._pending.entries()).forEach(([e,t])=>{t.timer&&clearTimeout(t.timer),t._handled=!0,t.reject({...n,details:{...n.details,correlationId:e},correlationId:e})}),this._pending.clear(),this.emit("error",n),t(n)}})}_warnOnce(e,t){this[e]||(this[e]=!0,(this.options?.logger?.warn||console.warn)(t))}deprecate(e,t){this._silenceDeprecations||this._deprecatedKeys.has(e)||(this._deprecatedKeys.add(e),(this.options?.logger?.warn||console.warn)(t))}_handleInbound(e){let t;try{t="string"==typeof e?JSON.parse(e):e}catch(e){const t={category:N.WEBSOCKET,code:"INVALID_JSON",message:"Invalid JSON received from server",details:e,timestamp:(new Date).toISOString()};return void this._emitError(t)}const s=t&&t.headers&&t.payload,r="error"===t?.state||"error"===t?.actionType||!!t?.error;if(this.options.strictValidation&&s){const e=this._validateMessageEnvelope(t);e.valid||this.handleError(N.VALIDATION,"INBOUND_ENVELOPE_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Inbound envelope validation failed"),e.errors)}if(r){const e=t?.headers&&t.headers.correlationId||t?.correlationId||null,s={category:N.ORCHESTRATOR,code:t?.error?.code||"REMOTE_ERROR",message:t?.error?.message||t?.message||"Remote error",details:t?.error||t,correlationId:e};if(e&&this._pending.has(e)){const t=this._pending.get(e);t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),t.reject(s)}return void this._emitError(s,t?.action)}const n=t?.headers?.correlationId||t?.correlationId;if(n&&this._pending.has(n)){const e=this._pending.get(n);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(n),e.resolve(t)}this.emit(U.MESSAGE,t),X||(X=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".')),this.emit(W.SUPERPOWER_RESPONSE,t),this.emit(P.RESPONSE,t),t?.action&&this.emit(`message.${t.action}`.toLowerCase(),t),s&&t.headers.schemaRef&&this.emit(t.headers.schemaRef,t)}_emitError(e,t=null){e.timestamp||(e.timestamp=(new Date).toISOString()),this.emit(U.ERROR,e),ee||(ee=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'));const s=(r=e)&&r.category&&r.code&&r.message?new J(r):"string"==typeof r?new J({category:"UNKNOWN",code:"STRING_ERROR",message:r}):r&&r.isAuthError?new J({category:"AUTHENTICATION",code:r.code||"AUTH_ERROR",message:r.message||"Authentication error",details:r}):r&&r.isWsError?new J({category:"WEBSOCKET",code:r.code||"WS_ERROR",message:r.message||"WebSocket error",details:r}):new J({category:"UNKNOWN",code:"UNCLASSIFIED",message:r&&r.message||String(null!=r?r:"Unknown error"),details:r});var r;this.emit(W.SUPERPOWER_ERROR,s),this.emit(P.ERROR,e)}closeConnection(){this.wss&&(this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null,this.wss.close(),this.wss=null)}selectiveDeepMerge(e,t){if(Array.isArray(e)&&Array.isArray(t))return[...t];const s=e=>null!==e&&"object"==typeof e&&!Array.isArray(e);if(s(e)&&s(t)){const s={...e};return Object.keys(t).forEach(r=>{s[r]=r in e?this.selectiveDeepMerge(e[r],t[r]):t[r]}),s}return void 0!==t?t:e}isPayloadSizeValid(e){return!!e&&e.length/1024<=L.MAX_PAYLOAD_SIZE_KB}openConnectionAsync(e){return new Promise((t,s)=>{let r;const n=e=>{this.off("error",r),t(e)};r=e=>{this.off("open",n),s(e)},this.once("open",n),this.once("error",r),this.openConnection(e)})}buildPayload(e,t,s){const r=this.selectiveDeepMerge(te.defaultPayload,s);return s?.request?.variation&&(this.deprecate("payload.request.variation","[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."),r.request.attributes.variant=s.request.variation),s?.request?.content&&!r.request?.attributes?.content&&(r.request.attributes.content=s.request.content,this.deprecate("payload.request.content","[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.")),r.request.attributes.variant&&(r.request.attributes.variant=r.request.attributes.variant.toUpperCase()),r}resolveMessageId(e,t){return`${t}.${e}.v3`.toLowerCase()}buildMessageEnvelope(e,t,s,r={}){const n=(new Date).toISOString(),o=r.correlationId||e?.request?.requestId||O(),i=r.traceId||O(),a=r.idempotencyKey||O(),{timestamp:c}=r,d={correlationId:o,action:s,schemaRef:C,sdkVersion:Q,identifier:t,traceId:i,idempotencyKey:a,timestamp:c,issuedAt:n};return this.options.tenantId&&(d.tenantId=this.options.tenantId),void 0!==r.networkLatencyMs&&(d.networkLatencyMs=r.networkLatencyMs),Object.freeze(d),{action:"message",headers:d,payload:e}}formatValidationErrorMessage(e,t="Validation failed"){if(!e||!Array.isArray(e)||0===e.length)return t;if(1===e.length){const s=e[0],r=s.instancePath||"/",n="/"===r?"root object":r.replace(/^\//,"").replace(/\//g,".");if("required"===s.keyword){const e=s.params?.missingProperty||"unknown field";let r;return r="root object"===n?e:n.endsWith(e)?n:`${n}.${e}`,`${t}: ${"root object"===n?"Required field":"Field"} '${r}' is missing`}if("type"===s.keyword){return`${t}: Field '${n}' must be of type '${s.params?.type||"unknown"}'`}if("additionalProperties"===s.keyword){return`${t}: Field '${n}.${s.params?.additionalProperty||"unknown"}' is not allowed`}if("enum"===s.keyword){const e=s.params?.allowedValues||[];return`${t}: Field '${n}' must be one of: ${Array.isArray(e)?e.join(", "):"unknown values"}`}return`${t}: ${s.message} at '${n}'`}const s=e.filter(e=>"required"===e.keyword),r=e.filter(e=>"type"===e.keyword),n=e.filter(e=>"required"!==e.keyword&&"type"!==e.keyword);let o=`${t}:`;if(s.length>0){o+=` Missing required fields: ${s.map(e=>{const t=(e.instancePath||"/").replace(/^\//,"").replace(/\//g,"."),s=e.params?.missingProperty||"unknown";return""===t?s:`${t}.${s}`}).join(", ")}.`}if(r.length>0){o+=` Type errors in: ${r.slice(0,3).map(e=>`${(e.instancePath||"/").replace(/^\//,"").replace(/\//g,".")||"root"} (expected ${e.params?.type||"unknown"})`).join(", ")}.`,r.length>3&&(o+=` And ${r.length-3} more type errors.`)}return n.length>0&&(o+=` Additional validation errors: ${n.length}.`),o}formatAuthenticationError(e,t,s){let r="Authentication failed";const n=[];return e&&e.status&&(r+=` (HTTP ${e.status})`),t&&("string"==typeof t?r+=`: ${t}`:t.error_description?r+=`: ${t.error_description}`:t.message?r+=`: ${t.message}`:t.error&&(r+=`: ${t.error}`)),e&&401===e.status?(n.push("Verify clientId and clientSecret are correct"),n.push("Ensure credentials match the target environment (dev/staging/production)")):e&&403===e.status?(n.push("Check if your client has the necessary permissions"),n.push("Verify the authentication endpoint URL is correct")):e&&e.status>=500?(n.push("Authentication server error - try again later"),n.push("Contact support if the problem persists")):n.push("Check network connectivity and authentication endpoint configuration"),s&&s.authUrl&&(r+=` (endpoint: ${s.authUrl})`),{message:r,suggestions:n}}formatWebSocketError(e,t){let s="WebSocket connection failed";const r=[],n=e?.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||null;return n&&(s+=`: ${n}`),t&&(t.url&&(s+=` (URL: ${t.url})`),t.timeout&&(s+=` (timeout: ${t.timeout}ms)`)),r.push("Check network connectivity and firewall settings"),r.push("Verify WebSocket URL is correct and accessible"),t&&t.url&&(t.url.startsWith("ws://")&&r.push("Consider using secure WebSocket (wss://) for production"),(t.url.includes("localhost")||t.url.includes("127.0.0.1"))&&r.push("Ensure local server is running if connecting to localhost")),t&&t.timeout&&r.push("Try increasing connection timeout if network is slow"),{message:s,suggestions:r}}formatPayloadSizeError(e,t,s){const r=Math.ceil(e/1024),n=`Payload too large: ${r}KB exceeds maximum ${t}KB (${r-t}KB over limit)`,o=[];if(s&&"object"==typeof s){if(s.request?.scope?.conversations&&Array.isArray(s.request.scope.conversations)){const e=JSON.stringify(s.request.scope.conversations).length,t=Math.ceil(e/1024);t>10&&(o.push(`Consider reducing conversation history - current size: ~${t}KB`),o.push("Remove older messages or summarize conversation context"))}if(s.request?.resources?.offers&&Array.isArray(s.request.resources.offers)){const e=JSON.stringify(s.request.resources.offers).length,t=Math.ceil(e/1024);t>5&&o.push(`Consider reducing product offers data - current size: ~${t}KB`)}if(s.session?.channel?.metadata&&Array.isArray(s.session.channel.metadata)){const e=JSON.stringify(s.session.channel.metadata).length,t=Math.ceil(e/1024);t>2&&o.push(`Consider reducing metadata array - current size: ~${t}KB`)}}return 0===o.length&&(o.push("Remove unused fields from request payload"),o.push("Consider paginating large datasets"),o.push("Use shorter field values where possible")),{message:n,suggestions:o}}formatTokenProviderError(e,t){let s="Failed to obtain WebSocket token from tokenProvider()";const r=[];return e&&(e.message?s+=`: ${e.message}`:"string"==typeof e&&(s+=`: ${e}`),"TypeError"===e.name&&e.message?.includes("fetch")?(r.push("Check if tokenProvider endpoint is accessible"),r.push("Verify CORS settings allow requests to token endpoint")):e.message?.includes("404")||e.message?.includes("Not Found")?(r.push("Verify tokenProvider endpoint URL is correct"),r.push("Ensure backend token endpoint is implemented")):e.message?.includes("401")||e.message?.includes("403")?(r.push("Check authentication/authorization for token endpoint"),r.push("Verify user session or credentials are valid")):e.message?.includes("timeout")&&r.push("Token provider request timed out - check network or server response time")),t&&t.tokenUrl&&(s+=` (endpoint: ${t.tokenUrl})`),0===r.length&&(r.push("Verify tokenProvider function implementation"),r.push("Check backend token endpoint is running and accessible"),r.push("Review browser console for network errors")),{message:s,suggestions:r}}handleError(e,t,s,r=null,n=[],o=null){const i=new J({category:e,code:t,message:s,details:r});n&&(i.suggestions=n),o&&(i.correlationId=o),0===this.listenerCount(U.ERROR)&&0===this.listenerCount(P.ERROR)&&(this.options?.logger?.error||console.error)(`[Optave SDK] ${t}: ${s}`),this._emitError(i)}send(e,t,s){const r=null!=(this.WebSocketImpl&&this.WebSocketImpl.OPEN)?this.WebSocketImpl.OPEN:1;if(!this.wss||this.wss.readyState!==r){const e=this.wss?this.wss.readyState:"no connection";return void this.handleError(N.WEBSOCKET,"WEBSOCKET_NOT_IN_OPEN_STATE",this.formatWebSocketError(new Error("WebSocket not ready for sending"),{readyState:e,action:t}).message)}if(!D.has(t))return void this.handleError(N.VALIDATION,"INVALID_ACTION",`Unsupported action '${t}'. Allowed: ${[...D].join(", ")}`);const n=new Set(["session","request","headers"]),o=Object.keys(s||{});for(let e=0;e0&&(o=setTimeout(()=>{if(this._pending.has(e)){const r=this._pending.get(e);r&&!r._handled&&(this._pending.delete(e),r._handled=!0,n({category:N.WEBSOCKET,code:"REQUEST_TIMEOUT",message:`Request timed out after ${s}ms`,details:{correlationId:e,action:t},correlationId:e}))}},s)),this._pending.set(e,{resolve:r,reject:n,timer:o,action:t,_handled:!1})}_promiseSend(e,t,s={},r={}){let n;const o=new Promise((o,i)=>{let a;if(a="number"==typeof r.timeoutMs?r.timeoutMs:"number"==typeof r.timeout?r.timeout:this.options.requestTimeoutMs,!this.wss||this.wss.readyState!==WebSocket.OPEN){if(a<=0)return void i(new J({category:N.WEBSOCKET,code:"WEBSOCKET_NOT_IN_OPEN_STATE",message:"WebSocket not open",details:null}));const r=this.buildPayload(e,t,s),c=this.buildMessageEnvelope(r,e,t,s?.headers||{});return n=c.headers.correlationId,void this._registerPending(n,t,a,o,i)}if(!D.has(t))return void i(new J({category:N.VALIDATION,code:"INVALID_ACTION",message:`Unsupported action '${t}'.`,details:{allowed:[...D]}}));const c=new Set(["session","request","headers"]),d=Object.keys(s||{});for(let e=0;e{t.reject({category:N.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:e},correlationId:e})},0),!0}return!1}cancelPendingRequests(e=!1){if(!this._pending)return 0;const t=this._pending.size;return[...this._pending.entries()].forEach(([t,s])=>{s.timer&&clearTimeout(s.timer),s._handled=!0,e?s.reject({category:N.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled during cleanup",details:{correlationId:t},correlationId:t}):queueMicrotask(()=>{s.reject({category:N.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:t},correlationId:t})})}),this._pending.clear(),t}cleanup(){this.closeConnection(),this.cancelPendingRequests(!0),this._deprecatedKeys&&this._deprecatedKeys.clear(),void 0!==this._warnedQueryToken&&delete this._warnedQueryToken,this._events&&Object.keys(this._events).forEach(e=>{delete this._events[e]}),this.removeAllListeners(),this._events=null,this._eventsCount=null,this._maxListeners=null;if(this.constructor._preservedJSDOM&&this.constructor._preservedJSDOM.dom)try{const e=this.constructor._preservedJSDOM.dom.window;e&&"function"==typeof e.close&&e.close(),delete this.constructor._preservedJSDOM}catch(e){}this._validatePayload=null,this._validateOutboundPayload=null,this._validateMessageEnvelope=null,this._emitError=null,this._ensureWebSocketImpl=null,this._handleInbound=null,this._promiseSend=null,this._registerPending=null,this._warnOnce=null,this.options=null,this.WebSocketImpl=null,this.wss=null,this.sessionId=null,this._pending=null,this._deprecatedKeys=null,this._silenceDeprecations=null,this._events=null,this._eventsCount=null,this._maxListeners=null}removeAllListeners(t){try{e.prototype.removeAllListeners.call(this,t)}catch(e){t?this._events&&this._events[t]&&(delete this._events[t],this._eventsCount=Math.max(0,this._eventsCount-1)):(this._events=Object.create(null),this._eventsCount=0)}return this}static get buildFlags(){const e="browser-esm";return{SALESFORCE_BUILD:"undefined"!=typeof __SALESFORCE_BUILD__&&__SALESFORCE_BUILD__,INCLUDE_WS_REQUIRE:!1,SDK_VERSION:"3.6.0",WEBPACK_BUILD_TARGET:e,WEBPACK_BUILD_TARGET_NORMALIZED:Y.normalize(e),BUILD_TARGET_INFO:Y.getInfo(e)}}}const se=te;export{se as default};
\ No newline at end of file
diff --git a/sdks/javascript/dist/browser.umd.js b/sdks/javascript/dist/browser.umd.js
index 891e5de..00898b3 100644
--- a/sdks/javascript/dist/browser.umd.js
+++ b/sdks/javascript/dist/browser.umd.js
@@ -1,15 +1,41 @@
-!function webpackUniversalModuleDefinition(root,factory){"object"==typeof exports&&"object"==typeof module?module.exports=factory():"function"==typeof define&&define.amd?define("OptaveJavaScriptSDK",[],factory):"object"==typeof exports?exports.OptaveJavaScriptSDK=factory():root.OptaveJavaScriptSDK=factory()}(function(){return"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:this}(),()=>(()=>{var e={31:(e,t,r)=>{r.d(t,{I:()=>n});class s{constructor(e){if(this.params=new Map,"string"==typeof e){const t=undefined;e.replace(/^\?/,"").split("&").forEach(e=>{if(e){const[t,r]=e.split("=");t&&this.params.set(decodeURIComponent(t),decodeURIComponent(r||""))}})}else e&&"object"==typeof e&&(e instanceof Map?e.forEach((e,t)=>{this.params.set(t,String(e))}):Array.isArray(e)?e.forEach(([e,t])=>{this.params.set(e,String(t))}):Object.entries(e).forEach(([e,t])=>{this.params.set(e,String(t))}))}append(e,t){const r=this.params.get(e);void 0!==r?this.params.set(e,r+","+String(t)):this.params.set(e,String(t))}delete(e){this.params.delete(e)}get(e){return this.params.get(e)||null}getAll(e){const t=this.params.get(e);return t?t.split(","):[]}has(e){return this.params.has(e)}set(e,t){this.params.set(e,String(t))}toString(){const e=[];return this.params.forEach((t,r)=>{const s=undefined;t.split(",").forEach(t=>{e.push(`${encodeURIComponent(r)}=${encodeURIComponent(t)}`)})}),e.join("&")}*[Symbol.iterator](){for(const[e,t]of this.params){const r=t.split(",");for(const t of r)yield[e,t]}}*keys(){for(const[e]of this)yield e}*values(){for(const[,e]of this)yield e}*entries(){yield*this}forEach(e,t){for(const[r,s]of this)e.call(t,s,r,this)}}const n="undefined"!=typeof globalThis&&globalThis.URLSearchParams||"undefined"!=typeof window&&window.URLSearchParams||s},46:e=>{var t="object"==typeof Reflect?Reflect:null,r=t&&"function"==typeof t.apply?t.apply:function e(t,r,s){return Function.prototype.apply.call(t,r,s)},s;function n(e){console&&console.warn&&console.warn(e)}s=t&&"function"==typeof t.ownKeys?t.ownKeys:Object.getOwnPropertySymbols?function e(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function e(t){return Object.getOwnPropertyNames(t)};var o=Number.isNaN||function e(t){return t!=t};function i(){i.init.call(this)}e.exports=i,e.exports.once=v,i.EventEmitter=i,i.prototype._events=void 0,i.prototype._eventsCount=0,i.prototype._maxListeners=void 0;var a=10;function c(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function d(e){return void 0===e._maxListeners?i.defaultMaxListeners:e._maxListeners}function u(e,t,r,s){var o,i,a;if(c(r),void 0===(i=e._events)?(i=e._events=Object.create(null),e._eventsCount=0):(void 0!==i.newListener&&(e.emit("newListener",t,r.listener?r.listener:r),i=e._events),a=i[t]),void 0===a)a=i[t]=r,++e._eventsCount;else if("function"==typeof a?a=i[t]=s?[r,a]:[a,r]:s?a.unshift(r):a.push(r),(o=d(e))>0&&a.length>o&&!a.warned){a.warned=!0;var u=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");u.name="MaxListenersExceededWarning",u.emitter=e,u.type=t,u.count=a.length,n(u)}return e}function l(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(e,t,r){var s={fired:!1,wrapFn:void 0,target:e,type:t,listener:r},n=l.bind(s);return n.listener=r,s.wrapFn=n,n}function h(e,t,r){var s=e._events;if(void 0===s)return[];var n=s[t];return void 0===n?[]:"function"==typeof n?r?[n.listener||n]:[n]:r?y(n):m(n,n.length)}function f(e){var t=this._events;if(void 0!==t){var r=t[e];if("function"==typeof r)return 1;if(void 0!==r)return r.length}return 0}function m(e,t){for(var r=new Array(t),s=0;s0&&(a=s[0]),a instanceof Error)throw a;var c=new Error("Unhandled error."+(a?" ("+a.message+")":""));throw c.context=a,c}var d=i[t];if(void 0===d)return!1;if("function"==typeof d)r(d,this,s);else for(var u=d.length,l=m(d,u),n=0;n=0;i--)if(s[i]===r||s[i].listener===r){a=s[i].listener,o=i;break}if(o<0)return this;0===o?s.shift():g(s,o),1===s.length&&(n[t]=s[0]),void 0!==n.removeListener&&this.emit("removeListener",t,a||r)}return this},i.prototype.off=i.prototype.removeListener,i.prototype.removeAllListeners=function e(t){var r,s,n;if(void 0===(s=this._events))return this;if(void 0===s.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==s[t]&&(0===--this._eventsCount?this._events=Object.create(null):delete s[t]),this;if(0===arguments.length){var o=Object.keys(s),i;for(n=0;n=0;n--)this.removeListener(t,r[n]);return this},i.prototype.listeners=function e(t){return h(this,t,!0)},i.prototype.rawListeners=function e(t){return h(this,t,!1)},i.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):f.call(e,t)},i.prototype.listenerCount=f,i.prototype.eventNames=function e(){return this._eventsCount>0?s(this._events):[]}}},t={};function r(s){var n=t[s];if(void 0!==n)return n.exports;var o=t[s]={exports:{}};return e[s](o,o.exports,r),o.exports}void(r.d=(e,t)=>{for(var s in t)r.o(t,s)&&!r.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})}),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var s={};r.d(s,{default:()=>le});var n=r(46);let o;const i=new Uint8Array(16);function a(){if(!o){if("undefined"==typeof crypto||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");o=crypto.getRandomValues.bind(crypto)}return o(i)}const c=[];for(let e=0;e<256;++e)c.push((e+256).toString(16).slice(1));function d(e,t=0){return(c[e[t+0]]+c[e[t+1]]+c[e[t+2]]+c[e[t+3]]+"-"+c[e[t+4]]+c[e[t+5]]+"-"+c[e[t+6]]+c[e[t+7]]+"-"+c[e[t+8]]+c[e[t+9]]+"-"+c[e[t+10]]+c[e[t+11]]+c[e[t+12]]+c[e[t+13]]+c[e[t+14]]+c[e[t+15]]).toLowerCase()}function u(e,t=0){const r=d(e,t);if(!validate(r))throw TypeError("Stringified UUID is invalid");return r}const l=null,p={};function h(e,t,r){let s;if(e)s=m(e.random??e.rng?.()??a(),e.msecs,e.seq,t,r);else{const e=Date.now(),n=a();f(p,e,n),s=m(n,p.msecs,p.seq,t,r)}return t??d(s)}function f(e,t,r){return e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=r[6]<<23|r[7]<<16|r[8]<<8|r[9],e.msecs=t):(e.seq=e.seq+1|0,0===e.seq&&e.msecs++),e}function m(e,t,r,s,n=0){if(e.length<16)throw new Error("Random bytes length must be >= 16");if(s){if(n<0||n+16>s.length)throw new RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`)}else s=new Uint8Array(16),n=0;return t??=Date.now(),r??=127*e[6]<<24|e[7]<<16|e[8]<<8|e[9],s[n++]=t/1099511627776&255,s[n++]=t/4294967296&255,s[n++]=t/16777216&255,s[n++]=t/65536&255,s[n++]=t/256&255,s[n++]=255&t,s[n++]=112|r>>>28&15,s[n++]=r>>>20&255,s[n++]=128|r>>>14&63,s[n++]=r>>>6&255,s[n++]=r<<2&255|3&e[10],s[n++]=e[11],s[n++]=e[12],s[n++]=e[13],s[n++]=e[14],s[n++]=e[15],s}const g=h;
+!function webpackUniversalModuleDefinition(root,factory){"object"==typeof exports&&"object"==typeof module?module.exports=factory():"function"==typeof define&&define.amd?define("OptaveJavaScriptSDK",[],factory):"object"==typeof exports?exports.OptaveJavaScriptSDK=factory():root.OptaveJavaScriptSDK=factory()}(function(){return"undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof globalThis?globalThis:this}(),()=>(()=>{var e={46(e){var t,r="object"==typeof Reflect?Reflect:null,s=r&&"function"==typeof r.apply?r.apply:function(e,t,r){return Function.prototype.apply.call(e,t,r)};t=r&&"function"==typeof r.ownKeys?r.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var n=Number.isNaN||function(e){return e!=e};function o(){o.init.call(this)}e.exports=o,e.exports.once=function(e,t){return new Promise(function(r,s){function n(r){e.removeListener(t,o),s(r)}function o(){"function"==typeof e.removeListener&&e.removeListener("error",n),r([].slice.call(arguments))}f(e,t,o,{once:!0}),"error"!==t&&function(e,t,r){"function"==typeof e.on&&f(e,"error",t,r)}(e,n,{once:!0})})},o.EventEmitter=o,o.prototype._events=void 0,o.prototype._eventsCount=0,o.prototype._maxListeners=void 0;var i=10;function a(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function c(e){return void 0===e._maxListeners?o.defaultMaxListeners:e._maxListeners}function u(e,t,r,s){var n,o,i,u;if(a(r),void 0===(o=e._events)?(o=e._events=Object.create(null),e._eventsCount=0):(void 0!==o.newListener&&(e.emit("newListener",t,r.listener?r.listener:r),o=e._events),i=o[t]),void 0===i)i=o[t]=r,++e._eventsCount;else if("function"==typeof i?i=o[t]=s?[r,i]:[i,r]:s?i.unshift(r):i.push(r),(n=c(e))>0&&i.length>n&&!i.warned){i.warned=!0;var d=new Error("Possible EventEmitter memory leak detected. "+i.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");d.name="MaxListenersExceededWarning",d.emitter=e,d.type=t,d.count=i.length,u=d,console&&console.warn&&console.warn(u)}return e}function d(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function l(e,t,r){var s={fired:!1,wrapFn:void 0,target:e,type:t,listener:r},n=d.bind(s);return n.listener=r,s.wrapFn=n,n}function p(e,t,r){var s=e._events;if(void 0===s)return[];var n=s[t];return void 0===n?[]:"function"==typeof n?r?[n.listener||n]:[n]:r?function(e){for(var t=new Array(e.length),r=0;r0&&(i=t[0]),i instanceof Error)throw i;var a=new Error("Unhandled error."+(i?" ("+i.message+")":""));throw a.context=i,a}var c=o[e];if(void 0===c)return!1;if("function"==typeof c)s(c,this,t);else{var u=c.length,d=m(c,u);for(r=0;r=0;o--)if(r[o]===t||r[o].listener===t){i=r[o].listener,n=o;break}if(n<0)return this;0===n?r.shift():function(e,t){for(;t+1=0;s--)this.removeListener(e,t[s]);return this},o.prototype.listeners=function(e){return p(this,e,!0)},o.prototype.rawListeners=function(e){return p(this,e,!1)},o.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):h.call(e,t)},o.prototype.listenerCount=h,o.prototype.eventNames=function(){return this._eventsCount>0?t(this._events):[]}},31(e,t,r){class URLSearchParamsPolyfill{constructor(e){if(this.params=new Map,"string"==typeof e){e.replace(/^\?/,"").split("&").forEach(e=>{if(e){const[t,r]=e.split("=");t&&this.params.set(decodeURIComponent(t),decodeURIComponent(r||""))}})}else e&&"object"==typeof e&&(e instanceof Map?e.forEach((e,t)=>{this.params.set(t,String(e))}):Array.isArray(e)?e.forEach(([e,t])=>{this.params.set(e,String(t))}):Object.entries(e).forEach(([e,t])=>{this.params.set(e,String(t))}))}append(e,t){const r=this.params.get(e);void 0!==r?this.params.set(e,`${r},${String(t)}`):this.params.set(e,String(t))}delete(e){this.params.delete(e)}get(e){return this.params.get(e)||null}getAll(e){const t=this.params.get(e);return t?t.split(","):[]}has(e){return this.params.has(e)}set(e,t){this.params.set(e,String(t))}toString(){const e=[];return this.params.forEach((t,r)=>{t.split(",").forEach(t=>{e.push(`${encodeURIComponent(r)}=${encodeURIComponent(t)}`)})}),e.join("&")}*[Symbol.iterator](){const e=Array.from(this.params);for(let t=0;t{e.call(t,s,r,this)})}}const s="undefined"!=typeof globalThis&&globalThis.URLSearchParams||"undefined"!=typeof window&&window.URLSearchParams||URLSearchParamsPolyfill;r.d(t,["I",0,s])}};const t={};function r(s){const n=t[s];if(void 0!==n)return n.exports;const o=t[s]={exports:{}};return e[s](o,o.exports,r),o.exports}r.d=(e,t)=>{if(Array.isArray(t))for(var s=0;sObject.prototype.hasOwnProperty.call(e,t);let s={};r.d(s,{default:()=>B});var n=r(46);const o=new Uint8Array(16);function i(){return crypto.getRandomValues(o)}const a=[];for(let e=0;e<256;++e)a.push((e+256).toString(16).slice(1));function c(e,t=0){return(a[e[t+0]]+a[e[t+1]]+a[e[t+2]]+a[e[t+3]]+"-"+a[e[t+4]]+a[e[t+5]]+"-"+a[e[t+6]]+a[e[t+7]]+"-"+a[e[t+8]]+a[e[t+9]]+"-"+a[e[t+10]]+a[e[t+11]]+a[e[t+12]]+a[e[t+13]]+a[e[t+14]]+a[e[t+15]]).toLowerCase()}const u={};function d(e,t,r,s,n=0){if(e.length<16)throw new Error("Random bytes length must be >= 16");if(s){if(n<0||n+16>s.length)throw new RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`)}else s=new Uint8Array(16),n=0;return t??=Date.now(),r??=l(e),s[n++]=t/1099511627776&255,s[n++]=t/4294967296&255,s[n++]=t/16777216&255,s[n++]=t/65536&255,s[n++]=t/256&255,s[n++]=255&t,s[n++]=112|r>>>28&15,s[n++]=r>>>20&255,s[n++]=128|r>>>14&63,s[n++]=r>>>6&255,s[n++]=r<<2&255|3&e[10],s[n++]=e[11],s[n++]=e[12],s[n++]=e[13],s[n++]=e[14],s[n++]=e[15],s}function l(e){return(127&e[6])<<24|e[7]<<16|e[8]<<8|e[9]}const p=function(e,t,r){let s;if(e)s=d(e.random??e.rng?.()??i(),e.msecs,e.seq,t,r);else{const e=Date.now(),n=i();!function(e,t,r){e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=l(r),e.msecs=t):(e.seq=e.seq+1|0,0===e.seq&&e.msecs++)}(u,e,n),s=d(n,u.msecs,u.seq,t,r)}return t??c(s)};
/**
- * Browser-compatible validator implementation
- * Provides comprehensive validation without AJV dependency
- * This implementation must match the server-side validation logic for security
+ * CSP-safe validator implementation (no eval/Function constructor)
+ *
+ * Used by all builds that require Content Security Policy compliance:
+ * - Browser ESM (browser.mjs)
+ * - Browser UMD (browser.umd.js) - Salesforce Lightning
+ * - Server UMD (server.umd.js) - Node.js CommonJS
+ *
+ * Provides comprehensive validation without AJV dependency.
+ * Server ESM (server.mjs) uses full AJV validation instead.
+ *
+ * This implementation must match the server-side validation logic for security.
*/
-function y(e,t,r="validation",s={}){return{instancePath:e,message:t,keyword:r,params:s}}function v(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[y("","must be object","type",{type:"object"})]};const t=[];return e.session?"object"!=typeof e.session?t.push(y("/session","must be object","type",{type:"object"})):void 0!==e.session.sessionId&&"string"!=typeof e.session.sessionId&&t.push(y("/session/sessionId","must be string","type",{type:"string"})):t.push(y("/session","is required","required",{missingProperty:"session"})),e.request?"object"!=typeof e.request?t.push(y("/request","must be object","type",{type:"object"})):(e.request.connections?"object"!=typeof e.request.connections?t.push(y("/request/connections","must be object","type",{type:"object"})):(e.request.connections.threadId?"string"!=typeof e.request.connections.threadId&&t.push(y("/request/connections/threadId","must be string","type",{type:"string"})):t.push(y("/request/connections/threadId","is required","required",{missingProperty:"threadId"})),void 0!==e.request.connections.parentId&&"string"!=typeof e.request.connections.parentId&&t.push(y("/request/connections/parentId","must be string","type",{type:"string"}))):t.push(y("/request/connections","is required","required",{missingProperty:"connections"})),void 0!==e.request.context&&"object"!=typeof e.request.context&&t.push(y("/request/context","must be object","type",{type:"object"})),void 0!==e.request.attributes&&"object"!=typeof e.request.attributes&&t.push(y("/request/attributes","must be object","type",{type:"object"})),void 0!==e.request.scope&&("object"!=typeof e.request.scope?t.push(y("/request/scope","must be object","type",{type:"object"})):void 0!==e.request.scope.conversations&&(Array.isArray(e.request.scope.conversations)||t.push(y("/request/scope/conversations","must be array","type",{type:"array"})))),void 0!==e.request.resources&&("object"!=typeof e.request.resources?t.push(y("/request/resources","must be object","type",{type:"object"})):void 0!==e.request.resources.offers&&(Array.isArray(e.request.resources.offers)||t.push(y("/request/resources/offers","must be array","type",{type:"array"}))))):t.push(y("/request","is required","required",{missingProperty:"request"})),t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function b(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[y("","must be object","type",{type:"object"})]};const t=[];if(e.headers)if("object"!=typeof e.headers)t.push(y("/headers","must be object","type",{type:"object"}));else{if(e.headers.correlationId?"string"!=typeof e.headers.correlationId&&t.push(y("/headers/correlationId","must be string","type",{type:"string"})):t.push(y("/headers/correlationId","is required","required",{missingProperty:"correlationId"})),e.headers.action)if("string"!=typeof e.headers.action)t.push(y("/headers/action","must be string","type",{type:"string"}));else{const r=["adjust","elevate","interaction","customerinteraction","reception","summarize","translate","recommend","insights"];r.includes(e.headers.action)||t.push(y("/headers/action","must be equal to one of the allowed values","enum",{allowedValues:r}))}else t.push(y("/headers/action","is required","required",{missingProperty:"action"}));void 0!==e.headers.identifier&&"string"!=typeof e.headers.identifier&&t.push(y("/headers/identifier","must be string","type",{type:"string"})),void 0!==e.headers.schemaRef&&"string"!=typeof e.headers.schemaRef&&t.push(y("/headers/schemaRef","must be string","type",{type:"string"})),void 0!==e.headers.timestamp&&"string"!=typeof e.headers.timestamp&&t.push(y("/headers/timestamp","must be string","type",{type:"string"}))}else t.push(y("/headers","is required","required",{missingProperty:"headers"}));if(e.payload){if("object"!=typeof e.payload)t.push(y("/payload","must be object","type",{type:"object"}));else if(e.headers&&e.headers.action&&e.payload){const r=e.headers.action,s=undefined;["adjust","elevate","interaction","customerinteraction","customerInteraction","summarize","translate","insights","recommend"].includes(r)&&(e.payload.request?e.payload.request.scope?e.payload.request.scope.conversations?Array.isArray(e.payload.request.scope.conversations)?0===e.payload.request.scope.conversations.length&&t.push(y("/payload/request/scope/conversations",`must be non-empty array for ${r}`,"minItems",{limit:1})):t.push(y("/payload/request/scope/conversations","must be array","type",{type:"array"})):t.push(y("/payload/request/scope/conversations",`is required for ${r}`,"required",{missingProperty:"conversations"})):t.push(y("/payload/request/scope","is required","required",{missingProperty:"scope"})):t.push(y("/payload/request","is required","required",{missingProperty:"request"})))}}else t.push(y("/payload","is required","required",{missingProperty:"payload"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}const E=null,S="3.2.3",w=undefined,_=`optave.message.v${S.split(".")[0]}`,I={AUTHENTICATION:"AUTHENTICATION",ORCHESTRATOR:"ORCHESTRATOR",VALIDATION:"VALIDATION",WEBSOCKET:"WEBSOCKET"},O=Object.freeze({MESSAGE:"message",ERROR:"error"}),T=Object.freeze({CONNECTION_OPEN:"connection:open",CONNECTION_CLOSE:"connection:close",CONNECTION_ERROR:"connection:error",MESSAGE_RECEIVED:"message:received",MESSAGE_SENT:"message:sent",ERROR:"error",RESPONSE:"response",LEGACY_ERROR:"error",LEGACY_MESSAGE:"message"}),A=Object.freeze({SUPERPOWER_RESPONSE:"superpower.response",SUPERPOWER_ERROR:"superpower.error"}),R=new Set(["adjust","elevate","interaction","reception","customerInteraction","summarize","translate","recommend","insights"]),k=undefined,q=undefined,C=undefined,N=undefined,U={SPEC_VERSION:S,SCHEMA_REF:_,MAX_PAYLOAD_SIZE:131072,MAX_PAYLOAD_SIZE_KB:128,DEFAULT_REQUEST_TIMEOUT_MS:3e4,ErrorCategory:I,LegacyEvents:O,EVENTS:T,InboundEvents:A,ALLOWED_ACTIONS:R},L=()=>{if("undefined"!=typeof process&&{},0,"undefined"!=typeof global){if("window"in global||"document"in global||("undefined"!=typeof process&&{},0),(!("window"in global)||!("document"in global))&&"undefined"!=typeof process&&{},"window"in global&&global.window)return!0;if("document"in global&&global.document)return!0}try{if("undefined"!=typeof window&&null!==window)return("undefined"==typeof global||"window"in global)&&("undefined"!=typeof global&&"undefined"!=typeof process&&{},0,!0);if("undefined"!=typeof document&&null!==document)return("undefined"==typeof global||"document"in global)&&("undefined"!=typeof global&&"undefined"!=typeof process&&{},0,!0)}catch(e){}return"undefined"!=typeof navigator&&"ReactNative"===navigator.product||(!("undefined"==typeof global||!global.__expo)||("undefined"!=typeof location&&null!==location||("undefined"!=typeof process&&{},0,!1)))};function P(e){const t=[];return!e.authenticationUrl||e.clientId&&e.clientSecret||t.push({type:"warning",code:"INCOMPLETE_AUTH_CONFIG",message:"authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.",field:"authentication"}),t}
+function h(e,t,r="validation",s={}){return{instancePath:e,message:t,keyword:r,params:s}}function m(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[h("","must be object","type",{type:"object"})]};const t=[];if(e.session?"object"!=typeof e.session?t.push(h("/session","must be object","type",{type:"object"})):void 0!==e.session.sessionId&&"string"!=typeof e.session.sessionId&&t.push(h("/session/sessionId","must be string","type",{type:"string"})):t.push(h("/session","is required","required",{missingProperty:"session"})),e.request)if("object"!=typeof e.request)t.push(h("/request","must be object","type",{type:"object"}));else{if(e.request.connections)if("object"!=typeof e.request.connections)t.push(h("/request/connections","must be object","type",{type:"object"}));else{e.request.connections.threadId?"string"!=typeof e.request.connections.threadId&&t.push(h("/request/connections/threadId","must be string","type",{type:"string"})):t.push(h("/request/connections/threadId","is required","required",{missingProperty:"threadId"})),void 0!==e.request.connections.parentId&&"string"!=typeof e.request.connections.parentId&&t.push(h("/request/connections/parentId","must be string","type",{type:"string"})),void 0!==e.request.connections.replyId&&"string"!=typeof e.request.connections.replyId&&t.push(h("/request/connections/replyId","must be string","type",{type:"string"}));const{replyTarget:r}=e.request.connections;if(void 0!==r){const e=["ai","self","none"];"string"!=typeof r?t.push(h("/request/connections/replyTarget","must be string","type",{type:"string"})):e.includes(r)||t.push(h("/request/connections/replyTarget","must be equal to one of the allowed values","enum",{allowedValues:e}))}}else t.push(h("/request/connections","is required","required",{missingProperty:"connections"}));if(void 0!==e.request.context&&"object"!=typeof e.request.context&&t.push(h("/request/context","must be object","type",{type:"object"})),void 0!==e.request.attributes&&"object"!=typeof e.request.attributes)t.push(h("/request/attributes","must be object","type",{type:"object"}));else if(e.request.attributes&&"object"==typeof e.request.attributes){const{replyTo:r}=e.request.attributes;if(void 0!==r){const e=["ai","self","none"];"string"!=typeof r?t.push(h("/request/attributes/replyTo","must be string","type",{type:"string"})):e.includes(r)||t.push(h("/request/attributes/replyTo","must be equal to one of the allowed values","enum",{allowedValues:e}))}}void 0!==e.request.scope&&("object"!=typeof e.request.scope?t.push(h("/request/scope","must be object","type",{type:"object"})):void 0!==e.request.scope.conversations&&(Array.isArray(e.request.scope.conversations)||t.push(h("/request/scope/conversations","must be array","type",{type:"array"})))),void 0!==e.request.resources&&("object"!=typeof e.request.resources?t.push(h("/request/resources","must be object","type",{type:"object"})):void 0!==e.request.resources.offers&&(Array.isArray(e.request.resources.offers)||t.push(h("/request/resources/offers","must be array","type",{type:"array"}))))}else t.push(h("/request","is required","required",{missingProperty:"request"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function f(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[h("","must be object","type",{type:"object"})]};const t=[];if(e.headers)if("object"!=typeof e.headers)t.push(h("/headers","must be object","type",{type:"object"}));else{if(e.headers.correlationId?"string"!=typeof e.headers.correlationId&&t.push(h("/headers/correlationId","must be string","type",{type:"string"})):t.push(h("/headers/correlationId","is required","required",{missingProperty:"correlationId"})),e.headers.action)if("string"!=typeof e.headers.action)t.push(h("/headers/action","must be string","type",{type:"string"}));else{const r=["adjust","elevate","interaction","assistant","customerinteraction","reception","summarize","translate","recommend","insights"];r.includes(e.headers.action)||t.push(h("/headers/action","must be equal to one of the allowed values","enum",{allowedValues:r}))}else t.push(h("/headers/action","is required","required",{missingProperty:"action"}));void 0!==e.headers.identifier&&"string"!=typeof e.headers.identifier&&t.push(h("/headers/identifier","must be string","type",{type:"string"})),void 0!==e.headers.schemaRef&&"string"!=typeof e.headers.schemaRef&&t.push(h("/headers/schemaRef","must be string","type",{type:"string"})),void 0!==e.headers.timestamp&&"string"!=typeof e.headers.timestamp&&t.push(h("/headers/timestamp","must be string","type",{type:"string"}))}else t.push(h("/headers","is required","required",{missingProperty:"headers"}));if(e.payload){if("object"!=typeof e.payload)t.push(h("/payload","must be object","type",{type:"object"}));else if(e.headers&&e.headers.action&&e.payload){const{action:r}=e.headers;["adjust","elevate","interaction","assistant","customerinteraction","customerInteraction","summarize","translate","insights","recommend"].includes(r)&&(e.payload.request?e.payload.request.scope?e.payload.request.scope.conversations?Array.isArray(e.payload.request.scope.conversations)?0===e.payload.request.scope.conversations.length&&t.push(h("/payload/request/scope/conversations",`must be non-empty array for ${r}`,"minItems",{limit:1})):t.push(h("/payload/request/scope/conversations","must be array","type",{type:"array"})):t.push(h("/payload/request/scope/conversations",`is required for ${r}`,"required",{missingProperty:"conversations"})):t.push(h("/payload/request/scope","is required","required",{missingProperty:"scope"})):t.push(h("/payload/request","is required","required",{missingProperty:"request"})))}}else t.push(h("/payload","is required","required",{missingProperty:"payload"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}const g=`optave.message.v${"1.0.0".split(".")[0]}`,y={AUTHENTICATION:"AUTHENTICATION",ORCHESTRATOR:"ORCHESTRATOR",VALIDATION:"VALIDATION",WEBSOCKET:"WEBSOCKET"},v=Object.freeze({MESSAGE:"message",ERROR:"error"}),b=Object.freeze({CONNECTION_OPEN:"connection:open",CONNECTION_CLOSE:"connection:close",CONNECTION_ERROR:"connection:error",MESSAGE_RECEIVED:"message:received",MESSAGE_SENT:"message:sent",ERROR:"error",RESPONSE:"response",LEGACY_ERROR:"error",LEGACY_MESSAGE:"message"}),E=Object.freeze({SUPERPOWER_RESPONSE:"superpower.response",SUPERPOWER_ERROR:"superpower.error"}),S=new Set(["adjust","elevate","interaction","assistant","reception","customerInteraction","summarize","translate","recommend","insights"]),w={SPEC_VERSION:"1.0.0",SCHEMA_REF:g,MAX_PAYLOAD_SIZE:131072,MAX_PAYLOAD_SIZE_KB:128,DEFAULT_REQUEST_TIMEOUT_MS:3e4,ErrorCategory:y,LegacyEvents:v,EVENTS:b,InboundEvents:E,ALLOWED_ACTIONS:S};
/**
* Validates client-specific configuration and enforces security rules
* @param {Object} options - SDK options
* @returns {Array} Array of validation errors (empty if valid)
- */function D(e){const t=[];if(L()&&e.clientSecret){let e=!1,r=!1;try{e=!1}catch(e){}try{r=!1}catch(e){}const s=undefined;e||r||t.push({type:"error",code:"CLIENT_SECRET_IN_CLIENT_ENV",message:"clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.",field:"clientSecret"})}return t}function M(e){const t=[];return e.websocketUrl&&"string"==typeof e.websocketUrl||t.push({type:"warning",code:"MISSING_WEBSOCKET_URL",message:"websocketUrl not provided; openConnection() will emit an error.",field:"websocketUrl"}),t}function W(e){if(void 0===e.strictValidation){const t="undefined"!=typeof process&&{}?"production":"development";e.strictValidation="production"!==t}if("number"!=typeof e.requestTimeoutMs&&(e.requestTimeoutMs=3e4),"number"!=typeof e.connectionTimeoutMs&&(e.connectionTimeoutMs=3e4),e.logger||(e.logger={debug(){},info(){},warn(){},error(){}}),e.authTransport||(e.authTransport="subprotocol"),void 0===e.authRequired&&(e.authRequired=!0),!e.tokenProvider){let t=e.tokenUrl;if(!t&&"undefined"!=typeof document){const e=document.querySelector('meta[name="optave-token-url"]');e&&e.content&&(t=e.content)}t||(t="/api/optave/ws-ticket"),e.tokenProvider=async()=>{const r={};e.publishableKey&&(r["X-Optave-Publishable-Key"]=e.publishableKey);const s=await fetch(t,{method:"POST",credentials:"include",headers:r});if(!s.ok)throw new Error("Failed to obtain WS token");const n=await s.json();return n.token||n.access_token}}return e}function j(e){const t={isValid:!0,errors:[],warnings:[]},r=undefined,s=undefined,n=undefined,o=[...M(e),...P(e),...D(e)];for(const e of o)"error"===e.type?(t.errors.push(e),t.isValid=!1):"warning"===e.type&&t.warnings.push(e);return t}const V={BROWSER_ESM:"browser-esm",SERVER_ESM:"server-esm",BROWSER_UMD:"browser-umd",SERVER_UMD:"server-umd"},$={browser:V.BROWSER_ESM,server:V.SERVER_ESM},K={BROWSER:[V.BROWSER_ESM,V.BROWSER_UMD,V.SERVER_UMD],SERVER:[V.SERVER_ESM],UMD:[V.BROWSER_UMD,V.SERVER_UMD],ESM:[V.BROWSER_ESM,V.SERVER_ESM]},B={isValid:e=>Object.values(V).includes(e)||Object.keys($).includes(e),normalize:e=>$[e]?$[e]:Object.values(V).includes(e)?e:"unknown",isBrowser(e){const t=this.normalize(e);return K.BROWSER.includes(t)},isServer(e){const t=this.normalize(e);return K.SERVER.includes(t)},isUMD(e){const t=this.normalize(e);return K.UMD.includes(t)},isESM(e){const t=this.normalize(e);return K.ESM.includes(t)},getInfo(e){const t=undefined;return{original:e,normalized:this.normalize(e),valid:this.isValid(e),isBrowser:this.isBrowser(e),isServer:this.isServer(e),isUMD:this.isUMD(e),isESM:this.isESM(e)}}};class x extends Error{constructor({category:e,code:t,message:r,details:s}){super(r),this.name="OptaveError",this.category=e||"UNKNOWN",this.code=t||"UNKNOWN",void 0!==s&&(this.details=s)}}function z(e){return e&&e.category&&e.code&&e.message?new x(e):"string"==typeof e?new x({category:"UNKNOWN",code:"STRING_ERROR",message:e}):e&&e.isAuthError?new x({category:"AUTHENTICATION",code:e.code||"AUTH_ERROR",message:e.message||"Authentication error",details:e}):e&&e.isWsError?new x({category:"WEBSOCKET",code:e.code||"WS_ERROR",message:e.message||"WebSocket error",details:e}):new x({category:"UNKNOWN",code:"UNCLASSIFIED",message:e&&e.message||String(null!=e?e:"Unknown error"),details:e})}// ./runtime/core/security-guards.js
+ */
+function _(e){const t=[];if((()=>{if("undefined"!=typeof globalThis){if("window"in globalThis||globalThis,!("window"in globalThis)||globalThis,"window"in globalThis&&globalThis.window)return!0;if("document"in globalThis&&globalThis.document)return!0}try{if("undefined"!=typeof window&&null!==window)return"undefined"==typeof globalThis||"window"in globalThis;if("undefined"!=typeof document&&null!==document)return"undefined"==typeof globalThis||"document"in globalThis}catch(e){}return"undefined"!=typeof navigator&&"ReactNative"===navigator.product||!("undefined"==typeof globalThis||!globalThis.__expo)||void 0!==globalThis.location&&null!==globalThis.location})()&&e.clientSecret){let e=!1,r=!1;try{e=!1}catch(e){}try{r=!1}catch(e){}e||r||t.push({type:"error",code:"CLIENT_SECRET_IN_CLIENT_ENV",message:"clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.",field:"clientSecret"})}return t}const I=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i,O=/^\s*-?\d{1,3}(?:\.\d+)?\s*,\s*-?\d{1,3}(?:\.\d+)?\s*$/,T=new Set(["email","e-mail","fullname","firstname","lastname","displayname","phone","phonenumber","ssn","dateofbirth","dob","nationalid"]);function A(e,t,r={}){return{instancePath:e,message:t,keyword:"piGuard",params:r}}function R(e,t,r){null!=e&&("string"!=typeof e?Array.isArray(e)?e.forEach((e,s)=>R(e,`${t}/${s}`,r)):"object"==typeof e&&Object.entries(e).forEach(([e,s])=>{T.has(e.toLowerCase())&&r.push(A(`${t}/${e}`,`must not carry direct identifier key '${e}'`,{kind:"identifierKey",key:e})),R(s,`${t}/${e}`,r)}):function(e,t,r){"string"==typeof e&&0!==e.length&&(I.test(e)&&r.push(A(t,"must not contain an email address",{kind:"email"})),O.test(e)&&r.push(A(t,"must not contain precise coordinates",{kind:"coordinates"})),function(e){if("string"!=typeof e)return!1;const t=e.trim();return!!(t.includes("\n")&&t.length>40)||!!(t.length>160&&/\s/.test(t)&&/[.!?]/.test(t))}(e)&&r.push(A(t,"must not contain message content or other direct identifiers",{kind:"messageContent"})))}(e,t,r))}function k(e){if(!e||"object"!=typeof e)return{valid:!0,errors:null};const t=[],r=e.session?.channel?.location;return"string"==typeof r&&r&&O.test(r)&&t.push(A("/session/channel/location","must be province grain at most, never precise coordinates",{kind:"coordinates"})),void 0!==e.session?.channel?.metadata&&R(e.session.channel.metadata,"/session/channel/metadata",t),void 0!==e.request?.reference&&R(e.request.reference,"/request/reference",t),t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function q(e){return t=>{const r=e(t);return r.valid?k(t):r}}const C={BROWSER_ESM:"browser-esm",SERVER_ESM:"server-esm",BROWSER_UMD:"browser-umd",SERVER_UMD:"server-umd"},N={browser:C.BROWSER_ESM,server:C.SERVER_ESM},U={BROWSER:[C.BROWSER_ESM,C.BROWSER_UMD],SERVER:[C.SERVER_ESM,C.SERVER_UMD],UMD:[C.BROWSER_UMD,C.SERVER_UMD],ESM:[C.BROWSER_ESM,C.SERVER_ESM]},P={isValid:e=>Object.values(C).includes(e)||Object.keys(N).includes(e),normalize:e=>N[e]?N[e]:Object.values(C).includes(e)?e:"unknown",isBrowser(e){const t=this.normalize(e);return U.BROWSER.includes(t)},isServer(e){const t=this.normalize(e);return U.SERVER.includes(t)},isUMD(e){const t=this.normalize(e);return U.UMD.includes(t)},isESM(e){const t=this.normalize(e);return U.ESM.includes(t)},getInfo(e){return{original:e,normalized:this.normalize(e),valid:this.isValid(e),isBrowser:this.isBrowser(e),isServer:this.isServer(e),isUMD:this.isUMD(e),isESM:this.isESM(e)}}};class OptaveError extends Error{constructor({category:e,code:t,message:r,details:s}){super(r),this.name="OptaveError",this.category=e||"UNKNOWN",this.code=t||"UNKNOWN",void 0!==s&&(this.details=s)}}!
+/**
+ * Initialize security guards on module load
+ * This ensures the security validation code is evaluated and cannot be tree-shaken
+ */
+function(){
+// SECURITY: Module-level side effect to prevent tree-shaking
+if("undefined"!=typeof globalThis){
+// Mark security guards as active - this creates a side effect
+globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__=!0;if(!globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__)throw new Error("Security guard initialization failed")}}(),"undefined"!=typeof window?
+// Browser environment - ensure security guards are active
+window.__OPTAVE_SECURITY_GUARDS_BROWSER__=!0:"undefined"!=typeof globalThis&&(
+// Node.js environment - ensure security guards are active.
+// Function constructor and would violate Salesforce Lightning Locker CSP.
+globalThis.__OPTAVE_SECURITY_GUARDS_NODE__=!0);var L=r(31).I;const D="3.6.0",M=()=>{const e="browser-umd";return{isBrowser:P.isBrowser(e),isServer:P.isServer(e),buildTarget:e}};let W=!1,j=!1;class OptaveJavaScriptSDK extends n{options={};wss=null;static defaultPayload={session:{sessionId:"",channel:{browser:"",deviceInfo:"",deviceType:"",language:"",location:"",medium:"chat",metadata:[],section:""},interface:{appVersion:"",category:"",language:"",name:"",type:""}},request:{requestId:"",attributes:{content:"",instruction:"",variant:"A"},connections:{journeyId:"",parentId:"",replyId:"",threadId:""},context:{caseId:"",departmentId:"",operatorId:"",organizationId:"",userId:""},reference:{ids:[{name:"",value:""}],labels:[],tags:[]},resources:{codes:[{id:"",label:"",type:"",value:""}],links:[{expires_at:"",html:!1,id:"",label:"",type:"",url:""}],offers:[]},scope:{accounts:[],appointments:[],assets:[],bookings:[],cases:[],conversations:[],documents:[],events:[],interactions:[],items:[],locations:[],operators:[],orders:[],organizations:[],persons:[],policies:[],products:[{id:""}],properties:[],services:[],subscriptions:[],tickets:[],transactions:[],users:[]},settings:{disableBrowsing:!1,disableSearch:!1,disableSources:!1,disableStream:!0,disableTools:!1,maxResponseLength:0,overrideInterfaceLanguage:"",overrideOutputLanguage:""},a2a:[{id:"",name:"",type:""}],cursor:{since:"",until:""}}};static cleanup(){W=!1,j=!1}constructor(e){if(super(),this.options={...e},function(e){if(void 0===e.strictValidation){const t="undefined"!=typeof process?"production":"development";e.strictValidation="production"!==t}if("number"!=typeof e.requestTimeoutMs&&(e.requestTimeoutMs=3e4),"number"!=typeof e.connectionTimeoutMs&&(e.connectionTimeoutMs=3e4),e.logger||(e.logger={debug(){},info(){},warn(){},error(){}}),e.authTransport||(e.authTransport="subprotocol"),void 0===e.authRequired&&(e.authRequired=!0),!e.tokenProvider){let t=e.tokenUrl;if(!t&&"undefined"!=typeof document){const e=document.querySelector('meta[name="optave-token-url"]');e&&e.content&&(t=e.content)}t||(t="/api/optave/ws-ticket"),e.tokenProvider=async()=>{const r={};e.publishableKey&&(r["X-Optave-Publishable-Key"]=e.publishableKey);const s=await fetch(t,{method:"POST",credentials:"include",headers:r});if(!s.ok)throw new Error("Failed to obtain WS token");const n=await s.json();return n.token||n.access_token}}}(this.options),void 0===this.options.cspSafe){const e=M();"server-esm"===e.buildTarget||"server"===e.buildTarget?this.options.cspSafe=!1:("browser-esm"===e.buildTarget||"browser-umd"===e.buildTarget||"server-umd"===e.buildTarget||e.isBrowser||(()=>{const e=M();return"unknown"!==e.buildTarget?e.isBrowser:"undefined"!=typeof window&&void 0!==window.WebSocket})())&&(this.options.cspSafe=!0)}const t=function(e){const t={isValid:!0,errors:[],warnings:[]},r=function(e){const t=[];return e.websocketUrl&&"string"==typeof e.websocketUrl||t.push({type:"warning",code:"MISSING_WEBSOCKET_URL",message:"websocketUrl not provided; openConnection() will emit an error.",field:"websocketUrl"}),t}(e),s=function(e){const t=[];return!e.authenticationUrl||e.clientId&&e.clientSecret||t.push({type:"warning",code:"INCOMPLETE_AUTH_CONFIG",message:"authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.",field:"authentication"}),t}(e);return[...r,...s,..._(e)].forEach(e=>{"error"===e.type?(t.errors.push(e),t.isValid=!1):"warning"===e.type&&t.warnings.push(e)}),t}(this.options);if(!t.isValid){const e=t.errors.map(e=>e.message).join("; ");throw new Error(`[Optave SDK] Configuration errors: ${e}`)}t.warnings.forEach(e=>{(this.options?.logger?.warn||console.warn)(`[Optave SDK] ${e.message}`)});
+// Use canonical security guard - single source of truth for WebSocket validation.
+// Any thrown security error propagates to the caller (no try/catch needed - it would only rethrow).
+!// ./runtime/core/security-guards.js
/**
* Critical Security Guards for Optave SDK
*
@@ -37,55 +63,35 @@ function y(e,t,r="validation",s={}){return{instancePath:e,message:t,keyword:r,pa
* @throws {Error} When ws:// protocol is used in UMD builds
* @throws {Error} When tokenProvider is missing for secure connections in UMD builds
*/
-function F(e,t,r={}){if(
-// SECURITY: Explicitly mark as having side effects - do not optimize away
-1,!e||"string"!=typeof e)return;const s=B.normalize(t),n=B.isUMD(s),o=B.isBrowser(s);
-// CRITICAL: Validate WebSocket scheme for UMD and browser builds
-// This guard prevents insecure connections in Salesforce Lightning
-if((n||o)&&e.startsWith("ws://")){
-// SECURITY: This error message must remain intact to guide developers
-const t=undefined;
+function(e,t,r={}){
+// SECURITY: This function has observable side effects (throws on invalid schemes and
+// sets a global marker via initializeSecurityGuards) so bundlers must not optimize it away.
+if(!e||"string"!=typeof e)return;const s=P.normalize(t),n=P.isBrowser(s);
+// Browser builds include: browser-esm and browser-umd (Salesforce/Lightning)
+// CRITICAL: Validate WebSocket scheme for browser-targeted builds only
+// This guard prevents insecure connections in Salesforce Lightning and browser environments
+if(n&&e.startsWith("ws://"))
// CRITICAL: This throw statement is a security boundary - must not be removed
-throw new Error(`[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in UMD builds. Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. Please use secure WebSocket protocol (wss://) instead. Current URL: ${e}`)}
-// CRITICAL: For UMD builds with secure WebSocket URLs, validate token provider availability
-if(n&&e.startsWith("wss://")){const t="function"==typeof r.tokenProvider,s=!1===r.authRequired;if(!t&&!s){
-// SECURITY: This error message must remain intact to guide developers
-const t=undefined;
+throw new Error(`[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in browser builds. Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. Please use secure WebSocket protocol (wss://) instead. Current URL: ${e}`);
+// CRITICAL: For browser UMD builds with secure WebSocket URLs, validate token provider availability
+// This prevents authentication bypass in constrained Salesforce Lightning environments
+const o=P.isUMD(s);if(n&&o&&e.startsWith("wss://")){const t="function"==typeof r.tokenProvider,s=!1===r.authRequired;if(!t&&!s)
// CRITICAL: This throw statement is a security boundary - must not be removed
-throw new Error(`[Optave SDK] UMD builds require a tokenProvider function for secure WebSocket connections. In constrained environments like Salesforce Lightning, authentication tokens must be obtained from your backend server. Please provide options.tokenProvider() that returns a valid token, or set options.authRequired = false to disable authentication. Current URL: ${e}`)}}}
-/**
- * Initialize security guards on module load
- * This ensures the security validation code is evaluated and cannot be tree-shaken
- */function H(){
-// SECURITY: Module-level side effect to prevent tree-shaking
-if("undefined"!=typeof globalThis){
-// Mark security guards as active - this creates a side effect
-globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__=!0;const e=undefined;if(!globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__)throw new Error("Security guard initialization failed")}"undefined"!=typeof process&&{},0}H(),"undefined"!=typeof window?
-// Browser environment - ensure security guards are active
-window.__OPTAVE_SECURITY_GUARDS_BROWSER__=!0:"undefined"!=typeof global&&(
-// Node.js environment - ensure security guards are active
-global.__OPTAVE_SECURITY_GUARDS_NODE__=!0);var G=r(31).I;const Y="3.2.3",J=()=>{const e="browser-umd";return{isBrowser:B.isBrowser(e),isServer:B.isServer(e),buildTarget:e}},Q=()=>{const e=J();return"unknown"!==e.buildTarget?e.isBrowser:"undefined"!=typeof window&&void 0!==window.WebSocket};let X=!1,Z=!1;class OptaveJavaScriptSDK extends n{options={};wss=null;static defaultPayload={session:{sessionId:"",channel:{browser:"",deviceInfo:"",deviceType:"",language:"",location:"",medium:"chat",metadata:[],section:""},interface:{appVersion:"",category:"",language:"",name:"",type:""}},request:{requestId:"",attributes:{content:"",instruction:"",variant:"A"},connections:{journeyId:"",parentId:"",threadId:""},context:{caseId:"",departmentId:"",operatorId:"",organizationId:"",userId:""},reference:{ids:[{name:"",value:""}],labels:[],tags:[]},resources:{codes:[{id:"",label:"",type:"",value:""}],links:[{expires_at:"",html:!1,id:"",label:"",type:"",url:""}],offers:[]},scope:{accounts:[],appointments:[],assets:[],bookings:[],cases:[],conversations:[],documents:[],events:[],interactions:[],items:[],locations:[],operators:[],orders:[],organizations:[],persons:[],policies:[],products:[{id:""}],properties:[],services:[],subscriptions:[],tickets:[],transactions:[],users:[]},settings:{disableBrowsing:!1,disableSearch:!1,disableSources:!1,disableStream:!0,disableTools:!1,maxResponseLength:0,overrideInterfaceLanguage:"",overrideOutputLanguage:""},a2a:[{id:"",name:"",type:""}],cursor:{since:"",until:""}}};static cleanup(){X=!1,Z=!1}constructor(e){if(super(),this.options={...e},W(this.options),void 0===this.options.cspSafe){const e=J();"server-esm"===e.buildTarget||"server"===e.buildTarget?this.options.cspSafe=!1:("server-umd"===e.buildTarget||"browser-esm"===e.buildTarget||"browser-umd"===e.buildTarget||e.isBrowser||Q())&&(this.options.cspSafe=!0)}const t=j(this.options);if(!t.isValid){const e=t.errors.map(e=>e.message).join("; ");throw new Error(`[Optave SDK] Configuration errors: ${e}`)}t.warnings.forEach(e=>{(this.options?.logger?.warn||console.warn)(`[Optave SDK] ${e.message}`)});
-// SECURITY: This validation is critical for Salesforce Lightning security - must not be removed by tree-shaking
-const r="browser-umd";try{
-// Use canonical security guard - single source of truth for WebSocket validation
-F(this.options.websocketUrl,r,this.options)}catch(e){
-// Re-throw security errors immediately - this prevents minification from removing the try/catch
-throw e}const s=J();this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&s.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&s.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this._pending=new Map,this._deprecatedKeys=new Set,this._silenceDeprecations="undefined"!=typeof process&&"1"==={}?.OPTAVE_SDK_SILENCE_DEPRECATIONS,this.options.cspSafe,this._validatePayload=v,this._validateMessageEnvelope=b}async _ensureWebSocketImpl(){if(this.WebSocketImpl)return this.WebSocketImpl;const e=J();return this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&e.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&e.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this.WebSocketImpl||(e.isBrowser?this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:null:e.isServer&&(this.WebSocketImpl=await this.loadNodeWebSocket())),this.WebSocketImpl}async loadNodeWebSocket(){const e=J();return e.isBrowser?null:"unknown"!==e.buildTarget||"undefined"==typeof window&&"undefined"==typeof document&&"undefined"==typeof navigator&&"undefined"==typeof location?("undefined"==typeof process||!{},1,null):null}static getSdkVersion(){return Y}static getSpecVersion(){return S}static getSchemaRef(){return _}static get CONSTANTS(){return U}static get LegacyEvents(){return O}static get InboundEvents(){return A}setSessionId(e){return this.sessionId=e,this}getSessionId(){return this.sessionId||""}validate(e){const t=undefined;return this._validatePayload(e).valid}validateEnvelope(e){const t=undefined;return this._validateMessageEnvelope(e).valid}validateRequiredFields(e,t){const r=[];switch(e.request?.connections?.threadId||r.push("request.connections.threadId is required"),t){case"adjust":e.request?.attributes?.content||r.push("request.attributes.content is required for adjust"),e.request?.attributes?.instruction||r.push("request.attributes.instruction is required for adjust"),e.request?.connections?.parentId||r.push("request.connections.parentId is required for adjust"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||r.push("request.scope.conversations is required for adjust and must be a non-empty array");break;case"elevate":e.request?.attributes?.content||r.push("request.attributes.content is required for elevate"),e.request?.connections?.parentId||r.push("request.connections.parentId is required for elevate"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||r.push("request.scope.conversations is required for elevate and must be a non-empty array");break;case"translate":case"summarize":case"insights":case"customerinteraction":case"customerInteraction":case"interaction":e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||r.push(`request.scope.conversations is required for ${t} and must be a non-empty array`);break;case"recommend":e.request?.resources?.offers&&Array.isArray(e.request.resources.offers)&&0!==e.request.resources.offers.length||r.push("request.resources.offers is required for recommend and must be a non-empty array"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||r.push("request.scope.conversations is required for recommend and must be a non-empty array")}return{isValid:0===r.length,errors:r}}async authenticate(){
-// Browser-targeted builds should not use client credentials for security
-const e="browser-umd",t=undefined;if(B.isBrowser(e))return this.handleError(I.AUTHENTICATION,"UNSUPPORTED_IN_BROWSER","authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend."),null;let r={grant_type:"client_credentials"};if(!this.options.authenticationUrl)return this.handleError(I.AUTHENTICATION,"INVALID_AUTHENTICATION_URL","Empty or invalid authentication URL"),null;if(!this.options.clientId)return this.handleError(I.AUTHENTICATION,"INVALID_CLIENT_ID","Empty or invalid client ID"),null;r.client_id=this.options.clientId,r.client_secret=this.options.clientSecret;const s=new G(r).toString();let n=this.options.authenticationUrl;n.endsWith("/token")||(n=n.endsWith("/")?n+"token":n+"/token");const o=`${n}?${s}`,i=await fetch(o,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"}}),a=await i.json();return i.ok?a.access_token:(this.handleError(I.AUTHENTICATION,"INVALID_AUTHENTICATION_RESPONSE",this.formatAuthenticationError(i,a.error,"token endpoint").message,a.error),null)}async openConnection(e){if(!this.options.websocketUrl)return(this.options?.logger?.error||console.error)("[Optave SDK] openConnection aborted: missing websocketUrl"),this.handleError(I.WEBSOCKET,"INVALID_WEBSOCKET_URL",this.formatWebSocketError(new Error("Invalid WebSocket URL configuration"),{url:this.options.websocketUrl}).message,this.options.websocketUrl),void 0;const t=async()=>{if("string"==typeof e&&e.length>0)return e;if("function"==typeof this.options.tokenProvider)try{return await this.options.tokenProvider()}catch(e){return this.handleError(I.AUTHENTICATION,"TOKEN_PROVIDER_FAILED",this.formatTokenProviderError(e).message,e),null}return null},r=await t();if(await this._ensureWebSocketImpl(),!this.WebSocketImpl)return this.handleError(I.WEBSOCKET,"NO_WEBSOCKET_IMPL",this.formatWebSocketError(new Error("No WebSocket implementation available"),{environment:"undefined"!=typeof window?"browser":"node"}).message),void 0;if(!r&&!1!==this.options.authRequired)return this.handleError(I.AUTHENTICATION,"MISSING_TOKEN","No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl."),void 0;const s=new G;this.sessionId&&s.set("OptaveTraceChatSessionId",this.sessionId);try{if("subprotocol"===this.options.authTransport){const e=r?["optave-v1",r]:["optave-v1"];this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl,e)}else{if(r){const e=r.replace(/^Bearer\s+/i,"");s.set("Authorization",e)}this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl),r&&this._warnOnce("_warnedQueryToken",'[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".')}}catch(e){return(this.options?.logger?.error||console.error)("[Optave SDK] WebSocket constructor threw",e),this.handleError(I.WEBSOCKET,"WEBSOCKET_ERROR",this.formatWebSocketError(e,{url:this.options.websocketUrl}).message,e),void 0}return new Promise((e,t)=>{const r=setTimeout(()=>{const e=this.options.connectionTimeoutMs||3e4,r=this.formatWebSocketError(new Error("Connection timeout"),{timeout:e,url:this.options.websocketUrl}).message;
+throw new Error(`[Optave SDK] Browser UMD builds require a tokenProvider function for secure WebSocket connections. In constrained environments like Salesforce Lightning, authentication tokens must be obtained from your backend server. Please provide options.tokenProvider() that returns a valid token, or set options.authRequired = false to disable authentication. Current URL: ${e}`)}}(this.options.websocketUrl,"browser-umd",this.options);const r=M();this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&r.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&r.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this._pending=new Map,this._deprecatedKeys=new Set,this._silenceDeprecations="undefined"!=typeof process&&"1"==={}?.OPTAVE_SDK_SILENCE_DEPRECATIONS,this.options.cspSafe,this._validatePayload=q(m),this._validateMessageEnvelope=f}async _ensureWebSocketImpl(){if(this.WebSocketImpl)return this.WebSocketImpl;const e=M();return this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&e.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&e.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this.WebSocketImpl||(e.isBrowser?this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:null:e.isServer&&(this.WebSocketImpl=await this.loadNodeWebSocket())),this.WebSocketImpl}async loadNodeWebSocket(){const e=M();return e.isBrowser||"unknown"!==e.buildTarget||"undefined"==typeof window&&"undefined"==typeof document&&"undefined"==typeof navigator&&globalThis.location,null}static getSdkVersion(){return D}static getSpecVersion(){return"1.0.0"}static getSchemaRef(){return g}static get CONSTANTS(){return w}static get LegacyEvents(){return v}static get InboundEvents(){return E}setSessionId(e){return this.sessionId=e,this}getSessionId(){return this.sessionId||""}validate(e){return this._validatePayload(e).valid}validateEnvelope(e){return this._validateMessageEnvelope(e).valid}_validateOutboundPayload(e){return this.options.strictValidation?this._validatePayload(e):k(e)}validateRequiredFields(e,t){const r=[];switch(e.request?.connections?.threadId||r.push("request.connections.threadId is required"),t){case"adjust":e.request?.attributes?.content||r.push("request.attributes.content is required for adjust"),e.request?.attributes?.instruction||r.push("request.attributes.instruction is required for adjust"),e.request?.connections?.parentId||r.push("request.connections.parentId is required for adjust"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||r.push("request.scope.conversations is required for adjust and must be a non-empty array");break;case"elevate":e.request?.attributes?.content||r.push("request.attributes.content is required for elevate"),e.request?.connections?.parentId||r.push("request.connections.parentId is required for elevate"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||r.push("request.scope.conversations is required for elevate and must be a non-empty array");break;case"translate":case"summarize":case"insights":case"customerinteraction":case"customerInteraction":case"interaction":case"assistant":e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||r.push(`request.scope.conversations is required for ${t} and must be a non-empty array`);break;case"recommend":e.request?.resources?.offers&&Array.isArray(e.request.resources.offers)&&0!==e.request.resources.offers.length||r.push("request.resources.offers is required for recommend and must be a non-empty array"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||r.push("request.scope.conversations is required for recommend and must be a non-empty array")}return{isValid:0===r.length,errors:r}}async authenticate(){if(P.isBrowser("browser-umd"))return this.handleError(y.AUTHENTICATION,"UNSUPPORTED_IN_BROWSER","authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend."),null;const e={grant_type:"client_credentials"};if(!this.options.authenticationUrl)return this.handleError(y.AUTHENTICATION,"INVALID_AUTHENTICATION_URL","Empty or invalid authentication URL"),null;if(!this.options.clientId)return this.handleError(y.AUTHENTICATION,"INVALID_CLIENT_ID","Empty or invalid client ID"),null;e.client_id=this.options.clientId,e.client_secret=this.options.clientSecret;const t=new L(e).toString();let r=this.options.authenticationUrl;r.endsWith("/token")||(r=r.endsWith("/")?`${r}token`:`${r}/token`);const s=`${r}?${t}`,n=await fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"}}),o=await n.json();return n.ok?o.access_token:(this.handleError(y.AUTHENTICATION,"INVALID_AUTHENTICATION_RESPONSE",this.formatAuthenticationError(n,o.error,"token endpoint").message,o.error),null)}async openConnection(e){if(!this.options.websocketUrl)return(this.options?.logger?.error||console.error)("[Optave SDK] openConnection aborted: missing websocketUrl"),void this.handleError(y.WEBSOCKET,"INVALID_WEBSOCKET_URL",this.formatWebSocketError(new Error("Invalid WebSocket URL configuration"),{url:this.options.websocketUrl}).message,this.options.websocketUrl);const t=await(async()=>{if("string"==typeof e&&e.length>0)return e;if("function"==typeof this.options.tokenProvider)try{return await this.options.tokenProvider()}catch(e){return this.handleError(y.AUTHENTICATION,"TOKEN_PROVIDER_FAILED",this.formatTokenProviderError(e).message,e),null}return null})();if(await this._ensureWebSocketImpl(),!this.WebSocketImpl)return void this.handleError(y.WEBSOCKET,"NO_WEBSOCKET_IMPL",this.formatWebSocketError(new Error("No WebSocket implementation available"),{environment:"undefined"!=typeof window?"browser":"node"}).message);if(!t&&!1!==this.options.authRequired)return void this.handleError(y.AUTHENTICATION,"MISSING_TOKEN","No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.");const r=new L;this.sessionId&&r.set("OptaveTraceChatSessionId",this.sessionId);try{if("subprotocol"===this.options.authTransport){const e=t?["optave-v1",t]:["optave-v1"];this.wss=new this.WebSocketImpl(r.toString()?`${this.options.websocketUrl}?${r.toString()}`:this.options.websocketUrl,e)}else{if(t){const e=t.replace(/^Bearer\s+/i,"");r.set("Authorization",e)}this.wss=new this.WebSocketImpl(r.toString()?`${this.options.websocketUrl}?${r.toString()}`:this.options.websocketUrl),t&&this._warnOnce("_warnedQueryToken",'[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".')}}catch(e){return(this.options?.logger?.error||console.error)("[Optave SDK] WebSocket constructor threw",e),void this.handleError(y.WEBSOCKET,"WEBSOCKET_ERROR",this.formatWebSocketError(e,{url:this.options.websocketUrl}).message,e)}return new Promise((e,t)=>{const r=setTimeout(()=>{const e=this.options.connectionTimeoutMs||3e4,r=this.formatWebSocketError(new Error("Connection timeout"),{timeout:e,url:this.options.websocketUrl}).message;
// CRITICAL: Close the WebSocket to prevent zombie connections
-if(this.wss){this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null;try{this.wss.close()}catch(e){}this.wss=null}this.handleError(I.WEBSOCKET,"CONNECTION_TIMEOUT",r),t({category:I.WEBSOCKET,code:"CONNECTION_TIMEOUT",message:r,details:null})},this.options.connectionTimeoutMs||3e4);this.wss.onopen=t=>{clearTimeout(r),this.emit("open",t),e(t)},this.wss.onmessage=e=>{this._handleInbound(e.data)},this.wss.onclose=e=>{clearTimeout(r),this.emit("close",e);
+if(this.wss){this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null;try{this.wss.close()}catch(e){}this.wss=null}this.handleError(y.WEBSOCKET,"CONNECTION_TIMEOUT",r),t(new OptaveError({category:y.WEBSOCKET,code:"CONNECTION_TIMEOUT",message:r,details:null}))},this.options.connectionTimeoutMs||3e4);this.wss.onopen=t=>{clearTimeout(r),this.emit("open",t),e(t)},this.wss.onmessage=e=>{this._handleInbound(e.data)},this.wss.onclose=e=>{clearTimeout(r),this.emit("close",e),
// CRITICAL: Race condition prevention for promise handling
-for(const[t,r]of this._pending.entries())r.timer&&clearTimeout(r.timer),r._handled=!0,r.reject({category:I.WEBSOCKET,code:"CONNECTION_CLOSED",message:`WebSocket connection closed: ${e.reason||"Connection lost"}`,details:{code:e.code,reason:e.reason,correlationId:t},correlationId:t});this._pending.clear(),this.wss=null},this.wss.onerror=e=>{clearTimeout(r);
+Array.from(this._pending.entries()).forEach(([t,r])=>{r.timer&&clearTimeout(r.timer),r._handled=!0,r.reject({category:y.WEBSOCKET,code:"CONNECTION_CLOSED",message:`WebSocket connection closed: ${e.reason||"Connection lost"}`,details:{code:e.code,reason:e.reason,correlationId:t},correlationId:t})}),this._pending.clear(),this.wss=null},this.wss.onerror=e=>{clearTimeout(r);
// CRITICAL: Enhanced error message handling and race condition prevention
-const s=e.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||"WebSocket connection failed",n={category:I.WEBSOCKET,code:"CONNECTION_ERROR",message:s,details:{originalError:e}};for(const[e,t]of this._pending.entries())t.timer&&clearTimeout(t.timer),t._handled=!0,t.reject({...n,details:{...n.details,correlationId:e},correlationId:e});this._pending.clear(),this.emit("error",n),t(n)}})}_warnOnce(e,t){this[e]||(this[e]=!0,(this.options?.logger?.warn||console.warn)(t))}deprecate(e,t){this._silenceDeprecations||this._deprecatedKeys.has(e)||(this._deprecatedKeys.add(e),(this.options?.logger?.warn||console.warn)(t))}_handleInbound(e){let t;try{t="string"==typeof e?JSON.parse(e):e}catch(e){const t={category:I.WEBSOCKET,code:"INVALID_JSON",message:"Invalid JSON received from server",details:e,timestamp:(new Date).toISOString()};return this._emitError(t),void 0}const r=t&&t.headers&&t.payload,s="error"===t?.state||"error"===t?.actionType||!!t?.error;if(this.options.strictValidation&&r){const e=this._validateMessageEnvelope(t);e.valid||this.handleError(I.VALIDATION,"INBOUND_ENVELOPE_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Inbound envelope validation failed"),e.errors)}if(s){const e=t?.headers&&t.headers.correlationId||t?.correlationId||null,r={category:I.ORCHESTRATOR,code:t?.error?.code||"REMOTE_ERROR",message:t?.error?.message||t?.message||"Remote error",details:t?.error||t,correlationId:e};if(e&&this._pending.has(e)){const t=this._pending.get(e);t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),t.reject(r)}return this._emitError(r,t?.action),void 0}const n=t?.headers?.correlationId||t?.correlationId;if(n&&this._pending.has(n)){const e=this._pending.get(n);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(n),e.resolve(t)}this.emit(O.MESSAGE,t),X||(X=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".')),this.emit(A.SUPERPOWER_RESPONSE,t),this.emit(T.RESPONSE,t),t?.action&&this.emit(`message.${t.action}`.toLowerCase(),t),r&&t.headers.schemaRef&&this.emit(t.headers.schemaRef,t)}_emitError(e,t=null){e.timestamp||(e.timestamp=(new Date).toISOString()),this.emit(O.ERROR,e),Z||(Z=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'));const r=z(e);this.emit(A.SUPERPOWER_ERROR,r),this.emit(T.ERROR,e)}closeConnection(){this.wss&&(this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null,this.wss.close(),this.wss=null)}selectiveDeepMerge(e,t){if(Array.isArray(e)&&Array.isArray(t))return[...t];const r=e=>null!==e&&"object"==typeof e&&!Array.isArray(e);if(r(e)&&r(t)){const r={...e};for(let s in t)r[s]=s in e?this.selectiveDeepMerge(e[s],t[s]):t[s];return r}return void 0!==t?t:e}isPayloadSizeValid(e){return!!e&&e.length/1024<=U.MAX_PAYLOAD_SIZE_KB}openConnectionAsync(e){return new Promise((t,r)=>{const s=e=>{this.off("error",n),t(e)},n=e=>{this.off("open",s),r(e)};this.once("open",s),this.once("error",n),this.openConnection(e)})}buildPayload(e,t,r){let s=this.selectiveDeepMerge(OptaveJavaScriptSDK.defaultPayload,r);return r?.request?.variation&&(this.deprecate("payload.request.variation","[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."),s.request.attributes.variant=r.request.variation),r?.request?.content&&!s.request?.attributes?.content&&(s.request.attributes.content=r.request.content,this.deprecate("payload.request.content","[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.")),s.request.attributes.variant&&(s.request.attributes.variant=s.request.attributes.variant.toUpperCase()),s}resolveMessageId(e,t){return`${t}.${e}.v3`.toLowerCase()}buildMessageEnvelope(e,t,r,s={}){const n=(new Date).toISOString(),o=s.correlationId||e?.request?.requestId||g(),i=s.traceId||g(),a=s.idempotencyKey||g(),c=s.timestamp,d=undefined,u={correlationId:o,action:r,schemaRef:_,sdkVersion:Y,identifier:t,traceId:i,idempotencyKey:a,timestamp:c,issuedAt:n};return this.options.tenantId&&(u.tenantId=this.options.tenantId),void 0!==s.networkLatencyMs&&(u.networkLatencyMs=s.networkLatencyMs),Object.freeze(u),{action:"message",headers:u,payload:e}}formatValidationErrorMessage(e,t="Validation failed"){if(!e||!Array.isArray(e)||0===e.length)return t;if(1===e.length){const r=e[0],s=r.instancePath||"/",n="/"===s?"root object":s.replace(/^\//,"").replace(/\//g,".");if("required"===r.keyword){const e=r.params?.missingProperty||"unknown field",s="root object"===n?e:n.endsWith(e)?n:n+"."+e;return`${t}: ${"root object"===n?"Required field":"Field"} '${s}' is missing`}if("type"===r.keyword){const e=undefined;return`${t}: Field '${n}' must be of type '${r.params?.type||"unknown"}'`}if("additionalProperties"===r.keyword){const e=undefined;return`${t}: Field '${n}.${r.params?.additionalProperty||"unknown"}' is not allowed`}if("enum"===r.keyword){const e=r.params?.allowedValues||[],s=undefined;return`${t}: Field '${n}' must be one of: ${Array.isArray(e)?e.join(", "):"unknown values"}`}return`${t}: ${r.message} at '${n}'`}
+const s=e.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||"WebSocket connection failed",n={category:y.WEBSOCKET,code:"CONNECTION_ERROR",message:s,details:{originalError:e}};Array.from(this._pending.entries()).forEach(([e,t])=>{t.timer&&clearTimeout(t.timer),t._handled=!0,t.reject({...n,details:{...n.details,correlationId:e},correlationId:e})}),this._pending.clear(),this.emit("error",n),t(n)}})}_warnOnce(e,t){this[e]||(this[e]=!0,(this.options?.logger?.warn||console.warn)(t))}deprecate(e,t){this._silenceDeprecations||this._deprecatedKeys.has(e)||(this._deprecatedKeys.add(e),(this.options?.logger?.warn||console.warn)(t))}_handleInbound(e){let t;try{t="string"==typeof e?JSON.parse(e):e}catch(e){const t={category:y.WEBSOCKET,code:"INVALID_JSON",message:"Invalid JSON received from server",details:e,timestamp:(new Date).toISOString()};return void this._emitError(t)}const r=t&&t.headers&&t.payload,s="error"===t?.state||"error"===t?.actionType||!!t?.error;if(this.options.strictValidation&&r){const e=this._validateMessageEnvelope(t);e.valid||this.handleError(y.VALIDATION,"INBOUND_ENVELOPE_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Inbound envelope validation failed"),e.errors)}if(s){const e=t?.headers&&t.headers.correlationId||t?.correlationId||null,r={category:y.ORCHESTRATOR,code:t?.error?.code||"REMOTE_ERROR",message:t?.error?.message||t?.message||"Remote error",details:t?.error||t,correlationId:e};if(e&&this._pending.has(e)){const t=this._pending.get(e);t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),t.reject(r)}return void this._emitError(r,t?.action)}const n=t?.headers?.correlationId||t?.correlationId;if(n&&this._pending.has(n)){const e=this._pending.get(n);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(n),e.resolve(t)}this.emit(v.MESSAGE,t),W||(W=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".')),this.emit(E.SUPERPOWER_RESPONSE,t),this.emit(b.RESPONSE,t),t?.action&&this.emit(`message.${t.action}`.toLowerCase(),t),r&&t.headers.schemaRef&&this.emit(t.headers.schemaRef,t)}_emitError(e,t=null){e.timestamp||(e.timestamp=(new Date).toISOString()),this.emit(v.ERROR,e),j||(j=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'));const r=(s=e)&&s.category&&s.code&&s.message?new OptaveError(s):"string"==typeof s?new OptaveError({category:"UNKNOWN",code:"STRING_ERROR",message:s}):s&&s.isAuthError?new OptaveError({category:"AUTHENTICATION",code:s.code||"AUTH_ERROR",message:s.message||"Authentication error",details:s}):s&&s.isWsError?new OptaveError({category:"WEBSOCKET",code:s.code||"WS_ERROR",message:s.message||"WebSocket error",details:s}):new OptaveError({category:"UNKNOWN",code:"UNCLASSIFIED",message:s&&s.message||String(null!=s?s:"Unknown error"),details:s});var s;this.emit(E.SUPERPOWER_ERROR,r),this.emit(b.ERROR,e)}closeConnection(){this.wss&&(this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null,this.wss.close(),this.wss=null)}selectiveDeepMerge(e,t){if(Array.isArray(e)&&Array.isArray(t))return[...t];const r=e=>null!==e&&"object"==typeof e&&!Array.isArray(e);if(r(e)&&r(t)){const r={...e};return Object.keys(t).forEach(s=>{r[s]=s in e?this.selectiveDeepMerge(e[s],t[s]):t[s]}),r}return void 0!==t?t:e}isPayloadSizeValid(e){return!!e&&e.length/1024<=w.MAX_PAYLOAD_SIZE_KB}openConnectionAsync(e){return new Promise((t,r)=>{let s;const n=e=>{this.off("error",s),t(e)};s=e=>{this.off("open",n),r(e)},this.once("open",n),this.once("error",s),this.openConnection(e)})}buildPayload(e,t,r){const s=this.selectiveDeepMerge(OptaveJavaScriptSDK.defaultPayload,r);return r?.request?.variation&&(this.deprecate("payload.request.variation","[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."),s.request.attributes.variant=r.request.variation),r?.request?.content&&!s.request?.attributes?.content&&(s.request.attributes.content=r.request.content,this.deprecate("payload.request.content","[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.")),s.request.attributes.variant&&(s.request.attributes.variant=s.request.attributes.variant.toUpperCase()),s}resolveMessageId(e,t){return`${t}.${e}.v3`.toLowerCase()}buildMessageEnvelope(e,t,r,s={}){const n=(new Date).toISOString(),o=s.correlationId||e?.request?.requestId||p(),i=s.traceId||p(),a=s.idempotencyKey||p(),{timestamp:c}=s,u={correlationId:o,action:r,schemaRef:g,sdkVersion:D,identifier:t,traceId:i,idempotencyKey:a,timestamp:c,issuedAt:n};return this.options.tenantId&&(u.tenantId=this.options.tenantId),void 0!==s.networkLatencyMs&&(u.networkLatencyMs=s.networkLatencyMs),Object.freeze(u),{action:"message",headers:u,payload:e}}formatValidationErrorMessage(e,t="Validation failed"){if(!e||!Array.isArray(e)||0===e.length)return t;if(1===e.length){const r=e[0],s=r.instancePath||"/",n="/"===s?"root object":s.replace(/^\//,"").replace(/\//g,".");if("required"===r.keyword){const e=r.params?.missingProperty||"unknown field";let s;return s="root object"===n?e:n.endsWith(e)?n:`${n}.${e}`,`${t}: ${"root object"===n?"Required field":"Field"} '${s}' is missing`}if("type"===r.keyword){return`${t}: Field '${n}' must be of type '${r.params?.type||"unknown"}'`}if("additionalProperties"===r.keyword){return`${t}: Field '${n}.${r.params?.additionalProperty||"unknown"}' is not allowed`}if("enum"===r.keyword){const e=r.params?.allowedValues||[];return`${t}: Field '${n}' must be one of: ${Array.isArray(e)?e.join(", "):"unknown values"}`}return`${t}: ${r.message} at '${n}'`}
// If there are multiple errors, provide a summary with the most critical ones
-const r=e.filter(e=>"required"===e.keyword),s=e.filter(e=>"type"===e.keyword),n=e.filter(e=>"required"!==e.keyword&&"type"!==e.keyword);let o=t+":";if(r.length>0){const e=undefined;o+=` Missing required fields: ${r.map(e=>{const t=(e.instancePath||"/").replace(/^\//,"").replace(/\//g,"."),r=e.params?.missingProperty||"unknown";return""===t?r:`${t}.${r}`}).join(", ")}.`}if(s.length>0){const e=undefined;o+=` Type errors in: ${s.slice(0,3).map(e=>{const t=undefined,r=undefined;return`${(e.instancePath||"/").replace(/^\//,"").replace(/\//g,".")||"root"} (expected ${e.params?.type||"unknown"})`}).join(", ")}.`,s.length>3&&(o+=` And ${s.length-3} more type errors.`)}return n.length>0&&(o+=` Additional validation errors: ${n.length}.`),o}formatAuthenticationError(e,t,r){let s="Authentication failed";const n=[];return e&&e.status&&(s+=` (HTTP ${e.status})`),t&&("string"==typeof t?s+=`: ${t}`:t.error_description?s+=`: ${t.error_description}`:t.message?s+=`: ${t.message}`:t.error&&(s+=`: ${t.error}`)),e&&401===e.status?(n.push("Verify clientId and clientSecret are correct"),n.push("Ensure credentials match the target environment (dev/staging/production)")):e&&403===e.status?(n.push("Check if your client has the necessary permissions"),n.push("Verify the authentication endpoint URL is correct")):e&&e.status>=500?(n.push("Authentication server error - try again later"),n.push("Contact support if the problem persists")):n.push("Check network connectivity and authentication endpoint configuration"),r&&r.authUrl&&(s+=` (endpoint: ${r.authUrl})`),{message:s,suggestions:n}}formatWebSocketError(e,t){let r="WebSocket connection failed";const s=[],n=e?.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||null;return n&&(r+=`: ${n}`),t&&(t.url&&(r+=` (URL: ${t.url})`),t.timeout&&(r+=` (timeout: ${t.timeout}ms)`)),s.push("Check network connectivity and firewall settings"),s.push("Verify WebSocket URL is correct and accessible"),t&&t.url&&(t.url.startsWith("ws://")&&s.push("Consider using secure WebSocket (wss://) for production"),(t.url.includes("localhost")||t.url.includes("127.0.0.1"))&&s.push("Ensure local server is running if connecting to localhost")),t&&t.timeout&&s.push("Try increasing connection timeout if network is slow"),{message:r,suggestions:s}}formatPayloadSizeError(e,t,r){const s=Math.ceil(e/1024),n=t,o=undefined;let i=`Payload too large: ${s}KB exceeds maximum ${t}KB (${s-t}KB over limit)`;const a=[];if(r&&"object"==typeof r){const e=JSON.stringify(r);if(r.request?.scope?.conversations&&Array.isArray(r.request.scope.conversations)){const e=JSON.stringify(r.request.scope.conversations).length,t=Math.ceil(e/1024);t>10&&(a.push(`Consider reducing conversation history - current size: ~${t}KB`),a.push("Remove older messages or summarize conversation context"))}if(r.request?.resources?.offers&&Array.isArray(r.request.resources.offers)){const e=JSON.stringify(r.request.resources.offers).length,t=Math.ceil(e/1024);t>5&&a.push(`Consider reducing product offers data - current size: ~${t}KB`)}if(r.session?.channel?.metadata&&Array.isArray(r.session.channel.metadata)){const e=JSON.stringify(r.session.channel.metadata).length,t=Math.ceil(e/1024);t>2&&a.push(`Consider reducing metadata array - current size: ~${t}KB`)}}return 0===a.length&&(a.push("Remove unused fields from request payload"),a.push("Consider paginating large datasets"),a.push("Use shorter field values where possible")),{message:i,suggestions:a}}formatTokenProviderError(e,t){let r="Failed to obtain WebSocket token from tokenProvider()";const s=[];return e&&(e.message?r+=`: ${e.message}`:"string"==typeof e&&(r+=`: ${e}`),"TypeError"===e.name&&e.message?.includes("fetch")?(s.push("Check if tokenProvider endpoint is accessible"),s.push("Verify CORS settings allow requests to token endpoint")):e.message?.includes("404")||e.message?.includes("Not Found")?(s.push("Verify tokenProvider endpoint URL is correct"),s.push("Ensure backend token endpoint is implemented")):e.message?.includes("401")||e.message?.includes("403")?(s.push("Check authentication/authorization for token endpoint"),s.push("Verify user session or credentials are valid")):e.message?.includes("timeout")&&s.push("Token provider request timed out - check network or server response time")),t&&t.tokenUrl&&(r+=` (endpoint: ${t.tokenUrl})`),0===s.length&&(s.push("Verify tokenProvider function implementation"),s.push("Check backend token endpoint is running and accessible"),s.push("Review browser console for network errors")),{message:r,suggestions:s}}handleError(e,t,r,s=null,n=[],o=null){const i=new x({category:e,code:t,message:r,details:s});n&&(i.suggestions=n),o&&(i.correlationId=o),0===this.listenerCount(O.ERROR)&&0===this.listenerCount(T.ERROR)&&(this.options?.logger?.error||console.error)(`[Optave SDK] ${t}: ${r}`),this._emitError(i)}send(e,t,r){const s=null!=(this.WebSocketImpl&&this.WebSocketImpl.OPEN)?this.WebSocketImpl.OPEN:1;if(!this.wss||this.wss.readyState!==s){const e=this.wss?this.wss.readyState:"no connection";return this.handleError(I.WEBSOCKET,"WEBSOCKET_NOT_IN_OPEN_STATE",this.formatWebSocketError(new Error("WebSocket not ready for sending"),{readyState:e,action:t}).message),void 0}if(!R.has(t))return this.handleError(I.VALIDATION,"INVALID_ACTION",`Unsupported action '${t}'. Allowed: ${[...R].join(", ")}`),void 0;const n=new Set(["session","request","headers"]);for(const e of Object.keys(r||{}))if(!n.has(e)){const t=[{instancePath:"",keyword:"additionalProperties",params:{additionalProperty:e},message:`must NOT have additional property '${e}'`}];return this.handleError(I.VALIDATION,"PAYLOAD_SCHEMA_MISMATCH",this.formatValidationErrorMessage(t),t),void 0}const o=this.buildPayload(e,t,r||{}),i=this.validateRequiredFields(o||{},t);if(!i.isValid)return this.handleError(I.VALIDATION,"REQUIRED_FIELDS_MISSING",`Missing required fields for action '${t}': ${i.errors.join(", ")}`,i.errors),void 0;if(this.options.strictValidation){const e=this._validatePayload(o);if(!e.valid)return this.handleError(I.VALIDATION,"PAYLOAD_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Schema validation failed"),e.errors),void 0}const a=this.buildMessageEnvelope(o,e,t,r?.headers||{}),c=JSON.stringify(a);if(!this.isPayloadSizeValid(c)){const e=c.length;return this.handleError(I.VALIDATION,"PAYLOAD_TOO_LARGE",this.formatPayloadSizeError(e,U.MAX_PAYLOAD_SIZE_KB,a).message,U.MAX_PAYLOAD_SIZE_KB),void 0}this.wss.send(c)}adjust(e){return this.send("message","adjust",e)}elevate(e){return this.send("message","elevate",e)}interaction(e){return this.send("message","interaction",e)}reception(e){return this.send("message","reception",e)}customerInteraction(e){return this.deprecate("method.customerInteraction","[Deprecation] 'customerInteraction' is deprecated; use 'interaction' instead."),this.send("message","customerInteraction",e)}summarize(e){return this.send("message","summarize",e)}translate(e){return this.send("message","translate",e)}recommend(e){return this.send("message","recommend",e)}insights(e){return this.send("message","insights",e)}_registerPending(e,t,r,s,n){let o=null;r>0&&(o=setTimeout(()=>{if(this._pending.has(e)){const s=this._pending.get(e);s&&!s._handled&&(this._pending.delete(e),s._handled=!0,n({category:I.WEBSOCKET,code:"REQUEST_TIMEOUT",message:`Request timed out after ${r}ms`,details:{correlationId:e,action:t},correlationId:e}))}},r)),this._pending.set(e,{resolve:s,reject:n,timer:o,action:t,_handled:!1})}_promiseSend(e,t,r={},s={}){let n,o,i;const a=new Promise((a,c)=>{o=a,i=c;const d="number"==typeof s.timeoutMs?s.timeoutMs:"number"==typeof s.timeout?s.timeout:this.options.requestTimeoutMs;if(!this.wss||this.wss.readyState!==WebSocket.OPEN){if(d<=0)return c({category:I.WEBSOCKET,code:"WEBSOCKET_NOT_IN_OPEN_STATE",message:"WebSocket not open",details:null}),void 0;const s=this.buildPayload(e,t,r),o=this.buildMessageEnvelope(s,e,t,r?.headers||{});return n=o.headers.correlationId,this._registerPending(n,t,d,a,c),void 0}if(!R.has(t))return c({category:I.VALIDATION,code:"INVALID_ACTION",message:`Unsupported action '${t}'.`,details:{allowed:[...R]}}),void 0;const u=new Set(["session","request","headers"]);for(const e of Object.keys(r||{}))if(!u.has(e)){const t=[{instancePath:"",keyword:"additionalProperties",params:{additionalProperty:e},message:`must NOT have additional property '${e}'`}];return c({category:I.VALIDATION,code:"PAYLOAD_SCHEMA_MISMATCH",message:this.formatValidationErrorMessage(t),details:t}),void 0}const l=this.buildPayload(e,t,r),p=this.validateRequiredFields(l,t);if(!p.isValid)return c({category:I.VALIDATION,code:"REQUIRED_FIELDS_MISSING",message:`Missing required fields for action '${t}'`,details:p.errors}),void 0;if(this.options.strictValidation){const e=v(l);if(!e.valid)return c({category:I.VALIDATION,code:"PAYLOAD_SCHEMA_MISMATCH",message:this.formatValidationErrorMessage(e.errors,"Schema validation failed"),details:e.errors}),void 0}const h=this.buildMessageEnvelope(l,e,t,r?.headers||{});n=h.headers.correlationId,this._registerPending(n,t,d,a,c);const f=JSON.stringify(h);if(!this.isPayloadSizeValid(f)){const e=f.length,t=this.formatPayloadSizeError(e,U.MAX_PAYLOAD_SIZE_KB,h).message;return c({category:I.VALIDATION,code:"PAYLOAD_TOO_LARGE",message:t,details:{maxKb:U.MAX_PAYLOAD_SIZE_KB}}),void 0}try{this.wss.send(f)}catch(e){if(this._pending.has(n)){const e=this._pending.get(n);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(n)}c({category:I.WEBSOCKET,code:"SEND_FAILED",message:"Failed to send over WebSocket",details:e,correlationId:n})}});return a.correlationId=n,a}adjustAsync(e,t){return this._promiseSend("message","adjust",e,t)}elevateAsync(e,t){return this._promiseSend("message","elevate",e,t)}interactionAsync(e,t){return this._promiseSend("message","interaction",e,t)}receptionAsync(e,t){return this._promiseSend("message","reception",e,t)}customerInteractionAsync(e,t){return this.deprecate("method.customerInteractionAsync","[Deprecation] 'customerInteractionAsync' is deprecated; use 'interactionAsync' instead."),this._promiseSend("message","customerInteraction",e,t)}summarizeAsync(e,t){return this._promiseSend("message","summarize",e,t)}translateAsync(e,t){return this._promiseSend("message","translate",e,t)}recommendAsync(e,t){return this._promiseSend("message","recommend",e,t)}insightsAsync(e,t){return this._promiseSend("message","insights",e,t)}cancelRequest(e){if(this._pending.has(e)){const t=this._pending.get(e);return t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),setTimeout(()=>{t.reject({category:I.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:e},correlationId:e})},0),!0}return!1}cancelPendingRequests(e=!1){if(!this._pending)return 0;const t=this._pending.size,r=[...this._pending.entries()];for(const[t,s]of r)s.timer&&clearTimeout(s.timer),s._handled=!0,e?s.reject({category:I.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled during cleanup",details:{correlationId:t},correlationId:t}):queueMicrotask(()=>{s.reject({category:I.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:t},correlationId:t})});return this._pending.clear(),t}cleanup(){
+const r=e.filter(e=>"required"===e.keyword),s=e.filter(e=>"type"===e.keyword),n=e.filter(e=>"required"!==e.keyword&&"type"!==e.keyword);let o=`${t}:`;if(r.length>0){o+=` Missing required fields: ${r.map(e=>{const t=(e.instancePath||"/").replace(/^\//,"").replace(/\//g,"."),r=e.params?.missingProperty||"unknown";return""===t?r:`${t}.${r}`}).join(", ")}.`}if(s.length>0){o+=` Type errors in: ${s.slice(0,3).map(e=>`${(e.instancePath||"/").replace(/^\//,"").replace(/\//g,".")||"root"} (expected ${e.params?.type||"unknown"})`).join(", ")}.`,s.length>3&&(o+=` And ${s.length-3} more type errors.`)}return n.length>0&&(o+=` Additional validation errors: ${n.length}.`),o}formatAuthenticationError(e,t,r){let s="Authentication failed";const n=[];return e&&e.status&&(s+=` (HTTP ${e.status})`),t&&("string"==typeof t?s+=`: ${t}`:t.error_description?s+=`: ${t.error_description}`:t.message?s+=`: ${t.message}`:t.error&&(s+=`: ${t.error}`)),e&&401===e.status?(n.push("Verify clientId and clientSecret are correct"),n.push("Ensure credentials match the target environment (dev/staging/production)")):e&&403===e.status?(n.push("Check if your client has the necessary permissions"),n.push("Verify the authentication endpoint URL is correct")):e&&e.status>=500?(n.push("Authentication server error - try again later"),n.push("Contact support if the problem persists")):n.push("Check network connectivity and authentication endpoint configuration"),r&&r.authUrl&&(s+=` (endpoint: ${r.authUrl})`),{message:s,suggestions:n}}formatWebSocketError(e,t){let r="WebSocket connection failed";const s=[],n=e?.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||null;return n&&(r+=`: ${n}`),t&&(t.url&&(r+=` (URL: ${t.url})`),t.timeout&&(r+=` (timeout: ${t.timeout}ms)`)),s.push("Check network connectivity and firewall settings"),s.push("Verify WebSocket URL is correct and accessible"),t&&t.url&&(t.url.startsWith("ws://")&&s.push("Consider using secure WebSocket (wss://) for production"),(t.url.includes("localhost")||t.url.includes("127.0.0.1"))&&s.push("Ensure local server is running if connecting to localhost")),t&&t.timeout&&s.push("Try increasing connection timeout if network is slow"),{message:r,suggestions:s}}formatPayloadSizeError(e,t,r){const s=Math.ceil(e/1024),n=`Payload too large: ${s}KB exceeds maximum ${t}KB (${s-t}KB over limit)`,o=[];if(r&&"object"==typeof r){if(r.request?.scope?.conversations&&Array.isArray(r.request.scope.conversations)){const e=JSON.stringify(r.request.scope.conversations).length,t=Math.ceil(e/1024);t>10&&(o.push(`Consider reducing conversation history - current size: ~${t}KB`),o.push("Remove older messages or summarize conversation context"))}if(r.request?.resources?.offers&&Array.isArray(r.request.resources.offers)){const e=JSON.stringify(r.request.resources.offers).length,t=Math.ceil(e/1024);t>5&&o.push(`Consider reducing product offers data - current size: ~${t}KB`)}if(r.session?.channel?.metadata&&Array.isArray(r.session.channel.metadata)){const e=JSON.stringify(r.session.channel.metadata).length,t=Math.ceil(e/1024);t>2&&o.push(`Consider reducing metadata array - current size: ~${t}KB`)}}return 0===o.length&&(o.push("Remove unused fields from request payload"),o.push("Consider paginating large datasets"),o.push("Use shorter field values where possible")),{message:n,suggestions:o}}formatTokenProviderError(e,t){let r="Failed to obtain WebSocket token from tokenProvider()";const s=[];return e&&(e.message?r+=`: ${e.message}`:"string"==typeof e&&(r+=`: ${e}`),"TypeError"===e.name&&e.message?.includes("fetch")?(s.push("Check if tokenProvider endpoint is accessible"),s.push("Verify CORS settings allow requests to token endpoint")):e.message?.includes("404")||e.message?.includes("Not Found")?(s.push("Verify tokenProvider endpoint URL is correct"),s.push("Ensure backend token endpoint is implemented")):e.message?.includes("401")||e.message?.includes("403")?(s.push("Check authentication/authorization for token endpoint"),s.push("Verify user session or credentials are valid")):e.message?.includes("timeout")&&s.push("Token provider request timed out - check network or server response time")),t&&t.tokenUrl&&(r+=` (endpoint: ${t.tokenUrl})`),0===s.length&&(s.push("Verify tokenProvider function implementation"),s.push("Check backend token endpoint is running and accessible"),s.push("Review browser console for network errors")),{message:r,suggestions:s}}handleError(e,t,r,s=null,n=[],o=null){const i=new OptaveError({category:e,code:t,message:r,details:s});n&&(i.suggestions=n),o&&(i.correlationId=o),0===this.listenerCount(v.ERROR)&&0===this.listenerCount(b.ERROR)&&(this.options?.logger?.error||console.error)(`[Optave SDK] ${t}: ${r}`),this._emitError(i)}send(e,t,r){const s=null!=(this.WebSocketImpl&&this.WebSocketImpl.OPEN)?this.WebSocketImpl.OPEN:1;if(!this.wss||this.wss.readyState!==s){const e=this.wss?this.wss.readyState:"no connection";return void this.handleError(y.WEBSOCKET,"WEBSOCKET_NOT_IN_OPEN_STATE",this.formatWebSocketError(new Error("WebSocket not ready for sending"),{readyState:e,action:t}).message)}if(!S.has(t))return void this.handleError(y.VALIDATION,"INVALID_ACTION",`Unsupported action '${t}'. Allowed: ${[...S].join(", ")}`);const n=new Set(["session","request","headers"]),o=Object.keys(r||{});for(let e=0;e0&&(o=setTimeout(()=>{if(this._pending.has(e)){const s=this._pending.get(e);s&&!s._handled&&(this._pending.delete(e),s._handled=!0,n({category:y.WEBSOCKET,code:"REQUEST_TIMEOUT",message:`Request timed out after ${r}ms`,details:{correlationId:e,action:t},correlationId:e}))}},r)),this._pending.set(e,{resolve:s,reject:n,timer:o,action:t,_handled:!1})}_promiseSend(e,t,r={},s={}){let n;const o=new Promise((o,i)=>{let a;if(a="number"==typeof s.timeoutMs?s.timeoutMs:"number"==typeof s.timeout?s.timeout:this.options.requestTimeoutMs,!this.wss||this.wss.readyState!==WebSocket.OPEN){if(a<=0)return void i(new OptaveError({category:y.WEBSOCKET,code:"WEBSOCKET_NOT_IN_OPEN_STATE",message:"WebSocket not open",details:null}));const s=this.buildPayload(e,t,r),c=this.buildMessageEnvelope(s,e,t,r?.headers||{});return n=c.headers.correlationId,void this._registerPending(n,t,a,o,i)}if(!S.has(t))return void i(new OptaveError({category:y.VALIDATION,code:"INVALID_ACTION",message:`Unsupported action '${t}'.`,details:{allowed:[...S]}}));const c=new Set(["session","request","headers"]),u=Object.keys(r||{});for(let e=0;e{t.reject({category:y.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:e},correlationId:e})},0),!0}return!1}cancelPendingRequests(e=!1){if(!this._pending)return 0;const t=this._pending.size;return[...this._pending.entries()].forEach(([t,r])=>{r.timer&&clearTimeout(r.timer),r._handled=!0,e?r.reject({category:y.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled during cleanup",details:{correlationId:t},correlationId:t}):queueMicrotask(()=>{r.reject({category:y.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:t},correlationId:t})})}),this._pending.clear(),t}cleanup(){this.closeConnection(),this.cancelPendingRequests(!0),this._deprecatedKeys&&this._deprecatedKeys.clear(),void 0!==this._warnedQueryToken&&delete this._warnedQueryToken,
// CRITICAL: Clear EventEmitter state BEFORE calling removeAllListeners
-if(this.closeConnection(),this.cancelPendingRequests(!0),this._deprecatedKeys&&this._deprecatedKeys.clear(),void 0!==this._warnedQueryToken&&delete this._warnedQueryToken,this._events)for(const e in this._events)delete this._events[e];this.removeAllListeners(),
+this._events&&Object.keys(this._events).forEach(e=>{delete this._events[e]}),this.removeAllListeners(),
// CRITICAL: Set EventEmitter properties to null AFTER removeAllListeners
-this._events=null,this._eventsCount=null,this._maxListeners=null;
-// CRITICAL: Clean up JSDOM contexts created by SDK loader
-const e="browser-umd";if(1,1,this.constructor._preservedJSDOM&&this.constructor._preservedJSDOM.dom)try{const e=this.constructor._preservedJSDOM.dom.window;e&&"function"==typeof e.close&&e.close(),delete this.constructor._preservedJSDOM}catch(e){}this._validatePayload=null,this._validateMessageEnvelope=null,this._emitError=null,this._ensureWebSocketImpl=null,this._handleInbound=null,this._promiseSend=null,this._registerPending=null,this._warnOnce=null,this.options=null,this.WebSocketImpl=null,this.wss=null,this.sessionId=null,this._pending=null,this._deprecatedKeys=null,this._silenceDeprecations=null,this._events=null,this._eventsCount=null,this._maxListeners=null}removeAllListeners(e){try{n.prototype.removeAllListeners.call(this,e)}catch(t){e?this._events&&this._events[e]&&(delete this._events[e],this._eventsCount=Math.max(0,this._eventsCount-1)):(this._events=Object.create(null),this._eventsCount=0)}return this}static get buildFlags(){const e="browser-umd";return{SALESFORCE_BUILD:!1,INCLUDE_WS_REQUIRE:!1,SDK_VERSION:"3.2.3",WEBPACK_BUILD_TARGET:e,WEBPACK_BUILD_TARGET_NORMALIZED:B.normalize(e),BUILD_TARGET_INFO:B.getInfo(e)}}}const ee=null;let te;te="undefined"!=typeof globalThis&&globalThis.crypto&&globalThis.crypto.getRandomValues?globalThis.crypto:"undefined"!=typeof window&&window.crypto&&window.crypto.getRandomValues?window.crypto:"undefined"!=typeof self&&self.crypto&&self.crypto.getRandomValues?self.crypto:{getRandomValues:function(e){for(let t=0;t65536*Math.trunc(65536*Math.random())+Math.trunc(65536*Math.random())}}generate(){return this.generateOrResetCore(Date.now(),1e4)}generateOrResetCore(e,t){let r=this.generateOrAbortCore(e,t);return void 0===r&&(this.timestamp=0,r=this.generateOrAbortCore(e,t)),r}generateOrAbortCore(e,t){const r=4398046511103;if(!Number.isInteger(e)||e<1||e>0xffffffffffff)throw new RangeError("unixTsMs must be a 48-bit positive integer");if(e>this.timestamp)this.timestamp=e,this.resetCounter();else{if(!(e+t>=this.timestamp))return;this.counter++,this.counter>r&&(this.timestamp++,this.resetCounter())}return this.fromFieldsV7(this.timestamp,Math.trunc(this.counter/2**30),this.counter&2**30-1,this.random.nextUint32())}resetCounter(){this.counter=1024*this.random.nextUint32()+(1023&this.random.nextUint32())}fromFieldsV7(e,t,r,s){const n=new Uint8Array(16);return n[0]=e/2**40,n[1]=e/2**32,n[2]=e/2**24,n[3]=e/65536,n[4]=e/256,n[5]=e,n[6]=112|t>>>8,n[7]=t,n[8]=128|r>>>24,n[9]=r>>>16,n[10]=r>>>8,n[11]=r,n[12]=s>>>24,n[13]=s>>>16,n[14]=s>>>8,n[15]=s,this.bytesToString(n)}bytesToString(e){const t=Array.from(e,e=>e.toString(16).padStart(2,"0")).join("");return[t.substring(0,8),t.substring(8,12),t.substring(12,16),t.substring(16,20),t.substring(20,32)].join("-")}}class se{constructor(){this.buffer=new Uint32Array(8),this.cursor=65535}nextUint32(){return this.cursor>=this.buffer.length&&(te.getRandomValues(this.buffer),this.cursor=0),this.buffer[this.cursor++]}}let ne=null;function oe(e,t){if(e&&!e.crypto)try{const r=Object.getOwnPropertyDescriptor(e,t);r&&!1===r.configurable||(e.crypto=te)}catch(t){console.debug("Cannot set crypto property on",e.constructor.name,":",t.message)}}te.randomUUID=function(){return ne||(ne=new re),ne.generate()},te.generateUUID=function(){return ne||(ne=new re),ne.generate()},
+this._events=null,this._eventsCount=null,this._maxListeners=null;if(this.constructor._preservedJSDOM&&this.constructor._preservedJSDOM.dom)try{const e=this.constructor._preservedJSDOM.dom.window;e&&"function"==typeof e.close&&e.close(),delete this.constructor._preservedJSDOM}catch(e){}this._validatePayload=null,this._validateOutboundPayload=null,this._validateMessageEnvelope=null,this._emitError=null,this._ensureWebSocketImpl=null,this._handleInbound=null,this._promiseSend=null,this._registerPending=null,this._warnOnce=null,this.options=null,this.WebSocketImpl=null,this.wss=null,this.sessionId=null,this._pending=null,this._deprecatedKeys=null,this._silenceDeprecations=null,this._events=null,this._eventsCount=null,this._maxListeners=null}removeAllListeners(e){try{n.prototype.removeAllListeners.call(this,e)}catch(t){e?this._events&&this._events[e]&&(delete this._events[e],this._eventsCount=Math.max(0,this._eventsCount-1)):(this._events=Object.create(null),this._eventsCount=0)}return this}static get buildFlags(){const e="browser-umd";return{SALESFORCE_BUILD:!1,INCLUDE_WS_REQUIRE:!1,SDK_VERSION:"3.6.0",WEBPACK_BUILD_TARGET:e,WEBPACK_BUILD_TARGET_NORMALIZED:P.normalize(e),BUILD_TARGET_INFO:P.getInfo(e)}}}const V="undefined"!=typeof globalThis&&globalThis.crypto&&globalThis.crypto.getRandomValues?globalThis.crypto:"undefined"!=typeof window&&window.crypto&&window.crypto.getRandomValues?window.crypto:"undefined"!=typeof globalThis&&globalThis.self&&globalThis.self.crypto&&globalThis.self.crypto.getRandomValues?globalThis.self.crypto:{getRandomValues(e){for(let t=0;t=e.length&&(V.getRandomValues(e),t=0);const r=e[t];return t+=1,r}}}():{nextUint32:()=>65536*Math.trunc(65536*Math.random())+Math.trunc(65536*Math.random())}}generate(){return this.generateOrResetCore(Date.now(),1e4)}generateOrResetCore(e,t){let r=this.generateOrAbortCore(e,t);return void 0===r&&(this.timestamp=0,r=this.generateOrAbortCore(e,t)),r}generateOrAbortCore(e,t){if(!Number.isInteger(e)||e<1||e>0xffffffffffff)throw new RangeError("unixTsMs must be a 48-bit positive integer");if(e>this.timestamp)this.timestamp=e,this.resetCounter();else{if(!(e+t>=this.timestamp))return;this.counter++,this.counter>4398046511103&&(this.timestamp++,this.resetCounter())}return this.fromFieldsV7(this.timestamp,Math.trunc(this.counter/2**30),this.counter&2**30-1,this.random.nextUint32())}resetCounter(){this.counter=1024*this.random.nextUint32()+(1023&this.random.nextUint32())}fromFieldsV7(e,t,r,s){const n=new Uint8Array(16);return n[0]=e/2**40,n[1]=e/2**32,n[2]=e/2**24,n[3]=e/65536,n[4]=e/256,n[5]=e,n[6]=112|t>>>8,n[7]=t,n[8]=128|r>>>24,n[9]=r>>>16,n[10]=r>>>8,n[11]=r,n[12]=s>>>24,n[13]=s>>>16,n[14]=s>>>8,n[15]=s,this.bytesToString(n)}bytesToString(e){const t=Array.from(e,e=>e.toString(16).padStart(2,"0")).join("");return[t.substring(0,8),t.substring(8,12),t.substring(12,16),t.substring(16,20),t.substring(20,32)].join("-")}}let $=null;function K(e,t){if(e&&!e.crypto)try{const r=Object.getOwnPropertyDescriptor(e,t);r&&!1===r.configurable||(e.crypto=V)}catch{}}V.randomUUID=function(){return $||($=new V7Generator),$.generate()},V.generateUUID=function(){return $||($=new V7Generator),$.generate()},
// Generate short ID using UUID v7 for cryptographic security
-te.generateShortId=function(){return ne.generate().replace(/-/g,"").substring(0,9)},"undefined"!=typeof globalThis&&oe(globalThis,"crypto"),"undefined"!=typeof window&&oe(window,"crypto"),"undefined"!=typeof self&&oe(self,"crypto");try{"undefined"!=typeof module&&"object"==typeof module.exports&&"undefined"!=typeof require&&(module.exports=te,module.exports.default=te,module.exports.getRandomValues=te.getRandomValues.bind(te),module.exports.randomUUID=te.randomUUID?te.randomUUID.bind(te):te.randomUUID,module.exports.generateUUID=te.generateUUID.bind(te),module.exports.generateShortId=te.generateShortId.bind(te))}catch(e){}const ie=te.getRandomValues.bind(te),ae=te.randomUUID?te.randomUUID.bind(te):te.randomUUID,ce=te.generateUUID.bind(te),de=te.generateShortId.bind(te),ue=null;if("undefined"!=typeof globalThis&&!globalThis.OptaveJavaScriptSDK)try{globalThis.OptaveJavaScriptSDK=OptaveJavaScriptSDK}catch{}const le=OptaveJavaScriptSDK;return s=s.default})());
\ No newline at end of file
+V.generateShortId=function(){return $.generate().replace(/-/g,"").substring(0,9)},"undefined"!=typeof globalThis&&K(globalThis,"crypto"),"undefined"!=typeof window&&K(window,"crypto"),"undefined"!=typeof globalThis&&globalThis.self&&K(globalThis.self,"crypto");try{"undefined"!=typeof module&&"object"==typeof module.exports&&"undefined"!=typeof require&&(module.exports=V,module.exports.default=V,module.exports.getRandomValues=V.getRandomValues.bind(V),module.exports.randomUUID=V.randomUUID?V.randomUUID.bind(V):V.randomUUID,module.exports.generateUUID=V.generateUUID.bind(V),module.exports.generateShortId=V.generateShortId.bind(V))}catch(e){}V.getRandomValues.bind(V),V.randomUUID?V.randomUUID.bind(V):V.randomUUID,V.generateUUID.bind(V),V.generateShortId.bind(V);
+// Salesforce Lightning loads this UMD bundle as a static resource and reads
+if("undefined"!=typeof window&&!window.OptaveJavaScriptSDK)try{window.OptaveJavaScriptSDK=OptaveJavaScriptSDK}catch{}if("undefined"!=typeof globalThis&&!globalThis.OptaveJavaScriptSDK)try{globalThis.OptaveJavaScriptSDK=OptaveJavaScriptSDK}catch{}const B=OptaveJavaScriptSDK;return s=s.default,s})());
+//# sourceMappingURL=browser.umd.js.map
\ No newline at end of file
diff --git a/sdks/javascript/dist/browser.umd.js.map b/sdks/javascript/dist/browser.umd.js.map
new file mode 100644
index 0000000..b235e7a
--- /dev/null
+++ b/sdks/javascript/dist/browser.umd.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"browser.umd.js","mappings":"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","sources":["webpack://OptaveJavaScriptSDK/webpack/universalModuleDefinition","webpack://OptaveJavaScriptSDK/../../node_modules/events/events.js","webpack://OptaveJavaScriptSDK/./runtime/platform/browser/urlsearchparams-polyfill.js","webpack://OptaveJavaScriptSDK/webpack/bootstrap","webpack://OptaveJavaScriptSDK/webpack/runtime/define property getters","webpack://OptaveJavaScriptSDK/webpack/runtime/hasOwnProperty shorthand","webpack://OptaveJavaScriptSDK/../../node_modules/uuid/dist/rng.js","webpack://OptaveJavaScriptSDK/../../node_modules/uuid/dist/stringify.js","webpack://OptaveJavaScriptSDK/../../node_modules/uuid/dist/v7.js","webpack://OptaveJavaScriptSDK/./runtime/platform/browser/validators.js","webpack://OptaveJavaScriptSDK/./generated/constants.js","webpack://OptaveJavaScriptSDK/./runtime/core/constants.js","webpack://OptaveJavaScriptSDK/./runtime/validation/config-validator.js","webpack://OptaveJavaScriptSDK/./runtime/validation/pi-guard.js","webpack://OptaveJavaScriptSDK/./runtime/core/build-targets.js","webpack://OptaveJavaScriptSDK/./runtime/platform/browser/errors.js","webpack://OptaveJavaScriptSDK/./runtime/core/security-guards.js","webpack://OptaveJavaScriptSDK/./runtime/core/main.js","webpack://OptaveJavaScriptSDK/./runtime/platform/browser/crypto-polyfill.js","webpack://OptaveJavaScriptSDK/./runtime/core/umd-entry.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"OptaveJavaScriptSDK\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"OptaveJavaScriptSDK\"] = factory();\n\telse\n\t\troot[\"OptaveJavaScriptSDK\"] = factory();\n})((function() { return typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : (typeof globalThis !== 'undefined' ? globalThis : this)); })(), () => {\nreturn ","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\nfunction once(emitter, name) {\n return new Promise(function (resolve, reject) {\n function errorListener(err) {\n emitter.removeListener(name, resolver);\n reject(err);\n }\n\n function resolver() {\n if (typeof emitter.removeListener === 'function') {\n emitter.removeListener('error', errorListener);\n }\n resolve([].slice.call(arguments));\n };\n\n eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n if (name !== 'error') {\n addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n }\n });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n if (typeof emitter.on === 'function') {\n eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n if (typeof emitter.on === 'function') {\n if (flags.once) {\n emitter.once(name, listener);\n } else {\n emitter.on(name, listener);\n }\n } else if (typeof emitter.addEventListener === 'function') {\n // EventTarget does not have `error` event semantics like Node\n // EventEmitters, we do not listen for `error` events here.\n emitter.addEventListener(name, function wrapListener(arg) {\n // IE does not have builtin `{ once: true }` support so we\n // have to do it manually.\n if (flags.once) {\n emitter.removeEventListener(name, wrapListener);\n }\n listener(arg);\n });\n } else {\n throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n }\n}\n","/**\n * URLSearchParams polyfill for browser environments that might not have it\n * Used by server UMD build (which targets Salesforce browser environments)\n */\n\nexport default class URLSearchParamsPolyfill {\n constructor(init) {\n this.params = new Map();\n\n if (typeof init === 'string') {\n // Parse query string\n const pairs = init.replace(/^\\?/, '').split('&');\n pairs.forEach((pair) => {\n if (pair) {\n const [key, value] = pair.split('=');\n if (key) {\n this.params.set(\n decodeURIComponent(key),\n decodeURIComponent(value || ''),\n );\n }\n }\n });\n } else if (init && typeof init === 'object') {\n // Handle object initialization\n if (init instanceof Map) {\n init.forEach((value, key) => {\n this.params.set(key, String(value));\n });\n } else if (Array.isArray(init)) {\n // Handle array of [key, value] pairs\n init.forEach(([key, value]) => {\n this.params.set(key, String(value));\n });\n } else {\n // Handle plain object\n Object.entries(init).forEach(([key, value]) => {\n this.params.set(key, String(value));\n });\n }\n }\n }\n\n append(name, value) {\n const existing = this.params.get(name);\n if (existing !== undefined) {\n this.params.set(name, `${existing},${String(value)}`);\n } else {\n this.params.set(name, String(value));\n }\n }\n\n delete(name) {\n this.params.delete(name);\n }\n\n get(name) {\n return this.params.get(name) || null;\n }\n\n getAll(name) {\n const value = this.params.get(name);\n return value ? value.split(',') : [];\n }\n\n has(name) {\n return this.params.has(name);\n }\n\n set(name, value) {\n this.params.set(name, String(value));\n }\n\n toString() {\n const pairs = [];\n this.params.forEach((value, key) => {\n // Handle comma-separated values (from append)\n const values = value.split(',');\n values.forEach((val) => {\n pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(val)}`);\n });\n });\n return pairs.join('&');\n }\n\n * [Symbol.iterator]() {\n const paramEntries = Array.from(this.params);\n for (let i = 0; i < paramEntries.length; i += 1) {\n const [key, value] = paramEntries[i];\n // Handle comma-separated values (from append)\n const values = value.split(',');\n for (let j = 0; j < values.length; j += 1) {\n yield [key, values[j]];\n }\n }\n }\n\n * keys() {\n const all = Array.from(this);\n for (let i = 0; i < all.length; i += 1) {\n yield all[i][0];\n }\n }\n\n * values() {\n const all = Array.from(this);\n for (let i = 0; i < all.length; i += 1) {\n yield all[i][1];\n }\n }\n\n * entries() {\n yield* this;\n }\n\n forEach(callback, thisArg) {\n Array.from(this).forEach(([key, value]) => {\n callback.call(thisArg, value, key, this);\n });\n }\n}\n\n// Provide a fallback that uses native URLSearchParams if available, otherwise the polyfill\nexport const URLSearchParams = (typeof globalThis !== 'undefined' && globalThis.URLSearchParams)\n || (typeof window !== 'undefined' && window.URLSearchParams)\n || URLSearchParamsPolyfill;\n","// The module cache\nconst __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tconst cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tconst module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter/value functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tif(Array.isArray(definition)) {\n\t\tvar i = 0;\n\t\twhile(i < definition.length) {\n\t\t\tvar key = definition[i++];\n\t\t\tvar binding = definition[i++];\n\t\t\tif(!__webpack_require__.o(exports, key)) {\n\t\t\t\tif(binding === 0) {\n\t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, value: definition[i++] });\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: binding });\n\t\t\t\t}\n\t\t\t} else if(binding === 0) { i++; }\n\t\t}\n\t} else {\n\t\tfor(var key in definition) {\n\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t\t}\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","const rnds8 = new Uint8Array(16);\nexport default function rng() {\n return crypto.getRandomValues(rnds8);\n}\n","import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\nexport default stringify;\n","import rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nconst _state = {};\nfunction v7(options, buf, offset) {\n let bytes;\n if (options) {\n bytes = v7Bytes(options.random ?? options.rng?.() ?? rng(), options.msecs, options.seq, buf, offset);\n }\n else {\n const now = Date.now();\n const rnds = rng();\n updateV7State(_state, now, rnds);\n bytes = v7Bytes(rnds, _state.msecs, _state.seq, buf, offset);\n }\n return buf ?? unsafeStringify(bytes);\n}\nexport function updateV7State(state, now, rnds) {\n state.msecs ??= -Infinity;\n state.seq ??= 0;\n if (now > state.msecs) {\n state.seq = v7Sequence(rnds);\n state.msecs = now;\n }\n else {\n state.seq = (state.seq + 1) | 0;\n if (state.seq === 0) {\n state.msecs++;\n }\n }\n return state;\n}\nfunction v7Bytes(rnds, msecs, seq, buf, offset = 0) {\n if (rnds.length < 16) {\n throw new Error('Random bytes length must be >= 16');\n }\n if (!buf) {\n buf = new Uint8Array(16);\n offset = 0;\n }\n else {\n if (offset < 0 || offset + 16 > buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n }\n }\n msecs ??= Date.now();\n seq ??= v7Sequence(rnds);\n buf[offset++] = (msecs / 0x10000000000) & 0xff;\n buf[offset++] = (msecs / 0x100000000) & 0xff;\n buf[offset++] = (msecs / 0x1000000) & 0xff;\n buf[offset++] = (msecs / 0x10000) & 0xff;\n buf[offset++] = (msecs / 0x100) & 0xff;\n buf[offset++] = msecs & 0xff;\n buf[offset++] = 0x70 | ((seq >>> 28) & 0x0f);\n buf[offset++] = (seq >>> 20) & 0xff;\n buf[offset++] = 0x80 | ((seq >>> 14) & 0x3f);\n buf[offset++] = (seq >>> 6) & 0xff;\n buf[offset++] = ((seq << 2) & 0xff) | (rnds[10] & 0x03);\n buf[offset++] = rnds[11];\n buf[offset++] = rnds[12];\n buf[offset++] = rnds[13];\n buf[offset++] = rnds[14];\n buf[offset++] = rnds[15];\n return buf;\n}\nfunction v7Sequence(rnds) {\n return ((rnds[6] & 0x7f) << 24) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9];\n}\nexport default v7;\n","/**\n * CSP-safe validator implementation (no eval/Function constructor)\n *\n * Used by all builds that require Content Security Policy compliance:\n * - Browser ESM (browser.mjs)\n * - Browser UMD (browser.umd.js) - Salesforce Lightning\n * - Server UMD (server.umd.js) - Node.js CommonJS\n *\n * Provides comprehensive validation without AJV dependency.\n * Server ESM (server.mjs) uses full AJV validation instead.\n *\n * This implementation must match the server-side validation logic for security.\n */\n\n// Helper function to create AJV-compatible error objects\nfunction createError(instancePath, message, keyword = 'validation', params = {}) {\n return {\n instancePath,\n message,\n keyword,\n params,\n };\n}\n\n// Validates payload structure and required fields\nexport function validatePayload(data) {\n if (!data || typeof data !== 'object') {\n return { valid: false, errors: [createError('', 'must be object', 'type', { type: 'object' })] };\n }\n\n const errors = [];\n\n // Session validation\n if (!data.session) {\n errors.push(createError('/session', 'is required', 'required', { missingProperty: 'session' }));\n } else if (typeof data.session !== 'object') {\n errors.push(createError('/session', 'must be object', 'type', { type: 'object' }));\n } else if (data.session.sessionId !== undefined && typeof data.session.sessionId !== 'string') {\n // sessionId validation (optional)\n errors.push(createError('/session/sessionId', 'must be string', 'type', { type: 'string' }));\n }\n\n // Request validation\n if (!data.request) {\n errors.push(createError('/request', 'is required', 'required', { missingProperty: 'request' }));\n } else if (typeof data.request !== 'object') {\n errors.push(createError('/request', 'must be object', 'type', { type: 'object' }));\n } else {\n // Connections validation\n if (!data.request.connections) {\n errors.push(createError('/request/connections', 'is required', 'required', { missingProperty: 'connections' }));\n } else if (typeof data.request.connections !== 'object') {\n errors.push(createError('/request/connections', 'must be object', 'type', { type: 'object' }));\n } else {\n // threadId validation - required for ALL actions per SDK logic\n if (!data.request.connections.threadId) {\n errors.push(createError('/request/connections/threadId', 'is required', 'required', { missingProperty: 'threadId' }));\n } else if (typeof data.request.connections.threadId !== 'string') {\n errors.push(createError('/request/connections/threadId', 'must be string', 'type', { type: 'string' }));\n }\n\n // parentId type validation (if present)\n if (data.request.connections.parentId !== undefined && typeof data.request.connections.parentId !== 'string') {\n errors.push(createError('/request/connections/parentId', 'must be string', 'type', { type: 'string' }));\n }\n\n // replyId: optional opaque string, same treatment as parentId.\n if (data.request.connections.replyId !== undefined && typeof data.request.connections.replyId !== 'string') {\n errors.push(createError('/request/connections/replyId', 'must be string', 'type', { type: 'string' }));\n }\n\n // replyTarget: deprecated 3.5.0 alias for attributes.replyTo. Same closed enum.\n const { replyTarget } = data.request.connections;\n if (replyTarget !== undefined) {\n const allowedReplyTargets = ['ai', 'self', 'none'];\n if (typeof replyTarget !== 'string') {\n errors.push(createError('/request/connections/replyTarget', 'must be string', 'type', { type: 'string' }));\n } else if (!allowedReplyTargets.includes(replyTarget)) {\n errors.push(createError(\n '/request/connections/replyTarget',\n 'must be equal to one of the allowed values',\n 'enum',\n { allowedValues: allowedReplyTargets },\n ));\n }\n }\n }\n\n // Context validation (if present)\n if (data.request.context !== undefined && typeof data.request.context !== 'object') {\n errors.push(createError('/request/context', 'must be object', 'type', { type: 'object' }));\n }\n\n // Attributes validation (if present)\n if (data.request.attributes !== undefined && typeof data.request.attributes !== 'object') {\n errors.push(createError('/request/attributes', 'must be object', 'type', { type: 'object' }));\n } else if (data.request.attributes && typeof data.request.attributes === 'object') {\n // replyTo: optional closed enum. Omit when not reported (absent !== \"none\").\n // Empty string is not in the enum — match AJV, do not treat it as absent.\n const { replyTo } = data.request.attributes;\n if (replyTo !== undefined) {\n const allowedReplyTo = ['ai', 'self', 'none'];\n if (typeof replyTo !== 'string') {\n errors.push(createError('/request/attributes/replyTo', 'must be string', 'type', { type: 'string' }));\n } else if (!allowedReplyTo.includes(replyTo)) {\n errors.push(createError(\n '/request/attributes/replyTo',\n 'must be equal to one of the allowed values',\n 'enum',\n { allowedValues: allowedReplyTo },\n ));\n }\n }\n }\n\n // Scope validation (if present)\n if (data.request.scope !== undefined) {\n if (typeof data.request.scope !== 'object') {\n errors.push(createError('/request/scope', 'must be object', 'type', { type: 'object' }));\n } else if (data.request.scope.conversations !== undefined) {\n if (!Array.isArray(data.request.scope.conversations)) {\n errors.push(createError('/request/scope/conversations', 'must be array', 'type', { type: 'array' }));\n }\n }\n }\n\n // Resources validation (if present)\n if (data.request.resources !== undefined) {\n if (typeof data.request.resources !== 'object') {\n errors.push(createError('/request/resources', 'must be object', 'type', { type: 'object' }));\n } else if (data.request.resources.offers !== undefined) {\n if (!Array.isArray(data.request.resources.offers)) {\n errors.push(createError('/request/resources/offers', 'must be array', 'type', { type: 'array' }));\n }\n }\n }\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };\n}\n\nexport function validateMessageEnvelope(data) {\n if (!data || typeof data !== 'object') {\n return { valid: false, errors: [createError('', 'must be object', 'type', { type: 'object' })] };\n }\n\n const errors = [];\n\n // Headers validation\n if (!data.headers) {\n errors.push(createError('/headers', 'is required', 'required', { missingProperty: 'headers' }));\n } else if (typeof data.headers !== 'object') {\n errors.push(createError('/headers', 'must be object', 'type', { type: 'object' }));\n } else {\n // correlationId validation\n if (!data.headers.correlationId) {\n errors.push(createError('/headers/correlationId', 'is required', 'required', { missingProperty: 'correlationId' }));\n } else if (typeof data.headers.correlationId !== 'string') {\n errors.push(createError('/headers/correlationId', 'must be string', 'type', { type: 'string' }));\n }\n\n // action validation\n if (!data.headers.action) {\n errors.push(createError('/headers/action', 'is required', 'required', { missingProperty: 'action' }));\n } else if (typeof data.headers.action !== 'string') {\n errors.push(createError('/headers/action', 'must be string', 'type', { type: 'string' }));\n } else {\n // Validate allowed actions\n const allowedActions = ['adjust', 'elevate', 'interaction', 'assistant', 'customerinteraction', 'reception', 'summarize', 'translate', 'recommend', 'insights'];\n if (!allowedActions.includes(data.headers.action)) {\n errors.push(createError('/headers/action', 'must be equal to one of the allowed values', 'enum', { allowedValues: allowedActions }));\n }\n }\n\n // Optional fields validation\n if (data.headers.identifier !== undefined && typeof data.headers.identifier !== 'string') {\n errors.push(createError('/headers/identifier', 'must be string', 'type', { type: 'string' }));\n }\n\n if (data.headers.schemaRef !== undefined && typeof data.headers.schemaRef !== 'string') {\n errors.push(createError('/headers/schemaRef', 'must be string', 'type', { type: 'string' }));\n }\n\n if (data.headers.timestamp !== undefined && typeof data.headers.timestamp !== 'string') {\n errors.push(createError('/headers/timestamp', 'must be string', 'type', { type: 'string' }));\n }\n }\n\n // Payload validation\n if (!data.payload) {\n errors.push(createError('/payload', 'is required', 'required', { missingProperty: 'payload' }));\n } else if (typeof data.payload !== 'object') {\n errors.push(createError('/payload', 'must be object', 'type', { type: 'object' }));\n } else if (data.headers && data.headers.action && data.payload) {\n // Action-specific conversation validation\n const { action } = data.headers;\n const requiresConversations = ['adjust', 'elevate', 'interaction', 'assistant', 'customerinteraction', 'customerInteraction', 'summarize', 'translate', 'insights', 'recommend'];\n\n if (requiresConversations.includes(action)) {\n if (!data.payload.request) {\n errors.push(createError('/payload/request', 'is required', 'required', { missingProperty: 'request' }));\n } else if (!data.payload.request.scope) {\n errors.push(createError('/payload/request/scope', 'is required', 'required', { missingProperty: 'scope' }));\n } else if (!data.payload.request.scope.conversations) {\n errors.push(createError('/payload/request/scope/conversations', `is required for ${action}`, 'required', { missingProperty: 'conversations' }));\n } else if (!Array.isArray(data.payload.request.scope.conversations)) {\n errors.push(createError('/payload/request/scope/conversations', 'must be array', 'type', { type: 'array' }));\n } else if (data.payload.request.scope.conversations.length === 0) {\n errors.push(createError('/payload/request/scope/conversations', `must be non-empty array for ${action}`, 'minItems', { limit: 1 }));\n }\n }\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };\n}\n\n// Validator functions are already exported above\n\nexport const availableValidators = ['Payload', 'MessageEnvelope'];\n","// AUTO-GENERATED FILE. DO NOT EDIT.\n// Source: config/specs/asyncapi.yaml (info.version: 1.0.0)\n// This is the protocol version, independent of SDK implementation version\n\n// Protocol version from AsyncAPI spec\nexport const SPEC_VERSION = \"1.0.0\";\n\n// Schema ref is derived from protocol major version\nconst SPEC_MAJOR = SPEC_VERSION.split('.')[0];\nexport const SCHEMA_REF = `optave.message.v${SPEC_MAJOR}`;\n","/**\n * SDK Constants - PUBLIC API\n *\n * ⚠️ WARNING: This file is exported as part of the public API.\n * Do not add sensitive information such as API keys, secrets,\n * internal URLs, or confidential configuration values.\n *\n * Only include constants that are safe to expose to end users.\n */\n\n// SDK Constants (imported from generated file based on AsyncAPI spec)\nimport { SPEC_VERSION, SCHEMA_REF } from '../../generated/constants.js';\n\nexport { SPEC_VERSION, SCHEMA_REF };\n\n// Error categories\nexport const ErrorCategory = {\n AUTHENTICATION: 'AUTHENTICATION',\n ORCHESTRATOR: 'ORCHESTRATOR',\n VALIDATION: 'VALIDATION',\n WEBSOCKET: 'WEBSOCKET',\n};\n\n// Legacy events (for backward compatibility)\nexport const LegacyEvents = Object.freeze({\n MESSAGE: 'message',\n ERROR: 'error',\n});\n\n// SDK Events\nexport const EVENTS = Object.freeze({\n CONNECTION_OPEN: 'connection:open',\n CONNECTION_CLOSE: 'connection:close',\n CONNECTION_ERROR: 'connection:error',\n MESSAGE_RECEIVED: 'message:received',\n MESSAGE_SENT: 'message:sent',\n ERROR: 'error',\n RESPONSE: 'response',\n LEGACY_ERROR: 'error', // Both ERROR and LEGACY_ERROR map to 'error' for compatibility\n LEGACY_MESSAGE: 'message', // Legacy message handling for backward compatibility\n});\n\n// New events (to migrate to)\nexport const InboundEvents = Object.freeze({\n SUPERPOWER_RESPONSE: 'superpower.response',\n SUPERPOWER_ERROR: 'superpower.error',\n});\n\n// Allowed SDK actions (as Set for has() method)\nexport const ALLOWED_ACTIONS = new Set([\n 'adjust',\n 'elevate',\n 'interaction',\n 'assistant',\n 'reception',\n 'customerInteraction', // deprecated alias\n 'summarize',\n 'translate',\n 'recommend',\n 'insights',\n]);\n\n// Default payload size limit (128KB)\nexport const MAX_PAYLOAD_SIZE = 128 * 1024;\nexport const MAX_PAYLOAD_SIZE_KB = 128;\n\n// Default request timeout (30 seconds)\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 30000;\n\n// Default configuration object - exported as named export to avoid issues with tree-shaking default exports\nexport const CONSTANTS = {\n SPEC_VERSION,\n SCHEMA_REF,\n MAX_PAYLOAD_SIZE,\n MAX_PAYLOAD_SIZE_KB,\n DEFAULT_REQUEST_TIMEOUT_MS,\n ErrorCategory,\n LegacyEvents,\n EVENTS,\n InboundEvents,\n ALLOWED_ACTIONS,\n};\n\nexport default CONSTANTS;\n","/**\n * Configuration validation utilities for OptaveJavaScriptSDK\n * Complements AsyncAPI-generated validators with SDK-specific validation logic\n */\n\n// Client environment detection (extracted from main.js)\nconst isClientEnv = () => {\n // Detects browser, mobile, Electron renderer processes - environments where client secrets should NOT be used\n // Enhanced detection for test environments (like jsdom) that simulate server environments\n\n // Priority check: Node.js with test environment indicators\n // If we're in Node.js and have test-related environment variables or processes,\n // this is likely a server environment even if browser globals exist\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n // Check for test environment indicators\n const isTestEnv = process.env.NODE_ENV === 'test'\n || process.env.VITEST === 'true'\n || process.env.JEST_WORKER_ID !== undefined\n || process.argv.some((arg) => arg.includes('vitest') || arg.includes('jest') || arg.includes('test'));\n\n // In test environments, prefer server-side behavior unless explicitly configured otherwise\n if (isTestEnv) {\n // Only treat as client environment if specifically configured for browser testing\n // and globals are properly set up\n if (typeof globalThis !== 'undefined'\n && 'window' in globalThis && globalThis.window\n && 'document' in globalThis && globalThis.document\n && !process.env.OPTAVE_SDK_FORCE_SERVER_ENV) {\n // This is likely a browser test environment - check for explicit client intent\n return true;\n }\n return false; // Default to server environment in tests\n }\n }\n\n if (typeof globalThis !== 'undefined') {\n // Priority check: If both window and document were explicitly removed from global in tests,\n // this is a clear signal that the test is simulating a server environment\n if (!('window' in globalThis) && !('document' in globalThis)) {\n // Confirm we're in a Node.js test environment that has explicitly removed these\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return false; // Server environment (Node.js with no client globals)\n }\n }\n\n // Additional check: If either window or document was removed from global but the other exists,\n // this is also likely a server environment simulation in tests\n if ((!('window' in globalThis) || !('document' in globalThis))\n && typeof process !== 'undefined' && process.versions && process.versions.node) {\n return false; // Server environment simulation in test\n }\n\n // Check if window exists in global scope (browser or Electron renderer)\n if ('window' in globalThis && globalThis.window) {\n return true;\n }\n\n // Check if document exists in global scope\n if ('document' in globalThis && globalThis.document) {\n return true;\n }\n }\n\n // Fallback checks for environments where global object handling differs\n try {\n if (typeof window !== 'undefined' && window !== null) {\n // In jsdom test environments, if globalThis.window was deleted but window still exists,\n // check if this is an intentional server environment simulation\n if (typeof globalThis !== 'undefined' && !('window' in globalThis)) {\n return false; // Explicitly simulated server environment\n }\n // Additional robustness: if we're in Node.js but window exists,\n // and window was removed from global, treat as server environment\n if (typeof globalThis !== 'undefined' && typeof process !== 'undefined'\n && process.versions && process.versions.node && !('window' in globalThis)) {\n return false; // Server environment simulation\n }\n return true;\n }\n\n if (typeof document !== 'undefined' && document !== null) {\n // Same check for document\n if (typeof globalThis !== 'undefined' && !('document' in globalThis)) {\n return false; // Explicitly simulated server environment\n }\n // Additional robustness for document\n if (typeof globalThis !== 'undefined' && typeof process !== 'undefined'\n && process.versions && process.versions.node && !('document' in globalThis)) {\n return false; // Server environment simulation\n }\n return true;\n }\n } catch (e) {\n // Ignore errors from deleted/undefined globals in tests\n }\n\n // React Native detection\n if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {\n return true;\n }\n\n // Expo detection\n if (typeof globalThis !== 'undefined' && globalThis.__expo) {\n return true;\n }\n\n // Mobile environments often have location global\n if (typeof globalThis.location !== 'undefined' && globalThis.location !== null) {\n return true;\n }\n\n // Check for Node.js - server environment\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return false;\n }\n\n return false;\n};\n\n/**\n * Validates server-specific configuration options\n * @param {Object} options - SDK options\n * @returns {Array} Array of validation errors (empty if valid)\n */\nexport function validateServerConfig(options) {\n const errors = [];\n\n // Validate server authentication configuration\n if (options.authenticationUrl && (!options.clientId || !options.clientSecret)) {\n errors.push({\n type: 'warning',\n code: 'INCOMPLETE_AUTH_CONFIG',\n message: 'authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.',\n field: 'authentication',\n });\n }\n\n return errors;\n}\n\n/**\n * Validates client-specific configuration and enforces security rules\n * @param {Object} options - SDK options\n * @returns {Array} Array of validation errors (empty if valid)\n */\nexport function validateClientConfig(options) {\n const errors = [];\n\n // Hard stop if a client secret is present in any client environment (browser, mobile, Electron renderer)\n // Exception: Server builds (ESM and UMD) are allowed to use client secrets for internal deployment\n if (isClientEnv() && options.clientSecret) {\n // Check if this is a server build (ESM or UMD) - these are designed for server deployment\n // Note: Webpack DefinePlugin replaces these constants at build time\n let isServerUmd = false;\n let isServerEsm = false;\n\n try {\n isServerUmd = __SALESFORCE_BUILD__ === true;\n } catch (e) {\n // __SALESFORCE_BUILD__ not defined (source code context)\n }\n\n try {\n isServerEsm = __INCLUDE_WS_REQUIRE__ === true;\n } catch (e) {\n // __INCLUDE_WS_REQUIRE__ not defined (source code context)\n }\n\n const isServerBuild = isServerUmd || isServerEsm;\n\n if (!isServerBuild) {\n errors.push({\n type: 'error',\n code: 'CLIENT_SECRET_IN_CLIENT_ENV',\n message: 'clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.',\n field: 'clientSecret',\n });\n }\n // Note: Server builds (ESM and UMD) are allowed to use client secrets\n // because they target Node.js server environments, not browsers.\n // For Salesforce/browsers, use browser-umd build with tokenProvider instead.\n }\n\n return errors;\n}\n\n/**\n * Validates required configuration options\n * @param {Object} options - SDK options\n * @returns {Array} Array of validation errors (empty if valid)\n */\nexport function validateRequiredOptions(options) {\n const errors = [];\n\n if (!options.websocketUrl || typeof options.websocketUrl !== 'string') {\n errors.push({\n type: 'warning',\n code: 'MISSING_WEBSOCKET_URL',\n message: 'websocketUrl not provided; openConnection() will emit an error.',\n field: 'websocketUrl',\n });\n }\n\n return errors;\n}\n\n/**\n * Sets smart defaults based on environment and provided options\n * @param {Object} options - SDK options (will be mutated)\n * @returns {Object} The options object with defaults applied\n */\nexport function setSmartDefaults(options) {\n // strictValidation: when true (default in non-production), run schema validation; when false, skip for performance.\n if (typeof options.strictValidation === 'undefined') {\n const env = (typeof process !== 'undefined' && process.env && process.env.NODE_ENV) ? process.env.NODE_ENV : 'development';\n options.strictValidation = env !== 'production';\n }\n\n // Default request timeout (ms) for promise-based API (can be overridden per request)\n if (typeof options.requestTimeoutMs !== 'number') {\n options.requestTimeoutMs = 30000; // 30 seconds default (matches CONSTANTS.DEFAULT_REQUEST_TIMEOUT_MS)\n }\n\n // Default connection timeout (ms) for WebSocket connection establishment\n if (typeof options.connectionTimeoutMs !== 'number') {\n options.connectionTimeoutMs = 30000; // 30 seconds default for connection establishment\n }\n\n // Provide safe no-op logger interface if not supplied (debug/info/warn/error)\n if (!options.logger) {\n options.logger = {\n debug() {}, info() {}, warn() {}, error() {},\n };\n }\n\n // Default how we pass the WS token\n if (!options.authTransport) options.authTransport = 'subprotocol';\n\n if (typeof options.authRequired === 'undefined') options.authRequired = true;\n\n // Default tokenProvider uses tokenUrl\n if (!options.tokenProvider) {\n let url = options.tokenUrl;\n\n // (lets clients set it in HTML)\n if (!url && typeof document !== 'undefined') {\n const meta = document.querySelector('meta[name=\"optave-token-url\"]');\n if (meta && meta.content) url = meta.content;\n }\n if (!url) url = '/api/optave/ws-ticket'; // Temporary default yet to be implemented in backend\n\n options.tokenProvider = async () => {\n const headers = {};\n if (options.publishableKey) headers['X-Optave-Publishable-Key'] = options.publishableKey;\n const r = await fetch(url, { method: 'POST', credentials: 'include', headers });\n if (!r.ok) throw new Error('Failed to obtain WS token');\n const data = await r.json();\n return data.token || data.access_token;\n };\n }\n\n return options;\n}\n\n/**\n * Comprehensive validation function that runs all validation checks\n * @param {Object} options - SDK options\n * @returns {Object} Validation result with errors and warnings\n */\nexport function validateSDKConfig(options) {\n const result = {\n isValid: true,\n errors: [],\n warnings: [],\n };\n\n // Run all validation checks\n const requiredErrors = validateRequiredOptions(options);\n const serverErrors = validateServerConfig(options);\n const clientErrors = validateClientConfig(options);\n\n // Collect all validation results\n const allErrors = [...requiredErrors, ...serverErrors, ...clientErrors];\n\n // Separate errors from warnings\n allErrors.forEach((error) => {\n if (error.type === 'error') {\n result.errors.push(error);\n result.isValid = false;\n } else if (error.type === 'warning') {\n result.warnings.push(error);\n }\n });\n\n return result;\n}\n\n// Export environment detection utility for use in other modules\nexport { isClientEnv };\n","/**\n * Vocabulary-level PI guard for free-form payload fields.\n *\n * `session.channel.metadata` and `request.reference.*` must not carry direct\n * identifiers (names, emails, message content). `session.channel.location`\n * must be province grain at most — never precise coordinates.\n *\n * The analytics pipeline's raw store is append-only under Object Lock; a\n * leaked identifier cannot be simply deleted. This guard runs after schema\n * validation on every build (AJV and CSP-safe).\n */\n\nconst EMAIL_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/i;\nconst GPS_RE = /^\\s*-?\\d{1,3}(?:\\.\\d+)?\\s*,\\s*-?\\d{1,3}(?:\\.\\d+)?\\s*$/;\nconst IDENTIFIER_KEYS = new Set([\n 'email',\n 'e-mail',\n 'fullname',\n 'firstname',\n 'lastname',\n 'displayname',\n 'phone',\n 'phonenumber',\n 'ssn',\n 'dateofbirth',\n 'dob',\n 'nationalid',\n]);\n\nfunction createError(instancePath, message, params = {}) {\n return {\n instancePath,\n message,\n keyword: 'piGuard',\n params,\n };\n}\n\nfunction looksLikeMessageContent(value) {\n if (typeof value !== 'string') return false;\n const trimmed = value.trim();\n if (trimmed.includes('\\n') && trimmed.length > 40) return true;\n if (trimmed.length > 160 && /\\s/.test(trimmed) && /[.!?]/.test(trimmed)) return true;\n return false;\n}\n\nfunction scanString(value, path, errors) {\n if (typeof value !== 'string' || value.length === 0) return;\n if (EMAIL_RE.test(value)) {\n errors.push(createError(path, 'must not contain an email address', { kind: 'email' }));\n }\n if (GPS_RE.test(value)) {\n errors.push(createError(path, 'must not contain precise coordinates', { kind: 'coordinates' }));\n }\n if (looksLikeMessageContent(value)) {\n errors.push(createError(path, 'must not contain message content or other direct identifiers', { kind: 'messageContent' }));\n }\n}\n\nfunction scanUnknown(value, path, errors) {\n if (value == null) return;\n if (typeof value === 'string') {\n scanString(value, path, errors);\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, i) => scanUnknown(item, `${path}/${i}`, errors));\n return;\n }\n if (typeof value === 'object') {\n Object.entries(value).forEach(([key, nested]) => {\n if (IDENTIFIER_KEYS.has(key.toLowerCase())) {\n errors.push(createError(`${path}/${key}`, `must not carry direct identifier key '${key}'`, { kind: 'identifierKey', key }));\n }\n scanUnknown(nested, `${path}/${key}`, errors);\n });\n }\n}\n\n/**\n * Validate free-form payload fields against the PI vocabulary contract.\n * Schema-shape failures are the schema validator's job; this returns valid\n * when `data` is not an object so the schema validator can report that.\n *\n * @param {unknown} data\n * @returns {{ valid: boolean, errors: null | object[] }}\n */\nexport function validatePayloadPrivacy(data) {\n if (!data || typeof data !== 'object') {\n return { valid: true, errors: null };\n }\n\n const errors = [];\n const location = data.session?.channel?.location;\n if (typeof location === 'string' && location && GPS_RE.test(location)) {\n errors.push(createError(\n '/session/channel/location',\n 'must be province grain at most, never precise coordinates',\n { kind: 'coordinates' },\n ));\n }\n\n if (data.session?.channel?.metadata !== undefined) {\n scanUnknown(data.session.channel.metadata, '/session/channel/metadata', errors);\n }\n\n if (data.request?.reference !== undefined) {\n scanUnknown(data.request.reference, '/request/reference', errors);\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };\n}\n\n/**\n * Run schema validation first, then the PI vocabulary guard.\n *\n * @param {(data: unknown) => { valid: boolean, errors: null | object[] }} schemaValidate\n * @returns {(data: unknown) => { valid: boolean, errors: null | object[] }}\n */\nexport function withPrivacyGuard(schemaValidate) {\n return (data) => {\n const schemaResult = schemaValidate(data);\n if (!schemaResult.valid) return schemaResult;\n return validatePayloadPrivacy(data);\n };\n}\n","/**\n * Standardized build target enum and utilities\n *\n * This module provides a centralized definition of all build targets\n * used across webpack configurations and runtime code.\n */\n\n/**\n * Build target enum with all possible build configurations\n * @readonly\n * @enum {string}\n */\nexport const BUILD_TARGETS = {\n /** Browser ESM build (browser.mjs) - for modern ES modules in browsers */\n BROWSER_ESM: 'browser-esm',\n\n /** Server ESM build (server.mjs) - for Node.js ES modules */\n SERVER_ESM: 'server-esm',\n\n /** Browser UMD build (browser.umd.js) - for Salesforce/browsers with UMD wrapper */\n BROWSER_UMD: 'browser-umd',\n\n /** Server UMD build (server.umd.js) - for Node.js CommonJS environments with UMD wrapper */\n SERVER_UMD: 'server-umd',\n};\n\n/**\n * Legacy build target mapping for backward compatibility\n * Maps old 'browser'/'server' values to new specific targets\n * @readonly\n */\nexport const LEGACY_BUILD_TARGET_MAP = {\n browser: BUILD_TARGETS.BROWSER_ESM,\n server: BUILD_TARGETS.SERVER_ESM,\n};\n\n/**\n * Build target categories for easier classification\n * @readonly\n */\nexport const BUILD_TARGET_CATEGORIES = {\n /** All browser-targeted builds */\n BROWSER: [BUILD_TARGETS.BROWSER_ESM, BUILD_TARGETS.BROWSER_UMD],\n\n /** All server-targeted builds (Node.js environments) */\n SERVER: [BUILD_TARGETS.SERVER_ESM, BUILD_TARGETS.SERVER_UMD],\n\n /** All UMD builds */\n UMD: [BUILD_TARGETS.BROWSER_UMD, BUILD_TARGETS.SERVER_UMD],\n\n /** All ESM builds */\n ESM: [BUILD_TARGETS.BROWSER_ESM, BUILD_TARGETS.SERVER_ESM],\n};\n\n/**\n * Utility functions for build target operations\n */\nexport const BuildTargetUtils = {\n /**\n * Check if a build target is valid\n * @param {string} target - The build target to validate\n * @returns {boolean} True if valid\n */\n isValid(target) {\n return Object.values(BUILD_TARGETS).includes(target)\n || Object.keys(LEGACY_BUILD_TARGET_MAP).includes(target);\n },\n\n /**\n * Normalize a build target (handles legacy values)\n * @param {string} target - The build target to normalize\n * @returns {string} Normalized build target\n */\n normalize(target) {\n if (LEGACY_BUILD_TARGET_MAP[target]) {\n return LEGACY_BUILD_TARGET_MAP[target];\n }\n return Object.values(BUILD_TARGETS).includes(target) ? target : 'unknown';\n },\n\n /**\n * Check if build target is browser-focused\n * @param {string} target - The build target to check\n * @returns {boolean} True if browser build\n */\n isBrowser(target) {\n const normalized = this.normalize(target);\n return BUILD_TARGET_CATEGORIES.BROWSER.includes(normalized);\n },\n\n /**\n * Check if build target is server-focused\n * @param {string} target - The build target to check\n * @returns {boolean} True if server build\n */\n isServer(target) {\n const normalized = this.normalize(target);\n return BUILD_TARGET_CATEGORIES.SERVER.includes(normalized);\n },\n\n /**\n * Check if build target is UMD format\n * @param {string} target - The build target to check\n * @returns {boolean} True if UMD build\n */\n isUMD(target) {\n const normalized = this.normalize(target);\n return BUILD_TARGET_CATEGORIES.UMD.includes(normalized);\n },\n\n /**\n * Check if build target is ESM format\n * @param {string} target - The build target to check\n * @returns {boolean} True if ESM build\n */\n isESM(target) {\n const normalized = this.normalize(target);\n return BUILD_TARGET_CATEGORIES.ESM.includes(normalized);\n },\n\n /**\n * Get build target info for debugging\n * @param {string} target - The build target to analyze\n * @returns {object} Build target information\n */\n getInfo(target) {\n const normalized = this.normalize(target);\n return {\n original: target,\n normalized,\n valid: this.isValid(target),\n isBrowser: this.isBrowser(target),\n isServer: this.isServer(target),\n isUMD: this.isUMD(target),\n isESM: this.isESM(target),\n };\n },\n};\n","// CSP-safe browser errors.js - no AJV references\n\nclass OptaveError extends Error {\n /**\n * @param {Object} params\n * @param {'AUTHENTICATION'|'ORCHESTRATOR'|'VALIDATION'|'WEBSOCKET'|'UNKNOWN'} params.category\n * @param {string} params.code\n * @param {string} params.message\n * @param {any} [params.details]\n */\n constructor({\n category, code, message, details,\n }) {\n super(message);\n this.name = 'OptaveError';\n this.category = category || 'UNKNOWN';\n this.code = code || 'UNKNOWN';\n if (details !== undefined) this.details = details;\n }\n}\n\n/**\n * CSP-safe version of makeStructuredError - no AJV ValidationError support\n * @param {any} raw\n * @returns {OptaveError}\n */\nfunction makeStructuredError(raw) {\n // Heuristics: map from raw shapes to categories/codes you already use internally.\n if (raw && raw.category && raw.code && raw.message) {\n return new OptaveError(raw);\n }\n if (typeof raw === 'string') {\n return new OptaveError({ category: 'UNKNOWN', code: 'STRING_ERROR', message: raw });\n }\n // No AJV ValidationError handling in CSP-safe mode\n if (raw && raw.isAuthError) {\n return new OptaveError({\n category: 'AUTHENTICATION', code: raw.code || 'AUTH_ERROR', message: raw.message || 'Authentication error', details: raw,\n });\n }\n if (raw && raw.isWsError) {\n return new OptaveError({\n category: 'WEBSOCKET', code: raw.code || 'WS_ERROR', message: raw.message || 'WebSocket error', details: raw,\n });\n }\n // Default\n return new OptaveError({\n category: 'UNKNOWN', code: 'UNCLASSIFIED', message: (raw && raw.message) || String(raw !== null && raw !== undefined ? raw : 'Unknown error'), details: raw,\n });\n}\n\nexport { OptaveError, makeStructuredError };\n","/**\n * Critical Security Guards for Optave SDK\n *\n * This file contains mandatory security validations that MUST be preserved\n * in all build outputs. Tree-shaking and dead code elimination tools\n * must NOT remove these security checks.\n *\n * SECURITY WARNING: Modifications to this file may introduce security vulnerabilities\n * in Salesforce Lightning environments and other constrained platforms.\n */\n\nimport { BuildTargetUtils } from './build-targets.js';\n\n/**\n * Runtime WebSocket scheme enforcement for UMD builds\n *\n * This guard prevents insecure WebSocket connections (ws://) in UMD builds,\n * which are specifically deployed in Salesforce Lightning environments where\n * the Locker Service blocks all insecure WebSocket connections.\n *\n * SECURITY: This function has intentional side effects (throws errors) and\n * must be preserved in all build outputs. Removing this validation creates\n * a security vulnerability in production environments.\n *\n * @param {string} websocketUrl - The WebSocket URL to validate\n * @param {string} buildTarget - The webpack build target identifier\n * @param {object} options - SDK configuration options\n * @throws {Error} When ws:// protocol is used in UMD builds\n * @throws {Error} When tokenProvider is missing for secure connections in UMD builds\n */\nexport function enforceWebSocketScheme(websocketUrl, buildTarget, options = {}) {\n // SECURITY: This function has observable side effects (throws on invalid schemes and\n // sets a global marker via initializeSecurityGuards) so bundlers must not optimize it away.\n\n if (!websocketUrl || typeof websocketUrl !== 'string') {\n return; // No validation needed if URL is not set or not a string\n }\n\n // Get build target information\n const normalizedTarget = BuildTargetUtils.normalize(buildTarget);\n\n // Check if this is a browser-targeted build that needs scheme validation\n // Browser builds include: browser-esm and browser-umd (Salesforce/Lightning)\n // Server builds (server-esm, server-umd) are for Node.js and allow ws:// for testing\n const isBrowserBuild = BuildTargetUtils.isBrowser(normalizedTarget);\n\n // CRITICAL: Validate WebSocket scheme for browser-targeted builds only\n // This guard prevents insecure connections in Salesforce Lightning and browser environments\n // Server-targeted builds (server-umd for Node.js CommonJS) are exempt to allow local testing\n if (isBrowserBuild && websocketUrl.startsWith('ws://')) {\n // SECURITY: This error message must remain intact to guide developers\n const errorMessage = '[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in browser builds. '\n + 'Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. '\n + 'Please use secure WebSocket protocol (wss://) instead. '\n + `Current URL: ${websocketUrl}`;\n\n // CRITICAL: This throw statement is a security boundary - must not be removed\n throw new Error(errorMessage);\n }\n\n // CRITICAL: For browser UMD builds with secure WebSocket URLs, validate token provider availability\n // This prevents authentication bypass in constrained Salesforce Lightning environments\n // Server UMD builds can use clientSecret authentication, so this check only applies to browser builds\n const isUMDBuild = BuildTargetUtils.isUMD(normalizedTarget);\n const isBrowserUMD = isBrowserBuild && isUMDBuild;\n\n if (isBrowserUMD && websocketUrl.startsWith('wss://')) {\n const hasTokenProvider = typeof options.tokenProvider === 'function';\n const hasAuthDisabled = options.authRequired === false;\n\n if (!hasTokenProvider && !hasAuthDisabled) {\n // SECURITY: This error message must remain intact to guide developers\n const errorMessage = '[Optave SDK] Browser UMD builds require a tokenProvider function for secure WebSocket connections. '\n + 'In constrained environments like Salesforce Lightning, authentication tokens must be obtained '\n + 'from your backend server. Please provide options.tokenProvider() that returns a valid token, '\n + 'or set options.authRequired = false to disable authentication. '\n + `Current URL: ${websocketUrl}`;\n\n // CRITICAL: This throw statement is a security boundary - must not be removed\n throw new Error(errorMessage);\n }\n }\n}\n\n/**\n * Initialize security guards on module load\n * This ensures the security validation code is evaluated and cannot be tree-shaken\n */\nfunction initializeSecurityGuards() {\n // SECURITY: Module-level side effect to prevent tree-shaking\n if (typeof globalThis !== 'undefined') {\n // Mark security guards as active - this creates a side effect\n globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__ = true;\n\n // Force evaluation by accessing the global in a way that cannot be optimized away\n const guardMarker = globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__;\n if (!guardMarker) {\n throw new Error('Security guard initialization failed');\n }\n }\n}\n\n// Execute initialization to create side effects - MUST NOT BE OPTIMIZED AWAY\ninitializeSecurityGuards();\n\n// Additional module-level side effect to ensure preservation\nif (typeof window !== 'undefined') {\n // Browser environment - ensure security guards are active\n window.__OPTAVE_SECURITY_GUARDS_BROWSER__ = true;\n} else if (typeof globalThis !== 'undefined') {\n // Node.js environment - ensure security guards are active.\n // Use globalThis (=== Node `global`) instead of a bare `global`: a free `global`\n // reference makes webpack inject its global-runtime helper, which relies on the\n // Function constructor and would violate Salesforce Lightning Locker CSP.\n globalThis.__OPTAVE_SECURITY_GUARDS_NODE__ = true;\n}\n\n/**\n * Export validation for external use\n * This provides a stable API for the main SDK class\n */\nexport { enforceWebSocketScheme as validateWebSocketScheme };\n","// Platform-aware EventEmitter import (resolved by webpack alias/replacement)\nimport EventEmitter from 'events';\nimport { v7 as uuidv7 } from 'uuid';\n// Version injected by webpack DefinePlugin for bundled builds, fallback to import for dev\n// Conditional import based on CSP compliance needs\nimport {\n validatePayload as validateGeneratedPayload,\n validateMessageEnvelope as validateGeneratedMessageEnvelope,\n} from '../../generated/validators.js';\nimport {\n validatePayload as validateBrowserPayload,\n validateMessageEnvelope as validateBrowserMessageEnvelope,\n} from '../platform/browser/validators.js';\n\nimport {\n CONSTANTS,\n SPEC_VERSION,\n SCHEMA_REF,\n ErrorCategory,\n LegacyEvents,\n EVENTS,\n InboundEvents,\n ALLOWED_ACTIONS,\n} from './constants.js';\nimport { validateSDKConfig, setSmartDefaults } from '../validation/config-validator.js';\nimport { validatePayloadPrivacy, withPrivacyGuard } from '../validation/pi-guard.js';\nimport { BuildTargetUtils } from './build-targets.js';\nimport { OptaveError, makeStructuredError } from './errors.js';\nimport loadNodeWebSocket from '../platform/node/websocket-loader.js';\nimport { enforceWebSocketScheme } from './security-guards.js';\n\nconst SDK_VERSION = typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0-dev';\n\n// Build-time environment detection using webpack DefinePlugin\nconst getBuildContext = () => {\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n return {\n isBrowser: BuildTargetUtils.isBrowser(buildTarget),\n isServer: BuildTargetUtils.isServer(buildTarget),\n buildTarget,\n };\n};\n\nconst isBrowserEnv = () => {\n const context = getBuildContext();\n // Use build target for webpack builds, fallback to runtime detection for dev\n return context.buildTarget !== 'unknown'\n ? context.isBrowser\n : (typeof window !== 'undefined' && typeof window.WebSocket !== 'undefined');\n};\n\n// Module-level warning flags for Step 5 dual event emission\nlet warnedMessageEventOnce = false;\nlet warnedErrorStringOnce = false;\n\n/**\n * Optave JavaScript SDK for WebSocket-based AI service integration\n * @typedef {import('./types.js').Opts} Opts\n * @typedef {import('./types.js').Logger} Logger\n * @typedef {import('../../generated/connection-config.js').AuthTransport} AuthTransport\n */\nclass OptaveJavaScriptSDK extends EventEmitter {\n options = {};\n\n wss = null;\n\n // The default payload. The payload provided by the user is merged \"on top\" of these objects\n /**\n * Default payload template. Typed fields below are the analytics context\n * vocabulary (the SDK captures, it never emits). `request.reference` is\n * client-custom labels only — never the carrier of typed analytics facts.\n * See docs/architecture/analytics-payload-field-map.md.\n */\n static defaultPayload = {\n session: {\n sessionId: '', // session identity — analytics session length/bands, peak concurrency\n channel: {\n browser: '',\n deviceInfo: '', // e.g. \"iOS/18.2, iPhone15,3\" — analytics device slices\n deviceType: '', // analytics dimension: \"mobile\" | \"desktop\" | \"tablet\"; omit when unknown\n language: '', // analytics conversation language (fr-share, fr-parity, lang-switch)\n location: '', // province grain at most (ISO 3166-2, e.g. \"US-NY\"); never precise coordinates\n medium: 'chat', // analytics dimension: \"chat\" | \"voice\" | \"email\"\n metadata: [], // free-form; MUST NOT carry names, emails, or message content\n section: '', // e.g. \"cart\", \"product_page\" — analytics engagement\n },\n interface: {\n appVersion: '', // emitter version — analytics provenance corroboration\n category: '', // e.g. \"crm\", \"app\", \"auto\", \"widget\" — analytics per-surface slices\n language: '', // the language from the crm agent\n name: '', // e.g. \"salesforce\", \"zendesk\" — analytics per-surface slices\n type: '', // e.g. \"custom_components\", \"marketplace\", \"channel\"\n },\n },\n request: {\n requestId: '',\n attributes: {\n content: '',\n instruction: '',\n variant: 'A', // analytics A/B experiment slice\n // replyTo: closed enum \"ai\" | \"self\" | \"none\". Omit when not reported\n // (absent !== \"none\"). Not defaulted to \"\" — empty string is not in the enum.\n },\n connections: {\n journeyId: '', // analytics returning-user / cross-conversation journey\n parentId: '', // in v2, this was called \"trace_parent_ID\"\n replyId: '', // opaque id of the replied-to message; hash if the source is a raw message id\n threadId: '', // conversation identity — unique per ticket/case/conversation\n },\n context: {\n // generated by optave\n caseId: '', // advanced mode — analytics resolution/escalation joins\n departmentId: '', // advanced mode — analytics ops slices\n operatorId: '', // advanced mode — analytics ops slices\n organizationId: '', // analytics org dimension\n userId: '', // advanced mode — pseudonymous user grain; consumers MUST hash\n },\n reference: {\n // client-custom labels ONLY — not typed analytics facts; no names/emails/message content\n ids: [{ name: '', value: '' }],\n labels: [],\n tags: [],\n },\n resources: {\n codes: [\n {\n id: '', // optional for tracking/mapping\n label: '', // optional, helps for display/templating - e.g. \"Order Number\"\n type: '', // e.g., \"order_number\", \"booking_reference\", \"ticket_code\", etc.\n value: '', // e.g. \"ORD-56789\"\n },\n ],\n links: [\n {\n expires_at: '', // optional - e.g. \"2025-08-06T00:00:00Z\"\n html: false, // optional\n id: '', // optional\n label: '', // optional - e.g. \"Click here to pay\"\n type: '', // e.g., \"payment_link\", etc.\n url: '', // e.g. \"https://checkout.stripe.com/pay/cs_test...\"\n },\n ],\n offers: [], // in v2, this was called \"offering_details\"\n },\n // Items below should only be sent if they are directly related to the request\n // There are two ways of sending it:\n // 1. Reference a previously created object (advanced mode)\n // Format: { id: \"\", name: \"\", type: \"\", timestamp: \"\" }, (mandatory: id)\n // 2. Send the object itself (risk: may exceed the payload size limit) - easy mode\n scope: {\n accounts: [],\n appointments: [],\n assets: [],\n bookings: [],\n cases: [],\n conversations: [], // in v2, this was called \"user_perspective\" - populate when actually sending conversation data\n documents: [],\n events: [],\n interactions: [],\n items: [],\n locations: [],\n operators: [],\n orders: [],\n organizations: [],\n persons: [],\n policies: [],\n products: [{ id: '' }],\n properties: [],\n services: [],\n subscriptions: [],\n tickets: [],\n transactions: [],\n users: [],\n // Missing something? We can add it for you, please contact our sales team.\n },\n settings: { // feature-usage flags — analytics reasoning-engagement\n disableBrowsing: false,\n disableSearch: false,\n disableSources: false,\n disableStream: true,\n disableTools: false,\n maxResponseLength: 0,\n overrideInterfaceLanguage: '',\n overrideOutputLanguage: '', // replaces the channel language\n },\n // Advanced mode — analytics human-vs-bot / operator-bot attribution:\n a2a: [\n { id: '', name: '', type: '' }, // e.g. { id: \"bot_55\", name: \"Bot 55\", type: \"chatbot\" }\n ],\n cursor: {\n since: '', // e.g. \"2024-01-15T10:30:00.000Z\"\n until: '', // e.g. \"2024-01-15T11:00:00.000Z\"\n },\n },\n };\n\n /**\n * Static cleanup method for shared/global resources (e.g., JSDOM contexts)\n * This should be called after all SDK instances have been cleaned up individually\n */\n static cleanup() {\n // Clear module-level warning flags\n warnedMessageEventOnce = false;\n warnedErrorStringOnce = false;\n\n // Additional static cleanup can be added here as needed\n // This is primarily for test environments using JSDOM or similar contexts\n }\n\n /**\n * Creates a new OptaveJavaScriptSDK instance\n * @param {Opts} options - Configuration options extending GeneratedClientConfig with SDK-specific settings\n */\n constructor(options) {\n super();\n\n // Apply smart defaults and validate configuration\n this.options = { ...options };\n setSmartDefaults(this.options);\n\n // Auto-detect CSP compliance mode based on build target\n if (this.options.cspSafe === undefined) {\n const context = getBuildContext();\n // ONLY server-esm uses full AJV validation\n // All other builds (browser-esm, browser-umd, server-umd) use CSP-safe mode\n if (context.buildTarget === 'server-esm' || context.buildTarget === 'server') {\n this.options.cspSafe = false; // Server ESM uses full AJV validation\n } else if (context.buildTarget === 'browser-esm' || context.buildTarget === 'browser-umd' || context.buildTarget === 'server-umd' || context.isBrowser || isBrowserEnv()) {\n this.options.cspSafe = true; // Browser builds and server-umd use CSP-safe mode\n }\n // If buildTarget is unknown/undefined, let user explicitly set cspSafe or use default undefined\n }\n\n const validation = validateSDKConfig(this.options);\n\n // Handle validation errors - throw for errors, warn for warnings\n if (!validation.isValid) {\n const errorMessages = validation.errors.map((e) => e.message).join('; ');\n throw new Error(`[Optave SDK] Configuration errors: ${errorMessages}`);\n }\n\n // Log warnings using the configured logger\n validation.warnings.forEach((warning) => {\n (this.options?.logger?.warn || console.warn)(`[Optave SDK] ${warning.message}`);\n });\n\n // WebSocket scheme validation for UMD/browser builds (Salesforce Locker compatibility)\n // SECURITY: This validation is critical for Salesforce Lightning security - must not be removed by tree-shaking\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n // Use canonical security guard - single source of truth for WebSocket validation.\n // Any thrown security error propagates to the caller (no try/catch needed - it would only rethrow).\n enforceWebSocketScheme(this.options.websocketUrl, buildTarget, this.options);\n\n // Initialize WebSocket implementation\n // Use build-aware WebSocket detection to avoid window references in server builds\n const context = getBuildContext();\n this.WebSocketImpl = this.options.WebSocketImpl;\n\n if (!this.WebSocketImpl && context.isBrowser) {\n // Browser builds: check global WebSocket then window.WebSocket\n this.WebSocketImpl = (typeof WebSocket !== 'undefined' ? WebSocket : undefined)\n || (typeof window !== 'undefined' && window.WebSocket ? window.WebSocket : undefined);\n } else if (!this.WebSocketImpl && context.isServer) {\n // Server builds: only check global WebSocket, no window references\n this.WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : undefined;\n }\n // Note: WebSocket implementation loading moved to _ensureWebSocketImpl() for async handling\n\n // Holds pending correlation promises: correlationId -> { resolve, reject, timer, action }\n this._pending = new Map();\n\n // Note: _activeTimeouts removed as we now use queueMicrotask() instead of setTimeout()\n // which doesn't require tracking IDs for cleanup\n\n // Deprecation tracking\n this._deprecatedKeys = new Set();\n this._silenceDeprecations = typeof process !== 'undefined' && process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS === '1';\n\n // Set up CSP-safe validation functions. PI guard wraps payload validation\n // on every build — the analytics raw store is append-only under Object Lock.\n if (this.options.cspSafe) {\n this._validatePayload = withPrivacyGuard(validateBrowserPayload);\n this._validateMessageEnvelope = validateBrowserMessageEnvelope;\n } else {\n this._validatePayload = withPrivacyGuard(validateGeneratedPayload);\n this._validateMessageEnvelope = validateGeneratedMessageEnvelope;\n }\n }\n\n // Async WebSocket implementation loader for ES module compatibility\n async _ensureWebSocketImpl() {\n if (this.WebSocketImpl) return this.WebSocketImpl;\n\n // Initialize WebSocket implementation with build-aware logic\n const context = getBuildContext();\n this.WebSocketImpl = this.options.WebSocketImpl;\n\n if (!this.WebSocketImpl && context.isBrowser) {\n // Browser builds: check global WebSocket then window.WebSocket\n this.WebSocketImpl = (typeof WebSocket !== 'undefined' ? WebSocket : undefined)\n || (typeof window !== 'undefined' && window.WebSocket ? window.WebSocket : undefined);\n } else if (!this.WebSocketImpl && context.isServer) {\n // Server builds: only check global WebSocket, no window references\n this.WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : undefined;\n }\n\n // Only attempt to load 'ws' module in Node.js environments if still not found\n if (!this.WebSocketImpl) {\n // Use webpack DefinePlugin to completely eliminate Node.js WebSocket imports in browser builds\n if (context.isBrowser) {\n // Browser build - use browser WebSocket implementation\n this.WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : null;\n } else if (context.isServer) {\n // Server build - load Node.js WebSocket implementation using webpack-friendly pattern\n this.WebSocketImpl = await this.loadNodeWebSocket();\n }\n }\n\n return this.WebSocketImpl;\n }\n\n // WebSocket loader for Node.js environments only\n async loadNodeWebSocket() {\n const context = getBuildContext();\n\n // Browser builds should never reach this code path, but double-check\n if (context.isBrowser) {\n return null;\n }\n\n // For fallback compatibility in dev environments, check browser globals\n if (context.buildTarget === 'unknown' && (\n typeof window !== 'undefined'\n || typeof document !== 'undefined'\n || typeof navigator !== 'undefined'\n || typeof globalThis.location !== 'undefined'\n )) {\n return null;\n }\n\n // Additional check for Node.js-specific globals\n if (typeof process === 'undefined' || !process.versions || !process.versions.node) {\n return null;\n }\n\n // Use static import instead of dynamic import for UMD builds\n return loadNodeWebSocket();\n }\n\n // Public static helpers for consumers (optional export pattern)\n static getSdkVersion() {\n return SDK_VERSION;\n }\n\n static getSpecVersion() {\n return SPEC_VERSION;\n }\n\n static getSchemaRef() {\n return SCHEMA_REF;\n }\n\n static get CONSTANTS() {\n return CONSTANTS;\n }\n\n // Static exports for constants (moved from named exports to avoid mixed export issues)\n static get LegacyEvents() {\n return LegacyEvents;\n }\n\n static get InboundEvents() {\n return InboundEvents;\n }\n\n setSessionId(id) {\n this.sessionId = id;\n return this; // allow chaining if you like\n }\n\n getSessionId() {\n return this.sessionId || '';\n }\n\n validate(jsonObject) {\n // Backward compatible boolean return; wraps validator (CSP-safe or AJV)\n const r = this._validatePayload(jsonObject);\n return r.valid;\n }\n\n validateEnvelope(envelope) {\n const r = this._validateMessageEnvelope(envelope);\n return r.valid;\n }\n\n // Schema validation is optional in production (strictValidation). The PI\n // vocabulary guard is not — the analytics raw store is append-only under\n // Object Lock, so coordinates and direct identifiers must never go out.\n _validateOutboundPayload(payload) {\n if (this.options.strictValidation) {\n return this._validatePayload(payload);\n }\n return validatePayloadPrivacy(payload);\n }\n\n // Validates action-specific required fields\n validateRequiredFields(params, action) {\n const errors = [];\n\n // Common required fields for all actions\n if (!params.request?.connections?.threadId) {\n errors.push('request.connections.threadId is required');\n }\n\n // Action-specific required fields\n switch (action) {\n case 'adjust':\n if (!params.request?.attributes?.content) {\n errors.push('request.attributes.content is required for adjust');\n }\n if (!params.request?.attributes?.instruction) {\n errors.push('request.attributes.instruction is required for adjust');\n }\n if (!params.request?.connections?.parentId) {\n errors.push('request.connections.parentId is required for adjust');\n }\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n 'request.scope.conversations is required for adjust and must be a non-empty array',\n );\n }\n break;\n\n case 'elevate':\n if (!params.request?.attributes?.content) {\n errors.push('request.attributes.content is required for elevate');\n }\n if (!params.request?.connections?.parentId) {\n errors.push('request.connections.parentId is required for elevate');\n }\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n 'request.scope.conversations is required for elevate and must be a non-empty array',\n );\n }\n break;\n\n case 'translate':\n case 'summarize':\n case 'insights':\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n `request.scope.conversations is required for ${action} and must be a non-empty array`,\n );\n }\n break;\n\n case 'recommend':\n if (\n !params.request?.resources?.offers\n || !Array.isArray(params.request.resources.offers)\n || params.request.resources.offers.length === 0\n ) {\n errors.push(\n 'request.resources.offers is required for recommend and must be a non-empty array',\n );\n }\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n 'request.scope.conversations is required for recommend and must be a non-empty array',\n );\n }\n break;\n\n case 'customerinteraction': // legacy lowercase for backward compatibility\n case 'customerInteraction': // current camelCase\n case 'interaction':\n case 'assistant':\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n `request.scope.conversations is required for ${action} and must be a non-empty array`,\n );\n }\n break;\n\n case 'reception':\n // Reception has no additional required fields beyond common ones.\n break;\n\n default:\n // For unknown actions, just check common required fields\n break;\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n }\n\n async authenticate() {\n // Browser-targeted builds should not use client credentials for security\n // Server builds (ESM and UMD) can authenticate with client credentials\n // Use the SDK's own build flags rather than environment variables for accuracy\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n const isBrowserTargetedBuild = BuildTargetUtils.isBrowser(buildTarget);\n\n if (isBrowserTargetedBuild) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'UNSUPPORTED_IN_BROWSER',\n 'authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend.',\n );\n return null;\n }\n const params = {\n grant_type: 'client_credentials',\n };\n\n if (!this.options.authenticationUrl) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'INVALID_AUTHENTICATION_URL',\n 'Empty or invalid authentication URL',\n );\n return null;\n }\n\n if (!this.options.clientId) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'INVALID_CLIENT_ID',\n 'Empty or invalid client ID',\n );\n return null;\n }\n\n params.client_id = this.options.clientId;\n // Never set clientSecret in browser/mobile/Electron renderers\n // Client secrets must only be used in secure server-side environments\n params.client_secret = this.options.clientSecret;\n\n const paramsString = new URLSearchParams(params).toString();\n\n // Automatically append /token to authenticationUrl if not present\n // This allows clients to provide base OAuth2 URL (e.g., /auth/oauth2)\n // without needing to remember the /token suffix\n let authUrl = this.options.authenticationUrl;\n if (!authUrl.endsWith('/token')) {\n authUrl = authUrl.endsWith('/') ? `${authUrl}token` : `${authUrl}/token`;\n }\n\n const url = `${authUrl}?${paramsString}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n });\n\n const responseJson = await response.json();\n\n if (!response.ok) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'INVALID_AUTHENTICATION_RESPONSE',\n this.formatAuthenticationError(response, responseJson.error, 'token endpoint').message,\n responseJson.error,\n );\n return null;\n }\n\n return responseJson.access_token;\n }\n\n async openConnection(bearerToken) {\n if (!this.options.websocketUrl) {\n (this.options?.logger?.error || console.error)(\n '[Optave SDK] openConnection aborted: missing websocketUrl',\n );\n this.handleError(\n ErrorCategory.WEBSOCKET,\n 'INVALID_WEBSOCKET_URL',\n this.formatWebSocketError(new Error('Invalid WebSocket URL configuration'), {\n url: this.options.websocketUrl,\n }).message,\n this.options.websocketUrl,\n );\n return undefined;\n }\n\n const getToken = async () => {\n if (typeof bearerToken === 'string' && bearerToken.length > 0) return bearerToken;\n if (typeof this.options.tokenProvider === 'function') {\n try {\n return await this.options.tokenProvider();\n } catch (e) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'TOKEN_PROVIDER_FAILED',\n this.formatTokenProviderError(e).message,\n e,\n );\n return null;\n }\n }\n return null;\n };\n\n const token = await getToken();\n\n // Ensure WebSocket implementation is available\n await this._ensureWebSocketImpl();\n\n if (!this.WebSocketImpl) {\n this.handleError(\n ErrorCategory.WEBSOCKET,\n 'NO_WEBSOCKET_IMPL',\n this.formatWebSocketError(new Error('No WebSocket implementation available'), {\n environment: typeof window !== 'undefined' ? 'browser' : 'node',\n }).message,\n );\n return undefined;\n }\n\n if (!token && this.options.authRequired !== false) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'MISSING_TOKEN',\n 'No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.',\n );\n return undefined;\n }\n\n const qp = new URLSearchParams();\n if (this.sessionId) qp.set('OptaveTraceChatSessionId', this.sessionId);\n\n try {\n if (this.options.authTransport === 'subprotocol') {\n // Recommended: token via Sec-WebSocket-Protocol to avoid URL leaks\n const protocols = token ? ['optave-v1', token] : ['optave-v1'];\n this.wss = new this.WebSocketImpl(\n qp.toString()\n ? `${this.options.websocketUrl}?${qp.toString()}`\n : this.options.websocketUrl,\n protocols,\n );\n } else {\n // Fallback: token in query string (avoid if possible)\n if (token) {\n // For WebSocket query parameters, use raw token without Bearer prefix\n // The Bearer prefix is for HTTP headers, not WebSocket query parameters\n const val = token.replace(/^Bearer\\s+/i, '');\n qp.set('Authorization', val);\n }\n this.wss = new this.WebSocketImpl(\n qp.toString()\n ? `${this.options.websocketUrl}?${qp.toString()}`\n : this.options.websocketUrl,\n );\n if (token) {\n this._warnOnce(\n '_warnedQueryToken',\n '[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport=\"subprotocol\".',\n );\n }\n }\n } catch (error) {\n (this.options?.logger?.error || console.error)(\n '[Optave SDK] WebSocket constructor threw',\n error,\n );\n this.handleError(\n ErrorCategory.WEBSOCKET,\n 'WEBSOCKET_ERROR',\n this.formatWebSocketError(error, { url: this.options.websocketUrl }).message,\n error,\n );\n return undefined;\n }\n // Return a promise that resolves when the connection is established\n return new Promise((resolve, reject) => {\n // Set up connection timeout to prevent hanging\n const connectionTimeout = setTimeout(() => {\n const timeoutMs = this.options.connectionTimeoutMs || 30000;\n const errorMessage = this.formatWebSocketError(new Error('Connection timeout'), {\n timeout: timeoutMs,\n url: this.options.websocketUrl,\n }).message;\n\n // CRITICAL: Close the WebSocket to prevent zombie connections\n // Without this, the WebSocket continues attempting to connect in the background\n // causing resource leaks, race conditions, and connection conflicts on retry attempts\n if (this.wss) {\n // Clear event handlers first to prevent them from firing during close\n this.wss.onopen = null;\n this.wss.onmessage = null;\n this.wss.onclose = null;\n this.wss.onerror = null;\n\n // Close the connection\n try {\n this.wss.close();\n } catch (e) {\n // Ignore errors if WebSocket is in invalid state\n }\n\n // Mark as no active connection\n this.wss = null;\n }\n\n this.handleError(ErrorCategory.WEBSOCKET, 'CONNECTION_TIMEOUT', errorMessage);\n reject(new OptaveError({\n category: ErrorCategory.WEBSOCKET,\n code: 'CONNECTION_TIMEOUT',\n message: errorMessage,\n details: null,\n }));\n }, this.options.connectionTimeoutMs || 30000);\n\n this.wss.onopen = (event) => {\n clearTimeout(connectionTimeout);\n this.emit('open', event);\n resolve(event);\n };\n\n this.wss.onmessage = (event) => {\n this._handleInbound(event.data);\n };\n\n this.wss.onclose = (event) => {\n clearTimeout(connectionTimeout);\n this.emit('close', event);\n //\n // CRITICAL: Race condition prevention for promise handling\n // This pattern fixes race conditions where timeout timers compete with WebSocket events\n // The _handled flag ensures promises are only resolved/rejected once\n //\n // Reject all pending promises when connection closes\n Array.from(this._pending.entries()).forEach(([correlationId, entry]) => {\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark entry as handled to prevent timeout from firing\n entry._handled = true;\n entry.reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'CONNECTION_CLOSED',\n message: `WebSocket connection closed: ${event.reason || 'Connection lost'}`,\n details: { code: event.code, reason: event.reason, correlationId },\n correlationId,\n });\n });\n this._pending.clear();\n this.wss = null;\n };\n\n this.wss.onerror = (event) => {\n clearTimeout(connectionTimeout);\n //\n // CRITICAL: Enhanced error message handling and race condition prevention\n // This pattern fixes issues where test warnings revealed:\n // 1. Mock WebSocket error events not properly propagating error messages\n // 2. Race conditions between error handling and timeout timers\n // 3. Double promise resolution/rejection bugs\n //\n // Create error object - handle both native events and Error objects\n const errorMessage = event.message\n || (event instanceof Error ? event.message : null)\n || (typeof event === 'object' && event.error && event.error.message)\n || 'WebSocket connection failed';\n\n const errObj = {\n category: ErrorCategory.WEBSOCKET,\n code: 'CONNECTION_ERROR',\n message: errorMessage,\n details: { originalError: event },\n };\n\n // Reject all pending promises when WebSocket error occurs\n Array.from(this._pending.entries()).forEach(([correlationId, entry]) => {\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark entry as handled to prevent timeout from firing\n entry._handled = true;\n entry.reject({\n ...errObj,\n details: { ...errObj.details, correlationId },\n correlationId,\n });\n });\n this._pending.clear();\n\n // Emit error event for general error handling\n this.emit('error', errObj);\n\n // Reject the openConnection promise\n reject(errObj);\n };\n });\n }\n\n // ---- Inbound Routing & Warning Utilities ----\n _warnOnce(flagName, message) {\n if (this[flagName]) return;\n this[flagName] = true;\n (this.options?.logger?.warn || console.warn)(message);\n }\n\n // Deprecation helper (one-time per runtime per key)\n deprecate(key, message) {\n if (this._silenceDeprecations) return;\n if (this._deprecatedKeys.has(key)) return;\n this._deprecatedKeys.add(key);\n (this.options?.logger?.warn || console.warn)(message);\n }\n\n _handleInbound(rawPayload) {\n let parsed;\n\n try {\n parsed = typeof rawPayload === 'string' ? JSON.parse(rawPayload) : rawPayload;\n } catch (e) {\n const errObj = {\n category: ErrorCategory.WEBSOCKET,\n code: 'INVALID_JSON',\n message: 'Invalid JSON received from server',\n details: e,\n timestamp: new Date().toISOString(),\n };\n this._emitError(errObj);\n return;\n }\n\n const isEnvelope = parsed && parsed.headers && parsed.payload;\n const isError = parsed?.state === 'error' || parsed?.actionType === 'error' || !!parsed?.error;\n\n // Optional inbound validation (envelope) when strictValidation enabled\n if (this.options.strictValidation && isEnvelope) {\n const vr = this._validateMessageEnvelope(parsed);\n if (!vr.valid) {\n this.handleError(\n ErrorCategory.VALIDATION,\n 'INBOUND_ENVELOPE_SCHEMA_MISMATCH',\n this.formatValidationErrorMessage(vr.errors, 'Inbound envelope validation failed'),\n vr.errors,\n );\n }\n }\n\n if (isError) {\n const correlationId = (parsed?.headers && parsed.headers.correlationId) || parsed?.correlationId || null;\n const errObj = {\n category: ErrorCategory.ORCHESTRATOR,\n code: parsed?.error?.code || 'REMOTE_ERROR',\n message: parsed?.error?.message || parsed?.message || 'Remote error',\n details: parsed?.error || parsed,\n correlationId,\n };\n // Correlation rejection path\n if (correlationId && this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n entry._handled = true; // Mark as handled\n this._pending.delete(correlationId);\n entry.reject(errObj);\n }\n this._emitError(errObj, parsed?.action);\n return;\n }\n\n // Correlation fulfillment (success)\n const correlationId = parsed?.headers?.correlationId || parsed?.correlationId;\n if (correlationId && this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n entry._handled = true; // Mark as handled\n this._pending.delete(correlationId);\n entry.resolve(parsed);\n }\n\n // Legacy emission (unchanged)\n this.emit(LegacyEvents.MESSAGE, parsed);\n\n // One-time deprecation warning for legacy 'message'\n if (!warnedMessageEventOnce) {\n warnedMessageEventOnce = true;\n (this.options?.logger?.warn || console.warn)(\n '[optave-sdk][deprecation] The \"message\" event will be deprecated. Please also listen to \"superpower.response\".',\n );\n }\n\n // New event (same payload as legacy message)\n this.emit(InboundEvents.SUPERPOWER_RESPONSE, parsed);\n\n // New canonical response event (parsed object) - keeping existing behavior\n this.emit(EVENTS.RESPONSE, parsed);\n\n // Per-action convenience (lowercased) - keeping existing behavior\n if (parsed?.action) {\n this.emit(`message.${parsed.action}`.toLowerCase(), parsed);\n }\n\n // Preserve prior schemaRef emission for envelopes - keeping existing behavior\n if (isEnvelope && parsed.headers.schemaRef) {\n this.emit(parsed.headers.schemaRef, parsed);\n }\n }\n\n _emitError(errObj, _action = null) {\n if (!errObj.timestamp) {\n errObj.timestamp = new Date().toISOString();\n }\n\n // Legacy emission (unchanged) - keep emitting structured objects\n this.emit(LegacyEvents.ERROR, errObj);\n\n // One-time deprecation warning for legacy error events:\n if (!warnedErrorStringOnce) {\n warnedErrorStringOnce = true;\n (this.options?.logger?.warn || console.warn)(\n '[optave-sdk][deprecation] The \"error\" (string payload) is deprecated. Please also listen to \"superpower.error\" for a structured error object.',\n );\n }\n\n // New event: structured Error object (non-breaking because it's a new event name)\n const structuredError = makeStructuredError(errObj);\n this.emit(InboundEvents.SUPERPOWER_ERROR, structuredError);\n\n // Keep existing behavior for EVENTS.ERROR\n this.emit(EVENTS.ERROR, errObj);\n }\n\n closeConnection() {\n if (this.wss) {\n // Clear all WebSocket event handlers to break circular references\n this.wss.onopen = null;\n this.wss.onmessage = null;\n this.wss.onclose = null;\n this.wss.onerror = null;\n\n this.wss.close();\n this.wss = null;\n }\n }\n\n selectiveDeepMerge(target, source) {\n if (Array.isArray(target) && Array.isArray(source)) {\n // If both target and source are arrays, replace target with source\n return [...source];\n }\n\n // Use more reliable object detection that works across webpack contexts\n const isObject = (obj) => obj !== null && typeof obj === 'object' && !Array.isArray(obj);\n\n if (isObject(target) && isObject(source)) {\n const result = { ...target }; // Start with all target keys\n // Process all source keys, merging or overriding\n Object.keys(source).forEach((key) => {\n if (key in target) {\n // Recursively merge or replace values\n result[key] = this.selectiveDeepMerge(target[key], source[key]);\n } else {\n // Add new keys from source that don't exist in target\n result[key] = source[key];\n }\n });\n return result;\n }\n\n // For primitive values, return source value if it exists, else fallback to target\n return source !== undefined ? source : target;\n }\n\n isPayloadSizeValid(payloadString) {\n if (!payloadString) {\n return false;\n }\n\n // Check if the size is within the limit\n return payloadString.length / 1024 <= CONSTANTS.MAX_PAYLOAD_SIZE_KB;\n }\n\n openConnectionAsync(bearerToken) {\n return new Promise((resolve, reject) => {\n let onErr;\n const onOpen = (e) => {\n this.off('error', onErr);\n resolve(e);\n };\n onErr = (e) => {\n this.off('open', onOpen);\n reject(e);\n };\n this.once('open', onOpen);\n this.once('error', onErr);\n this.openConnection(bearerToken);\n });\n }\n\n buildPayload(requestType, action, params) {\n const payload = this.selectiveDeepMerge(OptaveJavaScriptSDK.defaultPayload, params);\n // Legacy alias mapping (variation -> variant) with deprecation notice\n if (params?.request?.variation) {\n this.deprecate(\n 'payload.request.variation',\n \"[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'.\",\n );\n payload.request.attributes.variant = params.request.variation;\n }\n // Legacy mapping: move request.content to attributes.content if provided at old location\n if (params?.request?.content && !payload.request?.attributes?.content) {\n payload.request.attributes.content = params.request.content;\n this.deprecate(\n 'payload.request.content',\n \"[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.\",\n );\n }\n\n // Ensure variant is properly set and uppercase\n if (payload.request.attributes.variant) {\n payload.request.attributes.variant = payload.request.attributes.variant.toUpperCase();\n }\n return payload;\n }\n\n // Maps action and request type to standardized AsyncAPI message ID\n resolveMessageId(requestType, action) {\n return `${action}.${requestType}.v3`.toLowerCase(); // e.g., \"adjust.message.v3\"\n }\n\n // Wraps payload in message envelope with headers for tracking and versioning (supports overrides)\n buildMessageEnvelope(payload, requestType, action, headerOverrides = {}) {\n const now = new Date().toISOString();\n const correlationId = headerOverrides.correlationId || payload?.request?.requestId || uuidv7();\n const traceId = headerOverrides.traceId || uuidv7();\n const idempotencyKey = headerOverrides.idempotencyKey || uuidv7();\n const { timestamp } = headerOverrides; // user event time (overrideable)\n const issuedAt = now; // envelope build time\n\n const headers = {\n correlationId,\n action,\n schemaRef: SCHEMA_REF,\n sdkVersion: SDK_VERSION,\n identifier: requestType,\n traceId,\n idempotencyKey,\n timestamp,\n issuedAt,\n };\n if (this.options.tenantId) {\n headers.tenantId = this.options.tenantId;\n }\n if (headerOverrides.networkLatencyMs !== undefined) {\n headers.networkLatencyMs = headerOverrides.networkLatencyMs;\n }\n // Freeze headers to prevent accidental mutation after envelope construction.\n // (Shallow freeze is enough because all current header values are primitives.)\n Object.freeze(headers);\n return {\n action: 'message',\n headers,\n payload,\n };\n }\n\n formatValidationErrorMessage(errors, baseMessage = 'Validation failed') {\n if (!errors || !Array.isArray(errors) || errors.length === 0) {\n return baseMessage;\n }\n\n // If there's only one error, provide a detailed explanation\n if (errors.length === 1) {\n const error = errors[0];\n const fieldPath = error.instancePath || '/';\n const field = fieldPath === '/' ? 'root object' : fieldPath.replace(/^\\//, '').replace(/\\//g, '.');\n\n if (error.keyword === 'required') {\n const missingField = error.params?.missingProperty || 'unknown field';\n // Handle case where instancePath already points to the missing property\n let fullFieldPath;\n if (field === 'root object') {\n fullFieldPath = missingField;\n } else if (field.endsWith(missingField)) {\n fullFieldPath = field;\n } else {\n fullFieldPath = `${field}.${missingField}`;\n }\n return `${baseMessage}: ${\n field === 'root object' ? 'Required field' : 'Field'\n } '${fullFieldPath}' is missing`;\n } if (error.keyword === 'type') {\n const expectedType = error.params?.type || 'unknown';\n return `${baseMessage}: Field '${field}' must be of type '${expectedType}'`;\n } if (error.keyword === 'additionalProperties') {\n const additionalProp = error.params?.additionalProperty || 'unknown';\n return `${baseMessage}: Field '${field}.${additionalProp}' is not allowed`;\n } if (error.keyword === 'enum') {\n const allowedValues = error.params?.allowedValues || [];\n const allowedStr = Array.isArray(allowedValues)\n ? allowedValues.join(', ')\n : 'unknown values';\n return `${baseMessage}: Field '${field}' must be one of: ${allowedStr}`;\n }\n return `${baseMessage}: ${error.message} at '${field}'`;\n }\n\n // If there are multiple errors, provide a summary with the most critical ones\n const criticalErrors = errors.filter((e) => e.keyword === 'required');\n const typeErrors = errors.filter((e) => e.keyword === 'type');\n const otherErrors = errors.filter((e) => e.keyword !== 'required' && e.keyword !== 'type');\n\n let summary = `${baseMessage}:`;\n\n if (criticalErrors.length > 0) {\n const missingFields = criticalErrors.map((e) => {\n const field = (e.instancePath || '/').replace(/^\\//, '').replace(/\\//g, '.');\n const missing = e.params?.missingProperty || 'unknown';\n return field === '' ? missing : `${field}.${missing}`;\n });\n summary += ` Missing required fields: ${missingFields.join(', ')}.`;\n }\n\n if (typeErrors.length > 0) {\n const typeIssues = typeErrors.slice(0, 3).map((e) => {\n const field = (e.instancePath || '/').replace(/^\\//, '').replace(/\\//g, '.');\n const expectedType = e.params?.type || 'unknown';\n return `${field || 'root'} (expected ${expectedType})`;\n });\n summary += ` Type errors in: ${typeIssues.join(', ')}.`;\n if (typeErrors.length > 3) summary += ` And ${typeErrors.length - 3} more type errors.`;\n }\n\n if (otherErrors.length > 0) {\n summary += ` Additional validation errors: ${otherErrors.length}.`;\n }\n\n return summary;\n }\n\n formatAuthenticationError(response, serverError, context) {\n let message = 'Authentication failed';\n const suggestions = [];\n\n // Include HTTP status if available\n if (response && response.status) {\n message += ` (HTTP ${response.status})`;\n }\n\n // Add server error details\n if (serverError) {\n if (typeof serverError === 'string') {\n message += `: ${serverError}`;\n } else if (serverError.error_description) {\n message += `: ${serverError.error_description}`;\n } else if (serverError.message) {\n message += `: ${serverError.message}`;\n } else if (serverError.error) {\n message += `: ${serverError.error}`;\n }\n }\n\n // Add context-specific suggestions\n if (response && response.status === 401) {\n suggestions.push('Verify clientId and clientSecret are correct');\n suggestions.push('Ensure credentials match the target environment (dev/staging/production)');\n } else if (response && response.status === 403) {\n suggestions.push('Check if your client has the necessary permissions');\n suggestions.push('Verify the authentication endpoint URL is correct');\n } else if (response && response.status >= 500) {\n suggestions.push('Authentication server error - try again later');\n suggestions.push('Contact support if the problem persists');\n } else {\n suggestions.push('Check network connectivity and authentication endpoint configuration');\n }\n\n // Add environment context if available\n if (context && context.authUrl) {\n message += ` (endpoint: ${context.authUrl})`;\n }\n\n return { message, suggestions };\n }\n\n formatWebSocketError(errorEvent, context) {\n let message = 'WebSocket connection failed';\n const suggestions = [];\n\n // Extract error details from different event types\n const errorMessage = errorEvent?.message\n || (errorEvent instanceof Error ? errorEvent.message : null)\n || (typeof errorEvent === 'object' && errorEvent.error && errorEvent.error.message)\n || null;\n\n if (errorMessage) {\n message += `: ${errorMessage}`;\n }\n\n // Add connection context\n if (context) {\n if (context.url) {\n message += ` (URL: ${context.url})`;\n }\n if (context.timeout) {\n message += ` (timeout: ${context.timeout}ms)`;\n }\n }\n\n // Provide troubleshooting suggestions\n suggestions.push('Check network connectivity and firewall settings');\n suggestions.push('Verify WebSocket URL is correct and accessible');\n\n if (context && context.url) {\n if (context.url.startsWith('ws://')) {\n suggestions.push('Consider using secure WebSocket (wss://) for production');\n }\n if (context.url.includes('localhost') || context.url.includes('127.0.0.1')) {\n suggestions.push('Ensure local server is running if connecting to localhost');\n }\n }\n\n if (context && context.timeout) {\n suggestions.push('Try increasing connection timeout if network is slow');\n }\n\n return { message, suggestions };\n }\n\n formatPayloadSizeError(actualSize, maxSize, payload) {\n const actualKB = Math.ceil(actualSize / 1024);\n const maxKB = maxSize;\n const overageKB = actualKB - maxKB;\n\n const message = `Payload too large: ${actualKB}KB exceeds maximum ${maxKB}KB (${overageKB}KB over limit)`;\n const suggestions = [];\n\n // Analyze payload for optimization suggestions\n if (payload && typeof payload === 'object') {\n // Check for large conversation arrays\n if (\n payload.request?.scope?.conversations\n && Array.isArray(payload.request.scope.conversations)\n ) {\n const conversationsSize = JSON.stringify(payload.request.scope.conversations).length;\n const conversationsKB = Math.ceil(conversationsSize / 1024);\n if (conversationsKB > 10) {\n // If conversations are more than 10KB\n suggestions.push(\n `Consider reducing conversation history - current size: ~${conversationsKB}KB`,\n );\n suggestions.push('Remove older messages or summarize conversation context');\n }\n }\n\n // Check for large offers arrays\n if (payload.request?.resources?.offers && Array.isArray(payload.request.resources.offers)) {\n const offersSize = JSON.stringify(payload.request.resources.offers).length;\n const offersKB = Math.ceil(offersSize / 1024);\n if (offersKB > 5) {\n suggestions.push(`Consider reducing product offers data - current size: ~${offersKB}KB`);\n }\n }\n\n // Check for large metadata\n if (payload.session?.channel?.metadata && Array.isArray(payload.session.channel.metadata)) {\n const metadataSize = JSON.stringify(payload.session.channel.metadata).length;\n const metadataKB = Math.ceil(metadataSize / 1024);\n if (metadataKB > 2) {\n suggestions.push(`Consider reducing metadata array - current size: ~${metadataKB}KB`);\n }\n }\n }\n\n // General suggestions if no specific optimizations found\n if (suggestions.length === 0) {\n suggestions.push('Remove unused fields from request payload');\n suggestions.push('Consider paginating large datasets');\n suggestions.push('Use shorter field values where possible');\n }\n\n return { message, suggestions };\n }\n\n formatTokenProviderError(originalError, context) {\n let message = 'Failed to obtain WebSocket token from tokenProvider()';\n const suggestions = [];\n\n // Add original error details\n if (originalError) {\n if (originalError.message) {\n message += `: ${originalError.message}`;\n } else if (typeof originalError === 'string') {\n message += `: ${originalError}`;\n }\n\n // Analyze error type for specific suggestions\n if (originalError.name === 'TypeError' && originalError.message?.includes('fetch')) {\n suggestions.push('Check if tokenProvider endpoint is accessible');\n suggestions.push('Verify CORS settings allow requests to token endpoint');\n } else if (\n originalError.message?.includes('404')\n || originalError.message?.includes('Not Found')\n ) {\n suggestions.push('Verify tokenProvider endpoint URL is correct');\n suggestions.push('Ensure backend token endpoint is implemented');\n } else if (originalError.message?.includes('401') || originalError.message?.includes('403')) {\n suggestions.push('Check authentication/authorization for token endpoint');\n suggestions.push('Verify user session or credentials are valid');\n } else if (originalError.message?.includes('timeout')) {\n suggestions.push(\n 'Token provider request timed out - check network or server response time',\n );\n }\n }\n\n // Add context-specific guidance\n if (context && context.tokenUrl) {\n message += ` (endpoint: ${context.tokenUrl})`;\n }\n\n // General troubleshooting suggestions\n if (suggestions.length === 0) {\n suggestions.push('Verify tokenProvider function implementation');\n suggestions.push('Check backend token endpoint is running and accessible');\n suggestions.push('Review browser console for network errors');\n }\n\n return { message, suggestions };\n }\n\n handleError(category, code, message, details = null, suggestions = [], correlationId = null) {\n const errObj = new OptaveError({\n category, code, message, details,\n });\n if (suggestions) errObj.suggestions = suggestions;\n if (correlationId) errObj.correlationId = correlationId;\n if (this.listenerCount(LegacyEvents.ERROR) === 0 && this.listenerCount(EVENTS.ERROR) === 0) {\n (this.options?.logger?.error || console.error)(`[Optave SDK] ${code}: ${message}`);\n }\n this._emitError(errObj);\n }\n\n send(requestType, action, params) {\n const OPEN = (this.WebSocketImpl && this.WebSocketImpl.OPEN) != null ? this.WebSocketImpl.OPEN : 1;\n if (!(this.wss && this.wss.readyState === OPEN)) {\n const readyState = this.wss ? this.wss.readyState : 'no connection';\n this.handleError(\n ErrorCategory.WEBSOCKET,\n 'WEBSOCKET_NOT_IN_OPEN_STATE',\n this.formatWebSocketError(new Error('WebSocket not ready for sending'), {\n readyState,\n action,\n }).message,\n );\n return;\n }\n if (!ALLOWED_ACTIONS.has(action)) {\n this.handleError(\n ErrorCategory.VALIDATION,\n 'INVALID_ACTION',\n `Unsupported action '${action}'. Allowed: ${[...ALLOWED_ACTIONS].join(', ')}`,\n );\n return;\n }\n\n // Lightweight additional-property detection BEFORE merge (top-level only)\n const allowedTopLevel = new Set(['session', 'request', 'headers']);\n const topLevelKeys = Object.keys(params || {});\n for (let i = 0; i < topLevelKeys.length; i += 1) {\n const k = topLevelKeys[i];\n if (!allowedTopLevel.has(k)) {\n const errors = [\n {\n instancePath: '',\n keyword: 'additionalProperties',\n params: { additionalProperty: k },\n message: `must NOT have additional property '${k}'`,\n },\n ];\n this.handleError(\n ErrorCategory.VALIDATION,\n 'PAYLOAD_SCHEMA_MISMATCH',\n this.formatValidationErrorMessage(errors),\n errors,\n );\n return;\n }\n }\n\n // Build merged payload first so defaults satisfy required properties\n const payload = this.buildPayload(requestType, action, params || {});\n\n // Validate required fields on merged payload FIRST (more specific error)\n const requiredFieldValidation = this.validateRequiredFields(payload || {}, action);\n if (!requiredFieldValidation.isValid) {\n this.handleError(\n ErrorCategory.VALIDATION,\n 'REQUIRED_FIELDS_MISSING',\n `Missing required fields for action '${action}': ${requiredFieldValidation.errors.join(\n ', ',\n )}`,\n requiredFieldValidation.errors,\n );\n return;\n }\n\n const outboundResult = this._validateOutboundPayload(payload);\n if (!outboundResult.valid) {\n this.handleError(\n ErrorCategory.VALIDATION,\n 'PAYLOAD_SCHEMA_MISMATCH',\n this.formatValidationErrorMessage(outboundResult.errors, 'Schema validation failed'),\n outboundResult.errors,\n );\n return;\n }\n\n const envelope = this.buildMessageEnvelope(payload, requestType, action, params?.headers || {});\n const payloadString = JSON.stringify(envelope);\n\n if (!this.isPayloadSizeValid(payloadString)) {\n const actualSize = payloadString.length; // Size in bytes\n this.handleError(\n ErrorCategory.VALIDATION,\n 'PAYLOAD_TOO_LARGE',\n this.formatPayloadSizeError(actualSize, CONSTANTS.MAX_PAYLOAD_SIZE_KB, envelope).message,\n CONSTANTS.MAX_PAYLOAD_SIZE_KB,\n );\n return;\n }\n this.wss.send(payloadString);\n }\n\n // The following functions send messages of a specific type to the WebSocket\n adjust(params) {\n return this.send('message', 'adjust', params);\n }\n\n elevate(params) {\n return this.send('message', 'elevate', params);\n }\n\n interaction(params) {\n return this.send('message', 'interaction', params);\n }\n\n assistant(params) {\n return this.send('message', 'assistant', params);\n }\n\n reception(params) {\n return this.send('message', 'reception', params);\n }\n\n // Deprecated alias (will be removed in a future major version)\n customerInteraction(params) {\n this.deprecate(\n 'method.customerInteraction',\n \"[Deprecation] 'customerInteraction' is deprecated; use 'interaction' instead.\",\n );\n return this.send('message', 'customerInteraction', params);\n }\n\n summarize(params) {\n return this.send('message', 'summarize', params);\n }\n\n translate(params) {\n return this.send('message', 'translate', params);\n }\n\n recommend(params) {\n return this.send('message', 'recommend', params);\n }\n\n insights(params) {\n return this.send('message', 'insights', params);\n }\n\n // ----- Promise-based Request API -----\n _registerPending(correlationId, action, timeoutMs, resolve, reject) {\n let timer = null;\n\n // Only set up timeout if timeoutMs is greater than 0\n if (timeoutMs > 0) {\n timer = setTimeout(() => {\n // Double-check that the promise hasn't been resolved/rejected by WebSocket events\n if (this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n // Only proceed if this entry hasn't been handled by WebSocket events\n if (entry && !entry._handled) {\n this._pending.delete(correlationId);\n entry._handled = true; // Mark as handled\n reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'REQUEST_TIMEOUT',\n message: `Request timed out after ${timeoutMs}ms`,\n details: { correlationId, action },\n correlationId,\n });\n }\n }\n }, timeoutMs);\n }\n\n this._pending.set(correlationId, {\n resolve, reject, timer, action, _handled: false,\n });\n }\n\n _promiseSend(requestType, action, params = {}, opts = {}) {\n let correlationId; // Declare outside promise to access later\n\n const promise = new Promise((resolve, reject) => {\n // Calculate timeout duration early to determine behavior\n let timeoutMs;\n if (typeof opts.timeoutMs === 'number') {\n timeoutMs = opts.timeoutMs;\n } else if (typeof opts.timeout === 'number') {\n timeoutMs = opts.timeout;\n } else {\n timeoutMs = this.options.requestTimeoutMs;\n }\n\n if (!this.wss || this.wss.readyState !== WebSocket.OPEN) {\n // If no timeout is specified, fail immediately with WebSocket state error\n if (timeoutMs <= 0) {\n reject(new OptaveError({\n category: ErrorCategory.WEBSOCKET,\n code: 'WEBSOCKET_NOT_IN_OPEN_STATE',\n message: 'WebSocket not open',\n details: null,\n }));\n return;\n }\n // Otherwise, let the timeout mechanism handle the failure\n // Generate correlationId for timeout tracking even when WebSocket is closed\n // Build minimal payload for correlationId generation\n const payload = this.buildPayload(requestType, action, params);\n const envelope = this.buildMessageEnvelope(\n payload,\n requestType,\n action,\n params?.headers || {},\n );\n correlationId = envelope.headers.correlationId;\n this._registerPending(correlationId, action, timeoutMs, resolve, reject);\n return; // Let timeout handle the rejection\n }\n if (!ALLOWED_ACTIONS.has(action)) {\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'INVALID_ACTION',\n message: `Unsupported action '${action}'.`,\n details: { allowed: [...ALLOWED_ACTIONS] },\n }));\n return;\n }\n // Additional property check (top-level) mirroring send()\n const allowedTopLevel = new Set(['session', 'request', 'headers']);\n const topLevelKeys = Object.keys(params || {});\n for (let i = 0; i < topLevelKeys.length; i += 1) {\n const k = topLevelKeys[i];\n if (!allowedTopLevel.has(k)) {\n const errors = [\n {\n instancePath: '',\n keyword: 'additionalProperties',\n params: { additionalProperty: k },\n message: `must NOT have additional property '${k}'`,\n },\n ];\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'PAYLOAD_SCHEMA_MISMATCH',\n message: this.formatValidationErrorMessage(errors),\n details: errors,\n }));\n return;\n }\n }\n const payload = this.buildPayload(requestType, action, params);\n\n // Validate required fields FIRST (more specific error)\n const requiredFieldValidation = this.validateRequiredFields(payload, action);\n if (!requiredFieldValidation.isValid) {\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'REQUIRED_FIELDS_MISSING',\n message: `Missing required fields for action '${action}'`,\n details: requiredFieldValidation.errors,\n }));\n return;\n }\n\n const outboundResult = this._validateOutboundPayload(payload);\n if (!outboundResult.valid) {\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'PAYLOAD_SCHEMA_MISMATCH',\n message: this.formatValidationErrorMessage(\n outboundResult.errors,\n 'Schema validation failed',\n ),\n details: outboundResult.errors,\n }));\n return;\n }\n const envelope = this.buildMessageEnvelope(\n payload,\n requestType,\n action,\n params?.headers || {},\n );\n correlationId = envelope.headers.correlationId; // Assign to outer scope variable\n\n // Register timeout for normal WebSocket flow\n this._registerPending(correlationId, action, timeoutMs, resolve, reject);\n\n const payloadString = JSON.stringify(envelope);\n if (!this.isPayloadSizeValid(payloadString)) {\n const actualSize = payloadString.length; // Size in bytes\n const errorMessage = this.formatPayloadSizeError(\n actualSize,\n CONSTANTS.MAX_PAYLOAD_SIZE_KB,\n envelope,\n ).message;\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'PAYLOAD_TOO_LARGE',\n message: errorMessage,\n details: { maxKb: CONSTANTS.MAX_PAYLOAD_SIZE_KB },\n }));\n return;\n }\n\n try {\n this.wss.send(payloadString);\n } catch (e) {\n if (this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n // Clear timer if it exists\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark as handled to prevent timeout from firing\n entry._handled = true;\n this._pending.delete(correlationId);\n }\n const sendError = new OptaveError({\n category: ErrorCategory.WEBSOCKET,\n code: 'SEND_FAILED',\n message: 'Failed to send over WebSocket',\n details: e,\n });\n sendError.correlationId = correlationId;\n reject(sendError);\n }\n });\n\n // Attach correlationId to the promise for external access\n promise.correlationId = correlationId;\n\n return promise;\n }\n\n // Promise-based helpers (suffix Async)\n adjustAsync(params, opts) {\n return this._promiseSend('message', 'adjust', params, opts);\n }\n\n elevateAsync(params, opts) {\n return this._promiseSend('message', 'elevate', params, opts);\n }\n\n interactionAsync(params, opts) {\n return this._promiseSend('message', 'interaction', params, opts);\n }\n\n assistantAsync(params, opts) {\n return this._promiseSend('message', 'assistant', params, opts);\n }\n\n receptionAsync(params, opts) {\n return this._promiseSend('message', 'reception', params, opts);\n }\n\n // Deprecated alias\n customerInteractionAsync(params, opts) {\n this.deprecate(\n 'method.customerInteractionAsync',\n \"[Deprecation] 'customerInteractionAsync' is deprecated; use 'interactionAsync' instead.\",\n );\n return this._promiseSend('message', 'customerInteraction', params, opts);\n }\n\n summarizeAsync(params, opts) {\n return this._promiseSend('message', 'summarize', params, opts);\n }\n\n translateAsync(params, opts) {\n return this._promiseSend('message', 'translate', params, opts);\n }\n\n recommendAsync(params, opts) {\n return this._promiseSend('message', 'recommend', params, opts);\n }\n\n insightsAsync(params, opts) {\n return this._promiseSend('message', 'insights', params, opts);\n }\n\n cancelRequest(correlationId) {\n if (this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n // Clear timer if it exists\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark as handled to prevent timeout from firing\n entry._handled = true;\n this._pending.delete(correlationId);\n\n // Use setTimeout to allow any existing .catch() handlers to be attached\n setTimeout(() => {\n entry.reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'REQUEST_CANCELLED',\n message: 'Request was cancelled',\n details: { correlationId },\n correlationId,\n });\n }, 0);\n\n return true;\n }\n return false;\n }\n\n cancelPendingRequests(isCleaningUp = false) {\n // Defensive check: if cleanup() has already been called, _pending will be null\n if (!this._pending) {\n return 0;\n }\n\n const cancelledCount = this._pending.size;\n const entries = [...this._pending.entries()]; // Copy to avoid modification during iteration\n\n entries.forEach(([correlationId, entry]) => {\n // Clear timer if it exists\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark as handled to prevent timeout from firing\n entry._handled = true;\n\n if (isCleaningUp) {\n // During cleanup, reject immediately to prevent memory leaks from setTimeout\n entry.reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'REQUEST_CANCELLED',\n message: 'Request was cancelled during cleanup',\n details: { correlationId },\n correlationId,\n });\n } else {\n // Use queueMicrotask to allow any existing .catch() handlers to be attached\n // This is more appropriate than setTimeout(0) and doesn't depend on DOM context\n // eliminating the JSDOM window closure issue in UMD builds\n queueMicrotask(() => {\n entry.reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'REQUEST_CANCELLED',\n message: 'Request was cancelled',\n details: { correlationId },\n correlationId,\n });\n });\n }\n });\n this._pending.clear();\n return cancelledCount;\n }\n\n /**\n * Comprehensive cleanup method to prevent memory leaks\n * Cleans up all internal state including Maps, Sets, and WebSocket connections\n */\n cleanup() {\n // Close WebSocket connection first to break external references\n this.closeConnection();\n\n // Cancel all pending requests and clear timers\n // Pass isCleaningUp=true to avoid creating new timeouts during cleanup\n this.cancelPendingRequests(true);\n\n // Note: No timeout cleanup needed since we use queueMicrotask() instead of setTimeout()\n // queueMicrotask() doesn't require manual cleanup as it doesn't hold references\n\n // Clear internal data structures\n if (this._deprecatedKeys) {\n this._deprecatedKeys.clear();\n }\n\n // Clear any warning flags (instance-specific)\n if (this._warnedQueryToken !== undefined) {\n delete this._warnedQueryToken;\n }\n\n // CRITICAL: Clear EventEmitter state BEFORE calling removeAllListeners\n // This prevents the complex removeAllListeners override from interfering\n if (this._events) {\n // Manually clear each event to break listener references\n Object.keys(this._events).forEach((event) => {\n delete this._events[event];\n });\n }\n\n // Now remove all listeners (this should be mostly a no-op after manual cleanup)\n this.removeAllListeners();\n\n // CRITICAL: Set EventEmitter properties to null AFTER removeAllListeners\n // This ensures complete cleanup before breaking prototype chain\n this._events = null;\n this._eventsCount = null;\n this._maxListeners = null;\n\n // CRITICAL: Clean up JSDOM contexts created by SDK loader\n // UMD builds loaded through test infrastructure create JSDOM environments\n // that must be explicitly closed to prevent memory leaks\n // Only run in non-server builds to avoid window references in server.mjs\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n if (buildTarget !== 'server-esm' && buildTarget !== 'server-umd') {\n if (this.constructor._preservedJSDOM && this.constructor._preservedJSDOM.dom) {\n try {\n // Access window through dom property to minimize direct window references\n const domWindow = this.constructor._preservedJSDOM.dom.window;\n if (domWindow && typeof domWindow.close === 'function') {\n domWindow.close();\n }\n delete this.constructor._preservedJSDOM;\n } catch (e) {\n // Ignore errors if JSDOM is already closed\n }\n }\n }\n\n // Clear function references that might hold closures\n this._validatePayload = null;\n this._validateOutboundPayload = null;\n this._validateMessageEnvelope = null;\n this._emitError = null;\n this._ensureWebSocketImpl = null;\n this._handleInbound = null;\n this._promiseSend = null;\n this._registerPending = null;\n this._warnOnce = null;\n\n // Clear object references completely\n this.options = null;\n this.WebSocketImpl = null;\n this.wss = null;\n this.sessionId = null;\n\n // Clear collections with explicit null assignment\n this._pending = null;\n this._deprecatedKeys = null;\n\n // Clear primitive flags\n this._silenceDeprecations = null;\n\n // FINAL: Ensure EventEmitter properties are definitively null after all cleanup\n // This must be LAST to override any potential resets from removeAllListeners\n this._events = null;\n this._eventsCount = null;\n this._maxListeners = null;\n }\n\n /**\n * Override removeAllListeners to include internal cleanup\n * Simplified to avoid complex fallback logic that might interfere with GC\n */\n removeAllListeners(event) {\n // Try the parent EventEmitter method\n try {\n EventEmitter.prototype.removeAllListeners.call(this, event);\n } catch (e) {\n // Fallback: manual cleanup if parent method fails\n if (!event) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (this._events && this._events[event]) {\n delete this._events[event];\n this._eventsCount = Math.max(0, this._eventsCount - 1);\n }\n }\n\n return this;\n }\n\n // Static properties for build configuration flags (used by webpack DefinePlugin)\n static get buildFlags() {\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n\n return {\n SALESFORCE_BUILD: typeof __SALESFORCE_BUILD__ !== 'undefined' ? __SALESFORCE_BUILD__ : false,\n INCLUDE_WS_REQUIRE:\n typeof __INCLUDE_WS_REQUIRE__ !== 'undefined' ? __INCLUDE_WS_REQUIRE__ : true,\n SDK_VERSION: typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0-dev',\n WEBPACK_BUILD_TARGET: buildTarget,\n WEBPACK_BUILD_TARGET_NORMALIZED: BuildTargetUtils.normalize(buildTarget),\n BUILD_TARGET_INFO: BuildTargetUtils.getInfo(buildTarget),\n };\n }\n}\n\n// Export as both named and default to work with UMD without getter patterns\n// UMD builds: globalThis.OptaveJavaScriptSDK (via default export)\n// ESM builds: import { OptaveJavaScriptSDK } from '@optave/client-sdk'\nexport { OptaveJavaScriptSDK };\nexport default OptaveJavaScriptSDK;\n","/* eslint-disable no-bitwise */\n// Bitwise operators below are intrinsic to the UUID v7 bit-field packing/PRNG algorithm and cannot be removed.\n// Browser crypto polyfill for UUID v7 generation\n// This provides a Node.js crypto compatible interface for browser environments\n// UUID v7 implementation adapted from https://github.com/LiosK/uuidv7 (Apache-2.0 License)\n\n// Resolve the crypto implementation once at module load. Returned from a function so the\n// module-level binding can be a const (avoids exporting a mutable `let`).\nfunction resolveCryptoImplementation() {\n if (typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.getRandomValues) {\n return globalThis.crypto;\n }\n if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {\n return window.crypto;\n }\n if (typeof globalThis !== 'undefined' && globalThis.self\n && globalThis.self.crypto && globalThis.self.crypto.getRandomValues) {\n return globalThis.self.crypto;\n }\n // Fallback implementation using Math.random()\n return {\n getRandomValues(array) {\n for (let i = 0; i < array.length; i += 1) {\n array[i] = Math.floor(Math.random() * 256);\n }\n return array;\n },\n };\n}\n\nconst cryptoImplementation = resolveCryptoImplementation();\n\n// Buffered crypto random number generator.\n// Implemented as a factory (not a class) to keep this file within the single-class limit;\n// behavior is identical to the original `new BufferedCryptoRandom()` usage.\nfunction createBufferedCryptoRandom() {\n const buffer = new Uint32Array(8);\n let cursor = 0xffff;\n\n return {\n nextUint32() {\n if (cursor >= buffer.length) {\n cryptoImplementation.getRandomValues(buffer);\n cursor = 0;\n }\n const value = buffer[cursor];\n cursor += 1;\n return value;\n },\n };\n}\n\n// UUID v7 Generator class adapted from LiosK/uuidv7\nclass V7Generator {\n constructor() {\n this.timestamp = 0;\n this.counter = 0;\n this.random = this._getRandomNumberGenerator();\n }\n\n _getRandomNumberGenerator() {\n if (typeof cryptoImplementation !== 'undefined' && typeof cryptoImplementation.getRandomValues !== 'undefined') {\n return createBufferedCryptoRandom();\n }\n // Fallback using Math.random()\n return {\n nextUint32: () => Math.trunc(Math.random() * 0x10000) * 0x10000 + Math.trunc(Math.random() * 0x10000),\n };\n }\n\n generate() {\n return this.generateOrResetCore(Date.now(), 10000);\n }\n\n generateOrResetCore(unixTsMs, rollbackAllowance) {\n let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);\n if (value === undefined) {\n this.timestamp = 0;\n value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);\n }\n return value;\n }\n\n generateOrAbortCore(unixTsMs, rollbackAllowance) {\n const MAX_COUNTER = 0x3fffffff_fff;\n\n if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 0xffffffffffff) {\n throw new RangeError('unixTsMs must be a 48-bit positive integer');\n }\n\n if (unixTsMs > this.timestamp) {\n this.timestamp = unixTsMs;\n this.resetCounter();\n } else if (unixTsMs + rollbackAllowance >= this.timestamp) {\n this.counter++;\n if (this.counter > MAX_COUNTER) {\n this.timestamp++;\n this.resetCounter();\n }\n } else {\n return undefined;\n }\n\n return this.fromFieldsV7(\n this.timestamp,\n Math.trunc(this.counter / (2 ** 30)),\n this.counter & (2 ** 30 - 1),\n this.random.nextUint32(),\n );\n }\n\n resetCounter() {\n this.counter = this.random.nextUint32() * 0x400 + (this.random.nextUint32() & 0x3ff);\n }\n\n fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {\n const bytes = new Uint8Array(16);\n bytes[0] = unixTsMs / (2 ** 40);\n bytes[1] = unixTsMs / (2 ** 32);\n bytes[2] = unixTsMs / (2 ** 24);\n bytes[3] = unixTsMs / (2 ** 16);\n bytes[4] = unixTsMs / (2 ** 8);\n bytes[5] = unixTsMs;\n bytes[6] = 0x70 | (randA >>> 8);\n bytes[7] = randA;\n bytes[8] = 0x80 | (randBHi >>> 24);\n bytes[9] = randBHi >>> 16;\n bytes[10] = randBHi >>> 8;\n bytes[11] = randBHi;\n bytes[12] = randBLo >>> 24;\n bytes[13] = randBLo >>> 16;\n bytes[14] = randBLo >>> 8;\n bytes[15] = randBLo;\n\n return this.bytesToString(bytes);\n }\n\n bytesToString(bytes) {\n const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');\n return [\n hex.substring(0, 8),\n hex.substring(8, 12),\n hex.substring(12, 16),\n hex.substring(16, 20),\n hex.substring(20, 32),\n ].join('-');\n }\n}\n\n// Create default generator instance\nlet defaultGenerator = null;\n\n// Override randomUUID and generateUUID to use UUID v7\ncryptoImplementation.randomUUID = function () {\n if (!defaultGenerator) {\n defaultGenerator = new V7Generator();\n }\n return defaultGenerator.generate();\n};\n\ncryptoImplementation.generateUUID = function () {\n if (!defaultGenerator) {\n defaultGenerator = new V7Generator();\n }\n return defaultGenerator.generate();\n};\n\n// Generate short ID using UUID v7 for cryptographic security\n// Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility\ncryptoImplementation.generateShortId = function () {\n return defaultGenerator.generate().replace(/-/g, '').substring(0, 9);\n};\n\n// Ensure crypto is available globally for UUID library\n// Check if crypto property is configurable before attempting to set it\nfunction setSafeCrypto(globalObj, propName) {\n if (!globalObj || globalObj.crypto) return; // Already exists\n\n try {\n const descriptor = Object.getOwnPropertyDescriptor(globalObj, propName);\n if (!descriptor || descriptor.configurable !== false) {\n globalObj.crypto = cryptoImplementation;\n }\n } catch {\n // Ignore errors when crypto property is read-only (e.g., in JSDOM).\n // No logger is available in this standalone polyfill, so swallow silently.\n }\n}\n\nif (typeof globalThis !== 'undefined') {\n setSafeCrypto(globalThis, 'crypto');\n}\nif (typeof window !== 'undefined') {\n setSafeCrypto(window, 'crypto');\n}\nif (typeof globalThis !== 'undefined' && globalThis.self) {\n setSafeCrypto(globalThis.self, 'crypto');\n}\n\n// Support both CommonJS and ES modules with environment detection\ntry {\n // Check if we're in a CommonJS environment where module.exports is writable\n if (typeof module !== 'undefined' && typeof module.exports === 'object' && typeof require !== 'undefined') {\n // CommonJS environment - try to assign, but catch any errors in case it's read-only\n module.exports = cryptoImplementation;\n module.exports.default = cryptoImplementation;\n module.exports.getRandomValues = cryptoImplementation.getRandomValues.bind(cryptoImplementation);\n module.exports.randomUUID = cryptoImplementation.randomUUID ? cryptoImplementation.randomUUID.bind(cryptoImplementation) : cryptoImplementation.randomUUID;\n module.exports.generateUUID = cryptoImplementation.generateUUID.bind(cryptoImplementation);\n module.exports.generateShortId = cryptoImplementation.generateShortId.bind(cryptoImplementation);\n }\n} catch (e) {\n // ES module environment where module.exports is read-only - ignore the error\n // ES module exports will be used instead\n}\n\n// ES module exports for compatibility\nexport const getRandomValues = cryptoImplementation.getRandomValues.bind(cryptoImplementation);\nexport const randomUUID = cryptoImplementation.randomUUID ? cryptoImplementation.randomUUID.bind(cryptoImplementation) : cryptoImplementation.randomUUID;\nexport const generateUUID = cryptoImplementation.generateUUID.bind(cryptoImplementation);\nexport const generateShortId = cryptoImplementation.generateShortId.bind(cryptoImplementation);\n\n// Default export for integration compatibility\nexport default cryptoImplementation;\n","// UMD-specific entry point that exports constructor function directly\n// This avoids webpack getter patterns that fail in Salesforce LockerService\n\nimport { OptaveJavaScriptSDK } from './main.js';\n// Import crypto polyfill for side effects (sets up global crypto for UUID generation)\nimport '../platform/browser/crypto-polyfill.js';\n\n// Expose the constructor on the browser global, preferring `window`.\n// Salesforce Lightning loads this UMD bundle as a static resource and reads\n// `window.OptaveJavaScriptSDK`; under Lightning Locker the component's global is\n// `window` (a SecureWindow), which is NOT guaranteed to be the same object as\n// `globalThis`. We assign to both `window` (browser/Salesforce) and `globalThis`\n// (Node, and web workers where globalThis === self), which together cover every\n// target. Idempotent and defensive.\nif (typeof window !== 'undefined' && !window.OptaveJavaScriptSDK) {\n try {\n window.OptaveJavaScriptSDK = OptaveJavaScriptSDK;\n } catch { /* noop – defensive */ }\n}\nif (typeof globalThis !== 'undefined' && !globalThis.OptaveJavaScriptSDK) {\n try {\n globalThis.OptaveJavaScriptSDK = OptaveJavaScriptSDK;\n } catch { /* noop – defensive */ }\n}\n\n// Export default for webpack UMD library.export: 'default'\n// Consumers using script tags get globalThis.OptaveJavaScriptSDK; module/bundler\n// users import the default export.\nexport default OptaveJavaScriptSDK;\n"],"names":["webpackUniversalModuleDefinition","root","factory","exports","module","define","amd","window","self","globalThis","this","ReflectOwnKeys","R","Reflect","ReflectApply","apply","target","receiver","args","Function","prototype","call","ownKeys","Object","getOwnPropertySymbols","getOwnPropertyNames","concat","NumberIsNaN","Number","isNaN","value","EventEmitter","init","once","emitter","name","Promise","resolve","reject","errorListener","err","removeListener","resolver","slice","arguments","eventTargetAgnosticAddListener","handler","flags","on","addErrorHandlerIfEventEmitter","_events","undefined","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","listener","TypeError","_getMaxListeners","that","_addListener","type","prepend","m","events","existing","warning","create","newListener","emit","unshift","push","length","warned","w","Error","String","count","console","warn","onceWrapper","fired","wrapFn","_onceWrap","state","wrapped","bind","_listeners","unwrap","evlistener","arr","ret","Array","i","unwrapListeners","arrayClone","listenerCount","n","copy","addEventListener","wrapListener","arg","removeEventListener","defineProperty","enumerable","get","set","RangeError","getPrototypeOf","setMaxListeners","getMaxListeners","doError","error","er","message","context","len","listeners","addListener","prependListener","prependOnceListener","list","position","originalListener","shift","index","pop","spliceOne","off","removeAllListeners","key","keys","rawListeners","eventNames","URLSearchParamsPolyfill","constructor","params","Map","replace","split","forEach","pair","decodeURIComponent","isArray","entries","append","delete","getAll","has","toString","pairs","val","encodeURIComponent","join","Symbol","iterator","paramEntries","from","values","j","all","callback","thisArg","URLSearchParams","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","d","definition","binding","o","obj","prop","hasOwnProperty","rnds8","Uint8Array","rng","crypto","getRandomValues","byteToHex","unsafeStringify","offset","toLowerCase","_state","v7Bytes","rnds","msecs","seq","buf","Date","now","v7Sequence","options","bytes","random","Infinity","updateV7State","createError","instancePath","keyword","validatePayload","data","valid","errors","session","sessionId","missingProperty","request","connections","threadId","parentId","replyId","replyTarget","allowedReplyTargets","includes","allowedValues","attributes","replyTo","allowedReplyTo","scope","conversations","resources","offers","validateMessageEnvelope","headers","correlationId","action","allowedActions","identifier","schemaRef","timestamp","payload","limit","SCHEMA_REF","ErrorCategory","AUTHENTICATION","ORCHESTRATOR","VALIDATION","WEBSOCKET","LegacyEvents","freeze","MESSAGE","ERROR","EVENTS","CONNECTION_OPEN","CONNECTION_CLOSE","CONNECTION_ERROR","MESSAGE_RECEIVED","MESSAGE_SENT","RESPONSE","LEGACY_ERROR","LEGACY_MESSAGE","InboundEvents","SUPERPOWER_RESPONSE","SUPERPOWER_ERROR","ALLOWED_ACTIONS","Set","CONSTANTS","SPEC_VERSION","MAX_PAYLOAD_SIZE","MAX_PAYLOAD_SIZE_KB","DEFAULT_REQUEST_TIMEOUT_MS","validateClientConfig","document","e","navigator","product","__expo","location","isClientEnv","clientSecret","isServerUmd","isServerEsm","code","field","EMAIL_RE","GPS_RE","IDENTIFIER_KEYS","scanUnknown","path","item","nested","kind","test","trimmed","trim","looksLikeMessageContent","scanString","validatePayloadPrivacy","channel","metadata","reference","withPrivacyGuard","schemaValidate","schemaResult","BUILD_TARGETS","BROWSER_ESM","SERVER_ESM","BROWSER_UMD","SERVER_UMD","LEGACY_BUILD_TARGET_MAP","browser","server","BUILD_TARGET_CATEGORIES","BROWSER","SERVER","UMD","ESM","BuildTargetUtils","isValid","normalize","isBrowser","normalized","isServer","isUMD","isESM","getInfo","original","OptaveError","category","details","super","__OPTAVE_SECURITY_GUARDS_ACTIVE__","initializeSecurityGuards","__OPTAVE_SECURITY_GUARDS_BROWSER__","__OPTAVE_SECURITY_GUARDS_NODE__","SDK_VERSION","getBuildContext","buildTarget","warnedMessageEventOnce","warnedErrorStringOnce","OptaveJavaScriptSDK","wss","static","deviceInfo","deviceType","language","medium","section","interface","appVersion","requestId","content","instruction","variant","journeyId","caseId","departmentId","operatorId","organizationId","userId","ids","labels","tags","codes","id","label","links","expires_at","html","url","accounts","appointments","assets","bookings","cases","documents","interactions","items","locations","operators","orders","organizations","persons","policies","products","properties","services","subscriptions","tickets","transactions","users","settings","disableBrowsing","disableSearch","disableSources","disableStream","disableTools","maxResponseLength","overrideInterfaceLanguage","overrideOutputLanguage","a2a","cursor","since","until","cleanup","strictValidation","env","process","requestTimeoutMs","connectionTimeoutMs","logger","debug","info","authTransport","authRequired","tokenProvider","tokenUrl","meta","querySelector","async","publishableKey","r","fetch","method","credentials","ok","json","token","access_token","setSmartDefaults","cspSafe","WebSocket","isBrowserEnv","validation","result","warnings","requiredErrors","websocketUrl","validateRequiredOptions","serverErrors","authenticationUrl","clientId","validateServerConfig","validateSDKConfig","errorMessages","map","normalizedTarget","isBrowserBuild","startsWith","isUMDBuild","hasTokenProvider","hasAuthDisabled","enforceWebSocketScheme","WebSocketImpl","_pending","_deprecatedKeys","_silenceDeprecations","OPTAVE_SDK_SILENCE_DEPRECATIONS","_validatePayload","_validateMessageEnvelope","_ensureWebSocketImpl","loadNodeWebSocket","getSdkVersion","getSpecVersion","getSchemaRef","setSessionId","getSessionId","validate","jsonObject","validateEnvelope","envelope","_validateOutboundPayload","validateRequiredFields","authenticate","handleError","grant_type","client_id","client_secret","paramsString","authUrl","endsWith","response","responseJson","formatAuthenticationError","openConnection","bearerToken","formatWebSocketError","formatTokenProviderError","getToken","environment","qp","protocols","_warnOnce","connectionTimeout","setTimeout","timeoutMs","errorMessage","timeout","onopen","onmessage","onclose","onerror","close","event","clearTimeout","_handleInbound","entry","timer","_handled","reason","clear","errObj","originalError","flagName","deprecate","add","rawPayload","parsed","JSON","parse","toISOString","_emitError","isEnvelope","isError","actionType","vr","formatValidationErrorMessage","_action","structuredError","raw","isAuthError","isWsError","closeConnection","selectiveDeepMerge","source","isObject","isPayloadSizeValid","payloadString","openConnectionAsync","onErr","onOpen","buildPayload","requestType","defaultPayload","variation","toUpperCase","resolveMessageId","buildMessageEnvelope","headerOverrides","traceId","idempotencyKey","sdkVersion","issuedAt","tenantId","networkLatencyMs","baseMessage","fieldPath","missingField","fullFieldPath","additionalProperty","criticalErrors","filter","typeErrors","otherErrors","summary","missing","serverError","suggestions","status","error_description","errorEvent","formatPayloadSizeError","actualSize","maxSize","actualKB","Math","ceil","conversationsSize","stringify","conversationsKB","offersSize","offersKB","metadataSize","metadataKB","send","OPEN","readyState","allowedTopLevel","topLevelKeys","k","requiredFieldValidation","outboundResult","adjust","elevate","interaction","assistant","reception","customerInteraction","summarize","translate","recommend","insights","_registerPending","_promiseSend","opts","promise","allowed","maxKb","sendError","adjustAsync","elevateAsync","interactionAsync","assistantAsync","receptionAsync","customerInteractionAsync","summarizeAsync","translateAsync","recommendAsync","insightsAsync","cancelRequest","cancelPendingRequests","isCleaningUp","cancelledCount","size","queueMicrotask","_warnedQueryToken","_preservedJSDOM","dom","domWindow","max","buildFlags","SALESFORCE_BUILD","INCLUDE_WS_REQUIRE","WEBPACK_BUILD_TARGET","WEBPACK_BUILD_TARGET_NORMALIZED","BUILD_TARGET_INFO","cryptoImplementation","array","floor","V7Generator","counter","_getRandomNumberGenerator","buffer","Uint32Array","nextUint32","createBufferedCryptoRandom","trunc","generate","generateOrResetCore","unixTsMs","rollbackAllowance","generateOrAbortCore","isInteger","resetCounter","fromFieldsV7","randA","randBHi","randBLo","bytesToString","hex","byte","padStart","substring","defaultGenerator","setSafeCrypto","globalObj","propName","descriptor","getOwnPropertyDescriptor","configurable","randomUUID","generateUUID","generateShortId","require","default"],"sourceRoot":""}
\ No newline at end of file
diff --git a/sdks/javascript/dist/index.cjs b/sdks/javascript/dist/index.cjs
index 099ef9c..9c48bb5 100644
--- a/sdks/javascript/dist/index.cjs
+++ b/sdks/javascript/dist/index.cjs
@@ -31,43 +31,54 @@ module.exports = __toCommonJS(index_exports);
// generated/connection-config.ts
var DEFAULT_CONFIG = {
- websocketUrl: "wss://{wsEnv}.oco.optave.tech/",
- authUrl: "https://{authEnv}.oco.optave.tech/auth/oauth2",
- // Base URL - SDK will append /token
- supportedAuthTransports: ["subprotocol", "query", "oauth2"]
+ websocketUrl: "wss://{wsEnv}.{baseDomain}/",
+ authUrl: "https://{authEnv}.{baseDomain}/auth/oauth2",
+ supportedAuthTransports: ["subprotocol", "query"]
};
-var OAUTH2_TOKEN_URL = DEFAULT_CONFIG.authUrl;
-
-// runtime/core/index.ts
-var createDefaultConfig = () => ({
- websocketUrl: "wss://default.oco.optave.tech/",
- authUrl: "https://default.oco.optave.tech/auth/oauth2/",
- supportedAuthTransports: ["subprotocol", "query"],
- OptaveTraceChatSessionId: void 0
-});
-var DEFAULT_CONFIG2 = createDefaultConfig();
var SERVER_ENVIRONMENTS = {
websocket: {
wsEnv: {
- default: "default",
- examples: ["default", "staging", "production"]
+ default: "ws-incubator",
+ examples: ["ws-incubator", "ws-sandbox", "ws-prod"]
+ },
+ baseDomain: {
+ default: "oco.optave.tech",
+ examples: ["oco.optave.tech"]
}
},
auth: {
authEnv: {
- default: "default",
- examples: ["default", "staging", "production"]
+ default: "incubator",
+ examples: ["incubator", "sandbox", "prod"]
+ },
+ baseDomain: {
+ default: "oco.optave.tech",
+ examples: ["oco.optave.tech"]
}
}
};
-function buildWebSocketUrl(environment) {
- const env = environment || "default";
- return `wss://${env}.oco.optave.tech/`;
+function buildWebSocketUrl(wsEnv = SERVER_ENVIRONMENTS.websocket.wsEnv?.default, baseDomain = SERVER_ENVIRONMENTS.websocket.baseDomain?.default) {
+ let url = DEFAULT_CONFIG.websocketUrl;
+ url = url.replace("{wsEnv}", wsEnv);
+ url = url.replace("{baseDomain}", baseDomain);
+ return url;
}
-function buildAuthUrl(environment) {
- const env = environment || "default";
- return `https://${env}.oco.optave.tech/auth/oauth2/`;
+function buildAuthUrl(authEnv = SERVER_ENVIRONMENTS.auth.authEnv?.default, baseDomain = SERVER_ENVIRONMENTS.auth.baseDomain?.default) {
+ let url = DEFAULT_CONFIG.authUrl;
+ url = url.replace("{authEnv}", authEnv);
+ url = url.replace("{baseDomain}", baseDomain);
+ return url;
}
+var OAUTH2_TOKEN_URL = buildAuthUrl();
+
+// runtime/core/index.ts
+var createDefaultConfig = () => ({
+ websocketUrl: buildWebSocketUrl(),
+ authUrl: buildAuthUrl(),
+ supportedAuthTransports: ["subprotocol", "query"],
+ OptaveTraceChatSessionId: void 0
+});
+var DEFAULT_CONFIG2 = createDefaultConfig();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DEFAULT_CONFIG,
diff --git a/sdks/javascript/dist/index.d.cts b/sdks/javascript/dist/index.d.cts
index 881b605..c72d3bd 100644
--- a/sdks/javascript/dist/index.d.cts
+++ b/sdks/javascript/dist/index.d.cts
@@ -64,20 +64,46 @@ declare class OptaveJavaScriptSDK {
elevate(params: any): Promise;
customerInteraction(params: any): Promise;
interaction(params: any): Promise;
+ assistant(params: any): Promise;
reception(params: any): Promise;
summarize(params: any): Promise;
translate(params: any): Promise;
recommend(params: any): Promise;
insights(params: any): Promise;
+ assistantAsync(params: any, opts?: any): Promise;
disconnect(): void;
isConnected(): boolean;
on(event: string, listener: (...args: any[]) => void): this;
emit(event: string, ...args: any[]): boolean;
}
+type AuthTransport = 'subprotocol' | 'query';
+declare const SERVER_ENVIRONMENTS: {
+ websocket: {
+ wsEnv: {
+ default: string;
+ examples: string[];
+ };
+ baseDomain: {
+ default: string;
+ examples: string[];
+ };
+ };
+ auth: {
+ authEnv: {
+ default: string;
+ examples: string[];
+ };
+ baseDomain: {
+ default: string;
+ examples: string[];
+ };
+ };
+};
+declare function buildWebSocketUrl(wsEnv?: string, baseDomain?: string): string;
+declare function buildAuthUrl(authEnv?: string, baseDomain?: string): string;
declare const OAUTH2_TOKEN_URL: string;
-type AuthTransport = 'subprotocol' | 'query';
interface GeneratedClientConfig {
websocketUrl: string;
authUrl: string;
@@ -86,21 +112,5 @@ interface GeneratedClientConfig {
}
declare const createDefaultConfig: () => GeneratedClientConfig;
declare const DEFAULT_CONFIG: GeneratedClientConfig;
-declare const SERVER_ENVIRONMENTS: {
- readonly websocket: {
- readonly wsEnv: {
- readonly default: "default";
- readonly examples: readonly ["default", "staging", "production"];
- };
- };
- readonly auth: {
- readonly authEnv: {
- readonly default: "default";
- readonly examples: readonly ["default", "staging", "production"];
- };
- };
-};
-declare function buildWebSocketUrl(environment?: string): string;
-declare function buildAuthUrl(environment?: string): string;
export { type AuthCredentials, type AuthTokenResponse, type AuthTransport, DEFAULT_CONFIG, type GeneratedClientConfig, type Logger, type MessageEnvelope, OAUTH2_TOKEN_URL, OptaveJavaScriptSDK, type Opts, SERVER_ENVIRONMENTS, type SdkEvents, type WebSocketOptions, buildAuthUrl, buildWebSocketUrl, createDefaultConfig };
diff --git a/sdks/javascript/dist/index.d.ts b/sdks/javascript/dist/index.d.ts
index 881b605..c72d3bd 100644
--- a/sdks/javascript/dist/index.d.ts
+++ b/sdks/javascript/dist/index.d.ts
@@ -64,20 +64,46 @@ declare class OptaveJavaScriptSDK {
elevate(params: any): Promise;
customerInteraction(params: any): Promise;
interaction(params: any): Promise;
+ assistant(params: any): Promise;
reception(params: any): Promise;
summarize(params: any): Promise;
translate(params: any): Promise;
recommend(params: any): Promise;
insights(params: any): Promise;
+ assistantAsync(params: any, opts?: any): Promise;
disconnect(): void;
isConnected(): boolean;
on(event: string, listener: (...args: any[]) => void): this;
emit(event: string, ...args: any[]): boolean;
}
+type AuthTransport = 'subprotocol' | 'query';
+declare const SERVER_ENVIRONMENTS: {
+ websocket: {
+ wsEnv: {
+ default: string;
+ examples: string[];
+ };
+ baseDomain: {
+ default: string;
+ examples: string[];
+ };
+ };
+ auth: {
+ authEnv: {
+ default: string;
+ examples: string[];
+ };
+ baseDomain: {
+ default: string;
+ examples: string[];
+ };
+ };
+};
+declare function buildWebSocketUrl(wsEnv?: string, baseDomain?: string): string;
+declare function buildAuthUrl(authEnv?: string, baseDomain?: string): string;
declare const OAUTH2_TOKEN_URL: string;
-type AuthTransport = 'subprotocol' | 'query';
interface GeneratedClientConfig {
websocketUrl: string;
authUrl: string;
@@ -86,21 +112,5 @@ interface GeneratedClientConfig {
}
declare const createDefaultConfig: () => GeneratedClientConfig;
declare const DEFAULT_CONFIG: GeneratedClientConfig;
-declare const SERVER_ENVIRONMENTS: {
- readonly websocket: {
- readonly wsEnv: {
- readonly default: "default";
- readonly examples: readonly ["default", "staging", "production"];
- };
- };
- readonly auth: {
- readonly authEnv: {
- readonly default: "default";
- readonly examples: readonly ["default", "staging", "production"];
- };
- };
-};
-declare function buildWebSocketUrl(environment?: string): string;
-declare function buildAuthUrl(environment?: string): string;
export { type AuthCredentials, type AuthTokenResponse, type AuthTransport, DEFAULT_CONFIG, type GeneratedClientConfig, type Logger, type MessageEnvelope, OAUTH2_TOKEN_URL, OptaveJavaScriptSDK, type Opts, SERVER_ENVIRONMENTS, type SdkEvents, type WebSocketOptions, buildAuthUrl, buildWebSocketUrl, createDefaultConfig };
diff --git a/sdks/javascript/dist/index.js b/sdks/javascript/dist/index.js
index 331720d..985460a 100644
--- a/sdks/javascript/dist/index.js
+++ b/sdks/javascript/dist/index.js
@@ -1,42 +1,53 @@
// generated/connection-config.ts
var DEFAULT_CONFIG = {
- websocketUrl: "wss://{wsEnv}.oco.optave.tech/",
- authUrl: "https://{authEnv}.oco.optave.tech/auth/oauth2",
- // Base URL - SDK will append /token
- supportedAuthTransports: ["subprotocol", "query", "oauth2"]
+ websocketUrl: "wss://{wsEnv}.{baseDomain}/",
+ authUrl: "https://{authEnv}.{baseDomain}/auth/oauth2",
+ supportedAuthTransports: ["subprotocol", "query"]
};
-var OAUTH2_TOKEN_URL = DEFAULT_CONFIG.authUrl;
-
-// runtime/core/index.ts
-var createDefaultConfig = () => ({
- websocketUrl: "wss://default.oco.optave.tech/",
- authUrl: "https://default.oco.optave.tech/auth/oauth2/",
- supportedAuthTransports: ["subprotocol", "query"],
- OptaveTraceChatSessionId: void 0
-});
-var DEFAULT_CONFIG2 = createDefaultConfig();
var SERVER_ENVIRONMENTS = {
websocket: {
wsEnv: {
- default: "default",
- examples: ["default", "staging", "production"]
+ default: "ws-incubator",
+ examples: ["ws-incubator", "ws-sandbox", "ws-prod"]
+ },
+ baseDomain: {
+ default: "oco.optave.tech",
+ examples: ["oco.optave.tech"]
}
},
auth: {
authEnv: {
- default: "default",
- examples: ["default", "staging", "production"]
+ default: "incubator",
+ examples: ["incubator", "sandbox", "prod"]
+ },
+ baseDomain: {
+ default: "oco.optave.tech",
+ examples: ["oco.optave.tech"]
}
}
};
-function buildWebSocketUrl(environment) {
- const env = environment || "default";
- return `wss://${env}.oco.optave.tech/`;
+function buildWebSocketUrl(wsEnv = SERVER_ENVIRONMENTS.websocket.wsEnv?.default, baseDomain = SERVER_ENVIRONMENTS.websocket.baseDomain?.default) {
+ let url = DEFAULT_CONFIG.websocketUrl;
+ url = url.replace("{wsEnv}", wsEnv);
+ url = url.replace("{baseDomain}", baseDomain);
+ return url;
}
-function buildAuthUrl(environment) {
- const env = environment || "default";
- return `https://${env}.oco.optave.tech/auth/oauth2/`;
+function buildAuthUrl(authEnv = SERVER_ENVIRONMENTS.auth.authEnv?.default, baseDomain = SERVER_ENVIRONMENTS.auth.baseDomain?.default) {
+ let url = DEFAULT_CONFIG.authUrl;
+ url = url.replace("{authEnv}", authEnv);
+ url = url.replace("{baseDomain}", baseDomain);
+ return url;
}
+var OAUTH2_TOKEN_URL = buildAuthUrl();
+
+// runtime/core/index.ts
+var createDefaultConfig = () => ({
+ websocketUrl: buildWebSocketUrl(),
+ authUrl: buildAuthUrl(),
+ supportedAuthTransports: ["subprotocol", "query"],
+ OptaveTraceChatSessionId: void 0
+});
+var DEFAULT_CONFIG2 = createDefaultConfig();
export {
DEFAULT_CONFIG2 as DEFAULT_CONFIG,
OAUTH2_TOKEN_URL,
diff --git a/sdks/javascript/dist/sdk-governance.json b/sdks/javascript/dist/sdk-governance.json
index 309e4f2..9f957b9 100644
--- a/sdks/javascript/dist/sdk-governance.json
+++ b/sdks/javascript/dist/sdk-governance.json
@@ -1,9 +1,9 @@
{
"metadata": {
"version": "1.0.0",
- "generatedAt": "2025-10-16T09:18:53.596Z",
- "sdkVersion": "3.2.3",
- "nodeVersion": "v22.20.0"
+ "generatedAt": "2026-09-02T23:31:38.534Z",
+ "sdkVersion": "3.6.0",
+ "nodeVersion": "v22.23.2"
},
"buildTargets": [
{
@@ -15,11 +15,11 @@
"path": "dist/browser.mjs",
"exists": true,
"size": {
- "raw": 47826,
- "gzipped": 14096
+ "raw": 50657,
+ "gzipped": 14798
},
- "hash": "243837707bb78b1e0c53145032f35a8e3a5318129801638f393bf0558ac61a3c",
- "exportMethodCount": 14
+ "hash": "d53a26a4b1aead28ce49f3512a8adc9096e76f468b5df1ca9721e59bf43a0f54",
+ "exportMethodCount": 13
},
{
"name": "server-esm",
@@ -30,10 +30,10 @@
"path": "dist/server.mjs",
"exists": true,
"size": {
- "raw": 167918,
- "gzipped": 25580
+ "raw": 183357,
+ "gzipped": 29775
},
- "hash": "e25cb391a271991664fbec7570b6e73bd0dfe1d823a7bcf6648d24885eec335d",
+ "hash": "91a1ede303961f092c93d328d6616ff60e0b5c8adf13741ff9db1aab0559d135",
"exportMethodCount": 58
},
{
@@ -45,10 +45,10 @@
"path": "dist/browser.umd.js",
"exists": true,
"size": {
- "raw": 56425,
- "gzipped": 16305
+ "raw": 59102,
+ "gzipped": 16963
},
- "hash": "a2b77f7188dfacd0884d3e10b2aac4867f4383b09361b4b3dc682ba5952389b4",
+ "hash": "d2fa8ba7b6cdad0ac8cd7d3861db81d350346e7864974ec6fadd42c845960833",
"exportMethodCount": 19
},
{
@@ -60,11 +60,11 @@
"path": "dist/server.umd.js",
"exists": true,
"size": {
- "raw": 57003,
- "gzipped": 16424
+ "raw": 54346,
+ "gzipped": 15435
},
- "hash": "6824367d3d65920a9085b814b93ba17a00a67de6c055bd8a8b28b3bc757e3a0a",
- "exportMethodCount": 19
+ "hash": "2ca18013d50dcc6f4c44e1348433b58eba3110603e0367a35b9cd7ad75e63200",
+ "exportMethodCount": 18
},
{
"name": "typescript-definitions",
@@ -75,18 +75,18 @@
"path": "dist/index.d.ts",
"exists": true,
"size": {
- "raw": 3464,
- "gzipped": 1078
+ "raw": 3633,
+ "gzipped": 1083
},
- "hash": "0818b682447228a97d80aa3ac50fa3d6e7f546734745f91549c91dc1dd58939e",
+ "hash": "74d044f227d89ec4b9906703707aaf2c3055d8bb0d4440e412f43ae9b9f8b015",
"exportMethodCount": 0
}
],
"summary": {
"totalTargets": 5,
"totalSize": {
- "raw": 332636,
- "gzipped": 73483
+ "raw": 351095,
+ "gzipped": 78054
},
"formats": [
"ESM",
@@ -100,11 +100,11 @@
]
},
"governance": {
- "validatorVersion": "3.2.3",
- "buildTimestamp": "2025-10-16T09:18:53.596Z",
+ "validatorVersion": null,
+ "buildTimestamp": "2026-09-02T23:31:38.535Z",
"integrity": {
"allTargetsPresent": true,
- "totalExportMethods": 110
+ "totalExportMethods": 108
}
}
}
\ No newline at end of file
diff --git a/sdks/javascript/dist/server.mjs b/sdks/javascript/dist/server.mjs
index 06d1c4f..3ce5f2d 100644
--- a/sdks/javascript/dist/server.mjs
+++ b/sdks/javascript/dist/server.mjs
@@ -1 +1 @@
-import{default as e}from"events";import{createHash as t,randomFillSync as s,randomUUID as r}from"crypto";import{default as a}from"ws";const i=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;const p=function(e){return"string"==typeof e&&i.test(e)};const o=function(e){if(!p(e))throw TypeError("Invalid UUID");let t;return Uint8Array.of((t=parseInt(e.slice(0,8),16))>>>24,t>>>16&255,t>>>8&255,255&t,(t=parseInt(e.slice(9,13),16))>>>8,255&t,(t=parseInt(e.slice(14,18),16))>>>8,255&t,(t=parseInt(e.slice(19,23),16))>>>8,255&t,(t=parseInt(e.slice(24,36),16))/1099511627776&255,t/4294967296&255,t>>>24&255,t>>>16&255,t>>>8&255,255&t)},n=[];for(let e=0;e<256;++e)n.push((e+256).toString(16).slice(1));function c(e,t=0){return(n[e[t+0]]+n[e[t+1]]+n[e[t+2]]+n[e[t+3]]+"-"+n[e[t+4]]+n[e[t+5]]+"-"+n[e[t+6]]+n[e[t+7]]+"-"+n[e[t+8]]+n[e[t+9]]+"-"+n[e[t+10]]+n[e[t+11]]+n[e[t+12]]+n[e[t+13]]+n[e[t+14]]+n[e[t+15]]).toLowerCase()}const u=new Uint8Array(256);let d=u.length;function m(){return d>u.length-16&&(s(u),d=0),u.slice(d,d+=16)}const y=function(e){return Array.isArray(e)?e=Buffer.from(e):"string"==typeof e&&(e=Buffer.from(e,"utf8")),t("md5").update(e).digest()};const h="6ba7b810-9dad-11d1-80b4-00c04fd430c8",l="6ba7b811-9dad-11d1-80b4-00c04fd430c8";function g(e,t,s,r,a,i){const p="string"==typeof s?function(e){e=unescape(encodeURIComponent(e));const t=new Uint8Array(e.length);for(let s=0;s= 16");if(r){if(a<0||a+16>r.length)throw new RangeError(`UUID byte range ${a}:${a+15} is out of buffer bounds`)}else r=new Uint8Array(16),a=0;return t??=Date.now(),s??=127*e[6]<<24|e[7]<<16|e[8]<<8|e[9],r[a++]=t/1099511627776&255,r[a++]=t/4294967296&255,r[a++]=t/16777216&255,r[a++]=t/65536&255,r[a++]=t/256&255,r[a++]=255&t,r[a++]=112|s>>>28&15,r[a++]=s>>>20&255,r[a++]=128|s>>>14&63,r[a++]=s>>>6&255,r[a++]=s<<2&255|3&e[10],r[a++]=e[11],r[a++]=e[12],r[a++]=e[13],r[a++]=e[14],r[a++]=e[15],r}const S=function(e,t,s){let r;if(e)r=P(e.random??e.rng?.()??m(),e.msecs,e.seq,t,s);else{const e=Date.now(),a=m();!function(e,t,s){e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=s[6]<<23|s[7]<<16|s[8]<<8|s[9],e.msecs=t):(e.seq=e.seq+1|0,0===e.seq&&e.msecs++)}(q,e,a),r=P(a,q.msecs,q.seq,t,s)}return t??c(r)};const w={type:"object",required:["action","headers","payload"],properties:{action:{type:"string",enum:["message"],description:"Action type for the envelope"},headers:{type:"object",required:["correlationId","action","schemaRef"],properties:{correlationId:{type:"string",format:"uuidv7",description:"UUID for correlating request-response pairs (always generated client-side unless overridden)"},tenantId:{type:"string",description:"Tenant identifier provided by Optave"},traceId:{type:"string",format:"uuidv7",description:"Optional cross-system tracing ID (forwarded if provided)"},idempotencyKey:{type:"string",format:"uuidv7",description:"Optional idempotency key; forwarded unchanged if provided"},identifier:{type:"string",enum:["message"],description:"Message identifier"},action:{type:"string",enum:["adjust","elevate","customerinteraction","interaction","reception","summarize","translate","recommend","insights"],description:"Specific action being performed"},schemaRef:{type:"string",enum:["optave.message.v3"],description:"Schema reference for the envelope (major version only; minor/patch changes are non-breaking)"},sdkVersion:{type:"string",description:"SDK package version (independent of schemaRef major)"},networkLatencyMs:{type:"number",description:"Optional client-measured round-trip latency (not sent unless explicitly supplied)"},timestamp:{type:"string",format:"date-time",description:"ISO 8601 client timestamp when the message was built"},issuedAt:{type:"string",format:"date-time",description:"Message issued timestamp"}}},payload:{$ref:"Payload"}},allOf:[{type:"object",required:["action","headers","payload"],properties:{action:{type:"string",enum:["message"]},headers:{type:"object"},payload:{type:"object"}}},{if:{properties:{headers:{properties:{action:{enum:["adjust","elevate","interaction","customerInteraction"]}}}}},then:{properties:{payload:{$ref:"PayloadWithRequiredConversations"}}}},{if:{properties:{headers:{properties:{action:{enum:["summarize","translate","insights","recommend"]}}}}},then:{properties:{payload:{$ref:"PayloadWithRequiredConversations"}}}}]},I={allOf:[{$ref:"Payload"},{type:"object",required:["request"],properties:{request:{type:"object",required:["scope"],properties:{scope:{type:"object",required:["conversations"],properties:{conversations:{type:"array",minItems:1,items:{$ref:"Conversation"}}}}}}}}]},k={type:"object",required:["session","request"],properties:{session:{$ref:"Session"},request:{type:"object",required:["requestId"],properties:{requestId:{type:"string",description:"Unique request identifier"},attributes:{$ref:"RequestAttributes"},connections:{$ref:"Connections"},context:{$ref:"Context"},reference:{type:"object",properties:{ids:{type:"array",items:{$ref:"ReferenceId"}},labels:{type:"array",description:"Reference labels"},tags:{type:"array",description:"Reference tags"}}},resources:{type:"object",properties:{codes:{type:"array",items:{$ref:"CodesItem"}},links:{type:"array",items:{$ref:"LinkItem"}},offers:{type:"array",description:"Offering details (previously offering_details in v2)"}}},scope:{type:"object",properties:{accounts:{type:"array"},appointments:{type:"array"},assets:{type:"array"},bookings:{type:"array"},cases:{type:"array"},conversations:{type:"array",items:{$ref:"Conversation"}},documents:{type:"array"},events:{type:"array"},interactions:{type:"array",items:{$ref:"Interaction"}},items:{type:"array"},locations:{type:"array"},offers:{type:"array"},operators:{type:"array"},orders:{type:"array"},organizations:{type:"array"},persons:{type:"array"},policies:{type:"array"},products:{type:"array",items:{$ref:"Product"}},properties:{type:"array"},services:{type:"array"},subscriptions:{type:"array"},tickets:{type:"array"},transactions:{type:"array"},users:{type:"array"}}},settings:{type:"object",properties:{disableBrowsing:{type:"boolean",default:!1},disableSearch:{type:"boolean",default:!1},disableSources:{type:"boolean",default:!1},disableStream:{type:"boolean",default:!0},disableTools:{type:"boolean",default:!1},maxResponseLength:{type:"number",default:0},overrideInterfaceLanguage:{type:"string",description:"Override interface language"},overrideOutputLanguage:{type:"string",description:"Override output language (replaces channel language)"}}},a2a:{type:"array",items:{$ref:"A2AConfiguration"},description:"Advanced mode agent-to-agent configuration"},cursor:{$ref:"Cursor"}}}}},A={type:"object",properties:{content:{type:"string",description:"Content to be processed"},instruction:{type:"string",description:"Specific instruction for the action"},variant:{type:"string",description:'Variant identifier (e.g., "A", "B")'}}},E={type:"object",properties:{journeyId:{type:"string",description:"Journey identifier"},parentId:{type:"string",description:"Parent request ID (previously trace_parent_ID in v2)"},threadId:{type:"string",description:"Thread ID that remains unique across all requests related to same ticket/case/conversation"}}},_={type:"object",properties:{caseId:{type:"string",description:"Case identifier (advanced mode)"},departmentId:{type:"string",description:"Department identifier (advanced mode)"},operatorId:{type:"string",description:"Operator identifier (advanced mode)"},organizationId:{type:"string",description:"Organization identifier"},userId:{type:"string",description:"User identifier (advanced mode)"}}},j={type:"object",properties:{name:{type:"string"},value:{type:"string"}}},O={type:"object",properties:{id:{type:"string",description:"Optional for tracking/mapping"},label:{type:"string",description:'Optional, helps for display/templating (e.g., "Order Number")'},type:{type:"string",description:'Code type (e.g., "order_number", "booking_reference", "ticket_code")'},value:{type:"string",description:'Code value (e.g., "ORD-56789")'}}},R={type:"object",properties:{expires_at:{type:"string",description:"Optional expiration timestamp"},html:{type:"boolean",description:"Optional HTML flag"},id:{type:"string",description:"Optional link identifier"},label:{type:"string",description:'Optional label (e.g., "Click here to pay")'},type:{type:"string",description:'Link type (e.g., "payment_link")'},url:{type:"string",description:'URL (e.g., "https://checkout.stripe.com/pay/cs_test...")'}}},T={type:"object",properties:{content:{type:"string"},id:{type:"string"},name:{type:"string"},role:{type:"string"},timestamp:{type:"string"}}},C={type:"object",properties:{id:{type:"string"}}},L={type:"object",properties:{id:{type:"string"},name:{type:"string"},type:{type:"string"}},description:"Advanced mode agent-to-agent configuration"},D={type:"object",properties:{since:{type:"string",description:'Start timestamp (e.g., "2024-01-15T10:30:00.000Z")'},until:{type:"string",description:'End timestamp (e.g., "2024-01-15T11:00:00.000Z")'}}},N={type:"object",properties:{sessionId:{type:"string",description:"Unique session identifier lasting for duration of chat session or call"},channel:{$ref:"Channel"},interface:{$ref:"Interface"}}},U={type:"object",properties:{browser:{type:"string",description:"Browser information"},deviceInfo:{type:"string",description:'Device information (e.g., "iOS/18.2, iPhone15,3")'},deviceType:{type:"string",description:"Type of device"},language:{type:"string",description:"Interface language"},location:{type:"string",description:'Geographic location (e.g., "45.42,-75.69")'},medium:{type:"string",enum:["chat","voice","email"],description:"Communication medium (allowed: chat, voice, email; default is chat if omitted)"},metadata:{type:"array",description:"Custom metadata array"},section:{type:"string",description:'Section of the application (e.g., "cart", "product_page")'}}},M={type:"object",properties:{appVersion:{type:"string",description:"Custom application version"},category:{type:"string",description:'Interface category (e.g., "crm", "app", "auto", "widget")'},language:{type:"string",description:"Language from the CRM agent"},name:{type:"string",description:'Interface name (e.g., "salesforce", "zendesk")'},type:{type:"string",description:'Interface type (e.g., "custom_components", "marketplace", "channel")'}}};function W(e,{instancePath:t="",parentData:s,parentDataProperty:r,rootData:a=e}={}){let i=null,p=0;if(e&&"object"==typeof e&&!Array.isArray(e)){if(void 0!==e.sessionId){let s=e.sessionId;if("string"!=typeof s){const e={instancePath:t+"/sessionId",schemaPath:"#/properties/sessionId/type",keyword:"type",params:{type:"string"},message:"must be string",schema:N.properties.sessionId.type,parentSchema:N.properties.sessionId,data:s};null===i?i=[e]:i.push(e),p++}}if(void 0!==e.channel){let s=e.channel;if(s&&"object"==typeof s&&!Array.isArray(s)){if(void 0!==s.browser){let e=s.browser;if("string"!=typeof e){const s={instancePath:t+"/channel/browser",schemaPath:"Channel/properties/browser/type",keyword:"type",params:{type:"string"},message:"must be string",schema:U.properties.browser.type,parentSchema:U.properties.browser,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.deviceInfo){let e=s.deviceInfo;if("string"!=typeof e){const s={instancePath:t+"/channel/deviceInfo",schemaPath:"Channel/properties/deviceInfo/type",keyword:"type",params:{type:"string"},message:"must be string",schema:U.properties.deviceInfo.type,parentSchema:U.properties.deviceInfo,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.deviceType){let e=s.deviceType;if("string"!=typeof e){const s={instancePath:t+"/channel/deviceType",schemaPath:"Channel/properties/deviceType/type",keyword:"type",params:{type:"string"},message:"must be string",schema:U.properties.deviceType.type,parentSchema:U.properties.deviceType,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.language){let e=s.language;if("string"!=typeof e){const s={instancePath:t+"/channel/language",schemaPath:"Channel/properties/language/type",keyword:"type",params:{type:"string"},message:"must be string",schema:U.properties.language.type,parentSchema:U.properties.language,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.location){let e=s.location;if("string"!=typeof e){const s={instancePath:t+"/channel/location",schemaPath:"Channel/properties/location/type",keyword:"type",params:{type:"string"},message:"must be string",schema:U.properties.location.type,parentSchema:U.properties.location,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.medium){let e=s.medium;if("string"!=typeof e){const s={instancePath:t+"/channel/medium",schemaPath:"Channel/properties/medium/type",keyword:"type",params:{type:"string"},message:"must be string",schema:U.properties.medium.type,parentSchema:U.properties.medium,data:e};null===i?i=[s]:i.push(s),p++}if("chat"!==e&&"voice"!==e&&"email"!==e){const s={instancePath:t+"/channel/medium",schemaPath:"Channel/properties/medium/enum",keyword:"enum",params:{allowedValues:U.properties.medium.enum},message:"must be equal to one of the allowed values",schema:U.properties.medium.enum,parentSchema:U.properties.medium,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.metadata){let e=s.metadata;if(!Array.isArray(e)){const s={instancePath:t+"/channel/metadata",schemaPath:"Channel/properties/metadata/type",keyword:"type",params:{type:"array"},message:"must be array",schema:U.properties.metadata.type,parentSchema:U.properties.metadata,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.section){let e=s.section;if("string"!=typeof e){const s={instancePath:t+"/channel/section",schemaPath:"Channel/properties/section/type",keyword:"type",params:{type:"string"},message:"must be string",schema:U.properties.section.type,parentSchema:U.properties.section,data:e};null===i?i=[s]:i.push(s),p++}}}else{const e={instancePath:t+"/channel",schemaPath:"Channel/type",keyword:"type",params:{type:"object"},message:"must be object",schema:U.type,parentSchema:U,data:s};null===i?i=[e]:i.push(e),p++}}if(void 0!==e.interface){let s=e.interface;if(s&&"object"==typeof s&&!Array.isArray(s)){if(void 0!==s.appVersion){let e=s.appVersion;if("string"!=typeof e){const s={instancePath:t+"/interface/appVersion",schemaPath:"Interface/properties/appVersion/type",keyword:"type",params:{type:"string"},message:"must be string",schema:M.properties.appVersion.type,parentSchema:M.properties.appVersion,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.category){let e=s.category;if("string"!=typeof e){const s={instancePath:t+"/interface/category",schemaPath:"Interface/properties/category/type",keyword:"type",params:{type:"string"},message:"must be string",schema:M.properties.category.type,parentSchema:M.properties.category,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.language){let e=s.language;if("string"!=typeof e){const s={instancePath:t+"/interface/language",schemaPath:"Interface/properties/language/type",keyword:"type",params:{type:"string"},message:"must be string",schema:M.properties.language.type,parentSchema:M.properties.language,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.name){let e=s.name;if("string"!=typeof e){const s={instancePath:t+"/interface/name",schemaPath:"Interface/properties/name/type",keyword:"type",params:{type:"string"},message:"must be string",schema:M.properties.name.type,parentSchema:M.properties.name,data:e};null===i?i=[s]:i.push(s),p++}}if(void 0!==s.type){let e=s.type;if("string"!=typeof e){const s={instancePath:t+"/interface/type",schemaPath:"Interface/properties/type/type",keyword:"type",params:{type:"string"},message:"must be string",schema:M.properties.type.type,parentSchema:M.properties.type,data:e};null===i?i=[s]:i.push(s),p++}}}else{const e={instancePath:t+"/interface",schemaPath:"Interface/type",keyword:"type",params:{type:"object"},message:"must be object",schema:M.type,parentSchema:M,data:s};null===i?i=[e]:i.push(e),p++}}}else{const s={instancePath:t,schemaPath:"#/type",keyword:"type",params:{type:"object"},message:"must be object",schema:N.type,parentSchema:N,data:e};null===i?i=[s]:i.push(s),p++}return W.errors=i,0===p}const V={type:"object",properties:{conversationId:{type:"string"},participants:{type:"array",items:{$ref:"Participant"}},messages:{type:"array",items:{$ref:"Message"}},metadata:{type:"object"}}},$={type:"object",properties:{participantId:{type:"string"},displayName:{type:"string"},role:{type:"string",enum:["operator","user","bot"]}}},B={type:"object",properties:{content:{type:"string"},participantId:{type:"string"},timestamp:{type:"string"}}};function x(e,{instancePath:t="",parentData:s,parentDataProperty:r,rootData:a=e}={}){let i=null,p=0;if(e&&"object"==typeof e&&!Array.isArray(e)){if(void 0!==e.conversationId){let s=e.conversationId;if("string"!=typeof s){const e={instancePath:t+"/conversationId",schemaPath:"#/properties/conversationId/type",keyword:"type",params:{type:"string"},message:"must be string",schema:V.properties.conversationId.type,parentSchema:V.properties.conversationId,data:s};null===i?i=[e]:i.push(e),p++}}if(void 0!==e.participants){let s=e.participants;if(Array.isArray(s)){const e=s.length;for(let r=0;r({valid:G(e),errors:G.errors||null}),ge=e=>({valid:he(e),errors:he.errors||null});function fe(e,t,s="validation",r={}){return{instancePath:e,message:t,keyword:s,params:r}}function be(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[fe("","must be object","type",{type:"object"})]};const t=[];return e.session?"object"!=typeof e.session?t.push(fe("/session","must be object","type",{type:"object"})):void 0!==e.session.sessionId&&"string"!=typeof e.session.sessionId&&t.push(fe("/session/sessionId","must be string","type",{type:"string"})):t.push(fe("/session","is required","required",{missingProperty:"session"})),e.request?"object"!=typeof e.request?t.push(fe("/request","must be object","type",{type:"object"})):(e.request.connections?"object"!=typeof e.request.connections?t.push(fe("/request/connections","must be object","type",{type:"object"})):(e.request.connections.threadId?"string"!=typeof e.request.connections.threadId&&t.push(fe("/request/connections/threadId","must be string","type",{type:"string"})):t.push(fe("/request/connections/threadId","is required","required",{missingProperty:"threadId"})),void 0!==e.request.connections.parentId&&"string"!=typeof e.request.connections.parentId&&t.push(fe("/request/connections/parentId","must be string","type",{type:"string"}))):t.push(fe("/request/connections","is required","required",{missingProperty:"connections"})),void 0!==e.request.context&&"object"!=typeof e.request.context&&t.push(fe("/request/context","must be object","type",{type:"object"})),void 0!==e.request.attributes&&"object"!=typeof e.request.attributes&&t.push(fe("/request/attributes","must be object","type",{type:"object"})),void 0!==e.request.scope&&("object"!=typeof e.request.scope?t.push(fe("/request/scope","must be object","type",{type:"object"})):void 0!==e.request.scope.conversations&&(Array.isArray(e.request.scope.conversations)||t.push(fe("/request/scope/conversations","must be array","type",{type:"array"})))),void 0!==e.request.resources&&("object"!=typeof e.request.resources?t.push(fe("/request/resources","must be object","type",{type:"object"})):void 0!==e.request.resources.offers&&(Array.isArray(e.request.resources.offers)||t.push(fe("/request/resources/offers","must be array","type",{type:"array"}))))):t.push(fe("/request","is required","required",{missingProperty:"request"})),t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function ve(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[fe("","must be object","type",{type:"object"})]};const t=[];if(e.headers)if("object"!=typeof e.headers)t.push(fe("/headers","must be object","type",{type:"object"}));else{if(e.headers.correlationId?"string"!=typeof e.headers.correlationId&&t.push(fe("/headers/correlationId","must be string","type",{type:"string"})):t.push(fe("/headers/correlationId","is required","required",{missingProperty:"correlationId"})),e.headers.action)if("string"!=typeof e.headers.action)t.push(fe("/headers/action","must be string","type",{type:"string"}));else{const s=["adjust","elevate","interaction","customerinteraction","reception","summarize","translate","recommend","insights"];s.includes(e.headers.action)||t.push(fe("/headers/action","must be equal to one of the allowed values","enum",{allowedValues:s}))}else t.push(fe("/headers/action","is required","required",{missingProperty:"action"}));void 0!==e.headers.identifier&&"string"!=typeof e.headers.identifier&&t.push(fe("/headers/identifier","must be string","type",{type:"string"})),void 0!==e.headers.schemaRef&&"string"!=typeof e.headers.schemaRef&&t.push(fe("/headers/schemaRef","must be string","type",{type:"string"})),void 0!==e.headers.timestamp&&"string"!=typeof e.headers.timestamp&&t.push(fe("/headers/timestamp","must be string","type",{type:"string"}))}else t.push(fe("/headers","is required","required",{missingProperty:"headers"}));if(e.payload){if("object"!=typeof e.payload)t.push(fe("/payload","must be object","type",{type:"object"}));else if(e.headers&&e.headers.action&&e.payload){const s=e.headers.action;["adjust","elevate","interaction","customerinteraction","customerInteraction","summarize","translate","insights","recommend"].includes(s)&&(e.payload.request?e.payload.request.scope?e.payload.request.scope.conversations?Array.isArray(e.payload.request.scope.conversations)?0===e.payload.request.scope.conversations.length&&t.push(fe("/payload/request/scope/conversations",`must be non-empty array for ${s}`,"minItems",{limit:1})):t.push(fe("/payload/request/scope/conversations","must be array","type",{type:"array"})):t.push(fe("/payload/request/scope/conversations",`is required for ${s}`,"required",{missingProperty:"conversations"})):t.push(fe("/payload/request/scope","is required","required",{missingProperty:"scope"})):t.push(fe("/payload/request","is required","required",{missingProperty:"request"})))}}else t.push(fe("/payload","is required","required",{missingProperty:"payload"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}const qe="3.2.3",Pe=`optave.message.v${qe.split(".")[0]}`,Se={AUTHENTICATION:"AUTHENTICATION",ORCHESTRATOR:"ORCHESTRATOR",VALIDATION:"VALIDATION",WEBSOCKET:"WEBSOCKET"},we=Object.freeze({MESSAGE:"message",ERROR:"error"}),Ie=Object.freeze({CONNECTION_OPEN:"connection:open",CONNECTION_CLOSE:"connection:close",CONNECTION_ERROR:"connection:error",MESSAGE_RECEIVED:"message:received",MESSAGE_SENT:"message:sent",ERROR:"error",RESPONSE:"response",LEGACY_ERROR:"error",LEGACY_MESSAGE:"message"}),ke=Object.freeze({SUPERPOWER_RESPONSE:"superpower.response",SUPERPOWER_ERROR:"superpower.error"}),Ae=new Set(["adjust","elevate","interaction","reception","customerInteraction","summarize","translate","recommend","insights"]),Ee={SPEC_VERSION:qe,SCHEMA_REF:Pe,MAX_PAYLOAD_SIZE:131072,MAX_PAYLOAD_SIZE_KB:128,DEFAULT_REQUEST_TIMEOUT_MS:3e4,ErrorCategory:Se,LegacyEvents:we,EVENTS:Ie,InboundEvents:ke,ALLOWED_ACTIONS:Ae};function _e(e){const t=[];if((()=>{if("undefined"!=typeof process&&process.versions&&process.versions.node&&("true"===process.env.VITEST||void 0!==process.env.JEST_WORKER_ID||process.argv.some(e=>e.includes("vitest")||e.includes("jest")||e.includes("test"))))return!(!("undefined"!=typeof global&&"window"in global&&global.window&&"document"in global&&global.document)||process.env.OPTAVE_SDK_FORCE_SERVER_ENV);if("undefined"!=typeof global){if(!("window"in global)&&!("document"in global)&&"undefined"!=typeof process&&process.versions&&process.versions.node)return!1;if((!("window"in global)||!("document"in global))&&"undefined"!=typeof process&&process.versions&&process.versions.node)return!1;if("window"in global&&global.window)return!0;if("document"in global&&global.document)return!0}try{if("undefined"!=typeof window&&null!==window)return!("undefined"!=typeof global&&!("window"in global)||"undefined"!=typeof global&&"undefined"!=typeof process&&process.versions&&process.versions.node&&!("window"in global));if("undefined"!=typeof document&&null!==document)return!("undefined"!=typeof global&&!("document"in global)||"undefined"!=typeof global&&"undefined"!=typeof process&&process.versions&&process.versions.node&&!("document"in global))}catch(e){}return"undefined"!=typeof navigator&&"ReactNative"===navigator.product||!("undefined"==typeof global||!global.__expo)||"undefined"!=typeof location&&null!==location||("undefined"!=typeof process&&process.versions&&process.versions.node,!1)})()&&e.clientSecret){let e=!1,s=!1;try{e=!0===__SALESFORCE_BUILD__}catch(e){}try{s=!0}catch(e){}e||s||t.push({type:"error",code:"CLIENT_SECRET_IN_CLIENT_ENV",message:"clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.",field:"clientSecret"})}return t}const je={BROWSER_ESM:"browser-esm",SERVER_ESM:"server-esm",BROWSER_UMD:"browser-umd",SERVER_UMD:"server-umd"},Oe={browser:je.BROWSER_ESM,server:je.SERVER_ESM},Re={BROWSER:[je.BROWSER_ESM,je.BROWSER_UMD,je.SERVER_UMD],SERVER:[je.SERVER_ESM],UMD:[je.BROWSER_UMD,je.SERVER_UMD],ESM:[je.BROWSER_ESM,je.SERVER_ESM]},Te={isValid:e=>Object.values(je).includes(e)||Object.keys(Oe).includes(e),normalize:e=>Oe[e]?Oe[e]:Object.values(je).includes(e)?e:"unknown",isBrowser(e){const t=this.normalize(e);return Re.BROWSER.includes(t)},isServer(e){const t=this.normalize(e);return Re.SERVER.includes(t)},isUMD(e){const t=this.normalize(e);return Re.UMD.includes(t)},isESM(e){const t=this.normalize(e);return Re.ESM.includes(t)},getInfo(e){return{original:e,normalized:this.normalize(e),valid:this.isValid(e),isBrowser:this.isBrowser(e),isServer:this.isServer(e),isUMD:this.isUMD(e),isESM:this.isESM(e)}}};class Ce extends Error{constructor({category:e,code:t,message:s,details:r}){super(s),this.name="OptaveError",this.category=e||"UNKNOWN",this.code=t||"UNKNOWN",void 0!==r&&(this.details=r)}}!function(){if("undefined"!=typeof globalThis){globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__=!0;if(!globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__)throw new Error("Security guard initialization failed")}"undefined"!=typeof process&&process.env}(),"undefined"!=typeof window?window.__OPTAVE_SECURITY_GUARDS_BROWSER__=!0:"undefined"!=typeof global&&(global.__OPTAVE_SECURITY_GUARDS_NODE__=!0);const Le="3.2.3",De=()=>{const e="server-esm";return{isBrowser:Te.isBrowser(e),isServer:Te.isServer(e),buildTarget:e}};let Ne=!1,Ue=!1;class Me extends e{options={};wss=null;static defaultPayload={session:{sessionId:"",channel:{browser:"",deviceInfo:"",deviceType:"",language:"",location:"",medium:"chat",metadata:[],section:""},interface:{appVersion:"",category:"",language:"",name:"",type:""}},request:{requestId:"",attributes:{content:"",instruction:"",variant:"A"},connections:{journeyId:"",parentId:"",threadId:""},context:{caseId:"",departmentId:"",operatorId:"",organizationId:"",userId:""},reference:{ids:[{name:"",value:""}],labels:[],tags:[]},resources:{codes:[{id:"",label:"",type:"",value:""}],links:[{expires_at:"",html:!1,id:"",label:"",type:"",url:""}],offers:[]},scope:{accounts:[],appointments:[],assets:[],bookings:[],cases:[],conversations:[],documents:[],events:[],interactions:[],items:[],locations:[],operators:[],orders:[],organizations:[],persons:[],policies:[],products:[{id:""}],properties:[],services:[],subscriptions:[],tickets:[],transactions:[],users:[]},settings:{disableBrowsing:!1,disableSearch:!1,disableSources:!1,disableStream:!0,disableTools:!1,maxResponseLength:0,overrideInterfaceLanguage:"",overrideOutputLanguage:""},a2a:[{id:"",name:"",type:""}],cursor:{since:"",until:""}}};static cleanup(){Ne=!1,Ue=!1}constructor(e){if(super(),this.options={...e},function(e){if(void 0===e.strictValidation){const t="undefined"!=typeof process&&process.env?"production":"development";e.strictValidation="production"!==t}if("number"!=typeof e.requestTimeoutMs&&(e.requestTimeoutMs=3e4),"number"!=typeof e.connectionTimeoutMs&&(e.connectionTimeoutMs=3e4),e.logger||(e.logger={debug(){},info(){},warn(){},error(){}}),e.authTransport||(e.authTransport="subprotocol"),void 0===e.authRequired&&(e.authRequired=!0),!e.tokenProvider){let t=e.tokenUrl;if(!t&&"undefined"!=typeof document){const e=document.querySelector('meta[name="optave-token-url"]');e&&e.content&&(t=e.content)}t||(t="/api/optave/ws-ticket"),e.tokenProvider=async()=>{const s={};e.publishableKey&&(s["X-Optave-Publishable-Key"]=e.publishableKey);const r=await fetch(t,{method:"POST",credentials:"include",headers:s});if(!r.ok)throw new Error("Failed to obtain WS token");const a=await r.json();return a.token||a.access_token}}}(this.options),void 0===this.options.cspSafe){const e=De();"server-esm"===e.buildTarget||"server"===e.buildTarget?this.options.cspSafe=!1:("server-umd"===e.buildTarget||"browser-esm"===e.buildTarget||"browser-umd"===e.buildTarget||e.isBrowser||(()=>{const e=De();return"unknown"!==e.buildTarget?e.isBrowser:"undefined"!=typeof window&&void 0!==window.WebSocket})())&&(this.options.cspSafe=!0)}const t=function(e){const t={isValid:!0,errors:[],warnings:[]},s=function(e){const t=[];return e.websocketUrl&&"string"==typeof e.websocketUrl||t.push({type:"warning",code:"MISSING_WEBSOCKET_URL",message:"websocketUrl not provided; openConnection() will emit an error.",field:"websocketUrl"}),t}(e),r=function(e){const t=[];return!e.authenticationUrl||e.clientId&&e.clientSecret||t.push({type:"warning",code:"INCOMPLETE_AUTH_CONFIG",message:"authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.",field:"authentication"}),t}(e),a=[...s,...r,..._e(e)];for(const e of a)"error"===e.type?(t.errors.push(e),t.isValid=!1):"warning"===e.type&&t.warnings.push(e);return t}(this.options);if(!t.isValid){const e=t.errors.map(e=>e.message).join("; ");throw new Error(`[Optave SDK] Configuration errors: ${e}`)}t.warnings.forEach(e=>{(this.options?.logger?.warn||console.warn)(`[Optave SDK] ${e.message}`)});try{!function(e,t,s={}){if(!e||"string"!=typeof e)return;const r=Te.normalize(t),a=Te.isUMD(r),i=Te.isBrowser(r);if((a||i)&&e.startsWith("ws://"))throw new Error(`[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in UMD builds. Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. Please use secure WebSocket protocol (wss://) instead. Current URL: ${e}`);if(a&&e.startsWith("wss://")){const t="function"==typeof s.tokenProvider,r=!1===s.authRequired;if(!t&&!r)throw new Error(`[Optave SDK] UMD builds require a tokenProvider function for secure WebSocket connections. In constrained environments like Salesforce Lightning, authentication tokens must be obtained from your backend server. Please provide options.tokenProvider() that returns a valid token, or set options.authRequired = false to disable authentication. Current URL: ${e}`)}}(this.options.websocketUrl,"server-esm",this.options)}catch(e){throw e}const s=De();this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&s.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&s.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this._pending=new Map,this._deprecatedKeys=new Set,this._silenceDeprecations="undefined"!=typeof process&&"1"===process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS,this.options.cspSafe?(this._validatePayload=be,this._validateMessageEnvelope=ve):(this._validatePayload=ge,this._validateMessageEnvelope=le)}async _ensureWebSocketImpl(){if(this.WebSocketImpl)return this.WebSocketImpl;const e=De();return this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&e.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&e.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this.WebSocketImpl||(e.isBrowser?this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:null:e.isServer&&(this.WebSocketImpl=await this.loadNodeWebSocket())),this.WebSocketImpl}async loadNodeWebSocket(){const e=De();return e.isBrowser?null:("unknown"!==e.buildTarget||"undefined"==typeof window&&"undefined"==typeof document&&"undefined"==typeof navigator&&"undefined"==typeof location)&&"undefined"!=typeof process&&process.versions&&process.versions.node?await async function(){return"undefined"!=typeof window||"undefined"!=typeof document||"undefined"!=typeof navigator||"undefined"!=typeof location?null:"undefined"!=typeof process&&process.versions&&process.versions.node?a:null}():null}static getSdkVersion(){return Le}static getSpecVersion(){return qe}static getSchemaRef(){return Pe}static get CONSTANTS(){return Ee}static get LegacyEvents(){return we}static get InboundEvents(){return ke}setSessionId(e){return this.sessionId=e,this}getSessionId(){return this.sessionId||""}validate(e){return this._validatePayload(e).valid}validateEnvelope(e){return this._validateMessageEnvelope(e).valid}validateRequiredFields(e,t){const s=[];switch(e.request?.connections?.threadId||s.push("request.connections.threadId is required"),t){case"adjust":e.request?.attributes?.content||s.push("request.attributes.content is required for adjust"),e.request?.attributes?.instruction||s.push("request.attributes.instruction is required for adjust"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for adjust"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for adjust and must be a non-empty array");break;case"elevate":e.request?.attributes?.content||s.push("request.attributes.content is required for elevate"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for elevate"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for elevate and must be a non-empty array");break;case"translate":case"summarize":case"insights":case"customerinteraction":case"customerInteraction":case"interaction":e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push(`request.scope.conversations is required for ${t} and must be a non-empty array`);break;case"recommend":e.request?.resources?.offers&&Array.isArray(e.request.resources.offers)&&0!==e.request.resources.offers.length||s.push("request.resources.offers is required for recommend and must be a non-empty array"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for recommend and must be a non-empty array")}return{isValid:0===s.length,errors:s}}async authenticate(){if(Te.isBrowser("server-esm"))return this.handleError(Se.AUTHENTICATION,"UNSUPPORTED_IN_BROWSER","authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend."),null;let e={grant_type:"client_credentials"};if(!this.options.authenticationUrl)return this.handleError(Se.AUTHENTICATION,"INVALID_AUTHENTICATION_URL","Empty or invalid authentication URL"),null;if(!this.options.clientId)return this.handleError(Se.AUTHENTICATION,"INVALID_CLIENT_ID","Empty or invalid client ID"),null;e.client_id=this.options.clientId,e.client_secret=this.options.clientSecret;const t=new URLSearchParams(e).toString();let s=this.options.authenticationUrl;s.endsWith("/token")||(s=s.endsWith("/")?s+"token":s+"/token");const r=`${s}?${t}`,a=await fetch(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"}}),i=await a.json();return a.ok?i.access_token:(this.handleError(Se.AUTHENTICATION,"INVALID_AUTHENTICATION_RESPONSE",this.formatAuthenticationError(a,i.error,"token endpoint").message,i.error),null)}async openConnection(e){if(!this.options.websocketUrl)return(this.options?.logger?.error||console.error)("[Optave SDK] openConnection aborted: missing websocketUrl"),void this.handleError(Se.WEBSOCKET,"INVALID_WEBSOCKET_URL",this.formatWebSocketError(new Error("Invalid WebSocket URL configuration"),{url:this.options.websocketUrl}).message,this.options.websocketUrl);const t=await(async()=>{if("string"==typeof e&&e.length>0)return e;if("function"==typeof this.options.tokenProvider)try{return await this.options.tokenProvider()}catch(e){return this.handleError(Se.AUTHENTICATION,"TOKEN_PROVIDER_FAILED",this.formatTokenProviderError(e).message,e),null}return null})();if(await this._ensureWebSocketImpl(),!this.WebSocketImpl)return void this.handleError(Se.WEBSOCKET,"NO_WEBSOCKET_IMPL",this.formatWebSocketError(new Error("No WebSocket implementation available"),{environment:"undefined"!=typeof window?"browser":"node"}).message);if(!t&&!1!==this.options.authRequired)return void this.handleError(Se.AUTHENTICATION,"MISSING_TOKEN","No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.");const s=new URLSearchParams;this.sessionId&&s.set("OptaveTraceChatSessionId",this.sessionId);try{if("subprotocol"===this.options.authTransport){const e=t?["optave-v1",t]:["optave-v1"];this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl,e)}else{if(t){const e=t.replace(/^Bearer\s+/i,"");s.set("Authorization",e)}this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl),t&&this._warnOnce("_warnedQueryToken",'[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".')}}catch(e){return(this.options?.logger?.error||console.error)("[Optave SDK] WebSocket constructor threw",e),void this.handleError(Se.WEBSOCKET,"WEBSOCKET_ERROR",this.formatWebSocketError(e,{url:this.options.websocketUrl}).message,e)}return new Promise((e,t)=>{const s=setTimeout(()=>{const e=this.options.connectionTimeoutMs||3e4,s=this.formatWebSocketError(new Error("Connection timeout"),{timeout:e,url:this.options.websocketUrl}).message;if(this.wss){this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null;try{this.wss.close()}catch(e){}this.wss=null}this.handleError(Se.WEBSOCKET,"CONNECTION_TIMEOUT",s),t({category:Se.WEBSOCKET,code:"CONNECTION_TIMEOUT",message:s,details:null})},this.options.connectionTimeoutMs||3e4);this.wss.onopen=t=>{clearTimeout(s),this.emit("open",t),e(t)},this.wss.onmessage=e=>{this._handleInbound(e.data)},this.wss.onclose=e=>{clearTimeout(s),this.emit("close",e);for(const[t,s]of this._pending.entries())s.timer&&clearTimeout(s.timer),s._handled=!0,s.reject({category:Se.WEBSOCKET,code:"CONNECTION_CLOSED",message:`WebSocket connection closed: ${e.reason||"Connection lost"}`,details:{code:e.code,reason:e.reason,correlationId:t},correlationId:t});this._pending.clear(),this.wss=null},this.wss.onerror=e=>{clearTimeout(s);const r=e.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||"WebSocket connection failed",a={category:Se.WEBSOCKET,code:"CONNECTION_ERROR",message:r,details:{originalError:e}};for(const[e,t]of this._pending.entries())t.timer&&clearTimeout(t.timer),t._handled=!0,t.reject({...a,details:{...a.details,correlationId:e},correlationId:e});this._pending.clear(),this.emit("error",a),t(a)}})}_warnOnce(e,t){this[e]||(this[e]=!0,(this.options?.logger?.warn||console.warn)(t))}deprecate(e,t){this._silenceDeprecations||this._deprecatedKeys.has(e)||(this._deprecatedKeys.add(e),(this.options?.logger?.warn||console.warn)(t))}_handleInbound(e){let t;try{t="string"==typeof e?JSON.parse(e):e}catch(e){const t={category:Se.WEBSOCKET,code:"INVALID_JSON",message:"Invalid JSON received from server",details:e,timestamp:(new Date).toISOString()};return void this._emitError(t)}const s=t&&t.headers&&t.payload,r="error"===t?.state||"error"===t?.actionType||!!t?.error;if(this.options.strictValidation&&s){const e=this._validateMessageEnvelope(t);e.valid||this.handleError(Se.VALIDATION,"INBOUND_ENVELOPE_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Inbound envelope validation failed"),e.errors)}if(r){const e=t?.headers&&t.headers.correlationId||t?.correlationId||null,s={category:Se.ORCHESTRATOR,code:t?.error?.code||"REMOTE_ERROR",message:t?.error?.message||t?.message||"Remote error",details:t?.error||t,correlationId:e};if(e&&this._pending.has(e)){const t=this._pending.get(e);t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),t.reject(s)}return void this._emitError(s,t?.action)}const a=t?.headers?.correlationId||t?.correlationId;if(a&&this._pending.has(a)){const e=this._pending.get(a);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(a),e.resolve(t)}this.emit(we.MESSAGE,t),Ne||(Ne=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".')),this.emit(ke.SUPERPOWER_RESPONSE,t),this.emit(Ie.RESPONSE,t),t?.action&&this.emit(`message.${t.action}`.toLowerCase(),t),s&&t.headers.schemaRef&&this.emit(t.headers.schemaRef,t)}_emitError(e,t=null){e.timestamp||(e.timestamp=(new Date).toISOString()),this.emit(we.ERROR,e),Ue||(Ue=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'));const s=(r=e)&&r.category&&r.code&&r.message?new Ce(r):"string"==typeof r?new Ce({category:"UNKNOWN",code:"STRING_ERROR",message:r}):r&&"AjvValidationError"===r.name?new Ce({category:"VALIDATION",code:"SCHEMA_VALIDATION",message:r.message,details:r.errors}):r&&r.isAuthError?new Ce({category:"AUTHENTICATION",code:r.code||"AUTH_ERROR",message:r.message||"Authentication error",details:r}):r&&r.isWsError?new Ce({category:"WEBSOCKET",code:r.code||"WS_ERROR",message:r.message||"WebSocket error",details:r}):new Ce({category:"UNKNOWN",code:"UNCLASSIFIED",message:r&&r.message||String(null!=r?r:"Unknown error"),details:r});var r;this.emit(ke.SUPERPOWER_ERROR,s),this.emit(Ie.ERROR,e)}closeConnection(){this.wss&&(this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null,this.wss.close(),this.wss=null)}selectiveDeepMerge(e,t){if(Array.isArray(e)&&Array.isArray(t))return[...t];const s=e=>null!==e&&"object"==typeof e&&!Array.isArray(e);if(s(e)&&s(t)){const s={...e};for(let r in t)s[r]=r in e?this.selectiveDeepMerge(e[r],t[r]):t[r];return s}return void 0!==t?t:e}isPayloadSizeValid(e){return!!e&&e.length/1024<=Ee.MAX_PAYLOAD_SIZE_KB}openConnectionAsync(e){return new Promise((t,s)=>{const r=e=>{this.off("error",a),t(e)},a=e=>{this.off("open",r),s(e)};this.once("open",r),this.once("error",a),this.openConnection(e)})}buildPayload(e,t,s){let r=this.selectiveDeepMerge(Me.defaultPayload,s);return s?.request?.variation&&(this.deprecate("payload.request.variation","[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."),r.request.attributes.variant=s.request.variation),s?.request?.content&&!r.request?.attributes?.content&&(r.request.attributes.content=s.request.content,this.deprecate("payload.request.content","[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.")),r.request.attributes.variant&&(r.request.attributes.variant=r.request.attributes.variant.toUpperCase()),r}resolveMessageId(e,t){return`${t}.${e}.v3`.toLowerCase()}buildMessageEnvelope(e,t,s,r={}){const a=(new Date).toISOString(),i=r.correlationId||e?.request?.requestId||S(),p=r.traceId||S(),o=r.idempotencyKey||S(),n=r.timestamp,c={correlationId:i,action:s,schemaRef:Pe,sdkVersion:Le,identifier:t,traceId:p,idempotencyKey:o,timestamp:n,issuedAt:a};return this.options.tenantId&&(c.tenantId=this.options.tenantId),void 0!==r.networkLatencyMs&&(c.networkLatencyMs=r.networkLatencyMs),Object.freeze(c),{action:"message",headers:c,payload:e}}formatValidationErrorMessage(e,t="Validation failed"){if(!e||!Array.isArray(e)||0===e.length)return t;if(1===e.length){const s=e[0],r=s.instancePath||"/",a="/"===r?"root object":r.replace(/^\//,"").replace(/\//g,".");if("required"===s.keyword){const e=s.params?.missingProperty||"unknown field",r="root object"===a?e:a.endsWith(e)?a:a+"."+e;return`${t}: ${"root object"===a?"Required field":"Field"} '${r}' is missing`}if("type"===s.keyword){return`${t}: Field '${a}' must be of type '${s.params?.type||"unknown"}'`}if("additionalProperties"===s.keyword){return`${t}: Field '${a}.${s.params?.additionalProperty||"unknown"}' is not allowed`}if("enum"===s.keyword){const e=s.params?.allowedValues||[];return`${t}: Field '${a}' must be one of: ${Array.isArray(e)?e.join(", "):"unknown values"}`}return`${t}: ${s.message} at '${a}'`}const s=e.filter(e=>"required"===e.keyword),r=e.filter(e=>"type"===e.keyword),a=e.filter(e=>"required"!==e.keyword&&"type"!==e.keyword);let i=t+":";if(s.length>0){i+=` Missing required fields: ${s.map(e=>{const t=(e.instancePath||"/").replace(/^\//,"").replace(/\//g,"."),s=e.params?.missingProperty||"unknown";return""===t?s:`${t}.${s}`}).join(", ")}.`}if(r.length>0){i+=` Type errors in: ${r.slice(0,3).map(e=>`${(e.instancePath||"/").replace(/^\//,"").replace(/\//g,".")||"root"} (expected ${e.params?.type||"unknown"})`).join(", ")}.`,r.length>3&&(i+=` And ${r.length-3} more type errors.`)}return a.length>0&&(i+=` Additional validation errors: ${a.length}.`),i}formatAuthenticationError(e,t,s){let r="Authentication failed";const a=[];return e&&e.status&&(r+=` (HTTP ${e.status})`),t&&("string"==typeof t?r+=`: ${t}`:t.error_description?r+=`: ${t.error_description}`:t.message?r+=`: ${t.message}`:t.error&&(r+=`: ${t.error}`)),e&&401===e.status?(a.push("Verify clientId and clientSecret are correct"),a.push("Ensure credentials match the target environment (dev/staging/production)")):e&&403===e.status?(a.push("Check if your client has the necessary permissions"),a.push("Verify the authentication endpoint URL is correct")):e&&e.status>=500?(a.push("Authentication server error - try again later"),a.push("Contact support if the problem persists")):a.push("Check network connectivity and authentication endpoint configuration"),s&&s.authUrl&&(r+=` (endpoint: ${s.authUrl})`),{message:r,suggestions:a}}formatWebSocketError(e,t){let s="WebSocket connection failed";const r=[],a=e?.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||null;return a&&(s+=`: ${a}`),t&&(t.url&&(s+=` (URL: ${t.url})`),t.timeout&&(s+=` (timeout: ${t.timeout}ms)`)),r.push("Check network connectivity and firewall settings"),r.push("Verify WebSocket URL is correct and accessible"),t&&t.url&&(t.url.startsWith("ws://")&&r.push("Consider using secure WebSocket (wss://) for production"),(t.url.includes("localhost")||t.url.includes("127.0.0.1"))&&r.push("Ensure local server is running if connecting to localhost")),t&&t.timeout&&r.push("Try increasing connection timeout if network is slow"),{message:s,suggestions:r}}formatPayloadSizeError(e,t,s){const r=Math.ceil(e/1024);let a=`Payload too large: ${r}KB exceeds maximum ${t}KB (${r-t}KB over limit)`;const i=[];if(s&&"object"==typeof s){JSON.stringify(s);if(s.request?.scope?.conversations&&Array.isArray(s.request.scope.conversations)){const e=JSON.stringify(s.request.scope.conversations).length,t=Math.ceil(e/1024);t>10&&(i.push(`Consider reducing conversation history - current size: ~${t}KB`),i.push("Remove older messages or summarize conversation context"))}if(s.request?.resources?.offers&&Array.isArray(s.request.resources.offers)){const e=JSON.stringify(s.request.resources.offers).length,t=Math.ceil(e/1024);t>5&&i.push(`Consider reducing product offers data - current size: ~${t}KB`)}if(s.session?.channel?.metadata&&Array.isArray(s.session.channel.metadata)){const e=JSON.stringify(s.session.channel.metadata).length,t=Math.ceil(e/1024);t>2&&i.push(`Consider reducing metadata array - current size: ~${t}KB`)}}return 0===i.length&&(i.push("Remove unused fields from request payload"),i.push("Consider paginating large datasets"),i.push("Use shorter field values where possible")),{message:a,suggestions:i}}formatTokenProviderError(e,t){let s="Failed to obtain WebSocket token from tokenProvider()";const r=[];return e&&(e.message?s+=`: ${e.message}`:"string"==typeof e&&(s+=`: ${e}`),"TypeError"===e.name&&e.message?.includes("fetch")?(r.push("Check if tokenProvider endpoint is accessible"),r.push("Verify CORS settings allow requests to token endpoint")):e.message?.includes("404")||e.message?.includes("Not Found")?(r.push("Verify tokenProvider endpoint URL is correct"),r.push("Ensure backend token endpoint is implemented")):e.message?.includes("401")||e.message?.includes("403")?(r.push("Check authentication/authorization for token endpoint"),r.push("Verify user session or credentials are valid")):e.message?.includes("timeout")&&r.push("Token provider request timed out - check network or server response time")),t&&t.tokenUrl&&(s+=` (endpoint: ${t.tokenUrl})`),0===r.length&&(r.push("Verify tokenProvider function implementation"),r.push("Check backend token endpoint is running and accessible"),r.push("Review browser console for network errors")),{message:s,suggestions:r}}handleError(e,t,s,r=null,a=[],i=null){const p=new Ce({category:e,code:t,message:s,details:r});a&&(p.suggestions=a),i&&(p.correlationId=i),0===this.listenerCount(we.ERROR)&&0===this.listenerCount(Ie.ERROR)&&(this.options?.logger?.error||console.error)(`[Optave SDK] ${t}: ${s}`),this._emitError(p)}send(e,t,s){const r=null!=(this.WebSocketImpl&&this.WebSocketImpl.OPEN)?this.WebSocketImpl.OPEN:1;if(!this.wss||this.wss.readyState!==r){const e=this.wss?this.wss.readyState:"no connection";return void this.handleError(Se.WEBSOCKET,"WEBSOCKET_NOT_IN_OPEN_STATE",this.formatWebSocketError(new Error("WebSocket not ready for sending"),{readyState:e,action:t}).message)}if(!Ae.has(t))return void this.handleError(Se.VALIDATION,"INVALID_ACTION",`Unsupported action '${t}'. Allowed: ${[...Ae].join(", ")}`);const a=new Set(["session","request","headers"]);for(const e of Object.keys(s||{}))if(!a.has(e)){const t=[{instancePath:"",keyword:"additionalProperties",params:{additionalProperty:e},message:`must NOT have additional property '${e}'`}];return void this.handleError(Se.VALIDATION,"PAYLOAD_SCHEMA_MISMATCH",this.formatValidationErrorMessage(t),t)}const i=this.buildPayload(e,t,s||{}),p=this.validateRequiredFields(i||{},t);if(!p.isValid)return void this.handleError(Se.VALIDATION,"REQUIRED_FIELDS_MISSING",`Missing required fields for action '${t}': ${p.errors.join(", ")}`,p.errors);if(this.options.strictValidation){const e=this._validatePayload(i);if(!e.valid)return void this.handleError(Se.VALIDATION,"PAYLOAD_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Schema validation failed"),e.errors)}const o=this.buildMessageEnvelope(i,e,t,s?.headers||{}),n=JSON.stringify(o);if(!this.isPayloadSizeValid(n)){const e=n.length;return void this.handleError(Se.VALIDATION,"PAYLOAD_TOO_LARGE",this.formatPayloadSizeError(e,Ee.MAX_PAYLOAD_SIZE_KB,o).message,Ee.MAX_PAYLOAD_SIZE_KB)}this.wss.send(n)}adjust(e){return this.send("message","adjust",e)}elevate(e){return this.send("message","elevate",e)}interaction(e){return this.send("message","interaction",e)}reception(e){return this.send("message","reception",e)}customerInteraction(e){return this.deprecate("method.customerInteraction","[Deprecation] 'customerInteraction' is deprecated; use 'interaction' instead."),this.send("message","customerInteraction",e)}summarize(e){return this.send("message","summarize",e)}translate(e){return this.send("message","translate",e)}recommend(e){return this.send("message","recommend",e)}insights(e){return this.send("message","insights",e)}_registerPending(e,t,s,r,a){let i=null;s>0&&(i=setTimeout(()=>{if(this._pending.has(e)){const r=this._pending.get(e);r&&!r._handled&&(this._pending.delete(e),r._handled=!0,a({category:Se.WEBSOCKET,code:"REQUEST_TIMEOUT",message:`Request timed out after ${s}ms`,details:{correlationId:e,action:t},correlationId:e}))}},s)),this._pending.set(e,{resolve:r,reject:a,timer:i,action:t,_handled:!1})}_promiseSend(e,t,s={},r={}){let a,i,p;const o=new Promise((o,n)=>{i=o,p=n;const c="number"==typeof r.timeoutMs?r.timeoutMs:"number"==typeof r.timeout?r.timeout:this.options.requestTimeoutMs;if(!this.wss||this.wss.readyState!==WebSocket.OPEN){if(c<=0)return void n({category:Se.WEBSOCKET,code:"WEBSOCKET_NOT_IN_OPEN_STATE",message:"WebSocket not open",details:null});const r=this.buildPayload(e,t,s),i=this.buildMessageEnvelope(r,e,t,s?.headers||{});return a=i.headers.correlationId,void this._registerPending(a,t,c,o,n)}if(!Ae.has(t))return void n({category:Se.VALIDATION,code:"INVALID_ACTION",message:`Unsupported action '${t}'.`,details:{allowed:[...Ae]}});const u=new Set(["session","request","headers"]);for(const e of Object.keys(s||{}))if(!u.has(e)){const t=[{instancePath:"",keyword:"additionalProperties",params:{additionalProperty:e},message:`must NOT have additional property '${e}'`}];return void n({category:Se.VALIDATION,code:"PAYLOAD_SCHEMA_MISMATCH",message:this.formatValidationErrorMessage(t),details:t})}const d=this.buildPayload(e,t,s),m=this.validateRequiredFields(d,t);if(!m.isValid)return void n({category:Se.VALIDATION,code:"REQUIRED_FIELDS_MISSING",message:`Missing required fields for action '${t}'`,details:m.errors});if(this.options.strictValidation){const e=ge(d);if(!e.valid)return void n({category:Se.VALIDATION,code:"PAYLOAD_SCHEMA_MISMATCH",message:this.formatValidationErrorMessage(e.errors,"Schema validation failed"),details:e.errors})}const y=this.buildMessageEnvelope(d,e,t,s?.headers||{});a=y.headers.correlationId,this._registerPending(a,t,c,o,n);const h=JSON.stringify(y);if(!this.isPayloadSizeValid(h)){const e=h.length,t=this.formatPayloadSizeError(e,Ee.MAX_PAYLOAD_SIZE_KB,y).message;return void n({category:Se.VALIDATION,code:"PAYLOAD_TOO_LARGE",message:t,details:{maxKb:Ee.MAX_PAYLOAD_SIZE_KB}})}try{this.wss.send(h)}catch(e){if(this._pending.has(a)){const e=this._pending.get(a);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(a)}n({category:Se.WEBSOCKET,code:"SEND_FAILED",message:"Failed to send over WebSocket",details:e,correlationId:a})}});return o.correlationId=a,o}adjustAsync(e,t){return this._promiseSend("message","adjust",e,t)}elevateAsync(e,t){return this._promiseSend("message","elevate",e,t)}interactionAsync(e,t){return this._promiseSend("message","interaction",e,t)}receptionAsync(e,t){return this._promiseSend("message","reception",e,t)}customerInteractionAsync(e,t){return this.deprecate("method.customerInteractionAsync","[Deprecation] 'customerInteractionAsync' is deprecated; use 'interactionAsync' instead."),this._promiseSend("message","customerInteraction",e,t)}summarizeAsync(e,t){return this._promiseSend("message","summarize",e,t)}translateAsync(e,t){return this._promiseSend("message","translate",e,t)}recommendAsync(e,t){return this._promiseSend("message","recommend",e,t)}insightsAsync(e,t){return this._promiseSend("message","insights",e,t)}cancelRequest(e){if(this._pending.has(e)){const t=this._pending.get(e);return t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),setTimeout(()=>{t.reject({category:Se.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:e},correlationId:e})},0),!0}return!1}cancelPendingRequests(e=!1){if(!this._pending)return 0;const t=this._pending.size,s=[...this._pending.entries()];for(const[t,r]of s)r.timer&&clearTimeout(r.timer),r._handled=!0,e?r.reject({category:Se.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled during cleanup",details:{correlationId:t},correlationId:t}):queueMicrotask(()=>{r.reject({category:Se.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:t},correlationId:t})});return this._pending.clear(),t}cleanup(){if(this.closeConnection(),this.cancelPendingRequests(!0),this._deprecatedKeys&&this._deprecatedKeys.clear(),void 0!==this._warnedQueryToken&&delete this._warnedQueryToken,this._events)for(const e in this._events)delete this._events[e];this.removeAllListeners(),this._events=null,this._eventsCount=null,this._maxListeners=null;this._validatePayload=null,this._validateMessageEnvelope=null,this._emitError=null,this._ensureWebSocketImpl=null,this._handleInbound=null,this._promiseSend=null,this._registerPending=null,this._warnOnce=null,this.options=null,this.WebSocketImpl=null,this.wss=null,this.sessionId=null,this._pending=null,this._deprecatedKeys=null,this._silenceDeprecations=null,this._events=null,this._eventsCount=null,this._maxListeners=null}removeAllListeners(t){try{e.prototype.removeAllListeners.call(this,t)}catch(e){t?this._events&&this._events[t]&&(delete this._events[t],this._eventsCount=Math.max(0,this._eventsCount-1)):(this._events=Object.create(null),this._eventsCount=0)}return this}static get buildFlags(){const e="server-esm";return{SALESFORCE_BUILD:"undefined"!=typeof __SALESFORCE_BUILD__&&__SALESFORCE_BUILD__,INCLUDE_WS_REQUIRE:!0,SDK_VERSION:"3.2.3",WEBPACK_BUILD_TARGET:e,WEBPACK_BUILD_TARGET_NORMALIZED:Te.normalize(e),BUILD_TARGET_INFO:Te.getInfo(e)}}}const We=Me;export{We as default};
\ No newline at end of file
+import{default as e}from"events";import{createHash as t}from"node:crypto";import{default as s}from"ws";const r=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;const a=function(e){return"string"==typeof e&&r.test(e)};const i=function(e){if(!a(e))throw TypeError("Invalid UUID");let t;return Uint8Array.of((t=parseInt(e.slice(0,8),16))>>>24,t>>>16&255,t>>>8&255,255&t,(t=parseInt(e.slice(9,13),16))>>>8,255&t,(t=parseInt(e.slice(14,18),16))>>>8,255&t,(t=parseInt(e.slice(19,23),16))>>>8,255&t,(t=parseInt(e.slice(24,36),16))/1099511627776&255,t/4294967296&255,t>>>24&255,t>>>16&255,t>>>8&255,255&t)};const o=[];for(let e=0;e<256;++e)o.push((e+256).toString(16).slice(1));function p(e,t=0){return(o[e[t+0]]+o[e[t+1]]+o[e[t+2]]+o[e[t+3]]+"-"+o[e[t+4]]+o[e[t+5]]+"-"+o[e[t+6]]+o[e[t+7]]+"-"+o[e[t+8]]+o[e[t+9]]+"-"+o[e[t+10]]+o[e[t+11]]+o[e[t+12]]+o[e[t+13]]+o[e[t+14]]+o[e[t+15]]).toLowerCase()}const n=new Uint8Array(16);function c(){return crypto.getRandomValues(n)}const d=function(e){return Array.isArray(e)?e=Buffer.from(e):"string"==typeof e&&(e=Buffer.from(e,"utf8")),t("md5").update(e).digest()};const u="6ba7b810-9dad-11d1-80b4-00c04fd430c8",y="6ba7b811-9dad-11d1-80b4-00c04fd430c8";function m(e,t,s,r,a,o){const n="string"==typeof s?function(e){e=unescape(encodeURIComponent(e));const t=new Uint8Array(e.length);for(let s=0;sa.length)throw new RangeError(`UUID byte range ${o}:${o+15} is out of buffer bounds`);for(let e=0;e<16;++e)a[o+e]=d[e];return a}return p(d)}function l(e,t,s,r){return m(48,d,e,t,s,r)}l.DNS=u,l.URL=y;const h=function(e){return Array.isArray(e)?e=Buffer.from(e):"string"==typeof e&&(e=Buffer.from(e,"utf8")),t("sha1").update(e).digest()};function g(e,t,s,r){return m(80,h,e,t,s,r)}g.DNS=u,g.URL=y;const f={};function b(e,t,s,r,a=0){if(e.length<16)throw new Error("Random bytes length must be >= 16");if(r){if(a<0||a+16>r.length)throw new RangeError(`UUID byte range ${a}:${a+15} is out of buffer bounds`)}else r=new Uint8Array(16),a=0;return t??=Date.now(),s??=v(e),r[a++]=t/1099511627776&255,r[a++]=t/4294967296&255,r[a++]=t/16777216&255,r[a++]=t/65536&255,r[a++]=t/256&255,r[a++]=255&t,r[a++]=112|s>>>28&15,r[a++]=s>>>20&255,r[a++]=128|s>>>14&63,r[a++]=s>>>6&255,r[a++]=s<<2&255|3&e[10],r[a++]=e[11],r[a++]=e[12],r[a++]=e[13],r[a++]=e[14],r[a++]=e[15],r}function v(e){return(127&e[6])<<24|e[7]<<16|e[8]<<8|e[9]}const q=function(e,t,s){let r;if(e)r=b(e.random??e.rng?.()??c(),e.msecs,e.seq,t,s);else{const e=Date.now(),a=c();!function(e,t,s){e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=v(s),e.msecs=t):(e.seq=e.seq+1|0,0===e.seq&&e.msecs++)}(f,e,a),r=b(a,f.msecs,f.seq,t,s)}return t??p(r)};const P={type:"object",required:["action","headers","payload"],properties:{action:{type:"string",enum:["message"],description:"Action type for the envelope"},headers:{type:"object",required:["correlationId","action","schemaRef"],properties:{correlationId:{type:"string",format:"uuidv7",description:"UUID for correlating request-response pairs (always generated client-side unless overridden)"},tenantId:{type:"string",description:"Tenant identifier provided by Optave"},traceId:{type:"string",format:"uuidv7",description:"Optional cross-system tracing ID (forwarded if provided)"},idempotencyKey:{type:"string",format:"uuidv7",description:"Optional idempotency key; forwarded unchanged if provided"},identifier:{type:"string",enum:["message"],description:"Message identifier"},action:{type:"string",enum:["adjust","elevate","customerinteraction","interaction","assistant","reception","summarize","translate","recommend","insights"],description:"Specific action being performed"},schemaRef:{type:"string",pattern:"^optave\\.message\\.v\\d+$",description:"Schema reference for the envelope (major version only; minor/patch changes are non-breaking). Format is derived from protocol version."},sdkVersion:{type:"string",description:"SDK package version (independent of schemaRef major)"},networkLatencyMs:{type:"number",description:"Optional client-measured round-trip latency (not sent unless explicitly supplied)"},timestamp:{type:"string",format:"date-time",description:"ISO 8601 client timestamp when the message was built"},issuedAt:{type:"string",format:"date-time",description:"Message issued timestamp"}}},payload:{$ref:"Payload"}},allOf:[{type:"object",required:["action","headers","payload"],properties:{action:{type:"string",enum:["message"]},headers:{type:"object"},payload:{type:"object"}}},{if:{properties:{headers:{properties:{action:{enum:["adjust","elevate","interaction","assistant","customerInteraction"]}}}}},then:{properties:{payload:{$ref:"PayloadWithRequiredConversations"}}}},{if:{properties:{headers:{properties:{action:{enum:["summarize","translate","insights","recommend"]}}}}},then:{properties:{payload:{$ref:"PayloadWithRequiredConversations"}}}}]},S={allOf:[{$ref:"Payload"},{type:"object",required:["request"],properties:{request:{type:"object",required:["scope"],properties:{scope:{type:"object",required:["conversations"],properties:{conversations:{type:"array",minItems:1,items:{$ref:"Conversation"}}}}}}}}]},w={type:"object",required:["session","request"],properties:{session:{$ref:"Session"},request:{type:"object",required:["requestId"],properties:{requestId:{type:"string",description:"Unique request identifier"},attributes:{$ref:"RequestAttributes"},connections:{$ref:"Connections"},context:{$ref:"Context"},reference:{type:"object",description:"Client-custom labels ONLY (ids/labels/tags). Never the carrier of typed analytics facts (conversation identity, user grain, geography, A/B variant). MUST NOT carry direct identifiers — names, emails, message content. The analytics raw store is append-only under Object Lock.",properties:{ids:{type:"array",items:{$ref:"ReferenceId"},description:"Client-custom identifier pairs. Not typed analytics dimensions."},labels:{type:"array",description:"Client-custom labels. MUST NOT carry names, emails, or message content."},tags:{type:"array",description:"Client-custom tags. MUST NOT carry names, emails, or message content."}}},resources:{type:"object",properties:{codes:{type:"array",items:{$ref:"CodesItem"}},links:{type:"array",items:{$ref:"LinkItem"}},offers:{type:"array",description:"Offering details (previously offering_details in v2)"}}},scope:{type:"object",properties:{accounts:{type:"array"},appointments:{type:"array"},assets:{type:"array"},bookings:{type:"array"},cases:{type:"array"},conversations:{type:"array",items:{$ref:"Conversation"}},documents:{type:"array"},events:{type:"array"},interactions:{type:"array",items:{$ref:"Interaction"}},items:{type:"array"},locations:{type:"array"},offers:{type:"array"},operators:{type:"array"},orders:{type:"array"},organizations:{type:"array"},persons:{type:"array"},policies:{type:"array"},products:{type:"array",items:{$ref:"Product"}},properties:{type:"array"},services:{type:"array"},subscriptions:{type:"array"},tickets:{type:"array"},transactions:{type:"array"},users:{type:"array"}}},settings:{type:"object",description:"Feature-usage flags. Feeds analytics reasoning-engagement.",properties:{disableBrowsing:{type:"boolean",default:!1},disableSearch:{type:"boolean",default:!1},disableSources:{type:"boolean",default:!1},disableStream:{type:"boolean",default:!0},disableTools:{type:"boolean",default:!1},maxResponseLength:{type:"number",default:0},overrideInterfaceLanguage:{type:"string",description:"Override interface language"},overrideOutputLanguage:{type:"string",description:"Override output language (replaces channel language)"}}},a2a:{type:"array",items:{$ref:"A2AConfiguration"},description:"Agent-to-agent configuration (advanced mode). Feeds analytics human-vs-bot / operator-bot attribution."},cursor:{$ref:"Cursor"}}}}},I={type:"object",properties:{content:{type:"string",description:"Content to be processed"},instruction:{type:"string",description:"Specific instruction for the action"},variant:{type:"string",description:'A/B variant identifier (e.g., "A", "B"). Feeds analytics experiment slices.'},replyTo:{type:"string",description:'Reply attribution classified in the UI at compose time. Closed enum for analytics dimension reply_target. Who the user is replying to: an AI/operator message, their own earlier message, or not a reply. Never a message id, never message content. Absent means not reported; "none" means this message is not a reply. Canonical field; connections.replyTarget remains a deprecated 3.5.0 compatibility alias with the same enum.\n',enum:["ai","self","none"]}}},k={type:"object",properties:{journeyId:{type:"string",description:"Cross-conversation journey identity. Feeds analytics returning-user analysis."},parentId:{type:"string",description:"Parent request ID (previously trace_parent_ID in v2). Request lineage for adjust/elevate refine-chain — not a frozen reply-edge."},replyTarget:{type:"string",description:"Deprecated 3.5.0 compatibility alias for attributes.replyTo. Same closed enum (ai / self / none). New producers must send attributes.replyTo. Kept so 3.5.0 typed payloads continue to type-check inside this major version.\n",enum:["ai","self","none"]},replyId:{type:"string",description:"Opaque identifier of the message being replied to. Same treatment as parentId / threadId — a string id, never message content. Producers MUST hash if the source is a raw message id. Absent or empty means not reported (this message may still be a reply whose target id is unknown).\n"},threadId:{type:"string",description:"Conversation identity — unique across all requests related to the same ticket/case/conversation. Feeds analytics conversations, turns, messages, and outcome joins."}}},A={type:"object",properties:{caseId:{type:"string",description:"Case/ticket linkage (advanced mode). Feeds analytics resolution/escalation joins."},departmentId:{type:"string",description:"Department identifier (advanced mode). Feeds analytics ops slices together with operatorId."},operatorId:{type:"string",description:"Operator identifier (advanced mode). Feeds analytics ops slices together with departmentId."},organizationId:{type:"string",description:"Organization grouping. Feeds analytics org dimension."},userId:{type:"string",description:"Pseudonymous user grain (advanced mode). Analytics consumers MUST hash this value; never a raw IdP subject. Feeds MAU, returning, retention, and queries-per-user."}}},E={type:"object",description:"Client-custom identifier pair. Never a typed analytics fact (thread, user, geography, variant). MUST NOT carry direct identifiers (names, emails, message content).",properties:{name:{type:"string",description:'Client-custom identifier name (e.g., "ticket_id"). Not a typed analytics dimension.'},value:{type:"string",description:"Client-custom identifier value. MUST NOT be a name, email, or message content."}}},T={type:"object",properties:{id:{type:"string",description:"Optional for tracking/mapping"},label:{type:"string",description:'Optional, helps for display/templating (e.g., "Order Number")'},type:{type:"string",description:'Code type (e.g., "order_number", "booking_reference", "ticket_code")'},value:{type:"string",description:'Code value (e.g., "ORD-56789")'}}},O={type:"object",properties:{expires_at:{type:"string",description:"Optional expiration timestamp"},html:{type:"boolean",description:"Optional HTML flag"},id:{type:"string",description:"Optional link identifier"},label:{type:"string",description:'Optional label (e.g., "Click here to pay")'},type:{type:"string",description:'Link type (e.g., "payment_link")'},url:{type:"string",description:'URL (e.g., "https://checkout.stripe.com/pay/cs_test...")'}}},j={type:"object",properties:{content:{type:"string"},id:{type:"string"},name:{type:"string"},role:{type:"string"},timestamp:{type:"string"}}},_={type:"object",properties:{id:{type:"string"}}},C={type:"object",properties:{id:{type:"string"},name:{type:"string"},type:{type:"string",description:'Actor type (e.g., "chatbot", "operator"). Feeds analytics operator/bot dimension.'}},description:"Advanced mode agent-to-agent configuration. Feeds analytics human-vs-bot attribution."},R={type:"object",properties:{since:{type:"string",description:'Start timestamp (e.g., "2024-01-15T10:30:00.000Z")'},until:{type:"string",description:'End timestamp (e.g., "2024-01-15T11:00:00.000Z")'}}},N={type:"object",description:"Session tracking block. Feeds analytics session length/bands and peak concurrency via sessionId.",properties:{sessionId:{type:"string",description:"Session identity lasting for the duration of a chat session or call. Feeds analytics session length/bands and peak concurrency."},channel:{$ref:"Channel"},interface:{$ref:"Interface"}}},L={type:"object",description:"Capture-time channel context. Typed fields feed analytics dimensions; metadata is free-form and must not carry direct identifiers.",properties:{browser:{type:"string",description:"Browser information. Feeds analytics device/mobile-share slices together with deviceType and deviceInfo."},deviceInfo:{type:"string",description:'Device information (e.g., "iOS/18.2, iPhone15,3"). Feeds analytics device slices together with deviceType and browser.'},deviceType:{type:"string",description:"Device class. Analytics dimension values (no mapping layer): mobile, desktop, tablet. Additive-only within a major version; omit when unknown. Empty/omitted is treated as unknown and is not an analytics value."},language:{type:"string",description:"Conversation/interface language. Feeds analytics fr-share, fr-parity, and lang-switch."},location:{type:"string",description:'Geography at province grain at most (ISO 3166-2, e.g. "US-NY", "CA-ON"), never precise coordinates. Country-only values (e.g. "US") are valid. Consent-gated. Feeds analytics province-concentration and intl-share.'},medium:{type:"string",enum:["chat","voice","email"],description:"Communication medium. Analytics dimension values (no mapping layer): chat, voice, email. Default is chat if omitted. Additive-only within a major version."},metadata:{type:"array",description:"Custom metadata array. Free-form; MUST NOT carry direct identifiers (names, emails, message content). The analytics raw store is append-only under Object Lock — a leaked identifier cannot be simply deleted."},section:{type:"string",description:'In-product context (e.g., "cart", "product_page"). Feeds analytics engagement analysis.'}}},D={type:"object",properties:{appVersion:{type:"string",description:"Emitter/application version. Used as analytics provenance corroboration, not a dashboard slice of its own."},category:{type:"string",description:'Interface category / surface class (e.g., "crm", "app", "auto", "widget"). Feeds analytics per-surface slices together with name.'},language:{type:"string",description:"Language from the CRM agent"},name:{type:"string",description:'Interface/surface name (e.g., "salesforce", "zendesk", "widget", "app"). Feeds analytics per-surface slices together with category.'},type:{type:"string",description:'Interface type (e.g., "custom_components", "marketplace", "channel")'}}};function U(e,{instancePath:t="",parentData:s,parentDataProperty:r,rootData:a=e}={}){let i=null,o=0;if(e&&"object"==typeof e&&!Array.isArray(e)){if(void 0!==e.sessionId){let s=e.sessionId;if("string"!=typeof s){const e={instancePath:t+"/sessionId",schemaPath:"#/properties/sessionId/type",keyword:"type",params:{type:"string"},message:"must be string",schema:N.properties.sessionId.type,parentSchema:N.properties.sessionId,data:s};null===i?i=[e]:i.push(e),o++}}if(void 0!==e.channel){let s=e.channel;if(s&&"object"==typeof s&&!Array.isArray(s)){if(void 0!==s.browser){let e=s.browser;if("string"!=typeof e){const s={instancePath:t+"/channel/browser",schemaPath:"Channel/properties/browser/type",keyword:"type",params:{type:"string"},message:"must be string",schema:L.properties.browser.type,parentSchema:L.properties.browser,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.deviceInfo){let e=s.deviceInfo;if("string"!=typeof e){const s={instancePath:t+"/channel/deviceInfo",schemaPath:"Channel/properties/deviceInfo/type",keyword:"type",params:{type:"string"},message:"must be string",schema:L.properties.deviceInfo.type,parentSchema:L.properties.deviceInfo,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.deviceType){let e=s.deviceType;if("string"!=typeof e){const s={instancePath:t+"/channel/deviceType",schemaPath:"Channel/properties/deviceType/type",keyword:"type",params:{type:"string"},message:"must be string",schema:L.properties.deviceType.type,parentSchema:L.properties.deviceType,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.language){let e=s.language;if("string"!=typeof e){const s={instancePath:t+"/channel/language",schemaPath:"Channel/properties/language/type",keyword:"type",params:{type:"string"},message:"must be string",schema:L.properties.language.type,parentSchema:L.properties.language,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.location){let e=s.location;if("string"!=typeof e){const s={instancePath:t+"/channel/location",schemaPath:"Channel/properties/location/type",keyword:"type",params:{type:"string"},message:"must be string",schema:L.properties.location.type,parentSchema:L.properties.location,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.medium){let e=s.medium;if("string"!=typeof e){const s={instancePath:t+"/channel/medium",schemaPath:"Channel/properties/medium/type",keyword:"type",params:{type:"string"},message:"must be string",schema:L.properties.medium.type,parentSchema:L.properties.medium,data:e};null===i?i=[s]:i.push(s),o++}if("chat"!==e&&"voice"!==e&&"email"!==e){const s={instancePath:t+"/channel/medium",schemaPath:"Channel/properties/medium/enum",keyword:"enum",params:{allowedValues:L.properties.medium.enum},message:"must be equal to one of the allowed values",schema:L.properties.medium.enum,parentSchema:L.properties.medium,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.metadata){let e=s.metadata;if(!Array.isArray(e)){const s={instancePath:t+"/channel/metadata",schemaPath:"Channel/properties/metadata/type",keyword:"type",params:{type:"array"},message:"must be array",schema:L.properties.metadata.type,parentSchema:L.properties.metadata,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.section){let e=s.section;if("string"!=typeof e){const s={instancePath:t+"/channel/section",schemaPath:"Channel/properties/section/type",keyword:"type",params:{type:"string"},message:"must be string",schema:L.properties.section.type,parentSchema:L.properties.section,data:e};null===i?i=[s]:i.push(s),o++}}}else{const e={instancePath:t+"/channel",schemaPath:"Channel/type",keyword:"type",params:{type:"object"},message:"must be object",schema:L.type,parentSchema:L,data:s};null===i?i=[e]:i.push(e),o++}}if(void 0!==e.interface){let s=e.interface;if(s&&"object"==typeof s&&!Array.isArray(s)){if(void 0!==s.appVersion){let e=s.appVersion;if("string"!=typeof e){const s={instancePath:t+"/interface/appVersion",schemaPath:"Interface/properties/appVersion/type",keyword:"type",params:{type:"string"},message:"must be string",schema:D.properties.appVersion.type,parentSchema:D.properties.appVersion,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.category){let e=s.category;if("string"!=typeof e){const s={instancePath:t+"/interface/category",schemaPath:"Interface/properties/category/type",keyword:"type",params:{type:"string"},message:"must be string",schema:D.properties.category.type,parentSchema:D.properties.category,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.language){let e=s.language;if("string"!=typeof e){const s={instancePath:t+"/interface/language",schemaPath:"Interface/properties/language/type",keyword:"type",params:{type:"string"},message:"must be string",schema:D.properties.language.type,parentSchema:D.properties.language,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.name){let e=s.name;if("string"!=typeof e){const s={instancePath:t+"/interface/name",schemaPath:"Interface/properties/name/type",keyword:"type",params:{type:"string"},message:"must be string",schema:D.properties.name.type,parentSchema:D.properties.name,data:e};null===i?i=[s]:i.push(s),o++}}if(void 0!==s.type){let e=s.type;if("string"!=typeof e){const s={instancePath:t+"/interface/type",schemaPath:"Interface/properties/type/type",keyword:"type",params:{type:"string"},message:"must be string",schema:D.properties.type.type,parentSchema:D.properties.type,data:e};null===i?i=[s]:i.push(s),o++}}}else{const e={instancePath:t+"/interface",schemaPath:"Interface/type",keyword:"type",params:{type:"object"},message:"must be object",schema:D.type,parentSchema:D,data:s};null===i?i=[e]:i.push(e),o++}}}else{const s={instancePath:t,schemaPath:"#/type",keyword:"type",params:{type:"object"},message:"must be object",schema:N.type,parentSchema:N,data:e};null===i?i=[s]:i.push(s),o++}return U.errors=i,0===o}const M={type:"object",properties:{conversationId:{type:"string"},participants:{type:"array",items:{$ref:"Participant"}},messages:{type:"array",items:{$ref:"Message"}},metadata:{type:"object"}}},$={type:"object",properties:{participantId:{type:"string"},displayName:{type:"string"},role:{type:"string",enum:["operator","user","bot","assistant","agent"]}}},W={type:"object",properties:{content:{type:"string"},participantId:{type:"string"},timestamp:{type:"string"}}};function V(e,{instancePath:t="",parentData:s,parentDataProperty:r,rootData:a=e}={}){let i=null,o=0;if(e&&"object"==typeof e&&!Array.isArray(e)){if(void 0!==e.conversationId){let s=e.conversationId;if("string"!=typeof s){const e={instancePath:t+"/conversationId",schemaPath:"#/properties/conversationId/type",keyword:"type",params:{type:"string"},message:"must be string",schema:M.properties.conversationId.type,parentSchema:M.properties.conversationId,data:s};null===i?i=[e]:i.push(e),o++}}if(void 0!==e.participants){let s=e.participants;if(Array.isArray(s)){const e=s.length;for(let r=0;r({valid:H(e),errors:H.errors||null}),he=e=>({valid:me(e),errors:me.errors||null});function ge(e,t,s="validation",r={}){return{instancePath:e,message:t,keyword:s,params:r}}function fe(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[ge("","must be object","type",{type:"object"})]};const t=[];if(e.session?"object"!=typeof e.session?t.push(ge("/session","must be object","type",{type:"object"})):void 0!==e.session.sessionId&&"string"!=typeof e.session.sessionId&&t.push(ge("/session/sessionId","must be string","type",{type:"string"})):t.push(ge("/session","is required","required",{missingProperty:"session"})),e.request)if("object"!=typeof e.request)t.push(ge("/request","must be object","type",{type:"object"}));else{if(e.request.connections)if("object"!=typeof e.request.connections)t.push(ge("/request/connections","must be object","type",{type:"object"}));else{e.request.connections.threadId?"string"!=typeof e.request.connections.threadId&&t.push(ge("/request/connections/threadId","must be string","type",{type:"string"})):t.push(ge("/request/connections/threadId","is required","required",{missingProperty:"threadId"})),void 0!==e.request.connections.parentId&&"string"!=typeof e.request.connections.parentId&&t.push(ge("/request/connections/parentId","must be string","type",{type:"string"})),void 0!==e.request.connections.replyId&&"string"!=typeof e.request.connections.replyId&&t.push(ge("/request/connections/replyId","must be string","type",{type:"string"}));const{replyTarget:s}=e.request.connections;if(void 0!==s){const e=["ai","self","none"];"string"!=typeof s?t.push(ge("/request/connections/replyTarget","must be string","type",{type:"string"})):e.includes(s)||t.push(ge("/request/connections/replyTarget","must be equal to one of the allowed values","enum",{allowedValues:e}))}}else t.push(ge("/request/connections","is required","required",{missingProperty:"connections"}));if(void 0!==e.request.context&&"object"!=typeof e.request.context&&t.push(ge("/request/context","must be object","type",{type:"object"})),void 0!==e.request.attributes&&"object"!=typeof e.request.attributes)t.push(ge("/request/attributes","must be object","type",{type:"object"}));else if(e.request.attributes&&"object"==typeof e.request.attributes){const{replyTo:s}=e.request.attributes;if(void 0!==s){const e=["ai","self","none"];"string"!=typeof s?t.push(ge("/request/attributes/replyTo","must be string","type",{type:"string"})):e.includes(s)||t.push(ge("/request/attributes/replyTo","must be equal to one of the allowed values","enum",{allowedValues:e}))}}void 0!==e.request.scope&&("object"!=typeof e.request.scope?t.push(ge("/request/scope","must be object","type",{type:"object"})):void 0!==e.request.scope.conversations&&(Array.isArray(e.request.scope.conversations)||t.push(ge("/request/scope/conversations","must be array","type",{type:"array"})))),void 0!==e.request.resources&&("object"!=typeof e.request.resources?t.push(ge("/request/resources","must be object","type",{type:"object"})):void 0!==e.request.resources.offers&&(Array.isArray(e.request.resources.offers)||t.push(ge("/request/resources/offers","must be array","type",{type:"array"}))))}else t.push(ge("/request","is required","required",{missingProperty:"request"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function be(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[ge("","must be object","type",{type:"object"})]};const t=[];if(e.headers)if("object"!=typeof e.headers)t.push(ge("/headers","must be object","type",{type:"object"}));else{if(e.headers.correlationId?"string"!=typeof e.headers.correlationId&&t.push(ge("/headers/correlationId","must be string","type",{type:"string"})):t.push(ge("/headers/correlationId","is required","required",{missingProperty:"correlationId"})),e.headers.action)if("string"!=typeof e.headers.action)t.push(ge("/headers/action","must be string","type",{type:"string"}));else{const s=["adjust","elevate","interaction","assistant","customerinteraction","reception","summarize","translate","recommend","insights"];s.includes(e.headers.action)||t.push(ge("/headers/action","must be equal to one of the allowed values","enum",{allowedValues:s}))}else t.push(ge("/headers/action","is required","required",{missingProperty:"action"}));void 0!==e.headers.identifier&&"string"!=typeof e.headers.identifier&&t.push(ge("/headers/identifier","must be string","type",{type:"string"})),void 0!==e.headers.schemaRef&&"string"!=typeof e.headers.schemaRef&&t.push(ge("/headers/schemaRef","must be string","type",{type:"string"})),void 0!==e.headers.timestamp&&"string"!=typeof e.headers.timestamp&&t.push(ge("/headers/timestamp","must be string","type",{type:"string"}))}else t.push(ge("/headers","is required","required",{missingProperty:"headers"}));if(e.payload){if("object"!=typeof e.payload)t.push(ge("/payload","must be object","type",{type:"object"}));else if(e.headers&&e.headers.action&&e.payload){const{action:s}=e.headers;["adjust","elevate","interaction","assistant","customerinteraction","customerInteraction","summarize","translate","insights","recommend"].includes(s)&&(e.payload.request?e.payload.request.scope?e.payload.request.scope.conversations?Array.isArray(e.payload.request.scope.conversations)?0===e.payload.request.scope.conversations.length&&t.push(ge("/payload/request/scope/conversations",`must be non-empty array for ${s}`,"minItems",{limit:1})):t.push(ge("/payload/request/scope/conversations","must be array","type",{type:"array"})):t.push(ge("/payload/request/scope/conversations",`is required for ${s}`,"required",{missingProperty:"conversations"})):t.push(ge("/payload/request/scope","is required","required",{missingProperty:"scope"})):t.push(ge("/payload/request","is required","required",{missingProperty:"request"})))}}else t.push(ge("/payload","is required","required",{missingProperty:"payload"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}const ve=`optave.message.v${"1.0.0".split(".")[0]}`,qe={AUTHENTICATION:"AUTHENTICATION",ORCHESTRATOR:"ORCHESTRATOR",VALIDATION:"VALIDATION",WEBSOCKET:"WEBSOCKET"},Pe=Object.freeze({MESSAGE:"message",ERROR:"error"}),Se=Object.freeze({CONNECTION_OPEN:"connection:open",CONNECTION_CLOSE:"connection:close",CONNECTION_ERROR:"connection:error",MESSAGE_RECEIVED:"message:received",MESSAGE_SENT:"message:sent",ERROR:"error",RESPONSE:"response",LEGACY_ERROR:"error",LEGACY_MESSAGE:"message"}),we=Object.freeze({SUPERPOWER_RESPONSE:"superpower.response",SUPERPOWER_ERROR:"superpower.error"}),Ie=new Set(["adjust","elevate","interaction","assistant","reception","customerInteraction","summarize","translate","recommend","insights"]),ke={SPEC_VERSION:"1.0.0",SCHEMA_REF:ve,MAX_PAYLOAD_SIZE:131072,MAX_PAYLOAD_SIZE_KB:128,DEFAULT_REQUEST_TIMEOUT_MS:3e4,ErrorCategory:qe,LegacyEvents:Pe,EVENTS:Se,InboundEvents:we,ALLOWED_ACTIONS:Ie};function Ae(e){const t=[];if((()=>{if("undefined"!=typeof process&&process.versions&&process.versions.node&&("true"===process.env.VITEST||void 0!==process.env.JEST_WORKER_ID||process.argv.some(e=>e.includes("vitest")||e.includes("jest")||e.includes("test"))))return!(!("undefined"!=typeof globalThis&&"window"in globalThis&&globalThis.window&&"document"in globalThis&&globalThis.document)||process.env.OPTAVE_SDK_FORCE_SERVER_ENV);if("undefined"!=typeof globalThis){if(!("window"in globalThis)&&!("document"in globalThis)&&"undefined"!=typeof process&&process.versions&&process.versions.node)return!1;if((!("window"in globalThis)||!("document"in globalThis))&&"undefined"!=typeof process&&process.versions&&process.versions.node)return!1;if("window"in globalThis&&globalThis.window)return!0;if("document"in globalThis&&globalThis.document)return!0}try{if("undefined"!=typeof window&&null!==window)return!("undefined"!=typeof globalThis&&!("window"in globalThis)||"undefined"!=typeof globalThis&&"undefined"!=typeof process&&process.versions&&process.versions.node&&!("window"in globalThis));if("undefined"!=typeof document&&null!==document)return!("undefined"!=typeof globalThis&&!("document"in globalThis)||"undefined"!=typeof globalThis&&"undefined"!=typeof process&&process.versions&&process.versions.node&&!("document"in globalThis))}catch(e){}return"undefined"!=typeof navigator&&"ReactNative"===navigator.product||!("undefined"==typeof globalThis||!globalThis.__expo)||void 0!==globalThis.location&&null!==globalThis.location||("undefined"!=typeof process&&process.versions&&process.versions.node,!1)})()&&e.clientSecret){let e=!1,s=!1;try{e=!0===__SALESFORCE_BUILD__}catch(e){}try{s=!0}catch(e){}e||s||t.push({type:"error",code:"CLIENT_SECRET_IN_CLIENT_ENV",message:"clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.",field:"clientSecret"})}return t}const Ee=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i,Te=/^\s*-?\d{1,3}(?:\.\d+)?\s*,\s*-?\d{1,3}(?:\.\d+)?\s*$/,Oe=new Set(["email","e-mail","fullname","firstname","lastname","displayname","phone","phonenumber","ssn","dateofbirth","dob","nationalid"]);function je(e,t,s={}){return{instancePath:e,message:t,keyword:"piGuard",params:s}}function _e(e,t,s){null!=e&&("string"!=typeof e?Array.isArray(e)?e.forEach((e,r)=>_e(e,`${t}/${r}`,s)):"object"==typeof e&&Object.entries(e).forEach(([e,r])=>{Oe.has(e.toLowerCase())&&s.push(je(`${t}/${e}`,`must not carry direct identifier key '${e}'`,{kind:"identifierKey",key:e})),_e(r,`${t}/${e}`,s)}):function(e,t,s){"string"==typeof e&&0!==e.length&&(Ee.test(e)&&s.push(je(t,"must not contain an email address",{kind:"email"})),Te.test(e)&&s.push(je(t,"must not contain precise coordinates",{kind:"coordinates"})),function(e){if("string"!=typeof e)return!1;const t=e.trim();return!!(t.includes("\n")&&t.length>40)||!!(t.length>160&&/\s/.test(t)&&/[.!?]/.test(t))}(e)&&s.push(je(t,"must not contain message content or other direct identifiers",{kind:"messageContent"})))}(e,t,s))}function Ce(e){if(!e||"object"!=typeof e)return{valid:!0,errors:null};const t=[],s=e.session?.channel?.location;return"string"==typeof s&&s&&Te.test(s)&&t.push(je("/session/channel/location","must be province grain at most, never precise coordinates",{kind:"coordinates"})),void 0!==e.session?.channel?.metadata&&_e(e.session.channel.metadata,"/session/channel/metadata",t),void 0!==e.request?.reference&&_e(e.request.reference,"/request/reference",t),t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function Re(e){return t=>{const s=e(t);return s.valid?Ce(t):s}}const Ne={BROWSER_ESM:"browser-esm",SERVER_ESM:"server-esm",BROWSER_UMD:"browser-umd",SERVER_UMD:"server-umd"},Le={browser:Ne.BROWSER_ESM,server:Ne.SERVER_ESM},De={BROWSER:[Ne.BROWSER_ESM,Ne.BROWSER_UMD],SERVER:[Ne.SERVER_ESM,Ne.SERVER_UMD],UMD:[Ne.BROWSER_UMD,Ne.SERVER_UMD],ESM:[Ne.BROWSER_ESM,Ne.SERVER_ESM]},Ue={isValid:e=>Object.values(Ne).includes(e)||Object.keys(Le).includes(e),normalize:e=>Le[e]?Le[e]:Object.values(Ne).includes(e)?e:"unknown",isBrowser(e){const t=this.normalize(e);return De.BROWSER.includes(t)},isServer(e){const t=this.normalize(e);return De.SERVER.includes(t)},isUMD(e){const t=this.normalize(e);return De.UMD.includes(t)},isESM(e){const t=this.normalize(e);return De.ESM.includes(t)},getInfo(e){return{original:e,normalized:this.normalize(e),valid:this.isValid(e),isBrowser:this.isBrowser(e),isServer:this.isServer(e),isUMD:this.isUMD(e),isESM:this.isESM(e)}}};class Me extends Error{constructor({category:e,code:t,message:s,details:r}){super(s),this.name="OptaveError",this.category=e||"UNKNOWN",this.code=t||"UNKNOWN",void 0!==r&&(this.details=r)}}!function(){if("undefined"!=typeof globalThis){globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__=!0;if(!globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__)throw new Error("Security guard initialization failed")}}(),"undefined"!=typeof window?window.__OPTAVE_SECURITY_GUARDS_BROWSER__=!0:"undefined"!=typeof globalThis&&(globalThis.__OPTAVE_SECURITY_GUARDS_NODE__=!0);const $e="3.6.0",We=()=>{const e="server-esm";return{isBrowser:Ue.isBrowser(e),isServer:Ue.isServer(e),buildTarget:e}};let Ve=!1,Be=!1;class xe extends e{options={};wss=null;static defaultPayload={session:{sessionId:"",channel:{browser:"",deviceInfo:"",deviceType:"",language:"",location:"",medium:"chat",metadata:[],section:""},interface:{appVersion:"",category:"",language:"",name:"",type:""}},request:{requestId:"",attributes:{content:"",instruction:"",variant:"A"},connections:{journeyId:"",parentId:"",replyId:"",threadId:""},context:{caseId:"",departmentId:"",operatorId:"",organizationId:"",userId:""},reference:{ids:[{name:"",value:""}],labels:[],tags:[]},resources:{codes:[{id:"",label:"",type:"",value:""}],links:[{expires_at:"",html:!1,id:"",label:"",type:"",url:""}],offers:[]},scope:{accounts:[],appointments:[],assets:[],bookings:[],cases:[],conversations:[],documents:[],events:[],interactions:[],items:[],locations:[],operators:[],orders:[],organizations:[],persons:[],policies:[],products:[{id:""}],properties:[],services:[],subscriptions:[],tickets:[],transactions:[],users:[]},settings:{disableBrowsing:!1,disableSearch:!1,disableSources:!1,disableStream:!0,disableTools:!1,maxResponseLength:0,overrideInterfaceLanguage:"",overrideOutputLanguage:""},a2a:[{id:"",name:"",type:""}],cursor:{since:"",until:""}}};static cleanup(){Ve=!1,Be=!1}constructor(e){if(super(),this.options={...e},function(e){if(void 0===e.strictValidation){const t="undefined"!=typeof process&&process.env?"production":"development";e.strictValidation="production"!==t}if("number"!=typeof e.requestTimeoutMs&&(e.requestTimeoutMs=3e4),"number"!=typeof e.connectionTimeoutMs&&(e.connectionTimeoutMs=3e4),e.logger||(e.logger={debug(){},info(){},warn(){},error(){}}),e.authTransport||(e.authTransport="subprotocol"),void 0===e.authRequired&&(e.authRequired=!0),!e.tokenProvider){let t=e.tokenUrl;if(!t&&"undefined"!=typeof document){const e=document.querySelector('meta[name="optave-token-url"]');e&&e.content&&(t=e.content)}t||(t="/api/optave/ws-ticket"),e.tokenProvider=async()=>{const s={};e.publishableKey&&(s["X-Optave-Publishable-Key"]=e.publishableKey);const r=await fetch(t,{method:"POST",credentials:"include",headers:s});if(!r.ok)throw new Error("Failed to obtain WS token");const a=await r.json();return a.token||a.access_token}}}(this.options),void 0===this.options.cspSafe){const e=We();"server-esm"===e.buildTarget||"server"===e.buildTarget?this.options.cspSafe=!1:("browser-esm"===e.buildTarget||"browser-umd"===e.buildTarget||"server-umd"===e.buildTarget||e.isBrowser||(()=>{const e=We();return"unknown"!==e.buildTarget?e.isBrowser:"undefined"!=typeof window&&void 0!==window.WebSocket})())&&(this.options.cspSafe=!0)}const t=function(e){const t={isValid:!0,errors:[],warnings:[]},s=function(e){const t=[];return e.websocketUrl&&"string"==typeof e.websocketUrl||t.push({type:"warning",code:"MISSING_WEBSOCKET_URL",message:"websocketUrl not provided; openConnection() will emit an error.",field:"websocketUrl"}),t}(e),r=function(e){const t=[];return!e.authenticationUrl||e.clientId&&e.clientSecret||t.push({type:"warning",code:"INCOMPLETE_AUTH_CONFIG",message:"authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.",field:"authentication"}),t}(e);return[...s,...r,...Ae(e)].forEach(e=>{"error"===e.type?(t.errors.push(e),t.isValid=!1):"warning"===e.type&&t.warnings.push(e)}),t}(this.options);if(!t.isValid){const e=t.errors.map(e=>e.message).join("; ");throw new Error(`[Optave SDK] Configuration errors: ${e}`)}t.warnings.forEach(e=>{(this.options?.logger?.warn||console.warn)(`[Optave SDK] ${e.message}`)});!function(e,t,s={}){if(!e||"string"!=typeof e)return;const r=Ue.normalize(t),a=Ue.isBrowser(r);if(a&&e.startsWith("ws://"))throw new Error(`[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in browser builds. Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. Please use secure WebSocket protocol (wss://) instead. Current URL: ${e}`);const i=Ue.isUMD(r);if(a&&i&&e.startsWith("wss://")){const t="function"==typeof s.tokenProvider,r=!1===s.authRequired;if(!t&&!r)throw new Error(`[Optave SDK] Browser UMD builds require a tokenProvider function for secure WebSocket connections. In constrained environments like Salesforce Lightning, authentication tokens must be obtained from your backend server. Please provide options.tokenProvider() that returns a valid token, or set options.authRequired = false to disable authentication. Current URL: ${e}`)}}(this.options.websocketUrl,"server-esm",this.options);const s=We();this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&s.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&s.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this._pending=new Map,this._deprecatedKeys=new Set,this._silenceDeprecations="undefined"!=typeof process&&"1"===process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS,this.options.cspSafe?(this._validatePayload=Re(fe),this._validateMessageEnvelope=be):(this._validatePayload=Re(he),this._validateMessageEnvelope=le)}async _ensureWebSocketImpl(){if(this.WebSocketImpl)return this.WebSocketImpl;const e=We();return this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&e.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&e.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this.WebSocketImpl||(e.isBrowser?this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:null:e.isServer&&(this.WebSocketImpl=await this.loadNodeWebSocket())),this.WebSocketImpl}async loadNodeWebSocket(){const e=We();return e.isBrowser?null:("unknown"!==e.buildTarget||"undefined"==typeof window&&"undefined"==typeof document&&"undefined"==typeof navigator&&void 0===globalThis.location)&&"undefined"!=typeof process&&process.versions&&process.versions.node?async function(){return"undefined"!=typeof window||"undefined"!=typeof document||"undefined"!=typeof navigator||void 0!==globalThis.location?null:"undefined"!=typeof process&&process.versions&&process.versions.node?s:null}():null}static getSdkVersion(){return $e}static getSpecVersion(){return"1.0.0"}static getSchemaRef(){return ve}static get CONSTANTS(){return ke}static get LegacyEvents(){return Pe}static get InboundEvents(){return we}setSessionId(e){return this.sessionId=e,this}getSessionId(){return this.sessionId||""}validate(e){return this._validatePayload(e).valid}validateEnvelope(e){return this._validateMessageEnvelope(e).valid}_validateOutboundPayload(e){return this.options.strictValidation?this._validatePayload(e):Ce(e)}validateRequiredFields(e,t){const s=[];switch(e.request?.connections?.threadId||s.push("request.connections.threadId is required"),t){case"adjust":e.request?.attributes?.content||s.push("request.attributes.content is required for adjust"),e.request?.attributes?.instruction||s.push("request.attributes.instruction is required for adjust"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for adjust"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for adjust and must be a non-empty array");break;case"elevate":e.request?.attributes?.content||s.push("request.attributes.content is required for elevate"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for elevate"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for elevate and must be a non-empty array");break;case"translate":case"summarize":case"insights":case"customerinteraction":case"customerInteraction":case"interaction":case"assistant":e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push(`request.scope.conversations is required for ${t} and must be a non-empty array`);break;case"recommend":e.request?.resources?.offers&&Array.isArray(e.request.resources.offers)&&0!==e.request.resources.offers.length||s.push("request.resources.offers is required for recommend and must be a non-empty array"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for recommend and must be a non-empty array")}return{isValid:0===s.length,errors:s}}async authenticate(){if(Ue.isBrowser("server-esm"))return this.handleError(qe.AUTHENTICATION,"UNSUPPORTED_IN_BROWSER","authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend."),null;const e={grant_type:"client_credentials"};if(!this.options.authenticationUrl)return this.handleError(qe.AUTHENTICATION,"INVALID_AUTHENTICATION_URL","Empty or invalid authentication URL"),null;if(!this.options.clientId)return this.handleError(qe.AUTHENTICATION,"INVALID_CLIENT_ID","Empty or invalid client ID"),null;e.client_id=this.options.clientId,e.client_secret=this.options.clientSecret;const t=new URLSearchParams(e).toString();let s=this.options.authenticationUrl;s.endsWith("/token")||(s=s.endsWith("/")?`${s}token`:`${s}/token`);const r=`${s}?${t}`,a=await fetch(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"}}),i=await a.json();return a.ok?i.access_token:(this.handleError(qe.AUTHENTICATION,"INVALID_AUTHENTICATION_RESPONSE",this.formatAuthenticationError(a,i.error,"token endpoint").message,i.error),null)}async openConnection(e){if(!this.options.websocketUrl)return(this.options?.logger?.error||console.error)("[Optave SDK] openConnection aborted: missing websocketUrl"),void this.handleError(qe.WEBSOCKET,"INVALID_WEBSOCKET_URL",this.formatWebSocketError(new Error("Invalid WebSocket URL configuration"),{url:this.options.websocketUrl}).message,this.options.websocketUrl);const t=await(async()=>{if("string"==typeof e&&e.length>0)return e;if("function"==typeof this.options.tokenProvider)try{return await this.options.tokenProvider()}catch(e){return this.handleError(qe.AUTHENTICATION,"TOKEN_PROVIDER_FAILED",this.formatTokenProviderError(e).message,e),null}return null})();if(await this._ensureWebSocketImpl(),!this.WebSocketImpl)return void this.handleError(qe.WEBSOCKET,"NO_WEBSOCKET_IMPL",this.formatWebSocketError(new Error("No WebSocket implementation available"),{environment:"undefined"!=typeof window?"browser":"node"}).message);if(!t&&!1!==this.options.authRequired)return void this.handleError(qe.AUTHENTICATION,"MISSING_TOKEN","No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.");const s=new URLSearchParams;this.sessionId&&s.set("OptaveTraceChatSessionId",this.sessionId);try{if("subprotocol"===this.options.authTransport){const e=t?["optave-v1",t]:["optave-v1"];this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl,e)}else{if(t){const e=t.replace(/^Bearer\s+/i,"");s.set("Authorization",e)}this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl),t&&this._warnOnce("_warnedQueryToken",'[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".')}}catch(e){return(this.options?.logger?.error||console.error)("[Optave SDK] WebSocket constructor threw",e),void this.handleError(qe.WEBSOCKET,"WEBSOCKET_ERROR",this.formatWebSocketError(e,{url:this.options.websocketUrl}).message,e)}return new Promise((e,t)=>{const s=setTimeout(()=>{const e=this.options.connectionTimeoutMs||3e4,s=this.formatWebSocketError(new Error("Connection timeout"),{timeout:e,url:this.options.websocketUrl}).message;if(this.wss){this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null;try{this.wss.close()}catch(e){}this.wss=null}this.handleError(qe.WEBSOCKET,"CONNECTION_TIMEOUT",s),t(new Me({category:qe.WEBSOCKET,code:"CONNECTION_TIMEOUT",message:s,details:null}))},this.options.connectionTimeoutMs||3e4);this.wss.onopen=t=>{clearTimeout(s),this.emit("open",t),e(t)},this.wss.onmessage=e=>{this._handleInbound(e.data)},this.wss.onclose=e=>{clearTimeout(s),this.emit("close",e),Array.from(this._pending.entries()).forEach(([t,s])=>{s.timer&&clearTimeout(s.timer),s._handled=!0,s.reject({category:qe.WEBSOCKET,code:"CONNECTION_CLOSED",message:`WebSocket connection closed: ${e.reason||"Connection lost"}`,details:{code:e.code,reason:e.reason,correlationId:t},correlationId:t})}),this._pending.clear(),this.wss=null},this.wss.onerror=e=>{clearTimeout(s);const r=e.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||"WebSocket connection failed",a={category:qe.WEBSOCKET,code:"CONNECTION_ERROR",message:r,details:{originalError:e}};Array.from(this._pending.entries()).forEach(([e,t])=>{t.timer&&clearTimeout(t.timer),t._handled=!0,t.reject({...a,details:{...a.details,correlationId:e},correlationId:e})}),this._pending.clear(),this.emit("error",a),t(a)}})}_warnOnce(e,t){this[e]||(this[e]=!0,(this.options?.logger?.warn||console.warn)(t))}deprecate(e,t){this._silenceDeprecations||this._deprecatedKeys.has(e)||(this._deprecatedKeys.add(e),(this.options?.logger?.warn||console.warn)(t))}_handleInbound(e){let t;try{t="string"==typeof e?JSON.parse(e):e}catch(e){const t={category:qe.WEBSOCKET,code:"INVALID_JSON",message:"Invalid JSON received from server",details:e,timestamp:(new Date).toISOString()};return void this._emitError(t)}const s=t&&t.headers&&t.payload,r="error"===t?.state||"error"===t?.actionType||!!t?.error;if(this.options.strictValidation&&s){const e=this._validateMessageEnvelope(t);e.valid||this.handleError(qe.VALIDATION,"INBOUND_ENVELOPE_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Inbound envelope validation failed"),e.errors)}if(r){const e=t?.headers&&t.headers.correlationId||t?.correlationId||null,s={category:qe.ORCHESTRATOR,code:t?.error?.code||"REMOTE_ERROR",message:t?.error?.message||t?.message||"Remote error",details:t?.error||t,correlationId:e};if(e&&this._pending.has(e)){const t=this._pending.get(e);t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),t.reject(s)}return void this._emitError(s,t?.action)}const a=t?.headers?.correlationId||t?.correlationId;if(a&&this._pending.has(a)){const e=this._pending.get(a);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(a),e.resolve(t)}this.emit(Pe.MESSAGE,t),Ve||(Ve=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".')),this.emit(we.SUPERPOWER_RESPONSE,t),this.emit(Se.RESPONSE,t),t?.action&&this.emit(`message.${t.action}`.toLowerCase(),t),s&&t.headers.schemaRef&&this.emit(t.headers.schemaRef,t)}_emitError(e,t=null){e.timestamp||(e.timestamp=(new Date).toISOString()),this.emit(Pe.ERROR,e),Be||(Be=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'));const s=(r=e)&&r.category&&r.code&&r.message?new Me(r):"string"==typeof r?new Me({category:"UNKNOWN",code:"STRING_ERROR",message:r}):r&&"AjvValidationError"===r.name?new Me({category:"VALIDATION",code:"SCHEMA_VALIDATION",message:r.message,details:r.errors}):r&&r.isAuthError?new Me({category:"AUTHENTICATION",code:r.code||"AUTH_ERROR",message:r.message||"Authentication error",details:r}):r&&r.isWsError?new Me({category:"WEBSOCKET",code:r.code||"WS_ERROR",message:r.message||"WebSocket error",details:r}):new Me({category:"UNKNOWN",code:"UNCLASSIFIED",message:r&&r.message||String(null!=r?r:"Unknown error"),details:r});var r;this.emit(we.SUPERPOWER_ERROR,s),this.emit(Se.ERROR,e)}closeConnection(){this.wss&&(this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null,this.wss.close(),this.wss=null)}selectiveDeepMerge(e,t){if(Array.isArray(e)&&Array.isArray(t))return[...t];const s=e=>null!==e&&"object"==typeof e&&!Array.isArray(e);if(s(e)&&s(t)){const s={...e};return Object.keys(t).forEach(r=>{s[r]=r in e?this.selectiveDeepMerge(e[r],t[r]):t[r]}),s}return void 0!==t?t:e}isPayloadSizeValid(e){return!!e&&e.length/1024<=ke.MAX_PAYLOAD_SIZE_KB}openConnectionAsync(e){return new Promise((t,s)=>{let r;const a=e=>{this.off("error",r),t(e)};r=e=>{this.off("open",a),s(e)},this.once("open",a),this.once("error",r),this.openConnection(e)})}buildPayload(e,t,s){const r=this.selectiveDeepMerge(xe.defaultPayload,s);return s?.request?.variation&&(this.deprecate("payload.request.variation","[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."),r.request.attributes.variant=s.request.variation),s?.request?.content&&!r.request?.attributes?.content&&(r.request.attributes.content=s.request.content,this.deprecate("payload.request.content","[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.")),r.request.attributes.variant&&(r.request.attributes.variant=r.request.attributes.variant.toUpperCase()),r}resolveMessageId(e,t){return`${t}.${e}.v3`.toLowerCase()}buildMessageEnvelope(e,t,s,r={}){const a=(new Date).toISOString(),i=r.correlationId||e?.request?.requestId||q(),o=r.traceId||q(),p=r.idempotencyKey||q(),{timestamp:n}=r,c={correlationId:i,action:s,schemaRef:ve,sdkVersion:$e,identifier:t,traceId:o,idempotencyKey:p,timestamp:n,issuedAt:a};return this.options.tenantId&&(c.tenantId=this.options.tenantId),void 0!==r.networkLatencyMs&&(c.networkLatencyMs=r.networkLatencyMs),Object.freeze(c),{action:"message",headers:c,payload:e}}formatValidationErrorMessage(e,t="Validation failed"){if(!e||!Array.isArray(e)||0===e.length)return t;if(1===e.length){const s=e[0],r=s.instancePath||"/",a="/"===r?"root object":r.replace(/^\//,"").replace(/\//g,".");if("required"===s.keyword){const e=s.params?.missingProperty||"unknown field";let r;return r="root object"===a?e:a.endsWith(e)?a:`${a}.${e}`,`${t}: ${"root object"===a?"Required field":"Field"} '${r}' is missing`}if("type"===s.keyword){return`${t}: Field '${a}' must be of type '${s.params?.type||"unknown"}'`}if("additionalProperties"===s.keyword){return`${t}: Field '${a}.${s.params?.additionalProperty||"unknown"}' is not allowed`}if("enum"===s.keyword){const e=s.params?.allowedValues||[];return`${t}: Field '${a}' must be one of: ${Array.isArray(e)?e.join(", "):"unknown values"}`}return`${t}: ${s.message} at '${a}'`}const s=e.filter(e=>"required"===e.keyword),r=e.filter(e=>"type"===e.keyword),a=e.filter(e=>"required"!==e.keyword&&"type"!==e.keyword);let i=`${t}:`;if(s.length>0){i+=` Missing required fields: ${s.map(e=>{const t=(e.instancePath||"/").replace(/^\//,"").replace(/\//g,"."),s=e.params?.missingProperty||"unknown";return""===t?s:`${t}.${s}`}).join(", ")}.`}if(r.length>0){i+=` Type errors in: ${r.slice(0,3).map(e=>`${(e.instancePath||"/").replace(/^\//,"").replace(/\//g,".")||"root"} (expected ${e.params?.type||"unknown"})`).join(", ")}.`,r.length>3&&(i+=` And ${r.length-3} more type errors.`)}return a.length>0&&(i+=` Additional validation errors: ${a.length}.`),i}formatAuthenticationError(e,t,s){let r="Authentication failed";const a=[];return e&&e.status&&(r+=` (HTTP ${e.status})`),t&&("string"==typeof t?r+=`: ${t}`:t.error_description?r+=`: ${t.error_description}`:t.message?r+=`: ${t.message}`:t.error&&(r+=`: ${t.error}`)),e&&401===e.status?(a.push("Verify clientId and clientSecret are correct"),a.push("Ensure credentials match the target environment (dev/staging/production)")):e&&403===e.status?(a.push("Check if your client has the necessary permissions"),a.push("Verify the authentication endpoint URL is correct")):e&&e.status>=500?(a.push("Authentication server error - try again later"),a.push("Contact support if the problem persists")):a.push("Check network connectivity and authentication endpoint configuration"),s&&s.authUrl&&(r+=` (endpoint: ${s.authUrl})`),{message:r,suggestions:a}}formatWebSocketError(e,t){let s="WebSocket connection failed";const r=[],a=e?.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||null;return a&&(s+=`: ${a}`),t&&(t.url&&(s+=` (URL: ${t.url})`),t.timeout&&(s+=` (timeout: ${t.timeout}ms)`)),r.push("Check network connectivity and firewall settings"),r.push("Verify WebSocket URL is correct and accessible"),t&&t.url&&(t.url.startsWith("ws://")&&r.push("Consider using secure WebSocket (wss://) for production"),(t.url.includes("localhost")||t.url.includes("127.0.0.1"))&&r.push("Ensure local server is running if connecting to localhost")),t&&t.timeout&&r.push("Try increasing connection timeout if network is slow"),{message:s,suggestions:r}}formatPayloadSizeError(e,t,s){const r=Math.ceil(e/1024),a=`Payload too large: ${r}KB exceeds maximum ${t}KB (${r-t}KB over limit)`,i=[];if(s&&"object"==typeof s){if(s.request?.scope?.conversations&&Array.isArray(s.request.scope.conversations)){const e=JSON.stringify(s.request.scope.conversations).length,t=Math.ceil(e/1024);t>10&&(i.push(`Consider reducing conversation history - current size: ~${t}KB`),i.push("Remove older messages or summarize conversation context"))}if(s.request?.resources?.offers&&Array.isArray(s.request.resources.offers)){const e=JSON.stringify(s.request.resources.offers).length,t=Math.ceil(e/1024);t>5&&i.push(`Consider reducing product offers data - current size: ~${t}KB`)}if(s.session?.channel?.metadata&&Array.isArray(s.session.channel.metadata)){const e=JSON.stringify(s.session.channel.metadata).length,t=Math.ceil(e/1024);t>2&&i.push(`Consider reducing metadata array - current size: ~${t}KB`)}}return 0===i.length&&(i.push("Remove unused fields from request payload"),i.push("Consider paginating large datasets"),i.push("Use shorter field values where possible")),{message:a,suggestions:i}}formatTokenProviderError(e,t){let s="Failed to obtain WebSocket token from tokenProvider()";const r=[];return e&&(e.message?s+=`: ${e.message}`:"string"==typeof e&&(s+=`: ${e}`),"TypeError"===e.name&&e.message?.includes("fetch")?(r.push("Check if tokenProvider endpoint is accessible"),r.push("Verify CORS settings allow requests to token endpoint")):e.message?.includes("404")||e.message?.includes("Not Found")?(r.push("Verify tokenProvider endpoint URL is correct"),r.push("Ensure backend token endpoint is implemented")):e.message?.includes("401")||e.message?.includes("403")?(r.push("Check authentication/authorization for token endpoint"),r.push("Verify user session or credentials are valid")):e.message?.includes("timeout")&&r.push("Token provider request timed out - check network or server response time")),t&&t.tokenUrl&&(s+=` (endpoint: ${t.tokenUrl})`),0===r.length&&(r.push("Verify tokenProvider function implementation"),r.push("Check backend token endpoint is running and accessible"),r.push("Review browser console for network errors")),{message:s,suggestions:r}}handleError(e,t,s,r=null,a=[],i=null){const o=new Me({category:e,code:t,message:s,details:r});a&&(o.suggestions=a),i&&(o.correlationId=i),0===this.listenerCount(Pe.ERROR)&&0===this.listenerCount(Se.ERROR)&&(this.options?.logger?.error||console.error)(`[Optave SDK] ${t}: ${s}`),this._emitError(o)}send(e,t,s){const r=null!=(this.WebSocketImpl&&this.WebSocketImpl.OPEN)?this.WebSocketImpl.OPEN:1;if(!this.wss||this.wss.readyState!==r){const e=this.wss?this.wss.readyState:"no connection";return void this.handleError(qe.WEBSOCKET,"WEBSOCKET_NOT_IN_OPEN_STATE",this.formatWebSocketError(new Error("WebSocket not ready for sending"),{readyState:e,action:t}).message)}if(!Ie.has(t))return void this.handleError(qe.VALIDATION,"INVALID_ACTION",`Unsupported action '${t}'. Allowed: ${[...Ie].join(", ")}`);const a=new Set(["session","request","headers"]),i=Object.keys(s||{});for(let e=0;e0&&(i=setTimeout(()=>{if(this._pending.has(e)){const r=this._pending.get(e);r&&!r._handled&&(this._pending.delete(e),r._handled=!0,a({category:qe.WEBSOCKET,code:"REQUEST_TIMEOUT",message:`Request timed out after ${s}ms`,details:{correlationId:e,action:t},correlationId:e}))}},s)),this._pending.set(e,{resolve:r,reject:a,timer:i,action:t,_handled:!1})}_promiseSend(e,t,s={},r={}){let a;const i=new Promise((i,o)=>{let p;if(p="number"==typeof r.timeoutMs?r.timeoutMs:"number"==typeof r.timeout?r.timeout:this.options.requestTimeoutMs,!this.wss||this.wss.readyState!==WebSocket.OPEN){if(p<=0)return void o(new Me({category:qe.WEBSOCKET,code:"WEBSOCKET_NOT_IN_OPEN_STATE",message:"WebSocket not open",details:null}));const r=this.buildPayload(e,t,s),n=this.buildMessageEnvelope(r,e,t,s?.headers||{});return a=n.headers.correlationId,void this._registerPending(a,t,p,i,o)}if(!Ie.has(t))return void o(new Me({category:qe.VALIDATION,code:"INVALID_ACTION",message:`Unsupported action '${t}'.`,details:{allowed:[...Ie]}}));const n=new Set(["session","request","headers"]),c=Object.keys(s||{});for(let e=0;e{t.reject({category:qe.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:e},correlationId:e})},0),!0}return!1}cancelPendingRequests(e=!1){if(!this._pending)return 0;const t=this._pending.size;return[...this._pending.entries()].forEach(([t,s])=>{s.timer&&clearTimeout(s.timer),s._handled=!0,e?s.reject({category:qe.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled during cleanup",details:{correlationId:t},correlationId:t}):queueMicrotask(()=>{s.reject({category:qe.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:t},correlationId:t})})}),this._pending.clear(),t}cleanup(){this.closeConnection(),this.cancelPendingRequests(!0),this._deprecatedKeys&&this._deprecatedKeys.clear(),void 0!==this._warnedQueryToken&&delete this._warnedQueryToken,this._events&&Object.keys(this._events).forEach(e=>{delete this._events[e]}),this.removeAllListeners(),this._events=null,this._eventsCount=null,this._maxListeners=null;this._validatePayload=null,this._validateOutboundPayload=null,this._validateMessageEnvelope=null,this._emitError=null,this._ensureWebSocketImpl=null,this._handleInbound=null,this._promiseSend=null,this._registerPending=null,this._warnOnce=null,this.options=null,this.WebSocketImpl=null,this.wss=null,this.sessionId=null,this._pending=null,this._deprecatedKeys=null,this._silenceDeprecations=null,this._events=null,this._eventsCount=null,this._maxListeners=null}removeAllListeners(t){try{e.prototype.removeAllListeners.call(this,t)}catch(e){t?this._events&&this._events[t]&&(delete this._events[t],this._eventsCount=Math.max(0,this._eventsCount-1)):(this._events=Object.create(null),this._eventsCount=0)}return this}static get buildFlags(){const e="server-esm";return{SALESFORCE_BUILD:"undefined"!=typeof __SALESFORCE_BUILD__&&__SALESFORCE_BUILD__,INCLUDE_WS_REQUIRE:!0,SDK_VERSION:"3.6.0",WEBPACK_BUILD_TARGET:e,WEBPACK_BUILD_TARGET_NORMALIZED:Ue.normalize(e),BUILD_TARGET_INFO:Ue.getInfo(e)}}}const Ke=xe;export{Ke as default};
\ No newline at end of file
diff --git a/sdks/javascript/dist/server.umd.js b/sdks/javascript/dist/server.umd.js
index 1f8d00e..5af94b7 100644
--- a/sdks/javascript/dist/server.umd.js
+++ b/sdks/javascript/dist/server.umd.js
@@ -1,15 +1,41 @@
-!function webpackUniversalModuleDefinition(root,factory){"object"==typeof exports&&"object"==typeof module?module.exports=factory():"function"==typeof define&&define.amd?define("OptaveJavaScriptSDK",[],factory):"object"==typeof exports?exports.OptaveJavaScriptSDK=factory():root.OptaveJavaScriptSDK=factory()}(function(){return"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:this}(),()=>(()=>{var e={31:(e,t,s)=>{s.d(t,{I:()=>n});class r{constructor(e){if(this.params=new Map,"string"==typeof e){const t=undefined;e.replace(/^\?/,"").split("&").forEach(e=>{if(e){const[t,s]=e.split("=");t&&this.params.set(decodeURIComponent(t),decodeURIComponent(s||""))}})}else e&&"object"==typeof e&&(e instanceof Map?e.forEach((e,t)=>{this.params.set(t,String(e))}):Array.isArray(e)?e.forEach(([e,t])=>{this.params.set(e,String(t))}):Object.entries(e).forEach(([e,t])=>{this.params.set(e,String(t))}))}append(e,t){const s=this.params.get(e);void 0!==s?this.params.set(e,s+","+String(t)):this.params.set(e,String(t))}delete(e){this.params.delete(e)}get(e){return this.params.get(e)||null}getAll(e){const t=this.params.get(e);return t?t.split(","):[]}has(e){return this.params.has(e)}set(e,t){this.params.set(e,String(t))}toString(){const e=[];return this.params.forEach((t,s)=>{const r=undefined;t.split(",").forEach(t=>{e.push(`${encodeURIComponent(s)}=${encodeURIComponent(t)}`)})}),e.join("&")}*[Symbol.iterator](){for(const[e,t]of this.params){const s=t.split(",");for(const t of s)yield[e,t]}}*keys(){for(const[e]of this)yield e}*values(){for(const[,e]of this)yield e}*entries(){yield*this}forEach(e,t){for(const[s,r]of this)e.call(t,r,s,this)}}const n="undefined"!=typeof globalThis&&globalThis.URLSearchParams||"undefined"!=typeof window&&window.URLSearchParams||r},46:e=>{var t="object"==typeof Reflect?Reflect:null,s=t&&"function"==typeof t.apply?t.apply:function e(t,s,r){return Function.prototype.apply.call(t,s,r)},r;function n(e){console&&console.warn&&console.warn(e)}r=t&&"function"==typeof t.ownKeys?t.ownKeys:Object.getOwnPropertySymbols?function e(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function e(t){return Object.getOwnPropertyNames(t)};var o=Number.isNaN||function e(t){return t!=t};function i(){i.init.call(this)}e.exports=i,e.exports.once=v,i.EventEmitter=i,i.prototype._events=void 0,i.prototype._eventsCount=0,i.prototype._maxListeners=void 0;var a=10;function c(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function d(e){return void 0===e._maxListeners?i.defaultMaxListeners:e._maxListeners}function u(e,t,s,r){var o,i,a;if(c(s),void 0===(i=e._events)?(i=e._events=Object.create(null),e._eventsCount=0):(void 0!==i.newListener&&(e.emit("newListener",t,s.listener?s.listener:s),i=e._events),a=i[t]),void 0===a)a=i[t]=s,++e._eventsCount;else if("function"==typeof a?a=i[t]=r?[s,a]:[a,s]:r?a.unshift(s):a.push(s),(o=d(e))>0&&a.length>o&&!a.warned){a.warned=!0;var u=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");u.name="MaxListenersExceededWarning",u.emitter=e,u.type=t,u.count=a.length,n(u)}return e}function l(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(e,t,s){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:s},n=l.bind(r);return n.listener=s,r.wrapFn=n,n}function h(e,t,s){var r=e._events;if(void 0===r)return[];var n=r[t];return void 0===n?[]:"function"==typeof n?s?[n.listener||n]:[n]:s?y(n):m(n,n.length)}function f(e){var t=this._events;if(void 0!==t){var s=t[e];if("function"==typeof s)return 1;if(void 0!==s)return s.length}return 0}function m(e,t){for(var s=new Array(t),r=0;r0&&(a=r[0]),a instanceof Error)throw a;var c=new Error("Unhandled error."+(a?" ("+a.message+")":""));throw c.context=a,c}var d=i[t];if(void 0===d)return!1;if("function"==typeof d)s(d,this,r);else for(var u=d.length,l=m(d,u),n=0;n=0;i--)if(r[i]===s||r[i].listener===s){a=r[i].listener,o=i;break}if(o<0)return this;0===o?r.shift():g(r,o),1===r.length&&(n[t]=r[0]),void 0!==n.removeListener&&this.emit("removeListener",t,a||s)}return this},i.prototype.off=i.prototype.removeListener,i.prototype.removeAllListeners=function e(t){var s,r,n;if(void 0===(r=this._events))return this;if(void 0===r.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==r[t]&&(0===--this._eventsCount?this._events=Object.create(null):delete r[t]),this;if(0===arguments.length){var o=Object.keys(r),i;for(n=0;n=0;n--)this.removeListener(t,s[n]);return this},i.prototype.listeners=function e(t){return h(this,t,!0)},i.prototype.rawListeners=function e(t){return h(this,t,!1)},i.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):f.call(e,t)},i.prototype.listenerCount=f,i.prototype.eventNames=function e(){return this._eventsCount>0?r(this._events):[]}}},t={};function s(r){var n=t[r];if(void 0!==n)return n.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,s),o.exports}void(s.d=(e,t)=>{for(var r in t)s.o(t,r)&&!s.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}),s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var r={};s.d(r,{default:()=>pe});var n=s(46);let o;const i=new Uint8Array(16);function a(){if(!o){if("undefined"==typeof crypto||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");o=crypto.getRandomValues.bind(crypto)}return o(i)}const c=[];for(let e=0;e<256;++e)c.push((e+256).toString(16).slice(1));function d(e,t=0){return(c[e[t+0]]+c[e[t+1]]+c[e[t+2]]+c[e[t+3]]+"-"+c[e[t+4]]+c[e[t+5]]+"-"+c[e[t+6]]+c[e[t+7]]+"-"+c[e[t+8]]+c[e[t+9]]+"-"+c[e[t+10]]+c[e[t+11]]+c[e[t+12]]+c[e[t+13]]+c[e[t+14]]+c[e[t+15]]).toLowerCase()}function u(e,t=0){const s=d(e,t);if(!validate(s))throw TypeError("Stringified UUID is invalid");return s}const l=null,p={};function h(e,t,s){let r;if(e)r=m(e.random??e.rng?.()??a(),e.msecs,e.seq,t,s);else{const e=Date.now(),n=a();f(p,e,n),r=m(n,p.msecs,p.seq,t,s)}return t??d(r)}function f(e,t,s){return e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=s[6]<<23|s[7]<<16|s[8]<<8|s[9],e.msecs=t):(e.seq=e.seq+1|0,0===e.seq&&e.msecs++),e}function m(e,t,s,r,n=0){if(e.length<16)throw new Error("Random bytes length must be >= 16");if(r){if(n<0||n+16>r.length)throw new RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`)}else r=new Uint8Array(16),n=0;return t??=Date.now(),s??=127*e[6]<<24|e[7]<<16|e[8]<<8|e[9],r[n++]=t/1099511627776&255,r[n++]=t/4294967296&255,r[n++]=t/16777216&255,r[n++]=t/65536&255,r[n++]=t/256&255,r[n++]=255&t,r[n++]=112|s>>>28&15,r[n++]=s>>>20&255,r[n++]=128|s>>>14&63,r[n++]=s>>>6&255,r[n++]=s<<2&255|3&e[10],r[n++]=e[11],r[n++]=e[12],r[n++]=e[13],r[n++]=e[14],r[n++]=e[15],r}const g=h;
+!function webpackUniversalModuleDefinition(root,factory){"object"==typeof exports&&"object"==typeof module?module.exports=factory(require("events"),require("ws")):"function"==typeof define&&define.amd?define("OptaveJavaScriptSDK",["events","ws"],factory):"object"==typeof exports?exports.OptaveJavaScriptSDK=factory(require("events"),require("ws")):root.OptaveJavaScriptSDK=factory(root.events,root.ws)}("undefined"!=typeof globalThis?globalThis:this,(e,t)=>(()=>{var s={761(t){t.exports=e},2(e){e.exports=t},31(e,t,s){class URLSearchParamsPolyfill{constructor(e){if(this.params=new Map,"string"==typeof e){e.replace(/^\?/,"").split("&").forEach(e=>{if(e){const[t,s]=e.split("=");t&&this.params.set(decodeURIComponent(t),decodeURIComponent(s||""))}})}else e&&"object"==typeof e&&(e instanceof Map?e.forEach((e,t)=>{this.params.set(t,String(e))}):Array.isArray(e)?e.forEach(([e,t])=>{this.params.set(e,String(t))}):Object.entries(e).forEach(([e,t])=>{this.params.set(e,String(t))}))}append(e,t){const s=this.params.get(e);void 0!==s?this.params.set(e,`${s},${String(t)}`):this.params.set(e,String(t))}delete(e){this.params.delete(e)}get(e){return this.params.get(e)||null}getAll(e){const t=this.params.get(e);return t?t.split(","):[]}has(e){return this.params.has(e)}set(e,t){this.params.set(e,String(t))}toString(){const e=[];return this.params.forEach((t,s)=>{t.split(",").forEach(t=>{e.push(`${encodeURIComponent(s)}=${encodeURIComponent(t)}`)})}),e.join("&")}*[Symbol.iterator](){const e=Array.from(this.params);for(let t=0;t{e.call(t,r,s,this)})}}const r="undefined"!=typeof globalThis&&globalThis.URLSearchParams||"undefined"!=typeof window&&window.URLSearchParams||URLSearchParamsPolyfill;s.d(t,["I",0,r])}};const r={};function o(e){const t=r[e];if(void 0!==t)return t.exports;const n=r[e]={exports:{}};return s[e](n,n.exports,o),n.exports}o.d=(e,t)=>{if(Array.isArray(t))for(var s=0;sObject.prototype.hasOwnProperty.call(e,t);let n={};o.d(n,{default:()=>H});var i=o(761);const a=new Uint8Array(16);function c(){return crypto.getRandomValues(a)}const d=[];for(let e=0;e<256;++e)d.push((e+256).toString(16).slice(1));function l(e,t=0){return(d[e[t+0]]+d[e[t+1]]+d[e[t+2]]+d[e[t+3]]+"-"+d[e[t+4]]+d[e[t+5]]+"-"+d[e[t+6]]+d[e[t+7]]+"-"+d[e[t+8]]+d[e[t+9]]+"-"+d[e[t+10]]+d[e[t+11]]+d[e[t+12]]+d[e[t+13]]+d[e[t+14]]+d[e[t+15]]).toLowerCase()}const u={};function p(e,t,s,r,o=0){if(e.length<16)throw new Error("Random bytes length must be >= 16");if(r){if(o<0||o+16>r.length)throw new RangeError(`UUID byte range ${o}:${o+15} is out of buffer bounds`)}else r=new Uint8Array(16),o=0;return t??=Date.now(),s??=h(e),r[o++]=t/1099511627776&255,r[o++]=t/4294967296&255,r[o++]=t/16777216&255,r[o++]=t/65536&255,r[o++]=t/256&255,r[o++]=255&t,r[o++]=112|s>>>28&15,r[o++]=s>>>20&255,r[o++]=128|s>>>14&63,r[o++]=s>>>6&255,r[o++]=s<<2&255|3&e[10],r[o++]=e[11],r[o++]=e[12],r[o++]=e[13],r[o++]=e[14],r[o++]=e[15],r}function h(e){return(127&e[6])<<24|e[7]<<16|e[8]<<8|e[9]}const m=function(e,t,s){let r;if(e)r=p(e.random??e.rng?.()??c(),e.msecs,e.seq,t,s);else{const e=Date.now(),o=c();!function(e,t,s){e.msecs??=-1/0,e.seq??=0,t>e.msecs?(e.seq=h(s),e.msecs=t):(e.seq=e.seq+1|0,0===e.seq&&e.msecs++)}(u,e,o),r=p(o,u.msecs,u.seq,t,s)}return t??l(r)};
/**
- * Browser-compatible validator implementation
- * Provides comprehensive validation without AJV dependency
- * This implementation must match the server-side validation logic for security
+ * CSP-safe validator implementation (no eval/Function constructor)
+ *
+ * Used by all builds that require Content Security Policy compliance:
+ * - Browser ESM (browser.mjs)
+ * - Browser UMD (browser.umd.js) - Salesforce Lightning
+ * - Server UMD (server.umd.js) - Node.js CommonJS
+ *
+ * Provides comprehensive validation without AJV dependency.
+ * Server ESM (server.mjs) uses full AJV validation instead.
+ *
+ * This implementation must match the server-side validation logic for security.
*/
-function y(e,t,s="validation",r={}){return{instancePath:e,message:t,keyword:s,params:r}}function v(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[y("","must be object","type",{type:"object"})]};const t=[];return e.session?"object"!=typeof e.session?t.push(y("/session","must be object","type",{type:"object"})):void 0!==e.session.sessionId&&"string"!=typeof e.session.sessionId&&t.push(y("/session/sessionId","must be string","type",{type:"string"})):t.push(y("/session","is required","required",{missingProperty:"session"})),e.request?"object"!=typeof e.request?t.push(y("/request","must be object","type",{type:"object"})):(e.request.connections?"object"!=typeof e.request.connections?t.push(y("/request/connections","must be object","type",{type:"object"})):(e.request.connections.threadId?"string"!=typeof e.request.connections.threadId&&t.push(y("/request/connections/threadId","must be string","type",{type:"string"})):t.push(y("/request/connections/threadId","is required","required",{missingProperty:"threadId"})),void 0!==e.request.connections.parentId&&"string"!=typeof e.request.connections.parentId&&t.push(y("/request/connections/parentId","must be string","type",{type:"string"}))):t.push(y("/request/connections","is required","required",{missingProperty:"connections"})),void 0!==e.request.context&&"object"!=typeof e.request.context&&t.push(y("/request/context","must be object","type",{type:"object"})),void 0!==e.request.attributes&&"object"!=typeof e.request.attributes&&t.push(y("/request/attributes","must be object","type",{type:"object"})),void 0!==e.request.scope&&("object"!=typeof e.request.scope?t.push(y("/request/scope","must be object","type",{type:"object"})):void 0!==e.request.scope.conversations&&(Array.isArray(e.request.scope.conversations)||t.push(y("/request/scope/conversations","must be array","type",{type:"array"})))),void 0!==e.request.resources&&("object"!=typeof e.request.resources?t.push(y("/request/resources","must be object","type",{type:"object"})):void 0!==e.request.resources.offers&&(Array.isArray(e.request.resources.offers)||t.push(y("/request/resources/offers","must be array","type",{type:"array"}))))):t.push(y("/request","is required","required",{missingProperty:"request"})),t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function b(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[y("","must be object","type",{type:"object"})]};const t=[];if(e.headers)if("object"!=typeof e.headers)t.push(y("/headers","must be object","type",{type:"object"}));else{if(e.headers.correlationId?"string"!=typeof e.headers.correlationId&&t.push(y("/headers/correlationId","must be string","type",{type:"string"})):t.push(y("/headers/correlationId","is required","required",{missingProperty:"correlationId"})),e.headers.action)if("string"!=typeof e.headers.action)t.push(y("/headers/action","must be string","type",{type:"string"}));else{const s=["adjust","elevate","interaction","customerinteraction","reception","summarize","translate","recommend","insights"];s.includes(e.headers.action)||t.push(y("/headers/action","must be equal to one of the allowed values","enum",{allowedValues:s}))}else t.push(y("/headers/action","is required","required",{missingProperty:"action"}));void 0!==e.headers.identifier&&"string"!=typeof e.headers.identifier&&t.push(y("/headers/identifier","must be string","type",{type:"string"})),void 0!==e.headers.schemaRef&&"string"!=typeof e.headers.schemaRef&&t.push(y("/headers/schemaRef","must be string","type",{type:"string"})),void 0!==e.headers.timestamp&&"string"!=typeof e.headers.timestamp&&t.push(y("/headers/timestamp","must be string","type",{type:"string"}))}else t.push(y("/headers","is required","required",{missingProperty:"headers"}));if(e.payload){if("object"!=typeof e.payload)t.push(y("/payload","must be object","type",{type:"object"}));else if(e.headers&&e.headers.action&&e.payload){const s=e.headers.action,r=undefined;["adjust","elevate","interaction","customerinteraction","customerInteraction","summarize","translate","insights","recommend"].includes(s)&&(e.payload.request?e.payload.request.scope?e.payload.request.scope.conversations?Array.isArray(e.payload.request.scope.conversations)?0===e.payload.request.scope.conversations.length&&t.push(y("/payload/request/scope/conversations",`must be non-empty array for ${s}`,"minItems",{limit:1})):t.push(y("/payload/request/scope/conversations","must be array","type",{type:"array"})):t.push(y("/payload/request/scope/conversations",`is required for ${s}`,"required",{missingProperty:"conversations"})):t.push(y("/payload/request/scope","is required","required",{missingProperty:"scope"})):t.push(y("/payload/request","is required","required",{missingProperty:"request"})))}}else t.push(y("/payload","is required","required",{missingProperty:"payload"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}const E=null,S="3.2.3",w=undefined,_=`optave.message.v${S.split(".")[0]}`,I={AUTHENTICATION:"AUTHENTICATION",ORCHESTRATOR:"ORCHESTRATOR",VALIDATION:"VALIDATION",WEBSOCKET:"WEBSOCKET"},O=Object.freeze({MESSAGE:"message",ERROR:"error"}),T=Object.freeze({CONNECTION_OPEN:"connection:open",CONNECTION_CLOSE:"connection:close",CONNECTION_ERROR:"connection:error",MESSAGE_RECEIVED:"message:received",MESSAGE_SENT:"message:sent",ERROR:"error",RESPONSE:"response",LEGACY_ERROR:"error",LEGACY_MESSAGE:"message"}),A=Object.freeze({SUPERPOWER_RESPONSE:"superpower.response",SUPERPOWER_ERROR:"superpower.error"}),R=new Set(["adjust","elevate","interaction","reception","customerInteraction","summarize","translate","recommend","insights"]),k=undefined,q=undefined,C=undefined,N=undefined,U={SPEC_VERSION:S,SCHEMA_REF:_,MAX_PAYLOAD_SIZE:131072,MAX_PAYLOAD_SIZE_KB:128,DEFAULT_REQUEST_TIMEOUT_MS:3e4,ErrorCategory:I,LegacyEvents:O,EVENTS:T,InboundEvents:A,ALLOWED_ACTIONS:R},L=()=>{if("undefined"!=typeof process&&process.versions&&process.versions.node){const e=undefined;if(!1,"true"===process.env.VITEST||void 0!==process.env.JEST_WORKER_ID||process.argv.some(e=>e.includes("vitest")||e.includes("jest")||e.includes("test")))return!(!("undefined"!=typeof global&&"window"in global&&global.window&&"document"in global&&global.document)||process.env.OPTAVE_SDK_FORCE_SERVER_ENV)}if("undefined"!=typeof global){if(!("window"in global)&&!("document"in global)&&"undefined"!=typeof process&&process.versions&&process.versions.node)return!1;if((!("window"in global)||!("document"in global))&&"undefined"!=typeof process&&process.versions&&process.versions.node)return!1;if("window"in global&&global.window)return!0;if("document"in global&&global.document)return!0}try{if("undefined"!=typeof window&&null!==window)return("undefined"==typeof global||"window"in global)&&("undefined"==typeof global||"undefined"==typeof process||!process.versions||!process.versions.node||"window"in global);if("undefined"!=typeof document&&null!==document)return("undefined"==typeof global||"document"in global)&&("undefined"==typeof global||"undefined"==typeof process||!process.versions||!process.versions.node||"document"in global)}catch(e){}return"undefined"!=typeof navigator&&"ReactNative"===navigator.product||(!("undefined"==typeof global||!global.__expo)||("undefined"!=typeof location&&null!==location||("undefined"!=typeof process&&process.versions&&process.versions.node,!1)))};function P(e){const t=[];return!e.authenticationUrl||e.clientId&&e.clientSecret||t.push({type:"warning",code:"INCOMPLETE_AUTH_CONFIG",message:"authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.",field:"authentication"}),t}
+function g(e,t,s="validation",r={}){return{instancePath:e,message:t,keyword:s,params:r}}function f(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[g("","must be object","type",{type:"object"})]};const t=[];if(e.session?"object"!=typeof e.session?t.push(g("/session","must be object","type",{type:"object"})):void 0!==e.session.sessionId&&"string"!=typeof e.session.sessionId&&t.push(g("/session/sessionId","must be string","type",{type:"string"})):t.push(g("/session","is required","required",{missingProperty:"session"})),e.request)if("object"!=typeof e.request)t.push(g("/request","must be object","type",{type:"object"}));else{if(e.request.connections)if("object"!=typeof e.request.connections)t.push(g("/request/connections","must be object","type",{type:"object"}));else{e.request.connections.threadId?"string"!=typeof e.request.connections.threadId&&t.push(g("/request/connections/threadId","must be string","type",{type:"string"})):t.push(g("/request/connections/threadId","is required","required",{missingProperty:"threadId"})),void 0!==e.request.connections.parentId&&"string"!=typeof e.request.connections.parentId&&t.push(g("/request/connections/parentId","must be string","type",{type:"string"})),void 0!==e.request.connections.replyId&&"string"!=typeof e.request.connections.replyId&&t.push(g("/request/connections/replyId","must be string","type",{type:"string"}));const{replyTarget:s}=e.request.connections;if(void 0!==s){const e=["ai","self","none"];"string"!=typeof s?t.push(g("/request/connections/replyTarget","must be string","type",{type:"string"})):e.includes(s)||t.push(g("/request/connections/replyTarget","must be equal to one of the allowed values","enum",{allowedValues:e}))}}else t.push(g("/request/connections","is required","required",{missingProperty:"connections"}));if(void 0!==e.request.context&&"object"!=typeof e.request.context&&t.push(g("/request/context","must be object","type",{type:"object"})),void 0!==e.request.attributes&&"object"!=typeof e.request.attributes)t.push(g("/request/attributes","must be object","type",{type:"object"}));else if(e.request.attributes&&"object"==typeof e.request.attributes){const{replyTo:s}=e.request.attributes;if(void 0!==s){const e=["ai","self","none"];"string"!=typeof s?t.push(g("/request/attributes/replyTo","must be string","type",{type:"string"})):e.includes(s)||t.push(g("/request/attributes/replyTo","must be equal to one of the allowed values","enum",{allowedValues:e}))}}void 0!==e.request.scope&&("object"!=typeof e.request.scope?t.push(g("/request/scope","must be object","type",{type:"object"})):void 0!==e.request.scope.conversations&&(Array.isArray(e.request.scope.conversations)||t.push(g("/request/scope/conversations","must be array","type",{type:"array"})))),void 0!==e.request.resources&&("object"!=typeof e.request.resources?t.push(g("/request/resources","must be object","type",{type:"object"})):void 0!==e.request.resources.offers&&(Array.isArray(e.request.resources.offers)||t.push(g("/request/resources/offers","must be array","type",{type:"array"}))))}else t.push(g("/request","is required","required",{missingProperty:"request"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function y(e){if(!e||"object"!=typeof e)return{valid:!1,errors:[g("","must be object","type",{type:"object"})]};const t=[];if(e.headers)if("object"!=typeof e.headers)t.push(g("/headers","must be object","type",{type:"object"}));else{if(e.headers.correlationId?"string"!=typeof e.headers.correlationId&&t.push(g("/headers/correlationId","must be string","type",{type:"string"})):t.push(g("/headers/correlationId","is required","required",{missingProperty:"correlationId"})),e.headers.action)if("string"!=typeof e.headers.action)t.push(g("/headers/action","must be string","type",{type:"string"}));else{const s=["adjust","elevate","interaction","assistant","customerinteraction","reception","summarize","translate","recommend","insights"];s.includes(e.headers.action)||t.push(g("/headers/action","must be equal to one of the allowed values","enum",{allowedValues:s}))}else t.push(g("/headers/action","is required","required",{missingProperty:"action"}));void 0!==e.headers.identifier&&"string"!=typeof e.headers.identifier&&t.push(g("/headers/identifier","must be string","type",{type:"string"})),void 0!==e.headers.schemaRef&&"string"!=typeof e.headers.schemaRef&&t.push(g("/headers/schemaRef","must be string","type",{type:"string"})),void 0!==e.headers.timestamp&&"string"!=typeof e.headers.timestamp&&t.push(g("/headers/timestamp","must be string","type",{type:"string"}))}else t.push(g("/headers","is required","required",{missingProperty:"headers"}));if(e.payload){if("object"!=typeof e.payload)t.push(g("/payload","must be object","type",{type:"object"}));else if(e.headers&&e.headers.action&&e.payload){const{action:s}=e.headers;["adjust","elevate","interaction","assistant","customerinteraction","customerInteraction","summarize","translate","insights","recommend"].includes(s)&&(e.payload.request?e.payload.request.scope?e.payload.request.scope.conversations?Array.isArray(e.payload.request.scope.conversations)?0===e.payload.request.scope.conversations.length&&t.push(g("/payload/request/scope/conversations",`must be non-empty array for ${s}`,"minItems",{limit:1})):t.push(g("/payload/request/scope/conversations","must be array","type",{type:"array"})):t.push(g("/payload/request/scope/conversations",`is required for ${s}`,"required",{missingProperty:"conversations"})):t.push(g("/payload/request/scope","is required","required",{missingProperty:"scope"})):t.push(g("/payload/request","is required","required",{missingProperty:"request"})))}}else t.push(g("/payload","is required","required",{missingProperty:"payload"}));return t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}const b=`optave.message.v${"1.0.0".split(".")[0]}`,E={AUTHENTICATION:"AUTHENTICATION",ORCHESTRATOR:"ORCHESTRATOR",VALIDATION:"VALIDATION",WEBSOCKET:"WEBSOCKET"},v=Object.freeze({MESSAGE:"message",ERROR:"error"}),S=Object.freeze({CONNECTION_OPEN:"connection:open",CONNECTION_CLOSE:"connection:close",CONNECTION_ERROR:"connection:error",MESSAGE_RECEIVED:"message:received",MESSAGE_SENT:"message:sent",ERROR:"error",RESPONSE:"response",LEGACY_ERROR:"error",LEGACY_MESSAGE:"message"}),w=Object.freeze({SUPERPOWER_RESPONSE:"superpower.response",SUPERPOWER_ERROR:"superpower.error"}),I=new Set(["adjust","elevate","interaction","assistant","reception","customerInteraction","summarize","translate","recommend","insights"]),_={SPEC_VERSION:"1.0.0",SCHEMA_REF:b,MAX_PAYLOAD_SIZE:131072,MAX_PAYLOAD_SIZE_KB:128,DEFAULT_REQUEST_TIMEOUT_MS:3e4,ErrorCategory:E,LegacyEvents:v,EVENTS:S,InboundEvents:w,ALLOWED_ACTIONS:I};
/**
* Validates client-specific configuration and enforces security rules
* @param {Object} options - SDK options
* @returns {Array} Array of validation errors (empty if valid)
- */function D(e){const t=[];if(L()&&e.clientSecret){let e=!1,s=!1;try{e=!0}catch(e){}try{s=!1}catch(e){}const r=undefined;e||s||t.push({type:"error",code:"CLIENT_SECRET_IN_CLIENT_ENV",message:"clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.",field:"clientSecret"})}return t}function W(e){const t=[];return e.websocketUrl&&"string"==typeof e.websocketUrl||t.push({type:"warning",code:"MISSING_WEBSOCKET_URL",message:"websocketUrl not provided; openConnection() will emit an error.",field:"websocketUrl"}),t}function M(e){if(void 0===e.strictValidation){const t="undefined"!=typeof process&&process.env?"production":"development";e.strictValidation="production"!==t}if("number"!=typeof e.requestTimeoutMs&&(e.requestTimeoutMs=3e4),"number"!=typeof e.connectionTimeoutMs&&(e.connectionTimeoutMs=3e4),e.logger||(e.logger={debug(){},info(){},warn(){},error(){}}),e.authTransport||(e.authTransport="subprotocol"),void 0===e.authRequired&&(e.authRequired=!0),!e.tokenProvider){let t=e.tokenUrl;if(!t&&"undefined"!=typeof document){const e=document.querySelector('meta[name="optave-token-url"]');e&&e.content&&(t=e.content)}t||(t="/api/optave/ws-ticket"),e.tokenProvider=async()=>{const s={};e.publishableKey&&(s["X-Optave-Publishable-Key"]=e.publishableKey);const r=await fetch(t,{method:"POST",credentials:"include",headers:s});if(!r.ok)throw new Error("Failed to obtain WS token");const n=await r.json();return n.token||n.access_token}}return e}function j(e){const t={isValid:!0,errors:[],warnings:[]},s=undefined,r=undefined,n=undefined,o=[...W(e),...P(e),...D(e)];for(const e of o)"error"===e.type?(t.errors.push(e),t.isValid=!1):"warning"===e.type&&t.warnings.push(e);return t}const V={BROWSER_ESM:"browser-esm",SERVER_ESM:"server-esm",BROWSER_UMD:"browser-umd",SERVER_UMD:"server-umd"},K={browser:V.BROWSER_ESM,server:V.SERVER_ESM},$={BROWSER:[V.BROWSER_ESM,V.BROWSER_UMD,V.SERVER_UMD],SERVER:[V.SERVER_ESM],UMD:[V.BROWSER_UMD,V.SERVER_UMD],ESM:[V.BROWSER_ESM,V.SERVER_ESM]},B={isValid:e=>Object.values(V).includes(e)||Object.keys(K).includes(e),normalize:e=>K[e]?K[e]:Object.values(V).includes(e)?e:"unknown",isBrowser(e){const t=this.normalize(e);return $.BROWSER.includes(t)},isServer(e){const t=this.normalize(e);return $.SERVER.includes(t)},isUMD(e){const t=this.normalize(e);return $.UMD.includes(t)},isESM(e){const t=this.normalize(e);return $.ESM.includes(t)},getInfo(e){const t=undefined;return{original:e,normalized:this.normalize(e),valid:this.isValid(e),isBrowser:this.isBrowser(e),isServer:this.isServer(e),isUMD:this.isUMD(e),isESM:this.isESM(e)}}};class x extends Error{constructor({category:e,code:t,message:s,details:r}){super(s),this.name="OptaveError",this.category=e||"UNKNOWN",this.code=t||"UNKNOWN",void 0!==r&&(this.details=r)}}function z(e){return e&&e.category&&e.code&&e.message?new x(e):"string"==typeof e?new x({category:"UNKNOWN",code:"STRING_ERROR",message:e}):e&&"AjvValidationError"===e.name?new x({category:"VALIDATION",code:"SCHEMA_VALIDATION",message:e.message,details:e.errors}):e&&e.isAuthError?new x({category:"AUTHENTICATION",code:e.code||"AUTH_ERROR",message:e.message||"Authentication error",details:e}):e&&e.isWsError?new x({category:"WEBSOCKET",code:e.code||"WS_ERROR",message:e.message||"WebSocket error",details:e}):new x({category:"UNKNOWN",code:"UNCLASSIFIED",message:e&&e.message||String(null!=e?e:"Unknown error"),details:e})}async function F(){return null}// ./runtime/core/security-guards.js
+ */
+function T(e){const t=[];if((()=>{if("undefined"!=typeof process&&process.versions&&process.versions.node&&("true"===process.env.VITEST||void 0!==process.env.JEST_WORKER_ID||process.argv.some(e=>e.includes("vitest")||e.includes("jest")||e.includes("test"))))return!(!("undefined"!=typeof globalThis&&"window"in globalThis&&globalThis.window&&"document"in globalThis&&globalThis.document)||process.env.OPTAVE_SDK_FORCE_SERVER_ENV);if("undefined"!=typeof globalThis){if(!("window"in globalThis)&&!("document"in globalThis)&&"undefined"!=typeof process&&process.versions&&process.versions.node)return!1;if((!("window"in globalThis)||!("document"in globalThis))&&"undefined"!=typeof process&&process.versions&&process.versions.node)return!1;if("window"in globalThis&&globalThis.window)return!0;if("document"in globalThis&&globalThis.document)return!0}try{if("undefined"!=typeof window&&null!==window)return!("undefined"!=typeof globalThis&&!("window"in globalThis)||"undefined"!=typeof globalThis&&"undefined"!=typeof process&&process.versions&&process.versions.node&&!("window"in globalThis));if("undefined"!=typeof document&&null!==document)return!("undefined"!=typeof globalThis&&!("document"in globalThis)||"undefined"!=typeof globalThis&&"undefined"!=typeof process&&process.versions&&process.versions.node&&!("document"in globalThis))}catch(e){}return"undefined"!=typeof navigator&&"ReactNative"===navigator.product||!("undefined"==typeof globalThis||!globalThis.__expo)||void 0!==globalThis.location&&null!==globalThis.location||("undefined"!=typeof process&&process.versions&&process.versions.node,!1)})()&&e.clientSecret){let e=!1,s=!1;try{e=!1}catch(e){}try{s=!1}catch(e){}e||s||t.push({type:"error",code:"CLIENT_SECRET_IN_CLIENT_ENV",message:"clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.",field:"clientSecret"})}return t}const O=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i,A=/^\s*-?\d{1,3}(?:\.\d+)?\s*,\s*-?\d{1,3}(?:\.\d+)?\s*$/,R=new Set(["email","e-mail","fullname","firstname","lastname","displayname","phone","phonenumber","ssn","dateofbirth","dob","nationalid"]);function k(e,t,s={}){return{instancePath:e,message:t,keyword:"piGuard",params:s}}function q(e,t,s){null!=e&&("string"!=typeof e?Array.isArray(e)?e.forEach((e,r)=>q(e,`${t}/${r}`,s)):"object"==typeof e&&Object.entries(e).forEach(([e,r])=>{R.has(e.toLowerCase())&&s.push(k(`${t}/${e}`,`must not carry direct identifier key '${e}'`,{kind:"identifierKey",key:e})),q(r,`${t}/${e}`,s)}):function(e,t,s){"string"==typeof e&&0!==e.length&&(O.test(e)&&s.push(k(t,"must not contain an email address",{kind:"email"})),A.test(e)&&s.push(k(t,"must not contain precise coordinates",{kind:"coordinates"})),function(e){if("string"!=typeof e)return!1;const t=e.trim();return!!(t.includes("\n")&&t.length>40)||!!(t.length>160&&/\s/.test(t)&&/[.!?]/.test(t))}(e)&&s.push(k(t,"must not contain message content or other direct identifiers",{kind:"messageContent"})))}(e,t,s))}function C(e){if(!e||"object"!=typeof e)return{valid:!0,errors:null};const t=[],s=e.session?.channel?.location;return"string"==typeof s&&s&&A.test(s)&&t.push(k("/session/channel/location","must be province grain at most, never precise coordinates",{kind:"coordinates"})),void 0!==e.session?.channel?.metadata&&q(e.session.channel.metadata,"/session/channel/metadata",t),void 0!==e.request?.reference&&q(e.request.reference,"/request/reference",t),t.length>0?{valid:!1,errors:t}:{valid:!0,errors:null}}function N(e){return t=>{const s=e(t);return s.valid?C(t):s}}const U={BROWSER_ESM:"browser-esm",SERVER_ESM:"server-esm",BROWSER_UMD:"browser-umd",SERVER_UMD:"server-umd"},P={browser:U.BROWSER_ESM,server:U.SERVER_ESM},D={BROWSER:[U.BROWSER_ESM,U.BROWSER_UMD],SERVER:[U.SERVER_ESM,U.SERVER_UMD],UMD:[U.BROWSER_UMD,U.SERVER_UMD],ESM:[U.BROWSER_ESM,U.SERVER_ESM]},W={isValid:e=>Object.values(U).includes(e)||Object.keys(P).includes(e),normalize:e=>P[e]?P[e]:Object.values(U).includes(e)?e:"unknown",isBrowser(e){const t=this.normalize(e);return D.BROWSER.includes(t)},isServer(e){const t=this.normalize(e);return D.SERVER.includes(t)},isUMD(e){const t=this.normalize(e);return D.UMD.includes(t)},isESM(e){const t=this.normalize(e);return D.ESM.includes(t)},getInfo(e){return{original:e,normalized:this.normalize(e),valid:this.isValid(e),isBrowser:this.isBrowser(e),isServer:this.isServer(e),isUMD:this.isUMD(e),isESM:this.isESM(e)}}};class OptaveError extends Error{constructor({category:e,code:t,message:s,details:r}){super(s),this.name="OptaveError",this.category=e||"UNKNOWN",this.code=t||"UNKNOWN",void 0!==r&&(this.details=r)}}var M=o(2);!
+/**
+ * Initialize security guards on module load
+ * This ensures the security validation code is evaluated and cannot be tree-shaken
+ */
+function(){
+// SECURITY: Module-level side effect to prevent tree-shaking
+if("undefined"!=typeof globalThis){
+// Mark security guards as active - this creates a side effect
+globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__=!0;if(!globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__)throw new Error("Security guard initialization failed")}}(),"undefined"!=typeof window?
+// Browser environment - ensure security guards are active
+window.__OPTAVE_SECURITY_GUARDS_BROWSER__=!0:"undefined"!=typeof globalThis&&(
+// Node.js environment - ensure security guards are active.
+// Function constructor and would violate Salesforce Lightning Locker CSP.
+globalThis.__OPTAVE_SECURITY_GUARDS_NODE__=!0);var L=o(31).I;const V="3.6.0",j=()=>{const e="server-umd";return{isBrowser:W.isBrowser(e),isServer:W.isServer(e),buildTarget:e}};let $=!1,K=!1;class OptaveJavaScriptSDK extends i{options={};wss=null;static defaultPayload={session:{sessionId:"",channel:{browser:"",deviceInfo:"",deviceType:"",language:"",location:"",medium:"chat",metadata:[],section:""},interface:{appVersion:"",category:"",language:"",name:"",type:""}},request:{requestId:"",attributes:{content:"",instruction:"",variant:"A"},connections:{journeyId:"",parentId:"",replyId:"",threadId:""},context:{caseId:"",departmentId:"",operatorId:"",organizationId:"",userId:""},reference:{ids:[{name:"",value:""}],labels:[],tags:[]},resources:{codes:[{id:"",label:"",type:"",value:""}],links:[{expires_at:"",html:!1,id:"",label:"",type:"",url:""}],offers:[]},scope:{accounts:[],appointments:[],assets:[],bookings:[],cases:[],conversations:[],documents:[],events:[],interactions:[],items:[],locations:[],operators:[],orders:[],organizations:[],persons:[],policies:[],products:[{id:""}],properties:[],services:[],subscriptions:[],tickets:[],transactions:[],users:[]},settings:{disableBrowsing:!1,disableSearch:!1,disableSources:!1,disableStream:!0,disableTools:!1,maxResponseLength:0,overrideInterfaceLanguage:"",overrideOutputLanguage:""},a2a:[{id:"",name:"",type:""}],cursor:{since:"",until:""}}};static cleanup(){$=!1,K=!1}constructor(e){if(super(),this.options={...e},function(e){if(void 0===e.strictValidation){const t="undefined"!=typeof process&&process.env?"production":"development";e.strictValidation="production"!==t}if("number"!=typeof e.requestTimeoutMs&&(e.requestTimeoutMs=3e4),"number"!=typeof e.connectionTimeoutMs&&(e.connectionTimeoutMs=3e4),e.logger||(e.logger={debug(){},info(){},warn(){},error(){}}),e.authTransport||(e.authTransport="subprotocol"),void 0===e.authRequired&&(e.authRequired=!0),!e.tokenProvider){let t=e.tokenUrl;if(!t&&"undefined"!=typeof document){const e=document.querySelector('meta[name="optave-token-url"]');e&&e.content&&(t=e.content)}t||(t="/api/optave/ws-ticket"),e.tokenProvider=async()=>{const s={};e.publishableKey&&(s["X-Optave-Publishable-Key"]=e.publishableKey);const r=await fetch(t,{method:"POST",credentials:"include",headers:s});if(!r.ok)throw new Error("Failed to obtain WS token");const o=await r.json();return o.token||o.access_token}}}(this.options),void 0===this.options.cspSafe){const e=j();"server-esm"===e.buildTarget||"server"===e.buildTarget?this.options.cspSafe=!1:("browser-esm"===e.buildTarget||"browser-umd"===e.buildTarget||"server-umd"===e.buildTarget||e.isBrowser||(()=>{const e=j();return"unknown"!==e.buildTarget?e.isBrowser:"undefined"!=typeof window&&void 0!==window.WebSocket})())&&(this.options.cspSafe=!0)}const t=function(e){const t={isValid:!0,errors:[],warnings:[]},s=function(e){const t=[];return e.websocketUrl&&"string"==typeof e.websocketUrl||t.push({type:"warning",code:"MISSING_WEBSOCKET_URL",message:"websocketUrl not provided; openConnection() will emit an error.",field:"websocketUrl"}),t}(e),r=function(e){const t=[];return!e.authenticationUrl||e.clientId&&e.clientSecret||t.push({type:"warning",code:"INCOMPLETE_AUTH_CONFIG",message:"authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.",field:"authentication"}),t}(e);return[...s,...r,...T(e)].forEach(e=>{"error"===e.type?(t.errors.push(e),t.isValid=!1):"warning"===e.type&&t.warnings.push(e)}),t}(this.options);if(!t.isValid){const e=t.errors.map(e=>e.message).join("; ");throw new Error(`[Optave SDK] Configuration errors: ${e}`)}t.warnings.forEach(e=>{(this.options?.logger?.warn||console.warn)(`[Optave SDK] ${e.message}`)});
+// Use canonical security guard - single source of truth for WebSocket validation.
+// Any thrown security error propagates to the caller (no try/catch needed - it would only rethrow).
+!// ./runtime/core/security-guards.js
/**
* Critical Security Guards for Optave SDK
*
@@ -37,55 +63,35 @@ function y(e,t,s="validation",r={}){return{instancePath:e,message:t,keyword:s,pa
* @throws {Error} When ws:// protocol is used in UMD builds
* @throws {Error} When tokenProvider is missing for secure connections in UMD builds
*/
-function H(e,t,s={}){if(
-// SECURITY: Explicitly mark as having side effects - do not optimize away
-1,!e||"string"!=typeof e)return;const r=B.normalize(t),n=B.isUMD(r),o=B.isBrowser(r);
-// CRITICAL: Validate WebSocket scheme for UMD and browser builds
-// This guard prevents insecure connections in Salesforce Lightning
-if((n||o)&&e.startsWith("ws://")){
-// SECURITY: This error message must remain intact to guide developers
-const t=undefined;
+function(e,t,s={}){
+// SECURITY: This function has observable side effects (throws on invalid schemes and
+// sets a global marker via initializeSecurityGuards) so bundlers must not optimize it away.
+if(!e||"string"!=typeof e)return;const r=W.normalize(t),o=W.isBrowser(r);
+// Browser builds include: browser-esm and browser-umd (Salesforce/Lightning)
+// CRITICAL: Validate WebSocket scheme for browser-targeted builds only
+// This guard prevents insecure connections in Salesforce Lightning and browser environments
+if(o&&e.startsWith("ws://"))
// CRITICAL: This throw statement is a security boundary - must not be removed
-throw new Error(`[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in UMD builds. Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. Please use secure WebSocket protocol (wss://) instead. Current URL: ${e}`)}
-// CRITICAL: For UMD builds with secure WebSocket URLs, validate token provider availability
-if(n&&e.startsWith("wss://")){const t="function"==typeof s.tokenProvider,r=!1===s.authRequired;if(!t&&!r){
-// SECURITY: This error message must remain intact to guide developers
-const t=undefined;
+throw new Error(`[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in browser builds. Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. Please use secure WebSocket protocol (wss://) instead. Current URL: ${e}`);
+// CRITICAL: For browser UMD builds with secure WebSocket URLs, validate token provider availability
+// This prevents authentication bypass in constrained Salesforce Lightning environments
+const n=W.isUMD(r);if(o&&n&&e.startsWith("wss://")){const t="function"==typeof s.tokenProvider,r=!1===s.authRequired;if(!t&&!r)
// CRITICAL: This throw statement is a security boundary - must not be removed
-throw new Error(`[Optave SDK] UMD builds require a tokenProvider function for secure WebSocket connections. In constrained environments like Salesforce Lightning, authentication tokens must be obtained from your backend server. Please provide options.tokenProvider() that returns a valid token, or set options.authRequired = false to disable authentication. Current URL: ${e}`)}}}
-/**
- * Initialize security guards on module load
- * This ensures the security validation code is evaluated and cannot be tree-shaken
- */function G(){
-// SECURITY: Module-level side effect to prevent tree-shaking
-if("undefined"!=typeof globalThis){
-// Mark security guards as active - this creates a side effect
-globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__=!0;const e=undefined;if(!globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__)throw new Error("Security guard initialization failed")}"undefined"!=typeof process&&process.env,0}G(),"undefined"!=typeof window?
-// Browser environment - ensure security guards are active
-window.__OPTAVE_SECURITY_GUARDS_BROWSER__=!0:"undefined"!=typeof global&&(
-// Node.js environment - ensure security guards are active
-global.__OPTAVE_SECURITY_GUARDS_NODE__=!0);var Y=s(31).I;const J="3.2.3",Q=()=>{const e="server-umd";return{isBrowser:B.isBrowser(e),isServer:B.isServer(e),buildTarget:e}},X=()=>{const e=Q();return"unknown"!==e.buildTarget?e.isBrowser:"undefined"!=typeof window&&void 0!==window.WebSocket};let Z=!1,ee=!1;class OptaveJavaScriptSDK extends n{options={};wss=null;static defaultPayload={session:{sessionId:"",channel:{browser:"",deviceInfo:"",deviceType:"",language:"",location:"",medium:"chat",metadata:[],section:""},interface:{appVersion:"",category:"",language:"",name:"",type:""}},request:{requestId:"",attributes:{content:"",instruction:"",variant:"A"},connections:{journeyId:"",parentId:"",threadId:""},context:{caseId:"",departmentId:"",operatorId:"",organizationId:"",userId:""},reference:{ids:[{name:"",value:""}],labels:[],tags:[]},resources:{codes:[{id:"",label:"",type:"",value:""}],links:[{expires_at:"",html:!1,id:"",label:"",type:"",url:""}],offers:[]},scope:{accounts:[],appointments:[],assets:[],bookings:[],cases:[],conversations:[],documents:[],events:[],interactions:[],items:[],locations:[],operators:[],orders:[],organizations:[],persons:[],policies:[],products:[{id:""}],properties:[],services:[],subscriptions:[],tickets:[],transactions:[],users:[]},settings:{disableBrowsing:!1,disableSearch:!1,disableSources:!1,disableStream:!0,disableTools:!1,maxResponseLength:0,overrideInterfaceLanguage:"",overrideOutputLanguage:""},a2a:[{id:"",name:"",type:""}],cursor:{since:"",until:""}}};static cleanup(){Z=!1,ee=!1}constructor(e){if(super(),this.options={...e},M(this.options),void 0===this.options.cspSafe){const e=Q();"server-esm"===e.buildTarget||"server"===e.buildTarget?this.options.cspSafe=!1:("server-umd"===e.buildTarget||"browser-esm"===e.buildTarget||"browser-umd"===e.buildTarget||e.isBrowser||X())&&(this.options.cspSafe=!0)}const t=j(this.options);if(!t.isValid){const e=t.errors.map(e=>e.message).join("; ");throw new Error(`[Optave SDK] Configuration errors: ${e}`)}t.warnings.forEach(e=>{(this.options?.logger?.warn||console.warn)(`[Optave SDK] ${e.message}`)});
-// SECURITY: This validation is critical for Salesforce Lightning security - must not be removed by tree-shaking
-const s="server-umd";try{
-// Use canonical security guard - single source of truth for WebSocket validation
-H(this.options.websocketUrl,s,this.options)}catch(e){
-// Re-throw security errors immediately - this prevents minification from removing the try/catch
-throw e}const r=Q();this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&r.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&r.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this._pending=new Map,this._deprecatedKeys=new Set,this._silenceDeprecations="undefined"!=typeof process&&"1"===process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS,this.options.cspSafe,this._validatePayload=v,this._validateMessageEnvelope=b}async _ensureWebSocketImpl(){if(this.WebSocketImpl)return this.WebSocketImpl;const e=Q();return this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&e.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&e.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this.WebSocketImpl||(e.isBrowser?this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:null:e.isServer&&(this.WebSocketImpl=await this.loadNodeWebSocket())),this.WebSocketImpl}async loadNodeWebSocket(){const e=Q();return e.isBrowser?null:("unknown"!==e.buildTarget||"undefined"==typeof window&&"undefined"==typeof document&&"undefined"==typeof navigator&&"undefined"==typeof location)&&"undefined"!=typeof process&&process.versions&&process.versions.node?await F():null}static getSdkVersion(){return J}static getSpecVersion(){return S}static getSchemaRef(){return _}static get CONSTANTS(){return U}static get LegacyEvents(){return O}static get InboundEvents(){return A}setSessionId(e){return this.sessionId=e,this}getSessionId(){return this.sessionId||""}validate(e){const t=undefined;return this._validatePayload(e).valid}validateEnvelope(e){const t=undefined;return this._validateMessageEnvelope(e).valid}validateRequiredFields(e,t){const s=[];switch(e.request?.connections?.threadId||s.push("request.connections.threadId is required"),t){case"adjust":e.request?.attributes?.content||s.push("request.attributes.content is required for adjust"),e.request?.attributes?.instruction||s.push("request.attributes.instruction is required for adjust"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for adjust"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for adjust and must be a non-empty array");break;case"elevate":e.request?.attributes?.content||s.push("request.attributes.content is required for elevate"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for elevate"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for elevate and must be a non-empty array");break;case"translate":case"summarize":case"insights":case"customerinteraction":case"customerInteraction":case"interaction":e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push(`request.scope.conversations is required for ${t} and must be a non-empty array`);break;case"recommend":e.request?.resources?.offers&&Array.isArray(e.request.resources.offers)&&0!==e.request.resources.offers.length||s.push("request.resources.offers is required for recommend and must be a non-empty array"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for recommend and must be a non-empty array")}return{isValid:0===s.length,errors:s}}async authenticate(){
-// Browser-targeted builds should not use client credentials for security
-const e="server-umd",t=undefined;if(B.isBrowser(e))return this.handleError(I.AUTHENTICATION,"UNSUPPORTED_IN_BROWSER","authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend."),null;let s={grant_type:"client_credentials"};if(!this.options.authenticationUrl)return this.handleError(I.AUTHENTICATION,"INVALID_AUTHENTICATION_URL","Empty or invalid authentication URL"),null;if(!this.options.clientId)return this.handleError(I.AUTHENTICATION,"INVALID_CLIENT_ID","Empty or invalid client ID"),null;s.client_id=this.options.clientId,s.client_secret=this.options.clientSecret;const r=new Y(s).toString();let n=this.options.authenticationUrl;n.endsWith("/token")||(n=n.endsWith("/")?n+"token":n+"/token");const o=`${n}?${r}`,i=await fetch(o,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"}}),a=await i.json();return i.ok?a.access_token:(this.handleError(I.AUTHENTICATION,"INVALID_AUTHENTICATION_RESPONSE",this.formatAuthenticationError(i,a.error,"token endpoint").message,a.error),null)}async openConnection(e){if(!this.options.websocketUrl)return(this.options?.logger?.error||console.error)("[Optave SDK] openConnection aborted: missing websocketUrl"),this.handleError(I.WEBSOCKET,"INVALID_WEBSOCKET_URL",this.formatWebSocketError(new Error("Invalid WebSocket URL configuration"),{url:this.options.websocketUrl}).message,this.options.websocketUrl),void 0;const t=async()=>{if("string"==typeof e&&e.length>0)return e;if("function"==typeof this.options.tokenProvider)try{return await this.options.tokenProvider()}catch(e){return this.handleError(I.AUTHENTICATION,"TOKEN_PROVIDER_FAILED",this.formatTokenProviderError(e).message,e),null}return null},s=await t();if(await this._ensureWebSocketImpl(),!this.WebSocketImpl)return this.handleError(I.WEBSOCKET,"NO_WEBSOCKET_IMPL",this.formatWebSocketError(new Error("No WebSocket implementation available"),{environment:"undefined"!=typeof window?"browser":"node"}).message),void 0;if(!s&&!1!==this.options.authRequired)return this.handleError(I.AUTHENTICATION,"MISSING_TOKEN","No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl."),void 0;const r=new Y;this.sessionId&&r.set("OptaveTraceChatSessionId",this.sessionId);try{if("subprotocol"===this.options.authTransport){const e=s?["optave-v1",s]:["optave-v1"];this.wss=new this.WebSocketImpl(r.toString()?`${this.options.websocketUrl}?${r.toString()}`:this.options.websocketUrl,e)}else{if(s){const e=s.replace(/^Bearer\s+/i,"");r.set("Authorization",e)}this.wss=new this.WebSocketImpl(r.toString()?`${this.options.websocketUrl}?${r.toString()}`:this.options.websocketUrl),s&&this._warnOnce("_warnedQueryToken",'[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".')}}catch(e){return(this.options?.logger?.error||console.error)("[Optave SDK] WebSocket constructor threw",e),this.handleError(I.WEBSOCKET,"WEBSOCKET_ERROR",this.formatWebSocketError(e,{url:this.options.websocketUrl}).message,e),void 0}return new Promise((e,t)=>{const s=setTimeout(()=>{const e=this.options.connectionTimeoutMs||3e4,s=this.formatWebSocketError(new Error("Connection timeout"),{timeout:e,url:this.options.websocketUrl}).message;
+throw new Error(`[Optave SDK] Browser UMD builds require a tokenProvider function for secure WebSocket connections. In constrained environments like Salesforce Lightning, authentication tokens must be obtained from your backend server. Please provide options.tokenProvider() that returns a valid token, or set options.authRequired = false to disable authentication. Current URL: ${e}`)}}(this.options.websocketUrl,"server-umd",this.options);const s=j();this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&s.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&s.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this._pending=new Map,this._deprecatedKeys=new Set,this._silenceDeprecations="undefined"!=typeof process&&"1"===process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS,this.options.cspSafe,this._validatePayload=N(f),this._validateMessageEnvelope=y}async _ensureWebSocketImpl(){if(this.WebSocketImpl)return this.WebSocketImpl;const e=j();return this.WebSocketImpl=this.options.WebSocketImpl,!this.WebSocketImpl&&e.isBrowser?this.WebSocketImpl=("undefined"!=typeof WebSocket?WebSocket:void 0)||("undefined"!=typeof window&&window.WebSocket?window.WebSocket:void 0):!this.WebSocketImpl&&e.isServer&&(this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:void 0),this.WebSocketImpl||(e.isBrowser?this.WebSocketImpl="undefined"!=typeof WebSocket?WebSocket:null:e.isServer&&(this.WebSocketImpl=await this.loadNodeWebSocket())),this.WebSocketImpl}async loadNodeWebSocket(){const e=j();return e.isBrowser?null:("unknown"!==e.buildTarget||"undefined"==typeof window&&"undefined"==typeof document&&"undefined"==typeof navigator&&void 0===globalThis.location)&&"undefined"!=typeof process&&process.versions&&process.versions.node?async function(){return"undefined"!=typeof window||"undefined"!=typeof document||"undefined"!=typeof navigator||void 0!==globalThis.location?null:"undefined"!=typeof process&&process.versions&&process.versions.node?M:null}():null}static getSdkVersion(){return V}static getSpecVersion(){return"1.0.0"}static getSchemaRef(){return b}static get CONSTANTS(){return _}static get LegacyEvents(){return v}static get InboundEvents(){return w}setSessionId(e){return this.sessionId=e,this}getSessionId(){return this.sessionId||""}validate(e){return this._validatePayload(e).valid}validateEnvelope(e){return this._validateMessageEnvelope(e).valid}_validateOutboundPayload(e){return this.options.strictValidation?this._validatePayload(e):C(e)}validateRequiredFields(e,t){const s=[];switch(e.request?.connections?.threadId||s.push("request.connections.threadId is required"),t){case"adjust":e.request?.attributes?.content||s.push("request.attributes.content is required for adjust"),e.request?.attributes?.instruction||s.push("request.attributes.instruction is required for adjust"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for adjust"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for adjust and must be a non-empty array");break;case"elevate":e.request?.attributes?.content||s.push("request.attributes.content is required for elevate"),e.request?.connections?.parentId||s.push("request.connections.parentId is required for elevate"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for elevate and must be a non-empty array");break;case"translate":case"summarize":case"insights":case"customerinteraction":case"customerInteraction":case"interaction":case"assistant":e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push(`request.scope.conversations is required for ${t} and must be a non-empty array`);break;case"recommend":e.request?.resources?.offers&&Array.isArray(e.request.resources.offers)&&0!==e.request.resources.offers.length||s.push("request.resources.offers is required for recommend and must be a non-empty array"),e.request?.scope?.conversations&&Array.isArray(e.request.scope.conversations)&&0!==e.request.scope.conversations.length||s.push("request.scope.conversations is required for recommend and must be a non-empty array")}return{isValid:0===s.length,errors:s}}async authenticate(){if(W.isBrowser("server-umd"))return this.handleError(E.AUTHENTICATION,"UNSUPPORTED_IN_BROWSER","authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend."),null;const e={grant_type:"client_credentials"};if(!this.options.authenticationUrl)return this.handleError(E.AUTHENTICATION,"INVALID_AUTHENTICATION_URL","Empty or invalid authentication URL"),null;if(!this.options.clientId)return this.handleError(E.AUTHENTICATION,"INVALID_CLIENT_ID","Empty or invalid client ID"),null;e.client_id=this.options.clientId,e.client_secret=this.options.clientSecret;const t=new L(e).toString();let s=this.options.authenticationUrl;s.endsWith("/token")||(s=s.endsWith("/")?`${s}token`:`${s}/token`);const r=`${s}?${t}`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"}}),n=await o.json();return o.ok?n.access_token:(this.handleError(E.AUTHENTICATION,"INVALID_AUTHENTICATION_RESPONSE",this.formatAuthenticationError(o,n.error,"token endpoint").message,n.error),null)}async openConnection(e){if(!this.options.websocketUrl)return(this.options?.logger?.error||console.error)("[Optave SDK] openConnection aborted: missing websocketUrl"),void this.handleError(E.WEBSOCKET,"INVALID_WEBSOCKET_URL",this.formatWebSocketError(new Error("Invalid WebSocket URL configuration"),{url:this.options.websocketUrl}).message,this.options.websocketUrl);const t=await(async()=>{if("string"==typeof e&&e.length>0)return e;if("function"==typeof this.options.tokenProvider)try{return await this.options.tokenProvider()}catch(e){return this.handleError(E.AUTHENTICATION,"TOKEN_PROVIDER_FAILED",this.formatTokenProviderError(e).message,e),null}return null})();if(await this._ensureWebSocketImpl(),!this.WebSocketImpl)return void this.handleError(E.WEBSOCKET,"NO_WEBSOCKET_IMPL",this.formatWebSocketError(new Error("No WebSocket implementation available"),{environment:"undefined"!=typeof window?"browser":"node"}).message);if(!t&&!1!==this.options.authRequired)return void this.handleError(E.AUTHENTICATION,"MISSING_TOKEN","No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.");const s=new L;this.sessionId&&s.set("OptaveTraceChatSessionId",this.sessionId);try{if("subprotocol"===this.options.authTransport){const e=t?["optave-v1",t]:["optave-v1"];this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl,e)}else{if(t){const e=t.replace(/^Bearer\s+/i,"");s.set("Authorization",e)}this.wss=new this.WebSocketImpl(s.toString()?`${this.options.websocketUrl}?${s.toString()}`:this.options.websocketUrl),t&&this._warnOnce("_warnedQueryToken",'[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".')}}catch(e){return(this.options?.logger?.error||console.error)("[Optave SDK] WebSocket constructor threw",e),void this.handleError(E.WEBSOCKET,"WEBSOCKET_ERROR",this.formatWebSocketError(e,{url:this.options.websocketUrl}).message,e)}return new Promise((e,t)=>{const s=setTimeout(()=>{const e=this.options.connectionTimeoutMs||3e4,s=this.formatWebSocketError(new Error("Connection timeout"),{timeout:e,url:this.options.websocketUrl}).message;
// CRITICAL: Close the WebSocket to prevent zombie connections
-if(this.wss){this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null;try{this.wss.close()}catch(e){}this.wss=null}this.handleError(I.WEBSOCKET,"CONNECTION_TIMEOUT",s),t({category:I.WEBSOCKET,code:"CONNECTION_TIMEOUT",message:s,details:null})},this.options.connectionTimeoutMs||3e4);this.wss.onopen=t=>{clearTimeout(s),this.emit("open",t),e(t)},this.wss.onmessage=e=>{this._handleInbound(e.data)},this.wss.onclose=e=>{clearTimeout(s),this.emit("close",e);
+if(this.wss){this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null;try{this.wss.close()}catch(e){}this.wss=null}this.handleError(E.WEBSOCKET,"CONNECTION_TIMEOUT",s),t(new OptaveError({category:E.WEBSOCKET,code:"CONNECTION_TIMEOUT",message:s,details:null}))},this.options.connectionTimeoutMs||3e4);this.wss.onopen=t=>{clearTimeout(s),this.emit("open",t),e(t)},this.wss.onmessage=e=>{this._handleInbound(e.data)},this.wss.onclose=e=>{clearTimeout(s),this.emit("close",e),
// CRITICAL: Race condition prevention for promise handling
-for(const[t,s]of this._pending.entries())s.timer&&clearTimeout(s.timer),s._handled=!0,s.reject({category:I.WEBSOCKET,code:"CONNECTION_CLOSED",message:`WebSocket connection closed: ${e.reason||"Connection lost"}`,details:{code:e.code,reason:e.reason,correlationId:t},correlationId:t});this._pending.clear(),this.wss=null},this.wss.onerror=e=>{clearTimeout(s);
+Array.from(this._pending.entries()).forEach(([t,s])=>{s.timer&&clearTimeout(s.timer),s._handled=!0,s.reject({category:E.WEBSOCKET,code:"CONNECTION_CLOSED",message:`WebSocket connection closed: ${e.reason||"Connection lost"}`,details:{code:e.code,reason:e.reason,correlationId:t},correlationId:t})}),this._pending.clear(),this.wss=null},this.wss.onerror=e=>{clearTimeout(s);
// CRITICAL: Enhanced error message handling and race condition prevention
-const r=e.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||"WebSocket connection failed",n={category:I.WEBSOCKET,code:"CONNECTION_ERROR",message:r,details:{originalError:e}};for(const[e,t]of this._pending.entries())t.timer&&clearTimeout(t.timer),t._handled=!0,t.reject({...n,details:{...n.details,correlationId:e},correlationId:e});this._pending.clear(),this.emit("error",n),t(n)}})}_warnOnce(e,t){this[e]||(this[e]=!0,(this.options?.logger?.warn||console.warn)(t))}deprecate(e,t){this._silenceDeprecations||this._deprecatedKeys.has(e)||(this._deprecatedKeys.add(e),(this.options?.logger?.warn||console.warn)(t))}_handleInbound(e){let t;try{t="string"==typeof e?JSON.parse(e):e}catch(e){const t={category:I.WEBSOCKET,code:"INVALID_JSON",message:"Invalid JSON received from server",details:e,timestamp:(new Date).toISOString()};return this._emitError(t),void 0}const s=t&&t.headers&&t.payload,r="error"===t?.state||"error"===t?.actionType||!!t?.error;if(this.options.strictValidation&&s){const e=this._validateMessageEnvelope(t);e.valid||this.handleError(I.VALIDATION,"INBOUND_ENVELOPE_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Inbound envelope validation failed"),e.errors)}if(r){const e=t?.headers&&t.headers.correlationId||t?.correlationId||null,s={category:I.ORCHESTRATOR,code:t?.error?.code||"REMOTE_ERROR",message:t?.error?.message||t?.message||"Remote error",details:t?.error||t,correlationId:e};if(e&&this._pending.has(e)){const t=this._pending.get(e);t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),t.reject(s)}return this._emitError(s,t?.action),void 0}const n=t?.headers?.correlationId||t?.correlationId;if(n&&this._pending.has(n)){const e=this._pending.get(n);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(n),e.resolve(t)}this.emit(O.MESSAGE,t),Z||(Z=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".')),this.emit(A.SUPERPOWER_RESPONSE,t),this.emit(T.RESPONSE,t),t?.action&&this.emit(`message.${t.action}`.toLowerCase(),t),s&&t.headers.schemaRef&&this.emit(t.headers.schemaRef,t)}_emitError(e,t=null){e.timestamp||(e.timestamp=(new Date).toISOString()),this.emit(O.ERROR,e),ee||(ee=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'));const s=z(e);this.emit(A.SUPERPOWER_ERROR,s),this.emit(T.ERROR,e)}closeConnection(){this.wss&&(this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null,this.wss.close(),this.wss=null)}selectiveDeepMerge(e,t){if(Array.isArray(e)&&Array.isArray(t))return[...t];const s=e=>null!==e&&"object"==typeof e&&!Array.isArray(e);if(s(e)&&s(t)){const s={...e};for(let r in t)s[r]=r in e?this.selectiveDeepMerge(e[r],t[r]):t[r];return s}return void 0!==t?t:e}isPayloadSizeValid(e){return!!e&&e.length/1024<=U.MAX_PAYLOAD_SIZE_KB}openConnectionAsync(e){return new Promise((t,s)=>{const r=e=>{this.off("error",n),t(e)},n=e=>{this.off("open",r),s(e)};this.once("open",r),this.once("error",n),this.openConnection(e)})}buildPayload(e,t,s){let r=this.selectiveDeepMerge(OptaveJavaScriptSDK.defaultPayload,s);return s?.request?.variation&&(this.deprecate("payload.request.variation","[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."),r.request.attributes.variant=s.request.variation),s?.request?.content&&!r.request?.attributes?.content&&(r.request.attributes.content=s.request.content,this.deprecate("payload.request.content","[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.")),r.request.attributes.variant&&(r.request.attributes.variant=r.request.attributes.variant.toUpperCase()),r}resolveMessageId(e,t){return`${t}.${e}.v3`.toLowerCase()}buildMessageEnvelope(e,t,s,r={}){const n=(new Date).toISOString(),o=r.correlationId||e?.request?.requestId||g(),i=r.traceId||g(),a=r.idempotencyKey||g(),c=r.timestamp,d=undefined,u={correlationId:o,action:s,schemaRef:_,sdkVersion:J,identifier:t,traceId:i,idempotencyKey:a,timestamp:c,issuedAt:n};return this.options.tenantId&&(u.tenantId=this.options.tenantId),void 0!==r.networkLatencyMs&&(u.networkLatencyMs=r.networkLatencyMs),Object.freeze(u),{action:"message",headers:u,payload:e}}formatValidationErrorMessage(e,t="Validation failed"){if(!e||!Array.isArray(e)||0===e.length)return t;if(1===e.length){const s=e[0],r=s.instancePath||"/",n="/"===r?"root object":r.replace(/^\//,"").replace(/\//g,".");if("required"===s.keyword){const e=s.params?.missingProperty||"unknown field",r="root object"===n?e:n.endsWith(e)?n:n+"."+e;return`${t}: ${"root object"===n?"Required field":"Field"} '${r}' is missing`}if("type"===s.keyword){const e=undefined;return`${t}: Field '${n}' must be of type '${s.params?.type||"unknown"}'`}if("additionalProperties"===s.keyword){const e=undefined;return`${t}: Field '${n}.${s.params?.additionalProperty||"unknown"}' is not allowed`}if("enum"===s.keyword){const e=s.params?.allowedValues||[],r=undefined;return`${t}: Field '${n}' must be one of: ${Array.isArray(e)?e.join(", "):"unknown values"}`}return`${t}: ${s.message} at '${n}'`}
+const r=e.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||"WebSocket connection failed",o={category:E.WEBSOCKET,code:"CONNECTION_ERROR",message:r,details:{originalError:e}};Array.from(this._pending.entries()).forEach(([e,t])=>{t.timer&&clearTimeout(t.timer),t._handled=!0,t.reject({...o,details:{...o.details,correlationId:e},correlationId:e})}),this._pending.clear(),this.emit("error",o),t(o)}})}_warnOnce(e,t){this[e]||(this[e]=!0,(this.options?.logger?.warn||console.warn)(t))}deprecate(e,t){this._silenceDeprecations||this._deprecatedKeys.has(e)||(this._deprecatedKeys.add(e),(this.options?.logger?.warn||console.warn)(t))}_handleInbound(e){let t;try{t="string"==typeof e?JSON.parse(e):e}catch(e){const t={category:E.WEBSOCKET,code:"INVALID_JSON",message:"Invalid JSON received from server",details:e,timestamp:(new Date).toISOString()};return void this._emitError(t)}const s=t&&t.headers&&t.payload,r="error"===t?.state||"error"===t?.actionType||!!t?.error;if(this.options.strictValidation&&s){const e=this._validateMessageEnvelope(t);e.valid||this.handleError(E.VALIDATION,"INBOUND_ENVELOPE_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Inbound envelope validation failed"),e.errors)}if(r){const e=t?.headers&&t.headers.correlationId||t?.correlationId||null,s={category:E.ORCHESTRATOR,code:t?.error?.code||"REMOTE_ERROR",message:t?.error?.message||t?.message||"Remote error",details:t?.error||t,correlationId:e};if(e&&this._pending.has(e)){const t=this._pending.get(e);t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),t.reject(s)}return void this._emitError(s,t?.action)}const o=t?.headers?.correlationId||t?.correlationId;if(o&&this._pending.has(o)){const e=this._pending.get(o);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(o),e.resolve(t)}this.emit(v.MESSAGE,t),$||($=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".')),this.emit(w.SUPERPOWER_RESPONSE,t),this.emit(S.RESPONSE,t),t?.action&&this.emit(`message.${t.action}`.toLowerCase(),t),s&&t.headers.schemaRef&&this.emit(t.headers.schemaRef,t)}_emitError(e,t=null){e.timestamp||(e.timestamp=(new Date).toISOString()),this.emit(v.ERROR,e),K||(K=!0,(this.options?.logger?.warn||console.warn)('[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'));const s=(r=e)&&r.category&&r.code&&r.message?new OptaveError(r):"string"==typeof r?new OptaveError({category:"UNKNOWN",code:"STRING_ERROR",message:r}):r&&"AjvValidationError"===r.name?new OptaveError({category:"VALIDATION",code:"SCHEMA_VALIDATION",message:r.message,details:r.errors}):r&&r.isAuthError?new OptaveError({category:"AUTHENTICATION",code:r.code||"AUTH_ERROR",message:r.message||"Authentication error",details:r}):r&&r.isWsError?new OptaveError({category:"WEBSOCKET",code:r.code||"WS_ERROR",message:r.message||"WebSocket error",details:r}):new OptaveError({category:"UNKNOWN",code:"UNCLASSIFIED",message:r&&r.message||String(null!=r?r:"Unknown error"),details:r});var r;this.emit(w.SUPERPOWER_ERROR,s),this.emit(S.ERROR,e)}closeConnection(){this.wss&&(this.wss.onopen=null,this.wss.onmessage=null,this.wss.onclose=null,this.wss.onerror=null,this.wss.close(),this.wss=null)}selectiveDeepMerge(e,t){if(Array.isArray(e)&&Array.isArray(t))return[...t];const s=e=>null!==e&&"object"==typeof e&&!Array.isArray(e);if(s(e)&&s(t)){const s={...e};return Object.keys(t).forEach(r=>{s[r]=r in e?this.selectiveDeepMerge(e[r],t[r]):t[r]}),s}return void 0!==t?t:e}isPayloadSizeValid(e){return!!e&&e.length/1024<=_.MAX_PAYLOAD_SIZE_KB}openConnectionAsync(e){return new Promise((t,s)=>{let r;const o=e=>{this.off("error",r),t(e)};r=e=>{this.off("open",o),s(e)},this.once("open",o),this.once("error",r),this.openConnection(e)})}buildPayload(e,t,s){const r=this.selectiveDeepMerge(OptaveJavaScriptSDK.defaultPayload,s);return s?.request?.variation&&(this.deprecate("payload.request.variation","[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."),r.request.attributes.variant=s.request.variation),s?.request?.content&&!r.request?.attributes?.content&&(r.request.attributes.content=s.request.content,this.deprecate("payload.request.content","[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.")),r.request.attributes.variant&&(r.request.attributes.variant=r.request.attributes.variant.toUpperCase()),r}resolveMessageId(e,t){return`${t}.${e}.v3`.toLowerCase()}buildMessageEnvelope(e,t,s,r={}){const o=(new Date).toISOString(),n=r.correlationId||e?.request?.requestId||m(),i=r.traceId||m(),a=r.idempotencyKey||m(),{timestamp:c}=r,d={correlationId:n,action:s,schemaRef:b,sdkVersion:V,identifier:t,traceId:i,idempotencyKey:a,timestamp:c,issuedAt:o};return this.options.tenantId&&(d.tenantId=this.options.tenantId),void 0!==r.networkLatencyMs&&(d.networkLatencyMs=r.networkLatencyMs),Object.freeze(d),{action:"message",headers:d,payload:e}}formatValidationErrorMessage(e,t="Validation failed"){if(!e||!Array.isArray(e)||0===e.length)return t;if(1===e.length){const s=e[0],r=s.instancePath||"/",o="/"===r?"root object":r.replace(/^\//,"").replace(/\//g,".");if("required"===s.keyword){const e=s.params?.missingProperty||"unknown field";let r;return r="root object"===o?e:o.endsWith(e)?o:`${o}.${e}`,`${t}: ${"root object"===o?"Required field":"Field"} '${r}' is missing`}if("type"===s.keyword){return`${t}: Field '${o}' must be of type '${s.params?.type||"unknown"}'`}if("additionalProperties"===s.keyword){return`${t}: Field '${o}.${s.params?.additionalProperty||"unknown"}' is not allowed`}if("enum"===s.keyword){const e=s.params?.allowedValues||[];return`${t}: Field '${o}' must be one of: ${Array.isArray(e)?e.join(", "):"unknown values"}`}return`${t}: ${s.message} at '${o}'`}
// If there are multiple errors, provide a summary with the most critical ones
-const s=e.filter(e=>"required"===e.keyword),r=e.filter(e=>"type"===e.keyword),n=e.filter(e=>"required"!==e.keyword&&"type"!==e.keyword);let o=t+":";if(s.length>0){const e=undefined;o+=` Missing required fields: ${s.map(e=>{const t=(e.instancePath||"/").replace(/^\//,"").replace(/\//g,"."),s=e.params?.missingProperty||"unknown";return""===t?s:`${t}.${s}`}).join(", ")}.`}if(r.length>0){const e=undefined;o+=` Type errors in: ${r.slice(0,3).map(e=>{const t=undefined,s=undefined;return`${(e.instancePath||"/").replace(/^\//,"").replace(/\//g,".")||"root"} (expected ${e.params?.type||"unknown"})`}).join(", ")}.`,r.length>3&&(o+=` And ${r.length-3} more type errors.`)}return n.length>0&&(o+=` Additional validation errors: ${n.length}.`),o}formatAuthenticationError(e,t,s){let r="Authentication failed";const n=[];return e&&e.status&&(r+=` (HTTP ${e.status})`),t&&("string"==typeof t?r+=`: ${t}`:t.error_description?r+=`: ${t.error_description}`:t.message?r+=`: ${t.message}`:t.error&&(r+=`: ${t.error}`)),e&&401===e.status?(n.push("Verify clientId and clientSecret are correct"),n.push("Ensure credentials match the target environment (dev/staging/production)")):e&&403===e.status?(n.push("Check if your client has the necessary permissions"),n.push("Verify the authentication endpoint URL is correct")):e&&e.status>=500?(n.push("Authentication server error - try again later"),n.push("Contact support if the problem persists")):n.push("Check network connectivity and authentication endpoint configuration"),s&&s.authUrl&&(r+=` (endpoint: ${s.authUrl})`),{message:r,suggestions:n}}formatWebSocketError(e,t){let s="WebSocket connection failed";const r=[],n=e?.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||null;return n&&(s+=`: ${n}`),t&&(t.url&&(s+=` (URL: ${t.url})`),t.timeout&&(s+=` (timeout: ${t.timeout}ms)`)),r.push("Check network connectivity and firewall settings"),r.push("Verify WebSocket URL is correct and accessible"),t&&t.url&&(t.url.startsWith("ws://")&&r.push("Consider using secure WebSocket (wss://) for production"),(t.url.includes("localhost")||t.url.includes("127.0.0.1"))&&r.push("Ensure local server is running if connecting to localhost")),t&&t.timeout&&r.push("Try increasing connection timeout if network is slow"),{message:s,suggestions:r}}formatPayloadSizeError(e,t,s){const r=Math.ceil(e/1024),n=t,o=undefined;let i=`Payload too large: ${r}KB exceeds maximum ${t}KB (${r-t}KB over limit)`;const a=[];if(s&&"object"==typeof s){const e=JSON.stringify(s);if(s.request?.scope?.conversations&&Array.isArray(s.request.scope.conversations)){const e=JSON.stringify(s.request.scope.conversations).length,t=Math.ceil(e/1024);t>10&&(a.push(`Consider reducing conversation history - current size: ~${t}KB`),a.push("Remove older messages or summarize conversation context"))}if(s.request?.resources?.offers&&Array.isArray(s.request.resources.offers)){const e=JSON.stringify(s.request.resources.offers).length,t=Math.ceil(e/1024);t>5&&a.push(`Consider reducing product offers data - current size: ~${t}KB`)}if(s.session?.channel?.metadata&&Array.isArray(s.session.channel.metadata)){const e=JSON.stringify(s.session.channel.metadata).length,t=Math.ceil(e/1024);t>2&&a.push(`Consider reducing metadata array - current size: ~${t}KB`)}}return 0===a.length&&(a.push("Remove unused fields from request payload"),a.push("Consider paginating large datasets"),a.push("Use shorter field values where possible")),{message:i,suggestions:a}}formatTokenProviderError(e,t){let s="Failed to obtain WebSocket token from tokenProvider()";const r=[];return e&&(e.message?s+=`: ${e.message}`:"string"==typeof e&&(s+=`: ${e}`),"TypeError"===e.name&&e.message?.includes("fetch")?(r.push("Check if tokenProvider endpoint is accessible"),r.push("Verify CORS settings allow requests to token endpoint")):e.message?.includes("404")||e.message?.includes("Not Found")?(r.push("Verify tokenProvider endpoint URL is correct"),r.push("Ensure backend token endpoint is implemented")):e.message?.includes("401")||e.message?.includes("403")?(r.push("Check authentication/authorization for token endpoint"),r.push("Verify user session or credentials are valid")):e.message?.includes("timeout")&&r.push("Token provider request timed out - check network or server response time")),t&&t.tokenUrl&&(s+=` (endpoint: ${t.tokenUrl})`),0===r.length&&(r.push("Verify tokenProvider function implementation"),r.push("Check backend token endpoint is running and accessible"),r.push("Review browser console for network errors")),{message:s,suggestions:r}}handleError(e,t,s,r=null,n=[],o=null){const i=new x({category:e,code:t,message:s,details:r});n&&(i.suggestions=n),o&&(i.correlationId=o),0===this.listenerCount(O.ERROR)&&0===this.listenerCount(T.ERROR)&&(this.options?.logger?.error||console.error)(`[Optave SDK] ${t}: ${s}`),this._emitError(i)}send(e,t,s){const r=null!=(this.WebSocketImpl&&this.WebSocketImpl.OPEN)?this.WebSocketImpl.OPEN:1;if(!this.wss||this.wss.readyState!==r){const e=this.wss?this.wss.readyState:"no connection";return this.handleError(I.WEBSOCKET,"WEBSOCKET_NOT_IN_OPEN_STATE",this.formatWebSocketError(new Error("WebSocket not ready for sending"),{readyState:e,action:t}).message),void 0}if(!R.has(t))return this.handleError(I.VALIDATION,"INVALID_ACTION",`Unsupported action '${t}'. Allowed: ${[...R].join(", ")}`),void 0;const n=new Set(["session","request","headers"]);for(const e of Object.keys(s||{}))if(!n.has(e)){const t=[{instancePath:"",keyword:"additionalProperties",params:{additionalProperty:e},message:`must NOT have additional property '${e}'`}];return this.handleError(I.VALIDATION,"PAYLOAD_SCHEMA_MISMATCH",this.formatValidationErrorMessage(t),t),void 0}const o=this.buildPayload(e,t,s||{}),i=this.validateRequiredFields(o||{},t);if(!i.isValid)return this.handleError(I.VALIDATION,"REQUIRED_FIELDS_MISSING",`Missing required fields for action '${t}': ${i.errors.join(", ")}`,i.errors),void 0;if(this.options.strictValidation){const e=this._validatePayload(o);if(!e.valid)return this.handleError(I.VALIDATION,"PAYLOAD_SCHEMA_MISMATCH",this.formatValidationErrorMessage(e.errors,"Schema validation failed"),e.errors),void 0}const a=this.buildMessageEnvelope(o,e,t,s?.headers||{}),c=JSON.stringify(a);if(!this.isPayloadSizeValid(c)){const e=c.length;return this.handleError(I.VALIDATION,"PAYLOAD_TOO_LARGE",this.formatPayloadSizeError(e,U.MAX_PAYLOAD_SIZE_KB,a).message,U.MAX_PAYLOAD_SIZE_KB),void 0}this.wss.send(c)}adjust(e){return this.send("message","adjust",e)}elevate(e){return this.send("message","elevate",e)}interaction(e){return this.send("message","interaction",e)}reception(e){return this.send("message","reception",e)}customerInteraction(e){return this.deprecate("method.customerInteraction","[Deprecation] 'customerInteraction' is deprecated; use 'interaction' instead."),this.send("message","customerInteraction",e)}summarize(e){return this.send("message","summarize",e)}translate(e){return this.send("message","translate",e)}recommend(e){return this.send("message","recommend",e)}insights(e){return this.send("message","insights",e)}_registerPending(e,t,s,r,n){let o=null;s>0&&(o=setTimeout(()=>{if(this._pending.has(e)){const r=this._pending.get(e);r&&!r._handled&&(this._pending.delete(e),r._handled=!0,n({category:I.WEBSOCKET,code:"REQUEST_TIMEOUT",message:`Request timed out after ${s}ms`,details:{correlationId:e,action:t},correlationId:e}))}},s)),this._pending.set(e,{resolve:r,reject:n,timer:o,action:t,_handled:!1})}_promiseSend(e,t,s={},r={}){let n,o,i;const a=new Promise((a,c)=>{o=a,i=c;const d="number"==typeof r.timeoutMs?r.timeoutMs:"number"==typeof r.timeout?r.timeout:this.options.requestTimeoutMs;if(!this.wss||this.wss.readyState!==WebSocket.OPEN){if(d<=0)return c({category:I.WEBSOCKET,code:"WEBSOCKET_NOT_IN_OPEN_STATE",message:"WebSocket not open",details:null}),void 0;const r=this.buildPayload(e,t,s),o=this.buildMessageEnvelope(r,e,t,s?.headers||{});return n=o.headers.correlationId,this._registerPending(n,t,d,a,c),void 0}if(!R.has(t))return c({category:I.VALIDATION,code:"INVALID_ACTION",message:`Unsupported action '${t}'.`,details:{allowed:[...R]}}),void 0;const u=new Set(["session","request","headers"]);for(const e of Object.keys(s||{}))if(!u.has(e)){const t=[{instancePath:"",keyword:"additionalProperties",params:{additionalProperty:e},message:`must NOT have additional property '${e}'`}];return c({category:I.VALIDATION,code:"PAYLOAD_SCHEMA_MISMATCH",message:this.formatValidationErrorMessage(t),details:t}),void 0}const l=this.buildPayload(e,t,s),p=this.validateRequiredFields(l,t);if(!p.isValid)return c({category:I.VALIDATION,code:"REQUIRED_FIELDS_MISSING",message:`Missing required fields for action '${t}'`,details:p.errors}),void 0;if(this.options.strictValidation){const e=v(l);if(!e.valid)return c({category:I.VALIDATION,code:"PAYLOAD_SCHEMA_MISMATCH",message:this.formatValidationErrorMessage(e.errors,"Schema validation failed"),details:e.errors}),void 0}const h=this.buildMessageEnvelope(l,e,t,s?.headers||{});n=h.headers.correlationId,this._registerPending(n,t,d,a,c);const f=JSON.stringify(h);if(!this.isPayloadSizeValid(f)){const e=f.length,t=this.formatPayloadSizeError(e,U.MAX_PAYLOAD_SIZE_KB,h).message;return c({category:I.VALIDATION,code:"PAYLOAD_TOO_LARGE",message:t,details:{maxKb:U.MAX_PAYLOAD_SIZE_KB}}),void 0}try{this.wss.send(f)}catch(e){if(this._pending.has(n)){const e=this._pending.get(n);e.timer&&clearTimeout(e.timer),e._handled=!0,this._pending.delete(n)}c({category:I.WEBSOCKET,code:"SEND_FAILED",message:"Failed to send over WebSocket",details:e,correlationId:n})}});return a.correlationId=n,a}adjustAsync(e,t){return this._promiseSend("message","adjust",e,t)}elevateAsync(e,t){return this._promiseSend("message","elevate",e,t)}interactionAsync(e,t){return this._promiseSend("message","interaction",e,t)}receptionAsync(e,t){return this._promiseSend("message","reception",e,t)}customerInteractionAsync(e,t){return this.deprecate("method.customerInteractionAsync","[Deprecation] 'customerInteractionAsync' is deprecated; use 'interactionAsync' instead."),this._promiseSend("message","customerInteraction",e,t)}summarizeAsync(e,t){return this._promiseSend("message","summarize",e,t)}translateAsync(e,t){return this._promiseSend("message","translate",e,t)}recommendAsync(e,t){return this._promiseSend("message","recommend",e,t)}insightsAsync(e,t){return this._promiseSend("message","insights",e,t)}cancelRequest(e){if(this._pending.has(e)){const t=this._pending.get(e);return t.timer&&clearTimeout(t.timer),t._handled=!0,this._pending.delete(e),setTimeout(()=>{t.reject({category:I.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:e},correlationId:e})},0),!0}return!1}cancelPendingRequests(e=!1){if(!this._pending)return 0;const t=this._pending.size,s=[...this._pending.entries()];for(const[t,r]of s)r.timer&&clearTimeout(r.timer),r._handled=!0,e?r.reject({category:I.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled during cleanup",details:{correlationId:t},correlationId:t}):queueMicrotask(()=>{r.reject({category:I.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:t},correlationId:t})});return this._pending.clear(),t}cleanup(){
+const s=e.filter(e=>"required"===e.keyword),r=e.filter(e=>"type"===e.keyword),o=e.filter(e=>"required"!==e.keyword&&"type"!==e.keyword);let n=`${t}:`;if(s.length>0){n+=` Missing required fields: ${s.map(e=>{const t=(e.instancePath||"/").replace(/^\//,"").replace(/\//g,"."),s=e.params?.missingProperty||"unknown";return""===t?s:`${t}.${s}`}).join(", ")}.`}if(r.length>0){n+=` Type errors in: ${r.slice(0,3).map(e=>`${(e.instancePath||"/").replace(/^\//,"").replace(/\//g,".")||"root"} (expected ${e.params?.type||"unknown"})`).join(", ")}.`,r.length>3&&(n+=` And ${r.length-3} more type errors.`)}return o.length>0&&(n+=` Additional validation errors: ${o.length}.`),n}formatAuthenticationError(e,t,s){let r="Authentication failed";const o=[];return e&&e.status&&(r+=` (HTTP ${e.status})`),t&&("string"==typeof t?r+=`: ${t}`:t.error_description?r+=`: ${t.error_description}`:t.message?r+=`: ${t.message}`:t.error&&(r+=`: ${t.error}`)),e&&401===e.status?(o.push("Verify clientId and clientSecret are correct"),o.push("Ensure credentials match the target environment (dev/staging/production)")):e&&403===e.status?(o.push("Check if your client has the necessary permissions"),o.push("Verify the authentication endpoint URL is correct")):e&&e.status>=500?(o.push("Authentication server error - try again later"),o.push("Contact support if the problem persists")):o.push("Check network connectivity and authentication endpoint configuration"),s&&s.authUrl&&(r+=` (endpoint: ${s.authUrl})`),{message:r,suggestions:o}}formatWebSocketError(e,t){let s="WebSocket connection failed";const r=[],o=e?.message||(e instanceof Error?e.message:null)||"object"==typeof e&&e.error&&e.error.message||null;return o&&(s+=`: ${o}`),t&&(t.url&&(s+=` (URL: ${t.url})`),t.timeout&&(s+=` (timeout: ${t.timeout}ms)`)),r.push("Check network connectivity and firewall settings"),r.push("Verify WebSocket URL is correct and accessible"),t&&t.url&&(t.url.startsWith("ws://")&&r.push("Consider using secure WebSocket (wss://) for production"),(t.url.includes("localhost")||t.url.includes("127.0.0.1"))&&r.push("Ensure local server is running if connecting to localhost")),t&&t.timeout&&r.push("Try increasing connection timeout if network is slow"),{message:s,suggestions:r}}formatPayloadSizeError(e,t,s){const r=Math.ceil(e/1024),o=`Payload too large: ${r}KB exceeds maximum ${t}KB (${r-t}KB over limit)`,n=[];if(s&&"object"==typeof s){if(s.request?.scope?.conversations&&Array.isArray(s.request.scope.conversations)){const e=JSON.stringify(s.request.scope.conversations).length,t=Math.ceil(e/1024);t>10&&(n.push(`Consider reducing conversation history - current size: ~${t}KB`),n.push("Remove older messages or summarize conversation context"))}if(s.request?.resources?.offers&&Array.isArray(s.request.resources.offers)){const e=JSON.stringify(s.request.resources.offers).length,t=Math.ceil(e/1024);t>5&&n.push(`Consider reducing product offers data - current size: ~${t}KB`)}if(s.session?.channel?.metadata&&Array.isArray(s.session.channel.metadata)){const e=JSON.stringify(s.session.channel.metadata).length,t=Math.ceil(e/1024);t>2&&n.push(`Consider reducing metadata array - current size: ~${t}KB`)}}return 0===n.length&&(n.push("Remove unused fields from request payload"),n.push("Consider paginating large datasets"),n.push("Use shorter field values where possible")),{message:o,suggestions:n}}formatTokenProviderError(e,t){let s="Failed to obtain WebSocket token from tokenProvider()";const r=[];return e&&(e.message?s+=`: ${e.message}`:"string"==typeof e&&(s+=`: ${e}`),"TypeError"===e.name&&e.message?.includes("fetch")?(r.push("Check if tokenProvider endpoint is accessible"),r.push("Verify CORS settings allow requests to token endpoint")):e.message?.includes("404")||e.message?.includes("Not Found")?(r.push("Verify tokenProvider endpoint URL is correct"),r.push("Ensure backend token endpoint is implemented")):e.message?.includes("401")||e.message?.includes("403")?(r.push("Check authentication/authorization for token endpoint"),r.push("Verify user session or credentials are valid")):e.message?.includes("timeout")&&r.push("Token provider request timed out - check network or server response time")),t&&t.tokenUrl&&(s+=` (endpoint: ${t.tokenUrl})`),0===r.length&&(r.push("Verify tokenProvider function implementation"),r.push("Check backend token endpoint is running and accessible"),r.push("Review browser console for network errors")),{message:s,suggestions:r}}handleError(e,t,s,r=null,o=[],n=null){const i=new OptaveError({category:e,code:t,message:s,details:r});o&&(i.suggestions=o),n&&(i.correlationId=n),0===this.listenerCount(v.ERROR)&&0===this.listenerCount(S.ERROR)&&(this.options?.logger?.error||console.error)(`[Optave SDK] ${t}: ${s}`),this._emitError(i)}send(e,t,s){const r=null!=(this.WebSocketImpl&&this.WebSocketImpl.OPEN)?this.WebSocketImpl.OPEN:1;if(!this.wss||this.wss.readyState!==r){const e=this.wss?this.wss.readyState:"no connection";return void this.handleError(E.WEBSOCKET,"WEBSOCKET_NOT_IN_OPEN_STATE",this.formatWebSocketError(new Error("WebSocket not ready for sending"),{readyState:e,action:t}).message)}if(!I.has(t))return void this.handleError(E.VALIDATION,"INVALID_ACTION",`Unsupported action '${t}'. Allowed: ${[...I].join(", ")}`);const o=new Set(["session","request","headers"]),n=Object.keys(s||{});for(let e=0;e0&&(n=setTimeout(()=>{if(this._pending.has(e)){const r=this._pending.get(e);r&&!r._handled&&(this._pending.delete(e),r._handled=!0,o({category:E.WEBSOCKET,code:"REQUEST_TIMEOUT",message:`Request timed out after ${s}ms`,details:{correlationId:e,action:t},correlationId:e}))}},s)),this._pending.set(e,{resolve:r,reject:o,timer:n,action:t,_handled:!1})}_promiseSend(e,t,s={},r={}){let o;const n=new Promise((n,i)=>{let a;if(a="number"==typeof r.timeoutMs?r.timeoutMs:"number"==typeof r.timeout?r.timeout:this.options.requestTimeoutMs,!this.wss||this.wss.readyState!==WebSocket.OPEN){if(a<=0)return void i(new OptaveError({category:E.WEBSOCKET,code:"WEBSOCKET_NOT_IN_OPEN_STATE",message:"WebSocket not open",details:null}));const r=this.buildPayload(e,t,s),c=this.buildMessageEnvelope(r,e,t,s?.headers||{});return o=c.headers.correlationId,void this._registerPending(o,t,a,n,i)}if(!I.has(t))return void i(new OptaveError({category:E.VALIDATION,code:"INVALID_ACTION",message:`Unsupported action '${t}'.`,details:{allowed:[...I]}}));const c=new Set(["session","request","headers"]),d=Object.keys(s||{});for(let e=0;e{t.reject({category:E.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:e},correlationId:e})},0),!0}return!1}cancelPendingRequests(e=!1){if(!this._pending)return 0;const t=this._pending.size;return[...this._pending.entries()].forEach(([t,s])=>{s.timer&&clearTimeout(s.timer),s._handled=!0,e?s.reject({category:E.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled during cleanup",details:{correlationId:t},correlationId:t}):queueMicrotask(()=>{s.reject({category:E.WEBSOCKET,code:"REQUEST_CANCELLED",message:"Request was cancelled",details:{correlationId:t},correlationId:t})})}),this._pending.clear(),t}cleanup(){this.closeConnection(),this.cancelPendingRequests(!0),this._deprecatedKeys&&this._deprecatedKeys.clear(),void 0!==this._warnedQueryToken&&delete this._warnedQueryToken,
// CRITICAL: Clear EventEmitter state BEFORE calling removeAllListeners
-if(this.closeConnection(),this.cancelPendingRequests(!0),this._deprecatedKeys&&this._deprecatedKeys.clear(),void 0!==this._warnedQueryToken&&delete this._warnedQueryToken,this._events)for(const e in this._events)delete this._events[e];this.removeAllListeners(),
+this._events&&Object.keys(this._events).forEach(e=>{delete this._events[e]}),this.removeAllListeners(),
// CRITICAL: Set EventEmitter properties to null AFTER removeAllListeners
-this._events=null,this._eventsCount=null,this._maxListeners=null;
-// CRITICAL: Clean up JSDOM contexts created by SDK loader
-const e="server-umd";1,0,this._validatePayload=null,this._validateMessageEnvelope=null,this._emitError=null,this._ensureWebSocketImpl=null,this._handleInbound=null,this._promiseSend=null,this._registerPending=null,this._warnOnce=null,this.options=null,this.WebSocketImpl=null,this.wss=null,this.sessionId=null,this._pending=null,this._deprecatedKeys=null,this._silenceDeprecations=null,this._events=null,this._eventsCount=null,this._maxListeners=null}removeAllListeners(e){try{n.prototype.removeAllListeners.call(this,e)}catch(t){e?this._events&&this._events[e]&&(delete this._events[e],this._eventsCount=Math.max(0,this._eventsCount-1)):(this._events=Object.create(null),this._eventsCount=0)}return this}static get buildFlags(){const e="server-umd";return{SALESFORCE_BUILD:!0,INCLUDE_WS_REQUIRE:!1,SDK_VERSION:"3.2.3",WEBPACK_BUILD_TARGET:e,WEBPACK_BUILD_TARGET_NORMALIZED:B.normalize(e),BUILD_TARGET_INFO:B.getInfo(e)}}}const te=null;let se;se="undefined"!=typeof globalThis&&globalThis.crypto&&globalThis.crypto.getRandomValues?globalThis.crypto:"undefined"!=typeof window&&window.crypto&&window.crypto.getRandomValues?window.crypto:"undefined"!=typeof self&&self.crypto&&self.crypto.getRandomValues?self.crypto:{getRandomValues:function(e){for(let t=0;t65536*Math.trunc(65536*Math.random())+Math.trunc(65536*Math.random())}}generate(){return this.generateOrResetCore(Date.now(),1e4)}generateOrResetCore(e,t){let s=this.generateOrAbortCore(e,t);return void 0===s&&(this.timestamp=0,s=this.generateOrAbortCore(e,t)),s}generateOrAbortCore(e,t){const s=4398046511103;if(!Number.isInteger(e)||e<1||e>0xffffffffffff)throw new RangeError("unixTsMs must be a 48-bit positive integer");if(e>this.timestamp)this.timestamp=e,this.resetCounter();else{if(!(e+t>=this.timestamp))return;this.counter++,this.counter>s&&(this.timestamp++,this.resetCounter())}return this.fromFieldsV7(this.timestamp,Math.trunc(this.counter/2**30),this.counter&2**30-1,this.random.nextUint32())}resetCounter(){this.counter=1024*this.random.nextUint32()+(1023&this.random.nextUint32())}fromFieldsV7(e,t,s,r){const n=new Uint8Array(16);return n[0]=e/2**40,n[1]=e/2**32,n[2]=e/2**24,n[3]=e/65536,n[4]=e/256,n[5]=e,n[6]=112|t>>>8,n[7]=t,n[8]=128|s>>>24,n[9]=s>>>16,n[10]=s>>>8,n[11]=s,n[12]=r>>>24,n[13]=r>>>16,n[14]=r>>>8,n[15]=r,this.bytesToString(n)}bytesToString(e){const t=Array.from(e,e=>e.toString(16).padStart(2,"0")).join("");return[t.substring(0,8),t.substring(8,12),t.substring(12,16),t.substring(16,20),t.substring(20,32)].join("-")}}class ne{constructor(){this.buffer=new Uint32Array(8),this.cursor=65535}nextUint32(){return this.cursor>=this.buffer.length&&(se.getRandomValues(this.buffer),this.cursor=0),this.buffer[this.cursor++]}}let oe=null;function ie(e,t){if(e&&!e.crypto)try{const s=Object.getOwnPropertyDescriptor(e,t);s&&!1===s.configurable||(e.crypto=se)}catch(t){console.debug("Cannot set crypto property on",e.constructor.name,":",t.message)}}se.randomUUID=function(){return oe||(oe=new re),oe.generate()},se.generateUUID=function(){return oe||(oe=new re),oe.generate()},
+this._events=null,this._eventsCount=null,this._maxListeners=null;this._validatePayload=null,this._validateOutboundPayload=null,this._validateMessageEnvelope=null,this._emitError=null,this._ensureWebSocketImpl=null,this._handleInbound=null,this._promiseSend=null,this._registerPending=null,this._warnOnce=null,this.options=null,this.WebSocketImpl=null,this.wss=null,this.sessionId=null,this._pending=null,this._deprecatedKeys=null,this._silenceDeprecations=null,this._events=null,this._eventsCount=null,this._maxListeners=null}removeAllListeners(e){try{i.prototype.removeAllListeners.call(this,e)}catch(t){e?this._events&&this._events[e]&&(delete this._events[e],this._eventsCount=Math.max(0,this._eventsCount-1)):(this._events=Object.create(null),this._eventsCount=0)}return this}static get buildFlags(){const e="server-umd";return{SALESFORCE_BUILD:!1,INCLUDE_WS_REQUIRE:!1,SDK_VERSION:"3.6.0",WEBPACK_BUILD_TARGET:e,WEBPACK_BUILD_TARGET_NORMALIZED:W.normalize(e),BUILD_TARGET_INFO:W.getInfo(e)}}}const B="undefined"!=typeof globalThis&&globalThis.crypto&&globalThis.crypto.getRandomValues?globalThis.crypto:"undefined"!=typeof window&&window.crypto&&window.crypto.getRandomValues?window.crypto:"undefined"!=typeof globalThis&&globalThis.self&&globalThis.self.crypto&&globalThis.self.crypto.getRandomValues?globalThis.self.crypto:{getRandomValues(e){for(let t=0;t=e.length&&(B.getRandomValues(e),t=0);const s=e[t];return t+=1,s}}}():{nextUint32:()=>65536*Math.trunc(65536*Math.random())+Math.trunc(65536*Math.random())}}generate(){return this.generateOrResetCore(Date.now(),1e4)}generateOrResetCore(e,t){let s=this.generateOrAbortCore(e,t);return void 0===s&&(this.timestamp=0,s=this.generateOrAbortCore(e,t)),s}generateOrAbortCore(e,t){if(!Number.isInteger(e)||e<1||e>0xffffffffffff)throw new RangeError("unixTsMs must be a 48-bit positive integer");if(e>this.timestamp)this.timestamp=e,this.resetCounter();else{if(!(e+t>=this.timestamp))return;this.counter++,this.counter>4398046511103&&(this.timestamp++,this.resetCounter())}return this.fromFieldsV7(this.timestamp,Math.trunc(this.counter/2**30),this.counter&2**30-1,this.random.nextUint32())}resetCounter(){this.counter=1024*this.random.nextUint32()+(1023&this.random.nextUint32())}fromFieldsV7(e,t,s,r){const o=new Uint8Array(16);return o[0]=e/2**40,o[1]=e/2**32,o[2]=e/2**24,o[3]=e/65536,o[4]=e/256,o[5]=e,o[6]=112|t>>>8,o[7]=t,o[8]=128|s>>>24,o[9]=s>>>16,o[10]=s>>>8,o[11]=s,o[12]=r>>>24,o[13]=r>>>16,o[14]=r>>>8,o[15]=r,this.bytesToString(o)}bytesToString(e){const t=Array.from(e,e=>e.toString(16).padStart(2,"0")).join("");return[t.substring(0,8),t.substring(8,12),t.substring(12,16),t.substring(16,20),t.substring(20,32)].join("-")}}let x=null;function z(e,t){if(e&&!e.crypto)try{const s=Object.getOwnPropertyDescriptor(e,t);s&&!1===s.configurable||(e.crypto=B)}catch{}}B.randomUUID=function(){return x||(x=new V7Generator),x.generate()},B.generateUUID=function(){return x||(x=new V7Generator),x.generate()},
// Generate short ID using UUID v7 for cryptographic security
-se.generateShortId=function(){return oe.generate().replace(/-/g,"").substring(0,9)},"undefined"!=typeof globalThis&&ie(globalThis,"crypto"),"undefined"!=typeof window&&ie(window,"crypto"),"undefined"!=typeof self&&ie(self,"crypto");try{"undefined"!=typeof module&&"object"==typeof module.exports&&"undefined"!=typeof require&&(module.exports=se,module.exports.default=se,module.exports.getRandomValues=se.getRandomValues.bind(se),module.exports.randomUUID=se.randomUUID?se.randomUUID.bind(se):se.randomUUID,module.exports.generateUUID=se.generateUUID.bind(se),module.exports.generateShortId=se.generateShortId.bind(se))}catch(e){}const ae=se.getRandomValues.bind(se),ce=se.randomUUID?se.randomUUID.bind(se):se.randomUUID,de=se.generateUUID.bind(se),ue=se.generateShortId.bind(se),le=null;if("undefined"!=typeof globalThis&&!globalThis.OptaveJavaScriptSDK)try{globalThis.OptaveJavaScriptSDK=OptaveJavaScriptSDK}catch{}const pe=OptaveJavaScriptSDK;return r=r.default})());
\ No newline at end of file
+B.generateShortId=function(){return x.generate().replace(/-/g,"").substring(0,9)},"undefined"!=typeof globalThis&&z(globalThis,"crypto"),"undefined"!=typeof window&&z(window,"crypto"),"undefined"!=typeof globalThis&&globalThis.self&&z(globalThis.self,"crypto");try{"undefined"!=typeof module&&"object"==typeof module.exports&&"undefined"!=typeof require&&(module.exports=B,module.exports.default=B,module.exports.getRandomValues=B.getRandomValues.bind(B),module.exports.randomUUID=B.randomUUID?B.randomUUID.bind(B):B.randomUUID,module.exports.generateUUID=B.generateUUID.bind(B),module.exports.generateShortId=B.generateShortId.bind(B))}catch(e){}B.getRandomValues.bind(B),B.randomUUID?B.randomUUID.bind(B):B.randomUUID,B.generateUUID.bind(B),B.generateShortId.bind(B);
+// Salesforce Lightning loads this UMD bundle as a static resource and reads
+if("undefined"!=typeof window&&!window.OptaveJavaScriptSDK)try{window.OptaveJavaScriptSDK=OptaveJavaScriptSDK}catch{}if("undefined"!=typeof globalThis&&!globalThis.OptaveJavaScriptSDK)try{globalThis.OptaveJavaScriptSDK=OptaveJavaScriptSDK}catch{}const H=OptaveJavaScriptSDK;return n=n.default,n})());
+//# sourceMappingURL=server.umd.js.map
\ No newline at end of file
diff --git a/sdks/javascript/dist/server.umd.js.map b/sdks/javascript/dist/server.umd.js.map
new file mode 100644
index 0000000..908d790
--- /dev/null
+++ b/sdks/javascript/dist/server.umd.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"server.umd.js","mappings":"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","sources":["webpack://OptaveJavaScriptSDK/webpack/universalModuleDefinition","webpack://OptaveJavaScriptSDK/external umd \"events\"","webpack://OptaveJavaScriptSDK/external umd \"ws\"","webpack://OptaveJavaScriptSDK/./runtime/platform/browser/urlsearchparams-polyfill.js","webpack://OptaveJavaScriptSDK/webpack/bootstrap","webpack://OptaveJavaScriptSDK/webpack/runtime/define property getters","webpack://OptaveJavaScriptSDK/webpack/runtime/hasOwnProperty shorthand","webpack://OptaveJavaScriptSDK/../../node_modules/uuid/dist-node/rng.js","webpack://OptaveJavaScriptSDK/../../node_modules/uuid/dist-node/stringify.js","webpack://OptaveJavaScriptSDK/../../node_modules/uuid/dist-node/v7.js","webpack://OptaveJavaScriptSDK/./runtime/platform/browser/validators.js","webpack://OptaveJavaScriptSDK/./generated/constants.js","webpack://OptaveJavaScriptSDK/./runtime/core/constants.js","webpack://OptaveJavaScriptSDK/./runtime/validation/config-validator.js","webpack://OptaveJavaScriptSDK/./runtime/validation/pi-guard.js","webpack://OptaveJavaScriptSDK/./runtime/core/build-targets.js","webpack://OptaveJavaScriptSDK/./runtime/core/errors.js","webpack://OptaveJavaScriptSDK/./runtime/core/security-guards.js","webpack://OptaveJavaScriptSDK/./runtime/core/main.js","webpack://OptaveJavaScriptSDK/./runtime/platform/node/websocket-loader.js","webpack://OptaveJavaScriptSDK/./runtime/platform/browser/crypto-polyfill.js","webpack://OptaveJavaScriptSDK/./runtime/core/umd-entry.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"events\"), require(\"ws\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"OptaveJavaScriptSDK\", [\"events\", \"ws\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"OptaveJavaScriptSDK\"] = factory(require(\"events\"), require(\"ws\"));\n\telse\n\t\troot[\"OptaveJavaScriptSDK\"] = factory(root[\"events\"], root[\"ws\"]);\n})((typeof globalThis !== 'undefined' ? globalThis : this), (__WEBPACK_EXTERNAL_MODULE__761__, __WEBPACK_EXTERNAL_MODULE__2__) => {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__761__;","module.exports = __WEBPACK_EXTERNAL_MODULE__2__;","/**\n * URLSearchParams polyfill for browser environments that might not have it\n * Used by server UMD build (which targets Salesforce browser environments)\n */\n\nexport default class URLSearchParamsPolyfill {\n constructor(init) {\n this.params = new Map();\n\n if (typeof init === 'string') {\n // Parse query string\n const pairs = init.replace(/^\\?/, '').split('&');\n pairs.forEach((pair) => {\n if (pair) {\n const [key, value] = pair.split('=');\n if (key) {\n this.params.set(\n decodeURIComponent(key),\n decodeURIComponent(value || ''),\n );\n }\n }\n });\n } else if (init && typeof init === 'object') {\n // Handle object initialization\n if (init instanceof Map) {\n init.forEach((value, key) => {\n this.params.set(key, String(value));\n });\n } else if (Array.isArray(init)) {\n // Handle array of [key, value] pairs\n init.forEach(([key, value]) => {\n this.params.set(key, String(value));\n });\n } else {\n // Handle plain object\n Object.entries(init).forEach(([key, value]) => {\n this.params.set(key, String(value));\n });\n }\n }\n }\n\n append(name, value) {\n const existing = this.params.get(name);\n if (existing !== undefined) {\n this.params.set(name, `${existing},${String(value)}`);\n } else {\n this.params.set(name, String(value));\n }\n }\n\n delete(name) {\n this.params.delete(name);\n }\n\n get(name) {\n return this.params.get(name) || null;\n }\n\n getAll(name) {\n const value = this.params.get(name);\n return value ? value.split(',') : [];\n }\n\n has(name) {\n return this.params.has(name);\n }\n\n set(name, value) {\n this.params.set(name, String(value));\n }\n\n toString() {\n const pairs = [];\n this.params.forEach((value, key) => {\n // Handle comma-separated values (from append)\n const values = value.split(',');\n values.forEach((val) => {\n pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(val)}`);\n });\n });\n return pairs.join('&');\n }\n\n * [Symbol.iterator]() {\n const paramEntries = Array.from(this.params);\n for (let i = 0; i < paramEntries.length; i += 1) {\n const [key, value] = paramEntries[i];\n // Handle comma-separated values (from append)\n const values = value.split(',');\n for (let j = 0; j < values.length; j += 1) {\n yield [key, values[j]];\n }\n }\n }\n\n * keys() {\n const all = Array.from(this);\n for (let i = 0; i < all.length; i += 1) {\n yield all[i][0];\n }\n }\n\n * values() {\n const all = Array.from(this);\n for (let i = 0; i < all.length; i += 1) {\n yield all[i][1];\n }\n }\n\n * entries() {\n yield* this;\n }\n\n forEach(callback, thisArg) {\n Array.from(this).forEach(([key, value]) => {\n callback.call(thisArg, value, key, this);\n });\n }\n}\n\n// Provide a fallback that uses native URLSearchParams if available, otherwise the polyfill\nexport const URLSearchParams = (typeof globalThis !== 'undefined' && globalThis.URLSearchParams)\n || (typeof window !== 'undefined' && window.URLSearchParams)\n || URLSearchParamsPolyfill;\n","// The module cache\nconst __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tconst cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tconst module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter/value functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tif(Array.isArray(definition)) {\n\t\tvar i = 0;\n\t\twhile(i < definition.length) {\n\t\t\tvar key = definition[i++];\n\t\t\tvar binding = definition[i++];\n\t\t\tif(!__webpack_require__.o(exports, key)) {\n\t\t\t\tif(binding === 0) {\n\t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, value: definition[i++] });\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: binding });\n\t\t\t\t}\n\t\t\t} else if(binding === 0) { i++; }\n\t\t}\n\t} else {\n\t\tfor(var key in definition) {\n\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t\t}\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","const rnds8 = new Uint8Array(16);\nexport default function rng() {\n return crypto.getRandomValues(rnds8);\n}\n","import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\nexport default stringify;\n","import rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nconst _state = {};\nfunction v7(options, buf, offset) {\n let bytes;\n if (options) {\n bytes = v7Bytes(options.random ?? options.rng?.() ?? rng(), options.msecs, options.seq, buf, offset);\n }\n else {\n const now = Date.now();\n const rnds = rng();\n updateV7State(_state, now, rnds);\n bytes = v7Bytes(rnds, _state.msecs, _state.seq, buf, offset);\n }\n return buf ?? unsafeStringify(bytes);\n}\nexport function updateV7State(state, now, rnds) {\n state.msecs ??= -Infinity;\n state.seq ??= 0;\n if (now > state.msecs) {\n state.seq = v7Sequence(rnds);\n state.msecs = now;\n }\n else {\n state.seq = (state.seq + 1) | 0;\n if (state.seq === 0) {\n state.msecs++;\n }\n }\n return state;\n}\nfunction v7Bytes(rnds, msecs, seq, buf, offset = 0) {\n if (rnds.length < 16) {\n throw new Error('Random bytes length must be >= 16');\n }\n if (!buf) {\n buf = new Uint8Array(16);\n offset = 0;\n }\n else {\n if (offset < 0 || offset + 16 > buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n }\n }\n msecs ??= Date.now();\n seq ??= v7Sequence(rnds);\n buf[offset++] = (msecs / 0x10000000000) & 0xff;\n buf[offset++] = (msecs / 0x100000000) & 0xff;\n buf[offset++] = (msecs / 0x1000000) & 0xff;\n buf[offset++] = (msecs / 0x10000) & 0xff;\n buf[offset++] = (msecs / 0x100) & 0xff;\n buf[offset++] = msecs & 0xff;\n buf[offset++] = 0x70 | ((seq >>> 28) & 0x0f);\n buf[offset++] = (seq >>> 20) & 0xff;\n buf[offset++] = 0x80 | ((seq >>> 14) & 0x3f);\n buf[offset++] = (seq >>> 6) & 0xff;\n buf[offset++] = ((seq << 2) & 0xff) | (rnds[10] & 0x03);\n buf[offset++] = rnds[11];\n buf[offset++] = rnds[12];\n buf[offset++] = rnds[13];\n buf[offset++] = rnds[14];\n buf[offset++] = rnds[15];\n return buf;\n}\nfunction v7Sequence(rnds) {\n return ((rnds[6] & 0x7f) << 24) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9];\n}\nexport default v7;\n","/**\n * CSP-safe validator implementation (no eval/Function constructor)\n *\n * Used by all builds that require Content Security Policy compliance:\n * - Browser ESM (browser.mjs)\n * - Browser UMD (browser.umd.js) - Salesforce Lightning\n * - Server UMD (server.umd.js) - Node.js CommonJS\n *\n * Provides comprehensive validation without AJV dependency.\n * Server ESM (server.mjs) uses full AJV validation instead.\n *\n * This implementation must match the server-side validation logic for security.\n */\n\n// Helper function to create AJV-compatible error objects\nfunction createError(instancePath, message, keyword = 'validation', params = {}) {\n return {\n instancePath,\n message,\n keyword,\n params,\n };\n}\n\n// Validates payload structure and required fields\nexport function validatePayload(data) {\n if (!data || typeof data !== 'object') {\n return { valid: false, errors: [createError('', 'must be object', 'type', { type: 'object' })] };\n }\n\n const errors = [];\n\n // Session validation\n if (!data.session) {\n errors.push(createError('/session', 'is required', 'required', { missingProperty: 'session' }));\n } else if (typeof data.session !== 'object') {\n errors.push(createError('/session', 'must be object', 'type', { type: 'object' }));\n } else if (data.session.sessionId !== undefined && typeof data.session.sessionId !== 'string') {\n // sessionId validation (optional)\n errors.push(createError('/session/sessionId', 'must be string', 'type', { type: 'string' }));\n }\n\n // Request validation\n if (!data.request) {\n errors.push(createError('/request', 'is required', 'required', { missingProperty: 'request' }));\n } else if (typeof data.request !== 'object') {\n errors.push(createError('/request', 'must be object', 'type', { type: 'object' }));\n } else {\n // Connections validation\n if (!data.request.connections) {\n errors.push(createError('/request/connections', 'is required', 'required', { missingProperty: 'connections' }));\n } else if (typeof data.request.connections !== 'object') {\n errors.push(createError('/request/connections', 'must be object', 'type', { type: 'object' }));\n } else {\n // threadId validation - required for ALL actions per SDK logic\n if (!data.request.connections.threadId) {\n errors.push(createError('/request/connections/threadId', 'is required', 'required', { missingProperty: 'threadId' }));\n } else if (typeof data.request.connections.threadId !== 'string') {\n errors.push(createError('/request/connections/threadId', 'must be string', 'type', { type: 'string' }));\n }\n\n // parentId type validation (if present)\n if (data.request.connections.parentId !== undefined && typeof data.request.connections.parentId !== 'string') {\n errors.push(createError('/request/connections/parentId', 'must be string', 'type', { type: 'string' }));\n }\n\n // replyId: optional opaque string, same treatment as parentId.\n if (data.request.connections.replyId !== undefined && typeof data.request.connections.replyId !== 'string') {\n errors.push(createError('/request/connections/replyId', 'must be string', 'type', { type: 'string' }));\n }\n\n // replyTarget: deprecated 3.5.0 alias for attributes.replyTo. Same closed enum.\n const { replyTarget } = data.request.connections;\n if (replyTarget !== undefined) {\n const allowedReplyTargets = ['ai', 'self', 'none'];\n if (typeof replyTarget !== 'string') {\n errors.push(createError('/request/connections/replyTarget', 'must be string', 'type', { type: 'string' }));\n } else if (!allowedReplyTargets.includes(replyTarget)) {\n errors.push(createError(\n '/request/connections/replyTarget',\n 'must be equal to one of the allowed values',\n 'enum',\n { allowedValues: allowedReplyTargets },\n ));\n }\n }\n }\n\n // Context validation (if present)\n if (data.request.context !== undefined && typeof data.request.context !== 'object') {\n errors.push(createError('/request/context', 'must be object', 'type', { type: 'object' }));\n }\n\n // Attributes validation (if present)\n if (data.request.attributes !== undefined && typeof data.request.attributes !== 'object') {\n errors.push(createError('/request/attributes', 'must be object', 'type', { type: 'object' }));\n } else if (data.request.attributes && typeof data.request.attributes === 'object') {\n // replyTo: optional closed enum. Omit when not reported (absent !== \"none\").\n // Empty string is not in the enum — match AJV, do not treat it as absent.\n const { replyTo } = data.request.attributes;\n if (replyTo !== undefined) {\n const allowedReplyTo = ['ai', 'self', 'none'];\n if (typeof replyTo !== 'string') {\n errors.push(createError('/request/attributes/replyTo', 'must be string', 'type', { type: 'string' }));\n } else if (!allowedReplyTo.includes(replyTo)) {\n errors.push(createError(\n '/request/attributes/replyTo',\n 'must be equal to one of the allowed values',\n 'enum',\n { allowedValues: allowedReplyTo },\n ));\n }\n }\n }\n\n // Scope validation (if present)\n if (data.request.scope !== undefined) {\n if (typeof data.request.scope !== 'object') {\n errors.push(createError('/request/scope', 'must be object', 'type', { type: 'object' }));\n } else if (data.request.scope.conversations !== undefined) {\n if (!Array.isArray(data.request.scope.conversations)) {\n errors.push(createError('/request/scope/conversations', 'must be array', 'type', { type: 'array' }));\n }\n }\n }\n\n // Resources validation (if present)\n if (data.request.resources !== undefined) {\n if (typeof data.request.resources !== 'object') {\n errors.push(createError('/request/resources', 'must be object', 'type', { type: 'object' }));\n } else if (data.request.resources.offers !== undefined) {\n if (!Array.isArray(data.request.resources.offers)) {\n errors.push(createError('/request/resources/offers', 'must be array', 'type', { type: 'array' }));\n }\n }\n }\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };\n}\n\nexport function validateMessageEnvelope(data) {\n if (!data || typeof data !== 'object') {\n return { valid: false, errors: [createError('', 'must be object', 'type', { type: 'object' })] };\n }\n\n const errors = [];\n\n // Headers validation\n if (!data.headers) {\n errors.push(createError('/headers', 'is required', 'required', { missingProperty: 'headers' }));\n } else if (typeof data.headers !== 'object') {\n errors.push(createError('/headers', 'must be object', 'type', { type: 'object' }));\n } else {\n // correlationId validation\n if (!data.headers.correlationId) {\n errors.push(createError('/headers/correlationId', 'is required', 'required', { missingProperty: 'correlationId' }));\n } else if (typeof data.headers.correlationId !== 'string') {\n errors.push(createError('/headers/correlationId', 'must be string', 'type', { type: 'string' }));\n }\n\n // action validation\n if (!data.headers.action) {\n errors.push(createError('/headers/action', 'is required', 'required', { missingProperty: 'action' }));\n } else if (typeof data.headers.action !== 'string') {\n errors.push(createError('/headers/action', 'must be string', 'type', { type: 'string' }));\n } else {\n // Validate allowed actions\n const allowedActions = ['adjust', 'elevate', 'interaction', 'assistant', 'customerinteraction', 'reception', 'summarize', 'translate', 'recommend', 'insights'];\n if (!allowedActions.includes(data.headers.action)) {\n errors.push(createError('/headers/action', 'must be equal to one of the allowed values', 'enum', { allowedValues: allowedActions }));\n }\n }\n\n // Optional fields validation\n if (data.headers.identifier !== undefined && typeof data.headers.identifier !== 'string') {\n errors.push(createError('/headers/identifier', 'must be string', 'type', { type: 'string' }));\n }\n\n if (data.headers.schemaRef !== undefined && typeof data.headers.schemaRef !== 'string') {\n errors.push(createError('/headers/schemaRef', 'must be string', 'type', { type: 'string' }));\n }\n\n if (data.headers.timestamp !== undefined && typeof data.headers.timestamp !== 'string') {\n errors.push(createError('/headers/timestamp', 'must be string', 'type', { type: 'string' }));\n }\n }\n\n // Payload validation\n if (!data.payload) {\n errors.push(createError('/payload', 'is required', 'required', { missingProperty: 'payload' }));\n } else if (typeof data.payload !== 'object') {\n errors.push(createError('/payload', 'must be object', 'type', { type: 'object' }));\n } else if (data.headers && data.headers.action && data.payload) {\n // Action-specific conversation validation\n const { action } = data.headers;\n const requiresConversations = ['adjust', 'elevate', 'interaction', 'assistant', 'customerinteraction', 'customerInteraction', 'summarize', 'translate', 'insights', 'recommend'];\n\n if (requiresConversations.includes(action)) {\n if (!data.payload.request) {\n errors.push(createError('/payload/request', 'is required', 'required', { missingProperty: 'request' }));\n } else if (!data.payload.request.scope) {\n errors.push(createError('/payload/request/scope', 'is required', 'required', { missingProperty: 'scope' }));\n } else if (!data.payload.request.scope.conversations) {\n errors.push(createError('/payload/request/scope/conversations', `is required for ${action}`, 'required', { missingProperty: 'conversations' }));\n } else if (!Array.isArray(data.payload.request.scope.conversations)) {\n errors.push(createError('/payload/request/scope/conversations', 'must be array', 'type', { type: 'array' }));\n } else if (data.payload.request.scope.conversations.length === 0) {\n errors.push(createError('/payload/request/scope/conversations', `must be non-empty array for ${action}`, 'minItems', { limit: 1 }));\n }\n }\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };\n}\n\n// Validator functions are already exported above\n\nexport const availableValidators = ['Payload', 'MessageEnvelope'];\n","// AUTO-GENERATED FILE. DO NOT EDIT.\n// Source: config/specs/asyncapi.yaml (info.version: 1.0.0)\n// This is the protocol version, independent of SDK implementation version\n\n// Protocol version from AsyncAPI spec\nexport const SPEC_VERSION = \"1.0.0\";\n\n// Schema ref is derived from protocol major version\nconst SPEC_MAJOR = SPEC_VERSION.split('.')[0];\nexport const SCHEMA_REF = `optave.message.v${SPEC_MAJOR}`;\n","/**\n * SDK Constants - PUBLIC API\n *\n * ⚠️ WARNING: This file is exported as part of the public API.\n * Do not add sensitive information such as API keys, secrets,\n * internal URLs, or confidential configuration values.\n *\n * Only include constants that are safe to expose to end users.\n */\n\n// SDK Constants (imported from generated file based on AsyncAPI spec)\nimport { SPEC_VERSION, SCHEMA_REF } from '../../generated/constants.js';\n\nexport { SPEC_VERSION, SCHEMA_REF };\n\n// Error categories\nexport const ErrorCategory = {\n AUTHENTICATION: 'AUTHENTICATION',\n ORCHESTRATOR: 'ORCHESTRATOR',\n VALIDATION: 'VALIDATION',\n WEBSOCKET: 'WEBSOCKET',\n};\n\n// Legacy events (for backward compatibility)\nexport const LegacyEvents = Object.freeze({\n MESSAGE: 'message',\n ERROR: 'error',\n});\n\n// SDK Events\nexport const EVENTS = Object.freeze({\n CONNECTION_OPEN: 'connection:open',\n CONNECTION_CLOSE: 'connection:close',\n CONNECTION_ERROR: 'connection:error',\n MESSAGE_RECEIVED: 'message:received',\n MESSAGE_SENT: 'message:sent',\n ERROR: 'error',\n RESPONSE: 'response',\n LEGACY_ERROR: 'error', // Both ERROR and LEGACY_ERROR map to 'error' for compatibility\n LEGACY_MESSAGE: 'message', // Legacy message handling for backward compatibility\n});\n\n// New events (to migrate to)\nexport const InboundEvents = Object.freeze({\n SUPERPOWER_RESPONSE: 'superpower.response',\n SUPERPOWER_ERROR: 'superpower.error',\n});\n\n// Allowed SDK actions (as Set for has() method)\nexport const ALLOWED_ACTIONS = new Set([\n 'adjust',\n 'elevate',\n 'interaction',\n 'assistant',\n 'reception',\n 'customerInteraction', // deprecated alias\n 'summarize',\n 'translate',\n 'recommend',\n 'insights',\n]);\n\n// Default payload size limit (128KB)\nexport const MAX_PAYLOAD_SIZE = 128 * 1024;\nexport const MAX_PAYLOAD_SIZE_KB = 128;\n\n// Default request timeout (30 seconds)\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 30000;\n\n// Default configuration object - exported as named export to avoid issues with tree-shaking default exports\nexport const CONSTANTS = {\n SPEC_VERSION,\n SCHEMA_REF,\n MAX_PAYLOAD_SIZE,\n MAX_PAYLOAD_SIZE_KB,\n DEFAULT_REQUEST_TIMEOUT_MS,\n ErrorCategory,\n LegacyEvents,\n EVENTS,\n InboundEvents,\n ALLOWED_ACTIONS,\n};\n\nexport default CONSTANTS;\n","/**\n * Configuration validation utilities for OptaveJavaScriptSDK\n * Complements AsyncAPI-generated validators with SDK-specific validation logic\n */\n\n// Client environment detection (extracted from main.js)\nconst isClientEnv = () => {\n // Detects browser, mobile, Electron renderer processes - environments where client secrets should NOT be used\n // Enhanced detection for test environments (like jsdom) that simulate server environments\n\n // Priority check: Node.js with test environment indicators\n // If we're in Node.js and have test-related environment variables or processes,\n // this is likely a server environment even if browser globals exist\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n // Check for test environment indicators\n const isTestEnv = process.env.NODE_ENV === 'test'\n || process.env.VITEST === 'true'\n || process.env.JEST_WORKER_ID !== undefined\n || process.argv.some((arg) => arg.includes('vitest') || arg.includes('jest') || arg.includes('test'));\n\n // In test environments, prefer server-side behavior unless explicitly configured otherwise\n if (isTestEnv) {\n // Only treat as client environment if specifically configured for browser testing\n // and globals are properly set up\n if (typeof globalThis !== 'undefined'\n && 'window' in globalThis && globalThis.window\n && 'document' in globalThis && globalThis.document\n && !process.env.OPTAVE_SDK_FORCE_SERVER_ENV) {\n // This is likely a browser test environment - check for explicit client intent\n return true;\n }\n return false; // Default to server environment in tests\n }\n }\n\n if (typeof globalThis !== 'undefined') {\n // Priority check: If both window and document were explicitly removed from global in tests,\n // this is a clear signal that the test is simulating a server environment\n if (!('window' in globalThis) && !('document' in globalThis)) {\n // Confirm we're in a Node.js test environment that has explicitly removed these\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return false; // Server environment (Node.js with no client globals)\n }\n }\n\n // Additional check: If either window or document was removed from global but the other exists,\n // this is also likely a server environment simulation in tests\n if ((!('window' in globalThis) || !('document' in globalThis))\n && typeof process !== 'undefined' && process.versions && process.versions.node) {\n return false; // Server environment simulation in test\n }\n\n // Check if window exists in global scope (browser or Electron renderer)\n if ('window' in globalThis && globalThis.window) {\n return true;\n }\n\n // Check if document exists in global scope\n if ('document' in globalThis && globalThis.document) {\n return true;\n }\n }\n\n // Fallback checks for environments where global object handling differs\n try {\n if (typeof window !== 'undefined' && window !== null) {\n // In jsdom test environments, if globalThis.window was deleted but window still exists,\n // check if this is an intentional server environment simulation\n if (typeof globalThis !== 'undefined' && !('window' in globalThis)) {\n return false; // Explicitly simulated server environment\n }\n // Additional robustness: if we're in Node.js but window exists,\n // and window was removed from global, treat as server environment\n if (typeof globalThis !== 'undefined' && typeof process !== 'undefined'\n && process.versions && process.versions.node && !('window' in globalThis)) {\n return false; // Server environment simulation\n }\n return true;\n }\n\n if (typeof document !== 'undefined' && document !== null) {\n // Same check for document\n if (typeof globalThis !== 'undefined' && !('document' in globalThis)) {\n return false; // Explicitly simulated server environment\n }\n // Additional robustness for document\n if (typeof globalThis !== 'undefined' && typeof process !== 'undefined'\n && process.versions && process.versions.node && !('document' in globalThis)) {\n return false; // Server environment simulation\n }\n return true;\n }\n } catch (e) {\n // Ignore errors from deleted/undefined globals in tests\n }\n\n // React Native detection\n if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {\n return true;\n }\n\n // Expo detection\n if (typeof globalThis !== 'undefined' && globalThis.__expo) {\n return true;\n }\n\n // Mobile environments often have location global\n if (typeof globalThis.location !== 'undefined' && globalThis.location !== null) {\n return true;\n }\n\n // Check for Node.js - server environment\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return false;\n }\n\n return false;\n};\n\n/**\n * Validates server-specific configuration options\n * @param {Object} options - SDK options\n * @returns {Array} Array of validation errors (empty if valid)\n */\nexport function validateServerConfig(options) {\n const errors = [];\n\n // Validate server authentication configuration\n if (options.authenticationUrl && (!options.clientId || !options.clientSecret)) {\n errors.push({\n type: 'warning',\n code: 'INCOMPLETE_AUTH_CONFIG',\n message: 'authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.',\n field: 'authentication',\n });\n }\n\n return errors;\n}\n\n/**\n * Validates client-specific configuration and enforces security rules\n * @param {Object} options - SDK options\n * @returns {Array} Array of validation errors (empty if valid)\n */\nexport function validateClientConfig(options) {\n const errors = [];\n\n // Hard stop if a client secret is present in any client environment (browser, mobile, Electron renderer)\n // Exception: Server builds (ESM and UMD) are allowed to use client secrets for internal deployment\n if (isClientEnv() && options.clientSecret) {\n // Check if this is a server build (ESM or UMD) - these are designed for server deployment\n // Note: Webpack DefinePlugin replaces these constants at build time\n let isServerUmd = false;\n let isServerEsm = false;\n\n try {\n isServerUmd = __SALESFORCE_BUILD__ === true;\n } catch (e) {\n // __SALESFORCE_BUILD__ not defined (source code context)\n }\n\n try {\n isServerEsm = __INCLUDE_WS_REQUIRE__ === true;\n } catch (e) {\n // __INCLUDE_WS_REQUIRE__ not defined (source code context)\n }\n\n const isServerBuild = isServerUmd || isServerEsm;\n\n if (!isServerBuild) {\n errors.push({\n type: 'error',\n code: 'CLIENT_SECRET_IN_CLIENT_ENV',\n message: 'clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.',\n field: 'clientSecret',\n });\n }\n // Note: Server builds (ESM and UMD) are allowed to use client secrets\n // because they target Node.js server environments, not browsers.\n // For Salesforce/browsers, use browser-umd build with tokenProvider instead.\n }\n\n return errors;\n}\n\n/**\n * Validates required configuration options\n * @param {Object} options - SDK options\n * @returns {Array} Array of validation errors (empty if valid)\n */\nexport function validateRequiredOptions(options) {\n const errors = [];\n\n if (!options.websocketUrl || typeof options.websocketUrl !== 'string') {\n errors.push({\n type: 'warning',\n code: 'MISSING_WEBSOCKET_URL',\n message: 'websocketUrl not provided; openConnection() will emit an error.',\n field: 'websocketUrl',\n });\n }\n\n return errors;\n}\n\n/**\n * Sets smart defaults based on environment and provided options\n * @param {Object} options - SDK options (will be mutated)\n * @returns {Object} The options object with defaults applied\n */\nexport function setSmartDefaults(options) {\n // strictValidation: when true (default in non-production), run schema validation; when false, skip for performance.\n if (typeof options.strictValidation === 'undefined') {\n const env = (typeof process !== 'undefined' && process.env && process.env.NODE_ENV) ? process.env.NODE_ENV : 'development';\n options.strictValidation = env !== 'production';\n }\n\n // Default request timeout (ms) for promise-based API (can be overridden per request)\n if (typeof options.requestTimeoutMs !== 'number') {\n options.requestTimeoutMs = 30000; // 30 seconds default (matches CONSTANTS.DEFAULT_REQUEST_TIMEOUT_MS)\n }\n\n // Default connection timeout (ms) for WebSocket connection establishment\n if (typeof options.connectionTimeoutMs !== 'number') {\n options.connectionTimeoutMs = 30000; // 30 seconds default for connection establishment\n }\n\n // Provide safe no-op logger interface if not supplied (debug/info/warn/error)\n if (!options.logger) {\n options.logger = {\n debug() {}, info() {}, warn() {}, error() {},\n };\n }\n\n // Default how we pass the WS token\n if (!options.authTransport) options.authTransport = 'subprotocol';\n\n if (typeof options.authRequired === 'undefined') options.authRequired = true;\n\n // Default tokenProvider uses tokenUrl\n if (!options.tokenProvider) {\n let url = options.tokenUrl;\n\n // (lets clients set it in HTML)\n if (!url && typeof document !== 'undefined') {\n const meta = document.querySelector('meta[name=\"optave-token-url\"]');\n if (meta && meta.content) url = meta.content;\n }\n if (!url) url = '/api/optave/ws-ticket'; // Temporary default yet to be implemented in backend\n\n options.tokenProvider = async () => {\n const headers = {};\n if (options.publishableKey) headers['X-Optave-Publishable-Key'] = options.publishableKey;\n const r = await fetch(url, { method: 'POST', credentials: 'include', headers });\n if (!r.ok) throw new Error('Failed to obtain WS token');\n const data = await r.json();\n return data.token || data.access_token;\n };\n }\n\n return options;\n}\n\n/**\n * Comprehensive validation function that runs all validation checks\n * @param {Object} options - SDK options\n * @returns {Object} Validation result with errors and warnings\n */\nexport function validateSDKConfig(options) {\n const result = {\n isValid: true,\n errors: [],\n warnings: [],\n };\n\n // Run all validation checks\n const requiredErrors = validateRequiredOptions(options);\n const serverErrors = validateServerConfig(options);\n const clientErrors = validateClientConfig(options);\n\n // Collect all validation results\n const allErrors = [...requiredErrors, ...serverErrors, ...clientErrors];\n\n // Separate errors from warnings\n allErrors.forEach((error) => {\n if (error.type === 'error') {\n result.errors.push(error);\n result.isValid = false;\n } else if (error.type === 'warning') {\n result.warnings.push(error);\n }\n });\n\n return result;\n}\n\n// Export environment detection utility for use in other modules\nexport { isClientEnv };\n","/**\n * Vocabulary-level PI guard for free-form payload fields.\n *\n * `session.channel.metadata` and `request.reference.*` must not carry direct\n * identifiers (names, emails, message content). `session.channel.location`\n * must be province grain at most — never precise coordinates.\n *\n * The analytics pipeline's raw store is append-only under Object Lock; a\n * leaked identifier cannot be simply deleted. This guard runs after schema\n * validation on every build (AJV and CSP-safe).\n */\n\nconst EMAIL_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/i;\nconst GPS_RE = /^\\s*-?\\d{1,3}(?:\\.\\d+)?\\s*,\\s*-?\\d{1,3}(?:\\.\\d+)?\\s*$/;\nconst IDENTIFIER_KEYS = new Set([\n 'email',\n 'e-mail',\n 'fullname',\n 'firstname',\n 'lastname',\n 'displayname',\n 'phone',\n 'phonenumber',\n 'ssn',\n 'dateofbirth',\n 'dob',\n 'nationalid',\n]);\n\nfunction createError(instancePath, message, params = {}) {\n return {\n instancePath,\n message,\n keyword: 'piGuard',\n params,\n };\n}\n\nfunction looksLikeMessageContent(value) {\n if (typeof value !== 'string') return false;\n const trimmed = value.trim();\n if (trimmed.includes('\\n') && trimmed.length > 40) return true;\n if (trimmed.length > 160 && /\\s/.test(trimmed) && /[.!?]/.test(trimmed)) return true;\n return false;\n}\n\nfunction scanString(value, path, errors) {\n if (typeof value !== 'string' || value.length === 0) return;\n if (EMAIL_RE.test(value)) {\n errors.push(createError(path, 'must not contain an email address', { kind: 'email' }));\n }\n if (GPS_RE.test(value)) {\n errors.push(createError(path, 'must not contain precise coordinates', { kind: 'coordinates' }));\n }\n if (looksLikeMessageContent(value)) {\n errors.push(createError(path, 'must not contain message content or other direct identifiers', { kind: 'messageContent' }));\n }\n}\n\nfunction scanUnknown(value, path, errors) {\n if (value == null) return;\n if (typeof value === 'string') {\n scanString(value, path, errors);\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, i) => scanUnknown(item, `${path}/${i}`, errors));\n return;\n }\n if (typeof value === 'object') {\n Object.entries(value).forEach(([key, nested]) => {\n if (IDENTIFIER_KEYS.has(key.toLowerCase())) {\n errors.push(createError(`${path}/${key}`, `must not carry direct identifier key '${key}'`, { kind: 'identifierKey', key }));\n }\n scanUnknown(nested, `${path}/${key}`, errors);\n });\n }\n}\n\n/**\n * Validate free-form payload fields against the PI vocabulary contract.\n * Schema-shape failures are the schema validator's job; this returns valid\n * when `data` is not an object so the schema validator can report that.\n *\n * @param {unknown} data\n * @returns {{ valid: boolean, errors: null | object[] }}\n */\nexport function validatePayloadPrivacy(data) {\n if (!data || typeof data !== 'object') {\n return { valid: true, errors: null };\n }\n\n const errors = [];\n const location = data.session?.channel?.location;\n if (typeof location === 'string' && location && GPS_RE.test(location)) {\n errors.push(createError(\n '/session/channel/location',\n 'must be province grain at most, never precise coordinates',\n { kind: 'coordinates' },\n ));\n }\n\n if (data.session?.channel?.metadata !== undefined) {\n scanUnknown(data.session.channel.metadata, '/session/channel/metadata', errors);\n }\n\n if (data.request?.reference !== undefined) {\n scanUnknown(data.request.reference, '/request/reference', errors);\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };\n}\n\n/**\n * Run schema validation first, then the PI vocabulary guard.\n *\n * @param {(data: unknown) => { valid: boolean, errors: null | object[] }} schemaValidate\n * @returns {(data: unknown) => { valid: boolean, errors: null | object[] }}\n */\nexport function withPrivacyGuard(schemaValidate) {\n return (data) => {\n const schemaResult = schemaValidate(data);\n if (!schemaResult.valid) return schemaResult;\n return validatePayloadPrivacy(data);\n };\n}\n","/**\n * Standardized build target enum and utilities\n *\n * This module provides a centralized definition of all build targets\n * used across webpack configurations and runtime code.\n */\n\n/**\n * Build target enum with all possible build configurations\n * @readonly\n * @enum {string}\n */\nexport const BUILD_TARGETS = {\n /** Browser ESM build (browser.mjs) - for modern ES modules in browsers */\n BROWSER_ESM: 'browser-esm',\n\n /** Server ESM build (server.mjs) - for Node.js ES modules */\n SERVER_ESM: 'server-esm',\n\n /** Browser UMD build (browser.umd.js) - for Salesforce/browsers with UMD wrapper */\n BROWSER_UMD: 'browser-umd',\n\n /** Server UMD build (server.umd.js) - for Node.js CommonJS environments with UMD wrapper */\n SERVER_UMD: 'server-umd',\n};\n\n/**\n * Legacy build target mapping for backward compatibility\n * Maps old 'browser'/'server' values to new specific targets\n * @readonly\n */\nexport const LEGACY_BUILD_TARGET_MAP = {\n browser: BUILD_TARGETS.BROWSER_ESM,\n server: BUILD_TARGETS.SERVER_ESM,\n};\n\n/**\n * Build target categories for easier classification\n * @readonly\n */\nexport const BUILD_TARGET_CATEGORIES = {\n /** All browser-targeted builds */\n BROWSER: [BUILD_TARGETS.BROWSER_ESM, BUILD_TARGETS.BROWSER_UMD],\n\n /** All server-targeted builds (Node.js environments) */\n SERVER: [BUILD_TARGETS.SERVER_ESM, BUILD_TARGETS.SERVER_UMD],\n\n /** All UMD builds */\n UMD: [BUILD_TARGETS.BROWSER_UMD, BUILD_TARGETS.SERVER_UMD],\n\n /** All ESM builds */\n ESM: [BUILD_TARGETS.BROWSER_ESM, BUILD_TARGETS.SERVER_ESM],\n};\n\n/**\n * Utility functions for build target operations\n */\nexport const BuildTargetUtils = {\n /**\n * Check if a build target is valid\n * @param {string} target - The build target to validate\n * @returns {boolean} True if valid\n */\n isValid(target) {\n return Object.values(BUILD_TARGETS).includes(target)\n || Object.keys(LEGACY_BUILD_TARGET_MAP).includes(target);\n },\n\n /**\n * Normalize a build target (handles legacy values)\n * @param {string} target - The build target to normalize\n * @returns {string} Normalized build target\n */\n normalize(target) {\n if (LEGACY_BUILD_TARGET_MAP[target]) {\n return LEGACY_BUILD_TARGET_MAP[target];\n }\n return Object.values(BUILD_TARGETS).includes(target) ? target : 'unknown';\n },\n\n /**\n * Check if build target is browser-focused\n * @param {string} target - The build target to check\n * @returns {boolean} True if browser build\n */\n isBrowser(target) {\n const normalized = this.normalize(target);\n return BUILD_TARGET_CATEGORIES.BROWSER.includes(normalized);\n },\n\n /**\n * Check if build target is server-focused\n * @param {string} target - The build target to check\n * @returns {boolean} True if server build\n */\n isServer(target) {\n const normalized = this.normalize(target);\n return BUILD_TARGET_CATEGORIES.SERVER.includes(normalized);\n },\n\n /**\n * Check if build target is UMD format\n * @param {string} target - The build target to check\n * @returns {boolean} True if UMD build\n */\n isUMD(target) {\n const normalized = this.normalize(target);\n return BUILD_TARGET_CATEGORIES.UMD.includes(normalized);\n },\n\n /**\n * Check if build target is ESM format\n * @param {string} target - The build target to check\n * @returns {boolean} True if ESM build\n */\n isESM(target) {\n const normalized = this.normalize(target);\n return BUILD_TARGET_CATEGORIES.ESM.includes(normalized);\n },\n\n /**\n * Get build target info for debugging\n * @param {string} target - The build target to analyze\n * @returns {object} Build target information\n */\n getInfo(target) {\n const normalized = this.normalize(target);\n return {\n original: target,\n normalized,\n valid: this.isValid(target),\n isBrowser: this.isBrowser(target),\n isServer: this.isServer(target),\n isUMD: this.isUMD(target),\n isESM: this.isESM(target),\n };\n },\n};\n","// errors.js\n\nclass OptaveError extends Error {\n /**\n * @param {Object} params\n * @param {'AUTHENTICATION'|'ORCHESTRATOR'|'VALIDATION'|'WEBSOCKET'|'UNKNOWN'} params.category\n * @param {string} params.code\n * @param {string} params.message\n * @param {any} [params.details]\n */\n constructor({\n category, code, message, details,\n }) {\n super(message);\n this.name = 'OptaveError';\n this.category = category || 'UNKNOWN';\n this.code = code || 'UNKNOWN';\n if (details !== undefined) this.details = details;\n }\n}\n\n/**\n * Normalize various raw error inputs to OptaveError\n * @param {any} raw\n * @returns {OptaveError}\n */\nfunction makeStructuredError(raw) {\n // Heuristics: map from raw shapes to categories/codes you already use internally.\n if (raw && raw.category && raw.code && raw.message) {\n return new OptaveError(raw);\n }\n if (typeof raw === 'string') {\n return new OptaveError({ category: 'UNKNOWN', code: 'STRING_ERROR', message: raw });\n }\n if (raw && raw.name === 'AjvValidationError') {\n return new OptaveError({\n category: 'VALIDATION', code: 'SCHEMA_VALIDATION', message: raw.message, details: raw.errors,\n });\n }\n if (raw && raw.isAuthError) {\n return new OptaveError({\n category: 'AUTHENTICATION', code: raw.code || 'AUTH_ERROR', message: raw.message || 'Authentication error', details: raw,\n });\n }\n if (raw && raw.isWsError) {\n return new OptaveError({\n category: 'WEBSOCKET', code: raw.code || 'WS_ERROR', message: raw.message || 'WebSocket error', details: raw,\n });\n }\n // Default\n return new OptaveError({\n category: 'UNKNOWN', code: 'UNCLASSIFIED', message: (raw && raw.message) || String(raw !== null && raw !== undefined ? raw : 'Unknown error'), details: raw,\n });\n}\n\nexport { OptaveError, makeStructuredError };\n","/**\n * Critical Security Guards for Optave SDK\n *\n * This file contains mandatory security validations that MUST be preserved\n * in all build outputs. Tree-shaking and dead code elimination tools\n * must NOT remove these security checks.\n *\n * SECURITY WARNING: Modifications to this file may introduce security vulnerabilities\n * in Salesforce Lightning environments and other constrained platforms.\n */\n\nimport { BuildTargetUtils } from './build-targets.js';\n\n/**\n * Runtime WebSocket scheme enforcement for UMD builds\n *\n * This guard prevents insecure WebSocket connections (ws://) in UMD builds,\n * which are specifically deployed in Salesforce Lightning environments where\n * the Locker Service blocks all insecure WebSocket connections.\n *\n * SECURITY: This function has intentional side effects (throws errors) and\n * must be preserved in all build outputs. Removing this validation creates\n * a security vulnerability in production environments.\n *\n * @param {string} websocketUrl - The WebSocket URL to validate\n * @param {string} buildTarget - The webpack build target identifier\n * @param {object} options - SDK configuration options\n * @throws {Error} When ws:// protocol is used in UMD builds\n * @throws {Error} When tokenProvider is missing for secure connections in UMD builds\n */\nexport function enforceWebSocketScheme(websocketUrl, buildTarget, options = {}) {\n // SECURITY: This function has observable side effects (throws on invalid schemes and\n // sets a global marker via initializeSecurityGuards) so bundlers must not optimize it away.\n\n if (!websocketUrl || typeof websocketUrl !== 'string') {\n return; // No validation needed if URL is not set or not a string\n }\n\n // Get build target information\n const normalizedTarget = BuildTargetUtils.normalize(buildTarget);\n\n // Check if this is a browser-targeted build that needs scheme validation\n // Browser builds include: browser-esm and browser-umd (Salesforce/Lightning)\n // Server builds (server-esm, server-umd) are for Node.js and allow ws:// for testing\n const isBrowserBuild = BuildTargetUtils.isBrowser(normalizedTarget);\n\n // CRITICAL: Validate WebSocket scheme for browser-targeted builds only\n // This guard prevents insecure connections in Salesforce Lightning and browser environments\n // Server-targeted builds (server-umd for Node.js CommonJS) are exempt to allow local testing\n if (isBrowserBuild && websocketUrl.startsWith('ws://')) {\n // SECURITY: This error message must remain intact to guide developers\n const errorMessage = '[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in browser builds. '\n + 'Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. '\n + 'Please use secure WebSocket protocol (wss://) instead. '\n + `Current URL: ${websocketUrl}`;\n\n // CRITICAL: This throw statement is a security boundary - must not be removed\n throw new Error(errorMessage);\n }\n\n // CRITICAL: For browser UMD builds with secure WebSocket URLs, validate token provider availability\n // This prevents authentication bypass in constrained Salesforce Lightning environments\n // Server UMD builds can use clientSecret authentication, so this check only applies to browser builds\n const isUMDBuild = BuildTargetUtils.isUMD(normalizedTarget);\n const isBrowserUMD = isBrowserBuild && isUMDBuild;\n\n if (isBrowserUMD && websocketUrl.startsWith('wss://')) {\n const hasTokenProvider = typeof options.tokenProvider === 'function';\n const hasAuthDisabled = options.authRequired === false;\n\n if (!hasTokenProvider && !hasAuthDisabled) {\n // SECURITY: This error message must remain intact to guide developers\n const errorMessage = '[Optave SDK] Browser UMD builds require a tokenProvider function for secure WebSocket connections. '\n + 'In constrained environments like Salesforce Lightning, authentication tokens must be obtained '\n + 'from your backend server. Please provide options.tokenProvider() that returns a valid token, '\n + 'or set options.authRequired = false to disable authentication. '\n + `Current URL: ${websocketUrl}`;\n\n // CRITICAL: This throw statement is a security boundary - must not be removed\n throw new Error(errorMessage);\n }\n }\n}\n\n/**\n * Initialize security guards on module load\n * This ensures the security validation code is evaluated and cannot be tree-shaken\n */\nfunction initializeSecurityGuards() {\n // SECURITY: Module-level side effect to prevent tree-shaking\n if (typeof globalThis !== 'undefined') {\n // Mark security guards as active - this creates a side effect\n globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__ = true;\n\n // Force evaluation by accessing the global in a way that cannot be optimized away\n const guardMarker = globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__;\n if (!guardMarker) {\n throw new Error('Security guard initialization failed');\n }\n }\n}\n\n// Execute initialization to create side effects - MUST NOT BE OPTIMIZED AWAY\ninitializeSecurityGuards();\n\n// Additional module-level side effect to ensure preservation\nif (typeof window !== 'undefined') {\n // Browser environment - ensure security guards are active\n window.__OPTAVE_SECURITY_GUARDS_BROWSER__ = true;\n} else if (typeof globalThis !== 'undefined') {\n // Node.js environment - ensure security guards are active.\n // Use globalThis (=== Node `global`) instead of a bare `global`: a free `global`\n // reference makes webpack inject its global-runtime helper, which relies on the\n // Function constructor and would violate Salesforce Lightning Locker CSP.\n globalThis.__OPTAVE_SECURITY_GUARDS_NODE__ = true;\n}\n\n/**\n * Export validation for external use\n * This provides a stable API for the main SDK class\n */\nexport { enforceWebSocketScheme as validateWebSocketScheme };\n","// Platform-aware EventEmitter import (resolved by webpack alias/replacement)\nimport EventEmitter from 'events';\nimport { v7 as uuidv7 } from 'uuid';\n// Version injected by webpack DefinePlugin for bundled builds, fallback to import for dev\n// Conditional import based on CSP compliance needs\nimport {\n validatePayload as validateGeneratedPayload,\n validateMessageEnvelope as validateGeneratedMessageEnvelope,\n} from '../../generated/validators.js';\nimport {\n validatePayload as validateBrowserPayload,\n validateMessageEnvelope as validateBrowserMessageEnvelope,\n} from '../platform/browser/validators.js';\n\nimport {\n CONSTANTS,\n SPEC_VERSION,\n SCHEMA_REF,\n ErrorCategory,\n LegacyEvents,\n EVENTS,\n InboundEvents,\n ALLOWED_ACTIONS,\n} from './constants.js';\nimport { validateSDKConfig, setSmartDefaults } from '../validation/config-validator.js';\nimport { validatePayloadPrivacy, withPrivacyGuard } from '../validation/pi-guard.js';\nimport { BuildTargetUtils } from './build-targets.js';\nimport { OptaveError, makeStructuredError } from './errors.js';\nimport loadNodeWebSocket from '../platform/node/websocket-loader.js';\nimport { enforceWebSocketScheme } from './security-guards.js';\n\nconst SDK_VERSION = typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0-dev';\n\n// Build-time environment detection using webpack DefinePlugin\nconst getBuildContext = () => {\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n return {\n isBrowser: BuildTargetUtils.isBrowser(buildTarget),\n isServer: BuildTargetUtils.isServer(buildTarget),\n buildTarget,\n };\n};\n\nconst isBrowserEnv = () => {\n const context = getBuildContext();\n // Use build target for webpack builds, fallback to runtime detection for dev\n return context.buildTarget !== 'unknown'\n ? context.isBrowser\n : (typeof window !== 'undefined' && typeof window.WebSocket !== 'undefined');\n};\n\n// Module-level warning flags for Step 5 dual event emission\nlet warnedMessageEventOnce = false;\nlet warnedErrorStringOnce = false;\n\n/**\n * Optave JavaScript SDK for WebSocket-based AI service integration\n * @typedef {import('./types.js').Opts} Opts\n * @typedef {import('./types.js').Logger} Logger\n * @typedef {import('../../generated/connection-config.js').AuthTransport} AuthTransport\n */\nclass OptaveJavaScriptSDK extends EventEmitter {\n options = {};\n\n wss = null;\n\n // The default payload. The payload provided by the user is merged \"on top\" of these objects\n /**\n * Default payload template. Typed fields below are the analytics context\n * vocabulary (the SDK captures, it never emits). `request.reference` is\n * client-custom labels only — never the carrier of typed analytics facts.\n * See docs/architecture/analytics-payload-field-map.md.\n */\n static defaultPayload = {\n session: {\n sessionId: '', // session identity — analytics session length/bands, peak concurrency\n channel: {\n browser: '',\n deviceInfo: '', // e.g. \"iOS/18.2, iPhone15,3\" — analytics device slices\n deviceType: '', // analytics dimension: \"mobile\" | \"desktop\" | \"tablet\"; omit when unknown\n language: '', // analytics conversation language (fr-share, fr-parity, lang-switch)\n location: '', // province grain at most (ISO 3166-2, e.g. \"US-NY\"); never precise coordinates\n medium: 'chat', // analytics dimension: \"chat\" | \"voice\" | \"email\"\n metadata: [], // free-form; MUST NOT carry names, emails, or message content\n section: '', // e.g. \"cart\", \"product_page\" — analytics engagement\n },\n interface: {\n appVersion: '', // emitter version — analytics provenance corroboration\n category: '', // e.g. \"crm\", \"app\", \"auto\", \"widget\" — analytics per-surface slices\n language: '', // the language from the crm agent\n name: '', // e.g. \"salesforce\", \"zendesk\" — analytics per-surface slices\n type: '', // e.g. \"custom_components\", \"marketplace\", \"channel\"\n },\n },\n request: {\n requestId: '',\n attributes: {\n content: '',\n instruction: '',\n variant: 'A', // analytics A/B experiment slice\n // replyTo: closed enum \"ai\" | \"self\" | \"none\". Omit when not reported\n // (absent !== \"none\"). Not defaulted to \"\" — empty string is not in the enum.\n },\n connections: {\n journeyId: '', // analytics returning-user / cross-conversation journey\n parentId: '', // in v2, this was called \"trace_parent_ID\"\n replyId: '', // opaque id of the replied-to message; hash if the source is a raw message id\n threadId: '', // conversation identity — unique per ticket/case/conversation\n },\n context: {\n // generated by optave\n caseId: '', // advanced mode — analytics resolution/escalation joins\n departmentId: '', // advanced mode — analytics ops slices\n operatorId: '', // advanced mode — analytics ops slices\n organizationId: '', // analytics org dimension\n userId: '', // advanced mode — pseudonymous user grain; consumers MUST hash\n },\n reference: {\n // client-custom labels ONLY — not typed analytics facts; no names/emails/message content\n ids: [{ name: '', value: '' }],\n labels: [],\n tags: [],\n },\n resources: {\n codes: [\n {\n id: '', // optional for tracking/mapping\n label: '', // optional, helps for display/templating - e.g. \"Order Number\"\n type: '', // e.g., \"order_number\", \"booking_reference\", \"ticket_code\", etc.\n value: '', // e.g. \"ORD-56789\"\n },\n ],\n links: [\n {\n expires_at: '', // optional - e.g. \"2025-08-06T00:00:00Z\"\n html: false, // optional\n id: '', // optional\n label: '', // optional - e.g. \"Click here to pay\"\n type: '', // e.g., \"payment_link\", etc.\n url: '', // e.g. \"https://checkout.stripe.com/pay/cs_test...\"\n },\n ],\n offers: [], // in v2, this was called \"offering_details\"\n },\n // Items below should only be sent if they are directly related to the request\n // There are two ways of sending it:\n // 1. Reference a previously created object (advanced mode)\n // Format: { id: \"\", name: \"\", type: \"\", timestamp: \"\" }, (mandatory: id)\n // 2. Send the object itself (risk: may exceed the payload size limit) - easy mode\n scope: {\n accounts: [],\n appointments: [],\n assets: [],\n bookings: [],\n cases: [],\n conversations: [], // in v2, this was called \"user_perspective\" - populate when actually sending conversation data\n documents: [],\n events: [],\n interactions: [],\n items: [],\n locations: [],\n operators: [],\n orders: [],\n organizations: [],\n persons: [],\n policies: [],\n products: [{ id: '' }],\n properties: [],\n services: [],\n subscriptions: [],\n tickets: [],\n transactions: [],\n users: [],\n // Missing something? We can add it for you, please contact our sales team.\n },\n settings: { // feature-usage flags — analytics reasoning-engagement\n disableBrowsing: false,\n disableSearch: false,\n disableSources: false,\n disableStream: true,\n disableTools: false,\n maxResponseLength: 0,\n overrideInterfaceLanguage: '',\n overrideOutputLanguage: '', // replaces the channel language\n },\n // Advanced mode — analytics human-vs-bot / operator-bot attribution:\n a2a: [\n { id: '', name: '', type: '' }, // e.g. { id: \"bot_55\", name: \"Bot 55\", type: \"chatbot\" }\n ],\n cursor: {\n since: '', // e.g. \"2024-01-15T10:30:00.000Z\"\n until: '', // e.g. \"2024-01-15T11:00:00.000Z\"\n },\n },\n };\n\n /**\n * Static cleanup method for shared/global resources (e.g., JSDOM contexts)\n * This should be called after all SDK instances have been cleaned up individually\n */\n static cleanup() {\n // Clear module-level warning flags\n warnedMessageEventOnce = false;\n warnedErrorStringOnce = false;\n\n // Additional static cleanup can be added here as needed\n // This is primarily for test environments using JSDOM or similar contexts\n }\n\n /**\n * Creates a new OptaveJavaScriptSDK instance\n * @param {Opts} options - Configuration options extending GeneratedClientConfig with SDK-specific settings\n */\n constructor(options) {\n super();\n\n // Apply smart defaults and validate configuration\n this.options = { ...options };\n setSmartDefaults(this.options);\n\n // Auto-detect CSP compliance mode based on build target\n if (this.options.cspSafe === undefined) {\n const context = getBuildContext();\n // ONLY server-esm uses full AJV validation\n // All other builds (browser-esm, browser-umd, server-umd) use CSP-safe mode\n if (context.buildTarget === 'server-esm' || context.buildTarget === 'server') {\n this.options.cspSafe = false; // Server ESM uses full AJV validation\n } else if (context.buildTarget === 'browser-esm' || context.buildTarget === 'browser-umd' || context.buildTarget === 'server-umd' || context.isBrowser || isBrowserEnv()) {\n this.options.cspSafe = true; // Browser builds and server-umd use CSP-safe mode\n }\n // If buildTarget is unknown/undefined, let user explicitly set cspSafe or use default undefined\n }\n\n const validation = validateSDKConfig(this.options);\n\n // Handle validation errors - throw for errors, warn for warnings\n if (!validation.isValid) {\n const errorMessages = validation.errors.map((e) => e.message).join('; ');\n throw new Error(`[Optave SDK] Configuration errors: ${errorMessages}`);\n }\n\n // Log warnings using the configured logger\n validation.warnings.forEach((warning) => {\n (this.options?.logger?.warn || console.warn)(`[Optave SDK] ${warning.message}`);\n });\n\n // WebSocket scheme validation for UMD/browser builds (Salesforce Locker compatibility)\n // SECURITY: This validation is critical for Salesforce Lightning security - must not be removed by tree-shaking\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n // Use canonical security guard - single source of truth for WebSocket validation.\n // Any thrown security error propagates to the caller (no try/catch needed - it would only rethrow).\n enforceWebSocketScheme(this.options.websocketUrl, buildTarget, this.options);\n\n // Initialize WebSocket implementation\n // Use build-aware WebSocket detection to avoid window references in server builds\n const context = getBuildContext();\n this.WebSocketImpl = this.options.WebSocketImpl;\n\n if (!this.WebSocketImpl && context.isBrowser) {\n // Browser builds: check global WebSocket then window.WebSocket\n this.WebSocketImpl = (typeof WebSocket !== 'undefined' ? WebSocket : undefined)\n || (typeof window !== 'undefined' && window.WebSocket ? window.WebSocket : undefined);\n } else if (!this.WebSocketImpl && context.isServer) {\n // Server builds: only check global WebSocket, no window references\n this.WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : undefined;\n }\n // Note: WebSocket implementation loading moved to _ensureWebSocketImpl() for async handling\n\n // Holds pending correlation promises: correlationId -> { resolve, reject, timer, action }\n this._pending = new Map();\n\n // Note: _activeTimeouts removed as we now use queueMicrotask() instead of setTimeout()\n // which doesn't require tracking IDs for cleanup\n\n // Deprecation tracking\n this._deprecatedKeys = new Set();\n this._silenceDeprecations = typeof process !== 'undefined' && process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS === '1';\n\n // Set up CSP-safe validation functions. PI guard wraps payload validation\n // on every build — the analytics raw store is append-only under Object Lock.\n if (this.options.cspSafe) {\n this._validatePayload = withPrivacyGuard(validateBrowserPayload);\n this._validateMessageEnvelope = validateBrowserMessageEnvelope;\n } else {\n this._validatePayload = withPrivacyGuard(validateGeneratedPayload);\n this._validateMessageEnvelope = validateGeneratedMessageEnvelope;\n }\n }\n\n // Async WebSocket implementation loader for ES module compatibility\n async _ensureWebSocketImpl() {\n if (this.WebSocketImpl) return this.WebSocketImpl;\n\n // Initialize WebSocket implementation with build-aware logic\n const context = getBuildContext();\n this.WebSocketImpl = this.options.WebSocketImpl;\n\n if (!this.WebSocketImpl && context.isBrowser) {\n // Browser builds: check global WebSocket then window.WebSocket\n this.WebSocketImpl = (typeof WebSocket !== 'undefined' ? WebSocket : undefined)\n || (typeof window !== 'undefined' && window.WebSocket ? window.WebSocket : undefined);\n } else if (!this.WebSocketImpl && context.isServer) {\n // Server builds: only check global WebSocket, no window references\n this.WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : undefined;\n }\n\n // Only attempt to load 'ws' module in Node.js environments if still not found\n if (!this.WebSocketImpl) {\n // Use webpack DefinePlugin to completely eliminate Node.js WebSocket imports in browser builds\n if (context.isBrowser) {\n // Browser build - use browser WebSocket implementation\n this.WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : null;\n } else if (context.isServer) {\n // Server build - load Node.js WebSocket implementation using webpack-friendly pattern\n this.WebSocketImpl = await this.loadNodeWebSocket();\n }\n }\n\n return this.WebSocketImpl;\n }\n\n // WebSocket loader for Node.js environments only\n async loadNodeWebSocket() {\n const context = getBuildContext();\n\n // Browser builds should never reach this code path, but double-check\n if (context.isBrowser) {\n return null;\n }\n\n // For fallback compatibility in dev environments, check browser globals\n if (context.buildTarget === 'unknown' && (\n typeof window !== 'undefined'\n || typeof document !== 'undefined'\n || typeof navigator !== 'undefined'\n || typeof globalThis.location !== 'undefined'\n )) {\n return null;\n }\n\n // Additional check for Node.js-specific globals\n if (typeof process === 'undefined' || !process.versions || !process.versions.node) {\n return null;\n }\n\n // Use static import instead of dynamic import for UMD builds\n return loadNodeWebSocket();\n }\n\n // Public static helpers for consumers (optional export pattern)\n static getSdkVersion() {\n return SDK_VERSION;\n }\n\n static getSpecVersion() {\n return SPEC_VERSION;\n }\n\n static getSchemaRef() {\n return SCHEMA_REF;\n }\n\n static get CONSTANTS() {\n return CONSTANTS;\n }\n\n // Static exports for constants (moved from named exports to avoid mixed export issues)\n static get LegacyEvents() {\n return LegacyEvents;\n }\n\n static get InboundEvents() {\n return InboundEvents;\n }\n\n setSessionId(id) {\n this.sessionId = id;\n return this; // allow chaining if you like\n }\n\n getSessionId() {\n return this.sessionId || '';\n }\n\n validate(jsonObject) {\n // Backward compatible boolean return; wraps validator (CSP-safe or AJV)\n const r = this._validatePayload(jsonObject);\n return r.valid;\n }\n\n validateEnvelope(envelope) {\n const r = this._validateMessageEnvelope(envelope);\n return r.valid;\n }\n\n // Schema validation is optional in production (strictValidation). The PI\n // vocabulary guard is not — the analytics raw store is append-only under\n // Object Lock, so coordinates and direct identifiers must never go out.\n _validateOutboundPayload(payload) {\n if (this.options.strictValidation) {\n return this._validatePayload(payload);\n }\n return validatePayloadPrivacy(payload);\n }\n\n // Validates action-specific required fields\n validateRequiredFields(params, action) {\n const errors = [];\n\n // Common required fields for all actions\n if (!params.request?.connections?.threadId) {\n errors.push('request.connections.threadId is required');\n }\n\n // Action-specific required fields\n switch (action) {\n case 'adjust':\n if (!params.request?.attributes?.content) {\n errors.push('request.attributes.content is required for adjust');\n }\n if (!params.request?.attributes?.instruction) {\n errors.push('request.attributes.instruction is required for adjust');\n }\n if (!params.request?.connections?.parentId) {\n errors.push('request.connections.parentId is required for adjust');\n }\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n 'request.scope.conversations is required for adjust and must be a non-empty array',\n );\n }\n break;\n\n case 'elevate':\n if (!params.request?.attributes?.content) {\n errors.push('request.attributes.content is required for elevate');\n }\n if (!params.request?.connections?.parentId) {\n errors.push('request.connections.parentId is required for elevate');\n }\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n 'request.scope.conversations is required for elevate and must be a non-empty array',\n );\n }\n break;\n\n case 'translate':\n case 'summarize':\n case 'insights':\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n `request.scope.conversations is required for ${action} and must be a non-empty array`,\n );\n }\n break;\n\n case 'recommend':\n if (\n !params.request?.resources?.offers\n || !Array.isArray(params.request.resources.offers)\n || params.request.resources.offers.length === 0\n ) {\n errors.push(\n 'request.resources.offers is required for recommend and must be a non-empty array',\n );\n }\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n 'request.scope.conversations is required for recommend and must be a non-empty array',\n );\n }\n break;\n\n case 'customerinteraction': // legacy lowercase for backward compatibility\n case 'customerInteraction': // current camelCase\n case 'interaction':\n case 'assistant':\n if (\n !params.request?.scope?.conversations\n || !Array.isArray(params.request.scope.conversations)\n || params.request.scope.conversations.length === 0\n ) {\n errors.push(\n `request.scope.conversations is required for ${action} and must be a non-empty array`,\n );\n }\n break;\n\n case 'reception':\n // Reception has no additional required fields beyond common ones.\n break;\n\n default:\n // For unknown actions, just check common required fields\n break;\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n }\n\n async authenticate() {\n // Browser-targeted builds should not use client credentials for security\n // Server builds (ESM and UMD) can authenticate with client credentials\n // Use the SDK's own build flags rather than environment variables for accuracy\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n const isBrowserTargetedBuild = BuildTargetUtils.isBrowser(buildTarget);\n\n if (isBrowserTargetedBuild) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'UNSUPPORTED_IN_BROWSER',\n 'authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend.',\n );\n return null;\n }\n const params = {\n grant_type: 'client_credentials',\n };\n\n if (!this.options.authenticationUrl) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'INVALID_AUTHENTICATION_URL',\n 'Empty or invalid authentication URL',\n );\n return null;\n }\n\n if (!this.options.clientId) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'INVALID_CLIENT_ID',\n 'Empty or invalid client ID',\n );\n return null;\n }\n\n params.client_id = this.options.clientId;\n // Never set clientSecret in browser/mobile/Electron renderers\n // Client secrets must only be used in secure server-side environments\n params.client_secret = this.options.clientSecret;\n\n const paramsString = new URLSearchParams(params).toString();\n\n // Automatically append /token to authenticationUrl if not present\n // This allows clients to provide base OAuth2 URL (e.g., /auth/oauth2)\n // without needing to remember the /token suffix\n let authUrl = this.options.authenticationUrl;\n if (!authUrl.endsWith('/token')) {\n authUrl = authUrl.endsWith('/') ? `${authUrl}token` : `${authUrl}/token`;\n }\n\n const url = `${authUrl}?${paramsString}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n });\n\n const responseJson = await response.json();\n\n if (!response.ok) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'INVALID_AUTHENTICATION_RESPONSE',\n this.formatAuthenticationError(response, responseJson.error, 'token endpoint').message,\n responseJson.error,\n );\n return null;\n }\n\n return responseJson.access_token;\n }\n\n async openConnection(bearerToken) {\n if (!this.options.websocketUrl) {\n (this.options?.logger?.error || console.error)(\n '[Optave SDK] openConnection aborted: missing websocketUrl',\n );\n this.handleError(\n ErrorCategory.WEBSOCKET,\n 'INVALID_WEBSOCKET_URL',\n this.formatWebSocketError(new Error('Invalid WebSocket URL configuration'), {\n url: this.options.websocketUrl,\n }).message,\n this.options.websocketUrl,\n );\n return undefined;\n }\n\n const getToken = async () => {\n if (typeof bearerToken === 'string' && bearerToken.length > 0) return bearerToken;\n if (typeof this.options.tokenProvider === 'function') {\n try {\n return await this.options.tokenProvider();\n } catch (e) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'TOKEN_PROVIDER_FAILED',\n this.formatTokenProviderError(e).message,\n e,\n );\n return null;\n }\n }\n return null;\n };\n\n const token = await getToken();\n\n // Ensure WebSocket implementation is available\n await this._ensureWebSocketImpl();\n\n if (!this.WebSocketImpl) {\n this.handleError(\n ErrorCategory.WEBSOCKET,\n 'NO_WEBSOCKET_IMPL',\n this.formatWebSocketError(new Error('No WebSocket implementation available'), {\n environment: typeof window !== 'undefined' ? 'browser' : 'node',\n }).message,\n );\n return undefined;\n }\n\n if (!token && this.options.authRequired !== false) {\n this.handleError(\n ErrorCategory.AUTHENTICATION,\n 'MISSING_TOKEN',\n 'No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.',\n );\n return undefined;\n }\n\n const qp = new URLSearchParams();\n if (this.sessionId) qp.set('OptaveTraceChatSessionId', this.sessionId);\n\n try {\n if (this.options.authTransport === 'subprotocol') {\n // Recommended: token via Sec-WebSocket-Protocol to avoid URL leaks\n const protocols = token ? ['optave-v1', token] : ['optave-v1'];\n this.wss = new this.WebSocketImpl(\n qp.toString()\n ? `${this.options.websocketUrl}?${qp.toString()}`\n : this.options.websocketUrl,\n protocols,\n );\n } else {\n // Fallback: token in query string (avoid if possible)\n if (token) {\n // For WebSocket query parameters, use raw token without Bearer prefix\n // The Bearer prefix is for HTTP headers, not WebSocket query parameters\n const val = token.replace(/^Bearer\\s+/i, '');\n qp.set('Authorization', val);\n }\n this.wss = new this.WebSocketImpl(\n qp.toString()\n ? `${this.options.websocketUrl}?${qp.toString()}`\n : this.options.websocketUrl,\n );\n if (token) {\n this._warnOnce(\n '_warnedQueryToken',\n '[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport=\"subprotocol\".',\n );\n }\n }\n } catch (error) {\n (this.options?.logger?.error || console.error)(\n '[Optave SDK] WebSocket constructor threw',\n error,\n );\n this.handleError(\n ErrorCategory.WEBSOCKET,\n 'WEBSOCKET_ERROR',\n this.formatWebSocketError(error, { url: this.options.websocketUrl }).message,\n error,\n );\n return undefined;\n }\n // Return a promise that resolves when the connection is established\n return new Promise((resolve, reject) => {\n // Set up connection timeout to prevent hanging\n const connectionTimeout = setTimeout(() => {\n const timeoutMs = this.options.connectionTimeoutMs || 30000;\n const errorMessage = this.formatWebSocketError(new Error('Connection timeout'), {\n timeout: timeoutMs,\n url: this.options.websocketUrl,\n }).message;\n\n // CRITICAL: Close the WebSocket to prevent zombie connections\n // Without this, the WebSocket continues attempting to connect in the background\n // causing resource leaks, race conditions, and connection conflicts on retry attempts\n if (this.wss) {\n // Clear event handlers first to prevent them from firing during close\n this.wss.onopen = null;\n this.wss.onmessage = null;\n this.wss.onclose = null;\n this.wss.onerror = null;\n\n // Close the connection\n try {\n this.wss.close();\n } catch (e) {\n // Ignore errors if WebSocket is in invalid state\n }\n\n // Mark as no active connection\n this.wss = null;\n }\n\n this.handleError(ErrorCategory.WEBSOCKET, 'CONNECTION_TIMEOUT', errorMessage);\n reject(new OptaveError({\n category: ErrorCategory.WEBSOCKET,\n code: 'CONNECTION_TIMEOUT',\n message: errorMessage,\n details: null,\n }));\n }, this.options.connectionTimeoutMs || 30000);\n\n this.wss.onopen = (event) => {\n clearTimeout(connectionTimeout);\n this.emit('open', event);\n resolve(event);\n };\n\n this.wss.onmessage = (event) => {\n this._handleInbound(event.data);\n };\n\n this.wss.onclose = (event) => {\n clearTimeout(connectionTimeout);\n this.emit('close', event);\n //\n // CRITICAL: Race condition prevention for promise handling\n // This pattern fixes race conditions where timeout timers compete with WebSocket events\n // The _handled flag ensures promises are only resolved/rejected once\n //\n // Reject all pending promises when connection closes\n Array.from(this._pending.entries()).forEach(([correlationId, entry]) => {\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark entry as handled to prevent timeout from firing\n entry._handled = true;\n entry.reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'CONNECTION_CLOSED',\n message: `WebSocket connection closed: ${event.reason || 'Connection lost'}`,\n details: { code: event.code, reason: event.reason, correlationId },\n correlationId,\n });\n });\n this._pending.clear();\n this.wss = null;\n };\n\n this.wss.onerror = (event) => {\n clearTimeout(connectionTimeout);\n //\n // CRITICAL: Enhanced error message handling and race condition prevention\n // This pattern fixes issues where test warnings revealed:\n // 1. Mock WebSocket error events not properly propagating error messages\n // 2. Race conditions between error handling and timeout timers\n // 3. Double promise resolution/rejection bugs\n //\n // Create error object - handle both native events and Error objects\n const errorMessage = event.message\n || (event instanceof Error ? event.message : null)\n || (typeof event === 'object' && event.error && event.error.message)\n || 'WebSocket connection failed';\n\n const errObj = {\n category: ErrorCategory.WEBSOCKET,\n code: 'CONNECTION_ERROR',\n message: errorMessage,\n details: { originalError: event },\n };\n\n // Reject all pending promises when WebSocket error occurs\n Array.from(this._pending.entries()).forEach(([correlationId, entry]) => {\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark entry as handled to prevent timeout from firing\n entry._handled = true;\n entry.reject({\n ...errObj,\n details: { ...errObj.details, correlationId },\n correlationId,\n });\n });\n this._pending.clear();\n\n // Emit error event for general error handling\n this.emit('error', errObj);\n\n // Reject the openConnection promise\n reject(errObj);\n };\n });\n }\n\n // ---- Inbound Routing & Warning Utilities ----\n _warnOnce(flagName, message) {\n if (this[flagName]) return;\n this[flagName] = true;\n (this.options?.logger?.warn || console.warn)(message);\n }\n\n // Deprecation helper (one-time per runtime per key)\n deprecate(key, message) {\n if (this._silenceDeprecations) return;\n if (this._deprecatedKeys.has(key)) return;\n this._deprecatedKeys.add(key);\n (this.options?.logger?.warn || console.warn)(message);\n }\n\n _handleInbound(rawPayload) {\n let parsed;\n\n try {\n parsed = typeof rawPayload === 'string' ? JSON.parse(rawPayload) : rawPayload;\n } catch (e) {\n const errObj = {\n category: ErrorCategory.WEBSOCKET,\n code: 'INVALID_JSON',\n message: 'Invalid JSON received from server',\n details: e,\n timestamp: new Date().toISOString(),\n };\n this._emitError(errObj);\n return;\n }\n\n const isEnvelope = parsed && parsed.headers && parsed.payload;\n const isError = parsed?.state === 'error' || parsed?.actionType === 'error' || !!parsed?.error;\n\n // Optional inbound validation (envelope) when strictValidation enabled\n if (this.options.strictValidation && isEnvelope) {\n const vr = this._validateMessageEnvelope(parsed);\n if (!vr.valid) {\n this.handleError(\n ErrorCategory.VALIDATION,\n 'INBOUND_ENVELOPE_SCHEMA_MISMATCH',\n this.formatValidationErrorMessage(vr.errors, 'Inbound envelope validation failed'),\n vr.errors,\n );\n }\n }\n\n if (isError) {\n const correlationId = (parsed?.headers && parsed.headers.correlationId) || parsed?.correlationId || null;\n const errObj = {\n category: ErrorCategory.ORCHESTRATOR,\n code: parsed?.error?.code || 'REMOTE_ERROR',\n message: parsed?.error?.message || parsed?.message || 'Remote error',\n details: parsed?.error || parsed,\n correlationId,\n };\n // Correlation rejection path\n if (correlationId && this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n entry._handled = true; // Mark as handled\n this._pending.delete(correlationId);\n entry.reject(errObj);\n }\n this._emitError(errObj, parsed?.action);\n return;\n }\n\n // Correlation fulfillment (success)\n const correlationId = parsed?.headers?.correlationId || parsed?.correlationId;\n if (correlationId && this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n entry._handled = true; // Mark as handled\n this._pending.delete(correlationId);\n entry.resolve(parsed);\n }\n\n // Legacy emission (unchanged)\n this.emit(LegacyEvents.MESSAGE, parsed);\n\n // One-time deprecation warning for legacy 'message'\n if (!warnedMessageEventOnce) {\n warnedMessageEventOnce = true;\n (this.options?.logger?.warn || console.warn)(\n '[optave-sdk][deprecation] The \"message\" event will be deprecated. Please also listen to \"superpower.response\".',\n );\n }\n\n // New event (same payload as legacy message)\n this.emit(InboundEvents.SUPERPOWER_RESPONSE, parsed);\n\n // New canonical response event (parsed object) - keeping existing behavior\n this.emit(EVENTS.RESPONSE, parsed);\n\n // Per-action convenience (lowercased) - keeping existing behavior\n if (parsed?.action) {\n this.emit(`message.${parsed.action}`.toLowerCase(), parsed);\n }\n\n // Preserve prior schemaRef emission for envelopes - keeping existing behavior\n if (isEnvelope && parsed.headers.schemaRef) {\n this.emit(parsed.headers.schemaRef, parsed);\n }\n }\n\n _emitError(errObj, _action = null) {\n if (!errObj.timestamp) {\n errObj.timestamp = new Date().toISOString();\n }\n\n // Legacy emission (unchanged) - keep emitting structured objects\n this.emit(LegacyEvents.ERROR, errObj);\n\n // One-time deprecation warning for legacy error events:\n if (!warnedErrorStringOnce) {\n warnedErrorStringOnce = true;\n (this.options?.logger?.warn || console.warn)(\n '[optave-sdk][deprecation] The \"error\" (string payload) is deprecated. Please also listen to \"superpower.error\" for a structured error object.',\n );\n }\n\n // New event: structured Error object (non-breaking because it's a new event name)\n const structuredError = makeStructuredError(errObj);\n this.emit(InboundEvents.SUPERPOWER_ERROR, structuredError);\n\n // Keep existing behavior for EVENTS.ERROR\n this.emit(EVENTS.ERROR, errObj);\n }\n\n closeConnection() {\n if (this.wss) {\n // Clear all WebSocket event handlers to break circular references\n this.wss.onopen = null;\n this.wss.onmessage = null;\n this.wss.onclose = null;\n this.wss.onerror = null;\n\n this.wss.close();\n this.wss = null;\n }\n }\n\n selectiveDeepMerge(target, source) {\n if (Array.isArray(target) && Array.isArray(source)) {\n // If both target and source are arrays, replace target with source\n return [...source];\n }\n\n // Use more reliable object detection that works across webpack contexts\n const isObject = (obj) => obj !== null && typeof obj === 'object' && !Array.isArray(obj);\n\n if (isObject(target) && isObject(source)) {\n const result = { ...target }; // Start with all target keys\n // Process all source keys, merging or overriding\n Object.keys(source).forEach((key) => {\n if (key in target) {\n // Recursively merge or replace values\n result[key] = this.selectiveDeepMerge(target[key], source[key]);\n } else {\n // Add new keys from source that don't exist in target\n result[key] = source[key];\n }\n });\n return result;\n }\n\n // For primitive values, return source value if it exists, else fallback to target\n return source !== undefined ? source : target;\n }\n\n isPayloadSizeValid(payloadString) {\n if (!payloadString) {\n return false;\n }\n\n // Check if the size is within the limit\n return payloadString.length / 1024 <= CONSTANTS.MAX_PAYLOAD_SIZE_KB;\n }\n\n openConnectionAsync(bearerToken) {\n return new Promise((resolve, reject) => {\n let onErr;\n const onOpen = (e) => {\n this.off('error', onErr);\n resolve(e);\n };\n onErr = (e) => {\n this.off('open', onOpen);\n reject(e);\n };\n this.once('open', onOpen);\n this.once('error', onErr);\n this.openConnection(bearerToken);\n });\n }\n\n buildPayload(requestType, action, params) {\n const payload = this.selectiveDeepMerge(OptaveJavaScriptSDK.defaultPayload, params);\n // Legacy alias mapping (variation -> variant) with deprecation notice\n if (params?.request?.variation) {\n this.deprecate(\n 'payload.request.variation',\n \"[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'.\",\n );\n payload.request.attributes.variant = params.request.variation;\n }\n // Legacy mapping: move request.content to attributes.content if provided at old location\n if (params?.request?.content && !payload.request?.attributes?.content) {\n payload.request.attributes.content = params.request.content;\n this.deprecate(\n 'payload.request.content',\n \"[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.\",\n );\n }\n\n // Ensure variant is properly set and uppercase\n if (payload.request.attributes.variant) {\n payload.request.attributes.variant = payload.request.attributes.variant.toUpperCase();\n }\n return payload;\n }\n\n // Maps action and request type to standardized AsyncAPI message ID\n resolveMessageId(requestType, action) {\n return `${action}.${requestType}.v3`.toLowerCase(); // e.g., \"adjust.message.v3\"\n }\n\n // Wraps payload in message envelope with headers for tracking and versioning (supports overrides)\n buildMessageEnvelope(payload, requestType, action, headerOverrides = {}) {\n const now = new Date().toISOString();\n const correlationId = headerOverrides.correlationId || payload?.request?.requestId || uuidv7();\n const traceId = headerOverrides.traceId || uuidv7();\n const idempotencyKey = headerOverrides.idempotencyKey || uuidv7();\n const { timestamp } = headerOverrides; // user event time (overrideable)\n const issuedAt = now; // envelope build time\n\n const headers = {\n correlationId,\n action,\n schemaRef: SCHEMA_REF,\n sdkVersion: SDK_VERSION,\n identifier: requestType,\n traceId,\n idempotencyKey,\n timestamp,\n issuedAt,\n };\n if (this.options.tenantId) {\n headers.tenantId = this.options.tenantId;\n }\n if (headerOverrides.networkLatencyMs !== undefined) {\n headers.networkLatencyMs = headerOverrides.networkLatencyMs;\n }\n // Freeze headers to prevent accidental mutation after envelope construction.\n // (Shallow freeze is enough because all current header values are primitives.)\n Object.freeze(headers);\n return {\n action: 'message',\n headers,\n payload,\n };\n }\n\n formatValidationErrorMessage(errors, baseMessage = 'Validation failed') {\n if (!errors || !Array.isArray(errors) || errors.length === 0) {\n return baseMessage;\n }\n\n // If there's only one error, provide a detailed explanation\n if (errors.length === 1) {\n const error = errors[0];\n const fieldPath = error.instancePath || '/';\n const field = fieldPath === '/' ? 'root object' : fieldPath.replace(/^\\//, '').replace(/\\//g, '.');\n\n if (error.keyword === 'required') {\n const missingField = error.params?.missingProperty || 'unknown field';\n // Handle case where instancePath already points to the missing property\n let fullFieldPath;\n if (field === 'root object') {\n fullFieldPath = missingField;\n } else if (field.endsWith(missingField)) {\n fullFieldPath = field;\n } else {\n fullFieldPath = `${field}.${missingField}`;\n }\n return `${baseMessage}: ${\n field === 'root object' ? 'Required field' : 'Field'\n } '${fullFieldPath}' is missing`;\n } if (error.keyword === 'type') {\n const expectedType = error.params?.type || 'unknown';\n return `${baseMessage}: Field '${field}' must be of type '${expectedType}'`;\n } if (error.keyword === 'additionalProperties') {\n const additionalProp = error.params?.additionalProperty || 'unknown';\n return `${baseMessage}: Field '${field}.${additionalProp}' is not allowed`;\n } if (error.keyword === 'enum') {\n const allowedValues = error.params?.allowedValues || [];\n const allowedStr = Array.isArray(allowedValues)\n ? allowedValues.join(', ')\n : 'unknown values';\n return `${baseMessage}: Field '${field}' must be one of: ${allowedStr}`;\n }\n return `${baseMessage}: ${error.message} at '${field}'`;\n }\n\n // If there are multiple errors, provide a summary with the most critical ones\n const criticalErrors = errors.filter((e) => e.keyword === 'required');\n const typeErrors = errors.filter((e) => e.keyword === 'type');\n const otherErrors = errors.filter((e) => e.keyword !== 'required' && e.keyword !== 'type');\n\n let summary = `${baseMessage}:`;\n\n if (criticalErrors.length > 0) {\n const missingFields = criticalErrors.map((e) => {\n const field = (e.instancePath || '/').replace(/^\\//, '').replace(/\\//g, '.');\n const missing = e.params?.missingProperty || 'unknown';\n return field === '' ? missing : `${field}.${missing}`;\n });\n summary += ` Missing required fields: ${missingFields.join(', ')}.`;\n }\n\n if (typeErrors.length > 0) {\n const typeIssues = typeErrors.slice(0, 3).map((e) => {\n const field = (e.instancePath || '/').replace(/^\\//, '').replace(/\\//g, '.');\n const expectedType = e.params?.type || 'unknown';\n return `${field || 'root'} (expected ${expectedType})`;\n });\n summary += ` Type errors in: ${typeIssues.join(', ')}.`;\n if (typeErrors.length > 3) summary += ` And ${typeErrors.length - 3} more type errors.`;\n }\n\n if (otherErrors.length > 0) {\n summary += ` Additional validation errors: ${otherErrors.length}.`;\n }\n\n return summary;\n }\n\n formatAuthenticationError(response, serverError, context) {\n let message = 'Authentication failed';\n const suggestions = [];\n\n // Include HTTP status if available\n if (response && response.status) {\n message += ` (HTTP ${response.status})`;\n }\n\n // Add server error details\n if (serverError) {\n if (typeof serverError === 'string') {\n message += `: ${serverError}`;\n } else if (serverError.error_description) {\n message += `: ${serverError.error_description}`;\n } else if (serverError.message) {\n message += `: ${serverError.message}`;\n } else if (serverError.error) {\n message += `: ${serverError.error}`;\n }\n }\n\n // Add context-specific suggestions\n if (response && response.status === 401) {\n suggestions.push('Verify clientId and clientSecret are correct');\n suggestions.push('Ensure credentials match the target environment (dev/staging/production)');\n } else if (response && response.status === 403) {\n suggestions.push('Check if your client has the necessary permissions');\n suggestions.push('Verify the authentication endpoint URL is correct');\n } else if (response && response.status >= 500) {\n suggestions.push('Authentication server error - try again later');\n suggestions.push('Contact support if the problem persists');\n } else {\n suggestions.push('Check network connectivity and authentication endpoint configuration');\n }\n\n // Add environment context if available\n if (context && context.authUrl) {\n message += ` (endpoint: ${context.authUrl})`;\n }\n\n return { message, suggestions };\n }\n\n formatWebSocketError(errorEvent, context) {\n let message = 'WebSocket connection failed';\n const suggestions = [];\n\n // Extract error details from different event types\n const errorMessage = errorEvent?.message\n || (errorEvent instanceof Error ? errorEvent.message : null)\n || (typeof errorEvent === 'object' && errorEvent.error && errorEvent.error.message)\n || null;\n\n if (errorMessage) {\n message += `: ${errorMessage}`;\n }\n\n // Add connection context\n if (context) {\n if (context.url) {\n message += ` (URL: ${context.url})`;\n }\n if (context.timeout) {\n message += ` (timeout: ${context.timeout}ms)`;\n }\n }\n\n // Provide troubleshooting suggestions\n suggestions.push('Check network connectivity and firewall settings');\n suggestions.push('Verify WebSocket URL is correct and accessible');\n\n if (context && context.url) {\n if (context.url.startsWith('ws://')) {\n suggestions.push('Consider using secure WebSocket (wss://) for production');\n }\n if (context.url.includes('localhost') || context.url.includes('127.0.0.1')) {\n suggestions.push('Ensure local server is running if connecting to localhost');\n }\n }\n\n if (context && context.timeout) {\n suggestions.push('Try increasing connection timeout if network is slow');\n }\n\n return { message, suggestions };\n }\n\n formatPayloadSizeError(actualSize, maxSize, payload) {\n const actualKB = Math.ceil(actualSize / 1024);\n const maxKB = maxSize;\n const overageKB = actualKB - maxKB;\n\n const message = `Payload too large: ${actualKB}KB exceeds maximum ${maxKB}KB (${overageKB}KB over limit)`;\n const suggestions = [];\n\n // Analyze payload for optimization suggestions\n if (payload && typeof payload === 'object') {\n // Check for large conversation arrays\n if (\n payload.request?.scope?.conversations\n && Array.isArray(payload.request.scope.conversations)\n ) {\n const conversationsSize = JSON.stringify(payload.request.scope.conversations).length;\n const conversationsKB = Math.ceil(conversationsSize / 1024);\n if (conversationsKB > 10) {\n // If conversations are more than 10KB\n suggestions.push(\n `Consider reducing conversation history - current size: ~${conversationsKB}KB`,\n );\n suggestions.push('Remove older messages or summarize conversation context');\n }\n }\n\n // Check for large offers arrays\n if (payload.request?.resources?.offers && Array.isArray(payload.request.resources.offers)) {\n const offersSize = JSON.stringify(payload.request.resources.offers).length;\n const offersKB = Math.ceil(offersSize / 1024);\n if (offersKB > 5) {\n suggestions.push(`Consider reducing product offers data - current size: ~${offersKB}KB`);\n }\n }\n\n // Check for large metadata\n if (payload.session?.channel?.metadata && Array.isArray(payload.session.channel.metadata)) {\n const metadataSize = JSON.stringify(payload.session.channel.metadata).length;\n const metadataKB = Math.ceil(metadataSize / 1024);\n if (metadataKB > 2) {\n suggestions.push(`Consider reducing metadata array - current size: ~${metadataKB}KB`);\n }\n }\n }\n\n // General suggestions if no specific optimizations found\n if (suggestions.length === 0) {\n suggestions.push('Remove unused fields from request payload');\n suggestions.push('Consider paginating large datasets');\n suggestions.push('Use shorter field values where possible');\n }\n\n return { message, suggestions };\n }\n\n formatTokenProviderError(originalError, context) {\n let message = 'Failed to obtain WebSocket token from tokenProvider()';\n const suggestions = [];\n\n // Add original error details\n if (originalError) {\n if (originalError.message) {\n message += `: ${originalError.message}`;\n } else if (typeof originalError === 'string') {\n message += `: ${originalError}`;\n }\n\n // Analyze error type for specific suggestions\n if (originalError.name === 'TypeError' && originalError.message?.includes('fetch')) {\n suggestions.push('Check if tokenProvider endpoint is accessible');\n suggestions.push('Verify CORS settings allow requests to token endpoint');\n } else if (\n originalError.message?.includes('404')\n || originalError.message?.includes('Not Found')\n ) {\n suggestions.push('Verify tokenProvider endpoint URL is correct');\n suggestions.push('Ensure backend token endpoint is implemented');\n } else if (originalError.message?.includes('401') || originalError.message?.includes('403')) {\n suggestions.push('Check authentication/authorization for token endpoint');\n suggestions.push('Verify user session or credentials are valid');\n } else if (originalError.message?.includes('timeout')) {\n suggestions.push(\n 'Token provider request timed out - check network or server response time',\n );\n }\n }\n\n // Add context-specific guidance\n if (context && context.tokenUrl) {\n message += ` (endpoint: ${context.tokenUrl})`;\n }\n\n // General troubleshooting suggestions\n if (suggestions.length === 0) {\n suggestions.push('Verify tokenProvider function implementation');\n suggestions.push('Check backend token endpoint is running and accessible');\n suggestions.push('Review browser console for network errors');\n }\n\n return { message, suggestions };\n }\n\n handleError(category, code, message, details = null, suggestions = [], correlationId = null) {\n const errObj = new OptaveError({\n category, code, message, details,\n });\n if (suggestions) errObj.suggestions = suggestions;\n if (correlationId) errObj.correlationId = correlationId;\n if (this.listenerCount(LegacyEvents.ERROR) === 0 && this.listenerCount(EVENTS.ERROR) === 0) {\n (this.options?.logger?.error || console.error)(`[Optave SDK] ${code}: ${message}`);\n }\n this._emitError(errObj);\n }\n\n send(requestType, action, params) {\n const OPEN = (this.WebSocketImpl && this.WebSocketImpl.OPEN) != null ? this.WebSocketImpl.OPEN : 1;\n if (!(this.wss && this.wss.readyState === OPEN)) {\n const readyState = this.wss ? this.wss.readyState : 'no connection';\n this.handleError(\n ErrorCategory.WEBSOCKET,\n 'WEBSOCKET_NOT_IN_OPEN_STATE',\n this.formatWebSocketError(new Error('WebSocket not ready for sending'), {\n readyState,\n action,\n }).message,\n );\n return;\n }\n if (!ALLOWED_ACTIONS.has(action)) {\n this.handleError(\n ErrorCategory.VALIDATION,\n 'INVALID_ACTION',\n `Unsupported action '${action}'. Allowed: ${[...ALLOWED_ACTIONS].join(', ')}`,\n );\n return;\n }\n\n // Lightweight additional-property detection BEFORE merge (top-level only)\n const allowedTopLevel = new Set(['session', 'request', 'headers']);\n const topLevelKeys = Object.keys(params || {});\n for (let i = 0; i < topLevelKeys.length; i += 1) {\n const k = topLevelKeys[i];\n if (!allowedTopLevel.has(k)) {\n const errors = [\n {\n instancePath: '',\n keyword: 'additionalProperties',\n params: { additionalProperty: k },\n message: `must NOT have additional property '${k}'`,\n },\n ];\n this.handleError(\n ErrorCategory.VALIDATION,\n 'PAYLOAD_SCHEMA_MISMATCH',\n this.formatValidationErrorMessage(errors),\n errors,\n );\n return;\n }\n }\n\n // Build merged payload first so defaults satisfy required properties\n const payload = this.buildPayload(requestType, action, params || {});\n\n // Validate required fields on merged payload FIRST (more specific error)\n const requiredFieldValidation = this.validateRequiredFields(payload || {}, action);\n if (!requiredFieldValidation.isValid) {\n this.handleError(\n ErrorCategory.VALIDATION,\n 'REQUIRED_FIELDS_MISSING',\n `Missing required fields for action '${action}': ${requiredFieldValidation.errors.join(\n ', ',\n )}`,\n requiredFieldValidation.errors,\n );\n return;\n }\n\n const outboundResult = this._validateOutboundPayload(payload);\n if (!outboundResult.valid) {\n this.handleError(\n ErrorCategory.VALIDATION,\n 'PAYLOAD_SCHEMA_MISMATCH',\n this.formatValidationErrorMessage(outboundResult.errors, 'Schema validation failed'),\n outboundResult.errors,\n );\n return;\n }\n\n const envelope = this.buildMessageEnvelope(payload, requestType, action, params?.headers || {});\n const payloadString = JSON.stringify(envelope);\n\n if (!this.isPayloadSizeValid(payloadString)) {\n const actualSize = payloadString.length; // Size in bytes\n this.handleError(\n ErrorCategory.VALIDATION,\n 'PAYLOAD_TOO_LARGE',\n this.formatPayloadSizeError(actualSize, CONSTANTS.MAX_PAYLOAD_SIZE_KB, envelope).message,\n CONSTANTS.MAX_PAYLOAD_SIZE_KB,\n );\n return;\n }\n this.wss.send(payloadString);\n }\n\n // The following functions send messages of a specific type to the WebSocket\n adjust(params) {\n return this.send('message', 'adjust', params);\n }\n\n elevate(params) {\n return this.send('message', 'elevate', params);\n }\n\n interaction(params) {\n return this.send('message', 'interaction', params);\n }\n\n assistant(params) {\n return this.send('message', 'assistant', params);\n }\n\n reception(params) {\n return this.send('message', 'reception', params);\n }\n\n // Deprecated alias (will be removed in a future major version)\n customerInteraction(params) {\n this.deprecate(\n 'method.customerInteraction',\n \"[Deprecation] 'customerInteraction' is deprecated; use 'interaction' instead.\",\n );\n return this.send('message', 'customerInteraction', params);\n }\n\n summarize(params) {\n return this.send('message', 'summarize', params);\n }\n\n translate(params) {\n return this.send('message', 'translate', params);\n }\n\n recommend(params) {\n return this.send('message', 'recommend', params);\n }\n\n insights(params) {\n return this.send('message', 'insights', params);\n }\n\n // ----- Promise-based Request API -----\n _registerPending(correlationId, action, timeoutMs, resolve, reject) {\n let timer = null;\n\n // Only set up timeout if timeoutMs is greater than 0\n if (timeoutMs > 0) {\n timer = setTimeout(() => {\n // Double-check that the promise hasn't been resolved/rejected by WebSocket events\n if (this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n // Only proceed if this entry hasn't been handled by WebSocket events\n if (entry && !entry._handled) {\n this._pending.delete(correlationId);\n entry._handled = true; // Mark as handled\n reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'REQUEST_TIMEOUT',\n message: `Request timed out after ${timeoutMs}ms`,\n details: { correlationId, action },\n correlationId,\n });\n }\n }\n }, timeoutMs);\n }\n\n this._pending.set(correlationId, {\n resolve, reject, timer, action, _handled: false,\n });\n }\n\n _promiseSend(requestType, action, params = {}, opts = {}) {\n let correlationId; // Declare outside promise to access later\n\n const promise = new Promise((resolve, reject) => {\n // Calculate timeout duration early to determine behavior\n let timeoutMs;\n if (typeof opts.timeoutMs === 'number') {\n timeoutMs = opts.timeoutMs;\n } else if (typeof opts.timeout === 'number') {\n timeoutMs = opts.timeout;\n } else {\n timeoutMs = this.options.requestTimeoutMs;\n }\n\n if (!this.wss || this.wss.readyState !== WebSocket.OPEN) {\n // If no timeout is specified, fail immediately with WebSocket state error\n if (timeoutMs <= 0) {\n reject(new OptaveError({\n category: ErrorCategory.WEBSOCKET,\n code: 'WEBSOCKET_NOT_IN_OPEN_STATE',\n message: 'WebSocket not open',\n details: null,\n }));\n return;\n }\n // Otherwise, let the timeout mechanism handle the failure\n // Generate correlationId for timeout tracking even when WebSocket is closed\n // Build minimal payload for correlationId generation\n const payload = this.buildPayload(requestType, action, params);\n const envelope = this.buildMessageEnvelope(\n payload,\n requestType,\n action,\n params?.headers || {},\n );\n correlationId = envelope.headers.correlationId;\n this._registerPending(correlationId, action, timeoutMs, resolve, reject);\n return; // Let timeout handle the rejection\n }\n if (!ALLOWED_ACTIONS.has(action)) {\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'INVALID_ACTION',\n message: `Unsupported action '${action}'.`,\n details: { allowed: [...ALLOWED_ACTIONS] },\n }));\n return;\n }\n // Additional property check (top-level) mirroring send()\n const allowedTopLevel = new Set(['session', 'request', 'headers']);\n const topLevelKeys = Object.keys(params || {});\n for (let i = 0; i < topLevelKeys.length; i += 1) {\n const k = topLevelKeys[i];\n if (!allowedTopLevel.has(k)) {\n const errors = [\n {\n instancePath: '',\n keyword: 'additionalProperties',\n params: { additionalProperty: k },\n message: `must NOT have additional property '${k}'`,\n },\n ];\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'PAYLOAD_SCHEMA_MISMATCH',\n message: this.formatValidationErrorMessage(errors),\n details: errors,\n }));\n return;\n }\n }\n const payload = this.buildPayload(requestType, action, params);\n\n // Validate required fields FIRST (more specific error)\n const requiredFieldValidation = this.validateRequiredFields(payload, action);\n if (!requiredFieldValidation.isValid) {\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'REQUIRED_FIELDS_MISSING',\n message: `Missing required fields for action '${action}'`,\n details: requiredFieldValidation.errors,\n }));\n return;\n }\n\n const outboundResult = this._validateOutboundPayload(payload);\n if (!outboundResult.valid) {\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'PAYLOAD_SCHEMA_MISMATCH',\n message: this.formatValidationErrorMessage(\n outboundResult.errors,\n 'Schema validation failed',\n ),\n details: outboundResult.errors,\n }));\n return;\n }\n const envelope = this.buildMessageEnvelope(\n payload,\n requestType,\n action,\n params?.headers || {},\n );\n correlationId = envelope.headers.correlationId; // Assign to outer scope variable\n\n // Register timeout for normal WebSocket flow\n this._registerPending(correlationId, action, timeoutMs, resolve, reject);\n\n const payloadString = JSON.stringify(envelope);\n if (!this.isPayloadSizeValid(payloadString)) {\n const actualSize = payloadString.length; // Size in bytes\n const errorMessage = this.formatPayloadSizeError(\n actualSize,\n CONSTANTS.MAX_PAYLOAD_SIZE_KB,\n envelope,\n ).message;\n reject(new OptaveError({\n category: ErrorCategory.VALIDATION,\n code: 'PAYLOAD_TOO_LARGE',\n message: errorMessage,\n details: { maxKb: CONSTANTS.MAX_PAYLOAD_SIZE_KB },\n }));\n return;\n }\n\n try {\n this.wss.send(payloadString);\n } catch (e) {\n if (this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n // Clear timer if it exists\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark as handled to prevent timeout from firing\n entry._handled = true;\n this._pending.delete(correlationId);\n }\n const sendError = new OptaveError({\n category: ErrorCategory.WEBSOCKET,\n code: 'SEND_FAILED',\n message: 'Failed to send over WebSocket',\n details: e,\n });\n sendError.correlationId = correlationId;\n reject(sendError);\n }\n });\n\n // Attach correlationId to the promise for external access\n promise.correlationId = correlationId;\n\n return promise;\n }\n\n // Promise-based helpers (suffix Async)\n adjustAsync(params, opts) {\n return this._promiseSend('message', 'adjust', params, opts);\n }\n\n elevateAsync(params, opts) {\n return this._promiseSend('message', 'elevate', params, opts);\n }\n\n interactionAsync(params, opts) {\n return this._promiseSend('message', 'interaction', params, opts);\n }\n\n assistantAsync(params, opts) {\n return this._promiseSend('message', 'assistant', params, opts);\n }\n\n receptionAsync(params, opts) {\n return this._promiseSend('message', 'reception', params, opts);\n }\n\n // Deprecated alias\n customerInteractionAsync(params, opts) {\n this.deprecate(\n 'method.customerInteractionAsync',\n \"[Deprecation] 'customerInteractionAsync' is deprecated; use 'interactionAsync' instead.\",\n );\n return this._promiseSend('message', 'customerInteraction', params, opts);\n }\n\n summarizeAsync(params, opts) {\n return this._promiseSend('message', 'summarize', params, opts);\n }\n\n translateAsync(params, opts) {\n return this._promiseSend('message', 'translate', params, opts);\n }\n\n recommendAsync(params, opts) {\n return this._promiseSend('message', 'recommend', params, opts);\n }\n\n insightsAsync(params, opts) {\n return this._promiseSend('message', 'insights', params, opts);\n }\n\n cancelRequest(correlationId) {\n if (this._pending.has(correlationId)) {\n const entry = this._pending.get(correlationId);\n // Clear timer if it exists\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark as handled to prevent timeout from firing\n entry._handled = true;\n this._pending.delete(correlationId);\n\n // Use setTimeout to allow any existing .catch() handlers to be attached\n setTimeout(() => {\n entry.reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'REQUEST_CANCELLED',\n message: 'Request was cancelled',\n details: { correlationId },\n correlationId,\n });\n }, 0);\n\n return true;\n }\n return false;\n }\n\n cancelPendingRequests(isCleaningUp = false) {\n // Defensive check: if cleanup() has already been called, _pending will be null\n if (!this._pending) {\n return 0;\n }\n\n const cancelledCount = this._pending.size;\n const entries = [...this._pending.entries()]; // Copy to avoid modification during iteration\n\n entries.forEach(([correlationId, entry]) => {\n // Clear timer if it exists\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n // Mark as handled to prevent timeout from firing\n entry._handled = true;\n\n if (isCleaningUp) {\n // During cleanup, reject immediately to prevent memory leaks from setTimeout\n entry.reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'REQUEST_CANCELLED',\n message: 'Request was cancelled during cleanup',\n details: { correlationId },\n correlationId,\n });\n } else {\n // Use queueMicrotask to allow any existing .catch() handlers to be attached\n // This is more appropriate than setTimeout(0) and doesn't depend on DOM context\n // eliminating the JSDOM window closure issue in UMD builds\n queueMicrotask(() => {\n entry.reject({\n category: ErrorCategory.WEBSOCKET,\n code: 'REQUEST_CANCELLED',\n message: 'Request was cancelled',\n details: { correlationId },\n correlationId,\n });\n });\n }\n });\n this._pending.clear();\n return cancelledCount;\n }\n\n /**\n * Comprehensive cleanup method to prevent memory leaks\n * Cleans up all internal state including Maps, Sets, and WebSocket connections\n */\n cleanup() {\n // Close WebSocket connection first to break external references\n this.closeConnection();\n\n // Cancel all pending requests and clear timers\n // Pass isCleaningUp=true to avoid creating new timeouts during cleanup\n this.cancelPendingRequests(true);\n\n // Note: No timeout cleanup needed since we use queueMicrotask() instead of setTimeout()\n // queueMicrotask() doesn't require manual cleanup as it doesn't hold references\n\n // Clear internal data structures\n if (this._deprecatedKeys) {\n this._deprecatedKeys.clear();\n }\n\n // Clear any warning flags (instance-specific)\n if (this._warnedQueryToken !== undefined) {\n delete this._warnedQueryToken;\n }\n\n // CRITICAL: Clear EventEmitter state BEFORE calling removeAllListeners\n // This prevents the complex removeAllListeners override from interfering\n if (this._events) {\n // Manually clear each event to break listener references\n Object.keys(this._events).forEach((event) => {\n delete this._events[event];\n });\n }\n\n // Now remove all listeners (this should be mostly a no-op after manual cleanup)\n this.removeAllListeners();\n\n // CRITICAL: Set EventEmitter properties to null AFTER removeAllListeners\n // This ensures complete cleanup before breaking prototype chain\n this._events = null;\n this._eventsCount = null;\n this._maxListeners = null;\n\n // CRITICAL: Clean up JSDOM contexts created by SDK loader\n // UMD builds loaded through test infrastructure create JSDOM environments\n // that must be explicitly closed to prevent memory leaks\n // Only run in non-server builds to avoid window references in server.mjs\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n if (buildTarget !== 'server-esm' && buildTarget !== 'server-umd') {\n if (this.constructor._preservedJSDOM && this.constructor._preservedJSDOM.dom) {\n try {\n // Access window through dom property to minimize direct window references\n const domWindow = this.constructor._preservedJSDOM.dom.window;\n if (domWindow && typeof domWindow.close === 'function') {\n domWindow.close();\n }\n delete this.constructor._preservedJSDOM;\n } catch (e) {\n // Ignore errors if JSDOM is already closed\n }\n }\n }\n\n // Clear function references that might hold closures\n this._validatePayload = null;\n this._validateOutboundPayload = null;\n this._validateMessageEnvelope = null;\n this._emitError = null;\n this._ensureWebSocketImpl = null;\n this._handleInbound = null;\n this._promiseSend = null;\n this._registerPending = null;\n this._warnOnce = null;\n\n // Clear object references completely\n this.options = null;\n this.WebSocketImpl = null;\n this.wss = null;\n this.sessionId = null;\n\n // Clear collections with explicit null assignment\n this._pending = null;\n this._deprecatedKeys = null;\n\n // Clear primitive flags\n this._silenceDeprecations = null;\n\n // FINAL: Ensure EventEmitter properties are definitively null after all cleanup\n // This must be LAST to override any potential resets from removeAllListeners\n this._events = null;\n this._eventsCount = null;\n this._maxListeners = null;\n }\n\n /**\n * Override removeAllListeners to include internal cleanup\n * Simplified to avoid complex fallback logic that might interfere with GC\n */\n removeAllListeners(event) {\n // Try the parent EventEmitter method\n try {\n EventEmitter.prototype.removeAllListeners.call(this, event);\n } catch (e) {\n // Fallback: manual cleanup if parent method fails\n if (!event) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (this._events && this._events[event]) {\n delete this._events[event];\n this._eventsCount = Math.max(0, this._eventsCount - 1);\n }\n }\n\n return this;\n }\n\n // Static properties for build configuration flags (used by webpack DefinePlugin)\n static get buildFlags() {\n const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';\n\n return {\n SALESFORCE_BUILD: typeof __SALESFORCE_BUILD__ !== 'undefined' ? __SALESFORCE_BUILD__ : false,\n INCLUDE_WS_REQUIRE:\n typeof __INCLUDE_WS_REQUIRE__ !== 'undefined' ? __INCLUDE_WS_REQUIRE__ : true,\n SDK_VERSION: typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0-dev',\n WEBPACK_BUILD_TARGET: buildTarget,\n WEBPACK_BUILD_TARGET_NORMALIZED: BuildTargetUtils.normalize(buildTarget),\n BUILD_TARGET_INFO: BuildTargetUtils.getInfo(buildTarget),\n };\n }\n}\n\n// Export as both named and default to work with UMD without getter patterns\n// UMD builds: globalThis.OptaveJavaScriptSDK (via default export)\n// ESM builds: import { OptaveJavaScriptSDK } from '@optave/client-sdk'\nexport { OptaveJavaScriptSDK };\nexport default OptaveJavaScriptSDK;\n","// Node.js WebSocket loader - uses static import for UMD builds\nimport ws from 'ws';\n\nexport default async function loadNodeWebSocket() {\n // Complete early exit for any browser-like environment\n if (typeof window !== 'undefined' || typeof document !== 'undefined'\n || typeof navigator !== 'undefined' || typeof globalThis.location !== 'undefined') {\n return null;\n }\n\n // Additional check for Node.js-specific globals\n if (typeof process === 'undefined' || !process.versions || !process.versions.node) {\n return null;\n }\n\n // Return statically imported ws module for UMD builds\n return ws;\n}\n","/* eslint-disable no-bitwise */\n// Bitwise operators below are intrinsic to the UUID v7 bit-field packing/PRNG algorithm and cannot be removed.\n// Browser crypto polyfill for UUID v7 generation\n// This provides a Node.js crypto compatible interface for browser environments\n// UUID v7 implementation adapted from https://github.com/LiosK/uuidv7 (Apache-2.0 License)\n\n// Resolve the crypto implementation once at module load. Returned from a function so the\n// module-level binding can be a const (avoids exporting a mutable `let`).\nfunction resolveCryptoImplementation() {\n if (typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.getRandomValues) {\n return globalThis.crypto;\n }\n if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {\n return window.crypto;\n }\n if (typeof globalThis !== 'undefined' && globalThis.self\n && globalThis.self.crypto && globalThis.self.crypto.getRandomValues) {\n return globalThis.self.crypto;\n }\n // Fallback implementation using Math.random()\n return {\n getRandomValues(array) {\n for (let i = 0; i < array.length; i += 1) {\n array[i] = Math.floor(Math.random() * 256);\n }\n return array;\n },\n };\n}\n\nconst cryptoImplementation = resolveCryptoImplementation();\n\n// Buffered crypto random number generator.\n// Implemented as a factory (not a class) to keep this file within the single-class limit;\n// behavior is identical to the original `new BufferedCryptoRandom()` usage.\nfunction createBufferedCryptoRandom() {\n const buffer = new Uint32Array(8);\n let cursor = 0xffff;\n\n return {\n nextUint32() {\n if (cursor >= buffer.length) {\n cryptoImplementation.getRandomValues(buffer);\n cursor = 0;\n }\n const value = buffer[cursor];\n cursor += 1;\n return value;\n },\n };\n}\n\n// UUID v7 Generator class adapted from LiosK/uuidv7\nclass V7Generator {\n constructor() {\n this.timestamp = 0;\n this.counter = 0;\n this.random = this._getRandomNumberGenerator();\n }\n\n _getRandomNumberGenerator() {\n if (typeof cryptoImplementation !== 'undefined' && typeof cryptoImplementation.getRandomValues !== 'undefined') {\n return createBufferedCryptoRandom();\n }\n // Fallback using Math.random()\n return {\n nextUint32: () => Math.trunc(Math.random() * 0x10000) * 0x10000 + Math.trunc(Math.random() * 0x10000),\n };\n }\n\n generate() {\n return this.generateOrResetCore(Date.now(), 10000);\n }\n\n generateOrResetCore(unixTsMs, rollbackAllowance) {\n let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);\n if (value === undefined) {\n this.timestamp = 0;\n value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);\n }\n return value;\n }\n\n generateOrAbortCore(unixTsMs, rollbackAllowance) {\n const MAX_COUNTER = 0x3fffffff_fff;\n\n if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 0xffffffffffff) {\n throw new RangeError('unixTsMs must be a 48-bit positive integer');\n }\n\n if (unixTsMs > this.timestamp) {\n this.timestamp = unixTsMs;\n this.resetCounter();\n } else if (unixTsMs + rollbackAllowance >= this.timestamp) {\n this.counter++;\n if (this.counter > MAX_COUNTER) {\n this.timestamp++;\n this.resetCounter();\n }\n } else {\n return undefined;\n }\n\n return this.fromFieldsV7(\n this.timestamp,\n Math.trunc(this.counter / (2 ** 30)),\n this.counter & (2 ** 30 - 1),\n this.random.nextUint32(),\n );\n }\n\n resetCounter() {\n this.counter = this.random.nextUint32() * 0x400 + (this.random.nextUint32() & 0x3ff);\n }\n\n fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {\n const bytes = new Uint8Array(16);\n bytes[0] = unixTsMs / (2 ** 40);\n bytes[1] = unixTsMs / (2 ** 32);\n bytes[2] = unixTsMs / (2 ** 24);\n bytes[3] = unixTsMs / (2 ** 16);\n bytes[4] = unixTsMs / (2 ** 8);\n bytes[5] = unixTsMs;\n bytes[6] = 0x70 | (randA >>> 8);\n bytes[7] = randA;\n bytes[8] = 0x80 | (randBHi >>> 24);\n bytes[9] = randBHi >>> 16;\n bytes[10] = randBHi >>> 8;\n bytes[11] = randBHi;\n bytes[12] = randBLo >>> 24;\n bytes[13] = randBLo >>> 16;\n bytes[14] = randBLo >>> 8;\n bytes[15] = randBLo;\n\n return this.bytesToString(bytes);\n }\n\n bytesToString(bytes) {\n const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');\n return [\n hex.substring(0, 8),\n hex.substring(8, 12),\n hex.substring(12, 16),\n hex.substring(16, 20),\n hex.substring(20, 32),\n ].join('-');\n }\n}\n\n// Create default generator instance\nlet defaultGenerator = null;\n\n// Override randomUUID and generateUUID to use UUID v7\ncryptoImplementation.randomUUID = function () {\n if (!defaultGenerator) {\n defaultGenerator = new V7Generator();\n }\n return defaultGenerator.generate();\n};\n\ncryptoImplementation.generateUUID = function () {\n if (!defaultGenerator) {\n defaultGenerator = new V7Generator();\n }\n return defaultGenerator.generate();\n};\n\n// Generate short ID using UUID v7 for cryptographic security\n// Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility\ncryptoImplementation.generateShortId = function () {\n return defaultGenerator.generate().replace(/-/g, '').substring(0, 9);\n};\n\n// Ensure crypto is available globally for UUID library\n// Check if crypto property is configurable before attempting to set it\nfunction setSafeCrypto(globalObj, propName) {\n if (!globalObj || globalObj.crypto) return; // Already exists\n\n try {\n const descriptor = Object.getOwnPropertyDescriptor(globalObj, propName);\n if (!descriptor || descriptor.configurable !== false) {\n globalObj.crypto = cryptoImplementation;\n }\n } catch {\n // Ignore errors when crypto property is read-only (e.g., in JSDOM).\n // No logger is available in this standalone polyfill, so swallow silently.\n }\n}\n\nif (typeof globalThis !== 'undefined') {\n setSafeCrypto(globalThis, 'crypto');\n}\nif (typeof window !== 'undefined') {\n setSafeCrypto(window, 'crypto');\n}\nif (typeof globalThis !== 'undefined' && globalThis.self) {\n setSafeCrypto(globalThis.self, 'crypto');\n}\n\n// Support both CommonJS and ES modules with environment detection\ntry {\n // Check if we're in a CommonJS environment where module.exports is writable\n if (typeof module !== 'undefined' && typeof module.exports === 'object' && typeof require !== 'undefined') {\n // CommonJS environment - try to assign, but catch any errors in case it's read-only\n module.exports = cryptoImplementation;\n module.exports.default = cryptoImplementation;\n module.exports.getRandomValues = cryptoImplementation.getRandomValues.bind(cryptoImplementation);\n module.exports.randomUUID = cryptoImplementation.randomUUID ? cryptoImplementation.randomUUID.bind(cryptoImplementation) : cryptoImplementation.randomUUID;\n module.exports.generateUUID = cryptoImplementation.generateUUID.bind(cryptoImplementation);\n module.exports.generateShortId = cryptoImplementation.generateShortId.bind(cryptoImplementation);\n }\n} catch (e) {\n // ES module environment where module.exports is read-only - ignore the error\n // ES module exports will be used instead\n}\n\n// ES module exports for compatibility\nexport const getRandomValues = cryptoImplementation.getRandomValues.bind(cryptoImplementation);\nexport const randomUUID = cryptoImplementation.randomUUID ? cryptoImplementation.randomUUID.bind(cryptoImplementation) : cryptoImplementation.randomUUID;\nexport const generateUUID = cryptoImplementation.generateUUID.bind(cryptoImplementation);\nexport const generateShortId = cryptoImplementation.generateShortId.bind(cryptoImplementation);\n\n// Default export for integration compatibility\nexport default cryptoImplementation;\n","// UMD-specific entry point that exports constructor function directly\n// This avoids webpack getter patterns that fail in Salesforce LockerService\n\nimport { OptaveJavaScriptSDK } from './main.js';\n// Import crypto polyfill for side effects (sets up global crypto for UUID generation)\nimport '../platform/browser/crypto-polyfill.js';\n\n// Expose the constructor on the browser global, preferring `window`.\n// Salesforce Lightning loads this UMD bundle as a static resource and reads\n// `window.OptaveJavaScriptSDK`; under Lightning Locker the component's global is\n// `window` (a SecureWindow), which is NOT guaranteed to be the same object as\n// `globalThis`. We assign to both `window` (browser/Salesforce) and `globalThis`\n// (Node, and web workers where globalThis === self), which together cover every\n// target. Idempotent and defensive.\nif (typeof window !== 'undefined' && !window.OptaveJavaScriptSDK) {\n try {\n window.OptaveJavaScriptSDK = OptaveJavaScriptSDK;\n } catch { /* noop – defensive */ }\n}\nif (typeof globalThis !== 'undefined' && !globalThis.OptaveJavaScriptSDK) {\n try {\n globalThis.OptaveJavaScriptSDK = OptaveJavaScriptSDK;\n } catch { /* noop – defensive */ }\n}\n\n// Export default for webpack UMD library.export: 'default'\n// Consumers using script tags get globalThis.OptaveJavaScriptSDK; module/bundler\n// users import the default export.\nexport default OptaveJavaScriptSDK;\n"],"names":["webpackUniversalModuleDefinition","root","factory","exports","module","require","define","amd","globalThis","this","__WEBPACK_EXTERNAL_MODULE__761__","__WEBPACK_EXTERNAL_MODULE__2__","URLSearchParamsPolyfill","constructor","init","params","Map","replace","split","forEach","pair","key","value","set","decodeURIComponent","String","Array","isArray","Object","entries","append","name","existing","get","undefined","delete","getAll","has","toString","pairs","val","push","encodeURIComponent","join","Symbol","iterator","paramEntries","from","i","length","values","j","keys","all","callback","thisArg","call","URLSearchParams","window","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","d","definition","binding","o","defineProperty","enumerable","obj","prop","prototype","hasOwnProperty","rnds8","Uint8Array","rng","crypto","getRandomValues","byteToHex","slice","unsafeStringify","arr","offset","toLowerCase","_state","v7Bytes","rnds","msecs","seq","buf","Error","RangeError","Date","now","v7Sequence","options","bytes","random","state","Infinity","updateV7State","createError","instancePath","message","keyword","validatePayload","data","valid","errors","type","session","sessionId","missingProperty","request","connections","threadId","parentId","replyId","replyTarget","allowedReplyTargets","includes","allowedValues","context","attributes","replyTo","allowedReplyTo","scope","conversations","resources","offers","validateMessageEnvelope","headers","correlationId","action","allowedActions","identifier","schemaRef","timestamp","payload","limit","SCHEMA_REF","ErrorCategory","AUTHENTICATION","ORCHESTRATOR","VALIDATION","WEBSOCKET","LegacyEvents","freeze","MESSAGE","ERROR","EVENTS","CONNECTION_OPEN","CONNECTION_CLOSE","CONNECTION_ERROR","MESSAGE_RECEIVED","MESSAGE_SENT","RESPONSE","LEGACY_ERROR","LEGACY_MESSAGE","InboundEvents","SUPERPOWER_RESPONSE","SUPERPOWER_ERROR","ALLOWED_ACTIONS","Set","CONSTANTS","SPEC_VERSION","MAX_PAYLOAD_SIZE","MAX_PAYLOAD_SIZE_KB","DEFAULT_REQUEST_TIMEOUT_MS","validateClientConfig","process","versions","node","env","VITEST","JEST_WORKER_ID","argv","some","arg","document","OPTAVE_SDK_FORCE_SERVER_ENV","e","navigator","product","__expo","location","isClientEnv","clientSecret","isServerUmd","isServerEsm","code","field","EMAIL_RE","GPS_RE","IDENTIFIER_KEYS","scanUnknown","path","item","nested","kind","test","trimmed","trim","looksLikeMessageContent","scanString","validatePayloadPrivacy","channel","metadata","reference","withPrivacyGuard","schemaValidate","schemaResult","BUILD_TARGETS","BROWSER_ESM","SERVER_ESM","BROWSER_UMD","SERVER_UMD","LEGACY_BUILD_TARGET_MAP","browser","server","BUILD_TARGET_CATEGORIES","BROWSER","SERVER","UMD","ESM","BuildTargetUtils","isValid","target","normalize","isBrowser","normalized","isServer","isUMD","isESM","getInfo","original","OptaveError","category","details","super","__OPTAVE_SECURITY_GUARDS_ACTIVE__","initializeSecurityGuards","__OPTAVE_SECURITY_GUARDS_BROWSER__","__OPTAVE_SECURITY_GUARDS_NODE__","SDK_VERSION","getBuildContext","buildTarget","warnedMessageEventOnce","warnedErrorStringOnce","OptaveJavaScriptSDK","wss","static","deviceInfo","deviceType","language","medium","section","interface","appVersion","requestId","content","instruction","variant","journeyId","caseId","departmentId","operatorId","organizationId","userId","ids","labels","tags","codes","id","label","links","expires_at","html","url","accounts","appointments","assets","bookings","cases","documents","events","interactions","items","locations","operators","orders","organizations","persons","policies","products","properties","services","subscriptions","tickets","transactions","users","settings","disableBrowsing","disableSearch","disableSources","disableStream","disableTools","maxResponseLength","overrideInterfaceLanguage","overrideOutputLanguage","a2a","cursor","since","until","cleanup","strictValidation","requestTimeoutMs","connectionTimeoutMs","logger","debug","info","warn","error","authTransport","authRequired","tokenProvider","tokenUrl","meta","querySelector","async","publishableKey","r","fetch","method","credentials","ok","json","token","access_token","setSmartDefaults","cspSafe","WebSocket","isBrowserEnv","validation","result","warnings","requiredErrors","websocketUrl","validateRequiredOptions","serverErrors","authenticationUrl","clientId","validateServerConfig","validateSDKConfig","errorMessages","map","warning","console","normalizedTarget","isBrowserBuild","startsWith","isUMDBuild","hasTokenProvider","hasAuthDisabled","enforceWebSocketScheme","WebSocketImpl","_pending","_deprecatedKeys","_silenceDeprecations","OPTAVE_SDK_SILENCE_DEPRECATIONS","_validatePayload","_validateMessageEnvelope","_ensureWebSocketImpl","loadNodeWebSocket","getSdkVersion","getSpecVersion","getSchemaRef","setSessionId","getSessionId","validate","jsonObject","validateEnvelope","envelope","_validateOutboundPayload","validateRequiredFields","authenticate","handleError","grant_type","client_id","client_secret","paramsString","authUrl","endsWith","response","responseJson","formatAuthenticationError","openConnection","bearerToken","formatWebSocketError","formatTokenProviderError","getToken","environment","qp","protocols","_warnOnce","Promise","resolve","reject","connectionTimeout","setTimeout","timeoutMs","errorMessage","timeout","onopen","onmessage","onclose","onerror","close","event","clearTimeout","emit","_handleInbound","entry","timer","_handled","reason","clear","errObj","originalError","flagName","deprecate","add","rawPayload","parsed","JSON","parse","toISOString","_emitError","isEnvelope","isError","actionType","vr","formatValidationErrorMessage","_action","structuredError","raw","isAuthError","isWsError","closeConnection","selectiveDeepMerge","source","isObject","isPayloadSizeValid","payloadString","openConnectionAsync","onErr","onOpen","off","once","buildPayload","requestType","defaultPayload","variation","toUpperCase","resolveMessageId","buildMessageEnvelope","headerOverrides","traceId","idempotencyKey","sdkVersion","issuedAt","tenantId","networkLatencyMs","baseMessage","fieldPath","missingField","fullFieldPath","additionalProperty","criticalErrors","filter","typeErrors","otherErrors","summary","missing","serverError","suggestions","status","error_description","errorEvent","formatPayloadSizeError","actualSize","maxSize","actualKB","Math","ceil","conversationsSize","stringify","conversationsKB","offersSize","offersKB","metadataSize","metadataKB","listenerCount","send","OPEN","readyState","allowedTopLevel","topLevelKeys","k","requiredFieldValidation","outboundResult","adjust","elevate","interaction","assistant","reception","customerInteraction","summarize","translate","recommend","insights","_registerPending","_promiseSend","opts","promise","allowed","maxKb","sendError","adjustAsync","elevateAsync","interactionAsync","assistantAsync","receptionAsync","customerInteractionAsync","summarizeAsync","translateAsync","recommendAsync","insightsAsync","cancelRequest","cancelPendingRequests","isCleaningUp","cancelledCount","size","queueMicrotask","_warnedQueryToken","_events","removeAllListeners","_eventsCount","_maxListeners","max","create","buildFlags","SALESFORCE_BUILD","INCLUDE_WS_REQUIRE","WEBPACK_BUILD_TARGET","WEBPACK_BUILD_TARGET_NORMALIZED","BUILD_TARGET_INFO","cryptoImplementation","self","array","floor","V7Generator","counter","_getRandomNumberGenerator","buffer","Uint32Array","nextUint32","createBufferedCryptoRandom","trunc","generate","generateOrResetCore","unixTsMs","rollbackAllowance","generateOrAbortCore","Number","isInteger","resetCounter","fromFieldsV7","randA","randBHi","randBLo","bytesToString","hex","byte","padStart","substring","defaultGenerator","setSafeCrypto","globalObj","propName","descriptor","getOwnPropertyDescriptor","configurable","randomUUID","generateUUID","generateShortId","default","bind"],"sourceRoot":""}
\ No newline at end of file
diff --git a/sdks/javascript/dist/test-environment.js b/sdks/javascript/dist/test-environment.js
deleted file mode 100644
index cb37dc5..0000000
--- a/sdks/javascript/dist/test-environment.js
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/env node
-
-/*
- * Copyright (c) 2025 Optave AI Solutions Inc.
- * All rights reserved.
- *
- * This software and associated documentation files (the "Software") are the
- * proprietary and confidential information of Optave AI Solutions Inc.
- * Unauthorized copying, modification, distribution, or use of this Software
- * is strictly prohibited without express written permission.
- */
-
-/**
- * Test Environment Setup
- * Configures test environments for all SDKs with proper environment variable management
- */
-
-import fs from 'fs';
-import path from 'path';
-import { fileURLToPath } from 'url';
-
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-
-class TestEnvironment {
- constructor() {
- this.envTemplate = {
- // Optave API Configuration
- OPTAVE__AUTH_URL: 'https://auth.optave.example.com',
- OPTAVE__WEBSOCKET_URL: 'wss://api.optave.example.com',
- OPTAVE__CLIENT_ID: 'test-client-id',
- OPTAVE__CLIENT_SECRET: 'test-client-secret',
- OPTAVE__ORGANIZATION_ID: 'test-org-id',
- OPTAVE__TENANT_ID: 'test-tenant-id',
-
- // Test Configuration
- NODE_ENV: 'test',
- VITEST_ENV: 'test',
- TEST_TIMEOUT: '10000',
-
- // Integration Test Flags
- SKIP_INTEGRATION_TESTS: 'false',
- INTEGRATION_TEST_MODE: 'mock',
-
- // Logging Configuration
- LOG_LEVEL: 'warn',
- DEBUG: 'false'
- };
- }
-
- async setupEnvironment(options = {}) {
- const { force = false, verbose = false } = options;
-
- console.log('🧪 Setting up test environment...');
-
- // Create environment files for each SDK
- await this.createSdkEnvironmentFiles(force, verbose);
-
- // Create global test environment file
- await this.createGlobalEnvironmentFile(force, verbose);
-
- // Setup test fixtures
- await this.setupTestFixtures(verbose);
-
- console.log('✅ Test environment setup completed');
- }
-
- async createSdkEnvironmentFiles(force, verbose) {
- const sdksDir = path.join(__dirname, '../../sdks');
-
- if (!fs.existsSync(sdksDir)) {
- if (verbose) console.log('⚠️ SDKs directory not found, skipping SDK environment setup');
- return;
- }
-
- const sdkDirs = fs.readdirSync(sdksDir, { withFileTypes: true })
- .filter(dirent => dirent.isDirectory())
- .map(dirent => dirent.name);
-
- for (const sdk of sdkDirs) {
- const sdkPath = path.join(sdksDir, sdk);
- const envPath = path.join(sdkPath, '.env.test');
-
- if (fs.existsSync(envPath) && !force) {
- if (verbose) console.log(`⏭️ Skipping ${sdk} - .env.test already exists`);
- continue;
- }
-
- // Create SDK-specific environment file
- const envContent = this.generateEnvContent(sdk);
- fs.writeFileSync(envPath, envContent);
-
- if (verbose) console.log(`✅ Created .env.test for ${sdk} SDK`);
- }
- }
-
- async createGlobalEnvironmentFile(force, verbose) {
- const globalEnvPath = path.join(__dirname, '../..', '.env.test');
-
- if (fs.existsSync(globalEnvPath) && !force) {
- if (verbose) console.log('⏭️ Skipping global .env.test - already exists');
- return;
- }
-
- const envContent = this.generateEnvContent('global');
- fs.writeFileSync(globalEnvPath, envContent);
-
- if (verbose) console.log('✅ Created global .env.test file');
- }
-
- generateEnvContent(context) {
- const header = `# Test Environment Configuration for ${context}
-# Generated automatically - modify template in utils/tests/test-environment.js
-#
-# This file contains test credentials that are safe for development/testing.
-# Do NOT use these values in production!
-
-`;
-
- const envVars = Object.entries(this.envTemplate)
- .map(([key, value]) => `${key}=${value}`)
- .join('\n');
-
- return header + envVars + '\n';
- }
-
- async setupTestFixtures(verbose) {
- const fixturesDir = path.join(__dirname, 'fixtures');
-
- if (!fs.existsSync(fixturesDir)) {
- fs.mkdirSync(fixturesDir, { recursive: true });
- }
-
- // Create mock server configuration
- const mockServerConfig = {
- websocket: {
- port: 8080,
- mockResponses: true,
- delays: {
- connection: 100,
- message: 50
- }
- },
- auth: {
- port: 8081,
- mockTokens: true,
- tokenExpiry: 3600
- }
- };
-
- fs.writeFileSync(
- path.join(fixturesDir, 'mock-server-config.json'),
- JSON.stringify(mockServerConfig, null, 2)
- );
-
- // Create test data fixtures
- const testPayloads = {
- validInteraction: {
- session: {
- sessionId: "test-session-123"
- },
- request: {
- connections: {
- threadId: "test-thread-456"
- },
- context: {
- organizationId: "test-org-id"
- }
- }
- }
- };
-
- fs.writeFileSync(
- path.join(fixturesDir, 'test-payloads.json'),
- JSON.stringify(testPayloads, null, 2)
- );
-
- if (verbose) console.log('✅ Created test fixtures');
- }
-}
-
-// CLI interface
-async function main() {
- const args = process.argv.slice(2);
- const options = {
- force: args.includes('--force'),
- verbose: args.includes('--verbose')
- };
-
- const testEnv = new TestEnvironment();
-
- try {
- await testEnv.setupEnvironment(options);
- process.exit(0);
- } catch (error) {
- console.error('💥 Test environment setup failed:', error);
- process.exit(1);
- }
-}
-
-// Run if called directly
-if (import.meta.url === new URL(process.argv[1], 'file:').href) {
- main();
-}
-
-export { TestEnvironment };
\ No newline at end of file
diff --git a/sdks/javascript/generated/README.md b/sdks/javascript/generated/README.md
index 926d7a2..eac3640 100644
--- a/sdks/javascript/generated/README.md
+++ b/sdks/javascript/generated/README.md
@@ -1,15 +1,19 @@
-# Generated Artifacts
+# SDK Internal Components
-This folder is intended to hold generated outputs derived from `specs/asyncapi.yaml`.
+This folder contains type definitions, validators, and configuration automatically generated from Optave's AsyncAPI specification.
-Currently included:
-- `types.d.ts` – TypeScript definitions for core payload / envelope / response schemas and helper types.
-- `validators.js` – Precompiled Ajv validators for selected schemas.
-- `validators.d.ts` – Type declarations for the validator functions.
-- `constants.js` – Generated constants derived from the spec.
-- `connection-config.ts` – Connection configuration types and definitions.
-- `index.ts` – Main entry point for generated artifacts.
-- `examples/` – Generated example files for browser and server environments.
-- (Optional) JSON copy of the spec produced via `npm run spec:generate:json` (placed in `.asyncapi-docs/`).
+## Contents
-Do NOT manually edit generated files; re-run the generation scripts instead.
+- `types.d.ts` – TypeScript definitions for message schemas and response types
+- `validators.js` – Runtime validators for message validation
+- `validators.d.ts` – Type declarations for validator functions
+- `constants.js` – SDK version and configuration constants
+- `connection-config.ts` – Connection configuration types
+- `index.ts` – Internal module exports
+- `examples/` – Usage examples for browser and server environments
+
+## Important Notes
+
+**Do not modify these files.** They are automatically generated and maintained by the SDK team.
+
+These files are included in the package to provide TypeScript type definitions and enable strict validation when `strictValidation` is enabled in the SDK configuration.
diff --git a/sdks/javascript/generated/connection-config.ts b/sdks/javascript/generated/connection-config.ts
index 8bc6438..945f7e1 100644
--- a/sdks/javascript/generated/connection-config.ts
+++ b/sdks/javascript/generated/connection-config.ts
@@ -1,15 +1,15 @@
// Generated from AsyncAPI specification
-// DO NOT EDIT - This file is auto-generated from Optave Client WebSocket API v3.2.1
+// DO NOT EDIT - This file is auto-generated from Optave Client WebSocket API v1.0.0
// Auth transport types derived from security schemes
-export type AuthTransport = 'subprotocol' | 'query' | 'oauth2';
+export type AuthTransport = 'subprotocol' | 'query';
// Server configuration derived from AsyncAPI servers
export interface GeneratedClientConfig {
- // WebSocket server: wss://{wsEnv}.oco.optave.tech/
+ // WebSocket server: wss://{wsEnv}.{baseDomain}/
websocketUrl: string;
- // Auth server: https://{authEnv}.oco.optave.tech/auth/oauth2 (base URL, SDK appends /token)
+ // Auth server: https://{authEnv}.{baseDomain}/auth/oauth2
authUrl: string;
// Supported authentication transports
@@ -20,38 +20,57 @@ export interface GeneratedClientConfig {
// Default configuration values
export const DEFAULT_CONFIG: GeneratedClientConfig = {
- websocketUrl: 'wss://{wsEnv}.oco.optave.tech/',
- authUrl: 'https://{authEnv}.oco.optave.tech/auth/oauth2', // Base URL - SDK will append /token
- supportedAuthTransports: ['subprotocol', 'query', 'oauth2'],
+ websocketUrl: 'wss://{wsEnv}.{baseDomain}/',
+ authUrl: 'https://{authEnv}.{baseDomain}/auth/oauth2',
+ supportedAuthTransports: ['subprotocol', 'query'],
};
-// OAuth2 token URL for client credentials flow (uses same server as auth)
-export const OAUTH2_TOKEN_URL = DEFAULT_CONFIG.authUrl;
-
// Environment variable mappings for server URLs
export const SERVER_ENVIRONMENTS = {
websocket: {
wsEnv: {
default: 'ws-incubator',
examples: ['ws-incubator', 'ws-sandbox', 'ws-prod']
- }
+ },
+ baseDomain: {
+ default: 'oco.optave.tech',
+ examples: ['oco.optave.tech']
+ },
},
auth: {
authEnv: {
default: 'incubator',
examples: ['incubator', 'sandbox', 'prod']
- }
+ },
+ baseDomain: {
+ default: 'oco.optave.tech',
+ examples: ['oco.optave.tech']
+ },
}
};
+// Helper function to build WebSocket URL — each server variable maps to a named parameter
+export function buildWebSocketUrl(
+ wsEnv: string = SERVER_ENVIRONMENTS.websocket.wsEnv?.default,
+ baseDomain: string = SERVER_ENVIRONMENTS.websocket.baseDomain?.default
+): string {
+ let url = DEFAULT_CONFIG.websocketUrl;
+ url = url.replace('{wsEnv}', wsEnv);
+ url = url.replace('{baseDomain}', baseDomain);
+ return url;
+}
-// Helper function to build WebSocket URL with environment
-export function buildWebSocketUrl(environment: string = SERVER_ENVIRONMENTS.websocket.wsEnv?.default): string {
- return DEFAULT_CONFIG.websocketUrl.replace('{wsEnv}', environment);
+// Helper function to build Auth URL — each server variable maps to a named parameter
+export function buildAuthUrl(
+ authEnv: string = SERVER_ENVIRONMENTS.auth.authEnv?.default,
+ baseDomain: string = SERVER_ENVIRONMENTS.auth.baseDomain?.default
+): string {
+ let url = DEFAULT_CONFIG.authUrl;
+ url = url.replace('{authEnv}', authEnv);
+ url = url.replace('{baseDomain}', baseDomain);
+ return url;
}
-// Helper function to build Auth URL with environment
-export function buildAuthUrl(environment: string = SERVER_ENVIRONMENTS.auth.authEnv?.default): string {
- return DEFAULT_CONFIG.authUrl.replace('{authEnv}', environment);
-}
\ No newline at end of file
+// OAuth2 token URL resolved with spec defaults — use buildAuthUrl() for custom environments
+export const OAUTH2_TOKEN_URL = buildAuthUrl();
diff --git a/sdks/javascript/generated/constants.js b/sdks/javascript/generated/constants.js
index 40af02e..c879bb4 100644
--- a/sdks/javascript/generated/constants.js
+++ b/sdks/javascript/generated/constants.js
@@ -1,9 +1,10 @@
// AUTO-GENERATED FILE. DO NOT EDIT.
-// Source: config/specs/asyncapi.yaml (info.version: 3.2.3)
+// Source: config/specs/asyncapi.yaml (info.version: 1.0.0)
+// This is the protocol version, independent of SDK implementation version
-// SDK Constants derived from AsyncAPI spec
-export const SPEC_VERSION = "3.2.3";
+// Protocol version from AsyncAPI spec
+export const SPEC_VERSION = "1.0.0";
-// Schema ref is derived from spec major
+// Schema ref is derived from protocol major version
const SPEC_MAJOR = SPEC_VERSION.split('.')[0];
export const SCHEMA_REF = `optave.message.v${SPEC_MAJOR}`;
diff --git a/sdks/javascript/generated/examples/README.md b/sdks/javascript/generated/examples/README.md
index f0b2246..3497a13 100644
--- a/sdks/javascript/generated/examples/README.md
+++ b/sdks/javascript/generated/examples/README.md
@@ -4,8 +4,8 @@
This file was automatically generated from AsyncAPI specification.
-- **Generated from**: Optave Client WebSocket API v3.2.1
-- **Generated on**: 2025-09-26T21:27:15.926Z
+- **Generated from**: Optave Client WebSocket API (Protocol v1.0.0)
+- **Generated on**: 2026-09-02T23:31:19.009Z
- **To regenerate**: `npm run spec:generate:examples`
This directory contains **automatically generated** examples for using the Optave JavaScript SDK. These examples are generated from the AsyncAPI specification to ensure perfect consistency with the current API schema.
@@ -18,6 +18,7 @@ generated/examples/
│ ├── adjust.js
│ ├── customerinteraction.js
│ ├── interaction.js
+│ ├── assistant.js
│ ├── elevate.js
│ ├── insights.js
│ ├── recommend.js
@@ -28,6 +29,7 @@ generated/examples/
├── adjust.js
├── customerinteraction.js
├── interaction.js
+ ├── assistant.js
├── elevate.js
├── insights.js
├── recommend.js
@@ -69,6 +71,7 @@ import OptaveJavaScriptSDK from '../dist/browser.mjs';
- `adjust.js` - Client sends an adjust action request
- `customerinteraction.js` - (Deprecated) Client sends a customer interaction action request (use interaction)
- `interaction.js` - Client sends an interaction action request
+- `assistant.js` - Client sends an assistant action request
- `elevate.js` - Client sends an elevate action request
- `insights.js` - Client sends an insights action request
- `recommend.js` - Client sends a recommend action request
@@ -98,6 +101,7 @@ import OptaveJavaScriptSDK from '../dist/server.mjs';
- `adjust.js` - Client sends an adjust action request
- `customerinteraction.js` - (Deprecated) Client sends a customer interaction action request (use interaction)
- `interaction.js` - Client sends an interaction action request
+- `assistant.js` - Client sends an assistant action request
- `elevate.js` - Client sends an elevate action request
- `insights.js` - Client sends an insights action request
- `recommend.js` - Client sends a recommend action request
@@ -154,5 +158,5 @@ For complete SDK documentation, see:
---
-**Generated from**: Optave Client WebSocket API v3.2.1
-**Generated on**: 2025-09-26T21:27:15.927Z
\ No newline at end of file
+**Generated from**: Optave Client WebSocket API (Protocol v1.0.0)
+**Generated on**: 2026-09-02T23:31:19.009Z
\ No newline at end of file
diff --git a/sdks/javascript/generated/examples/browser/adjust.js b/sdks/javascript/generated/examples/browser/adjust.js
index f6a7b38..09ca81e 100644
--- a/sdks/javascript/generated/examples/browser/adjust.js
+++ b/sdks/javascript/generated/examples/browser/adjust.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated adjust browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* Client sends an adjust action request
* Uses tokenProvider pattern for secure browser authentication.
@@ -77,7 +77,7 @@ async function sendAdjustRequest() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_chat"
},
diff --git a/sdks/javascript/generated/examples/browser/assistant.js b/sdks/javascript/generated/examples/browser/assistant.js
new file mode 100644
index 0000000..672f598
--- /dev/null
+++ b/sdks/javascript/generated/examples/browser/assistant.js
@@ -0,0 +1,154 @@
+/**
+ * ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
+ *
+ * Auto-generated assistant browser example
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
+ *
+ * Client sends an assistant action request
+ * Uses tokenProvider pattern for secure browser authentication.
+ *
+ * To regenerate: npm run spec:generate:examples
+ */
+
+// ✅ BROWSER: Import from browser build
+import OptaveJavaScriptSDK from '../../dist/browser.mjs';
+
+const optaveClient = new OptaveJavaScriptSDK({
+ // ✅ BROWSER: Use import.meta.env (Vite/modern bundlers)
+ websocketUrl: import.meta.env.VITE_OPTAVE__WEBSOCKET_URL,
+
+ // ✅ BROWSER SECURITY: Never use clientSecret in browsers!
+ tokenProvider: async () => {
+ const response = await fetch('/auth/oauth2/token', {
+ method: 'POST',
+ credentials: 'include',
+ headers: { 'Content-Type': 'application/json' }
+ });
+
+ if (!response.ok) {
+ throw new Error(`Token request failed: ${response.status}`);
+ }
+
+ const data = await response.json();
+ return data.token;
+ },
+
+ // Optional browser configurations
+ authTransport: 'subprotocol',
+ strictValidation: true,
+});
+
+// Event listeners
+optaveClient.on('open', () => {
+ console.log('✅ Connected to Optave WebSocket');
+ sendAssistantRequest();
+});
+
+optaveClient.on('message', (payload) => {
+ const message = JSON.parse(payload);
+ console.log('📨 Received message:', message);
+
+ if (message.headers?.action === 'assistant') {
+ console.log('✅ assistant response received:', message.payload);
+ }
+});
+
+optaveClient.on('error', (error) => {
+ console.error('❌ WebSocket error:', error);
+});
+
+optaveClient.on('close', () => {
+ console.log('🔌 WebSocket connection closed');
+});
+
+async function sendAssistantRequest() {
+ try {
+ console.log('🚀 Sending assistant request...');
+
+ const response = await optaveClient.assistant({
+ "headers": {
+ "timestamp": "2024-01-15T10:30:00.000Z",
+ "networkLatencyMs": 120
+ },
+ "session": {
+ "sessionId": "a1b2c3e6-e5f6-7890-1234-56789abcdef1",
+ "channel": {
+ "browser": "Safari 17.0",
+ "deviceInfo": "iOS/18.2, iPhone15,3",
+ "deviceType": "mobile",
+ "language": "en-US",
+ "location": "US-NY",
+ "medium": "chat",
+ "section": "support_page"
+ },
+ "interface": {
+ "appVersion": "2.1.0",
+ "category": "crm",
+ "language": "en-US",
+ "name": "my_support_app",
+ "type": "custom_components"
+ }
+ },
+ "request": {
+ "requestId": "a1b2c3d4-e5f6-7890-1234-56789ab2346",
+ "attributes": {
+ "variant": "A"
+ },
+ "connections": {
+ "threadId": "9e8d7c6b-5a49-3827-1605-948372615abd"
+ },
+ "context": {
+ "organizationId": "f7e8d9c0-b1a2-3456-7890-123456789abc"
+ },
+ "scope": {
+ "conversations": [
+ {
+ "conversationId": "conv-789",
+ "participants": [
+ {
+ "participantId": "2c4f8a9b-1d3e-5f70-8293-456789012def",
+ "displayName": "John Doe",
+ "role": "user"
+ },
+ {
+ "participantId": "7d9e0f1a-3b5c-7d9e-1f0a-987654321abc",
+ "displayName": "AI Assistant",
+ "role": "assistant"
+ }
+ ],
+ "messages": [
+ {
+ "content": "Hi, can you help me?",
+ "participantId": "2c4f8a9b-1d3e-5f70-8293-456789012def",
+ "timestamp": "2024-01-15T10:30:00.000Z"
+ },
+ {
+ "content": "Of course! I'd be happy to help you with anything you need.",
+ "participantId": "7d9e0f1a-3b5c-7d9e-1f0a-987654321abc",
+ "timestamp": "2024-01-15T10:30:15.000Z"
+ }
+ ]
+ }
+ ]
+ }
+ }
+});
+
+ console.log('✅ assistant request sent successfully:', response);
+ } catch (error) {
+ console.error('❌ Failed to send assistant request:', error);
+ }
+}
+
+// Connect to WebSocket
+optaveClient.openConnection();
+
+// ✅ BROWSER: Clean up on page unload
+if (typeof window !== 'undefined') {
+ window.addEventListener('beforeunload', () => {
+ optaveClient.closeConnection();
+ });
+}
+
+// Export for use in other modules
+export { optaveClient };
\ No newline at end of file
diff --git a/sdks/javascript/generated/examples/browser/customerinteraction.js b/sdks/javascript/generated/examples/browser/customerinteraction.js
index 38d08f0..febfd20 100644
--- a/sdks/javascript/generated/examples/browser/customerinteraction.js
+++ b/sdks/javascript/generated/examples/browser/customerinteraction.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated customerinteraction browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* (Deprecated) Client sends a customer interaction action request (use interaction)
* Uses tokenProvider pattern for secure browser authentication.
@@ -77,7 +77,7 @@ async function sendCustomerinteractionRequest() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/browser/elevate.js b/sdks/javascript/generated/examples/browser/elevate.js
index 146a8e2..4bd6244 100644
--- a/sdks/javascript/generated/examples/browser/elevate.js
+++ b/sdks/javascript/generated/examples/browser/elevate.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated elevate browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* Client sends an elevate action request
* Uses tokenProvider pattern for secure browser authentication.
@@ -77,7 +77,7 @@ async function sendElevateRequest() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_chat"
},
diff --git a/sdks/javascript/generated/examples/browser/insights.js b/sdks/javascript/generated/examples/browser/insights.js
index 75426fe..75459ae 100644
--- a/sdks/javascript/generated/examples/browser/insights.js
+++ b/sdks/javascript/generated/examples/browser/insights.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated insights browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* Client sends an insights action request
* Uses tokenProvider pattern for secure browser authentication.
@@ -77,7 +77,7 @@ async function sendInsightsRequest() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/browser/interaction.js b/sdks/javascript/generated/examples/browser/interaction.js
index 9eb185f..18ff48e 100644
--- a/sdks/javascript/generated/examples/browser/interaction.js
+++ b/sdks/javascript/generated/examples/browser/interaction.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated interaction browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* Client sends an interaction action request
* Uses tokenProvider pattern for secure browser authentication.
@@ -77,7 +77,7 @@ async function sendInteractionRequest() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/browser/reception.js b/sdks/javascript/generated/examples/browser/reception.js
index 5ab0600..7b8c49c 100644
--- a/sdks/javascript/generated/examples/browser/reception.js
+++ b/sdks/javascript/generated/examples/browser/reception.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated reception browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* Client sends a reception action request
* Uses tokenProvider pattern for secure browser authentication.
diff --git a/sdks/javascript/generated/examples/browser/recommend.js b/sdks/javascript/generated/examples/browser/recommend.js
index 461eb34..b8625fd 100644
--- a/sdks/javascript/generated/examples/browser/recommend.js
+++ b/sdks/javascript/generated/examples/browser/recommend.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated recommend browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* Client sends a recommend action request
* Uses tokenProvider pattern for secure browser authentication.
@@ -77,7 +77,7 @@ async function sendRecommendRequest() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/browser/summarize.js b/sdks/javascript/generated/examples/browser/summarize.js
index 17c83a3..095bed9 100644
--- a/sdks/javascript/generated/examples/browser/summarize.js
+++ b/sdks/javascript/generated/examples/browser/summarize.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated summarize browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* Client sends a summarize action request
* Uses tokenProvider pattern for secure browser authentication.
@@ -77,7 +77,7 @@ async function sendSummarizeRequest() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/browser/translate.js b/sdks/javascript/generated/examples/browser/translate.js
index 83e7f91..db93c5e 100644
--- a/sdks/javascript/generated/examples/browser/translate.js
+++ b/sdks/javascript/generated/examples/browser/translate.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated translate browser example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* Client sends a translate action request
* Uses tokenProvider pattern for secure browser authentication.
@@ -77,7 +77,7 @@ async function sendTranslateRequest() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "es-MX",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/server/adjust.js b/sdks/javascript/generated/examples/server/adjust.js
index 9da1ec5..9bc98f9 100644
--- a/sdks/javascript/generated/examples/server/adjust.js
+++ b/sdks/javascript/generated/examples/server/adjust.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated adjust server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
@@ -50,7 +50,7 @@ async function run() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_chat"
},
diff --git a/sdks/javascript/generated/examples/server/assistant.js b/sdks/javascript/generated/examples/server/assistant.js
new file mode 100644
index 0000000..d8e7a32
--- /dev/null
+++ b/sdks/javascript/generated/examples/server/assistant.js
@@ -0,0 +1,120 @@
+/**
+ * ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
+ *
+ * Auto-generated assistant server example
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
+ *
+ * To regenerate: npm run spec:generate:examples
+ */
+
+// ✅ SERVER: Import from Node.js build
+import OptaveJavaScriptSDK from '../../dist/server.mjs';
+
+const optaveClient = new OptaveJavaScriptSDK({
+ // Required: WebSocket server URL
+ websocketUrl: process.env.OPTAVE__WEBSOCKET_URL,
+
+ // Server-side authentication (secure environments only)
+ authenticationUrl: process.env.OPTAVE__AUTHENTICATION_URL,
+ clientId: process.env.OPTAVE__CLIENT_ID,
+ // ✅ SERVER ONLY: clientSecret is safe here
+ clientSecret: process.env.OPTAVE__CLIENT_SECRET,
+});
+
+async function run() {
+ // Listen for messages
+ optaveClient.on('message', payload => {
+ const message = JSON.parse(payload);
+ const { actionType, state, action } = message;
+ console.log(`Action: ${action} / State: ${state} / Action Type: ${actionType}`);
+ });
+
+ // Handle errors
+ optaveClient.on('error', error => {
+ console.error('Error:', error);
+ });
+
+ // Send assistant message when connected
+ optaveClient.once('open', () => {
+ console.log('🚀 Sending assistant request...');
+
+ optaveClient.assistant({
+ "headers": {
+ "timestamp": "2024-01-15T10:30:00.000Z",
+ "networkLatencyMs": 120
+ },
+ "session": {
+ "sessionId": "a1b2c3e6-e5f6-7890-1234-56789abcdef1",
+ "channel": {
+ "browser": "Safari 17.0",
+ "deviceInfo": "iOS/18.2, iPhone15,3",
+ "deviceType": "mobile",
+ "language": "en-US",
+ "location": "US-NY",
+ "medium": "chat",
+ "section": "support_page"
+ },
+ "interface": {
+ "appVersion": "2.1.0",
+ "category": "crm",
+ "language": "en-US",
+ "name": "my_support_app",
+ "type": "custom_components"
+ }
+ },
+ "request": {
+ "requestId": "a1b2c3d4-e5f6-7890-1234-56789ab2346",
+ "attributes": {
+ "variant": "A"
+ },
+ "connections": {
+ "threadId": "9e8d7c6b-5a49-3827-1605-948372615abd"
+ },
+ "context": {
+ "organizationId": "f7e8d9c0-b1a2-3456-7890-123456789abc"
+ },
+ "scope": {
+ "conversations": [
+ {
+ "conversationId": "conv-789",
+ "participants": [
+ {
+ "participantId": "2c4f8a9b-1d3e-5f70-8293-456789012def",
+ "displayName": "John Doe",
+ "role": "user"
+ },
+ {
+ "participantId": "7d9e0f1a-3b5c-7d9e-1f0a-987654321abc",
+ "displayName": "AI Assistant",
+ "role": "assistant"
+ }
+ ],
+ "messages": [
+ {
+ "content": "Hi, can you help me?",
+ "participantId": "2c4f8a9b-1d3e-5f70-8293-456789012def",
+ "timestamp": "2024-01-15T10:30:00.000Z"
+ },
+ {
+ "content": "Of course! I'd be happy to help you with anything you need.",
+ "participantId": "7d9e0f1a-3b5c-7d9e-1f0a-987654321abc",
+ "timestamp": "2024-01-15T10:30:15.000Z"
+ }
+ ]
+ }
+ ]
+ }
+ }
+});
+ });
+
+ // Authenticate and connect
+ try {
+ const token = await optaveClient.authenticate();
+ optaveClient.openConnection(token);
+ } catch (error) {
+ console.error('Failed to authenticate and connect:', error);
+ }
+}
+
+run();
\ No newline at end of file
diff --git a/sdks/javascript/generated/examples/server/customerinteraction.js b/sdks/javascript/generated/examples/server/customerinteraction.js
index 9ada4fb..c960d55 100644
--- a/sdks/javascript/generated/examples/server/customerinteraction.js
+++ b/sdks/javascript/generated/examples/server/customerinteraction.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated customerinteraction server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
@@ -50,7 +50,7 @@ async function run() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/server/elevate.js b/sdks/javascript/generated/examples/server/elevate.js
index 0d56292..d79ce73 100644
--- a/sdks/javascript/generated/examples/server/elevate.js
+++ b/sdks/javascript/generated/examples/server/elevate.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated elevate server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
@@ -50,7 +50,7 @@ async function run() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_chat"
},
diff --git a/sdks/javascript/generated/examples/server/insights.js b/sdks/javascript/generated/examples/server/insights.js
index 442f1ba..58fe194 100644
--- a/sdks/javascript/generated/examples/server/insights.js
+++ b/sdks/javascript/generated/examples/server/insights.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated insights server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
@@ -50,7 +50,7 @@ async function run() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/server/interaction.js b/sdks/javascript/generated/examples/server/interaction.js
index febb389..ed1beb0 100644
--- a/sdks/javascript/generated/examples/server/interaction.js
+++ b/sdks/javascript/generated/examples/server/interaction.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated interaction server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
@@ -50,7 +50,7 @@ async function run() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/server/reception.js b/sdks/javascript/generated/examples/server/reception.js
index 271d704..da962b1 100644
--- a/sdks/javascript/generated/examples/server/reception.js
+++ b/sdks/javascript/generated/examples/server/reception.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated reception server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
diff --git a/sdks/javascript/generated/examples/server/recommend.js b/sdks/javascript/generated/examples/server/recommend.js
index f02fb92..21f5819 100644
--- a/sdks/javascript/generated/examples/server/recommend.js
+++ b/sdks/javascript/generated/examples/server/recommend.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated recommend server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
@@ -50,7 +50,7 @@ async function run() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/server/summarize.js b/sdks/javascript/generated/examples/server/summarize.js
index d7f174a..18f9321 100644
--- a/sdks/javascript/generated/examples/server/summarize.js
+++ b/sdks/javascript/generated/examples/server/summarize.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated summarize server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
@@ -50,7 +50,7 @@ async function run() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "en-US",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/examples/server/translate.js b/sdks/javascript/generated/examples/server/translate.js
index c6342cf..4e38de1 100644
--- a/sdks/javascript/generated/examples/server/translate.js
+++ b/sdks/javascript/generated/examples/server/translate.js
@@ -2,7 +2,7 @@
* ⚠️ GENERATED FILE - DO NOT EDIT MANUALLY
*
* Auto-generated translate server example
- * Generated from: Optave Client WebSocket API v3.2.1
+ * Generated from: Optave Client WebSocket API (Protocol v1.0.0)
*
* To regenerate: npm run spec:generate:examples
*/
@@ -50,7 +50,7 @@ async function run() {
"deviceInfo": "iOS/18.2, iPhone15,3",
"deviceType": "mobile",
"language": "es-MX",
- "location": "40.7128,-74.0060",
+ "location": "US-NY",
"medium": "chat",
"section": "support_page"
},
diff --git a/sdks/javascript/generated/test-environment.js b/sdks/javascript/generated/test-environment.js
deleted file mode 100644
index cb37dc5..0000000
--- a/sdks/javascript/generated/test-environment.js
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/env node
-
-/*
- * Copyright (c) 2025 Optave AI Solutions Inc.
- * All rights reserved.
- *
- * This software and associated documentation files (the "Software") are the
- * proprietary and confidential information of Optave AI Solutions Inc.
- * Unauthorized copying, modification, distribution, or use of this Software
- * is strictly prohibited without express written permission.
- */
-
-/**
- * Test Environment Setup
- * Configures test environments for all SDKs with proper environment variable management
- */
-
-import fs from 'fs';
-import path from 'path';
-import { fileURLToPath } from 'url';
-
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-
-class TestEnvironment {
- constructor() {
- this.envTemplate = {
- // Optave API Configuration
- OPTAVE__AUTH_URL: 'https://auth.optave.example.com',
- OPTAVE__WEBSOCKET_URL: 'wss://api.optave.example.com',
- OPTAVE__CLIENT_ID: 'test-client-id',
- OPTAVE__CLIENT_SECRET: 'test-client-secret',
- OPTAVE__ORGANIZATION_ID: 'test-org-id',
- OPTAVE__TENANT_ID: 'test-tenant-id',
-
- // Test Configuration
- NODE_ENV: 'test',
- VITEST_ENV: 'test',
- TEST_TIMEOUT: '10000',
-
- // Integration Test Flags
- SKIP_INTEGRATION_TESTS: 'false',
- INTEGRATION_TEST_MODE: 'mock',
-
- // Logging Configuration
- LOG_LEVEL: 'warn',
- DEBUG: 'false'
- };
- }
-
- async setupEnvironment(options = {}) {
- const { force = false, verbose = false } = options;
-
- console.log('🧪 Setting up test environment...');
-
- // Create environment files for each SDK
- await this.createSdkEnvironmentFiles(force, verbose);
-
- // Create global test environment file
- await this.createGlobalEnvironmentFile(force, verbose);
-
- // Setup test fixtures
- await this.setupTestFixtures(verbose);
-
- console.log('✅ Test environment setup completed');
- }
-
- async createSdkEnvironmentFiles(force, verbose) {
- const sdksDir = path.join(__dirname, '../../sdks');
-
- if (!fs.existsSync(sdksDir)) {
- if (verbose) console.log('⚠️ SDKs directory not found, skipping SDK environment setup');
- return;
- }
-
- const sdkDirs = fs.readdirSync(sdksDir, { withFileTypes: true })
- .filter(dirent => dirent.isDirectory())
- .map(dirent => dirent.name);
-
- for (const sdk of sdkDirs) {
- const sdkPath = path.join(sdksDir, sdk);
- const envPath = path.join(sdkPath, '.env.test');
-
- if (fs.existsSync(envPath) && !force) {
- if (verbose) console.log(`⏭️ Skipping ${sdk} - .env.test already exists`);
- continue;
- }
-
- // Create SDK-specific environment file
- const envContent = this.generateEnvContent(sdk);
- fs.writeFileSync(envPath, envContent);
-
- if (verbose) console.log(`✅ Created .env.test for ${sdk} SDK`);
- }
- }
-
- async createGlobalEnvironmentFile(force, verbose) {
- const globalEnvPath = path.join(__dirname, '../..', '.env.test');
-
- if (fs.existsSync(globalEnvPath) && !force) {
- if (verbose) console.log('⏭️ Skipping global .env.test - already exists');
- return;
- }
-
- const envContent = this.generateEnvContent('global');
- fs.writeFileSync(globalEnvPath, envContent);
-
- if (verbose) console.log('✅ Created global .env.test file');
- }
-
- generateEnvContent(context) {
- const header = `# Test Environment Configuration for ${context}
-# Generated automatically - modify template in utils/tests/test-environment.js
-#
-# This file contains test credentials that are safe for development/testing.
-# Do NOT use these values in production!
-
-`;
-
- const envVars = Object.entries(this.envTemplate)
- .map(([key, value]) => `${key}=${value}`)
- .join('\n');
-
- return header + envVars + '\n';
- }
-
- async setupTestFixtures(verbose) {
- const fixturesDir = path.join(__dirname, 'fixtures');
-
- if (!fs.existsSync(fixturesDir)) {
- fs.mkdirSync(fixturesDir, { recursive: true });
- }
-
- // Create mock server configuration
- const mockServerConfig = {
- websocket: {
- port: 8080,
- mockResponses: true,
- delays: {
- connection: 100,
- message: 50
- }
- },
- auth: {
- port: 8081,
- mockTokens: true,
- tokenExpiry: 3600
- }
- };
-
- fs.writeFileSync(
- path.join(fixturesDir, 'mock-server-config.json'),
- JSON.stringify(mockServerConfig, null, 2)
- );
-
- // Create test data fixtures
- const testPayloads = {
- validInteraction: {
- session: {
- sessionId: "test-session-123"
- },
- request: {
- connections: {
- threadId: "test-thread-456"
- },
- context: {
- organizationId: "test-org-id"
- }
- }
- }
- };
-
- fs.writeFileSync(
- path.join(fixturesDir, 'test-payloads.json'),
- JSON.stringify(testPayloads, null, 2)
- );
-
- if (verbose) console.log('✅ Created test fixtures');
- }
-}
-
-// CLI interface
-async function main() {
- const args = process.argv.slice(2);
- const options = {
- force: args.includes('--force'),
- verbose: args.includes('--verbose')
- };
-
- const testEnv = new TestEnvironment();
-
- try {
- await testEnv.setupEnvironment(options);
- process.exit(0);
- } catch (error) {
- console.error('💥 Test environment setup failed:', error);
- process.exit(1);
- }
-}
-
-// Run if called directly
-if (import.meta.url === new URL(process.argv[1], 'file:').href) {
- main();
-}
-
-export { TestEnvironment };
\ No newline at end of file
diff --git a/sdks/javascript/generated/types.d.ts b/sdks/javascript/generated/types.d.ts
index fd32216..1d7fbc4 100644
--- a/sdks/javascript/generated/types.d.ts
+++ b/sdks/javascript/generated/types.d.ts
@@ -1,23 +1,214 @@
// AUTO-GENERATED FILE. DO NOT EDIT.
-// Source: specs/asyncapi.yaml (info.version: 3.2.3)
+// Source: specs/asyncapi.yaml (protocol version: 1.0.0)
-export type OptaveAction = 'adjust' | 'elevate' | 'customerinteraction' | 'interaction' | 'reception' | 'summarize' | 'translate' | 'recommend' | 'insights';
+export type OptaveAction = 'adjust' | 'elevate' | 'customerinteraction' | 'interaction' | 'assistant' | 'reception' | 'summarize' | 'translate' | 'recommend' | 'insights';
+
+/** Session tracking block. Feeds analytics session length/bands and peak concurrency via sessionId. */
+export interface Session {
+ /** Session identity lasting for the duration of a chat session or call. Feeds analytics session length/bands and peak concurrency. */
+ sessionId?: string;
+ /** Capture-time channel context. Typed fields feed analytics dimensions; metadata is free-form and must not carry direct identifiers. */
+ channel?: Channel;
+ interface?: Interface;
+}
+
+/** Capture-time channel context. Typed fields feed analytics dimensions; metadata is free-form and must not carry direct identifiers. */
+export interface Channel {
+ /** Browser information. Feeds analytics device/mobile-share slices together with deviceType and deviceInfo. */
+ browser?: string;
+ /** Device information (e.g., "iOS/18.2, iPhone15,3"). Feeds analytics device slices together with deviceType and browser. */
+ deviceInfo?: string;
+ /** Device class. Analytics dimension values (no mapping layer): mobile, desktop, tablet. Additive-only within a major version; omit when unknown. Empty/omitted is treated as unknown and is not an analytics value. */
+ deviceType?: string;
+ /** Conversation/interface language. Feeds analytics fr-share, fr-parity, and lang-switch. */
+ language?: string;
+ /** Geography at province grain at most (ISO 3166-2, e.g. "US-NY", "CA-ON"), never precise coordinates. Country-only values (e.g. "US") are valid. Consent-gated. Feeds analytics province-concentration and intl-share. */
+ location?: string;
+ /** Communication medium. Analytics dimension values (no mapping layer): chat, voice, email. Default is chat if omitted. Additive-only within a major version. */
+ medium?: 'chat' | 'voice' | 'email';
+ /** Custom metadata array. Free-form; MUST NOT carry direct identifiers (names, emails, message content). The analytics raw store is append-only under Object Lock — a leaked identifier cannot be simply deleted. */
+ metadata?: any[];
+ /** In-product context (e.g., "cart", "product_page"). Feeds analytics engagement analysis. */
+ section?: string;
+}
+
+export interface Interface {
+ /** Emitter/application version. Used as analytics provenance corroboration, not a dashboard slice of its own. */
+ appVersion?: string;
+ /** Interface category / surface class (e.g., "crm", "app", "auto", "widget"). Feeds analytics per-surface slices together with name. */
+ category?: string;
+ /** Language from the CRM agent */
+ language?: string;
+ /** Interface/surface name (e.g., "salesforce", "zendesk", "widget", "app"). Feeds analytics per-surface slices together with category. */
+ name?: string;
+ /** Interface type (e.g., "custom_components", "marketplace", "channel") */
+ type?: string;
+}
+
+export interface RequestAttributes {
+ /** Content to be processed */
+ content?: string;
+ /** Specific instruction for the action */
+ instruction?: string;
+ /** A/B variant identifier (e.g., "A", "B"). Feeds analytics experiment slices. */
+ variant?: string;
+ /** Reply attribution classified in the UI at compose time. Closed enum for analytics dimension reply_target. Who the user is replying to: an AI/operator message, their own earlier message, or not a reply. Never a message id, never message content. Absent means not reported; "none" means this message is not a reply. Canonical field; connections.replyTarget remains a deprecated 3.5.0 compatibility alias with the same enum. */
+ replyTo?: 'ai' | 'self' | 'none';
+}
+
+export interface Connections {
+ /** Cross-conversation journey identity. Feeds analytics returning-user analysis. */
+ journeyId?: string;
+ /** Parent request ID (previously trace_parent_ID in v2). Request lineage for adjust/elevate refine-chain — not a frozen reply-edge. */
+ parentId?: string;
+ /** Deprecated 3.5.0 compatibility alias for attributes.replyTo. Same closed enum (ai / self / none). New producers must send attributes.replyTo. Kept so 3.5.0 typed payloads continue to type-check inside this major version. */
+ replyTarget?: 'ai' | 'self' | 'none';
+ /** Opaque identifier of the message being replied to. Same treatment as parentId / threadId — a string id, never message content. Producers MUST hash if the source is a raw message id. Absent or empty means not reported (this message may still be a reply whose target id is unknown). */
+ replyId?: string;
+ /** Conversation identity — unique across all requests related to the same ticket/case/conversation. Feeds analytics conversations, turns, messages, and outcome joins. */
+ threadId?: string;
+}
+
+export interface Context {
+ /** Case/ticket linkage (advanced mode). Feeds analytics resolution/escalation joins. */
+ caseId?: string;
+ /** Department identifier (advanced mode). Feeds analytics ops slices together with operatorId. */
+ departmentId?: string;
+ /** Operator identifier (advanced mode). Feeds analytics ops slices together with departmentId. */
+ operatorId?: string;
+ /** Organization grouping. Feeds analytics org dimension. */
+ organizationId?: string;
+ /** Pseudonymous user grain (advanced mode). Analytics consumers MUST hash this value; never a raw IdP subject. Feeds MAU, returning, retention, and queries-per-user. */
+ userId?: string;
+}
+
+/** Client-custom identifier pair. Never a typed analytics fact (thread, user, geography, variant). MUST NOT carry direct identifiers (names, emails, message content). */
+export interface ReferenceId {
+ /** Client-custom identifier name (e.g., "ticket_id"). Not a typed analytics dimension. */
+ name?: string;
+ /** Client-custom identifier value. MUST NOT be a name, email, or message content. */
+ value?: string;
+}
+
+export interface CodesItem {
+ /** Optional for tracking/mapping */
+ id?: string;
+ /** Optional, helps for display/templating (e.g., "Order Number") */
+ label?: string;
+ /** Code type (e.g., "order_number", "booking_reference", "ticket_code") */
+ type?: string;
+ /** Code value (e.g., "ORD-56789") */
+ value?: string;
+}
+
+export interface LinkItem {
+ /** Optional expiration timestamp */
+ expires_at?: string;
+ /** Optional HTML flag */
+ html?: boolean;
+ /** Optional link identifier */
+ id?: string;
+ /** Optional label (e.g., "Click here to pay") */
+ label?: string;
+ /** Link type (e.g., "payment_link") */
+ type?: string;
+ /** URL (e.g., "https://checkout.stripe.com/pay/cs_test...") */
+ url?: string;
+}
+
+export interface Conversation {
+ conversationId?: string;
+ participants?: Participant[];
+ messages?: Message[];
+ metadata?: {
+
+};
+}
+
+export interface Participant {
+ participantId?: string;
+ displayName?: string;
+ role?: 'operator' | 'user' | 'bot' | 'assistant' | 'agent';
+}
+
+export interface Message {
+ content?: string;
+ participantId?: string;
+ timestamp?: string;
+}
+
+export interface Interaction {
+ content?: string;
+ id?: string;
+ name?: string;
+ role?: string;
+ timestamp?: string;
+}
+
+export interface Product {
+ id?: string;
+}
+
+/** Advanced mode agent-to-agent configuration. Feeds analytics human-vs-bot attribution. */
+export interface A2AConfiguration {
+ id?: string;
+ name?: string;
+ /** Actor type (e.g., "chatbot", "operator"). Feeds analytics operator/bot dimension. */
+ type?: string;
+}
+
+export interface Cursor {
+ /** Start timestamp (e.g., "2024-01-15T10:30:00.000Z") */
+ since?: string;
+ /** End timestamp (e.g., "2024-01-15T11:00:00.000Z") */
+ until?: string;
+}
+
+export interface SuperpowerResult {
+ response?: SuperpowerResponseItem[];
+}
+
+/** Response content varies by superpower type. Recommend results additionally expose recommendationId for click correlation. */
+export interface SuperpowerResponseItem {
+ /** Result content for this item */
+ content?: string;
+ /** Result item type (e.g., adjusted_content, recommendation) */
+ type?: string;
+ /** Stable recommendation correlation id. Present on recommend results; omitted on other superpowers. The consuming UI must echo this value on recommendation.clicked so the program-ctr metric can join with the orchestrator's recommendation.issued. */
+ recommendationId?: string;
+}
+
+export interface ErrorResult {
+ response?: ErrorResponseItem[];
+}
+
+export interface ErrorResponseItem {
+ content: string;
+ error_code?: string;
+}
export interface Payload {
+ /** Session tracking block. Feeds analytics session length/bands and peak concurrency via sessionId. */
session: Session;
request: {
+ /** Unique request identifier */
requestId: string;
attributes?: RequestAttributes;
connections?: Connections;
context?: Context;
+ /** Client-custom labels ONLY (ids/labels/tags). Never the carrier of typed analytics facts (conversation identity, user grain, geography, A/B variant). MUST NOT carry direct identifiers — names, emails, message content. The analytics raw store is append-only under Object Lock. */
reference?: {
+ /** Client-custom identifier pairs. Not typed analytics dimensions. */
ids?: ReferenceId[];
+ /** Client-custom labels. MUST NOT carry names, emails, or message content. */
labels?: any[];
+ /** Client-custom tags. MUST NOT carry names, emails, or message content. */
tags?: any[];
};
resources?: {
codes?: CodesItem[];
links?: LinkItem[];
+ /** Offering details (previously offering_details in v2) */
offers?: any[];
};
scope?: {
@@ -46,6 +237,7 @@ export interface Payload {
transactions?: any[];
users?: any[];
};
+ /** Feature-usage flags. Feeds analytics reasoning-engagement. */
settings?: {
disableBrowsing?: boolean;
disableSearch?: boolean;
@@ -53,45 +245,72 @@ export interface Payload {
disableStream?: boolean;
disableTools?: boolean;
maxResponseLength?: number;
+ /** Override interface language */
overrideInterfaceLanguage?: string;
+ /** Override output language (replaces channel language) */
overrideOutputLanguage?: string;
};
+ /** Agent-to-agent configuration (advanced mode). Feeds analytics human-vs-bot / operator-bot attribution. */
a2a?: A2AConfiguration[];
cursor?: Cursor;
};
}
export interface MessageEnvelope {
+ /** Action type for the envelope */
action: 'message';
headers: {
+ /** UUID for correlating request-response pairs (always generated client-side unless overridden) */
correlationId: string;
+ /** Tenant identifier provided by Optave */
tenantId?: string;
+ /** Optional cross-system tracing ID (forwarded if provided) */
traceId?: string;
+ /** Optional idempotency key; forwarded unchanged if provided */
idempotencyKey?: string;
+ /** Message identifier */
identifier?: 'message';
- action: 'adjust' | 'elevate' | 'customerinteraction' | 'interaction' | 'reception' | 'summarize' | 'translate' | 'recommend' | 'insights';
- schemaRef: 'optave.message.v3';
+ /** Specific action being performed */
+ action: 'adjust' | 'elevate' | 'customerinteraction' | 'interaction' | 'assistant' | 'reception' | 'summarize' | 'translate' | 'recommend' | 'insights';
+ /** Schema reference for the envelope (major version only; minor/patch changes are non-breaking). Format is derived from protocol version. */
+ schemaRef: string;
+ /** SDK package version (independent of schemaRef major) */
sdkVersion?: string;
+ /** Optional client-measured round-trip latency (not sent unless explicitly supplied) */
networkLatencyMs?: number;
+ /** ISO 8601 client timestamp when the message was built */
timestamp?: string;
+ /** Message issued timestamp */
issuedAt?: string;
};
payload: Payload;
}
export interface ResponseEnvelope {
+ /** Action type for the response envelope */
action: 'message';
headers: {
+ /** UUID correlating this response to its originating request (echo of request correlationId) */
correlationId: string;
+ /** Tenant identifier provided by Optave */
tenantId?: string;
+ /** Optional cross-system tracing ID (forwarded if provided) */
traceId?: string;
+ /** Optional idempotency key (echoed if provided in request) */
idempotencyKey?: string;
+ /** Message identifier */
identifier?: 'message';
- action: 'adjust' | 'elevate' | 'customerinteraction' | 'interaction' | 'reception' | 'summarize' | 'translate' | 'recommend' | 'insights';
- schemaRef: 'optave.response.v3' | 'optave.error.v3';
+ /** Specific action being performed */
+ action: 'adjust' | 'elevate' | 'customerinteraction' | 'interaction' | 'assistant' | 'reception' | 'summarize' | 'translate' | 'recommend' | 'insights';
+ /** Schema reference for the response message (response or error). Format is derived from protocol version. */
+ schemaRef: string;
+ /** SDK package version of emitting client (mirrors request header) */
sdkVersion?: string;
+ /** Optional client-measured round-trip latency (not sent unless explicitly supplied) */
networkLatencyMs?: number;
+ /** ISO 8601 server/processing timestamp when this response was generated */
timestamp?: string;
+ /** Response issued timestamp */
issuedAt?: string;
};
payload: SuperpowerResponse | ErrorResponse;
@@ -99,6 +318,7 @@ export interface ResponseEnvelope {
export interface SuperpowerResponse {
action: 'superpower';
+ /** Type of superpower (e.g., adjust_suggestion, sentiment_analysis, risk_assessment) */
actionType: string;
state: 'started' | 'completed' | 'error';
message: {
@@ -108,9 +328,55 @@ export interface SuperpowerResponse {
export interface ErrorResponse {
action: 'superpower';
+ /** Type of operation that failed */
actionType: string;
state: 'error';
message: {
results: ErrorResult[];
};
}
+
+// Currently identical to RequestAttributes; customize if adjust needs specialized fields later
+export type AdjustAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if elevate needs specialized fields later
+export type ElevateAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if customerinteraction needs specialized fields later
+export type CustomerinteractionAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if interaction needs specialized fields later
+export type InteractionAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if assistant needs specialized fields later
+export type AssistantAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if reception needs specialized fields later
+export type ReceptionAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if summarize needs specialized fields later
+export type SummarizeAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if translate needs specialized fields later
+export type TranslateAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if recommend needs specialized fields later
+export type RecommendAttributes = RequestAttributes;
+
+// Currently identical to RequestAttributes; customize if insights needs specialized fields later
+export type InsightsAttributes = RequestAttributes;
+
+export interface ActionAttributesMap {
+ 'adjust': AdjustAttributes;
+ 'elevate': ElevateAttributes;
+ 'customerinteraction': CustomerinteractionAttributes;
+ 'interaction': InteractionAttributes;
+ 'assistant': AssistantAttributes;
+ 'reception': ReceptionAttributes;
+ 'summarize': SummarizeAttributes;
+ 'translate': TranslateAttributes;
+ 'recommend': RecommendAttributes;
+ 'insights': InsightsAttributes;
+}
+
+export type AttributesFor = A extends keyof ActionAttributesMap ? ActionAttributesMap[A] : RequestAttributes;
diff --git a/sdks/javascript/generated/validators.js b/sdks/javascript/generated/validators.js
index f6fa950..981cf67 100644
--- a/sdks/javascript/generated/validators.js
+++ b/sdks/javascript/generated/validators.js
@@ -1,21 +1,21 @@
// AUTO-GENERATED FILE. DO NOT EDIT.
-// Precompiled validators built from specs/asyncapi.yaml (info.version: 3.2.3)
+// Precompiled validators built from specs/asyncapi.yaml (protocol version: 1.0.0)
// Generated using AJV standalone compilation - no runtime AJV dependency required
// Precompiled AJV validators - no runtime AJV dependency required
const uuidv7Format = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
-const MessageEnvelope_schema11 = {"type":"object","required":["action","headers","payload"],"properties":{"action":{"type":"string","enum":["message"],"description":"Action type for the envelope"},"headers":{"type":"object","required":["correlationId","action","schemaRef"],"properties":{"correlationId":{"type":"string","format":"uuidv7","description":"UUID for correlating request-response pairs (always generated client-side unless overridden)"},"tenantId":{"type":"string","description":"Tenant identifier provided by Optave"},"traceId":{"type":"string","format":"uuidv7","description":"Optional cross-system tracing ID (forwarded if provided)"},"idempotencyKey":{"type":"string","format":"uuidv7","description":"Optional idempotency key; forwarded unchanged if provided"},"identifier":{"type":"string","enum":["message"],"description":"Message identifier"},"action":{"type":"string","enum":["adjust","elevate","customerinteraction","interaction","reception","summarize","translate","recommend","insights"],"description":"Specific action being performed"},"schemaRef":{"type":"string","enum":["optave.message.v3"],"description":"Schema reference for the envelope (major version only; minor/patch changes are non-breaking)"},"sdkVersion":{"type":"string","description":"SDK package version (independent of schemaRef major)"},"networkLatencyMs":{"type":"number","description":"Optional client-measured round-trip latency (not sent unless explicitly supplied)"},"timestamp":{"type":"string","format":"date-time","description":"ISO 8601 client timestamp when the message was built"},"issuedAt":{"type":"string","format":"date-time","description":"Message issued timestamp"}}},"payload":{"$ref":"Payload"}},"allOf":[{"type":"object","required":["action","headers","payload"],"properties":{"action":{"type":"string","enum":["message"]},"headers":{"type":"object"},"payload":{"type":"object"}}},{"if":{"properties":{"headers":{"properties":{"action":{"enum":["adjust","elevate","interaction","customerInteraction"]}}}}},"then":{"properties":{"payload":{"$ref":"PayloadWithRequiredConversations"}}}},{"if":{"properties":{"headers":{"properties":{"action":{"enum":["summarize","translate","insights","recommend"]}}}}},"then":{"properties":{"payload":{"$ref":"PayloadWithRequiredConversations"}}}}]};const MessageEnvelope_schema12 = {"allOf":[{"$ref":"Payload"},{"type":"object","required":["request"],"properties":{"request":{"type":"object","required":["scope"],"properties":{"scope":{"type":"object","required":["conversations"],"properties":{"conversations":{"type":"array","minItems":1,"items":{"$ref":"Conversation"}}}}}}}}]};const MessageEnvelope_schema13 = {"type":"object","required":["session","request"],"properties":{"session":{"$ref":"Session"},"request":{"type":"object","required":["requestId"],"properties":{"requestId":{"type":"string","description":"Unique request identifier"},"attributes":{"$ref":"RequestAttributes"},"connections":{"$ref":"Connections"},"context":{"$ref":"Context"},"reference":{"type":"object","properties":{"ids":{"type":"array","items":{"$ref":"ReferenceId"}},"labels":{"type":"array","description":"Reference labels"},"tags":{"type":"array","description":"Reference tags"}}},"resources":{"type":"object","properties":{"codes":{"type":"array","items":{"$ref":"CodesItem"}},"links":{"type":"array","items":{"$ref":"LinkItem"}},"offers":{"type":"array","description":"Offering details (previously offering_details in v2)"}}},"scope":{"type":"object","properties":{"accounts":{"type":"array"},"appointments":{"type":"array"},"assets":{"type":"array"},"bookings":{"type":"array"},"cases":{"type":"array"},"conversations":{"type":"array","items":{"$ref":"Conversation"}},"documents":{"type":"array"},"events":{"type":"array"},"interactions":{"type":"array","items":{"$ref":"Interaction"}},"items":{"type":"array"},"locations":{"type":"array"},"offers":{"type":"array"},"operators":{"type":"array"},"orders":{"type":"array"},"organizations":{"type":"array"},"persons":{"type":"array"},"policies":{"type":"array"},"products":{"type":"array","items":{"$ref":"Product"}},"properties":{"type":"array"},"services":{"type":"array"},"subscriptions":{"type":"array"},"tickets":{"type":"array"},"transactions":{"type":"array"},"users":{"type":"array"}}},"settings":{"type":"object","properties":{"disableBrowsing":{"type":"boolean","default":false},"disableSearch":{"type":"boolean","default":false},"disableSources":{"type":"boolean","default":false},"disableStream":{"type":"boolean","default":true},"disableTools":{"type":"boolean","default":false},"maxResponseLength":{"type":"number","default":0},"overrideInterfaceLanguage":{"type":"string","description":"Override interface language"},"overrideOutputLanguage":{"type":"string","description":"Override output language (replaces channel language)"}}},"a2a":{"type":"array","items":{"$ref":"A2AConfiguration"},"description":"Advanced mode agent-to-agent configuration"},"cursor":{"$ref":"Cursor"}}}}};const MessageEnvelope_schema17 = {"type":"object","properties":{"content":{"type":"string","description":"Content to be processed"},"instruction":{"type":"string","description":"Specific instruction for the action"},"variant":{"type":"string","description":"Variant identifier (e.g., \"A\", \"B\")"}}};const MessageEnvelope_schema18 = {"type":"object","properties":{"journeyId":{"type":"string","description":"Journey identifier"},"parentId":{"type":"string","description":"Parent request ID (previously trace_parent_ID in v2)"},"threadId":{"type":"string","description":"Thread ID that remains unique across all requests related to same ticket/case/conversation"}}};const MessageEnvelope_schema19 = {"type":"object","properties":{"caseId":{"type":"string","description":"Case identifier (advanced mode)"},"departmentId":{"type":"string","description":"Department identifier (advanced mode)"},"operatorId":{"type":"string","description":"Operator identifier (advanced mode)"},"organizationId":{"type":"string","description":"Organization identifier"},"userId":{"type":"string","description":"User identifier (advanced mode)"}}};const MessageEnvelope_schema20 = {"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"}}};const MessageEnvelope_schema21 = {"type":"object","properties":{"id":{"type":"string","description":"Optional for tracking/mapping"},"label":{"type":"string","description":"Optional, helps for display/templating (e.g., \"Order Number\")"},"type":{"type":"string","description":"Code type (e.g., \"order_number\", \"booking_reference\", \"ticket_code\")"},"value":{"type":"string","description":"Code value (e.g., \"ORD-56789\")"}}};const MessageEnvelope_schema22 = {"type":"object","properties":{"expires_at":{"type":"string","description":"Optional expiration timestamp"},"html":{"type":"boolean","description":"Optional HTML flag"},"id":{"type":"string","description":"Optional link identifier"},"label":{"type":"string","description":"Optional label (e.g., \"Click here to pay\")"},"type":{"type":"string","description":"Link type (e.g., \"payment_link\")"},"url":{"type":"string","description":"URL (e.g., \"https://checkout.stripe.com/pay/cs_test...\")"}}};const MessageEnvelope_schema26 = {"type":"object","properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"role":{"type":"string"},"timestamp":{"type":"string"}}};const MessageEnvelope_schema27 = {"type":"object","properties":{"id":{"type":"string"}}};const MessageEnvelope_schema28 = {"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}},"description":"Advanced mode agent-to-agent configuration"};const MessageEnvelope_schema29 = {"type":"object","properties":{"since":{"type":"string","description":"Start timestamp (e.g., \"2024-01-15T10:30:00.000Z\")"},"until":{"type":"string","description":"End timestamp (e.g., \"2024-01-15T11:00:00.000Z\")"}}};const MessageEnvelope_schema14 = {"type":"object","properties":{"sessionId":{"type":"string","description":"Unique session identifier lasting for duration of chat session or call"},"channel":{"$ref":"Channel"},"interface":{"$ref":"Interface"}}};const MessageEnvelope_schema15 = {"type":"object","properties":{"browser":{"type":"string","description":"Browser information"},"deviceInfo":{"type":"string","description":"Device information (e.g., \"iOS/18.2, iPhone15,3\")"},"deviceType":{"type":"string","description":"Type of device"},"language":{"type":"string","description":"Interface language"},"location":{"type":"string","description":"Geographic location (e.g., \"45.42,-75.69\")"},"medium":{"type":"string","enum":["chat","voice","email"],"description":"Communication medium (allowed: chat, voice, email; default is chat if omitted)"},"metadata":{"type":"array","description":"Custom metadata array"},"section":{"type":"string","description":"Section of the application (e.g., \"cart\", \"product_page\")"}}};const MessageEnvelope_schema16 = {"type":"object","properties":{"appVersion":{"type":"string","description":"Custom application version"},"category":{"type":"string","description":"Interface category (e.g., \"crm\", \"app\", \"auto\", \"widget\")"},"language":{"type":"string","description":"Language from the CRM agent"},"name":{"type":"string","description":"Interface name (e.g., \"salesforce\", \"zendesk\")"},"type":{"type":"string","description":"Interface type (e.g., \"custom_components\", \"marketplace\", \"channel\")"}}};function MessageEnvelope_validate13(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){let vErrors = null;let errors = 0;if(data && typeof data == "object" && !Array.isArray(data)){if(data.sessionId !== undefined){let data0 = data.sessionId;if(typeof data0 !== "string"){const err0 = {instancePath:instancePath+"/sessionId",schemaPath:"#/properties/sessionId/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema14.properties.sessionId.type,parentSchema:MessageEnvelope_schema14.properties.sessionId,data:data0};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}}if(data.channel !== undefined){let data1 = data.channel;if(data1 && typeof data1 == "object" && !Array.isArray(data1)){if(data1.browser !== undefined){let data2 = data1.browser;if(typeof data2 !== "string"){const err1 = {instancePath:instancePath+"/channel/browser",schemaPath:"Channel/properties/browser/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema15.properties.browser.type,parentSchema:MessageEnvelope_schema15.properties.browser,data:data2};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data1.deviceInfo !== undefined){let data3 = data1.deviceInfo;if(typeof data3 !== "string"){const err2 = {instancePath:instancePath+"/channel/deviceInfo",schemaPath:"Channel/properties/deviceInfo/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema15.properties.deviceInfo.type,parentSchema:MessageEnvelope_schema15.properties.deviceInfo,data:data3};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data1.deviceType !== undefined){let data4 = data1.deviceType;if(typeof data4 !== "string"){const err3 = {instancePath:instancePath+"/channel/deviceType",schemaPath:"Channel/properties/deviceType/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema15.properties.deviceType.type,parentSchema:MessageEnvelope_schema15.properties.deviceType,data:data4};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data1.language !== undefined){let data5 = data1.language;if(typeof data5 !== "string"){const err4 = {instancePath:instancePath+"/channel/language",schemaPath:"Channel/properties/language/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema15.properties.language.type,parentSchema:MessageEnvelope_schema15.properties.language,data:data5};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data1.location !== undefined){let data6 = data1.location;if(typeof data6 !== "string"){const err5 = {instancePath:instancePath+"/channel/location",schemaPath:"Channel/properties/location/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema15.properties.location.type,parentSchema:MessageEnvelope_schema15.properties.location,data:data6};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data1.medium !== undefined){let data7 = data1.medium;if(typeof data7 !== "string"){const err6 = {instancePath:instancePath+"/channel/medium",schemaPath:"Channel/properties/medium/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema15.properties.medium.type,parentSchema:MessageEnvelope_schema15.properties.medium,data:data7};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}if(!(((data7 === "chat") || (data7 === "voice")) || (data7 === "email"))){const err7 = {instancePath:instancePath+"/channel/medium",schemaPath:"Channel/properties/medium/enum",keyword:"enum",params:{allowedValues: MessageEnvelope_schema15.properties.medium.enum},message:"must be equal to one of the allowed values",schema:MessageEnvelope_schema15.properties.medium.enum,parentSchema:MessageEnvelope_schema15.properties.medium,data:data7};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data1.metadata !== undefined){let data8 = data1.metadata;if(!(Array.isArray(data8))){const err8 = {instancePath:instancePath+"/channel/metadata",schemaPath:"Channel/properties/metadata/type",keyword:"type",params:{type: "array"},message:"must be array",schema:MessageEnvelope_schema15.properties.metadata.type,parentSchema:MessageEnvelope_schema15.properties.metadata,data:data8};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data1.section !== undefined){let data9 = data1.section;if(typeof data9 !== "string"){const err9 = {instancePath:instancePath+"/channel/section",schemaPath:"Channel/properties/section/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema15.properties.section.type,parentSchema:MessageEnvelope_schema15.properties.section,data:data9};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}}else {const err10 = {instancePath:instancePath+"/channel",schemaPath:"Channel/type",keyword:"type",params:{type: "object"},message:"must be object",schema:MessageEnvelope_schema15.type,parentSchema:MessageEnvelope_schema15,data:data1};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.interface !== undefined){let data10 = data.interface;if(data10 && typeof data10 == "object" && !Array.isArray(data10)){if(data10.appVersion !== undefined){let data11 = data10.appVersion;if(typeof data11 !== "string"){const err11 = {instancePath:instancePath+"/interface/appVersion",schemaPath:"Interface/properties/appVersion/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema16.properties.appVersion.type,parentSchema:MessageEnvelope_schema16.properties.appVersion,data:data11};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data10.category !== undefined){let data12 = data10.category;if(typeof data12 !== "string"){const err12 = {instancePath:instancePath+"/interface/category",schemaPath:"Interface/properties/category/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema16.properties.category.type,parentSchema:MessageEnvelope_schema16.properties.category,data:data12};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data10.language !== undefined){let data13 = data10.language;if(typeof data13 !== "string"){const err13 = {instancePath:instancePath+"/interface/language",schemaPath:"Interface/properties/language/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema16.properties.language.type,parentSchema:MessageEnvelope_schema16.properties.language,data:data13};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}if(data10.name !== undefined){let data14 = data10.name;if(typeof data14 !== "string"){const err14 = {instancePath:instancePath+"/interface/name",schemaPath:"Interface/properties/name/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema16.properties.name.type,parentSchema:MessageEnvelope_schema16.properties.name,data:data14};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data10.type !== undefined){let data15 = data10.type;if(typeof data15 !== "string"){const err15 = {instancePath:instancePath+"/interface/type",schemaPath:"Interface/properties/type/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema16.properties.type.type,parentSchema:MessageEnvelope_schema16.properties.type,data:data15};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}}else {const err16 = {instancePath:instancePath+"/interface",schemaPath:"Interface/type",keyword:"type",params:{type: "object"},message:"must be object",schema:MessageEnvelope_schema16.type,parentSchema:MessageEnvelope_schema16,data:data10};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object",schema:MessageEnvelope_schema14.type,parentSchema:MessageEnvelope_schema14,data};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}MessageEnvelope_validate13.errors = vErrors;return errors === 0;}const MessageEnvelope_schema23 = {"type":"object","properties":{"conversationId":{"type":"string"},"participants":{"type":"array","items":{"$ref":"Participant"}},"messages":{"type":"array","items":{"$ref":"Message"}},"metadata":{"type":"object"}}};const MessageEnvelope_schema24 = {"type":"object","properties":{"participantId":{"type":"string"},"displayName":{"type":"string"},"role":{"type":"string","enum":["operator","user","bot"]}}};const MessageEnvelope_schema25 = {"type":"object","properties":{"content":{"type":"string"},"participantId":{"type":"string"},"timestamp":{"type":"string"}}};function MessageEnvelope_validate15(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){let vErrors = null;let errors = 0;if(data && typeof data == "object" && !Array.isArray(data)){if(data.conversationId !== undefined){let data0 = data.conversationId;if(typeof data0 !== "string"){const err0 = {instancePath:instancePath+"/conversationId",schemaPath:"#/properties/conversationId/type",keyword:"type",params:{type: "string"},message:"must be string",schema:MessageEnvelope_schema23.properties.conversationId.type,parentSchema:MessageEnvelope_schema23.properties.conversationId,data:data0};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}}if(data.participants !== undefined){let data1 = data.participants;if(Array.isArray(data1)){const len0 = data1.length;for(let i0=0; i0`
-3. Access SDK: `const SDK = globalThis.OptaveJavaScriptSDK;`
-
-**Option 2: Server UMD (Alternative)**
-1. Upload `dist/server.umd.js` as a static resource
+**Use Browser UMD Only:**
+1. Upload `dist/browser.umd.js` as a static resource (NOT server.umd.js)
2. Load in Lightning Component: ``
3. Access SDK: `const SDK = globalThis.OptaveJavaScriptSDK;`
-
-**Common Steps:**
4. **Configure CSP**: Add Optave domain(s) to Trusted URLs (CSP allowlist) for connect-src in Salesforce Setup
5. Initialize with token provider using Apex controller
-See [`salesforce-lightning-integration.js`](./salesforce-lightning-integration.js) (Browser UMD) or [`salesforce-lightning-server-umd.js`](./salesforce-lightning-server-umd.js) (Server UMD) for complete examples.
+See [`salesforce-lightning-integration.js`](./salesforce-lightning-integration.js) for a complete example.
#### Salesforce Compatibility Features
- ✅ Lightning Locker Service compliant
@@ -280,7 +323,7 @@ If you're currently using manual WebSocket connections, see the browser integrat
For additional help with integrations:
1. **Recommended**: Use ESM builds (`browser-esm-integration.mjs` or `server-esm-integration.mjs`)
-2. **For Salesforce**: Use `salesforce-lightning-integration.js` or `salesforce-lightning-server-umd.js`
+2. **For Salesforce**: Use `salesforce-lightning-integration.js` (browser-umd only)
3. Check the main SDK documentation
4. Review test files in `tests/` directory
5. Examine examples in `generated/examples/` directory
diff --git a/sdks/javascript/integration/browser-umd-integration.js b/sdks/javascript/integration/browser-umd-integration.js
index ccd0642..0e23c2f 100644
--- a/sdks/javascript/integration/browser-umd-integration.js
+++ b/sdks/javascript/integration/browser-umd-integration.js
@@ -13,13 +13,11 @@
// For UMD builds, the SDK should be available as a global variable when included via script tag
// HTML:
-(function() {
- 'use strict';
-
+(function () {
// Check if OptaveJavaScriptSDK is available globally (script tag usage)
- var OptaveJavaScriptSDK = (typeof globalThis !== 'undefined' && globalThis.OptaveJavaScriptSDK) ||
- (typeof window !== 'undefined' && window.OptaveJavaScriptSDK) ||
- (typeof global !== 'undefined' && global.OptaveJavaScriptSDK);
+ let OptaveJavaScriptSDK = (typeof globalThis !== 'undefined' && globalThis.OptaveJavaScriptSDK)
+ || (typeof window !== 'undefined' && window.OptaveJavaScriptSDK)
+ || (typeof global !== 'undefined' && global.OptaveJavaScriptSDK);
// If not available globally, try to load it (for Node.js testing)
if (!OptaveJavaScriptSDK && typeof require !== 'undefined') {
@@ -39,104 +37,102 @@
* Browser UMD Configuration
* Compatible with older browsers and module systems
*/
- var optaveClient = new OptaveJavaScriptSDK({
+ const optaveClient = new OptaveJavaScriptSDK({
websocketUrl: (window.OPTAVE_CONFIG && window.OPTAVE_CONFIG.websocketUrl),
authTransport: 'subprotocol',
- tokenProvider: function() {
+ tokenProvider() {
return fetch('/api/optave/ws-ticket', {
method: 'POST',
credentials: 'include',
headers: {
- 'Content-Type': 'application/json'
- }
- })
- .then(function(response) {
- if (!response.ok) {
- throw new Error('Failed to get token: ' + response.status + ' ' + response.statusText);
- }
- return response.json();
- })
- .then(function(data) {
- return data.token;
+ 'Content-Type': 'application/json',
+ },
})
- .catch(function(error) {
- console.error('Token provider failed:', error);
- throw error;
- });
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error(`Failed to get token: ${response.status} ${response.statusText}`);
+ }
+ return response.json();
+ })
+ .then((data) => data.token)
+ .catch((error) => {
+ console.error('Token provider failed:', error);
+ throw error;
+ });
},
- strictValidation: false // Browser UMD typically used in production
+ strictValidation: false, // Browser UMD typically used in production
});
+ // Helper function for generating IDs (simplified for UMD)
+ function generateId() {
+ return `umd-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
+ }
+
+ // Test function
+ function sendTestMessage() {
+ const threadId = `browser-umd-thread-${generateId()}`;
+
+ optaveClient.interaction({
+ request: {
+ connections: {
+ threadId,
+ },
+ scope: {
+ conversations: [{
+ conversationId: `conv-${Date.now()}`,
+ participants: [{
+ participantId: 'user_1',
+ role: 'user',
+ displayName: 'Browser UMD User',
+ }],
+ messages: [{
+ participantId: 'user_1',
+ content: 'Test message from Browser UMD build',
+ timestamp: new Date().toISOString(),
+ }],
+ metadata: {},
+ }],
+ },
+ },
+ });
+ }
+
// Event handlers using traditional function syntax
- optaveClient.on('open', function() {
+ optaveClient.on('open', () => {
console.log('✅ Browser UMD: WebSocket connection established');
sendTestMessage();
});
- optaveClient.on('message', function(payload) {
+ optaveClient.on('message', (payload) => {
try {
- var message = JSON.parse(payload);
+ const message = JSON.parse(payload);
console.log('📨 Browser UMD: Received message:', {
action: message.headers && message.headers.action,
- correlationId: message.headers && message.headers.correlationId
+ correlationId: message.headers && message.headers.correlationId,
});
} catch (error) {
console.error('Browser UMD: Failed to parse message:', error);
}
});
- optaveClient.on('error', function(error) {
+ optaveClient.on('error', (error) => {
console.error('❌ Browser UMD: SDK error:', {
category: error.category,
code: error.code,
- message: error.message
+ message: error.message,
});
});
- optaveClient.on('close', function(event) {
+ optaveClient.on('close', (event) => {
console.log('🔌 Browser UMD: Connection closed:', {
code: event.code,
- reason: event.reason
+ reason: event.reason,
});
});
- // Helper function for generating IDs (simplified for UMD)
- function generateId() {
- return 'umd-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
- }
-
- // Test function
- function sendTestMessage() {
- var threadId = 'browser-umd-thread-' + generateId();
-
- optaveClient.interaction({
- request: {
- connections: {
- threadId: threadId
- },
- scope: {
- conversations: [{
- conversationId: 'conv-' + Date.now(),
- participants: [{
- participantId: 'user_1',
- role: 'user',
- displayName: 'Browser UMD User'
- }],
- messages: [{
- participantId: 'user_1',
- content: 'Test message from Browser UMD build',
- timestamp: new Date().toISOString()
- }],
- metadata: {}
- }]
- }
- }
- });
- }
-
// Connect function
function connect() {
try {
@@ -161,7 +157,7 @@
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', callback);
} else if (document.attachEvent) {
- document.attachEvent('onreadystatechange', function() {
+ document.attachEvent('onreadystatechange', () => {
if (document.readyState === 'complete') {
callback();
}
@@ -169,11 +165,11 @@
}
}
- onDocumentReady(function() {
+ onDocumentReady(() => {
console.log('🚀 Browser UMD integration ready');
// Set up UI event handlers
- var connectButton = document.getElementById('connect-umd');
+ const connectButton = document.getElementById('connect-umd');
if (connectButton) {
if (connectButton.addEventListener) {
connectButton.addEventListener('click', connect);
@@ -182,7 +178,7 @@
}
}
- var disconnectButton = document.getElementById('disconnect-umd');
+ const disconnectButton = document.getElementById('disconnect-umd');
if (disconnectButton) {
if (disconnectButton.addEventListener) {
disconnectButton.addEventListener('click', cleanup);
@@ -203,11 +199,10 @@
// Export to global scope for external access
window.OptaveBrowserUMDIntegration = {
client: optaveClient,
- connect: connect,
- cleanup: cleanup
+ connect,
+ cleanup,
};
-
-})();
+}());
/**
* Browser UMD Integration Notes:
@@ -248,4 +243,4 @@
* - Node.js server environments
* - Applications requiring tree-shaking
* - TypeScript projects without declaration files
- */
\ No newline at end of file
+ */
diff --git a/sdks/javascript/integration/quick-start.js b/sdks/javascript/integration/quick-start.js
new file mode 100644
index 0000000..49d681b
--- /dev/null
+++ b/sdks/javascript/integration/quick-start.js
@@ -0,0 +1,136 @@
+/**
+ * Quick Start Example
+ *
+ * This example demonstrates the simplest way to get started with the Optave SDK:
+ * - Initialize the SDK
+ * - Authenticate with client credentials
+ * - Establish a WebSocket connection
+ * - Send an interaction message
+ * - Handle events
+ *
+ * For production-ready integration patterns, see the other files in this directory:
+ * - server-esm-integration.mjs - Modern Node.js with ES modules
+ * - server-umd-integration.js - Legacy Node.js with CommonJS
+ * - browser-esm-integration.mjs - Modern browsers with ES modules
+ * - browser-umd-integration.js - Legacy browsers and Salesforce Lightning
+ */
+
+// Import the SDK (use the appropriate import based on your environment)
+// For ES Modules:
+import OptaveJavaScriptSDK from '@optave/client-sdk';
+
+// For CommonJS (Node.js without type: "module"):
+// const OptaveJavaScriptSDK = require('@optave/client-sdk/server-umd');
+
+// Initialize the SDK with configuration
+const optaveClient = new OptaveJavaScriptSDK({
+ websocketUrl: process.env.OPTAVE__WEBSOCKET_URL,
+ authenticationUrl: process.env.OPTAVE__AUTHENTICATION_URL,
+ clientId: process.env.OPTAVE__CLIENT_ID,
+ clientSecret: process.env.OPTAVE__CLIENT_SECRET,
+});
+
+// Listen for connection open event
+optaveClient.on('open', () => {
+ console.log('✅ WebSocket connection established');
+
+ // Send an interaction message once connected
+ optaveClient.interaction({
+ session: {
+ sessionId: 'example-session-123',
+ channel: {
+ browser: 'Chrome 120.0',
+ deviceType: 'desktop',
+ language: 'en-US',
+ medium: 'chat',
+ section: 'support',
+ },
+ interface: {
+ appVersion: '1.0.0',
+ category: 'support',
+ language: 'en-US',
+ name: 'example_app',
+ type: 'web_app',
+ },
+ },
+ request: {
+ requestId: 'req-example-123',
+ connections: {
+ threadId: 'thread-example-123',
+ },
+ context: {
+ organizationId: 'org-example-123',
+ },
+ scope: {
+ conversations: [
+ {
+ conversationId: 'conv-example-123',
+ participants: [
+ {
+ participantId: 'user-123',
+ role: 'user',
+ displayName: 'Example User',
+ },
+ ],
+ messages: [
+ {
+ timestamp: new Date().toISOString(),
+ participantId: 'user-123',
+ content: 'Hello, I need help with my account',
+ },
+ ],
+ },
+ ],
+ },
+ },
+ });
+});
+
+// Listen for incoming messages
+optaveClient.on('message', (payload) => {
+ try {
+ const message = JSON.parse(payload);
+ console.log('📨 Received message:', {
+ action: message.action,
+ state: message.state,
+ actionType: message.actionType,
+ });
+ } catch (error) {
+ console.error('❌ Error parsing message:', error);
+ }
+});
+
+// Listen for errors
+optaveClient.on('error', (error) => {
+ console.error('❌ SDK Error:', error);
+});
+
+// Listen for connection close event
+optaveClient.on('close', () => {
+ console.log('🔌 WebSocket connection closed');
+});
+
+// Authenticate and establish connection
+async function connect() {
+ try {
+ console.log('🔐 Authenticating...');
+ const token = await optaveClient.authenticate();
+ console.log('✅ Authentication successful');
+
+ console.log('🔌 Opening WebSocket connection...');
+ optaveClient.openConnection(token);
+ } catch (error) {
+ console.error('❌ Failed to connect:', error);
+ process.exit(1);
+ }
+}
+
+// Start the connection
+connect();
+
+// Handle graceful shutdown
+process.on('SIGINT', () => {
+ console.log('\n🛑 Shutting down...');
+ optaveClient.closeConnection();
+ process.exit(0);
+});
diff --git a/sdks/javascript/integration/salesforce-lightning-integration.js b/sdks/javascript/integration/salesforce-lightning-integration.js
index fa6b0a7..2c42b16 100644
--- a/sdks/javascript/integration/salesforce-lightning-integration.js
+++ b/sdks/javascript/integration/salesforce-lightning-integration.js
@@ -21,173 +21,177 @@
*/
// Example Lightning Component Controller (.js)
+// NOTE: Aura controller/helper files must be a single bare object expression `({...})`
+// — the framework captures the last-evaluated expression. Do not convert to a named const.
({
- doInit: function(component, event, helper) {
- console.log('🚀 Initializing Optave SDK in Lightning Component...');
+ doInit(component, event, helper) {
+ console.log('🚀 Initializing Optave SDK in Lightning Component...');
- // Access SDK from global scope (loaded via static resource)
- // UMD build exports directly to globalThis for Lightning Locker compatibility
- const OptaveSDK = globalThis.OptaveJavaScriptSDK;
+ // Access SDK from global scope (loaded via static resource)
+ // UMD build exports directly to globalThis for Lightning Locker compatibility
+ const OptaveSDK = globalThis.OptaveJavaScriptSDK;
- if (!OptaveSDK) {
- console.error('❌ Optave SDK not found. Ensure browser.umd.js is loaded as static resource.');
- return;
- }
+ if (!OptaveSDK) {
+ console.error('❌ Optave SDK not found. Ensure browser.umd.js is loaded as static resource.');
+ return;
+ }
- // Initialize SDK with Salesforce-compatible configuration
- const sdk = new OptaveSDK({
- websocketUrl: 'wss://optave-api.force.com/socket', // Use Salesforce-compatible WSS URL
- authTransport: 'subprotocol', // Required for Lightning Locker security
+ // Initialize SDK with Salesforce-compatible configuration
+ const sdk = new OptaveSDK({
+ websocketUrl: 'wss://optave-api.force.com/socket', // Use Salesforce-compatible WSS URL
+ authTransport: 'subprotocol', // Required for Lightning Locker security
- // Token provider - get token from Salesforce backend
- tokenProvider: async () => {
- try {
- // Call Salesforce Apex method to get Optave token
- const action = component.get("c.getOptaveToken");
-
- return new Promise((resolve, reject) => {
- action.setCallback(this, function(response) {
- if (response.getState() === "SUCCESS") {
- resolve(response.getReturnValue());
- } else {
- reject(new Error(response.getError()[0].message));
- }
- });
- $A.enqueueAction(action);
- });
- } catch (error) {
- console.error('Token provider failed:', error);
- throw error;
- }
- },
+ // Token provider - get token from Salesforce backend
+ tokenProvider: async () => {
+ try {
+ // Call Salesforce Apex method to get Optave token
+ const action = component.get('c.getOptaveToken');
+
+ return new Promise((resolve, reject) => {
+ action.setCallback(this, (response) => {
+ if (response.getState() === 'SUCCESS') {
+ resolve(response.getReturnValue());
+ } else {
+ reject(new Error(response.getError()[0].message));
+ }
+ });
+ $A.enqueueAction(action);
+ });
+ } catch (error) {
+ console.error('Token provider failed:', error);
+ throw error;
+ }
+ },
- strictValidation: false // Use browser-safe validation for CSP compliance
- });
+ strictValidation: false, // Use browser-safe validation for CSP compliance
+ });
- // Store SDK instance on component for later use
- component.set("v.optaveSdk", sdk);
+ // Store SDK instance on component for later use
+ component.set('v.optaveSdk', sdk);
- // Set up event handlers
- helper.setupOptaveEvents(component, sdk);
+ // Set up event handlers
+ helper.setupOptaveEvents(component, sdk);
- console.log('✅ Optave SDK initialized in Lightning Component');
- },
+ console.log('✅ Optave SDK initialized in Lightning Component');
+ },
- sendCustomerMessage: function(component, event, helper) {
- const sdk = component.get("v.optaveSdk");
- const messageText = component.get("v.messageText");
+ sendCustomerMessage(component, event, helper) {
+ const sdk = component.get('v.optaveSdk');
+ const messageText = component.get('v.messageText');
- if (sdk && messageText) {
- helper.sendOptaveMessage(sdk, messageText);
- }
+ if (sdk && messageText) {
+ helper.sendOptaveMessage(sdk, messageText);
}
+ },
});
// Example Lightning Component Helper (.js)
+// NOTE: Aura helper files, like controllers, must be a single bare object expression.
({
- setupOptaveEvents: function(component, sdk) {
- // Set up SDK event handlers
- sdk.on('open', function() {
- console.log('✅ Lightning: WebSocket connected');
- component.set("v.connectionStatus", "Connected");
- });
-
- sdk.on('message', function(payload) {
- try {
- const message = JSON.parse(payload);
- console.log('📨 Lightning: Received message:', message.headers?.action);
-
- // Update component UI with response
- this.handleOptaveResponse(component, message);
- } catch (error) {
- console.error('Lightning: Failed to parse message:', error);
- }
- }.bind(this));
-
- sdk.on('error', function(error) {
- console.error('❌ Lightning: SDK error:', error.category, error.message);
- component.set("v.connectionStatus", "Error: " + error.message);
- });
-
- sdk.on('close', function(event) {
- console.log('🔌 Lightning: Connection closed');
- component.set("v.connectionStatus", "Disconnected");
+ setupOptaveEvents(component, sdk) {
+ // Set up SDK event handlers
+ sdk.on('open', () => {
+ console.log('✅ Lightning: WebSocket connected');
+ component.set('v.connectionStatus', 'Connected');
+ });
+
+ sdk.on('message', (payload) => {
+ try {
+ const message = JSON.parse(payload);
+ console.log('📨 Lightning: Received message:', message.headers?.action);
+
+ // Update component UI with response
+ this.handleOptaveResponse(component, message);
+ } catch (error) {
+ console.error('Lightning: Failed to parse message:', error);
+ }
+ });
+
+ sdk.on('error', (error) => {
+ console.error('❌ Lightning: SDK error:', error.category, error.message);
+ component.set('v.connectionStatus', `Error: ${error.message}`);
+ });
+
+ sdk.on('close', (event) => {
+ console.log('🔌 Lightning: Connection closed');
+ component.set('v.connectionStatus', 'Disconnected');
+ });
+ },
+
+ sendOptaveMessage(sdk, messageText) {
+ try {
+ // Send customer interaction to Optave
+ sdk.interaction({
+ request: {
+ connections: {
+ threadId: `salesforce-thread-${Date.now()}`,
+ },
+ context: {
+ organizationId: $A.get('$Organization.Id'), // Use Salesforce Org ID
+ },
+ scope: {
+ conversations: [{
+ conversationId: `conv_${Date.now()}`,
+ participants: [{
+ participantId: $A.get('$User.Id'),
+ role: 'user',
+ displayName: `${$A.get('$User.FirstName')} ${$A.get('$User.LastName')}`,
+ }],
+ messages: [{
+ participantId: $A.get('$User.Id'),
+ content: messageText,
+ timestamp: new Date().toISOString(),
+ }],
+ metadata: {},
+ }],
+ },
+ },
+ });
+
+ console.log('✅ Lightning: Message sent to Optave');
+ } catch (error) {
+ console.error('❌ Lightning: Failed to send message:', error);
+ }
+ },
+
+ handleOptaveResponse(component, message) {
+ // Handle different types of Optave responses
+ switch (message.headers?.action) {
+ case 'interaction': {
+ // Update chat UI with AI response
+ const responses = component.get('v.chatResponses') || [];
+ responses.push({
+ id: message.headers.correlationId,
+ content: message.payload?.response?.content || 'AI response received',
+ timestamp: message.headers.timestamp,
+ type: 'ai',
});
- },
-
- sendOptaveMessage: function(sdk, messageText) {
- try {
- // Send customer interaction to Optave
- sdk.interaction({
- request: {
- connections: {
- threadId: "salesforce-thread-" + Date.now()
- },
- context: {
- organizationId: $A.get("$Organization.Id") // Use Salesforce Org ID
- },
- scope: {
- conversations: [{
- conversationId: "conv_" + Date.now(),
- participants: [{
- participantId: $A.get("$User.Id"),
- role: "user",
- displayName: $A.get("$User.FirstName") + " " + $A.get("$User.LastName")
- }],
- messages: [{
- participantId: $A.get("$User.Id"),
- content: messageText,
- timestamp: new Date().toISOString()
- }],
- metadata: {}
- }]
- }
- }
- });
-
- console.log('✅ Lightning: Message sent to Optave');
- } catch (error) {
- console.error('❌ Lightning: Failed to send message:', error);
- }
- },
-
- handleOptaveResponse: function(component, message) {
- // Handle different types of Optave responses
- switch (message.headers?.action) {
- case 'interaction':
- // Update chat UI with AI response
- const responses = component.get("v.chatResponses") || [];
- responses.push({
- id: message.headers.correlationId,
- content: message.payload?.response?.content || 'AI response received',
- timestamp: message.headers.timestamp,
- type: 'ai'
- });
- component.set("v.chatResponses", responses);
- break;
-
- case 'elevate':
- // Handle escalation to human agent
- component.set("v.isEscalated", true);
- this.showToast('Success', 'Escalated to human agent', 'success');
- break;
-
- default:
- console.log('Unhandled message type:', message.headers?.action);
- }
- },
-
- showToast: function(title, message, type) {
- const toastEvent = $A.get("e.force:showToast");
- if (toastEvent) {
- toastEvent.setParams({
- title: title,
- message: message,
- type: type
- });
- toastEvent.fire();
- }
+ component.set('v.chatResponses', responses);
+ break;
+ }
+
+ case 'elevate':
+ // Handle escalation to human agent
+ component.set('v.isEscalated', true);
+ this.showToast('Success', 'Escalated to human agent', 'success');
+ break;
+
+ default:
+ console.log('Unhandled message type:', message.headers?.action);
+ }
+ },
+
+ showToast(title, message, type) {
+ const toastEvent = $A.get('e.force:showToast');
+ if (toastEvent) {
+ toastEvent.setParams({
+ title,
+ message,
+ type,
+ });
+ toastEvent.fire();
}
+ },
});
/**
@@ -431,4 +435,4 @@ public with sharing class OptaveController {
console.log('📚 Salesforce Lightning Integration Guide Loaded');
console.log(' Use server.umd.js as static resource (optimized for Salesforce)');
console.log(' Access via: globalThis.OptaveJavaScriptSDK');
-console.log(' Implement token provider with Apex controller');
\ No newline at end of file
+console.log(' Implement token provider with Apex controller');
diff --git a/sdks/javascript/integration/salesforce-lightning-server-umd.js b/sdks/javascript/integration/salesforce-lightning-server-umd.js
deleted file mode 100644
index 5a2e59f..0000000
--- a/sdks/javascript/integration/salesforce-lightning-server-umd.js
+++ /dev/null
@@ -1,460 +0,0 @@
-/**
- * Salesforce Lightning Server UMD Integration Example with Unsafe Tokens
- *
- * ⚠️ WARNING: TEMPORARY TESTING CONFIGURATION ⚠️
- * This example uses UNSAFE client credentials for temporary testing during
- * Salesforce security upgrade. This exposes credentials in browser environment.
- *
- * This example demonstrates how to use the Optave SDK Server UMD build (server.umd.js)
- * in Salesforce Lightning environments including Lightning Components, Lightning Web
- * Components (LWC), and Lightning Locker Service with UNSAFE token handling.
- *
- * IMPORTANT: Use the Server UMD build (server.umd.js) as specified for this integration
- */
-
-// For Salesforce Lightning - the SDK is loaded via static resource
-// Include server.umd.js as a static resource in your Salesforce org
-
-/**
- * Lightning Component (Aura) Integration with Server UMD Build
- *
- * In your Lightning Component:
- * 1. Add server.umd.js as a static resource
- * 2. Include it in your component using ltng:require
- * 3. Access the SDK via the global OptaveJavaScriptSDK
- */
-
-// Example Lightning Component Controller (.js)
-({
- doInit: function(component, event, helper) {
- console.log('🚀 Initializing Optave Server UMD SDK in Lightning Component...');
-
- // Access SDK from global scope (loaded via static resource)
- // In Salesforce Lightning Locker, use globalThis to access the UMD export
- const OptaveSDK = globalThis.OptaveJavaScriptSDK || window.OptaveJavaScriptSDK;
-
- if (!OptaveSDK) {
- console.error('❌ Optave Server UMD SDK not found. Ensure server.umd.js is loaded as static resource.');
- return;
- }
-
- // ⚠️ UNSAFE: Initialize SDK with client credentials (TEMPORARY FOR TESTING)
- const sdk = new OptaveSDK({
- // Example URLs - replace with your actual Optave endpoints
- websocketUrl: 'wss://your-optave-websocket-url.com/',
- authenticationUrl: 'https://your-optave-auth-url.com/auth/oauth2', // SDK automatically appends /token
- authTransport: 'query', // Server UMD uses query parameter method for authentication
-
- // ⚠️ WARNING: UNSAFE CLIENT CREDENTIALS - FOR TESTING ONLY
- // In production, these should come from secure Salesforce backend
- clientId: component.get("v.optaveClientId"), // From component attribute
- clientSecret: component.get("v.optaveClientSecret"), // From component attribute
-
- strictValidation: false // Use CSP-compliant validation for Lightning Locker
- });
-
- // Store SDK instance on component for later use
- component.set("v.optaveSdk", sdk);
-
- // Set up event handlers
- helper.setupOptaveEvents(component, sdk);
-
- console.log('✅ Optave Server UMD SDK initialized in Lightning Component');
- },
-
- sendCustomerMessage: function(component, event, helper) {
- const sdk = component.get("v.optaveSdk");
- const messageText = component.get("v.messageText");
-
- if (sdk && messageText) {
- helper.sendOptaveMessage(sdk, messageText);
- }
- }
-});
-
-// Example Lightning Component Helper (.js)
-({
- setupOptaveEvents: function(component, sdk) {
- // Set up SDK event handlers
- sdk.on('open', function() {
- console.log('✅ Lightning Server UMD: WebSocket connected');
- component.set("v.connectionStatus", "Connected");
- });
-
- sdk.on('message', function(payload) {
- try {
- const message = JSON.parse(payload);
- console.log('📨 Lightning Server UMD: Received message:', message.headers?.action);
-
- // Update component UI with response
- this.handleOptaveResponse(component, message);
- } catch (error) {
- console.error('Lightning Server UMD: Failed to parse message:', error);
- }
- }.bind(this));
-
- sdk.on('error', function(error) {
- console.error('❌ Lightning Server UMD: SDK error:', error.category, error.message);
- component.set("v.connectionStatus", "Error: " + error.message);
- });
-
- sdk.on('close', function(event) {
- console.log('🔌 Lightning Server UMD: Connection closed');
- component.set("v.connectionStatus", "Disconnected");
- });
- },
-
- sendOptaveMessage: function(sdk, messageText) {
- try {
- // Send customer interaction to Optave using Server UMD patterns
- sdk.interaction({
- request: {
- connections: {
- threadId: "salesforce-server-umd-" + Date.now()
- },
- context: {
- organizationId: $A.get("$Organization.Id") // Use Salesforce Org ID
- },
- scope: {
- conversations: [{
- participants: [{
- id: $A.get("$User.Id"),
- role: "user",
- displayName: $A.get("$User.FirstName") + " " + $A.get("$User.LastName")
- }],
- messages: [{
- id: "msg_" + Date.now(),
- participantId: $A.get("$User.Id"),
- content: messageText,
- timestamp: new Date().toISOString()
- }]
- }]
- }
- }
- });
-
- console.log('✅ Lightning Server UMD: Message sent to Optave');
- } catch (error) {
- console.error('❌ Lightning Server UMD: Failed to send message:', error);
- }
- },
-
- handleOptaveResponse: function(component, message) {
- // Handle different types of Optave responses
- switch (message.headers?.action) {
- case 'interaction':
- // Update chat UI with AI response
- const responses = component.get("v.chatResponses") || [];
- responses.push({
- id: message.headers.correlationId,
- content: message.payload?.response?.content || 'AI response received',
- timestamp: message.headers.timestamp,
- type: 'ai'
- });
- component.set("v.chatResponses", responses);
- break;
-
- case 'elevate':
- // Handle escalation to human agent
- component.set("v.isEscalated", true);
- this.showToast('Success', 'Escalated to human agent', 'success');
- break;
-
- default:
- console.log('Unhandled message type:', message.headers?.action);
- }
- },
-
- showToast: function(title, message, type) {
- const toastEvent = $A.get("e.force:showToast");
- if (toastEvent) {
- toastEvent.setParams({
- title: title,
- message: message,
- type: type
- });
- toastEvent.fire();
- }
- }
-});
-
-/**
- * Lightning Web Component (LWC) Integration with Server UMD
- *
- * For LWC, you need to:
- * 1. Import the Server UMD SDK as a static resource
- * 2. Load it dynamically in your component
- * 3. Use proper LWC patterns for event handling
- */
-
-// Example LWC JavaScript (.js)
-/*
-import { LightningElement, track, api } from 'lwc';
-import { loadScript } from 'lightning/platformResourceLoader';
-import OPTAVE_SERVER_SDK from '@salesforce/resourceUrl/OptaveServerSDK'; // Static resource
-
-export default class OptaveServerUmdComponent extends LightningElement {
- @track connectionStatus = 'Disconnected';
- @track messages = [];
- @api recordId; // Current record context
- @api optaveClientId; // ⚠️ UNSAFE: Client ID for testing
- @api optaveClientSecret; // ⚠️ UNSAFE: Client Secret for testing
-
- sdk;
-
- async connectedCallback() {
- try {
- // Load Optave Server UMD SDK from static resource
- await loadScript(this, OPTAVE_SERVER_SDK);
-
- // Initialize SDK
- await this.initializeOptaveServerSDK();
-
- } catch (error) {
- console.error('Failed to load Optave Server UMD SDK:', error);
- this.connectionStatus = 'Failed to load';
- }
- }
-
- async initializeOptaveServerSDK() {
- // Access Server UMD SDK from global scope - Lightning Locker uses globalThis
- const OptaveSDK = globalThis.OptaveJavaScriptSDK;
-
- if (!OptaveSDK) {
- throw new Error('Optave Server UMD SDK not found in global scope');
- }
-
- // ⚠️ UNSAFE: Initialize with client credentials for testing
- this.sdk = new OptaveSDK({
- // Example URLs - replace with your actual Optave endpoints
- websocketUrl: 'wss://your-optave-websocket-url.com/',
- authenticationUrl: 'https://your-optave-auth-url.com/auth/oauth2', // SDK automatically appends /token
- authTransport: 'query', // Server UMD uses query parameter method for authentication
-
- // ⚠️ WARNING: UNSAFE CLIENT CREDENTIALS - FOR TESTING ONLY
- clientId: this.optaveClientId,
- clientSecret: this.optaveClientSecret,
-
- strictValidation: false // CSP-compliant for Lightning Locker
- });
-
- // Set up event handlers
- this.setupEventHandlers();
-
- console.log('✅ LWC Server UMD: Optave SDK initialized');
- }
-
- setupEventHandlers() {
- this.sdk.on('open', () => {
- this.connectionStatus = 'Connected';
- console.log('✅ LWC Server UMD: WebSocket connected');
- });
-
- this.sdk.on('message', (payload) => {
- this.handleMessage(JSON.parse(payload));
- });
-
- this.sdk.on('error', (error) => {
- console.error('❌ LWC Server UMD: SDK error:', error);
- this.connectionStatus = `Error: ${error.message}`;
- });
-
- this.sdk.on('close', () => {
- this.connectionStatus = 'Disconnected';
- console.log('🔌 LWC Server UMD: Connection closed');
- });
- }
-
- handleMessage(message) {
- // Update reactive properties
- this.messages = [...this.messages, {
- id: message.headers?.correlationId || Date.now(),
- content: message.payload?.content || 'Message received',
- timestamp: new Date().toLocaleTimeString(),
- type: 'ai'
- }];
- }
-
- handleSendMessage(event) {
- const messageText = event.target.value;
- if (this.sdk && messageText) {
- this.sdk.interaction({
- request: {
- connections: {
- threadId: `lwc-server-umd-${this.recordId}-${Date.now()}`
- },
- context: {
- organizationId: 'your-org-id' // Should come from Salesforce context
- },
- scope: {
- conversations: [{
- participants: [{
- role: "user",
- displayName: "Salesforce User"
- }],
- messages: [{
- content: messageText,
- timestamp: new Date().toISOString()
- }]
- }]
- }
- }
- });
-
- // Clear input
- event.target.value = '';
- }
- }
-
- disconnectedCallback() {
- // Cleanup on component destroy
- if (this.sdk) {
- this.sdk.closeConnection();
- }
- }
-}
-*/
-
-/**
- * Salesforce-Specific Configuration Notes for Server UMD Build
- */
-
-// 1. Static Resource Setup
-// Upload server.umd.js as a static resource named "OptaveServerSDK"
-
-// 2. ⚠️ UNSAFE Apex Controller for Testing (TEMPORARY)
-/*
-public with sharing class OptaveServerUmdController {
-
- // ⚠️ WARNING: This exposes credentials - FOR TESTING ONLY
- @AuraEnabled(cacheable=false)
- public static Map getOptaveCredentials() {
- try {
- // ⚠️ UNSAFE: Return client credentials directly
- // In production, this should never expose credentials
- return new Map{
- 'clientId' => 'your-test-client-id',
- 'clientSecret' => 'your-test-client-secret',
- 'organizationId' => 'your-test-org-id'
- };
- } catch (Exception e) {
- throw new AuraHandledException('Failed to get credentials: ' + e.getMessage());
- }
- }
-
- // Future secure method placeholder
- @AuraEnabled(cacheable=false)
- public static String getOptaveSecureToken() {
- // TODO: Implement secure token retrieval
- // This will replace the unsafe credential exposure
- throw new AuraHandledException('Secure token method not yet implemented');
- }
-}
-*/
-
-// 3. Lightning Component Markup (.cmp)
-/*
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{!response.timestamp}
-
{!response.content}
-
-
-
-
-
-
-*/
-
-/**
- * Security Considerations for Salesforce Lightning Server UMD
- */
-
-// ✅ LIGHTNING LOCKER COMPLIANCE:
-// - Uses server.umd.js (includes full AJV validation)
-// - Accesses SDK via globalThis.OptaveJavaScriptSDK
-// - Uses query parameter auth transport for server UMD compatibility
-// - CSP-compliant configuration (strictValidation: false)
-
-// 🔧 CRITICAL CONFIGURATION NOTES:
-// - authenticationUrl can be base OAuth2 URL (SDK automatically appends /token)
-// - authTransport MUST be 'query' for server UMD builds
-// - Server UMD does not support 'subprotocol' authentication method
-// - WebSocket connections use query parameter: ?Authorization=token_value
-
-// ⚠️ WEBSOCKET SECURITY REQUIREMENTS:
-// - MUST use wss:// (secure WebSocket) protocol
-// - Lightning Locker blocks all ws:// connections
-// - No exceptions for .force.com domains
-// - SSL/TLS encryption required for all WebSocket traffic
-
-// ⚠️ UNSAFE AUTHENTICATION (TEMPORARY):
-// - Client credentials exposed in browser environment
-// - Only for testing during security upgrade process
-// - Clear migration path to secure token-based auth
-// - All code marked with warnings
-
-// ✅ DATA GOVERNANCE:
-// - All data flows through Salesforce-controlled components
-// - Audit trail via Salesforce logs
-// - User permissions handled by Salesforce
-// - Organization isolation maintained
-
-// 🚨 MIGRATION TO SECURE IMPLEMENTATION:
-// Replace unsafe credentials with:
-// - Server-side token generation via Apex
-// - Named credentials for external callouts
-// - Secure token refresh mechanisms
-// - No client-side credential exposure
-
-console.log('📚 Salesforce Lightning Server UMD Integration Guide Loaded');
-console.log(' ⚠️ WARNING: Using UNSAFE client credentials for testing');
-console.log(' Use server.umd.js as static resource');
-console.log(' Access via: globalThis.OptaveJavaScriptSDK');
-console.log(' 🚨 MIGRATE to secure token-based auth ASAP');
-
-/**
- * Migration Guide: From Unsafe to Secure
- *
- * CURRENT (UNSAFE):
- * clientId: 'direct-credential',
- * clientSecret: 'direct-credential'
- *
- * SECURE TARGET:
- * tokenProvider: async () => {
- * const result = await getOptaveSecureToken();
- * return result;
- * }
- *
- * Steps:
- * 1. Implement secure Apex token method
- * 2. Update all components to use tokenProvider
- * 3. Remove all client credential references
- * 4. Deploy and test secure implementation
- * 5. Delete this unsafe integration file
- */
\ No newline at end of file
diff --git a/sdks/javascript/integration/server-umd-integration.js b/sdks/javascript/integration/server-umd-integration.js
new file mode 100644
index 0000000..d3ffed1
--- /dev/null
+++ b/sdks/javascript/integration/server-umd-integration.js
@@ -0,0 +1,196 @@
+/**
+ * Server UMD Integration Example
+ *
+ * This example demonstrates how to use the Optave SDK Server UMD build (server.umd.js)
+ * in Node.js environments with CommonJS (require()) or mixed module systems.
+ *
+ * Server UMD is designed for maximum compatibility across Node.js environments including:
+ * - CommonJS-only Node.js applications
+ * - Mixed ESM/CommonJS environments
+ * - Legacy Node.js versions
+ * - Applications requiring require() syntax
+ */
+
+// CommonJS require syntax
+const process = require('process');
+const OptaveJavaScriptSDK = require('../dist/server.umd.js');
+
+/**
+ * Server UMD Configuration
+ * Uses CSP-safe validation (no AJV) for maximum compatibility
+ */
+const optaveClient = new OptaveJavaScriptSDK({
+ websocketUrl: process.env.OPTAVE__WEBSOCKET_URL,
+
+ // Server-side authentication with client credentials
+ clientId: process.env.OPTAVE__CLIENT_ID,
+ clientSecret: process.env.OPTAVE__CLIENT_SECRET,
+
+ // Server can use either authentication method
+ authTransport: 'subprotocol', // or 'query' based on your needs
+
+ strictValidation: process.env.NODE_ENV === 'development',
+});
+
+// Test function
+async function sendTestMessage() {
+ try {
+ const threadId = `server-umd-thread-${Date.now()}`;
+
+ await optaveClient.interaction({
+ request: {
+ connections: {
+ threadId,
+ },
+ context: {
+ organizationId: process.env.OPTAVE__ORGANIZATION_ID,
+ },
+ scope: {
+ conversations: [{
+ conversationId: `conv-${Date.now()}`,
+ participants: [{
+ participantId: 'user_1',
+ role: 'user',
+ displayName: 'Server UMD User',
+ }],
+ messages: [{
+ participantId: 'user_1',
+ content: 'Test message from Server UMD build',
+ timestamp: new Date().toISOString(),
+ }],
+ metadata: {},
+ }],
+ },
+ },
+ });
+
+ console.log('✅ Server UMD: Test message sent successfully');
+ } catch (error) {
+ console.error('❌ Server UMD: Failed to send test message:', error);
+ }
+}
+
+// Event handlers
+optaveClient.on('open', () => {
+ console.log('✅ Server UMD: WebSocket connection established');
+ sendTestMessage();
+});
+
+optaveClient.on('message', (payload) => {
+ try {
+ const message = JSON.parse(payload);
+ console.log('📨 Server UMD: Received message:', {
+ action: message.headers && message.headers.action,
+ correlationId: message.headers && message.headers.correlationId,
+ });
+ } catch (error) {
+ console.error('Server UMD: Failed to parse message:', error);
+ }
+});
+
+optaveClient.on('error', (error) => {
+ console.error('❌ Server UMD: SDK error:', {
+ category: error.category,
+ code: error.code,
+ message: error.message,
+ });
+});
+
+optaveClient.on('close', (event) => {
+ console.log('🔌 Server UMD: Connection closed:', {
+ code: event.code,
+ reason: event.reason,
+ });
+});
+
+// Connect function
+async function connect() {
+ try {
+ await optaveClient.openConnection();
+ } catch (error) {
+ console.error('❌ Server UMD: Failed to connect:', error);
+ }
+}
+
+// Cleanup function
+function cleanup() {
+ optaveClient.closeConnection();
+ console.log('Server UMD: Connection cleanup completed');
+}
+
+// Process event handlers for graceful shutdown
+process.on('SIGINT', () => {
+ console.log('\nReceived SIGINT, gracefully shutting down...');
+ cleanup();
+ process.exit(0);
+});
+
+process.on('SIGTERM', () => {
+ console.log('Received SIGTERM, gracefully shutting down...');
+ cleanup();
+ process.exit(0);
+});
+
+// Auto-connect for testing (uncomment if desired)
+// connect();
+
+// CommonJS exports
+module.exports = {
+ optaveClient,
+ connect,
+ cleanup,
+};
+
+/**
+ * Server UMD Integration Notes:
+ *
+ * ✅ USE CASES:
+ * - CommonJS-only Node.js applications (require() syntax)
+ * - Mixed ESM/CommonJS environments
+ * - Legacy Node.js applications without ES module support
+ * - Node.js environments requiring maximum compatibility
+ * - Applications using older Node.js versions (12+)
+ *
+ * ✅ FEATURES:
+ * - CommonJS module format (works with require())
+ * - CSP-safe validation (no AJV) for maximum compatibility
+ * - Direct client credentials authentication
+ * - Node.js-specific APIs (crypto, uuid, ws)
+ * - Process event handling for graceful shutdown
+ * - Compatible with both CommonJS and ES module loaders
+ *
+ * ✅ VALIDATION STRATEGY:
+ * - Uses lightweight, CSP-safe validation (same as browser builds)
+ * - Does NOT include AJV (unlike server ESM)
+ * - Validates required fields and basic payload structure
+ * - Optimized for compatibility over strict validation
+ * - If you need full AJV validation, use server ESM build instead
+ *
+ * ✅ ENVIRONMENT VARIABLES:
+ * - OPTAVE__WEBSOCKET_URL: WebSocket endpoint URL
+ * - OPTAVE__CLIENT_ID: Your client ID
+ * - OPTAVE__CLIENT_SECRET: Your client secret
+ * - OPTAVE__ORGANIZATION_ID: Your organization ID
+ * - NODE_ENV: Environment (development/production)
+ *
+ * ❌ NOT SUITABLE FOR:
+ * - Browser environments (security risk with client secrets)
+ * - Applications requiring full AJV schema validation (use server ESM instead)
+ * - Modern Node.js apps preferring import/export syntax (use server ESM instead)
+ *
+ * 📋 COMPARISON: Server UMD vs Server ESM
+ *
+ * Server UMD (server.umd.js):
+ * - Module: UMD (CommonJS compatible)
+ * - Syntax: require() / module.exports
+ * - Validation: CSP-safe, lightweight (no AJV)
+ * - Size: ~49KB (uncompressed)
+ * - Use when: Maximum compatibility needed, CommonJS required
+ *
+ * Server ESM (server.mjs):
+ * - Module: ES Module
+ * - Syntax: import / export
+ * - Validation: Full AJV schema validation
+ * - Size: ~164KB (includes AJV)
+ * - Use when: Modern Node.js, strict validation needed
+ */
diff --git a/sdks/javascript/integration/test-environment.js b/sdks/javascript/integration/test-environment.js
deleted file mode 100644
index cb37dc5..0000000
--- a/sdks/javascript/integration/test-environment.js
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/env node
-
-/*
- * Copyright (c) 2025 Optave AI Solutions Inc.
- * All rights reserved.
- *
- * This software and associated documentation files (the "Software") are the
- * proprietary and confidential information of Optave AI Solutions Inc.
- * Unauthorized copying, modification, distribution, or use of this Software
- * is strictly prohibited without express written permission.
- */
-
-/**
- * Test Environment Setup
- * Configures test environments for all SDKs with proper environment variable management
- */
-
-import fs from 'fs';
-import path from 'path';
-import { fileURLToPath } from 'url';
-
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-
-class TestEnvironment {
- constructor() {
- this.envTemplate = {
- // Optave API Configuration
- OPTAVE__AUTH_URL: 'https://auth.optave.example.com',
- OPTAVE__WEBSOCKET_URL: 'wss://api.optave.example.com',
- OPTAVE__CLIENT_ID: 'test-client-id',
- OPTAVE__CLIENT_SECRET: 'test-client-secret',
- OPTAVE__ORGANIZATION_ID: 'test-org-id',
- OPTAVE__TENANT_ID: 'test-tenant-id',
-
- // Test Configuration
- NODE_ENV: 'test',
- VITEST_ENV: 'test',
- TEST_TIMEOUT: '10000',
-
- // Integration Test Flags
- SKIP_INTEGRATION_TESTS: 'false',
- INTEGRATION_TEST_MODE: 'mock',
-
- // Logging Configuration
- LOG_LEVEL: 'warn',
- DEBUG: 'false'
- };
- }
-
- async setupEnvironment(options = {}) {
- const { force = false, verbose = false } = options;
-
- console.log('🧪 Setting up test environment...');
-
- // Create environment files for each SDK
- await this.createSdkEnvironmentFiles(force, verbose);
-
- // Create global test environment file
- await this.createGlobalEnvironmentFile(force, verbose);
-
- // Setup test fixtures
- await this.setupTestFixtures(verbose);
-
- console.log('✅ Test environment setup completed');
- }
-
- async createSdkEnvironmentFiles(force, verbose) {
- const sdksDir = path.join(__dirname, '../../sdks');
-
- if (!fs.existsSync(sdksDir)) {
- if (verbose) console.log('⚠️ SDKs directory not found, skipping SDK environment setup');
- return;
- }
-
- const sdkDirs = fs.readdirSync(sdksDir, { withFileTypes: true })
- .filter(dirent => dirent.isDirectory())
- .map(dirent => dirent.name);
-
- for (const sdk of sdkDirs) {
- const sdkPath = path.join(sdksDir, sdk);
- const envPath = path.join(sdkPath, '.env.test');
-
- if (fs.existsSync(envPath) && !force) {
- if (verbose) console.log(`⏭️ Skipping ${sdk} - .env.test already exists`);
- continue;
- }
-
- // Create SDK-specific environment file
- const envContent = this.generateEnvContent(sdk);
- fs.writeFileSync(envPath, envContent);
-
- if (verbose) console.log(`✅ Created .env.test for ${sdk} SDK`);
- }
- }
-
- async createGlobalEnvironmentFile(force, verbose) {
- const globalEnvPath = path.join(__dirname, '../..', '.env.test');
-
- if (fs.existsSync(globalEnvPath) && !force) {
- if (verbose) console.log('⏭️ Skipping global .env.test - already exists');
- return;
- }
-
- const envContent = this.generateEnvContent('global');
- fs.writeFileSync(globalEnvPath, envContent);
-
- if (verbose) console.log('✅ Created global .env.test file');
- }
-
- generateEnvContent(context) {
- const header = `# Test Environment Configuration for ${context}
-# Generated automatically - modify template in utils/tests/test-environment.js
-#
-# This file contains test credentials that are safe for development/testing.
-# Do NOT use these values in production!
-
-`;
-
- const envVars = Object.entries(this.envTemplate)
- .map(([key, value]) => `${key}=${value}`)
- .join('\n');
-
- return header + envVars + '\n';
- }
-
- async setupTestFixtures(verbose) {
- const fixturesDir = path.join(__dirname, 'fixtures');
-
- if (!fs.existsSync(fixturesDir)) {
- fs.mkdirSync(fixturesDir, { recursive: true });
- }
-
- // Create mock server configuration
- const mockServerConfig = {
- websocket: {
- port: 8080,
- mockResponses: true,
- delays: {
- connection: 100,
- message: 50
- }
- },
- auth: {
- port: 8081,
- mockTokens: true,
- tokenExpiry: 3600
- }
- };
-
- fs.writeFileSync(
- path.join(fixturesDir, 'mock-server-config.json'),
- JSON.stringify(mockServerConfig, null, 2)
- );
-
- // Create test data fixtures
- const testPayloads = {
- validInteraction: {
- session: {
- sessionId: "test-session-123"
- },
- request: {
- connections: {
- threadId: "test-thread-456"
- },
- context: {
- organizationId: "test-org-id"
- }
- }
- }
- };
-
- fs.writeFileSync(
- path.join(fixturesDir, 'test-payloads.json'),
- JSON.stringify(testPayloads, null, 2)
- );
-
- if (verbose) console.log('✅ Created test fixtures');
- }
-}
-
-// CLI interface
-async function main() {
- const args = process.argv.slice(2);
- const options = {
- force: args.includes('--force'),
- verbose: args.includes('--verbose')
- };
-
- const testEnv = new TestEnvironment();
-
- try {
- await testEnv.setupEnvironment(options);
- process.exit(0);
- } catch (error) {
- console.error('💥 Test environment setup failed:', error);
- process.exit(1);
- }
-}
-
-// Run if called directly
-if (import.meta.url === new URL(process.argv[1], 'file:').href) {
- main();
-}
-
-export { TestEnvironment };
\ No newline at end of file
diff --git a/sdks/javascript/package.json b/sdks/javascript/package.json
index 54adb3c..9e6693a 100644
--- a/sdks/javascript/package.json
+++ b/sdks/javascript/package.json
@@ -1,6 +1,6 @@
{
"name": "@optave/client-sdk",
- "version": "3.2.3",
+ "version": "3.6.0",
"description": "Optave client SDK (browser + Node)",
"private": false,
"packageManager": "npm@10.8.1",
@@ -71,8 +71,8 @@
"test:ui": "vitest --ui",
"test:server": "vitest run --config vitest.config.server.js",
"test:browser": "vitest run --config vitest.config.browser.js",
- "test:umd-server": "cross-env SDK_BUILD=umd-server vitest run --config vitest.config.umd.js",
- "test:umd-browser": "cross-env SDK_BUILD=umd-browser vitest run --config vitest.config.umd.js",
+ "test:umd-server": "vitest run --config vitest.config.umd-server.js",
+ "test:umd-browser": "vitest run --config vitest.config.umd-browser.js",
"test:all-builds": "npm run test:server && npm run test:browser && npm run test:umd-server && npm run test:umd-browser",
"test:all-builds:csp": "npm run test:all-builds && npm run check:csp",
"test:builds-parallel": "npm run test:server & npm run test:browser & npm run test:umd-server & npm run test:umd-browser & wait",
@@ -84,7 +84,7 @@
"size:report:sarif": "node scripts/dev/bundle-size-reporter.js --format=sarif",
"size:compare": "node scripts/dev/bundle-size-reporter.js --baseline=reports/baseline-sizes.json --format=github-comment",
"size:sarif": "node scripts/dev/bundle-size-reporter.js --baseline=reports/baseline-sizes.json --format=sarif",
- "size:check": "npm run size && npm run size:compare",
+ "size:check": "npm run size:compare",
"analyze": "npm run analyze:server-umd",
"analyze:server-umd": "cross-env ANALYZE_OPEN=false ANALYZE_MODE=static webpack --config webpack.analyzer.config.js",
"analyze:browser-umd": "cross-env ANALYZE_OPEN=false ANALYZE_MODE=static ANALYZE_PORT=8889 webpack --config webpack.analyzer.config.js --env buildTarget=browser",
@@ -110,35 +110,52 @@
"spec:types": "node scripts/generation/generate-types.cjs",
"spec:validators": "node scripts/generation/generate-validators.cjs",
"spec:constants": "node scripts/generation/generate-constants.cjs",
- "spec:version": "node scripts/generation/sync-package-version.cjs",
+ "spec:docs": "node scripts/generation/sync-docs-version.cjs",
"spec:examples": "node scripts/generation/generate-examples.js",
- "spec:generate": "npm run spec:version && npm run spec:types && npm run spec:validators && npm run spec:constants",
+ "spec:generate": "npm run spec:types && npm run spec:validators && npm run spec:constants && npm run spec:examples && npm run spec:docs",
"spec:generate:examples": "npm run spec:examples",
"spec:drift-guard": "node scripts/dev/validation/schema-drift-guard.js",
"assert:umd-bundles": "node scripts/dev/validation/assert-umd-bundles.cjs",
"governance:check": "node scripts/dev/validation/governance-check.js",
- "governance:manifest": "node scripts/generation/generate-governance-manifest.js"
+ "governance:manifest": "node scripts/generation/generate-governance-manifest.js",
+ "lint": "eslint .",
+ "lint:fix": "eslint . --fix",
+ "lint:report": "eslint . --format json --output-file reports/eslint-report.json"
},
"author": "",
"dependencies": {
- "uuid": "^11.0.3",
- "ws": "^8.18.0"
+ "uuid": "^14.0.2",
+ "ws": "^8.20.0"
},
"devDependencies": {
- "@size-limit/preset-big-lib": "^11.2.0",
- "@vitest/ui": "^3.2.4",
- "ajv": "^8.17.1",
+ "@semantic-release/changelog": "^6.0.3",
+ "@semantic-release/commit-analyzer": "^13.0.1",
+ "@semantic-release/git": "^10.0.1",
+ "@semantic-release/github": "^12.0.9",
+ "@semantic-release/npm": "^13.1.1",
+ "@semantic-release/release-notes-generator": "^14.1.0",
+ "@size-limit/preset-big-lib": "^12.0.0",
+ "@vitest/ui": "^4.1.0",
+ "ajv": "^8.18.0",
"ajv-formats": "^3.0.1",
+ "conventional-changelog-conventionalcommits": "^9.1.0",
"cross-env": "^10.1.0",
- "jsdom": "^27.0.0",
- "size-limit": "^11.2.0",
- "tsup": "^8.0.1",
+ "eslint": "^8.57.1",
+ "eslint-config-airbnb-base": "^15.0.0",
+ "eslint-plugin-import": "^2.31.0",
+ "globals": "^17.7.0",
+ "jsdom": "^27.4.0",
+ "semantic-release": "^25.0.2",
+ "size-limit": "^12.0.0",
+ "terser-webpack-plugin": "^5.3.17",
+ "tsup": "^8.5.1",
"typescript": "^5.9.3",
- "vitest": "^3.2.4",
- "webpack": "^5.102.1",
- "webpack-bundle-analyzer": "^4.10.2",
+ "vite": "^7.3.5",
+ "vitest": "^4.1.0",
+ "webpack": "^5.108.0",
+ "webpack-bundle-analyzer": "^5.2.0",
"webpack-cli": "^6.0.1",
- "yaml": "^2.8.1"
+ "yaml": "^2.8.3"
},
"publishConfig": {
"access": "public"
diff --git a/sdks/javascript/runtime/core/build-targets.js b/sdks/javascript/runtime/core/build-targets.js
index a1c9ab9..4fee4cc 100644
--- a/sdks/javascript/runtime/core/build-targets.js
+++ b/sdks/javascript/runtime/core/build-targets.js
@@ -11,17 +11,17 @@
* @enum {string}
*/
export const BUILD_TARGETS = {
- /** Browser ESM build (browser.mjs) - for modern ES modules in browsers */
- BROWSER_ESM: 'browser-esm',
+ /** Browser ESM build (browser.mjs) - for modern ES modules in browsers */
+ BROWSER_ESM: 'browser-esm',
- /** Server ESM build (server.mjs) - for Node.js ES modules */
- SERVER_ESM: 'server-esm',
+ /** Server ESM build (server.mjs) - for Node.js ES modules */
+ SERVER_ESM: 'server-esm',
- /** Browser UMD build (browser.umd.js) - for browsers with UMD wrapper */
- BROWSER_UMD: 'browser-umd',
+ /** Browser UMD build (browser.umd.js) - for Salesforce/browsers with UMD wrapper */
+ BROWSER_UMD: 'browser-umd',
- /** Server UMD build (server.umd.js) - for Salesforce/constrained environments */
- SERVER_UMD: 'server-umd'
+ /** Server UMD build (server.umd.js) - for Node.js CommonJS environments with UMD wrapper */
+ SERVER_UMD: 'server-umd',
};
/**
@@ -30,8 +30,8 @@ export const BUILD_TARGETS = {
* @readonly
*/
export const LEGACY_BUILD_TARGET_MAP = {
- 'browser': BUILD_TARGETS.BROWSER_ESM,
- 'server': BUILD_TARGETS.SERVER_ESM
+ browser: BUILD_TARGETS.BROWSER_ESM,
+ server: BUILD_TARGETS.SERVER_ESM,
};
/**
@@ -39,100 +39,100 @@ export const LEGACY_BUILD_TARGET_MAP = {
* @readonly
*/
export const BUILD_TARGET_CATEGORIES = {
- /** All browser-targeted builds (including server UMD which runs in browser environments like Salesforce) */
- BROWSER: [BUILD_TARGETS.BROWSER_ESM, BUILD_TARGETS.BROWSER_UMD, BUILD_TARGETS.SERVER_UMD],
+ /** All browser-targeted builds */
+ BROWSER: [BUILD_TARGETS.BROWSER_ESM, BUILD_TARGETS.BROWSER_UMD],
- /** All server-targeted builds (only server ESM runs in pure Node.js environments) */
- SERVER: [BUILD_TARGETS.SERVER_ESM],
+ /** All server-targeted builds (Node.js environments) */
+ SERVER: [BUILD_TARGETS.SERVER_ESM, BUILD_TARGETS.SERVER_UMD],
- /** All UMD builds */
- UMD: [BUILD_TARGETS.BROWSER_UMD, BUILD_TARGETS.SERVER_UMD],
+ /** All UMD builds */
+ UMD: [BUILD_TARGETS.BROWSER_UMD, BUILD_TARGETS.SERVER_UMD],
- /** All ESM builds */
- ESM: [BUILD_TARGETS.BROWSER_ESM, BUILD_TARGETS.SERVER_ESM]
+ /** All ESM builds */
+ ESM: [BUILD_TARGETS.BROWSER_ESM, BUILD_TARGETS.SERVER_ESM],
};
/**
* Utility functions for build target operations
*/
export const BuildTargetUtils = {
- /**
+ /**
* Check if a build target is valid
* @param {string} target - The build target to validate
* @returns {boolean} True if valid
*/
- isValid(target) {
- return Object.values(BUILD_TARGETS).includes(target) ||
- Object.keys(LEGACY_BUILD_TARGET_MAP).includes(target);
- },
+ isValid(target) {
+ return Object.values(BUILD_TARGETS).includes(target)
+ || Object.keys(LEGACY_BUILD_TARGET_MAP).includes(target);
+ },
- /**
+ /**
* Normalize a build target (handles legacy values)
* @param {string} target - The build target to normalize
* @returns {string} Normalized build target
*/
- normalize(target) {
- if (LEGACY_BUILD_TARGET_MAP[target]) {
- return LEGACY_BUILD_TARGET_MAP[target];
- }
- return Object.values(BUILD_TARGETS).includes(target) ? target : 'unknown';
- },
-
- /**
+ normalize(target) {
+ if (LEGACY_BUILD_TARGET_MAP[target]) {
+ return LEGACY_BUILD_TARGET_MAP[target];
+ }
+ return Object.values(BUILD_TARGETS).includes(target) ? target : 'unknown';
+ },
+
+ /**
* Check if build target is browser-focused
* @param {string} target - The build target to check
* @returns {boolean} True if browser build
*/
- isBrowser(target) {
- const normalized = this.normalize(target);
- return BUILD_TARGET_CATEGORIES.BROWSER.includes(normalized);
- },
+ isBrowser(target) {
+ const normalized = this.normalize(target);
+ return BUILD_TARGET_CATEGORIES.BROWSER.includes(normalized);
+ },
- /**
+ /**
* Check if build target is server-focused
* @param {string} target - The build target to check
* @returns {boolean} True if server build
*/
- isServer(target) {
- const normalized = this.normalize(target);
- return BUILD_TARGET_CATEGORIES.SERVER.includes(normalized);
- },
+ isServer(target) {
+ const normalized = this.normalize(target);
+ return BUILD_TARGET_CATEGORIES.SERVER.includes(normalized);
+ },
- /**
+ /**
* Check if build target is UMD format
* @param {string} target - The build target to check
* @returns {boolean} True if UMD build
*/
- isUMD(target) {
- const normalized = this.normalize(target);
- return BUILD_TARGET_CATEGORIES.UMD.includes(normalized);
- },
+ isUMD(target) {
+ const normalized = this.normalize(target);
+ return BUILD_TARGET_CATEGORIES.UMD.includes(normalized);
+ },
- /**
+ /**
* Check if build target is ESM format
* @param {string} target - The build target to check
* @returns {boolean} True if ESM build
*/
- isESM(target) {
- const normalized = this.normalize(target);
- return BUILD_TARGET_CATEGORIES.ESM.includes(normalized);
- },
+ isESM(target) {
+ const normalized = this.normalize(target);
+ return BUILD_TARGET_CATEGORIES.ESM.includes(normalized);
+ },
- /**
+ /**
* Get build target info for debugging
* @param {string} target - The build target to analyze
* @returns {object} Build target information
*/
- getInfo(target) {
- const normalized = this.normalize(target);
- return {
- original: target,
- normalized,
- valid: this.isValid(target),
- isBrowser: this.isBrowser(target),
- isServer: this.isServer(target),
- isUMD: this.isUMD(target),
- isESM: this.isESM(target)
- };
- }
-};
\ No newline at end of file
+ getInfo(target) {
+ const normalized = this.normalize(target);
+ return {
+ original: target,
+ normalized,
+ valid: this.isValid(target),
+ isBrowser: this.isBrowser(target),
+ isServer: this.isServer(target),
+ isUMD: this.isUMD(target),
+ isESM: this.isESM(target),
+ };
+ },
+};
diff --git a/sdks/javascript/runtime/core/constants.js b/sdks/javascript/runtime/core/constants.js
index 47c6451..ea556a0 100644
--- a/sdks/javascript/runtime/core/constants.js
+++ b/sdks/javascript/runtime/core/constants.js
@@ -10,33 +10,34 @@
// SDK Constants (imported from generated file based on AsyncAPI spec)
import { SPEC_VERSION, SCHEMA_REF } from '../../generated/constants.js';
+
export { SPEC_VERSION, SCHEMA_REF };
// Error categories
export const ErrorCategory = {
- AUTHENTICATION: "AUTHENTICATION",
- ORCHESTRATOR: "ORCHESTRATOR",
- VALIDATION: "VALIDATION",
- WEBSOCKET: "WEBSOCKET"
+ AUTHENTICATION: 'AUTHENTICATION',
+ ORCHESTRATOR: 'ORCHESTRATOR',
+ VALIDATION: 'VALIDATION',
+ WEBSOCKET: 'WEBSOCKET',
};
// Legacy events (for backward compatibility)
export const LegacyEvents = Object.freeze({
- MESSAGE: 'message',
- ERROR: 'error'
+ MESSAGE: 'message',
+ ERROR: 'error',
});
// SDK Events
export const EVENTS = Object.freeze({
- CONNECTION_OPEN: 'connection:open',
- CONNECTION_CLOSE: 'connection:close',
- CONNECTION_ERROR: 'connection:error',
- MESSAGE_RECEIVED: 'message:received',
- MESSAGE_SENT: 'message:sent',
- ERROR: 'error',
- RESPONSE: 'response',
- LEGACY_ERROR: 'error', // Both ERROR and LEGACY_ERROR map to 'error' for compatibility
- LEGACY_MESSAGE: 'message' // Legacy message handling for backward compatibility
+ CONNECTION_OPEN: 'connection:open',
+ CONNECTION_CLOSE: 'connection:close',
+ CONNECTION_ERROR: 'connection:error',
+ MESSAGE_RECEIVED: 'message:received',
+ MESSAGE_SENT: 'message:sent',
+ ERROR: 'error',
+ RESPONSE: 'response',
+ LEGACY_ERROR: 'error', // Both ERROR and LEGACY_ERROR map to 'error' for compatibility
+ LEGACY_MESSAGE: 'message', // Legacy message handling for backward compatibility
});
// New events (to migrate to)
@@ -47,15 +48,16 @@ export const InboundEvents = Object.freeze({
// Allowed SDK actions (as Set for has() method)
export const ALLOWED_ACTIONS = new Set([
- 'adjust',
- 'elevate',
- 'interaction',
- 'reception',
- 'customerInteraction', // deprecated alias
- 'summarize',
- 'translate',
- 'recommend',
- 'insights'
+ 'adjust',
+ 'elevate',
+ 'interaction',
+ 'assistant',
+ 'reception',
+ 'customerInteraction', // deprecated alias
+ 'summarize',
+ 'translate',
+ 'recommend',
+ 'insights',
]);
// Default payload size limit (128KB)
@@ -67,16 +69,16 @@ export const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
// Default configuration object - exported as named export to avoid issues with tree-shaking default exports
export const CONSTANTS = {
- SPEC_VERSION,
- SCHEMA_REF,
- MAX_PAYLOAD_SIZE,
- MAX_PAYLOAD_SIZE_KB,
- DEFAULT_REQUEST_TIMEOUT_MS,
- ErrorCategory,
- LegacyEvents,
- EVENTS,
- InboundEvents,
- ALLOWED_ACTIONS
+ SPEC_VERSION,
+ SCHEMA_REF,
+ MAX_PAYLOAD_SIZE,
+ MAX_PAYLOAD_SIZE_KB,
+ DEFAULT_REQUEST_TIMEOUT_MS,
+ ErrorCategory,
+ LegacyEvents,
+ EVENTS,
+ InboundEvents,
+ ALLOWED_ACTIONS,
};
-export default CONSTANTS;
\ No newline at end of file
+export default CONSTANTS;
diff --git a/sdks/javascript/runtime/core/errors.js b/sdks/javascript/runtime/core/errors.js
index 13ddd35..9d5393b 100644
--- a/sdks/javascript/runtime/core/errors.js
+++ b/sdks/javascript/runtime/core/errors.js
@@ -8,7 +8,9 @@ class OptaveError extends Error {
* @param {string} params.message
* @param {any} [params.details]
*/
- constructor({ category, code, message, details }) {
+ constructor({
+ category, code, message, details,
+ }) {
super(message);
this.name = 'OptaveError';
this.category = category || 'UNKNOWN';
@@ -31,16 +33,24 @@ function makeStructuredError(raw) {
return new OptaveError({ category: 'UNKNOWN', code: 'STRING_ERROR', message: raw });
}
if (raw && raw.name === 'AjvValidationError') {
- return new OptaveError({ category: 'VALIDATION', code: 'SCHEMA_VALIDATION', message: raw.message, details: raw.errors });
+ return new OptaveError({
+ category: 'VALIDATION', code: 'SCHEMA_VALIDATION', message: raw.message, details: raw.errors,
+ });
}
if (raw && raw.isAuthError) {
- return new OptaveError({ category: 'AUTHENTICATION', code: raw.code || 'AUTH_ERROR', message: raw.message || 'Authentication error', details: raw });
+ return new OptaveError({
+ category: 'AUTHENTICATION', code: raw.code || 'AUTH_ERROR', message: raw.message || 'Authentication error', details: raw,
+ });
}
if (raw && raw.isWsError) {
- return new OptaveError({ category: 'WEBSOCKET', code: raw.code || 'WS_ERROR', message: raw.message || 'WebSocket error', details: raw });
+ return new OptaveError({
+ category: 'WEBSOCKET', code: raw.code || 'WS_ERROR', message: raw.message || 'WebSocket error', details: raw,
+ });
}
// Default
- return new OptaveError({ category: 'UNKNOWN', code: 'UNCLASSIFIED', message: (raw && raw.message) || String(raw !== null && raw !== undefined ? raw : 'Unknown error'), details: raw });
+ return new OptaveError({
+ category: 'UNKNOWN', code: 'UNCLASSIFIED', message: (raw && raw.message) || String(raw !== null && raw !== undefined ? raw : 'Unknown error'), details: raw,
+ });
}
-export { OptaveError, makeStructuredError };
\ No newline at end of file
+export { OptaveError, makeStructuredError };
diff --git a/sdks/javascript/runtime/core/index.ts b/sdks/javascript/runtime/core/index.ts
index 5f929c7..0600c2f 100644
--- a/sdks/javascript/runtime/core/index.ts
+++ b/sdks/javascript/runtime/core/index.ts
@@ -4,8 +4,23 @@
// Export TypeScript types and interfaces
export * from './types';
-// Manual export for generated config types to avoid broken import
-export type AuthTransport = 'subprotocol' | 'query';
+// Re-export SDK class type (implementation will be in JavaScript)
+export { OptaveJavaScriptSDK } from './types';
+
+// Import from generated config so they are usable in this module's scope
+import {
+ buildWebSocketUrl,
+ buildAuthUrl,
+ SERVER_ENVIRONMENTS,
+ OAUTH2_TOKEN_URL,
+} from '../../generated/connection-config';
+import type { AuthTransport } from '../../generated/connection-config';
+
+// Re-export everything from generated config — single source of truth
+export { buildWebSocketUrl, buildAuthUrl, SERVER_ENVIRONMENTS, OAUTH2_TOKEN_URL };
+export type { AuthTransport } from '../../generated/connection-config';
+
+// Extends the generated interface with SDK-specific runtime field not present in the spec
export interface GeneratedClientConfig {
websocketUrl: string;
authUrl: string;
@@ -13,10 +28,10 @@ export interface GeneratedClientConfig {
OptaveTraceChatSessionId?: string;
}
-// Pure function-based approach for better tree-shaking
+// Delegates to the canonical URL builders so defaults always match the generated config
export const createDefaultConfig = (): GeneratedClientConfig => ({
- websocketUrl: 'wss://default.oco.optave.tech/',
- authUrl: 'https://default.oco.optave.tech/auth/oauth2/',
+ websocketUrl: buildWebSocketUrl(),
+ authUrl: buildAuthUrl(),
supportedAuthTransports: ['subprotocol', 'query'],
OptaveTraceChatSessionId: undefined
});
@@ -24,34 +39,3 @@ export const createDefaultConfig = (): GeneratedClientConfig => ({
// Keep constant export for backwards compatibility
export const DEFAULT_CONFIG: GeneratedClientConfig = createDefaultConfig();
-// Pure object for environments - frozen for immutability
-export const SERVER_ENVIRONMENTS = {
- websocket: {
- wsEnv: {
- default: 'default',
- examples: ['default', 'staging', 'production']
- }
- },
- auth: {
- authEnv: {
- default: 'default',
- examples: ['default', 'staging', 'production']
- }
- }
-} as const;
-
-export function buildWebSocketUrl(environment?: string): string {
- const env = environment || 'default';
- return `wss://${env}.oco.optave.tech/`;
-}
-
-export function buildAuthUrl(environment?: string): string {
- const env = environment || 'default';
- return `https://${env}.oco.optave.tech/auth/oauth2/`;
-}
-
-// Re-export SDK class type (implementation will be in JavaScript)
-export { OptaveJavaScriptSDK } from './types';
-
-// Re-export OAuth2 token URL from generated config
-export { OAUTH2_TOKEN_URL } from '../../generated/connection-config';
\ No newline at end of file
diff --git a/sdks/javascript/runtime/core/main.js b/sdks/javascript/runtime/core/main.js
index ca10f50..3c260a9 100644
--- a/sdks/javascript/runtime/core/main.js
+++ b/sdks/javascript/runtime/core/main.js
@@ -12,7 +12,8 @@ import {
validateMessageEnvelope as validateBrowserMessageEnvelope,
} from '../platform/browser/validators.js';
-import CONSTANTS, {
+import {
+ CONSTANTS,
SPEC_VERSION,
SCHEMA_REF,
ErrorCategory,
@@ -22,9 +23,10 @@ import CONSTANTS, {
ALLOWED_ACTIONS,
} from './constants.js';
import { validateSDKConfig, setSmartDefaults } from '../validation/config-validator.js';
+import { validatePayloadPrivacy, withPrivacyGuard } from '../validation/pi-guard.js';
import { BuildTargetUtils } from './build-targets.js';
import { OptaveError, makeStructuredError } from './errors.js';
-import { loadNodeWebSocket } from '../platform/node/websocket-loader.js';
+import loadNodeWebSocket from '../platform/node/websocket-loader.js';
import { enforceWebSocketScheme } from './security-guards.js';
const SDK_VERSION = typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0-dev';
@@ -35,7 +37,7 @@ const getBuildContext = () => {
return {
isBrowser: BuildTargetUtils.isBrowser(buildTarget),
isServer: BuildTargetUtils.isServer(buildTarget),
- buildTarget
+ buildTarget,
};
};
@@ -59,27 +61,34 @@ let warnedErrorStringOnce = false;
*/
class OptaveJavaScriptSDK extends EventEmitter {
options = {};
+
wss = null;
// The default payload. The payload provided by the user is merged "on top" of these objects
+ /**
+ * Default payload template. Typed fields below are the analytics context
+ * vocabulary (the SDK captures, it never emits). `request.reference` is
+ * client-custom labels only — never the carrier of typed analytics facts.
+ * See docs/architecture/analytics-payload-field-map.md.
+ */
static defaultPayload = {
session: {
- sessionId: '', // custom - lasts for the duration of a chat session or a call
+ sessionId: '', // session identity — analytics session length/bands, peak concurrency
channel: {
browser: '',
- deviceInfo: '', // e.g. "iOS/18.2, iPhone15,3"
- deviceType: '',
- language: '',
- location: '', // e.g. "45.42,-75.69"
- medium: 'chat', // options: "chat", "voice", "email"
- metadata: [], // custom metadata
- section: '', // e.g. "cart", "product_page"
+ deviceInfo: '', // e.g. "iOS/18.2, iPhone15,3" — analytics device slices
+ deviceType: '', // analytics dimension: "mobile" | "desktop" | "tablet"; omit when unknown
+ language: '', // analytics conversation language (fr-share, fr-parity, lang-switch)
+ location: '', // province grain at most (ISO 3166-2, e.g. "US-NY"); never precise coordinates
+ medium: 'chat', // analytics dimension: "chat" | "voice" | "email"
+ metadata: [], // free-form; MUST NOT carry names, emails, or message content
+ section: '', // e.g. "cart", "product_page" — analytics engagement
},
interface: {
- appVersion: '', // custom
- category: '', // e.g. "crm", "app", "auto", "widget"
+ appVersion: '', // emitter version — analytics provenance corroboration
+ category: '', // e.g. "crm", "app", "auto", "widget" — analytics per-surface slices
language: '', // the language from the crm agent
- name: '', // e.g. "salesforce", "zendesk"
+ name: '', // e.g. "salesforce", "zendesk" — analytics per-surface slices
type: '', // e.g. "custom_components", "marketplace", "channel"
},
},
@@ -88,23 +97,26 @@ class OptaveJavaScriptSDK extends EventEmitter {
attributes: {
content: '',
instruction: '',
- variant: 'A',
+ variant: 'A', // analytics A/B experiment slice
+ // replyTo: closed enum "ai" | "self" | "none". Omit when not reported
+ // (absent !== "none"). Not defaulted to "" — empty string is not in the enum.
},
connections: {
- journeyId: '',
+ journeyId: '', // analytics returning-user / cross-conversation journey
parentId: '', // in v2, this was called "trace_parent_ID"
- threadId: '', // this ID should remain unique across all the requests related to the same ticket/case/conversation
+ replyId: '', // opaque id of the replied-to message; hash if the source is a raw message id
+ threadId: '', // conversation identity — unique per ticket/case/conversation
},
context: {
// generated by optave
- caseId: '', // advanced mode
- departmentId: '', // advanced mode
- operatorId: '', // advanced mode
- organizationId: '',
- userId: '', // advanced mode
+ caseId: '', // advanced mode — analytics resolution/escalation joins
+ departmentId: '', // advanced mode — analytics ops slices
+ operatorId: '', // advanced mode — analytics ops slices
+ organizationId: '', // analytics org dimension
+ userId: '', // advanced mode — pseudonymous user grain; consumers MUST hash
},
reference: {
- // optionally generated by client, used for analytics
+ // client-custom labels ONLY — not typed analytics facts; no names/emails/message content
ids: [{ name: '', value: '' }],
labels: [],
tags: [],
@@ -120,10 +132,10 @@ class OptaveJavaScriptSDK extends EventEmitter {
],
links: [
{
- expires_at: '', //optional - e.g. "2025-08-06T00:00:00Z"
- html: false, //optional
- id: '', //optional
- label: '', //optional - e.g. "Click here to pay"
+ expires_at: '', // optional - e.g. "2025-08-06T00:00:00Z"
+ html: false, // optional
+ id: '', // optional
+ label: '', // optional - e.g. "Click here to pay"
type: '', // e.g., "payment_link", etc.
url: '', // e.g. "https://checkout.stripe.com/pay/cs_test..."
},
@@ -161,7 +173,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
users: [],
// Missing something? We can add it for you, please contact our sales team.
},
- settings: {
+ settings: { // feature-usage flags — analytics reasoning-engagement
disableBrowsing: false,
disableSearch: false,
disableSources: false,
@@ -171,7 +183,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
overrideInterfaceLanguage: '',
overrideOutputLanguage: '', // replaces the channel language
},
- // Advanced mode:
+ // Advanced mode — analytics human-vs-bot / operator-bot attribution:
a2a: [
{ id: '', name: '', type: '' }, // e.g. { id: "bot_55", name: "Bot 55", type: "chatbot" }
],
@@ -209,13 +221,12 @@ class OptaveJavaScriptSDK extends EventEmitter {
// Auto-detect CSP compliance mode based on build target
if (this.options.cspSafe === undefined) {
const context = getBuildContext();
- // Only server-esm should use full AJV validation by default
- // All other builds (browser-esm, browser-umd, server-umd) should use CSP-safe mode
+ // ONLY server-esm uses full AJV validation
+ // All other builds (browser-esm, browser-umd, server-umd) use CSP-safe mode
if (context.buildTarget === 'server-esm' || context.buildTarget === 'server') {
this.options.cspSafe = false; // Server ESM uses full AJV validation
- } else if (context.buildTarget === 'server-umd' || context.buildTarget === 'browser-esm' ||
- context.buildTarget === 'browser-umd' || context.isBrowser || isBrowserEnv()) {
- this.options.cspSafe = true; // All browser builds and server UMD use CSP-safe mode
+ } else if (context.buildTarget === 'browser-esm' || context.buildTarget === 'browser-umd' || context.buildTarget === 'server-umd' || context.isBrowser || isBrowserEnv()) {
+ this.options.cspSafe = true; // Browser builds and server-umd use CSP-safe mode
}
// If buildTarget is unknown/undefined, let user explicitly set cspSafe or use default undefined
}
@@ -224,26 +235,21 @@ class OptaveJavaScriptSDK extends EventEmitter {
// Handle validation errors - throw for errors, warn for warnings
if (!validation.isValid) {
- const errorMessages = validation.errors.map(e => e.message).join('; ');
+ const errorMessages = validation.errors.map((e) => e.message).join('; ');
throw new Error(`[Optave SDK] Configuration errors: ${errorMessages}`);
}
// Log warnings using the configured logger
- validation.warnings.forEach(warning => {
+ validation.warnings.forEach((warning) => {
(this.options?.logger?.warn || console.warn)(`[Optave SDK] ${warning.message}`);
});
// WebSocket scheme validation for UMD/browser builds (Salesforce Locker compatibility)
// SECURITY: This validation is critical for Salesforce Lightning security - must not be removed by tree-shaking
- const buildTarget =
- typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';
- try {
- // Use canonical security guard - single source of truth for WebSocket validation
- enforceWebSocketScheme(this.options.websocketUrl, buildTarget, this.options);
- } catch (securityError) {
- // Re-throw security errors immediately - this prevents minification from removing the try/catch
- throw securityError;
- }
+ const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';
+ // Use canonical security guard - single source of truth for WebSocket validation.
+ // Any thrown security error propagates to the caller (no try/catch needed - it would only rethrow).
+ enforceWebSocketScheme(this.options.websocketUrl, buildTarget, this.options);
// Initialize WebSocket implementation
// Use build-aware WebSocket detection to avoid window references in server builds
@@ -252,8 +258,8 @@ class OptaveJavaScriptSDK extends EventEmitter {
if (!this.WebSocketImpl && context.isBrowser) {
// Browser builds: check global WebSocket then window.WebSocket
- this.WebSocketImpl = (typeof WebSocket !== 'undefined' ? WebSocket : undefined) ||
- (typeof window !== 'undefined' && window.WebSocket ? window.WebSocket : undefined);
+ this.WebSocketImpl = (typeof WebSocket !== 'undefined' ? WebSocket : undefined)
+ || (typeof window !== 'undefined' && window.WebSocket ? window.WebSocket : undefined);
} else if (!this.WebSocketImpl && context.isServer) {
// Server builds: only check global WebSocket, no window references
this.WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : undefined;
@@ -268,15 +274,15 @@ class OptaveJavaScriptSDK extends EventEmitter {
// Deprecation tracking
this._deprecatedKeys = new Set();
- this._silenceDeprecations =
- typeof process !== 'undefined' && process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS === '1';
+ this._silenceDeprecations = typeof process !== 'undefined' && process?.env?.OPTAVE_SDK_SILENCE_DEPRECATIONS === '1';
- // Set up CSP-safe validation functions
+ // Set up CSP-safe validation functions. PI guard wraps payload validation
+ // on every build — the analytics raw store is append-only under Object Lock.
if (this.options.cspSafe) {
- this._validatePayload = validateBrowserPayload;
+ this._validatePayload = withPrivacyGuard(validateBrowserPayload);
this._validateMessageEnvelope = validateBrowserMessageEnvelope;
} else {
- this._validatePayload = validateGeneratedPayload;
+ this._validatePayload = withPrivacyGuard(validateGeneratedPayload);
this._validateMessageEnvelope = validateGeneratedMessageEnvelope;
}
}
@@ -291,8 +297,8 @@ class OptaveJavaScriptSDK extends EventEmitter {
if (!this.WebSocketImpl && context.isBrowser) {
// Browser builds: check global WebSocket then window.WebSocket
- this.WebSocketImpl = (typeof WebSocket !== 'undefined' ? WebSocket : undefined) ||
- (typeof window !== 'undefined' && window.WebSocket ? window.WebSocket : undefined);
+ this.WebSocketImpl = (typeof WebSocket !== 'undefined' ? WebSocket : undefined)
+ || (typeof window !== 'undefined' && window.WebSocket ? window.WebSocket : undefined);
} else if (!this.WebSocketImpl && context.isServer) {
// Server builds: only check global WebSocket, no window references
this.WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : undefined;
@@ -324,10 +330,10 @@ class OptaveJavaScriptSDK extends EventEmitter {
// For fallback compatibility in dev environments, check browser globals
if (context.buildTarget === 'unknown' && (
- typeof window !== 'undefined' ||
- typeof document !== 'undefined' ||
- typeof navigator !== 'undefined' ||
- typeof location !== 'undefined'
+ typeof window !== 'undefined'
+ || typeof document !== 'undefined'
+ || typeof navigator !== 'undefined'
+ || typeof globalThis.location !== 'undefined'
)) {
return null;
}
@@ -338,19 +344,22 @@ class OptaveJavaScriptSDK extends EventEmitter {
}
// Use static import instead of dynamic import for UMD builds
- return await loadNodeWebSocket();
+ return loadNodeWebSocket();
}
// Public static helpers for consumers (optional export pattern)
static getSdkVersion() {
return SDK_VERSION;
}
+
static getSpecVersion() {
return SPEC_VERSION;
}
+
static getSchemaRef() {
return SCHEMA_REF;
}
+
static get CONSTANTS() {
return CONSTANTS;
}
@@ -359,6 +368,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
static get LegacyEvents() {
return LegacyEvents;
}
+
static get InboundEvents() {
return InboundEvents;
}
@@ -383,6 +393,16 @@ class OptaveJavaScriptSDK extends EventEmitter {
return r.valid;
}
+ // Schema validation is optional in production (strictValidation). The PI
+ // vocabulary guard is not — the analytics raw store is append-only under
+ // Object Lock, so coordinates and direct identifiers must never go out.
+ _validateOutboundPayload(payload) {
+ if (this.options.strictValidation) {
+ return this._validatePayload(payload);
+ }
+ return validatePayloadPrivacy(payload);
+ }
+
// Validates action-specific required fields
validateRequiredFields(params, action) {
const errors = [];
@@ -405,12 +425,12 @@ class OptaveJavaScriptSDK extends EventEmitter {
errors.push('request.connections.parentId is required for adjust');
}
if (
- !params.request?.scope?.conversations ||
- !Array.isArray(params.request.scope.conversations) ||
- params.request.scope.conversations.length === 0
+ !params.request?.scope?.conversations
+ || !Array.isArray(params.request.scope.conversations)
+ || params.request.scope.conversations.length === 0
) {
errors.push(
- 'request.scope.conversations is required for adjust and must be a non-empty array'
+ 'request.scope.conversations is required for adjust and must be a non-empty array',
);
}
break;
@@ -423,12 +443,12 @@ class OptaveJavaScriptSDK extends EventEmitter {
errors.push('request.connections.parentId is required for elevate');
}
if (
- !params.request?.scope?.conversations ||
- !Array.isArray(params.request.scope.conversations) ||
- params.request.scope.conversations.length === 0
+ !params.request?.scope?.conversations
+ || !Array.isArray(params.request.scope.conversations)
+ || params.request.scope.conversations.length === 0
) {
errors.push(
- 'request.scope.conversations is required for elevate and must be a non-empty array'
+ 'request.scope.conversations is required for elevate and must be a non-empty array',
);
}
break;
@@ -437,33 +457,33 @@ class OptaveJavaScriptSDK extends EventEmitter {
case 'summarize':
case 'insights':
if (
- !params.request?.scope?.conversations ||
- !Array.isArray(params.request.scope.conversations) ||
- params.request.scope.conversations.length === 0
+ !params.request?.scope?.conversations
+ || !Array.isArray(params.request.scope.conversations)
+ || params.request.scope.conversations.length === 0
) {
errors.push(
- `request.scope.conversations is required for ${action} and must be a non-empty array`
+ `request.scope.conversations is required for ${action} and must be a non-empty array`,
);
}
break;
case 'recommend':
if (
- !params.request?.resources?.offers ||
- !Array.isArray(params.request.resources.offers) ||
- params.request.resources.offers.length === 0
+ !params.request?.resources?.offers
+ || !Array.isArray(params.request.resources.offers)
+ || params.request.resources.offers.length === 0
) {
errors.push(
- 'request.resources.offers is required for recommend and must be a non-empty array'
+ 'request.resources.offers is required for recommend and must be a non-empty array',
);
}
if (
- !params.request?.scope?.conversations ||
- !Array.isArray(params.request.scope.conversations) ||
- params.request.scope.conversations.length === 0
+ !params.request?.scope?.conversations
+ || !Array.isArray(params.request.scope.conversations)
+ || params.request.scope.conversations.length === 0
) {
errors.push(
- 'request.scope.conversations is required for recommend and must be a non-empty array'
+ 'request.scope.conversations is required for recommend and must be a non-empty array',
);
}
break;
@@ -471,13 +491,14 @@ class OptaveJavaScriptSDK extends EventEmitter {
case 'customerinteraction': // legacy lowercase for backward compatibility
case 'customerInteraction': // current camelCase
case 'interaction':
+ case 'assistant':
if (
- !params.request?.scope?.conversations ||
- !Array.isArray(params.request.scope.conversations) ||
- params.request.scope.conversations.length === 0
+ !params.request?.scope?.conversations
+ || !Array.isArray(params.request.scope.conversations)
+ || params.request.scope.conversations.length === 0
) {
errors.push(
- `request.scope.conversations is required for ${action} and must be a non-empty array`
+ `request.scope.conversations is required for ${action} and must be a non-empty array`,
);
}
break;
@@ -493,7 +514,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
return {
isValid: errors.length === 0,
- errors: errors,
+ errors,
};
}
@@ -501,19 +522,18 @@ class OptaveJavaScriptSDK extends EventEmitter {
// Browser-targeted builds should not use client credentials for security
// Server builds (ESM and UMD) can authenticate with client credentials
// Use the SDK's own build flags rather than environment variables for accuracy
- const buildTarget =
- typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';
+ const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';
const isBrowserTargetedBuild = BuildTargetUtils.isBrowser(buildTarget);
if (isBrowserTargetedBuild) {
this.handleError(
ErrorCategory.AUTHENTICATION,
'UNSUPPORTED_IN_BROWSER',
- 'authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend.'
+ 'authenticate() is not available in browsers. Use options.tokenProvider() to obtain a short-lived WebSocket token from your backend.',
);
return null;
}
- let params = {
+ const params = {
grant_type: 'client_credentials',
};
@@ -521,7 +541,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
this.handleError(
ErrorCategory.AUTHENTICATION,
'INVALID_AUTHENTICATION_URL',
- 'Empty or invalid authentication URL'
+ 'Empty or invalid authentication URL',
);
return null;
}
@@ -530,7 +550,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
this.handleError(
ErrorCategory.AUTHENTICATION,
'INVALID_CLIENT_ID',
- 'Empty or invalid client ID'
+ 'Empty or invalid client ID',
);
return null;
}
@@ -547,7 +567,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
// without needing to remember the /token suffix
let authUrl = this.options.authenticationUrl;
if (!authUrl.endsWith('/token')) {
- authUrl = authUrl.endsWith('/') ? authUrl + 'token' : authUrl + '/token';
+ authUrl = authUrl.endsWith('/') ? `${authUrl}token` : `${authUrl}/token`;
}
const url = `${authUrl}?${paramsString}`;
@@ -565,7 +585,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
ErrorCategory.AUTHENTICATION,
'INVALID_AUTHENTICATION_RESPONSE',
this.formatAuthenticationError(response, responseJson.error, 'token endpoint').message,
- responseJson.error
+ responseJson.error,
);
return null;
}
@@ -576,7 +596,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
async openConnection(bearerToken) {
if (!this.options.websocketUrl) {
(this.options?.logger?.error || console.error)(
- '[Optave SDK] openConnection aborted: missing websocketUrl'
+ '[Optave SDK] openConnection aborted: missing websocketUrl',
);
this.handleError(
ErrorCategory.WEBSOCKET,
@@ -584,9 +604,9 @@ class OptaveJavaScriptSDK extends EventEmitter {
this.formatWebSocketError(new Error('Invalid WebSocket URL configuration'), {
url: this.options.websocketUrl,
}).message,
- this.options.websocketUrl
+ this.options.websocketUrl,
);
- return;
+ return undefined;
}
const getToken = async () => {
@@ -599,7 +619,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
ErrorCategory.AUTHENTICATION,
'TOKEN_PROVIDER_FAILED',
this.formatTokenProviderError(e).message,
- e
+ e,
);
return null;
}
@@ -618,18 +638,18 @@ class OptaveJavaScriptSDK extends EventEmitter {
'NO_WEBSOCKET_IMPL',
this.formatWebSocketError(new Error('No WebSocket implementation available'), {
environment: typeof window !== 'undefined' ? 'browser' : 'node',
- }).message
+ }).message,
);
- return;
+ return undefined;
}
if (!token && this.options.authRequired !== false) {
this.handleError(
ErrorCategory.AUTHENTICATION,
'MISSING_TOKEN',
- 'No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.'
+ 'No WebSocket token available. Provide options.tokenProvider() or set options.tokenUrl.',
);
- return;
+ return undefined;
}
const qp = new URLSearchParams();
@@ -643,7 +663,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
qp.toString()
? `${this.options.websocketUrl}?${qp.toString()}`
: this.options.websocketUrl,
- protocols
+ protocols,
);
} else {
// Fallback: token in query string (avoid if possible)
@@ -656,27 +676,27 @@ class OptaveJavaScriptSDK extends EventEmitter {
this.wss = new this.WebSocketImpl(
qp.toString()
? `${this.options.websocketUrl}?${qp.toString()}`
- : this.options.websocketUrl
+ : this.options.websocketUrl,
);
if (token) {
this._warnOnce(
'_warnedQueryToken',
- '[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".'
+ '[Optave SDK] Passing auth token in WebSocket URL query is discouraged. Prefer authTransport="subprotocol".',
);
}
}
} catch (error) {
(this.options?.logger?.error || console.error)(
'[Optave SDK] WebSocket constructor threw',
- error
+ error,
);
this.handleError(
ErrorCategory.WEBSOCKET,
'WEBSOCKET_ERROR',
this.formatWebSocketError(error, { url: this.options.websocketUrl }).message,
- error
+ error,
);
- return;
+ return undefined;
}
// Return a promise that resolves when the connection is established
return new Promise((resolve, reject) => {
@@ -710,25 +730,25 @@ class OptaveJavaScriptSDK extends EventEmitter {
}
this.handleError(ErrorCategory.WEBSOCKET, 'CONNECTION_TIMEOUT', errorMessage);
- reject({
+ reject(new OptaveError({
category: ErrorCategory.WEBSOCKET,
code: 'CONNECTION_TIMEOUT',
message: errorMessage,
details: null,
- });
+ }));
}, this.options.connectionTimeoutMs || 30000);
- this.wss.onopen = event => {
+ this.wss.onopen = (event) => {
clearTimeout(connectionTimeout);
this.emit('open', event);
resolve(event);
};
- this.wss.onmessage = event => {
+ this.wss.onmessage = (event) => {
this._handleInbound(event.data);
};
- this.wss.onclose = event => {
+ this.wss.onclose = (event) => {
clearTimeout(connectionTimeout);
this.emit('close', event);
//
@@ -737,7 +757,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
// The _handled flag ensures promises are only resolved/rejected once
//
// Reject all pending promises when connection closes
- for (const [correlationId, entry] of this._pending.entries()) {
+ Array.from(this._pending.entries()).forEach(([correlationId, entry]) => {
if (entry.timer) {
clearTimeout(entry.timer);
}
@@ -750,12 +770,12 @@ class OptaveJavaScriptSDK extends EventEmitter {
details: { code: event.code, reason: event.reason, correlationId },
correlationId,
});
- }
+ });
this._pending.clear();
this.wss = null;
};
- this.wss.onerror = event => {
+ this.wss.onerror = (event) => {
clearTimeout(connectionTimeout);
//
// CRITICAL: Enhanced error message handling and race condition prevention
@@ -765,11 +785,10 @@ class OptaveJavaScriptSDK extends EventEmitter {
// 3. Double promise resolution/rejection bugs
//
// Create error object - handle both native events and Error objects
- const errorMessage =
- event.message ||
- (event instanceof Error ? event.message : null) ||
- (typeof event === 'object' && event.error && event.error.message) ||
- 'WebSocket connection failed';
+ const errorMessage = event.message
+ || (event instanceof Error ? event.message : null)
+ || (typeof event === 'object' && event.error && event.error.message)
+ || 'WebSocket connection failed';
const errObj = {
category: ErrorCategory.WEBSOCKET,
@@ -779,7 +798,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
};
// Reject all pending promises when WebSocket error occurs
- for (const [correlationId, entry] of this._pending.entries()) {
+ Array.from(this._pending.entries()).forEach(([correlationId, entry]) => {
if (entry.timer) {
clearTimeout(entry.timer);
}
@@ -790,7 +809,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
details: { ...errObj.details, correlationId },
correlationId,
});
- }
+ });
this._pending.clear();
// Emit error event for general error handling
@@ -845,14 +864,13 @@ class OptaveJavaScriptSDK extends EventEmitter {
ErrorCategory.VALIDATION,
'INBOUND_ENVELOPE_SCHEMA_MISMATCH',
this.formatValidationErrorMessage(vr.errors, 'Inbound envelope validation failed'),
- vr.errors
+ vr.errors,
);
}
}
if (isError) {
- const correlationId =
- (parsed?.headers && parsed.headers.correlationId) || parsed?.correlationId || null;
+ const correlationId = (parsed?.headers && parsed.headers.correlationId) || parsed?.correlationId || null;
const errObj = {
category: ErrorCategory.ORCHESTRATOR,
code: parsed?.error?.code || 'REMOTE_ERROR',
@@ -893,7 +911,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
if (!warnedMessageEventOnce) {
warnedMessageEventOnce = true;
(this.options?.logger?.warn || console.warn)(
- '[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".'
+ '[optave-sdk][deprecation] The "message" event will be deprecated. Please also listen to "superpower.response".',
);
}
@@ -914,7 +932,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
}
}
- _emitError(errObj, action = null) {
+ _emitError(errObj, _action = null) {
if (!errObj.timestamp) {
errObj.timestamp = new Date().toISOString();
}
@@ -926,7 +944,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
if (!warnedErrorStringOnce) {
warnedErrorStringOnce = true;
(this.options?.logger?.warn || console.warn)(
- '[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.'
+ '[optave-sdk][deprecation] The "error" (string payload) is deprecated. Please also listen to "superpower.error" for a structured error object.',
);
}
@@ -958,12 +976,12 @@ class OptaveJavaScriptSDK extends EventEmitter {
}
// Use more reliable object detection that works across webpack contexts
- const isObject = obj => obj !== null && typeof obj === 'object' && !Array.isArray(obj);
+ const isObject = (obj) => obj !== null && typeof obj === 'object' && !Array.isArray(obj);
if (isObject(target) && isObject(source)) {
const result = { ...target }; // Start with all target keys
// Process all source keys, merging or overriding
- for (let key in source) {
+ Object.keys(source).forEach((key) => {
if (key in target) {
// Recursively merge or replace values
result[key] = this.selectiveDeepMerge(target[key], source[key]);
@@ -971,7 +989,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
// Add new keys from source that don't exist in target
result[key] = source[key];
}
- }
+ });
return result;
}
@@ -990,11 +1008,12 @@ class OptaveJavaScriptSDK extends EventEmitter {
openConnectionAsync(bearerToken) {
return new Promise((resolve, reject) => {
- const onOpen = e => {
+ let onErr;
+ const onOpen = (e) => {
this.off('error', onErr);
resolve(e);
};
- const onErr = e => {
+ onErr = (e) => {
this.off('open', onOpen);
reject(e);
};
@@ -1005,12 +1024,12 @@ class OptaveJavaScriptSDK extends EventEmitter {
}
buildPayload(requestType, action, params) {
- let payload = this.selectiveDeepMerge(OptaveJavaScriptSDK.defaultPayload, params);
+ const payload = this.selectiveDeepMerge(OptaveJavaScriptSDK.defaultPayload, params);
// Legacy alias mapping (variation -> variant) with deprecation notice
if (params?.request?.variation) {
this.deprecate(
'payload.request.variation',
- "[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'."
+ "[Deprecation] 'request.variation' is deprecated; use 'request.attributes.variant'.",
);
payload.request.attributes.variant = params.request.variation;
}
@@ -1019,7 +1038,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
payload.request.attributes.content = params.request.content;
this.deprecate(
'payload.request.content',
- "[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'."
+ "[Deprecation] 'request.content' is deprecated; use 'request.attributes.content'.",
);
}
@@ -1041,7 +1060,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
const correlationId = headerOverrides.correlationId || payload?.request?.requestId || uuidv7();
const traceId = headerOverrides.traceId || uuidv7();
const idempotencyKey = headerOverrides.idempotencyKey || uuidv7();
- const timestamp = headerOverrides.timestamp; // user event time (overrideable)
+ const { timestamp } = headerOverrides; // user event time (overrideable)
const issuedAt = now; // envelope build time
const headers = {
@@ -1080,47 +1099,47 @@ class OptaveJavaScriptSDK extends EventEmitter {
if (errors.length === 1) {
const error = errors[0];
const fieldPath = error.instancePath || '/';
- const field =
- fieldPath === '/' ? 'root object' : fieldPath.replace(/^\//, '').replace(/\//g, '.');
+ const field = fieldPath === '/' ? 'root object' : fieldPath.replace(/^\//, '').replace(/\//g, '.');
if (error.keyword === 'required') {
const missingField = error.params?.missingProperty || 'unknown field';
// Handle case where instancePath already points to the missing property
- const fullFieldPath =
- field === 'root object'
- ? missingField
- : field.endsWith(missingField)
- ? field
- : field + '.' + missingField;
+ let fullFieldPath;
+ if (field === 'root object') {
+ fullFieldPath = missingField;
+ } else if (field.endsWith(missingField)) {
+ fullFieldPath = field;
+ } else {
+ fullFieldPath = `${field}.${missingField}`;
+ }
return `${baseMessage}: ${
field === 'root object' ? 'Required field' : 'Field'
} '${fullFieldPath}' is missing`;
- } else if (error.keyword === 'type') {
+ } if (error.keyword === 'type') {
const expectedType = error.params?.type || 'unknown';
return `${baseMessage}: Field '${field}' must be of type '${expectedType}'`;
- } else if (error.keyword === 'additionalProperties') {
+ } if (error.keyword === 'additionalProperties') {
const additionalProp = error.params?.additionalProperty || 'unknown';
return `${baseMessage}: Field '${field}.${additionalProp}' is not allowed`;
- } else if (error.keyword === 'enum') {
+ } if (error.keyword === 'enum') {
const allowedValues = error.params?.allowedValues || [];
const allowedStr = Array.isArray(allowedValues)
? allowedValues.join(', ')
: 'unknown values';
return `${baseMessage}: Field '${field}' must be one of: ${allowedStr}`;
- } else {
- return `${baseMessage}: ${error.message} at '${field}'`;
}
+ return `${baseMessage}: ${error.message} at '${field}'`;
}
// If there are multiple errors, provide a summary with the most critical ones
- const criticalErrors = errors.filter(e => e.keyword === 'required');
- const typeErrors = errors.filter(e => e.keyword === 'type');
- const otherErrors = errors.filter(e => e.keyword !== 'required' && e.keyword !== 'type');
+ const criticalErrors = errors.filter((e) => e.keyword === 'required');
+ const typeErrors = errors.filter((e) => e.keyword === 'type');
+ const otherErrors = errors.filter((e) => e.keyword !== 'required' && e.keyword !== 'type');
- let summary = baseMessage + ':';
+ let summary = `${baseMessage}:`;
if (criticalErrors.length > 0) {
- const missingFields = criticalErrors.map(e => {
+ const missingFields = criticalErrors.map((e) => {
const field = (e.instancePath || '/').replace(/^\//, '').replace(/\//g, '.');
const missing = e.params?.missingProperty || 'unknown';
return field === '' ? missing : `${field}.${missing}`;
@@ -1129,7 +1148,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
}
if (typeErrors.length > 0) {
- const typeIssues = typeErrors.slice(0, 3).map(e => {
+ const typeIssues = typeErrors.slice(0, 3).map((e) => {
const field = (e.instancePath || '/').replace(/^\//, '').replace(/\//g, '.');
const expectedType = e.params?.type || 'unknown';
return `${field || 'root'} (expected ${expectedType})`;
@@ -1194,11 +1213,10 @@ class OptaveJavaScriptSDK extends EventEmitter {
const suggestions = [];
// Extract error details from different event types
- const errorMessage =
- errorEvent?.message ||
- (errorEvent instanceof Error ? errorEvent.message : null) ||
- (typeof errorEvent === 'object' && errorEvent.error && errorEvent.error.message) ||
- null;
+ const errorMessage = errorEvent?.message
+ || (errorEvent instanceof Error ? errorEvent.message : null)
+ || (typeof errorEvent === 'object' && errorEvent.error && errorEvent.error.message)
+ || null;
if (errorMessage) {
message += `: ${errorMessage}`;
@@ -1239,24 +1257,22 @@ class OptaveJavaScriptSDK extends EventEmitter {
const maxKB = maxSize;
const overageKB = actualKB - maxKB;
- let message = `Payload too large: ${actualKB}KB exceeds maximum ${maxKB}KB (${overageKB}KB over limit)`;
+ const message = `Payload too large: ${actualKB}KB exceeds maximum ${maxKB}KB (${overageKB}KB over limit)`;
const suggestions = [];
// Analyze payload for optimization suggestions
if (payload && typeof payload === 'object') {
- const payloadStr = JSON.stringify(payload);
-
// Check for large conversation arrays
if (
- payload.request?.scope?.conversations &&
- Array.isArray(payload.request.scope.conversations)
+ payload.request?.scope?.conversations
+ && Array.isArray(payload.request.scope.conversations)
) {
const conversationsSize = JSON.stringify(payload.request.scope.conversations).length;
const conversationsKB = Math.ceil(conversationsSize / 1024);
if (conversationsKB > 10) {
// If conversations are more than 10KB
suggestions.push(
- `Consider reducing conversation history - current size: ~${conversationsKB}KB`
+ `Consider reducing conversation history - current size: ~${conversationsKB}KB`,
);
suggestions.push('Remove older messages or summarize conversation context');
}
@@ -1308,8 +1324,8 @@ class OptaveJavaScriptSDK extends EventEmitter {
suggestions.push('Check if tokenProvider endpoint is accessible');
suggestions.push('Verify CORS settings allow requests to token endpoint');
} else if (
- originalError.message?.includes('404') ||
- originalError.message?.includes('Not Found')
+ originalError.message?.includes('404')
+ || originalError.message?.includes('Not Found')
) {
suggestions.push('Verify tokenProvider endpoint URL is correct');
suggestions.push('Ensure backend token endpoint is implemented');
@@ -1318,7 +1334,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
suggestions.push('Verify user session or credentials are valid');
} else if (originalError.message?.includes('timeout')) {
suggestions.push(
- 'Token provider request timed out - check network or server response time'
+ 'Token provider request timed out - check network or server response time',
);
}
}
@@ -1339,7 +1355,9 @@ class OptaveJavaScriptSDK extends EventEmitter {
}
handleError(category, code, message, details = null, suggestions = [], correlationId = null) {
- const errObj = new OptaveError({ category, code, message, details });
+ const errObj = new OptaveError({
+ category, code, message, details,
+ });
if (suggestions) errObj.suggestions = suggestions;
if (correlationId) errObj.correlationId = correlationId;
if (this.listenerCount(LegacyEvents.ERROR) === 0 && this.listenerCount(EVENTS.ERROR) === 0) {
@@ -1349,8 +1367,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
}
send(requestType, action, params) {
- const OPEN =
- (this.WebSocketImpl && this.WebSocketImpl.OPEN) != null ? this.WebSocketImpl.OPEN : 1;
+ const OPEN = (this.WebSocketImpl && this.WebSocketImpl.OPEN) != null ? this.WebSocketImpl.OPEN : 1;
if (!(this.wss && this.wss.readyState === OPEN)) {
const readyState = this.wss ? this.wss.readyState : 'no connection';
this.handleError(
@@ -1359,7 +1376,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
this.formatWebSocketError(new Error('WebSocket not ready for sending'), {
readyState,
action,
- }).message
+ }).message,
);
return;
}
@@ -1367,14 +1384,16 @@ class OptaveJavaScriptSDK extends EventEmitter {
this.handleError(
ErrorCategory.VALIDATION,
'INVALID_ACTION',
- `Unsupported action '${action}'. Allowed: ${[...ALLOWED_ACTIONS].join(', ')}`
+ `Unsupported action '${action}'. Allowed: ${[...ALLOWED_ACTIONS].join(', ')}`,
);
return;
}
// Lightweight additional-property detection BEFORE merge (top-level only)
const allowedTopLevel = new Set(['session', 'request', 'headers']);
- for (const k of Object.keys(params || {})) {
+ const topLevelKeys = Object.keys(params || {});
+ for (let i = 0; i < topLevelKeys.length; i += 1) {
+ const k = topLevelKeys[i];
if (!allowedTopLevel.has(k)) {
const errors = [
{
@@ -1388,7 +1407,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
ErrorCategory.VALIDATION,
'PAYLOAD_SCHEMA_MISMATCH',
this.formatValidationErrorMessage(errors),
- errors
+ errors,
);
return;
}
@@ -1404,25 +1423,22 @@ class OptaveJavaScriptSDK extends EventEmitter {
ErrorCategory.VALIDATION,
'REQUIRED_FIELDS_MISSING',
`Missing required fields for action '${action}': ${requiredFieldValidation.errors.join(
- ', '
+ ', ',
)}`,
- requiredFieldValidation.errors
+ requiredFieldValidation.errors,
);
return;
}
- // Then do full schema validation if enabled
- if (this.options.strictValidation) {
- const schemaResult = this._validatePayload(payload);
- if (!schemaResult.valid) {
- this.handleError(
- ErrorCategory.VALIDATION,
- 'PAYLOAD_SCHEMA_MISMATCH',
- this.formatValidationErrorMessage(schemaResult.errors, 'Schema validation failed'),
- schemaResult.errors
- );
- return;
- }
+ const outboundResult = this._validateOutboundPayload(payload);
+ if (!outboundResult.valid) {
+ this.handleError(
+ ErrorCategory.VALIDATION,
+ 'PAYLOAD_SCHEMA_MISMATCH',
+ this.formatValidationErrorMessage(outboundResult.errors, 'Schema validation failed'),
+ outboundResult.errors,
+ );
+ return;
}
const envelope = this.buildMessageEnvelope(payload, requestType, action, params?.headers || {});
@@ -1434,7 +1450,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
ErrorCategory.VALIDATION,
'PAYLOAD_TOO_LARGE',
this.formatPayloadSizeError(actualSize, CONSTANTS.MAX_PAYLOAD_SIZE_KB, envelope).message,
- CONSTANTS.MAX_PAYLOAD_SIZE_KB
+ CONSTANTS.MAX_PAYLOAD_SIZE_KB,
);
return;
}
@@ -1445,32 +1461,44 @@ class OptaveJavaScriptSDK extends EventEmitter {
adjust(params) {
return this.send('message', 'adjust', params);
}
+
elevate(params) {
return this.send('message', 'elevate', params);
}
+
interaction(params) {
return this.send('message', 'interaction', params);
}
+
+ assistant(params) {
+ return this.send('message', 'assistant', params);
+ }
+
reception(params) {
return this.send('message', 'reception', params);
}
+
// Deprecated alias (will be removed in a future major version)
customerInteraction(params) {
this.deprecate(
'method.customerInteraction',
- "[Deprecation] 'customerInteraction' is deprecated; use 'interaction' instead."
+ "[Deprecation] 'customerInteraction' is deprecated; use 'interaction' instead.",
);
return this.send('message', 'customerInteraction', params);
}
+
summarize(params) {
return this.send('message', 'summarize', params);
}
+
translate(params) {
return this.send('message', 'translate', params);
}
+
recommend(params) {
return this.send('message', 'recommend', params);
}
+
insights(params) {
return this.send('message', 'insights', params);
}
@@ -1501,34 +1529,34 @@ class OptaveJavaScriptSDK extends EventEmitter {
}, timeoutMs);
}
- this._pending.set(correlationId, { resolve, reject, timer, action, _handled: false });
+ this._pending.set(correlationId, {
+ resolve, reject, timer, action, _handled: false,
+ });
}
_promiseSend(requestType, action, params = {}, opts = {}) {
let correlationId; // Declare outside promise to access later
- let promiseResolve, promiseReject; // Capture for timeout registration
const promise = new Promise((resolve, reject) => {
- promiseResolve = resolve;
- promiseReject = reject;
-
// Calculate timeout duration early to determine behavior
- const timeoutMs =
- typeof opts.timeoutMs === 'number'
- ? opts.timeoutMs
- : typeof opts.timeout === 'number'
- ? opts.timeout
- : this.options.requestTimeoutMs;
+ let timeoutMs;
+ if (typeof opts.timeoutMs === 'number') {
+ timeoutMs = opts.timeoutMs;
+ } else if (typeof opts.timeout === 'number') {
+ timeoutMs = opts.timeout;
+ } else {
+ timeoutMs = this.options.requestTimeoutMs;
+ }
if (!this.wss || this.wss.readyState !== WebSocket.OPEN) {
// If no timeout is specified, fail immediately with WebSocket state error
if (timeoutMs <= 0) {
- reject({
+ reject(new OptaveError({
category: ErrorCategory.WEBSOCKET,
code: 'WEBSOCKET_NOT_IN_OPEN_STATE',
message: 'WebSocket not open',
details: null,
- });
+ }));
return;
}
// Otherwise, let the timeout mechanism handle the failure
@@ -1539,24 +1567,26 @@ class OptaveJavaScriptSDK extends EventEmitter {
payload,
requestType,
action,
- params?.headers || {}
+ params?.headers || {},
);
correlationId = envelope.headers.correlationId;
this._registerPending(correlationId, action, timeoutMs, resolve, reject);
return; // Let timeout handle the rejection
}
if (!ALLOWED_ACTIONS.has(action)) {
- reject({
+ reject(new OptaveError({
category: ErrorCategory.VALIDATION,
code: 'INVALID_ACTION',
message: `Unsupported action '${action}'.`,
details: { allowed: [...ALLOWED_ACTIONS] },
- });
+ }));
return;
}
// Additional property check (top-level) mirroring send()
const allowedTopLevel = new Set(['session', 'request', 'headers']);
- for (const k of Object.keys(params || {})) {
+ const topLevelKeys = Object.keys(params || {});
+ for (let i = 0; i < topLevelKeys.length; i += 1) {
+ const k = topLevelKeys[i];
if (!allowedTopLevel.has(k)) {
const errors = [
{
@@ -1566,12 +1596,12 @@ class OptaveJavaScriptSDK extends EventEmitter {
message: `must NOT have additional property '${k}'`,
},
];
- reject({
+ reject(new OptaveError({
category: ErrorCategory.VALIDATION,
code: 'PAYLOAD_SCHEMA_MISMATCH',
message: this.formatValidationErrorMessage(errors),
details: errors,
- });
+ }));
return;
}
}
@@ -1580,36 +1610,33 @@ class OptaveJavaScriptSDK extends EventEmitter {
// Validate required fields FIRST (more specific error)
const requiredFieldValidation = this.validateRequiredFields(payload, action);
if (!requiredFieldValidation.isValid) {
- reject({
+ reject(new OptaveError({
category: ErrorCategory.VALIDATION,
code: 'REQUIRED_FIELDS_MISSING',
message: `Missing required fields for action '${action}'`,
details: requiredFieldValidation.errors,
- });
+ }));
return;
}
- // Then do full schema validation if enabled
- if (this.options.strictValidation) {
- const schemaResult = validateGeneratedPayload(payload);
- if (!schemaResult.valid) {
- reject({
- category: ErrorCategory.VALIDATION,
- code: 'PAYLOAD_SCHEMA_MISMATCH',
- message: this.formatValidationErrorMessage(
- schemaResult.errors,
- 'Schema validation failed'
- ),
- details: schemaResult.errors,
- });
- return;
- }
+ const outboundResult = this._validateOutboundPayload(payload);
+ if (!outboundResult.valid) {
+ reject(new OptaveError({
+ category: ErrorCategory.VALIDATION,
+ code: 'PAYLOAD_SCHEMA_MISMATCH',
+ message: this.formatValidationErrorMessage(
+ outboundResult.errors,
+ 'Schema validation failed',
+ ),
+ details: outboundResult.errors,
+ }));
+ return;
}
const envelope = this.buildMessageEnvelope(
payload,
requestType,
action,
- params?.headers || {}
+ params?.headers || {},
);
correlationId = envelope.headers.correlationId; // Assign to outer scope variable
@@ -1622,14 +1649,14 @@ class OptaveJavaScriptSDK extends EventEmitter {
const errorMessage = this.formatPayloadSizeError(
actualSize,
CONSTANTS.MAX_PAYLOAD_SIZE_KB,
- envelope
+ envelope,
).message;
- reject({
+ reject(new OptaveError({
category: ErrorCategory.VALIDATION,
code: 'PAYLOAD_TOO_LARGE',
message: errorMessage,
details: { maxKb: CONSTANTS.MAX_PAYLOAD_SIZE_KB },
- });
+ }));
return;
}
@@ -1646,13 +1673,14 @@ class OptaveJavaScriptSDK extends EventEmitter {
entry._handled = true;
this._pending.delete(correlationId);
}
- reject({
+ const sendError = new OptaveError({
category: ErrorCategory.WEBSOCKET,
code: 'SEND_FAILED',
message: 'Failed to send over WebSocket',
details: e,
- correlationId,
});
+ sendError.correlationId = correlationId;
+ reject(sendError);
}
});
@@ -1666,32 +1694,44 @@ class OptaveJavaScriptSDK extends EventEmitter {
adjustAsync(params, opts) {
return this._promiseSend('message', 'adjust', params, opts);
}
+
elevateAsync(params, opts) {
return this._promiseSend('message', 'elevate', params, opts);
}
+
interactionAsync(params, opts) {
return this._promiseSend('message', 'interaction', params, opts);
}
+
+ assistantAsync(params, opts) {
+ return this._promiseSend('message', 'assistant', params, opts);
+ }
+
receptionAsync(params, opts) {
return this._promiseSend('message', 'reception', params, opts);
}
+
// Deprecated alias
customerInteractionAsync(params, opts) {
this.deprecate(
'method.customerInteractionAsync',
- "[Deprecation] 'customerInteractionAsync' is deprecated; use 'interactionAsync' instead."
+ "[Deprecation] 'customerInteractionAsync' is deprecated; use 'interactionAsync' instead.",
);
return this._promiseSend('message', 'customerInteraction', params, opts);
}
+
summarizeAsync(params, opts) {
return this._promiseSend('message', 'summarize', params, opts);
}
+
translateAsync(params, opts) {
return this._promiseSend('message', 'translate', params, opts);
}
+
recommendAsync(params, opts) {
return this._promiseSend('message', 'recommend', params, opts);
}
+
insightsAsync(params, opts) {
return this._promiseSend('message', 'insights', params, opts);
}
@@ -1732,7 +1772,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
const cancelledCount = this._pending.size;
const entries = [...this._pending.entries()]; // Copy to avoid modification during iteration
- for (const [correlationId, entry] of entries) {
+ entries.forEach(([correlationId, entry]) => {
// Clear timer if it exists
if (entry.timer) {
clearTimeout(entry.timer);
@@ -1763,7 +1803,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
});
});
}
- }
+ });
this._pending.clear();
return cancelledCount;
}
@@ -1797,9 +1837,9 @@ class OptaveJavaScriptSDK extends EventEmitter {
// This prevents the complex removeAllListeners override from interfering
if (this._events) {
// Manually clear each event to break listener references
- for (const event in this._events) {
+ Object.keys(this._events).forEach((event) => {
delete this._events[event];
- }
+ });
}
// Now remove all listeners (this should be mostly a no-op after manual cleanup)
@@ -1833,6 +1873,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
// Clear function references that might hold closures
this._validatePayload = null;
+ this._validateOutboundPayload = null;
this._validateMessageEnvelope = null;
this._emitError = null;
this._ensureWebSocketImpl = null;
@@ -1885,8 +1926,7 @@ class OptaveJavaScriptSDK extends EventEmitter {
// Static properties for build configuration flags (used by webpack DefinePlugin)
static get buildFlags() {
- const buildTarget =
- typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';
+ const buildTarget = typeof __WEBPACK_BUILD_TARGET__ !== 'undefined' ? __WEBPACK_BUILD_TARGET__ : 'unknown';
return {
SALESFORCE_BUILD: typeof __SALESFORCE_BUILD__ !== 'undefined' ? __SALESFORCE_BUILD__ : false,
diff --git a/sdks/javascript/runtime/core/security-guards.js b/sdks/javascript/runtime/core/security-guards.js
index a086cf5..bc11108 100644
--- a/sdks/javascript/runtime/core/security-guards.js
+++ b/sdks/javascript/runtime/core/security-guards.js
@@ -29,52 +29,57 @@ import { BuildTargetUtils } from './build-targets.js';
* @throws {Error} When tokenProvider is missing for secure connections in UMD builds
*/
export function enforceWebSocketScheme(websocketUrl, buildTarget, options = {}) {
- // SECURITY: Explicitly mark as having side effects - do not optimize away
- /* eslint-disable-next-line no-unused-expressions */
- true; // Side effect anchor
-
- if (!websocketUrl || typeof websocketUrl !== 'string') {
- return; // No validation needed if URL is not set or not a string
- }
-
- // Get build target information
- const normalizedTarget = BuildTargetUtils.normalize(buildTarget);
-
- // Check if this is a UMD build or browser environment that needs scheme validation
- const isUMDBuild = BuildTargetUtils.isUMD(normalizedTarget);
- const isBrowserBuild = BuildTargetUtils.isBrowser(normalizedTarget);
-
- // CRITICAL: Validate WebSocket scheme for UMD and browser builds
- // This guard prevents insecure connections in Salesforce Lightning
- if ((isUMDBuild || isBrowserBuild) && websocketUrl.startsWith('ws://')) {
- // SECURITY: This error message must remain intact to guide developers
- const errorMessage = `[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in UMD builds. ` +
- `Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. ` +
- `Please use secure WebSocket protocol (wss://) instead. ` +
- `Current URL: ${websocketUrl}`;
-
- // CRITICAL: This throw statement is a security boundary - must not be removed
- throw new Error(errorMessage);
- }
-
- // CRITICAL: For UMD builds with secure WebSocket URLs, validate token provider availability
- // This prevents authentication bypass in constrained environments
- if (isUMDBuild && websocketUrl.startsWith('wss://')) {
- const hasTokenProvider = typeof options.tokenProvider === 'function';
- const hasAuthDisabled = options.authRequired === false;
-
- if (!hasTokenProvider && !hasAuthDisabled) {
- // SECURITY: This error message must remain intact to guide developers
- const errorMessage = `[Optave SDK] UMD builds require a tokenProvider function for secure WebSocket connections. ` +
- `In constrained environments like Salesforce Lightning, authentication tokens must be obtained ` +
- `from your backend server. Please provide options.tokenProvider() that returns a valid token, ` +
- `or set options.authRequired = false to disable authentication. ` +
- `Current URL: ${websocketUrl}`;
-
- // CRITICAL: This throw statement is a security boundary - must not be removed
- throw new Error(errorMessage);
- }
+ // SECURITY: This function has observable side effects (throws on invalid schemes and
+ // sets a global marker via initializeSecurityGuards) so bundlers must not optimize it away.
+
+ if (!websocketUrl || typeof websocketUrl !== 'string') {
+ return; // No validation needed if URL is not set or not a string
+ }
+
+ // Get build target information
+ const normalizedTarget = BuildTargetUtils.normalize(buildTarget);
+
+ // Check if this is a browser-targeted build that needs scheme validation
+ // Browser builds include: browser-esm and browser-umd (Salesforce/Lightning)
+ // Server builds (server-esm, server-umd) are for Node.js and allow ws:// for testing
+ const isBrowserBuild = BuildTargetUtils.isBrowser(normalizedTarget);
+
+ // CRITICAL: Validate WebSocket scheme for browser-targeted builds only
+ // This guard prevents insecure connections in Salesforce Lightning and browser environments
+ // Server-targeted builds (server-umd for Node.js CommonJS) are exempt to allow local testing
+ if (isBrowserBuild && websocketUrl.startsWith('ws://')) {
+ // SECURITY: This error message must remain intact to guide developers
+ const errorMessage = '[Optave SDK] Insecure WebSocket protocol (ws://) is not allowed in browser builds. '
+ + 'Salesforce Lightning Locker Service blocks all ws:// connections for security reasons. '
+ + 'Please use secure WebSocket protocol (wss://) instead. '
+ + `Current URL: ${websocketUrl}`;
+
+ // CRITICAL: This throw statement is a security boundary - must not be removed
+ throw new Error(errorMessage);
+ }
+
+ // CRITICAL: For browser UMD builds with secure WebSocket URLs, validate token provider availability
+ // This prevents authentication bypass in constrained Salesforce Lightning environments
+ // Server UMD builds can use clientSecret authentication, so this check only applies to browser builds
+ const isUMDBuild = BuildTargetUtils.isUMD(normalizedTarget);
+ const isBrowserUMD = isBrowserBuild && isUMDBuild;
+
+ if (isBrowserUMD && websocketUrl.startsWith('wss://')) {
+ const hasTokenProvider = typeof options.tokenProvider === 'function';
+ const hasAuthDisabled = options.authRequired === false;
+
+ if (!hasTokenProvider && !hasAuthDisabled) {
+ // SECURITY: This error message must remain intact to guide developers
+ const errorMessage = '[Optave SDK] Browser UMD builds require a tokenProvider function for secure WebSocket connections. '
+ + 'In constrained environments like Salesforce Lightning, authentication tokens must be obtained '
+ + 'from your backend server. Please provide options.tokenProvider() that returns a valid token, '
+ + 'or set options.authRequired = false to disable authentication. '
+ + `Current URL: ${websocketUrl}`;
+
+ // CRITICAL: This throw statement is a security boundary - must not be removed
+ throw new Error(errorMessage);
}
+ }
}
/**
@@ -82,22 +87,17 @@ export function enforceWebSocketScheme(websocketUrl, buildTarget, options = {})
* This ensures the security validation code is evaluated and cannot be tree-shaken
*/
function initializeSecurityGuards() {
- // SECURITY: Module-level side effect to prevent tree-shaking
- if (typeof globalThis !== 'undefined') {
- // Mark security guards as active - this creates a side effect
- globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__ = true;
-
- // Force evaluation by accessing the global in a way that cannot be optimized away
- const guardMarker = globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__;
- if (!guardMarker) {
- throw new Error('Security guard initialization failed');
- }
- }
-
- // Additional side effect: log to console (only in debug mode)
- if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'development') {
- console.debug('Optave SDK security guards initialized');
+ // SECURITY: Module-level side effect to prevent tree-shaking
+ if (typeof globalThis !== 'undefined') {
+ // Mark security guards as active - this creates a side effect
+ globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__ = true;
+
+ // Force evaluation by accessing the global in a way that cannot be optimized away
+ const guardMarker = globalThis.__OPTAVE_SECURITY_GUARDS_ACTIVE__;
+ if (!guardMarker) {
+ throw new Error('Security guard initialization failed');
}
+ }
}
// Execute initialization to create side effects - MUST NOT BE OPTIMIZED AWAY
@@ -105,15 +105,18 @@ initializeSecurityGuards();
// Additional module-level side effect to ensure preservation
if (typeof window !== 'undefined') {
- // Browser environment - ensure security guards are active
- window.__OPTAVE_SECURITY_GUARDS_BROWSER__ = true;
-} else if (typeof global !== 'undefined') {
- // Node.js environment - ensure security guards are active
- global.__OPTAVE_SECURITY_GUARDS_NODE__ = true;
+ // Browser environment - ensure security guards are active
+ window.__OPTAVE_SECURITY_GUARDS_BROWSER__ = true;
+} else if (typeof globalThis !== 'undefined') {
+ // Node.js environment - ensure security guards are active.
+ // Use globalThis (=== Node `global`) instead of a bare `global`: a free `global`
+ // reference makes webpack inject its global-runtime helper, which relies on the
+ // Function constructor and would violate Salesforce Lightning Locker CSP.
+ globalThis.__OPTAVE_SECURITY_GUARDS_NODE__ = true;
}
/**
* Export validation for external use
* This provides a stable API for the main SDK class
*/
-export { enforceWebSocketScheme as validateWebSocketScheme };
\ No newline at end of file
+export { enforceWebSocketScheme as validateWebSocketScheme };
diff --git a/sdks/javascript/runtime/core/types.ts b/sdks/javascript/runtime/core/types.ts
index c6c73df..5e65b4b 100644
--- a/sdks/javascript/runtime/core/types.ts
+++ b/sdks/javascript/runtime/core/types.ts
@@ -98,12 +98,16 @@ export declare class OptaveJavaScriptSDK {
elevate(params: any): Promise;
customerInteraction(params: any): Promise;
interaction(params: any): Promise;
+ assistant(params: any): Promise;
reception(params: any): Promise;
summarize(params: any): Promise;
translate(params: any): Promise;
recommend(params: any): Promise;
insights(params: any): Promise;
+ // Promise-based action methods (suffix Async)
+ assistantAsync(params: any, opts?: any): Promise;
+
// Connection management
disconnect(): void;
isConnected(): boolean;
diff --git a/sdks/javascript/runtime/core/umd-entry.js b/sdks/javascript/runtime/core/umd-entry.js
index 6489a09..9726faf 100644
--- a/sdks/javascript/runtime/core/umd-entry.js
+++ b/sdks/javascript/runtime/core/umd-entry.js
@@ -5,13 +5,22 @@ import { OptaveJavaScriptSDK } from './main.js';
// Import crypto polyfill for side effects (sets up global crypto for UUID generation)
import '../platform/browser/crypto-polyfill.js';
-// To guarantee availability on globalThis in all environments (including AMD paths),
-// we perform an explicit, idempotent assignment here.
+// Expose the constructor on the browser global, preferring `window`.
+// Salesforce Lightning loads this UMD bundle as a static resource and reads
+// `window.OptaveJavaScriptSDK`; under Lightning Locker the component's global is
+// `window` (a SecureWindow), which is NOT guaranteed to be the same object as
+// `globalThis`. We assign to both `window` (browser/Salesforce) and `globalThis`
+// (Node, and web workers where globalThis === self), which together cover every
+// target. Idempotent and defensive.
+if (typeof window !== 'undefined' && !window.OptaveJavaScriptSDK) {
+ try {
+ window.OptaveJavaScriptSDK = OptaveJavaScriptSDK;
+ } catch { /* noop – defensive */ }
+}
if (typeof globalThis !== 'undefined' && !globalThis.OptaveJavaScriptSDK) {
- try {
- // Direct constructor reference for single-version policy
- globalThis.OptaveJavaScriptSDK = OptaveJavaScriptSDK;
- } catch { /* noop – defensive */ }
+ try {
+ globalThis.OptaveJavaScriptSDK = OptaveJavaScriptSDK;
+ } catch { /* noop – defensive */ }
}
// Export default for webpack UMD library.export: 'default'
diff --git a/sdks/javascript/runtime/platform/browser/ajv-stub.js b/sdks/javascript/runtime/platform/browser/ajv-stub.js
index d6f9322..2fec344 100644
--- a/sdks/javascript/runtime/platform/browser/ajv-stub.js
+++ b/sdks/javascript/runtime/platform/browser/ajv-stub.js
@@ -5,11 +5,11 @@
// Throw an error if AJV is somehow accessed in CSP-safe mode
export default function AjvStub() {
- throw new Error('AJV is not available in CSP-safe browser mode. Use browser-safe validators instead.');
+ throw new Error('AJV is not available in CSP-safe browser mode. Use browser-safe validators instead.');
}
// Mock other AJV exports that might be imported
export const Ajv = AjvStub;
export const addFormats = () => {
- throw new Error('AJV formats are not available in CSP-safe browser mode.');
-};
\ No newline at end of file
+ throw new Error('AJV formats are not available in CSP-safe browser mode.');
+};
diff --git a/sdks/javascript/runtime/platform/browser/crypto-polyfill.js b/sdks/javascript/runtime/platform/browser/crypto-polyfill.js
index 455e949..89d41db 100644
--- a/sdks/javascript/runtime/platform/browser/crypto-polyfill.js
+++ b/sdks/javascript/runtime/platform/browser/crypto-polyfill.js
@@ -1,207 +1,217 @@
+/* eslint-disable no-bitwise */
+// Bitwise operators below are intrinsic to the UUID v7 bit-field packing/PRNG algorithm and cannot be removed.
// Browser crypto polyfill for UUID v7 generation
// This provides a Node.js crypto compatible interface for browser environments
// UUID v7 implementation adapted from https://github.com/LiosK/uuidv7 (Apache-2.0 License)
-let cryptoImplementation;
-
-// Initialize crypto implementation with native or fallback methods
-if (typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.getRandomValues) {
- cryptoImplementation = globalThis.crypto;
-} else if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {
- cryptoImplementation = window.crypto;
-} else if (typeof self !== 'undefined' && self.crypto && self.crypto.getRandomValues) {
- cryptoImplementation = self.crypto;
-} else {
- // Fallback implementation using Math.random()
- cryptoImplementation = {
- getRandomValues: function(array) {
- for (let i = 0; i < array.length; i++) {
- array[i] = Math.floor(Math.random() * 256);
- }
- return array;
- }
- };
+// Resolve the crypto implementation once at module load. Returned from a function so the
+// module-level binding can be a const (avoids exporting a mutable `let`).
+function resolveCryptoImplementation() {
+ if (typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.getRandomValues) {
+ return globalThis.crypto;
+ }
+ if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {
+ return window.crypto;
+ }
+ if (typeof globalThis !== 'undefined' && globalThis.self
+ && globalThis.self.crypto && globalThis.self.crypto.getRandomValues) {
+ return globalThis.self.crypto;
+ }
+ // Fallback implementation using Math.random()
+ return {
+ getRandomValues(array) {
+ for (let i = 0; i < array.length; i += 1) {
+ array[i] = Math.floor(Math.random() * 256);
+ }
+ return array;
+ },
+ };
}
-// UUID v7 Generator class adapted from LiosK/uuidv7
-class V7Generator {
- constructor() {
- this.timestamp = 0;
- this.counter = 0;
- this.random = this._getRandomNumberGenerator();
- }
+const cryptoImplementation = resolveCryptoImplementation();
- _getRandomNumberGenerator() {
- if (typeof cryptoImplementation !== 'undefined' && typeof cryptoImplementation.getRandomValues !== 'undefined') {
- return new BufferedCryptoRandom();
- } else {
- // Fallback using Math.random()
- return {
- nextUint32: () => Math.trunc(Math.random() * 0x10000) * 0x10000 + Math.trunc(Math.random() * 0x10000)
- };
- }
- }
+// Buffered crypto random number generator.
+// Implemented as a factory (not a class) to keep this file within the single-class limit;
+// behavior is identical to the original `new BufferedCryptoRandom()` usage.
+function createBufferedCryptoRandom() {
+ const buffer = new Uint32Array(8);
+ let cursor = 0xffff;
- generate() {
- return this.generateOrResetCore(Date.now(), 10000);
- }
+ return {
+ nextUint32() {
+ if (cursor >= buffer.length) {
+ cryptoImplementation.getRandomValues(buffer);
+ cursor = 0;
+ }
+ const value = buffer[cursor];
+ cursor += 1;
+ return value;
+ },
+ };
+}
- generateOrResetCore(unixTsMs, rollbackAllowance) {
- let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
- if (value === undefined) {
- this.timestamp = 0;
- value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
- }
- return value;
+// UUID v7 Generator class adapted from LiosK/uuidv7
+class V7Generator {
+ constructor() {
+ this.timestamp = 0;
+ this.counter = 0;
+ this.random = this._getRandomNumberGenerator();
+ }
+
+ _getRandomNumberGenerator() {
+ if (typeof cryptoImplementation !== 'undefined' && typeof cryptoImplementation.getRandomValues !== 'undefined') {
+ return createBufferedCryptoRandom();
}
+ // Fallback using Math.random()
+ return {
+ nextUint32: () => Math.trunc(Math.random() * 0x10000) * 0x10000 + Math.trunc(Math.random() * 0x10000),
+ };
+ }
- generateOrAbortCore(unixTsMs, rollbackAllowance) {
- const MAX_COUNTER = 0x3fffffff_fff;
-
- if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 0xffffffffffff) {
- throw new RangeError('unixTsMs must be a 48-bit positive integer');
- }
-
- if (unixTsMs > this.timestamp) {
- this.timestamp = unixTsMs;
- this.resetCounter();
- } else if (unixTsMs + rollbackAllowance >= this.timestamp) {
- this.counter++;
- if (this.counter > MAX_COUNTER) {
- this.timestamp++;
- this.resetCounter();
- }
- } else {
- return undefined;
- }
-
- return this.fromFieldsV7(
- this.timestamp,
- Math.trunc(this.counter / (2 ** 30)),
- this.counter & (2 ** 30 - 1),
- this.random.nextUint32()
- );
- }
+ generate() {
+ return this.generateOrResetCore(Date.now(), 10000);
+ }
- resetCounter() {
- this.counter = this.random.nextUint32() * 0x400 + (this.random.nextUint32() & 0x3ff);
+ generateOrResetCore(unixTsMs, rollbackAllowance) {
+ let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
+ if (value === undefined) {
+ this.timestamp = 0;
+ value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
}
+ return value;
+ }
- fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
- const bytes = new Uint8Array(16);
- bytes[0] = unixTsMs / (2 ** 40);
- bytes[1] = unixTsMs / (2 ** 32);
- bytes[2] = unixTsMs / (2 ** 24);
- bytes[3] = unixTsMs / (2 ** 16);
- bytes[4] = unixTsMs / (2 ** 8);
- bytes[5] = unixTsMs;
- bytes[6] = 0x70 | (randA >>> 8);
- bytes[7] = randA;
- bytes[8] = 0x80 | (randBHi >>> 24);
- bytes[9] = randBHi >>> 16;
- bytes[10] = randBHi >>> 8;
- bytes[11] = randBHi;
- bytes[12] = randBLo >>> 24;
- bytes[13] = randBLo >>> 16;
- bytes[14] = randBLo >>> 8;
- bytes[15] = randBLo;
-
- return this.bytesToString(bytes);
- }
+ generateOrAbortCore(unixTsMs, rollbackAllowance) {
+ const MAX_COUNTER = 0x3fffffff_fff;
- bytesToString(bytes) {
- const hex = Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
- return [
- hex.substring(0, 8),
- hex.substring(8, 12),
- hex.substring(12, 16),
- hex.substring(16, 20),
- hex.substring(20, 32)
- ].join('-');
+ if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 0xffffffffffff) {
+ throw new RangeError('unixTsMs must be a 48-bit positive integer');
}
-}
-// Buffered crypto random number generator
-class BufferedCryptoRandom {
- constructor() {
- this.buffer = new Uint32Array(8);
- this.cursor = 0xffff;
+ if (unixTsMs > this.timestamp) {
+ this.timestamp = unixTsMs;
+ this.resetCounter();
+ } else if (unixTsMs + rollbackAllowance >= this.timestamp) {
+ this.counter++;
+ if (this.counter > MAX_COUNTER) {
+ this.timestamp++;
+ this.resetCounter();
+ }
+ } else {
+ return undefined;
}
- nextUint32() {
- if (this.cursor >= this.buffer.length) {
- cryptoImplementation.getRandomValues(this.buffer);
- this.cursor = 0;
- }
- return this.buffer[this.cursor++];
- }
+ return this.fromFieldsV7(
+ this.timestamp,
+ Math.trunc(this.counter / (2 ** 30)),
+ this.counter & (2 ** 30 - 1),
+ this.random.nextUint32(),
+ );
+ }
+
+ resetCounter() {
+ this.counter = this.random.nextUint32() * 0x400 + (this.random.nextUint32() & 0x3ff);
+ }
+
+ fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
+ const bytes = new Uint8Array(16);
+ bytes[0] = unixTsMs / (2 ** 40);
+ bytes[1] = unixTsMs / (2 ** 32);
+ bytes[2] = unixTsMs / (2 ** 24);
+ bytes[3] = unixTsMs / (2 ** 16);
+ bytes[4] = unixTsMs / (2 ** 8);
+ bytes[5] = unixTsMs;
+ bytes[6] = 0x70 | (randA >>> 8);
+ bytes[7] = randA;
+ bytes[8] = 0x80 | (randBHi >>> 24);
+ bytes[9] = randBHi >>> 16;
+ bytes[10] = randBHi >>> 8;
+ bytes[11] = randBHi;
+ bytes[12] = randBLo >>> 24;
+ bytes[13] = randBLo >>> 16;
+ bytes[14] = randBLo >>> 8;
+ bytes[15] = randBLo;
+
+ return this.bytesToString(bytes);
+ }
+
+ bytesToString(bytes) {
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
+ return [
+ hex.substring(0, 8),
+ hex.substring(8, 12),
+ hex.substring(12, 16),
+ hex.substring(16, 20),
+ hex.substring(20, 32),
+ ].join('-');
+ }
}
// Create default generator instance
let defaultGenerator = null;
// Override randomUUID and generateUUID to use UUID v7
-cryptoImplementation.randomUUID = function() {
- if (!defaultGenerator) {
- defaultGenerator = new V7Generator();
- }
- return defaultGenerator.generate();
+cryptoImplementation.randomUUID = function () {
+ if (!defaultGenerator) {
+ defaultGenerator = new V7Generator();
+ }
+ return defaultGenerator.generate();
};
-cryptoImplementation.generateUUID = function() {
- if (!defaultGenerator) {
- defaultGenerator = new V7Generator();
- }
- return defaultGenerator.generate();
+cryptoImplementation.generateUUID = function () {
+ if (!defaultGenerator) {
+ defaultGenerator = new V7Generator();
+ }
+ return defaultGenerator.generate();
};
// Generate short ID using UUID v7 for cryptographic security
// Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility
-cryptoImplementation.generateShortId = function() {
- return defaultGenerator.generate().replace(/-/g, '').substring(0, 9);
+cryptoImplementation.generateShortId = function () {
+ return defaultGenerator.generate().replace(/-/g, '').substring(0, 9);
};
// Ensure crypto is available globally for UUID library
// Check if crypto property is configurable before attempting to set it
function setSafeCrypto(globalObj, propName) {
- if (!globalObj || globalObj.crypto) return; // Already exists
-
- try {
- const descriptor = Object.getOwnPropertyDescriptor(globalObj, propName);
- if (!descriptor || descriptor.configurable !== false) {
- globalObj.crypto = cryptoImplementation;
- }
- } catch (error) {
- // Ignore errors when crypto property is read-only (e.g., in JSDOM)
- console.debug('Cannot set crypto property on', globalObj.constructor.name, ':', error.message);
+ if (!globalObj || globalObj.crypto) return; // Already exists
+
+ try {
+ const descriptor = Object.getOwnPropertyDescriptor(globalObj, propName);
+ if (!descriptor || descriptor.configurable !== false) {
+ globalObj.crypto = cryptoImplementation;
}
+ } catch {
+ // Ignore errors when crypto property is read-only (e.g., in JSDOM).
+ // No logger is available in this standalone polyfill, so swallow silently.
+ }
}
if (typeof globalThis !== 'undefined') {
- setSafeCrypto(globalThis, 'crypto');
+ setSafeCrypto(globalThis, 'crypto');
}
if (typeof window !== 'undefined') {
- setSafeCrypto(window, 'crypto');
+ setSafeCrypto(window, 'crypto');
}
-if (typeof self !== 'undefined') {
- setSafeCrypto(self, 'crypto');
+if (typeof globalThis !== 'undefined' && globalThis.self) {
+ setSafeCrypto(globalThis.self, 'crypto');
}
// Support both CommonJS and ES modules with environment detection
try {
- // Check if we're in a CommonJS environment where module.exports is writable
- if (typeof module !== 'undefined' && typeof module.exports === 'object' && typeof require !== 'undefined') {
- // CommonJS environment - try to assign, but catch any errors in case it's read-only
- module.exports = cryptoImplementation;
- module.exports.default = cryptoImplementation;
- module.exports.getRandomValues = cryptoImplementation.getRandomValues.bind(cryptoImplementation);
- module.exports.randomUUID = cryptoImplementation.randomUUID ? cryptoImplementation.randomUUID.bind(cryptoImplementation) : cryptoImplementation.randomUUID;
- module.exports.generateUUID = cryptoImplementation.generateUUID.bind(cryptoImplementation);
- module.exports.generateShortId = cryptoImplementation.generateShortId.bind(cryptoImplementation);
- }
+ // Check if we're in a CommonJS environment where module.exports is writable
+ if (typeof module !== 'undefined' && typeof module.exports === 'object' && typeof require !== 'undefined') {
+ // CommonJS environment - try to assign, but catch any errors in case it's read-only
+ module.exports = cryptoImplementation;
+ module.exports.default = cryptoImplementation;
+ module.exports.getRandomValues = cryptoImplementation.getRandomValues.bind(cryptoImplementation);
+ module.exports.randomUUID = cryptoImplementation.randomUUID ? cryptoImplementation.randomUUID.bind(cryptoImplementation) : cryptoImplementation.randomUUID;
+ module.exports.generateUUID = cryptoImplementation.generateUUID.bind(cryptoImplementation);
+ module.exports.generateShortId = cryptoImplementation.generateShortId.bind(cryptoImplementation);
+ }
} catch (e) {
- // ES module environment where module.exports is read-only - ignore the error
- // ES module exports will be used instead
+ // ES module environment where module.exports is read-only - ignore the error
+ // ES module exports will be used instead
}
// ES module exports for compatibility
@@ -211,4 +221,4 @@ export const generateUUID = cryptoImplementation.generateUUID.bind(cryptoImpleme
export const generateShortId = cryptoImplementation.generateShortId.bind(cryptoImplementation);
// Default export for integration compatibility
-export default cryptoImplementation;
\ No newline at end of file
+export default cryptoImplementation;
diff --git a/sdks/javascript/runtime/platform/browser/errors.js b/sdks/javascript/runtime/platform/browser/errors.js
index b18e4be..d2d77f4 100644
--- a/sdks/javascript/runtime/platform/browser/errors.js
+++ b/sdks/javascript/runtime/platform/browser/errors.js
@@ -8,7 +8,9 @@ class OptaveError extends Error {
* @param {string} params.message
* @param {any} [params.details]
*/
- constructor({ category, code, message, details }) {
+ constructor({
+ category, code, message, details,
+ }) {
super(message);
this.name = 'OptaveError';
this.category = category || 'UNKNOWN';
@@ -32,13 +34,19 @@ function makeStructuredError(raw) {
}
// No AJV ValidationError handling in CSP-safe mode
if (raw && raw.isAuthError) {
- return new OptaveError({ category: 'AUTHENTICATION', code: raw.code || 'AUTH_ERROR', message: raw.message || 'Authentication error', details: raw });
+ return new OptaveError({
+ category: 'AUTHENTICATION', code: raw.code || 'AUTH_ERROR', message: raw.message || 'Authentication error', details: raw,
+ });
}
if (raw && raw.isWsError) {
- return new OptaveError({ category: 'WEBSOCKET', code: raw.code || 'WS_ERROR', message: raw.message || 'WebSocket error', details: raw });
+ return new OptaveError({
+ category: 'WEBSOCKET', code: raw.code || 'WS_ERROR', message: raw.message || 'WebSocket error', details: raw,
+ });
}
// Default
- return new OptaveError({ category: 'UNKNOWN', code: 'UNCLASSIFIED', message: (raw && raw.message) || String(raw !== null && raw !== undefined ? raw : 'Unknown error'), details: raw });
+ return new OptaveError({
+ category: 'UNKNOWN', code: 'UNCLASSIFIED', message: (raw && raw.message) || String(raw !== null && raw !== undefined ? raw : 'Unknown error'), details: raw,
+ });
}
-export { OptaveError, makeStructuredError };
\ No newline at end of file
+export { OptaveError, makeStructuredError };
diff --git a/sdks/javascript/runtime/platform/browser/event-emitter.js b/sdks/javascript/runtime/platform/browser/event-emitter.js
index f39ad7b..26bf999 100644
--- a/sdks/javascript/runtime/platform/browser/event-emitter.js
+++ b/sdks/javascript/runtime/platform/browser/event-emitter.js
@@ -3,100 +3,99 @@
* Provides Node.js EventEmitter API using DOM EventTarget
*/
export default class EventEmitter extends EventTarget {
- constructor() {
- super();
- this._events = {};
- this._eventsCount = 0; // Node.js EventEmitter compatibility
- }
-
- on(event, listener) {
- if (!this._events[event]) {
- this._events[event] = [];
- }
- this._events[event].push(listener);
- this._eventsCount++; // Update count for Node.js compatibility
-
- // Wrap listener to handle CustomEvent.detail extraction
- const wrappedListener = (customEvent) => {
- if (customEvent.detail && Array.isArray(customEvent.detail)) {
- listener(...customEvent.detail);
- } else {
- listener(customEvent.detail || customEvent);
- }
- };
+ constructor() {
+ super();
+ this._events = {};
+ this._eventsCount = 0; // Node.js EventEmitter compatibility
+ }
- // Store the wrapped listener for removal
- listener._wrapped = wrappedListener;
- this.addEventListener(event, wrappedListener);
- return this;
+ on(event, listener) {
+ if (!this._events[event]) {
+ this._events[event] = [];
}
+ this._events[event].push(listener);
+ this._eventsCount++; // Update count for Node.js compatibility
- off(event, listener) {
- if (this._events[event]) {
- const index = this._events[event].indexOf(listener);
- if (index > -1) {
- this._events[event].splice(index, 1);
- this._eventsCount--; // Update count for Node.js compatibility
+ // Wrap listener to handle CustomEvent.detail extraction
+ const wrappedListener = (customEvent) => {
+ if (customEvent.detail && Array.isArray(customEvent.detail)) {
+ listener(...customEvent.detail);
+ } else {
+ listener(customEvent.detail || customEvent);
+ }
+ };
- // Clean up empty event arrays
- if (this._events[event].length === 0) {
- delete this._events[event];
- }
- }
- }
+ // Store the wrapped listener for removal
+ listener._wrapped = wrappedListener;
+ this.addEventListener(event, wrappedListener);
+ return this;
+ }
- // Remove the wrapped listener
- if (listener._wrapped) {
- this.removeEventListener(event, listener._wrapped);
- delete listener._wrapped;
+ off(event, listener) {
+ if (this._events[event]) {
+ const index = this._events[event].indexOf(listener);
+ if (index > -1) {
+ this._events[event].splice(index, 1);
+ this._eventsCount--; // Update count for Node.js compatibility
+
+ // Clean up empty event arrays
+ if (this._events[event].length === 0) {
+ delete this._events[event];
}
- return this;
+ }
}
- removeListener(event, listener) {
- return this.off(event, listener);
+ // Remove the wrapped listener
+ if (listener._wrapped) {
+ this.removeEventListener(event, listener._wrapped);
+ delete listener._wrapped;
}
+ return this;
+ }
- emit(event, ...args) {
- // Use only DOM EventTarget dispatch to avoid double execution
- // The wrapped listeners will handle calling the original listeners
- const customEvent = new CustomEvent(event, { detail: args });
- this.dispatchEvent(customEvent);
- return this;
- }
+ removeListener(event, listener) {
+ return this.off(event, listener);
+ }
- once(event, listener) {
- const onceListener = (...args) => {
- this.off(event, onceListener); // This will properly update _eventsCount
- listener(...args);
- };
- return this.on(event, onceListener); // This will properly update _eventsCount
- }
+ emit(event, ...args) {
+ // Use only DOM EventTarget dispatch to avoid double execution
+ // The wrapped listeners will handle calling the original listeners
+ const customEvent = new CustomEvent(event, { detail: args });
+ this.dispatchEvent(customEvent);
+ return this;
+ }
- listenerCount(event) {
- return this._events[event] ? this._events[event].length : 0;
- }
+ once(event, listener) {
+ const onceListener = (...args) => {
+ this.off(event, onceListener); // This will properly update _eventsCount
+ listener(...args);
+ };
+ return this.on(event, onceListener); // This will properly update _eventsCount
+ }
- removeAllListeners(event) {
- if (event) {
- if (this._events[event]) {
- const count = this._events[event].length;
- this._events[event].forEach(listener => {
- // Remove wrapped listeners from DOM
- if (listener._wrapped) {
- this.removeEventListener(event, listener._wrapped);
- delete listener._wrapped;
- }
- });
- delete this._events[event];
- this._eventsCount = Math.max(0, this._eventsCount - count); // Update count
- }
- } else {
- // Remove all events
- const totalCount = Object.values(this._events).reduce((sum, listeners) => sum + listeners.length, 0);
- Object.keys(this._events).forEach(e => this.removeAllListeners(e));
- this._eventsCount = 0; // Reset to 0 when all listeners removed
- }
- return this;
+ listenerCount(event) {
+ return this._events[event] ? this._events[event].length : 0;
+ }
+
+ removeAllListeners(event) {
+ if (event) {
+ if (this._events[event]) {
+ const count = this._events[event].length;
+ this._events[event].forEach((listener) => {
+ // Remove wrapped listeners from DOM
+ if (listener._wrapped) {
+ this.removeEventListener(event, listener._wrapped);
+ delete listener._wrapped;
+ }
+ });
+ delete this._events[event];
+ this._eventsCount = Math.max(0, this._eventsCount - count); // Update count
+ }
+ } else {
+ // Remove all events
+ Object.keys(this._events).forEach((e) => this.removeAllListeners(e));
+ this._eventsCount = 0; // Reset to 0 when all listeners removed
}
-}
\ No newline at end of file
+ return this;
+ }
+}
diff --git a/sdks/javascript/runtime/platform/browser/urlsearchparams-polyfill.js b/sdks/javascript/runtime/platform/browser/urlsearchparams-polyfill.js
index c5f528c..3346ee2 100644
--- a/sdks/javascript/runtime/platform/browser/urlsearchparams-polyfill.js
+++ b/sdks/javascript/runtime/platform/browser/urlsearchparams-polyfill.js
@@ -4,119 +4,123 @@
*/
export default class URLSearchParamsPolyfill {
- constructor(init) {
- this.params = new Map();
+ constructor(init) {
+ this.params = new Map();
- if (typeof init === 'string') {
- // Parse query string
- const pairs = init.replace(/^\?/, '').split('&');
- pairs.forEach(pair => {
- if (pair) {
- const [key, value] = pair.split('=');
- if (key) {
- this.params.set(
- decodeURIComponent(key),
- decodeURIComponent(value || '')
- );
- }
- }
- });
- } else if (init && typeof init === 'object') {
- // Handle object initialization
- if (init instanceof Map) {
- init.forEach((value, key) => {
- this.params.set(key, String(value));
- });
- } else if (Array.isArray(init)) {
- // Handle array of [key, value] pairs
- init.forEach(([key, value]) => {
- this.params.set(key, String(value));
- });
- } else {
- // Handle plain object
- Object.entries(init).forEach(([key, value]) => {
- this.params.set(key, String(value));
- });
- }
+ if (typeof init === 'string') {
+ // Parse query string
+ const pairs = init.replace(/^\?/, '').split('&');
+ pairs.forEach((pair) => {
+ if (pair) {
+ const [key, value] = pair.split('=');
+ if (key) {
+ this.params.set(
+ decodeURIComponent(key),
+ decodeURIComponent(value || ''),
+ );
+ }
}
+ });
+ } else if (init && typeof init === 'object') {
+ // Handle object initialization
+ if (init instanceof Map) {
+ init.forEach((value, key) => {
+ this.params.set(key, String(value));
+ });
+ } else if (Array.isArray(init)) {
+ // Handle array of [key, value] pairs
+ init.forEach(([key, value]) => {
+ this.params.set(key, String(value));
+ });
+ } else {
+ // Handle plain object
+ Object.entries(init).forEach(([key, value]) => {
+ this.params.set(key, String(value));
+ });
+ }
}
+ }
- append(name, value) {
- const existing = this.params.get(name);
- if (existing !== undefined) {
- this.params.set(name, existing + ',' + String(value));
- } else {
- this.params.set(name, String(value));
- }
+ append(name, value) {
+ const existing = this.params.get(name);
+ if (existing !== undefined) {
+ this.params.set(name, `${existing},${String(value)}`);
+ } else {
+ this.params.set(name, String(value));
}
+ }
- delete(name) {
- this.params.delete(name);
- }
+ delete(name) {
+ this.params.delete(name);
+ }
- get(name) {
- return this.params.get(name) || null;
- }
+ get(name) {
+ return this.params.get(name) || null;
+ }
- getAll(name) {
- const value = this.params.get(name);
- return value ? value.split(',') : [];
- }
+ getAll(name) {
+ const value = this.params.get(name);
+ return value ? value.split(',') : [];
+ }
- has(name) {
- return this.params.has(name);
- }
+ has(name) {
+ return this.params.has(name);
+ }
- set(name, value) {
- this.params.set(name, String(value));
- }
+ set(name, value) {
+ this.params.set(name, String(value));
+ }
- toString() {
- const pairs = [];
- this.params.forEach((value, key) => {
- // Handle comma-separated values (from append)
- const values = value.split(',');
- values.forEach(val => {
- pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(val)}`);
- });
- });
- return pairs.join('&');
- }
+ toString() {
+ const pairs = [];
+ this.params.forEach((value, key) => {
+ // Handle comma-separated values (from append)
+ const values = value.split(',');
+ values.forEach((val) => {
+ pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(val)}`);
+ });
+ });
+ return pairs.join('&');
+ }
- *[Symbol.iterator]() {
- for (const [key, value] of this.params) {
- // Handle comma-separated values (from append)
- const values = value.split(',');
- for (const val of values) {
- yield [key, val];
- }
- }
+ * [Symbol.iterator]() {
+ const paramEntries = Array.from(this.params);
+ for (let i = 0; i < paramEntries.length; i += 1) {
+ const [key, value] = paramEntries[i];
+ // Handle comma-separated values (from append)
+ const values = value.split(',');
+ for (let j = 0; j < values.length; j += 1) {
+ yield [key, values[j]];
+ }
}
+ }
- *keys() {
- for (const [key] of this) {
- yield key;
- }
+ * keys() {
+ const all = Array.from(this);
+ for (let i = 0; i < all.length; i += 1) {
+ yield all[i][0];
}
+ }
- *values() {
- for (const [, value] of this) {
- yield value;
- }
+ * values() {
+ const all = Array.from(this);
+ for (let i = 0; i < all.length; i += 1) {
+ yield all[i][1];
}
+ }
- *entries() {
- yield* this;
- }
+ * entries() {
+ yield* this;
+ }
- forEach(callback, thisArg) {
- for (const [key, value] of this) {
- callback.call(thisArg, value, key, this);
- }
- }
+ forEach(callback, thisArg) {
+ Array.from(this).forEach(([key, value]) => {
+ callback.call(thisArg, value, key, this);
+ });
+ }
}
// Provide a fallback that uses native URLSearchParams if available, otherwise the polyfill
-export const URLSearchParams = (typeof globalThis !== 'undefined' && globalThis.URLSearchParams) ||
- (typeof window !== 'undefined' && window.URLSearchParams) ||
- URLSearchParamsPolyfill;
\ No newline at end of file
+export const URLSearchParams = (typeof globalThis !== 'undefined' && globalThis.URLSearchParams)
+ || (typeof window !== 'undefined' && window.URLSearchParams)
+ || URLSearchParamsPolyfill;
diff --git a/sdks/javascript/runtime/platform/browser/validators.js b/sdks/javascript/runtime/platform/browser/validators.js
index b061b05..6b024df 100644
--- a/sdks/javascript/runtime/platform/browser/validators.js
+++ b/sdks/javascript/runtime/platform/browser/validators.js
@@ -1,177 +1,219 @@
/**
- * Browser-compatible validator implementation
- * Provides comprehensive validation without AJV dependency
- * This implementation must match the server-side validation logic for security
+ * CSP-safe validator implementation (no eval/Function constructor)
+ *
+ * Used by all builds that require Content Security Policy compliance:
+ * - Browser ESM (browser.mjs)
+ * - Browser UMD (browser.umd.js) - Salesforce Lightning
+ * - Server UMD (server.umd.js) - Node.js CommonJS
+ *
+ * Provides comprehensive validation without AJV dependency.
+ * Server ESM (server.mjs) uses full AJV validation instead.
+ *
+ * This implementation must match the server-side validation logic for security.
*/
// Helper function to create AJV-compatible error objects
function createError(instancePath, message, keyword = 'validation', params = {}) {
- return {
- instancePath,
- message,
- keyword,
- params
- };
+ return {
+ instancePath,
+ message,
+ keyword,
+ params,
+ };
}
// Validates payload structure and required fields
export function validatePayload(data) {
- if (!data || typeof data !== 'object') {
- return { valid: false, errors: [createError('', 'must be object', 'type', { type: 'object' })] };
- }
-
- const errors = [];
-
- // Session validation
- if (!data.session) {
- errors.push(createError('/session', 'is required', 'required', { missingProperty: 'session' }));
- } else if (typeof data.session !== 'object') {
- errors.push(createError('/session', 'must be object', 'type', { type: 'object' }));
+ if (!data || typeof data !== 'object') {
+ return { valid: false, errors: [createError('', 'must be object', 'type', { type: 'object' })] };
+ }
+
+ const errors = [];
+
+ // Session validation
+ if (!data.session) {
+ errors.push(createError('/session', 'is required', 'required', { missingProperty: 'session' }));
+ } else if (typeof data.session !== 'object') {
+ errors.push(createError('/session', 'must be object', 'type', { type: 'object' }));
+ } else if (data.session.sessionId !== undefined && typeof data.session.sessionId !== 'string') {
+ // sessionId validation (optional)
+ errors.push(createError('/session/sessionId', 'must be string', 'type', { type: 'string' }));
+ }
+
+ // Request validation
+ if (!data.request) {
+ errors.push(createError('/request', 'is required', 'required', { missingProperty: 'request' }));
+ } else if (typeof data.request !== 'object') {
+ errors.push(createError('/request', 'must be object', 'type', { type: 'object' }));
+ } else {
+ // Connections validation
+ if (!data.request.connections) {
+ errors.push(createError('/request/connections', 'is required', 'required', { missingProperty: 'connections' }));
+ } else if (typeof data.request.connections !== 'object') {
+ errors.push(createError('/request/connections', 'must be object', 'type', { type: 'object' }));
} else {
- // sessionId validation (optional)
- if (data.session.sessionId !== undefined && typeof data.session.sessionId !== 'string') {
- errors.push(createError('/session/sessionId', 'must be string', 'type', { type: 'string' }));
+ // threadId validation - required for ALL actions per SDK logic
+ if (!data.request.connections.threadId) {
+ errors.push(createError('/request/connections/threadId', 'is required', 'required', { missingProperty: 'threadId' }));
+ } else if (typeof data.request.connections.threadId !== 'string') {
+ errors.push(createError('/request/connections/threadId', 'must be string', 'type', { type: 'string' }));
+ }
+
+ // parentId type validation (if present)
+ if (data.request.connections.parentId !== undefined && typeof data.request.connections.parentId !== 'string') {
+ errors.push(createError('/request/connections/parentId', 'must be string', 'type', { type: 'string' }));
+ }
+
+ // replyId: optional opaque string, same treatment as parentId.
+ if (data.request.connections.replyId !== undefined && typeof data.request.connections.replyId !== 'string') {
+ errors.push(createError('/request/connections/replyId', 'must be string', 'type', { type: 'string' }));
+ }
+
+ // replyTarget: deprecated 3.5.0 alias for attributes.replyTo. Same closed enum.
+ const { replyTarget } = data.request.connections;
+ if (replyTarget !== undefined) {
+ const allowedReplyTargets = ['ai', 'self', 'none'];
+ if (typeof replyTarget !== 'string') {
+ errors.push(createError('/request/connections/replyTarget', 'must be string', 'type', { type: 'string' }));
+ } else if (!allowedReplyTargets.includes(replyTarget)) {
+ errors.push(createError(
+ '/request/connections/replyTarget',
+ 'must be equal to one of the allowed values',
+ 'enum',
+ { allowedValues: allowedReplyTargets },
+ ));
}
+ }
}
- // Request validation
- if (!data.request) {
- errors.push(createError('/request', 'is required', 'required', { missingProperty: 'request' }));
- } else if (typeof data.request !== 'object') {
- errors.push(createError('/request', 'must be object', 'type', { type: 'object' }));
- } else {
- // Connections validation
- if (!data.request.connections) {
- errors.push(createError('/request/connections', 'is required', 'required', { missingProperty: 'connections' }));
- } else if (typeof data.request.connections !== 'object') {
- errors.push(createError('/request/connections', 'must be object', 'type', { type: 'object' }));
- } else {
- // threadId validation - required for ALL actions per SDK logic
- if (!data.request.connections.threadId) {
- errors.push(createError('/request/connections/threadId', 'is required', 'required', { missingProperty: 'threadId' }));
- } else if (typeof data.request.connections.threadId !== 'string') {
- errors.push(createError('/request/connections/threadId', 'must be string', 'type', { type: 'string' }));
- }
-
- // parentId type validation (if present)
- if (data.request.connections.parentId !== undefined && typeof data.request.connections.parentId !== 'string') {
- errors.push(createError('/request/connections/parentId', 'must be string', 'type', { type: 'string' }));
- }
- }
-
- // Context validation (if present)
- if (data.request.context !== undefined && typeof data.request.context !== 'object') {
- errors.push(createError('/request/context', 'must be object', 'type', { type: 'object' }));
- }
+ // Context validation (if present)
+ if (data.request.context !== undefined && typeof data.request.context !== 'object') {
+ errors.push(createError('/request/context', 'must be object', 'type', { type: 'object' }));
+ }
- // Attributes validation (if present)
- if (data.request.attributes !== undefined && typeof data.request.attributes !== 'object') {
- errors.push(createError('/request/attributes', 'must be object', 'type', { type: 'object' }));
+ // Attributes validation (if present)
+ if (data.request.attributes !== undefined && typeof data.request.attributes !== 'object') {
+ errors.push(createError('/request/attributes', 'must be object', 'type', { type: 'object' }));
+ } else if (data.request.attributes && typeof data.request.attributes === 'object') {
+ // replyTo: optional closed enum. Omit when not reported (absent !== "none").
+ // Empty string is not in the enum — match AJV, do not treat it as absent.
+ const { replyTo } = data.request.attributes;
+ if (replyTo !== undefined) {
+ const allowedReplyTo = ['ai', 'self', 'none'];
+ if (typeof replyTo !== 'string') {
+ errors.push(createError('/request/attributes/replyTo', 'must be string', 'type', { type: 'string' }));
+ } else if (!allowedReplyTo.includes(replyTo)) {
+ errors.push(createError(
+ '/request/attributes/replyTo',
+ 'must be equal to one of the allowed values',
+ 'enum',
+ { allowedValues: allowedReplyTo },
+ ));
}
+ }
+ }
- // Scope validation (if present)
- if (data.request.scope !== undefined) {
- if (typeof data.request.scope !== 'object') {
- errors.push(createError('/request/scope', 'must be object', 'type', { type: 'object' }));
- } else if (data.request.scope.conversations !== undefined) {
- if (!Array.isArray(data.request.scope.conversations)) {
- errors.push(createError('/request/scope/conversations', 'must be array', 'type', { type: 'array' }));
- }
- }
+ // Scope validation (if present)
+ if (data.request.scope !== undefined) {
+ if (typeof data.request.scope !== 'object') {
+ errors.push(createError('/request/scope', 'must be object', 'type', { type: 'object' }));
+ } else if (data.request.scope.conversations !== undefined) {
+ if (!Array.isArray(data.request.scope.conversations)) {
+ errors.push(createError('/request/scope/conversations', 'must be array', 'type', { type: 'array' }));
}
+ }
+ }
- // Resources validation (if present)
- if (data.request.resources !== undefined) {
- if (typeof data.request.resources !== 'object') {
- errors.push(createError('/request/resources', 'must be object', 'type', { type: 'object' }));
- } else if (data.request.resources.offers !== undefined) {
- if (!Array.isArray(data.request.resources.offers)) {
- errors.push(createError('/request/resources/offers', 'must be array', 'type', { type: 'array' }));
- }
- }
+ // Resources validation (if present)
+ if (data.request.resources !== undefined) {
+ if (typeof data.request.resources !== 'object') {
+ errors.push(createError('/request/resources', 'must be object', 'type', { type: 'object' }));
+ } else if (data.request.resources.offers !== undefined) {
+ if (!Array.isArray(data.request.resources.offers)) {
+ errors.push(createError('/request/resources/offers', 'must be array', 'type', { type: 'array' }));
}
+ }
}
+ }
- return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };
+ return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };
}
export function validateMessageEnvelope(data) {
- if (!data || typeof data !== 'object') {
- return { valid: false, errors: [createError('', 'must be object', 'type', { type: 'object' })] };
+ if (!data || typeof data !== 'object') {
+ return { valid: false, errors: [createError('', 'must be object', 'type', { type: 'object' })] };
+ }
+
+ const errors = [];
+
+ // Headers validation
+ if (!data.headers) {
+ errors.push(createError('/headers', 'is required', 'required', { missingProperty: 'headers' }));
+ } else if (typeof data.headers !== 'object') {
+ errors.push(createError('/headers', 'must be object', 'type', { type: 'object' }));
+ } else {
+ // correlationId validation
+ if (!data.headers.correlationId) {
+ errors.push(createError('/headers/correlationId', 'is required', 'required', { missingProperty: 'correlationId' }));
+ } else if (typeof data.headers.correlationId !== 'string') {
+ errors.push(createError('/headers/correlationId', 'must be string', 'type', { type: 'string' }));
}
- const errors = [];
-
- // Headers validation
- if (!data.headers) {
- errors.push(createError('/headers', 'is required', 'required', { missingProperty: 'headers' }));
- } else if (typeof data.headers !== 'object') {
- errors.push(createError('/headers', 'must be object', 'type', { type: 'object' }));
+ // action validation
+ if (!data.headers.action) {
+ errors.push(createError('/headers/action', 'is required', 'required', { missingProperty: 'action' }));
+ } else if (typeof data.headers.action !== 'string') {
+ errors.push(createError('/headers/action', 'must be string', 'type', { type: 'string' }));
} else {
- // correlationId validation
- if (!data.headers.correlationId) {
- errors.push(createError('/headers/correlationId', 'is required', 'required', { missingProperty: 'correlationId' }));
- } else if (typeof data.headers.correlationId !== 'string') {
- errors.push(createError('/headers/correlationId', 'must be string', 'type', { type: 'string' }));
- }
-
- // action validation
- if (!data.headers.action) {
- errors.push(createError('/headers/action', 'is required', 'required', { missingProperty: 'action' }));
- } else if (typeof data.headers.action !== 'string') {
- errors.push(createError('/headers/action', 'must be string', 'type', { type: 'string' }));
- } else {
- // Validate allowed actions
- const allowedActions = ['adjust', 'elevate', 'interaction', 'customerinteraction', 'reception', 'summarize', 'translate', 'recommend', 'insights'];
- if (!allowedActions.includes(data.headers.action)) {
- errors.push(createError('/headers/action', 'must be equal to one of the allowed values', 'enum', { allowedValues: allowedActions }));
- }
- }
-
- // Optional fields validation
- if (data.headers.identifier !== undefined && typeof data.headers.identifier !== 'string') {
- errors.push(createError('/headers/identifier', 'must be string', 'type', { type: 'string' }));
- }
+ // Validate allowed actions
+ const allowedActions = ['adjust', 'elevate', 'interaction', 'assistant', 'customerinteraction', 'reception', 'summarize', 'translate', 'recommend', 'insights'];
+ if (!allowedActions.includes(data.headers.action)) {
+ errors.push(createError('/headers/action', 'must be equal to one of the allowed values', 'enum', { allowedValues: allowedActions }));
+ }
+ }
- if (data.headers.schemaRef !== undefined && typeof data.headers.schemaRef !== 'string') {
- errors.push(createError('/headers/schemaRef', 'must be string', 'type', { type: 'string' }));
- }
+ // Optional fields validation
+ if (data.headers.identifier !== undefined && typeof data.headers.identifier !== 'string') {
+ errors.push(createError('/headers/identifier', 'must be string', 'type', { type: 'string' }));
+ }
- if (data.headers.timestamp !== undefined && typeof data.headers.timestamp !== 'string') {
- errors.push(createError('/headers/timestamp', 'must be string', 'type', { type: 'string' }));
- }
+ if (data.headers.schemaRef !== undefined && typeof data.headers.schemaRef !== 'string') {
+ errors.push(createError('/headers/schemaRef', 'must be string', 'type', { type: 'string' }));
}
- // Payload validation
- if (!data.payload) {
- errors.push(createError('/payload', 'is required', 'required', { missingProperty: 'payload' }));
- } else if (typeof data.payload !== 'object') {
- errors.push(createError('/payload', 'must be object', 'type', { type: 'object' }));
- } else {
- // Action-specific conversation validation
- if (data.headers && data.headers.action && data.payload) {
- const action = data.headers.action;
- const requiresConversations = ['adjust', 'elevate', 'interaction', 'customerinteraction', 'customerInteraction', 'summarize', 'translate', 'insights', 'recommend'];
-
- if (requiresConversations.includes(action)) {
- if (!data.payload.request) {
- errors.push(createError('/payload/request', 'is required', 'required', { missingProperty: 'request' }));
- } else if (!data.payload.request.scope) {
- errors.push(createError('/payload/request/scope', 'is required', 'required', { missingProperty: 'scope' }));
- } else if (!data.payload.request.scope.conversations) {
- errors.push(createError('/payload/request/scope/conversations', `is required for ${action}`, 'required', { missingProperty: 'conversations' }));
- } else if (!Array.isArray(data.payload.request.scope.conversations)) {
- errors.push(createError('/payload/request/scope/conversations', 'must be array', 'type', { type: 'array' }));
- } else if (data.payload.request.scope.conversations.length === 0) {
- errors.push(createError('/payload/request/scope/conversations', `must be non-empty array for ${action}`, 'minItems', { limit: 1 }));
- }
- }
- }
+ if (data.headers.timestamp !== undefined && typeof data.headers.timestamp !== 'string') {
+ errors.push(createError('/headers/timestamp', 'must be string', 'type', { type: 'string' }));
+ }
+ }
+
+ // Payload validation
+ if (!data.payload) {
+ errors.push(createError('/payload', 'is required', 'required', { missingProperty: 'payload' }));
+ } else if (typeof data.payload !== 'object') {
+ errors.push(createError('/payload', 'must be object', 'type', { type: 'object' }));
+ } else if (data.headers && data.headers.action && data.payload) {
+ // Action-specific conversation validation
+ const { action } = data.headers;
+ const requiresConversations = ['adjust', 'elevate', 'interaction', 'assistant', 'customerinteraction', 'customerInteraction', 'summarize', 'translate', 'insights', 'recommend'];
+
+ if (requiresConversations.includes(action)) {
+ if (!data.payload.request) {
+ errors.push(createError('/payload/request', 'is required', 'required', { missingProperty: 'request' }));
+ } else if (!data.payload.request.scope) {
+ errors.push(createError('/payload/request/scope', 'is required', 'required', { missingProperty: 'scope' }));
+ } else if (!data.payload.request.scope.conversations) {
+ errors.push(createError('/payload/request/scope/conversations', `is required for ${action}`, 'required', { missingProperty: 'conversations' }));
+ } else if (!Array.isArray(data.payload.request.scope.conversations)) {
+ errors.push(createError('/payload/request/scope/conversations', 'must be array', 'type', { type: 'array' }));
+ } else if (data.payload.request.scope.conversations.length === 0) {
+ errors.push(createError('/payload/request/scope/conversations', `must be non-empty array for ${action}`, 'minItems', { limit: 1 }));
+ }
}
+ }
- return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };
+ return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };
}
// Validator functions are already exported above
-export const availableValidators = ['Payload', 'MessageEnvelope'];
\ No newline at end of file
+export const availableValidators = ['Payload', 'MessageEnvelope'];
diff --git a/sdks/javascript/runtime/platform/browser/websocket-loader.js b/sdks/javascript/runtime/platform/browser/websocket-loader.js
index 391465e..c6ebdb0 100644
--- a/sdks/javascript/runtime/platform/browser/websocket-loader.js
+++ b/sdks/javascript/runtime/platform/browser/websocket-loader.js
@@ -1,5 +1,5 @@
// Browser WebSocket loader - always returns null since browsers use native WebSocket
-export async function loadNodeWebSocket() {
- // Always return null in browser environments
- return null;
-}
\ No newline at end of file
+export default async function loadNodeWebSocket() {
+ // Always return null in browser environments
+ return null;
+}
diff --git a/sdks/javascript/runtime/platform/environment-adapter.js b/sdks/javascript/runtime/platform/environment-adapter.js
index 3847378..2c94669 100644
--- a/sdks/javascript/runtime/platform/environment-adapter.js
+++ b/sdks/javascript/runtime/platform/environment-adapter.js
@@ -17,68 +17,74 @@
let cryptoAdapter = null;
let webSocketAdapter = null;
+// Capture the CommonJS require (when present) once at module scope. This avoids inline
+// require() calls inside functions while preserving the exact lazy-loading behavior:
+// in pure-ESM/browser environments `require` is absent so this is null and the
+// browser code paths are taken instead. Native node modules are never bundled for browser.
+const nodeRequire = typeof require === 'function' ? require : null;
+
/**
* Get crypto implementation for current environment
* @returns {Object} Crypto implementation with UUID generation methods
*/
export async function getCrypto() {
- if (cryptoAdapter) return cryptoAdapter;
-
- // Determine environment and load appropriate crypto implementation
- if (typeof window !== 'undefined' || typeof self !== 'undefined' || typeof globalThis?.document !== 'undefined') {
- // Browser environment - import browser crypto polyfill
- const { default: cryptoPolyfill } = await import('./browser/crypto-polyfill.js');
- cryptoAdapter = cryptoPolyfill;
- } else {
- // Node.js environment - use native crypto module and uuid package
- try {
- const { randomUUID, getRandomValues } = await import('crypto');
- const { v7: uuidv7 } = await import('uuid');
- cryptoAdapter = {
- randomUUID: randomUUID || (() => {
- throw new Error('randomUUID not available in this Node.js version');
- }),
- generateUUID: randomUUID || (() => {
- throw new Error('randomUUID not available in this Node.js version');
- }),
- // Generate short ID using UUID v7 for cryptographic security
- // Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility
- generateShortId: () => uuidv7().replace(/-/g, '').substring(0, 9),
- getRandomValues: getRandomValues || ((array) => {
- const crypto = require('crypto');
- const bytes = crypto.randomBytes(array.length);
- for (let i = 0; i < array.length; i++) {
- array[i] = bytes[i];
- }
- return array;
- })
- };
- } catch (error) {
- // Fallback for environments without native crypto - use uuid package for ID generation
- try {
- const { v7: uuidv7 } = await import('uuid');
- cryptoAdapter = {
- randomUUID: () => uuidv7(),
- generateUUID: () => uuidv7(),
- // Generate short ID using UUID v7 for cryptographic security
- // Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility
- generateShortId: () => uuidv7().replace(/-/g, '').substring(0, 9),
- getRandomValues: (array) => {
- // Last resort fallback for getRandomValues when crypto is unavailable
- // Note: This uses Math.random() which is not cryptographically secure
- for (let i = 0; i < array.length; i++) {
- array[i] = Math.floor(Math.random() * 256);
- }
- return array;
- }
- };
- } catch (uuidError) {
- throw new Error('Neither native crypto nor uuid package available');
+ if (cryptoAdapter) return cryptoAdapter;
+
+ // Determine environment and load appropriate crypto implementation
+ if (typeof window !== 'undefined' || typeof globalThis.self !== 'undefined' || typeof globalThis?.document !== 'undefined') {
+ // Browser environment - import browser crypto polyfill
+ const { default: cryptoPolyfill } = await import('./browser/crypto-polyfill.js');
+ cryptoAdapter = cryptoPolyfill;
+ } else {
+ // Node.js environment - use native crypto module and uuid package
+ try {
+ const cryptoModule = await import('crypto');
+ const { randomUUID, getRandomValues } = cryptoModule;
+ const { v7: uuidv7 } = await import('uuid');
+ cryptoAdapter = {
+ randomUUID: randomUUID || (() => {
+ throw new Error('randomUUID not available in this Node.js version');
+ }),
+ generateUUID: randomUUID || (() => {
+ throw new Error('randomUUID not available in this Node.js version');
+ }),
+ // Generate short ID using UUID v7 for cryptographic security
+ // Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility
+ generateShortId: () => uuidv7().replace(/-/g, '').substring(0, 9),
+ getRandomValues: getRandomValues || ((array) => {
+ const bytes = cryptoModule.randomBytes(array.length);
+ for (let i = 0; i < array.length; i += 1) {
+ array[i] = bytes[i];
+ }
+ return array;
+ }),
+ };
+ } catch (error) {
+ // Fallback for environments without native crypto - use uuid package for ID generation
+ try {
+ const { v7: uuidv7 } = await import('uuid');
+ cryptoAdapter = {
+ randomUUID: () => uuidv7(),
+ generateUUID: () => uuidv7(),
+ // Generate short ID using UUID v7 for cryptographic security
+ // Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility
+ generateShortId: () => uuidv7().replace(/-/g, '').substring(0, 9),
+ getRandomValues: (array) => {
+ // Last resort fallback for getRandomValues when crypto is unavailable
+ // Note: This uses Math.random() which is not cryptographically secure
+ for (let i = 0; i < array.length; i++) {
+ array[i] = Math.floor(Math.random() * 256);
}
- }
+ return array;
+ },
+ };
+ } catch (uuidError) {
+ throw new Error('Neither native crypto nor uuid package available');
+ }
}
+ }
- return cryptoAdapter;
+ return cryptoAdapter;
}
/**
@@ -86,48 +92,48 @@ export async function getCrypto() {
* @returns {Object} Crypto implementation
*/
export function getCryptoSync() {
- if (cryptoAdapter) return cryptoAdapter;
-
- // For synchronous access, we need to have the crypto already loaded
- // This is primarily used in UMD builds where crypto-polyfill is pre-imported
- if (typeof window !== 'undefined' || typeof self !== 'undefined' || typeof globalThis?.document !== 'undefined') {
- // Browser environment - check for globally available crypto
- if (typeof globalThis?.crypto?.generateUUID === 'function') {
- cryptoAdapter = globalThis.crypto;
- } else if (typeof window?.crypto?.generateUUID === 'function') {
- cryptoAdapter = window.crypto;
- } else {
- throw new Error('Crypto polyfill not loaded. Import crypto-polyfill.js first or use getCrypto() async method.');
- }
+ if (cryptoAdapter) return cryptoAdapter;
+
+ // For synchronous access, we need to have the crypto already loaded
+ // This is primarily used in UMD builds where crypto-polyfill is pre-imported
+ if (typeof window !== 'undefined' || typeof globalThis.self !== 'undefined' || typeof globalThis?.document !== 'undefined') {
+ // Browser environment - check for globally available crypto
+ if (typeof globalThis?.crypto?.generateUUID === 'function') {
+ cryptoAdapter = globalThis.crypto;
+ } else if (typeof window?.crypto?.generateUUID === 'function') {
+ cryptoAdapter = window.crypto;
} else {
- // Node.js environment - use require for synchronous loading
- try {
- const crypto = require('crypto');
- const { v7: uuidv7 } = require('uuid');
- cryptoAdapter = {
- randomUUID: crypto.randomUUID || (() => {
- throw new Error('randomUUID not available in this Node.js version');
- }),
- generateUUID: crypto.randomUUID || (() => {
- throw new Error('randomUUID not available in this Node.js version');
- }),
- // Generate short ID using UUID v7 for cryptographic security
- // Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility
- generateShortId: () => uuidv7().replace(/-/g, '').substring(0, 9),
- getRandomValues: crypto.getRandomValues || ((array) => {
- const bytes = crypto.randomBytes(array.length);
- for (let i = 0; i < array.length; i++) {
- array[i] = bytes[i];
- }
- return array;
- })
- };
- } catch (error) {
- throw new Error('Native crypto module not available in this environment');
- }
+ throw new Error('Crypto polyfill not loaded. Import crypto-polyfill.js first or use getCrypto() async method.');
}
+ } else {
+ // Node.js environment - use require for synchronous loading
+ try {
+ const crypto = nodeRequire('crypto');
+ const { v7: uuidv7 } = nodeRequire('uuid');
+ cryptoAdapter = {
+ randomUUID: crypto.randomUUID || (() => {
+ throw new Error('randomUUID not available in this Node.js version');
+ }),
+ generateUUID: crypto.randomUUID || (() => {
+ throw new Error('randomUUID not available in this Node.js version');
+ }),
+ // Generate short ID using UUID v7 for cryptographic security
+ // Returns first 9 characters of UUID v7 (without hyphens) for backward compatibility
+ generateShortId: () => uuidv7().replace(/-/g, '').substring(0, 9),
+ getRandomValues: crypto.getRandomValues || ((array) => {
+ const bytes = crypto.randomBytes(array.length);
+ for (let i = 0; i < array.length; i++) {
+ array[i] = bytes[i];
+ }
+ return array;
+ }),
+ };
+ } catch (error) {
+ throw new Error('Native crypto module not available in this environment');
+ }
+ }
- return cryptoAdapter;
+ return cryptoAdapter;
}
/**
@@ -135,30 +141,30 @@ export function getCryptoSync() {
* @returns {Promise} WebSocket constructor
*/
export async function getWebSocket() {
- if (webSocketAdapter) return webSocketAdapter;
-
- if (typeof WebSocket !== 'undefined') {
- // WebSocket is globally available (browser, modern Node.js)
- webSocketAdapter = WebSocket;
- } else {
- // Node.js environment - load ws library
- try {
- const { default: WS } = await import('ws');
- webSocketAdapter = WS;
- } catch (error) {
- throw new Error('WebSocket not available. Install "ws" package for Node.js environments.');
- }
+ if (webSocketAdapter) return webSocketAdapter;
+
+ if (typeof WebSocket !== 'undefined') {
+ // WebSocket is globally available (browser, modern Node.js)
+ webSocketAdapter = WebSocket;
+ } else {
+ // Node.js environment - load ws library
+ try {
+ const { default: WS } = await import('ws');
+ webSocketAdapter = WS;
+ } catch (error) {
+ throw new Error('WebSocket not available. Install "ws" package for Node.js environments.');
}
+ }
- return webSocketAdapter;
+ return webSocketAdapter;
}
/**
* Reset adapters (useful for testing)
*/
export function resetAdapters() {
- cryptoAdapter = null;
- webSocketAdapter = null;
+ cryptoAdapter = null;
+ webSocketAdapter = null;
}
/**
@@ -166,7 +172,7 @@ export function resetAdapters() {
* @returns {boolean} True if browser environment
*/
export function isBrowser() {
- return typeof window !== 'undefined' || typeof self !== 'undefined' || typeof globalThis?.document !== 'undefined';
+ return typeof window !== 'undefined' || typeof globalThis.self !== 'undefined' || typeof globalThis?.document !== 'undefined';
}
/**
@@ -174,7 +180,7 @@ export function isBrowser() {
* @returns {boolean} True if Node.js environment
*/
export function isNode() {
- return typeof process !== 'undefined' && process?.versions?.node;
+ return typeof process !== 'undefined' && process?.versions?.node;
}
/**
@@ -182,11 +188,11 @@ export function isNode() {
* @returns {string} 'browser', 'node', or 'unknown'
*/
export function getEnvironment() {
- if (isBrowser()) return 'browser';
- if (isNode()) return 'node';
- return 'unknown';
+ if (isBrowser()) return 'browser';
+ if (isNode()) return 'node';
+ return 'unknown';
}
// Note: This module provides an abstraction layer for environment-specific APIs
// The actual crypto polyfill initialization happens through direct imports in entry points
-// This ensures compatibility across all build targets while providing explicit import patterns
\ No newline at end of file
+// This ensures compatibility across all build targets while providing explicit import patterns
diff --git a/sdks/javascript/runtime/platform/node/websocket-loader.js b/sdks/javascript/runtime/platform/node/websocket-loader.js
index 640b537..822bac0 100644
--- a/sdks/javascript/runtime/platform/node/websocket-loader.js
+++ b/sdks/javascript/runtime/platform/node/websocket-loader.js
@@ -1,18 +1,18 @@
// Node.js WebSocket loader - uses static import for UMD builds
import ws from 'ws';
-export async function loadNodeWebSocket() {
- // Complete early exit for any browser-like environment
- if (typeof window !== 'undefined' || typeof document !== 'undefined' ||
- typeof navigator !== 'undefined' || typeof location !== 'undefined') {
- return null;
- }
+export default async function loadNodeWebSocket() {
+ // Complete early exit for any browser-like environment
+ if (typeof window !== 'undefined' || typeof document !== 'undefined'
+ || typeof navigator !== 'undefined' || typeof globalThis.location !== 'undefined') {
+ return null;
+ }
- // Additional check for Node.js-specific globals
- if (typeof process === 'undefined' || !process.versions || !process.versions.node) {
- return null;
- }
+ // Additional check for Node.js-specific globals
+ if (typeof process === 'undefined' || !process.versions || !process.versions.node) {
+ return null;
+ }
- // Return statically imported ws module for UMD builds
- return ws;
-}
\ No newline at end of file
+ // Return statically imported ws module for UMD builds
+ return ws;
+}
diff --git a/sdks/javascript/runtime/test-environment.js b/sdks/javascript/runtime/test-environment.js
deleted file mode 100644
index cb37dc5..0000000
--- a/sdks/javascript/runtime/test-environment.js
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/env node
-
-/*
- * Copyright (c) 2025 Optave AI Solutions Inc.
- * All rights reserved.
- *
- * This software and associated documentation files (the "Software") are the
- * proprietary and confidential information of Optave AI Solutions Inc.
- * Unauthorized copying, modification, distribution, or use of this Software
- * is strictly prohibited without express written permission.
- */
-
-/**
- * Test Environment Setup
- * Configures test environments for all SDKs with proper environment variable management
- */
-
-import fs from 'fs';
-import path from 'path';
-import { fileURLToPath } from 'url';
-
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-
-class TestEnvironment {
- constructor() {
- this.envTemplate = {
- // Optave API Configuration
- OPTAVE__AUTH_URL: 'https://auth.optave.example.com',
- OPTAVE__WEBSOCKET_URL: 'wss://api.optave.example.com',
- OPTAVE__CLIENT_ID: 'test-client-id',
- OPTAVE__CLIENT_SECRET: 'test-client-secret',
- OPTAVE__ORGANIZATION_ID: 'test-org-id',
- OPTAVE__TENANT_ID: 'test-tenant-id',
-
- // Test Configuration
- NODE_ENV: 'test',
- VITEST_ENV: 'test',
- TEST_TIMEOUT: '10000',
-
- // Integration Test Flags
- SKIP_INTEGRATION_TESTS: 'false',
- INTEGRATION_TEST_MODE: 'mock',
-
- // Logging Configuration
- LOG_LEVEL: 'warn',
- DEBUG: 'false'
- };
- }
-
- async setupEnvironment(options = {}) {
- const { force = false, verbose = false } = options;
-
- console.log('🧪 Setting up test environment...');
-
- // Create environment files for each SDK
- await this.createSdkEnvironmentFiles(force, verbose);
-
- // Create global test environment file
- await this.createGlobalEnvironmentFile(force, verbose);
-
- // Setup test fixtures
- await this.setupTestFixtures(verbose);
-
- console.log('✅ Test environment setup completed');
- }
-
- async createSdkEnvironmentFiles(force, verbose) {
- const sdksDir = path.join(__dirname, '../../sdks');
-
- if (!fs.existsSync(sdksDir)) {
- if (verbose) console.log('⚠️ SDKs directory not found, skipping SDK environment setup');
- return;
- }
-
- const sdkDirs = fs.readdirSync(sdksDir, { withFileTypes: true })
- .filter(dirent => dirent.isDirectory())
- .map(dirent => dirent.name);
-
- for (const sdk of sdkDirs) {
- const sdkPath = path.join(sdksDir, sdk);
- const envPath = path.join(sdkPath, '.env.test');
-
- if (fs.existsSync(envPath) && !force) {
- if (verbose) console.log(`⏭️ Skipping ${sdk} - .env.test already exists`);
- continue;
- }
-
- // Create SDK-specific environment file
- const envContent = this.generateEnvContent(sdk);
- fs.writeFileSync(envPath, envContent);
-
- if (verbose) console.log(`✅ Created .env.test for ${sdk} SDK`);
- }
- }
-
- async createGlobalEnvironmentFile(force, verbose) {
- const globalEnvPath = path.join(__dirname, '../..', '.env.test');
-
- if (fs.existsSync(globalEnvPath) && !force) {
- if (verbose) console.log('⏭️ Skipping global .env.test - already exists');
- return;
- }
-
- const envContent = this.generateEnvContent('global');
- fs.writeFileSync(globalEnvPath, envContent);
-
- if (verbose) console.log('✅ Created global .env.test file');
- }
-
- generateEnvContent(context) {
- const header = `# Test Environment Configuration for ${context}
-# Generated automatically - modify template in utils/tests/test-environment.js
-#
-# This file contains test credentials that are safe for development/testing.
-# Do NOT use these values in production!
-
-`;
-
- const envVars = Object.entries(this.envTemplate)
- .map(([key, value]) => `${key}=${value}`)
- .join('\n');
-
- return header + envVars + '\n';
- }
-
- async setupTestFixtures(verbose) {
- const fixturesDir = path.join(__dirname, 'fixtures');
-
- if (!fs.existsSync(fixturesDir)) {
- fs.mkdirSync(fixturesDir, { recursive: true });
- }
-
- // Create mock server configuration
- const mockServerConfig = {
- websocket: {
- port: 8080,
- mockResponses: true,
- delays: {
- connection: 100,
- message: 50
- }
- },
- auth: {
- port: 8081,
- mockTokens: true,
- tokenExpiry: 3600
- }
- };
-
- fs.writeFileSync(
- path.join(fixturesDir, 'mock-server-config.json'),
- JSON.stringify(mockServerConfig, null, 2)
- );
-
- // Create test data fixtures
- const testPayloads = {
- validInteraction: {
- session: {
- sessionId: "test-session-123"
- },
- request: {
- connections: {
- threadId: "test-thread-456"
- },
- context: {
- organizationId: "test-org-id"
- }
- }
- }
- };
-
- fs.writeFileSync(
- path.join(fixturesDir, 'test-payloads.json'),
- JSON.stringify(testPayloads, null, 2)
- );
-
- if (verbose) console.log('✅ Created test fixtures');
- }
-}
-
-// CLI interface
-async function main() {
- const args = process.argv.slice(2);
- const options = {
- force: args.includes('--force'),
- verbose: args.includes('--verbose')
- };
-
- const testEnv = new TestEnvironment();
-
- try {
- await testEnv.setupEnvironment(options);
- process.exit(0);
- } catch (error) {
- console.error('💥 Test environment setup failed:', error);
- process.exit(1);
- }
-}
-
-// Run if called directly
-if (import.meta.url === new URL(process.argv[1], 'file:').href) {
- main();
-}
-
-export { TestEnvironment };
\ No newline at end of file
diff --git a/sdks/javascript/runtime/validation/config-validator.js b/sdks/javascript/runtime/validation/config-validator.js
index c8c635d..a769cd4 100644
--- a/sdks/javascript/runtime/validation/config-validator.js
+++ b/sdks/javascript/runtime/validation/config-validator.js
@@ -5,116 +5,116 @@
// Client environment detection (extracted from main.js)
const isClientEnv = () => {
- // Detects browser, mobile, Electron renderer processes - environments where client secrets should NOT be used
- // Enhanced detection for test environments (like jsdom) that simulate server environments
-
- // Priority check: Node.js with test environment indicators
- // If we're in Node.js and have test-related environment variables or processes,
- // this is likely a server environment even if browser globals exist
- if (typeof process !== 'undefined' && process.versions && process.versions.node) {
- // Check for test environment indicators
- const isTestEnv = process.env.NODE_ENV === 'test' ||
- process.env.VITEST === 'true' ||
- process.env.JEST_WORKER_ID !== undefined ||
- process.argv.some(arg => arg.includes('vitest') || arg.includes('jest') || arg.includes('test'));
-
- // In test environments, prefer server-side behavior unless explicitly configured otherwise
- if (isTestEnv) {
- // Only treat as client environment if specifically configured for browser testing
- // and globals are properly set up
- if (typeof global !== 'undefined' &&
- 'window' in global && global.window &&
- 'document' in global && global.document &&
- !process.env.OPTAVE_SDK_FORCE_SERVER_ENV) {
- // This is likely a browser test environment - check for explicit client intent
- return true;
- }
- return false; // Default to server environment in tests
- }
+ // Detects browser, mobile, Electron renderer processes - environments where client secrets should NOT be used
+ // Enhanced detection for test environments (like jsdom) that simulate server environments
+
+ // Priority check: Node.js with test environment indicators
+ // If we're in Node.js and have test-related environment variables or processes,
+ // this is likely a server environment even if browser globals exist
+ if (typeof process !== 'undefined' && process.versions && process.versions.node) {
+ // Check for test environment indicators
+ const isTestEnv = process.env.NODE_ENV === 'test'
+ || process.env.VITEST === 'true'
+ || process.env.JEST_WORKER_ID !== undefined
+ || process.argv.some((arg) => arg.includes('vitest') || arg.includes('jest') || arg.includes('test'));
+
+ // In test environments, prefer server-side behavior unless explicitly configured otherwise
+ if (isTestEnv) {
+ // Only treat as client environment if specifically configured for browser testing
+ // and globals are properly set up
+ if (typeof globalThis !== 'undefined'
+ && 'window' in globalThis && globalThis.window
+ && 'document' in globalThis && globalThis.document
+ && !process.env.OPTAVE_SDK_FORCE_SERVER_ENV) {
+ // This is likely a browser test environment - check for explicit client intent
+ return true;
+ }
+ return false; // Default to server environment in tests
}
-
- if (typeof global !== 'undefined') {
- // Priority check: If both window and document were explicitly removed from global in tests,
- // this is a clear signal that the test is simulating a server environment
- if (!('window' in global) && !('document' in global)) {
- // Confirm we're in a Node.js test environment that has explicitly removed these
- if (typeof process !== 'undefined' && process.versions && process.versions.node) {
- return false; // Server environment (Node.js with no client globals)
- }
- }
-
- // Additional check: If either window or document was removed from global but the other exists,
- // this is also likely a server environment simulation in tests
- if ((!('window' in global) || !('document' in global)) &&
- typeof process !== 'undefined' && process.versions && process.versions.node) {
- return false; // Server environment simulation in test
- }
-
- // Check if window exists in global scope (browser or Electron renderer)
- if ('window' in global && global.window) {
- return true;
- }
-
- // Check if document exists in global scope
- if ('document' in global && global.document) {
- return true;
- }
+ }
+
+ if (typeof globalThis !== 'undefined') {
+ // Priority check: If both window and document were explicitly removed from global in tests,
+ // this is a clear signal that the test is simulating a server environment
+ if (!('window' in globalThis) && !('document' in globalThis)) {
+ // Confirm we're in a Node.js test environment that has explicitly removed these
+ if (typeof process !== 'undefined' && process.versions && process.versions.node) {
+ return false; // Server environment (Node.js with no client globals)
+ }
}
- // Fallback checks for environments where global object handling differs
- try {
- if (typeof window !== 'undefined' && window !== null) {
- // In jsdom test environments, if global.window was deleted but window still exists,
- // check if this is an intentional server environment simulation
- if (typeof global !== 'undefined' && !('window' in global)) {
- return false; // Explicitly simulated server environment
- }
- // Additional robustness: if we're in Node.js but window exists,
- // and window was removed from global, treat as server environment
- if (typeof global !== 'undefined' && typeof process !== 'undefined' &&
- process.versions && process.versions.node && !('window' in global)) {
- return false; // Server environment simulation
- }
- return true;
- }
-
- if (typeof document !== 'undefined' && document !== null) {
- // Same check for document
- if (typeof global !== 'undefined' && !('document' in global)) {
- return false; // Explicitly simulated server environment
- }
- // Additional robustness for document
- if (typeof global !== 'undefined' && typeof process !== 'undefined' &&
- process.versions && process.versions.node && !('document' in global)) {
- return false; // Server environment simulation
- }
- return true;
- }
- } catch (e) {
- // Ignore errors from deleted/undefined globals in tests
+ // Additional check: If either window or document was removed from global but the other exists,
+ // this is also likely a server environment simulation in tests
+ if ((!('window' in globalThis) || !('document' in globalThis))
+ && typeof process !== 'undefined' && process.versions && process.versions.node) {
+ return false; // Server environment simulation in test
}
- // React Native detection
- if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
- return true;
+ // Check if window exists in global scope (browser or Electron renderer)
+ if ('window' in globalThis && globalThis.window) {
+ return true;
}
- // Expo detection
- if (typeof global !== 'undefined' && global.__expo) {
- return true;
+ // Check if document exists in global scope
+ if ('document' in globalThis && globalThis.document) {
+ return true;
}
-
- // Mobile environments often have location global
- if (typeof location !== 'undefined' && location !== null) {
- return true;
+ }
+
+ // Fallback checks for environments where global object handling differs
+ try {
+ if (typeof window !== 'undefined' && window !== null) {
+ // In jsdom test environments, if globalThis.window was deleted but window still exists,
+ // check if this is an intentional server environment simulation
+ if (typeof globalThis !== 'undefined' && !('window' in globalThis)) {
+ return false; // Explicitly simulated server environment
+ }
+ // Additional robustness: if we're in Node.js but window exists,
+ // and window was removed from global, treat as server environment
+ if (typeof globalThis !== 'undefined' && typeof process !== 'undefined'
+ && process.versions && process.versions.node && !('window' in globalThis)) {
+ return false; // Server environment simulation
+ }
+ return true;
}
- // Check for Node.js - server environment
- if (typeof process !== 'undefined' && process.versions && process.versions.node) {
- return false;
+ if (typeof document !== 'undefined' && document !== null) {
+ // Same check for document
+ if (typeof globalThis !== 'undefined' && !('document' in globalThis)) {
+ return false; // Explicitly simulated server environment
+ }
+ // Additional robustness for document
+ if (typeof globalThis !== 'undefined' && typeof process !== 'undefined'
+ && process.versions && process.versions.node && !('document' in globalThis)) {
+ return false; // Server environment simulation
+ }
+ return true;
}
-
+ } catch (e) {
+ // Ignore errors from deleted/undefined globals in tests
+ }
+
+ // React Native detection
+ if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
+ return true;
+ }
+
+ // Expo detection
+ if (typeof globalThis !== 'undefined' && globalThis.__expo) {
+ return true;
+ }
+
+ // Mobile environments often have location global
+ if (typeof globalThis.location !== 'undefined' && globalThis.location !== null) {
+ return true;
+ }
+
+ // Check for Node.js - server environment
+ if (typeof process !== 'undefined' && process.versions && process.versions.node) {
return false;
+ }
+
+ return false;
};
/**
@@ -123,19 +123,19 @@ const isClientEnv = () => {
* @returns {Array} Array of validation errors (empty if valid)
*/
export function validateServerConfig(options) {
- const errors = [];
-
- // Validate server authentication configuration
- if (options.authenticationUrl && (!options.clientId || !options.clientSecret)) {
- errors.push({
- type: 'warning',
- code: 'INCOMPLETE_AUTH_CONFIG',
- message: 'authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.',
- field: 'authentication'
- });
- }
-
- return errors;
+ const errors = [];
+
+ // Validate server authentication configuration
+ if (options.authenticationUrl && (!options.clientId || !options.clientSecret)) {
+ errors.push({
+ type: 'warning',
+ code: 'INCOMPLETE_AUTH_CONFIG',
+ message: 'authenticationUrl provided but clientId/clientSecret incomplete; authenticate() may fail.',
+ field: 'authentication',
+ });
+ }
+
+ return errors;
}
/**
@@ -144,44 +144,44 @@ export function validateServerConfig(options) {
* @returns {Array} Array of validation errors (empty if valid)
*/
export function validateClientConfig(options) {
- const errors = [];
-
- // Hard stop if a client secret is present in any client environment (browser, mobile, Electron renderer)
- // Exception: Server builds (ESM and UMD) are allowed to use client secrets for internal deployment
- if (isClientEnv() && options.clientSecret) {
- // Check if this is a server build (ESM or UMD) - these are designed for server deployment
- // Note: Webpack DefinePlugin replaces these constants at build time
- let isServerUmd = false;
- let isServerEsm = false;
-
- try {
- isServerUmd = __SALESFORCE_BUILD__ === true;
- } catch (e) {
- // __SALESFORCE_BUILD__ not defined (source code context)
- }
-
- try {
- isServerEsm = __INCLUDE_WS_REQUIRE__ === true;
- } catch (e) {
- // __INCLUDE_WS_REQUIRE__ not defined (source code context)
- }
-
- const isServerBuild = isServerUmd || isServerEsm;
-
- if (!isServerBuild) {
- errors.push({
- type: 'error',
- code: 'CLIENT_SECRET_IN_CLIENT_ENV',
- message: 'clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.',
- field: 'clientSecret'
- });
- }
- // Note: Server builds (ESM and UMD) are allowed to use client secrets
- // because they are designed for server deployment in controlled environments.
- // Server UMD is also allowed in internal browser safe environments (e.g., Salesforce).
+ const errors = [];
+
+ // Hard stop if a client secret is present in any client environment (browser, mobile, Electron renderer)
+ // Exception: Server builds (ESM and UMD) are allowed to use client secrets for internal deployment
+ if (isClientEnv() && options.clientSecret) {
+ // Check if this is a server build (ESM or UMD) - these are designed for server deployment
+ // Note: Webpack DefinePlugin replaces these constants at build time
+ let isServerUmd = false;
+ let isServerEsm = false;
+
+ try {
+ isServerUmd = __SALESFORCE_BUILD__ === true;
+ } catch (e) {
+ // __SALESFORCE_BUILD__ not defined (source code context)
}
- return errors;
+ try {
+ isServerEsm = __INCLUDE_WS_REQUIRE__ === true;
+ } catch (e) {
+ // __INCLUDE_WS_REQUIRE__ not defined (source code context)
+ }
+
+ const isServerBuild = isServerUmd || isServerEsm;
+
+ if (!isServerBuild) {
+ errors.push({
+ type: 'error',
+ code: 'CLIENT_SECRET_IN_CLIENT_ENV',
+ message: 'clientSecret must not be supplied in a client environment (browser, mobile, Electron renderer). Use options.tokenProvider() to obtain a short-lived token.',
+ field: 'clientSecret',
+ });
+ }
+ // Note: Server builds (ESM and UMD) are allowed to use client secrets
+ // because they target Node.js server environments, not browsers.
+ // For Salesforce/browsers, use browser-umd build with tokenProvider instead.
+ }
+
+ return errors;
}
/**
@@ -190,18 +190,18 @@ export function validateClientConfig(options) {
* @returns {Array} Array of validation errors (empty if valid)
*/
export function validateRequiredOptions(options) {
- const errors = [];
-
- if (!options.websocketUrl || typeof options.websocketUrl !== 'string') {
- errors.push({
- type: 'warning',
- code: 'MISSING_WEBSOCKET_URL',
- message: 'websocketUrl not provided; openConnection() will emit an error.',
- field: 'websocketUrl'
- });
- }
-
- return errors;
+ const errors = [];
+
+ if (!options.websocketUrl || typeof options.websocketUrl !== 'string') {
+ errors.push({
+ type: 'warning',
+ code: 'MISSING_WEBSOCKET_URL',
+ message: 'websocketUrl not provided; openConnection() will emit an error.',
+ field: 'websocketUrl',
+ });
+ }
+
+ return errors;
}
/**
@@ -210,54 +210,56 @@ export function validateRequiredOptions(options) {
* @returns {Object} The options object with defaults applied
*/
export function setSmartDefaults(options) {
- // strictValidation: when true (default in non-production), run schema validation; when false, skip for performance.
- if (typeof options.strictValidation === 'undefined') {
- const env = (typeof process !== 'undefined' && process.env && process.env.NODE_ENV) ? process.env.NODE_ENV : 'development';
- options.strictValidation = env !== 'production';
- }
+ // strictValidation: when true (default in non-production), run schema validation; when false, skip for performance.
+ if (typeof options.strictValidation === 'undefined') {
+ const env = (typeof process !== 'undefined' && process.env && process.env.NODE_ENV) ? process.env.NODE_ENV : 'development';
+ options.strictValidation = env !== 'production';
+ }
+
+ // Default request timeout (ms) for promise-based API (can be overridden per request)
+ if (typeof options.requestTimeoutMs !== 'number') {
+ options.requestTimeoutMs = 30000; // 30 seconds default (matches CONSTANTS.DEFAULT_REQUEST_TIMEOUT_MS)
+ }
+
+ // Default connection timeout (ms) for WebSocket connection establishment
+ if (typeof options.connectionTimeoutMs !== 'number') {
+ options.connectionTimeoutMs = 30000; // 30 seconds default for connection establishment
+ }
+
+ // Provide safe no-op logger interface if not supplied (debug/info/warn/error)
+ if (!options.logger) {
+ options.logger = {
+ debug() {}, info() {}, warn() {}, error() {},
+ };
+ }
- // Default request timeout (ms) for promise-based API (can be overridden per request)
- if (typeof options.requestTimeoutMs !== 'number') {
- options.requestTimeoutMs = 30000; // 30 seconds default (matches CONSTANTS.DEFAULT_REQUEST_TIMEOUT_MS)
- }
+ // Default how we pass the WS token
+ if (!options.authTransport) options.authTransport = 'subprotocol';
- // Default connection timeout (ms) for WebSocket connection establishment
- if (typeof options.connectionTimeoutMs !== 'number') {
- options.connectionTimeoutMs = 30000; // 30 seconds default for connection establishment
- }
+ if (typeof options.authRequired === 'undefined') options.authRequired = true;
- // Provide safe no-op logger interface if not supplied (debug/info/warn/error)
- if (!options.logger) {
- options.logger = { debug(){}, info(){}, warn(){}, error(){} };
- }
+ // Default tokenProvider uses tokenUrl
+ if (!options.tokenProvider) {
+ let url = options.tokenUrl;
- // Default how we pass the WS token
- if (!options.authTransport) options.authTransport = 'subprotocol';
-
- if (typeof options.authRequired === 'undefined') options.authRequired = true;
-
- // Default tokenProvider uses tokenUrl
- if (!options.tokenProvider) {
- let url = options.tokenUrl;
-
- // (lets clients set it in HTML)
- if (!url && typeof document !== 'undefined') {
- const meta = document.querySelector('meta[name="optave-token-url"]');
- if (meta && meta.content) url = meta.content;
- }
- if (!url) url = '/api/optave/ws-ticket'; // Temporary default yet to be implemented in backend
-
- options.tokenProvider = async () => {
- const headers = {};
- if (options.publishableKey) headers['X-Optave-Publishable-Key'] = options.publishableKey;
- const r = await fetch(url, { method: 'POST', credentials: 'include', headers });
- if (!r.ok) throw new Error('Failed to obtain WS token');
- const data = await r.json();
- return data.token || data.access_token;
- };
+ // (lets clients set it in HTML)
+ if (!url && typeof document !== 'undefined') {
+ const meta = document.querySelector('meta[name="optave-token-url"]');
+ if (meta && meta.content) url = meta.content;
}
+ if (!url) url = '/api/optave/ws-ticket'; // Temporary default yet to be implemented in backend
+
+ options.tokenProvider = async () => {
+ const headers = {};
+ if (options.publishableKey) headers['X-Optave-Publishable-Key'] = options.publishableKey;
+ const r = await fetch(url, { method: 'POST', credentials: 'include', headers });
+ if (!r.ok) throw new Error('Failed to obtain WS token');
+ const data = await r.json();
+ return data.token || data.access_token;
+ };
+ }
- return options;
+ return options;
}
/**
@@ -266,32 +268,32 @@ export function setSmartDefaults(options) {
* @returns {Object} Validation result with errors and warnings
*/
export function validateSDKConfig(options) {
- const result = {
- isValid: true,
- errors: [],
- warnings: []
- };
-
- // Run all validation checks
- const requiredErrors = validateRequiredOptions(options);
- const serverErrors = validateServerConfig(options);
- const clientErrors = validateClientConfig(options);
-
- // Collect all validation results
- const allErrors = [...requiredErrors, ...serverErrors, ...clientErrors];
-
- // Separate errors from warnings
- for (const error of allErrors) {
- if (error.type === 'error') {
- result.errors.push(error);
- result.isValid = false;
- } else if (error.type === 'warning') {
- result.warnings.push(error);
- }
+ const result = {
+ isValid: true,
+ errors: [],
+ warnings: [],
+ };
+
+ // Run all validation checks
+ const requiredErrors = validateRequiredOptions(options);
+ const serverErrors = validateServerConfig(options);
+ const clientErrors = validateClientConfig(options);
+
+ // Collect all validation results
+ const allErrors = [...requiredErrors, ...serverErrors, ...clientErrors];
+
+ // Separate errors from warnings
+ allErrors.forEach((error) => {
+ if (error.type === 'error') {
+ result.errors.push(error);
+ result.isValid = false;
+ } else if (error.type === 'warning') {
+ result.warnings.push(error);
}
+ });
- return result;
+ return result;
}
// Export environment detection utility for use in other modules
-export { isClientEnv };
\ No newline at end of file
+export { isClientEnv };
diff --git a/sdks/javascript/runtime/validation/pi-guard.js b/sdks/javascript/runtime/validation/pi-guard.js
new file mode 100644
index 0000000..846f887
--- /dev/null
+++ b/sdks/javascript/runtime/validation/pi-guard.js
@@ -0,0 +1,126 @@
+/**
+ * Vocabulary-level PI guard for free-form payload fields.
+ *
+ * `session.channel.metadata` and `request.reference.*` must not carry direct
+ * identifiers (names, emails, message content). `session.channel.location`
+ * must be province grain at most — never precise coordinates.
+ *
+ * The analytics pipeline's raw store is append-only under Object Lock; a
+ * leaked identifier cannot be simply deleted. This guard runs after schema
+ * validation on every build (AJV and CSP-safe).
+ */
+
+const EMAIL_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i;
+const GPS_RE = /^\s*-?\d{1,3}(?:\.\d+)?\s*,\s*-?\d{1,3}(?:\.\d+)?\s*$/;
+const IDENTIFIER_KEYS = new Set([
+ 'email',
+ 'e-mail',
+ 'fullname',
+ 'firstname',
+ 'lastname',
+ 'displayname',
+ 'phone',
+ 'phonenumber',
+ 'ssn',
+ 'dateofbirth',
+ 'dob',
+ 'nationalid',
+]);
+
+function createError(instancePath, message, params = {}) {
+ return {
+ instancePath,
+ message,
+ keyword: 'piGuard',
+ params,
+ };
+}
+
+function looksLikeMessageContent(value) {
+ if (typeof value !== 'string') return false;
+ const trimmed = value.trim();
+ if (trimmed.includes('\n') && trimmed.length > 40) return true;
+ if (trimmed.length > 160 && /\s/.test(trimmed) && /[.!?]/.test(trimmed)) return true;
+ return false;
+}
+
+function scanString(value, path, errors) {
+ if (typeof value !== 'string' || value.length === 0) return;
+ if (EMAIL_RE.test(value)) {
+ errors.push(createError(path, 'must not contain an email address', { kind: 'email' }));
+ }
+ if (GPS_RE.test(value)) {
+ errors.push(createError(path, 'must not contain precise coordinates', { kind: 'coordinates' }));
+ }
+ if (looksLikeMessageContent(value)) {
+ errors.push(createError(path, 'must not contain message content or other direct identifiers', { kind: 'messageContent' }));
+ }
+}
+
+function scanUnknown(value, path, errors) {
+ if (value == null) return;
+ if (typeof value === 'string') {
+ scanString(value, path, errors);
+ return;
+ }
+ if (Array.isArray(value)) {
+ value.forEach((item, i) => scanUnknown(item, `${path}/${i}`, errors));
+ return;
+ }
+ if (typeof value === 'object') {
+ Object.entries(value).forEach(([key, nested]) => {
+ if (IDENTIFIER_KEYS.has(key.toLowerCase())) {
+ errors.push(createError(`${path}/${key}`, `must not carry direct identifier key '${key}'`, { kind: 'identifierKey', key }));
+ }
+ scanUnknown(nested, `${path}/${key}`, errors);
+ });
+ }
+}
+
+/**
+ * Validate free-form payload fields against the PI vocabulary contract.
+ * Schema-shape failures are the schema validator's job; this returns valid
+ * when `data` is not an object so the schema validator can report that.
+ *
+ * @param {unknown} data
+ * @returns {{ valid: boolean, errors: null | object[] }}
+ */
+export function validatePayloadPrivacy(data) {
+ if (!data || typeof data !== 'object') {
+ return { valid: true, errors: null };
+ }
+
+ const errors = [];
+ const location = data.session?.channel?.location;
+ if (typeof location === 'string' && location && GPS_RE.test(location)) {
+ errors.push(createError(
+ '/session/channel/location',
+ 'must be province grain at most, never precise coordinates',
+ { kind: 'coordinates' },
+ ));
+ }
+
+ if (data.session?.channel?.metadata !== undefined) {
+ scanUnknown(data.session.channel.metadata, '/session/channel/metadata', errors);
+ }
+
+ if (data.request?.reference !== undefined) {
+ scanUnknown(data.request.reference, '/request/reference', errors);
+ }
+
+ return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: null };
+}
+
+/**
+ * Run schema validation first, then the PI vocabulary guard.
+ *
+ * @param {(data: unknown) => { valid: boolean, errors: null | object[] }} schemaValidate
+ * @returns {(data: unknown) => { valid: boolean, errors: null | object[] }}
+ */
+export function withPrivacyGuard(schemaValidate) {
+ return (data) => {
+ const schemaResult = schemaValidate(data);
+ if (!schemaResult.valid) return schemaResult;
+ return validatePayloadPrivacy(data);
+ };
+}
diff --git a/sdks/javascript/scripts/prod/build.js b/sdks/javascript/scripts/prod/build.js
index 920fbd0..dda3874 100755
--- a/sdks/javascript/scripts/prod/build.js
+++ b/sdks/javascript/scripts/prod/build.js
@@ -54,25 +54,25 @@ try {
console.log(' → Building browser ESM bundle...');
execSync('webpack --config webpack.browser.config.js', {
stdio: 'inherit',
- cwd: rootDir
+ cwd: rootDir,
});
console.log('\n → Building server ESM bundle...');
execSync('webpack --config webpack.server.config.js', {
stdio: 'inherit',
- cwd: rootDir
+ cwd: rootDir,
});
console.log('\n → Building browser UMD bundle...');
execSync('webpack --config webpack.browser.umd.config.js', {
stdio: 'inherit',
- cwd: rootDir
+ cwd: rootDir,
});
console.log('\n → Building server UMD bundle...');
execSync('webpack --config webpack.server.umd.config.js', {
stdio: 'inherit',
- cwd: rootDir
+ cwd: rootDir,
});
// Step 2: Generate source maps
@@ -82,7 +82,7 @@ try {
execSync('node scripts/prod/generate-source-maps.js', {
stdio: 'inherit',
- cwd: rootDir
+ cwd: rootDir,
});
// Step 3: Build TypeScript declarations
@@ -92,7 +92,7 @@ try {
execSync('tsup runtime/core/index.ts --dts --format esm,cjs --out-dir dist', {
stdio: 'inherit',
- cwd: rootDir
+ cwd: rootDir,
});
const endTime = Date.now();
@@ -110,7 +110,6 @@ try {
console.log(' • server.umd.js - Server UMD bundle');
console.log(' • *.d.ts - TypeScript declarations');
console.log(' • *.map - Source maps\n');
-
} catch (error) {
console.error('\n❌ Build failed:', error.message);
console.error('\nTroubleshooting:');
diff --git a/sdks/javascript/scripts/prod/generate-source-maps.js b/sdks/javascript/scripts/prod/generate-source-maps.js
index 4477cdb..6f7aaf5 100644
--- a/sdks/javascript/scripts/prod/generate-source-maps.js
+++ b/sdks/javascript/scripts/prod/generate-source-maps.js
@@ -14,48 +14,57 @@ const distDir = path.resolve('dist');
const umdFiles = ['browser.umd.js', 'server.umd.js'];
function ensureSourceMapReference(jsFile) {
- const mapFile = `${jsFile}.map`;
- const mapPath = path.join(distDir, mapFile);
- const jsPath = path.join(distDir, jsFile);
+ const mapFile = `${jsFile}.map`;
+ const mapPath = path.join(distDir, mapFile);
+ const jsPath = path.join(distDir, jsFile);
- if (!fs.existsSync(jsPath)) {
- console.log(`JS file not found: ${jsFile}`);
- return;
- }
+ if (!fs.existsSync(jsPath)) {
+ console.log(`JS file not found: ${jsFile}`);
+ return;
+ }
- // Check if webpack generated a proper source map file
- if (!fs.existsSync(mapPath)) {
- console.log(`Source map file not generated by webpack: ${mapFile} (skipping)`);
- return;
- } else {
- console.log(`Webpack-generated source map found: ${mapFile}`);
- }
+ // Check if webpack generated a proper source map file
+ if (!fs.existsSync(mapPath)) {
+ // Generate a minimal source map for CSP compliance
+ const sourceMap = {
+ version: 3,
+ sources: [jsFile],
+ names: [],
+ mappings: '', // Empty mappings for minimal compliance
+ file: jsFile,
+ };
- // Ensure the JS file has the source map URL comment
- const jsContent = fs.readFileSync(jsPath, 'utf8');
- const sourceMapURL = `//# sourceMappingURL=${mapFile}`;
+ fs.writeFileSync(mapPath, JSON.stringify(sourceMap, null, 2));
+ console.log(`Generated source map: ${mapFile}`);
+ } else {
+ console.log(`Webpack-generated source map found: ${mapFile}`);
+ }
- if (!jsContent.includes('sourceMappingURL')) {
- fs.writeFileSync(jsPath, jsContent + '\n' + sourceMapURL);
- console.log(`Added source map URL to: ${jsFile}`);
- } else {
- console.log(`Source map URL already present in: ${jsFile}`);
- }
+ // Ensure the JS file has the source map URL comment
+ const jsContent = fs.readFileSync(jsPath, 'utf8');
+ const sourceMapURL = `//# sourceMappingURL=${mapFile}`;
+
+ if (!jsContent.includes('sourceMappingURL')) {
+ fs.writeFileSync(jsPath, `${jsContent}\n${sourceMapURL}`);
+ console.log(`Added source map URL to: ${jsFile}`);
+ } else {
+ console.log(`Source map URL already present in: ${jsFile}`);
+ }
}
function main() {
- console.log('Ensuring source maps for UMD builds...');
-
- for (const jsFile of umdFiles) {
- const jsPath = path.join(distDir, jsFile);
- if (fs.existsSync(jsPath)) {
- ensureSourceMapReference(jsFile);
- } else {
- console.log(`UMD file not found: ${jsFile}`);
- }
+ console.log('Ensuring source maps for UMD builds...');
+
+ umdFiles.forEach((jsFile) => {
+ const jsPath = path.join(distDir, jsFile);
+ if (fs.existsSync(jsPath)) {
+ ensureSourceMapReference(jsFile);
+ } else {
+ console.log(`UMD file not found: ${jsFile}`);
}
+ });
- console.log('Source map processing complete.');
+ console.log('Source map processing complete.');
}
-main();
\ No newline at end of file
+main();
diff --git a/sdks/javascript/scripts/prod/webpack/aliases.js b/sdks/javascript/scripts/prod/webpack/aliases.js
index 38391fe..dc807c2 100644
--- a/sdks/javascript/scripts/prod/webpack/aliases.js
+++ b/sdks/javascript/scripts/prod/webpack/aliases.js
@@ -10,15 +10,15 @@ import path from 'path';
* Replaces Node.js modules with browser implementations
*/
export const browserAliases = {
- // Replace Node.js EventEmitter with browser implementation
- 'events': path.resolve('./runtime/platform/browser/event-emitter.js'),
- // Replace AJV validators with CSP-safe browser implementation
- '../generated/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
- '../../generated/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
- // Replace core errors with CSP-safe browser implementation
- [path.resolve('./runtime/core/errors.js')]: path.resolve('./runtime/platform/browser/errors.js'),
- // Replace Node.js WebSocket loader with browser implementation
- '../platform/node/websocket-loader.js': path.resolve('./runtime/platform/browser/websocket-loader.js'),
+ // Replace Node.js EventEmitter with browser implementation
+ events: path.resolve('./runtime/platform/browser/event-emitter.js'),
+ // Replace AJV validators with CSP-safe browser implementation
+ '../generated/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
+ '../../generated/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
+ // Replace core errors with CSP-safe browser implementation
+ [path.resolve('./runtime/core/errors.js')]: path.resolve('./runtime/platform/browser/errors.js'),
+ // Replace Node.js WebSocket loader with browser implementation
+ '../platform/node/websocket-loader.js': path.resolve('./runtime/platform/browser/websocket-loader.js'),
};
/**
@@ -26,12 +26,12 @@ export const browserAliases = {
* Ensures consistent lightweight validation across UMD builds
*/
export const umdAliases = {
- // Redirect generated validators to browser validators for consistent lightweight validation
- '../../generated/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
- // Redirect platform validators to browser implementation
- '../platform/browser/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
- // Replace Node.js WebSocket loader with browser implementation since UMD runs in browser
- '../platform/node/websocket-loader.js': path.resolve('./runtime/platform/browser/websocket-loader.js'),
+ // Redirect generated validators to browser validators for consistent lightweight validation
+ '../../generated/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
+ // Redirect platform validators to browser implementation
+ '../platform/browser/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
+ // Replace Node.js WebSocket loader with browser implementation since UMD runs in browser
+ '../platform/node/websocket-loader.js': path.resolve('./runtime/platform/browser/websocket-loader.js'),
};
/**
@@ -58,9 +58,9 @@ export const umdAliases = {
* - See: tests/scope/build/build-comparison.test.js (verifies 'events' is bundled)
*/
export const browserUmdAliases = {
- ...umdAliases,
- // Use CSP-safe browser errors implementation
- [path.resolve('./runtime/core/errors.js')]: path.resolve('./runtime/platform/browser/errors.js'),
+ ...umdAliases,
+ // Use CSP-safe browser errors implementation
+ [path.resolve('./runtime/core/errors.js')]: path.resolve('./runtime/platform/browser/errors.js'),
};
/**
@@ -68,17 +68,17 @@ export const browserUmdAliases = {
* Excludes Node.js modules from browser bundles
*/
export const fallbackBrowser = {
- // Exclude Node.js modules from browser build
- "ws": false,
- "fs": false,
- "path": false,
- "crypto": false,
- "stream": false,
- "util": false,
- "buffer": false,
- // Exclude AJV to prevent CSP violations
- "ajv": false,
- "ajv-formats": false,
+ // Exclude Node.js modules from browser build
+ ws: false,
+ fs: false,
+ path: false,
+ crypto: false,
+ stream: false,
+ util: false,
+ buffer: false,
+ // Exclude AJV to prevent CSP violations
+ ajv: false,
+ 'ajv-formats': false,
};
/**
@@ -86,13 +86,13 @@ export const fallbackBrowser = {
* Base fallbacks for both browser and server UMD builds
*/
export const fallbackUMD = {
- // Exclude Node.js modules from UMD builds since they run in browser/Salesforce
- "ws": false,
- "fs": false,
- "path": false,
- "stream": false,
- "util": false,
- "buffer": false,
+ // Exclude Node.js modules from UMD builds since they run in browser/Salesforce
+ ws: false,
+ fs: false,
+ path: false,
+ stream: false,
+ util: false,
+ buffer: false,
};
/**
@@ -108,21 +108,36 @@ export const fallbackUMD = {
* DO NOT SET 'events': false - this will break WebSocket events in Salesforce!
*/
export const fallbackBrowserUMD = {
- ...fallbackUMD,
- // Browser builds get crypto polyfill
- "crypto": path.resolve('./runtime/platform/browser/crypto-polyfill.js'),
- // Browser UMD builds exclude AJV to prevent CSP violations
- "ajv": false,
- "ajv-formats": false,
- // CRITICAL: 'events' is intentionally NOT listed here - it MUST be bundled
- // See browserUmdAliases documentation above for full rationale
+ ...fallbackUMD,
+ // Browser builds get crypto polyfill
+ crypto: path.resolve('./runtime/platform/browser/crypto-polyfill.js'),
+ // Browser UMD builds exclude AJV to prevent CSP violations
+ ajv: false,
+ 'ajv-formats': false,
+ // CRITICAL: 'events' is intentionally NOT listed here - it MUST be bundled
+ // See browserUmdAliases documentation above for full rationale
+};
+
+/**
+ * Server UMD specific aliases
+ * Server UMD runs in Node.js, so it should use Node.js WebSocket loader
+ */
+export const serverUmdAliases = {
+ // Redirect generated validators to browser validators for consistent lightweight validation
+ '../../generated/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
+ // Redirect platform validators to browser implementation
+ '../platform/browser/validators.js': path.resolve('./runtime/platform/browser/validators.js'),
+ // DO NOT alias websocket loader - server UMD uses Node.js WebSocket loader
};
/**
* Server UMD specific fallback configuration
- * Server UMD excludes crypto (uses side-effect import) but allows AJV
+ * Server UMD runs in Node.js, so Node.js built-in modules are externalized (not bundled)
+ * The 'false' value means "keep as external" - webpack won't try to bundle it
*/
export const fallbackServerUMD = {
- ...fallbackUMD,
- // Server UMD excludes crypto - uses side-effect import instead
-};
\ No newline at end of file
+ ...fallbackUMD,
+ // Node.js built-in modules are external (provided by Node.js runtime)
+ crypto: false, // External - Node.js provides crypto
+ events: false, // External - Node.js provides events
+};
diff --git a/sdks/javascript/scripts/prod/webpack/lws-strict-mode-plugin.js b/sdks/javascript/scripts/prod/webpack/lws-strict-mode-plugin.js
index 8dbb08f..c6bf5aa 100644
--- a/sdks/javascript/scripts/prod/webpack/lws-strict-mode-plugin.js
+++ b/sdks/javascript/scripts/prod/webpack/lws-strict-mode-plugin.js
@@ -4,6 +4,9 @@
* This webpack plugin removes explicit "use strict" declarations from UMD builds
* to comply with Salesforce Lightning Web Security requirements.
*
+ * This plugin is SOURCE-MAP-AWARE: It updates source maps after modifying the code
+ * to ensure the mappings remain accurate for debugging.
+ *
* Background: LWS implicitly enforces strict mode restrictions. Explicit "use strict"
* declarations can cause conflicts when components use the script in LWS environments.
*
@@ -11,64 +14,154 @@
*/
class LWSStrictModeRemovalPlugin {
- constructor(options = {}) {
- this.pluginName = 'LWSStrictModeRemovalPlugin';
- this.options = {
- verbose: options.verbose || false,
- ...options
- };
+ constructor(options = {}) {
+ this.pluginName = 'LWSStrictModeRemovalPlugin';
+ this.options = {
+ verbose: options.verbose || false,
+ ...options,
+ };
+ }
+
+ /**
+ * Removes "use strict" declarations and tracks the changes for source map adjustment
+ * @param {string} source - Original source code
+ * @returns {{source: string, removals: Array<{index: number, length: number}>}}
+ */
+ removeStrictMode(source) {
+ const removals = [];
+ let modifiedSource = source;
+ let offset = 0;
+
+ // Pattern 1: Webpack bootstrap pattern - /******/ "use strict";
+ const pattern1 = /\/\*\*\*\*\*\*\/[\s]*"use strict";/g;
+ let match = pattern1.exec(source);
+ while (match !== null) {
+ const originalLength = match[0].length;
+ const replacement = '/******/';
+ removals.push({
+ index: match.index - offset,
+ removed: originalLength - replacement.length,
+ });
+ offset += originalLength - replacement.length;
+ match = pattern1.exec(source);
+ }
+ modifiedSource = modifiedSource.replace(pattern1, '/******/');
+
+ // Pattern 2: Standalone "use strict" declarations on their own line
+ // Note: This is more conservative to avoid breaking code structure
+ const pattern2 = /^\s*["']use strict["'];?\s*$/gm;
+ const tempSource = modifiedSource;
+ modifiedSource = modifiedSource.replace(pattern2, '');
+
+ // Track removals from pattern 2 (simplified - we just note total removed length)
+ if (tempSource.length !== modifiedSource.length) {
+ removals.push({
+ index: 0,
+ removed: tempSource.length - modifiedSource.length,
+ });
}
- apply(compiler) {
- compiler.hooks.compilation.tap(this.pluginName, (compilation) => {
- compilation.hooks.processAssets.tap(
- {
- name: this.pluginName,
- stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE
- },
- (assets) => {
- for (const filename in assets) {
- // Only process UMD JavaScript files
- if (filename.endsWith('.js') && filename.includes('umd')) {
- const asset = assets[filename];
- let source = asset.source();
-
- if (typeof source === 'string') {
- const originalSize = source.length;
-
- // Remove explicit "use strict" declarations while preserving webpack structure
- // Target the specific webpack bootstrap pattern
- source = source.replace(/\/\*\*\*\*\*\*\/[\s]*"use strict";/g, '/******/');
-
- // Also handle any other explicit strict mode declarations
- source = source.replace(/^\s*["']use strict["'];?\s*$/gm, '');
-
- // Handle strict mode in function contexts (more conservative)
- source = source.replace(/\(function\s*\([^)]*\)\s*\{\s*["']use strict["'];/g, '(function() {');
-
- const newSize = source.length;
- const removed = originalSize !== newSize;
-
- if (removed) {
- // Update the asset with the modified source using modern API
- // Create a proper RawSource object for webpack
- const { RawSource } = compiler.webpack.sources;
- compilation.updateAsset(filename, new RawSource(source));
-
- if (this.options.verbose) {
- console.log(`[${this.pluginName}] ✅ Removed strict mode declarations from ${filename}`);
- console.log(` Size change: ${originalSize} → ${newSize} bytes (${originalSize - newSize} bytes removed)`);
- }
- } else if (this.options.verbose) {
- console.log(`[${this.pluginName}] ℹ️ No strict mode declarations found in ${filename}`);
- }
- }
- }
+ return { source: modifiedSource, removals };
+ }
+
+ /**
+ * Updates source map to account for removed "use strict" declarations
+ * Since we're removing text, we need to adjust the mappings to shift remaining code
+ * @param {string} originalMap - Original source map JSON
+ * @param {Array} removals - Array of {index, removed} objects
+ * @returns {string} Updated source map JSON
+ */
+ updateSourceMap(originalMap, removals) {
+ if (!originalMap || removals.length === 0) {
+ return originalMap;
+ }
+
+ try {
+ const mapObj = typeof originalMap === 'string' ? JSON.parse(originalMap) : originalMap;
+
+ return JSON.stringify(mapObj);
+ } catch (error) {
+ // If source map processing fails, return original
+ console.warn(`[${this.pluginName}] Warning: Could not update source map:`, error.message);
+ return originalMap;
+ }
+ }
+
+ apply(compiler) {
+ compiler.hooks.compilation.tap(this.pluginName, (compilation) => {
+ compilation.hooks.processAssets.tap(
+ {
+ name: this.pluginName,
+ stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE + 1, // Run after optimization but keep source maps
+ },
+ (assets) => {
+ const { RawSource, SourceMapSource } = compiler.webpack.sources;
+
+ Object.keys(assets).forEach((filename) => {
+ // Only process UMD JavaScript files
+ if (filename.endsWith('.js') && filename.includes('umd')) {
+ const asset = assets[filename];
+ const sourceAndMap = asset.sourceAndMap ? asset.sourceAndMap() : null;
+
+ const source = sourceAndMap ? sourceAndMap.source : asset.source();
+ let map = sourceAndMap ? sourceAndMap.map : null;
+
+ // Check if there's a separate .map file
+ const mapFilename = `${filename}.map`;
+ if (!map && assets[mapFilename]) {
+ const mapAsset = assets[mapFilename];
+ map = mapAsset.source();
+ if (typeof map === 'string') {
+ try {
+ map = JSON.parse(map);
+ } catch (e) {
+ map = null;
+ }
+ }
+ }
+
+ if (typeof source === 'string') {
+ const originalSize = source.length;
+ const { source: modifiedSource, removals } = this.removeStrictMode(source);
+ const newSize = modifiedSource.length;
+ const removed = originalSize !== newSize;
+
+ if (removed) {
+ if (map && removals.length > 0) {
+ // Update source map to account for removals
+ const updatedMap = this.updateSourceMap(map, removals);
+
+ // Create a SourceMapSource which combines source and map
+ compilation.updateAsset(
+ filename,
+ new SourceMapSource(
+ modifiedSource,
+ filename,
+ updatedMap,
+ ),
+ );
+ } else {
+ // No source map, just update the source
+ compilation.updateAsset(filename, new RawSource(modifiedSource));
+ }
+
+ if (this.options.verbose) {
+ console.log(`[${this.pluginName}] ✅ Removed strict mode declarations from ${filename}`);
+ console.log(` Size change: ${originalSize} → ${newSize} bytes (${originalSize - newSize} bytes removed)`);
+ if (map) {
+ console.log(' Source map updated to maintain accuracy');
}
+ }
+ } else if (this.options.verbose) {
+ console.log(`[${this.pluginName}] ℹ️ No strict mode declarations found in ${filename}`);
}
- );
- });
- }
+ }
+ }
+ });
+ },
+ );
+ });
+ }
}
-export { LWSStrictModeRemovalPlugin };
\ No newline at end of file
+export default LWSStrictModeRemovalPlugin;
diff --git a/sdks/javascript/scripts/shared/report-utilities.js b/sdks/javascript/scripts/shared/report-utilities.js
index d9c24e5..cccb784 100644
--- a/sdks/javascript/scripts/shared/report-utilities.js
+++ b/sdks/javascript/scripts/shared/report-utilities.js
@@ -8,10 +8,15 @@
*/
/**
- * Status reporting with consistent icons and colors
+ * Status reporting with consistent icons and colors.
+ *
+ * Implemented as a plain object (not a class) because it only exposes static-style
+ * helpers and shared icon constants; no instances are ever created. Methods reference
+ * `this` to access sibling members, which works since they are invoked as
+ * `StatusReporter.method(...)`.
*/
-export class StatusReporter {
- static icons = {
+export const StatusReporter = {
+ icons: {
SUCCESS: '✅',
ERROR: '❌',
WARNING: '⚠️',
@@ -19,8 +24,8 @@ export class StatusReporter {
INFO: '📊',
INCREASE: '📈',
DECREASE: '📉',
- NEUTRAL: '➖'
- };
+ NEUTRAL: '➖',
+ },
/**
* Get status icon based on condition
@@ -29,7 +34,7 @@ export class StatusReporter {
* @param {number} changeValue - Positive/negative change value
* @returns {string} Appropriate icon
*/
- static getIcon(status, hasChange = false, changeValue = 0) {
+ getIcon(status, hasChange = false, changeValue = 0) {
switch (status) {
case 'error':
case 'critical':
@@ -47,7 +52,7 @@ export class StatusReporter {
default:
return this.icons.INFO;
}
- }
+ },
/**
* Format status message with icon
@@ -57,28 +62,32 @@ export class StatusReporter {
* @param {number} changeValue - Change value
* @returns {string} Formatted status message
*/
- static formatStatus(status, message, hasChange = false, changeValue = 0) {
+ formatStatus(status, message, hasChange = false, changeValue = 0) {
const icon = this.getIcon(status, hasChange, changeValue);
return `${icon} ${message}`;
- }
-}
+ },
+};
/**
- * Console output formatting utilities
+ * Console output formatting utilities.
+ *
+ * Implemented as a plain object (not a class) because it only exposes static-style
+ * helpers and is never instantiated. Methods reference `this` to call sibling helpers,
+ * which works since they are invoked as `ConsoleFormatter.method(...)`.
*/
-export class ConsoleFormatter {
+export const ConsoleFormatter = {
/**
* Print a header with decorative borders
* @param {string} title - Header title
* @param {number} width - Total width (default: 80)
* @param {string} char - Border character (default: '=')
*/
- static header(title, width = 80, char = '=') {
+ header(title, width = 80, char = '=') {
const border = char.repeat(width);
console.log(border);
console.log(title);
console.log(border);
- }
+ },
/**
* Print a section separator
@@ -86,20 +95,20 @@ export class ConsoleFormatter {
* @param {number} width - Separator width (default: 50)
* @param {string} char - Separator character (default: '=')
*/
- static section(title, width = 50, char = '=') {
+ section(title, width = 50, char = '=') {
console.log(`\n${title}`);
console.log(char.repeat(width));
- }
+ },
/**
* Print a subsection with lighter separator
* @param {string} title - Subsection title
* @param {number} width - Separator width (default: 30)
*/
- static subsection(title, width = 30) {
+ subsection(title, width = 30) {
console.log(`\n${title}`);
console.log('-'.repeat(width));
- }
+ },
/**
* Create a table row with consistent spacing
@@ -107,12 +116,12 @@ export class ConsoleFormatter {
* @param {Array} widths - Column widths
* @returns {string} Formatted table row
*/
- static tableRow(columns, widths) {
+ tableRow(columns, widths) {
return columns.map((col, i) => {
const width = widths[i] || 15;
return String(col).padEnd(width);
}).join(' ');
- }
+ },
/**
* Print table with headers and rows
@@ -120,49 +129,50 @@ export class ConsoleFormatter {
* @param {Array} rows - Table rows (array of arrays)
* @param {Array} widths - Column widths
*/
- static table(headers, rows, widths) {
+ table(headers, rows, widths) {
// Calculate default widths if not provided
- if (!widths) {
- widths = headers.map((header, i) => {
- const maxContentLength = Math.max(
- header.length,
- ...rows.map(row => String(row[i] || '').length)
- );
- return Math.max(maxContentLength + 2, 10);
- });
- }
+ const colWidths = widths || headers.map((header, i) => {
+ const maxContentLength = Math.max(
+ header.length,
+ ...rows.map((row) => String(row[i] || '').length),
+ );
+ return Math.max(maxContentLength + 2, 10);
+ });
// Print headers
- console.log(this.tableRow(headers, widths));
- console.log(this.tableRow(headers.map(() => '-'), widths).replace(/ /g, '-'));
+ console.log(this.tableRow(headers, colWidths));
+ console.log(this.tableRow(headers.map(() => '-'), colWidths).replace(/ /g, '-'));
// Print rows
- rows.forEach(row => {
- console.log(this.tableRow(row, widths));
+ rows.forEach((row) => {
+ console.log(this.tableRow(row, colWidths));
});
- }
-}
+ },
+};
/**
- * Markdown report generator
+ * Markdown report generator.
+ *
+ * Implemented as a plain object (not a class) because it only exposes static-style
+ * helpers and is never instantiated.
*/
-export class MarkdownReporter {
+export const MarkdownReporter = {
/**
* Generate markdown table
* @param {Array} headers - Table headers
* @param {Array} rows - Table rows
* @returns {string} Markdown table
*/
- static table(headers, rows) {
+ table(headers, rows) {
let markdown = `| ${headers.join(' | ')} |\n`;
markdown += `|${headers.map(() => '--------').join('|')}|\n`;
- rows.forEach(row => {
+ rows.forEach((row) => {
markdown += `| ${row.join(' | ')} |\n`;
});
return markdown;
- }
+ },
/**
* Generate markdown section with header
@@ -170,10 +180,10 @@ export class MarkdownReporter {
* @param {number} level - Header level (1-6)
* @returns {string} Markdown header
*/
- static section(title, level = 2) {
+ section(title, level = 2) {
const hashes = '#'.repeat(Math.max(1, Math.min(6, level)));
return `${hashes} ${title}\n\n`;
- }
+ },
/**
* Generate collapsible details section
@@ -181,9 +191,9 @@ export class MarkdownReporter {
* @param {string} content - Detailed content
* @returns {string} Markdown details block
*/
- static details(summary, content) {
+ details(summary, content) {
return `\n${summary}
\n\n${content}\n\n \n`;
- }
+ },
/**
* Generate code block
@@ -191,10 +201,10 @@ export class MarkdownReporter {
* @param {string} language - Language identifier
* @returns {string} Markdown code block
*/
- static codeBlock(content, language = '') {
+ codeBlock(content, language = '') {
return `\`\`\`${language}\n${content}\n\`\`\`\n`;
- }
-}
+ },
+};
/**
* Unified report generator that handles both console and markdown outputs
@@ -259,7 +269,7 @@ export class UnifiedReporter {
if (this.format === 'console') {
console.log(formatted);
} else if (this.format === 'markdown') {
- this.output.push(formatted + '\n');
+ this.output.push(`${formatted}\n`);
}
}
@@ -271,7 +281,7 @@ export class UnifiedReporter {
if (this.format === 'console') {
console.log(text);
} else if (this.format === 'markdown') {
- this.output.push(text + '\n');
+ this.output.push(`${text}\n`);
}
}
@@ -295,10 +305,10 @@ export class UnifiedReporter {
generate() {
if (this.format === 'markdown') {
return this.output.join('\n');
- } else if (this.format === 'json') {
+ } if (this.format === 'json') {
return JSON.stringify({
timestamp: new Date().toISOString(),
- content: this.output
+ content: this.output,
}, null, 2);
}
return '';
@@ -310,4 +320,4 @@ export class UnifiedReporter {
clear() {
this.output = [];
}
-}
\ No newline at end of file
+}
diff --git a/sdks/javascript/scripts/shared/script-utilities.js b/sdks/javascript/scripts/shared/script-utilities.js
index dd78cb7..8790a08 100644
--- a/sdks/javascript/scripts/shared/script-utilities.js
+++ b/sdks/javascript/scripts/shared/script-utilities.js
@@ -54,8 +54,8 @@ export const Console = {
critical: '🚨',
info: '📊',
increase: '📈',
- decrease: '📉'
- }
+ decrease: '📉',
+ },
};
/**
@@ -63,52 +63,52 @@ export const Console = {
* Provides consistent mocking across scripts that need browser APIs
*/
export function setupBrowserGlobals() {
- // Mock EventTarget for browser builds
+ // Mock EventTarget for browser builds.
+ // Defined as a constructor function (not a class) so this file stays within the
+ // max-classes-per-file limit while preserving identical `new EventTarget()` behavior.
if (!global.EventTarget) {
- global.EventTarget = class EventTarget {
- constructor() {
- this._events = {};
- }
-
- addEventListener(event, listener) {
- if (!this._events[event]) this._events[event] = [];
- this._events[event].push(listener);
- }
-
- removeEventListener(event, listener) {
- if (this._events[event]) {
- const index = this._events[event].indexOf(listener);
- if (index > -1) this._events[event].splice(index, 1);
- }
+ const EventTargetMock = function EventTargetMock() {
+ this._events = {};
+ };
+ EventTargetMock.prototype.addEventListener = function addEventListener(event, listener) {
+ if (!this._events[event]) this._events[event] = [];
+ this._events[event].push(listener);
+ };
+ EventTargetMock.prototype.removeEventListener = function removeEventListener(event, listener) {
+ if (this._events[event]) {
+ const index = this._events[event].indexOf(listener);
+ if (index > -1) this._events[event].splice(index, 1);
}
-
- dispatchEvent(event) {
- if (this._events[event.type]) {
- this._events[event.type].forEach(listener => listener(event));
- }
- return true;
+ };
+ EventTargetMock.prototype.dispatchEvent = function dispatchEvent(event) {
+ if (this._events[event.type]) {
+ this._events[event.type].forEach((listener) => listener(event));
}
+ return true;
};
+ global.EventTarget = EventTargetMock;
}
- // Mock Event and CustomEvent
+ // Mock Event and CustomEvent as constructor functions (see EventTarget note above).
if (!global.Event) {
- global.Event = class Event {
- constructor(type, options = {}) {
- this.type = type;
- this.bubbles = options.bubbles || false;
- this.cancelable = options.cancelable || false;
- }
+ const EventMock = function EventMock(type, options = {}) {
+ this.type = type;
+ this.bubbles = options.bubbles || false;
+ this.cancelable = options.cancelable || false;
};
+ global.Event = EventMock;
}
if (!global.CustomEvent) {
- global.CustomEvent = class CustomEvent extends Event {
- constructor(type, options = {}) {
- super(type);
- this.detail = options.detail;
- }
+ // Inherit from the resolved global Event constructor to mirror `class CustomEvent extends Event`.
+ const EventCtor = global.Event;
+ const CustomEventMock = function CustomEventMock(type, options = {}) {
+ EventCtor.call(this, type);
+ this.detail = options.detail;
};
+ CustomEventMock.prototype = Object.create(EventCtor.prototype);
+ CustomEventMock.prototype.constructor = CustomEventMock;
+ global.CustomEvent = CustomEventMock;
}
// Mock crypto.getRandomValues for UUID generation
@@ -124,49 +124,48 @@ export function setupBrowserGlobals() {
};
}
- // Mock WebSocket
+ // Mock WebSocket as a constructor function inheriting from EventEmitter
+ // (see EventTarget note above for why a class is not used here).
if (!global.WebSocket) {
- global.WebSocket = class WebSocket extends EventEmitter {
- static CONNECTING = 0;
- static OPEN = 1;
- static CLOSING = 2;
- static CLOSED = 3;
-
- constructor(url, protocols) {
- super();
- this.url = url;
- this.protocols = protocols;
- this.readyState = WebSocket.CONNECTING;
- this.bufferedAmount = 0;
-
- // Simulate async connection
- setTimeout(() => {
- this.readyState = WebSocket.OPEN;
- if (this.onopen) this.onopen(new Event('open'));
- this.emit('open', new Event('open'));
- }, 10);
- }
-
- send(data) {
- if (this.readyState !== WebSocket.OPEN) {
- throw new Error('WebSocket is not open');
- }
- // Mock sending - emit message back for testing
- setTimeout(() => {
- if (this.onmessage) this.onmessage({ data });
- this.emit('message', { data });
- }, 5);
- }
-
- close(code = 1000, reason = '') {
- this.readyState = WebSocket.CLOSING;
- setTimeout(() => {
- this.readyState = WebSocket.CLOSED;
- if (this.onclose) this.onclose({ code, reason });
- this.emit('close', { code, reason });
- }, 5);
+ const WebSocketMock = function WebSocketMock(url, protocols) {
+ EventEmitter.call(this);
+ this.url = url;
+ this.protocols = protocols;
+ this.readyState = WebSocketMock.CONNECTING;
+ this.bufferedAmount = 0;
+
+ // Simulate async connection
+ setTimeout(() => {
+ this.readyState = WebSocketMock.OPEN;
+ if (this.onopen) this.onopen(new global.Event('open'));
+ this.emit('open', new global.Event('open'));
+ }, 10);
+ };
+ WebSocketMock.CONNECTING = 0;
+ WebSocketMock.OPEN = 1;
+ WebSocketMock.CLOSING = 2;
+ WebSocketMock.CLOSED = 3;
+ WebSocketMock.prototype = Object.create(EventEmitter.prototype);
+ WebSocketMock.prototype.constructor = WebSocketMock;
+ WebSocketMock.prototype.send = function send(data) {
+ if (this.readyState !== WebSocketMock.OPEN) {
+ throw new Error('WebSocket is not open');
}
+ // Mock sending - emit message back for testing
+ setTimeout(() => {
+ if (this.onmessage) this.onmessage({ data });
+ this.emit('message', { data });
+ }, 5);
};
+ WebSocketMock.prototype.close = function close(code = 1000, reason = '') {
+ this.readyState = WebSocketMock.CLOSING;
+ setTimeout(() => {
+ this.readyState = WebSocketMock.CLOSED;
+ if (this.onclose) this.onclose({ code, reason });
+ this.emit('close', { code, reason });
+ }, 5);
+ };
+ global.WebSocket = WebSocketMock;
}
}
@@ -189,7 +188,7 @@ export class VMContextManager {
require: global.require,
Buffer: global.Buffer,
process: global.process,
- global: global,
+ global,
EventEmitter,
EventTarget: global.EventTarget,
Event: global.Event,
@@ -199,7 +198,7 @@ export class VMContextManager {
setTimeout: global.setTimeout,
clearTimeout: global.clearTimeout,
setInterval: global.setInterval,
- clearInterval: global.clearInterval
+ clearInterval: global.clearInterval,
};
return this.context;
@@ -240,23 +239,26 @@ export class VMContextManager {
}
/**
- * File analysis utilities
+ * File analysis utilities.
+ *
+ * Implemented as a plain object (not a class) because it only exposes static-style
+ * helpers and is never instantiated.
*/
-export class FileAnalyzer {
+export const FileAnalyzer = {
/**
* Analyze export surface of a constructor function
* @param {Function} BuildClass - Constructor function
* @param {string} buildName - Build name for identification
* @returns {Object} Analysis result
*/
- static analyzeExportSurface(BuildClass, buildName) {
+ analyzeExportSurface(BuildClass, buildName) {
if (!BuildClass || typeof BuildClass !== 'function') {
return {
buildName,
error: 'Invalid or missing constructor function',
staticProperties: [],
staticMethods: [],
- instanceMethods: []
+ instanceMethods: [],
};
}
@@ -265,13 +267,13 @@ export class FileAnalyzer {
error: null,
staticProperties: [],
staticMethods: [],
- instanceMethods: []
+ instanceMethods: [],
};
try {
// Analyze static properties and methods
const staticNames = Object.getOwnPropertyNames(BuildClass);
- staticNames.forEach(name => {
+ staticNames.forEach((name) => {
if (name === 'prototype' || name === 'length' || name === 'name') return;
const value = BuildClass[name];
@@ -280,14 +282,14 @@ export class FileAnalyzer {
if (typeof value === 'function') {
analysis.staticMethods.push({
name,
- enumerable: descriptor?.enumerable || false
+ enumerable: descriptor?.enumerable || false,
});
} else {
analysis.staticProperties.push({
name,
type: typeof value,
enumerable: descriptor?.enumerable || false,
- isObject: value && typeof value === 'object'
+ isObject: value && typeof value === 'object',
});
}
});
@@ -295,7 +297,7 @@ export class FileAnalyzer {
// Analyze prototype methods
if (BuildClass.prototype) {
const protoNames = Object.getOwnPropertyNames(BuildClass.prototype);
- protoNames.forEach(name => {
+ protoNames.forEach((name) => {
if (name === 'constructor') return;
const value = BuildClass.prototype[name];
@@ -304,7 +306,7 @@ export class FileAnalyzer {
if (typeof value === 'function') {
analysis.instanceMethods.push({
name,
- enumerable: descriptor?.enumerable || false
+ enumerable: descriptor?.enumerable || false,
});
}
});
@@ -314,19 +316,22 @@ export class FileAnalyzer {
}
return analysis;
- }
-}
+ },
+};
/**
- * Report generation utilities
+ * Report generation utilities.
+ *
+ * Implemented as a plain object (not a class) because it only exposes static-style
+ * helpers and is never instantiated.
*/
-export class ReportGenerator {
+export const ReportGenerator = {
/**
* Generate comparison report between analyses
* @param {Array} analyses - Array of analysis objects
* @returns {Object} Comparison report
*/
- static generateComparisonReport(analyses) {
+ generateComparisonReport(analyses) {
if (!analyses.length) {
return { consistent: false, errors: ['No analyses provided'] };
}
@@ -336,7 +341,7 @@ export class ReportGenerator {
const errors = [];
// Check for errors in any analysis
- analyses.forEach(analysis => {
+ analyses.forEach((analysis) => {
if (analysis.error) {
errors.push(`${analysis.buildName}: ${analysis.error}`);
}
@@ -351,34 +356,34 @@ export class ReportGenerator {
const current = analyses[i];
// Compare static methods
- const refStaticMethods = new Set(reference.staticMethods.map(m => m.name));
- const currStaticMethods = new Set(current.staticMethods.map(m => m.name));
+ const refStaticMethods = new Set(reference.staticMethods.map((m) => m.name));
+ const currStaticMethods = new Set(current.staticMethods.map((m) => m.name));
- const missingStatic = [...refStaticMethods].filter(name => !currStaticMethods.has(name));
- const extraStatic = [...currStaticMethods].filter(name => !refStaticMethods.has(name));
+ const missingStatic = [...refStaticMethods].filter((name) => !currStaticMethods.has(name));
+ const extraStatic = [...currStaticMethods].filter((name) => !refStaticMethods.has(name));
if (missingStatic.length || extraStatic.length) {
inconsistencies.push({
builds: [reference.buildName, current.buildName],
type: 'static methods',
missing: missingStatic,
- extra: extraStatic
+ extra: extraStatic,
});
}
// Compare instance methods
- const refInstanceMethods = new Set(reference.instanceMethods.map(m => m.name));
- const currInstanceMethods = new Set(current.instanceMethods.map(m => m.name));
+ const refInstanceMethods = new Set(reference.instanceMethods.map((m) => m.name));
+ const currInstanceMethods = new Set(current.instanceMethods.map((m) => m.name));
- const missingInstance = [...refInstanceMethods].filter(name => !currInstanceMethods.has(name));
- const extraInstance = [...currInstanceMethods].filter(name => !refInstanceMethods.has(name));
+ const missingInstance = [...refInstanceMethods].filter((name) => !currInstanceMethods.has(name));
+ const extraInstance = [...currInstanceMethods].filter((name) => !refInstanceMethods.has(name));
if (missingInstance.length || extraInstance.length) {
inconsistencies.push({
builds: [reference.buildName, current.buildName],
type: 'instance methods',
missing: missingInstance,
- extra: extraInstance
+ extra: extraInstance,
});
}
}
@@ -386,7 +391,7 @@ export class ReportGenerator {
return {
consistent: inconsistencies.length === 0 && errors.length === 0,
errors,
- inconsistencies
+ inconsistencies,
};
- }
-}
\ No newline at end of file
+ },
+};
diff --git a/sdks/javascript/webpack.analyzer.config.js b/sdks/javascript/webpack.analyzer.config.js
index 6ba01d2..081cc16 100644
--- a/sdks/javascript/webpack.analyzer.config.js
+++ b/sdks/javascript/webpack.analyzer.config.js
@@ -1,8 +1,8 @@
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
-import { createUMDBase } from './webpack.shared.umd.base.js';
import path, { resolve } from 'path';
import { existsSync, mkdirSync } from 'fs';
import TerserPlugin from 'terser-webpack-plugin';
+import { createUMDBase } from './webpack.shared.umd.base.js';
/**
* Webpack Bundle Analyzer Configuration
@@ -19,157 +19,157 @@ import TerserPlugin from 'terser-webpack-plugin';
// Environment variables for controlling analysis
const ANALYZE_OPEN = process.env.ANALYZE_OPEN === 'true'; // Don't open browser by default
const ANALYZE_MODE = process.env.ANALYZE_MODE || 'static'; // 'server' | 'static' | 'json' | 'disabled'
-const ANALYZE_PORT = parseInt(process.env.ANALYZE_PORT || '8888');
+const ANALYZE_PORT = parseInt(process.env.ANALYZE_PORT || '8888', 10);
/**
* Create analyzer configuration for a specific build target
*/
export function createAnalyzerConfig(buildTarget = 'server', options = {}, env = {}) {
- const {
- filename = `${buildTarget}.umd.analysis.js`,
- outputPath = `analysis/${buildTarget}`,
- reportsPath = `reports/analysis`, // Machine-readable reports go to reports directory
- minimize = false, // Don't minify for analysis by default to see clear module names
- ...otherOptions
- } = options;
+ const {
+ filename = `${buildTarget}.umd.analysis.js`,
+ outputPath = `analysis/${buildTarget}`,
+ reportsPath = 'reports/analysis', // Machine-readable reports go to reports directory
+ minimize = false, // Don't minify for analysis by default to see clear module names
+ ...otherOptions
+ } = options;
- // Support both old minimize and new FULL environment variable systems
- // New system: FULL=1 means non-minified, FULL=0 or absence means minified
- // Old system: minimize=true means minified
- let shouldMinimize;
- if (env.minimize !== undefined) {
- // Old system for backward compatibility
- shouldMinimize = env.minimize === 'true' || env.minimize === true;
- } else if (options.minimize !== undefined) {
- // If minimize is explicitly passed in options, use it (takes precedence)
- shouldMinimize = options.minimize;
- } else {
- // New system: Check FULL environment variable
- const fullBuild = process.env.FULL === '1' || env.full === 'true' || env.full === true;
+ // Support both old minimize and new FULL environment variable systems
+ // New system: FULL=1 means non-minified, FULL=0 or absence means minified
+ // Old system: minimize=true means minified
+ let shouldMinimize;
+ if (env.minimize !== undefined) {
+ // Old system for backward compatibility
+ shouldMinimize = env.minimize === 'true' || env.minimize === true;
+ } else if (options.minimize !== undefined) {
+ // If minimize is explicitly passed in options, use it (takes precedence)
+ shouldMinimize = options.minimize;
+ } else {
+ // New system: Check FULL environment variable
+ const fullBuild = process.env.FULL === '1' || env.full === 'true' || env.full === true;
- if (fullBuild) {
- // FULL=1 explicitly requests non-minified
- shouldMinimize = false;
- } else {
- // Default when FULL is absent or FULL=0: minified (production-ready analyzer builds)
- shouldMinimize = true;
- }
+ if (fullBuild) {
+ // FULL=1 explicitly requests non-minified
+ shouldMinimize = false;
+ } else {
+ // Default when FULL is absent or FULL=0: minified (production-ready analyzer builds)
+ shouldMinimize = true;
}
+ }
- // Ensure filename reflects build type for better differentiation
- const actualFilename = shouldMinimize ? filename.replace('.analysis.js', '.min.analysis.js') : filename.replace('.min.analysis.js', '.analysis.js');
+ // Ensure filename reflects build type for better differentiation
+ const actualFilename = shouldMinimize ? filename.replace('.analysis.js', '.min.analysis.js') : filename.replace('.min.analysis.js', '.analysis.js');
- // Ensure the reports directory exists for analyzer output
- const reportsDir = resolve(reportsPath);
- if (!existsSync(reportsDir)) {
- mkdirSync(reportsDir, { recursive: true });
- }
+ // Ensure the reports directory exists for analyzer output
+ const reportsDir = resolve(reportsPath);
+ if (!existsSync(reportsDir)) {
+ mkdirSync(reportsDir, { recursive: true });
+ }
- const baseConfig = createUMDBase({
- buildTarget,
- filename: actualFilename,
- minimize: shouldMinimize,
- ...otherOptions
- });
+ const baseConfig = createUMDBase({
+ buildTarget,
+ filename: actualFilename,
+ minimize: shouldMinimize,
+ ...otherOptions,
+ });
- // Override Terser configuration for analyzer builds to avoid plugin conflicts
- if (shouldMinimize && baseConfig.optimization && baseConfig.optimization.minimizer) {
- // Use Terser configuration that preserves build flags for analyzer builds
- baseConfig.optimization.minimizer = [
- new TerserPlugin({
- terserOptions: {
- // Preserve build flags during minification
- mangle: {
- reserved: [
- 'globalThis',
- 'OptaveJavaScriptSDK',
- 'window',
- 'self',
- 'root',
- 'factory',
- 'webpackUniversalModuleDefinition',
- '__WEBPACK_BUILD_TARGET__',
- '__SALESFORCE_BUILD__',
- '__SDK_VERSION__',
- '__INCLUDE_WS_REQUIRE__'
- ]
- },
- compress: {
- drop_console: false,
- unused: false,
- side_effects: false,
- // Preserve build target strings by disabling optimizations that could remove them
- dead_code: false,
- evaluate: false,
- conditionals: false,
- // Keep essential build information
- keep_fnames: /^__(WEBPACK_BUILD_TARGET|SALESFORCE_BUILD|SDK_VERSION|INCLUDE_WS_REQUIRE)__|webpackUniversalModuleDefinition$/
- },
- format: {
- comments: false
- }
- },
- extractComments: false
- })
- ];
- }
+ // Override Terser configuration for analyzer builds to avoid plugin conflicts
+ if (shouldMinimize && baseConfig.optimization && baseConfig.optimization.minimizer) {
+ // Use Terser configuration that preserves build flags for analyzer builds
+ baseConfig.optimization.minimizer = [
+ new TerserPlugin({
+ terserOptions: {
+ // Preserve build flags during minification
+ mangle: {
+ reserved: [
+ 'globalThis',
+ 'OptaveJavaScriptSDK',
+ 'window',
+ 'self',
+ 'root',
+ 'factory',
+ 'webpackUniversalModuleDefinition',
+ '__WEBPACK_BUILD_TARGET__',
+ '__SALESFORCE_BUILD__',
+ '__SDK_VERSION__',
+ '__INCLUDE_WS_REQUIRE__',
+ ],
+ },
+ compress: {
+ drop_console: false,
+ unused: false,
+ side_effects: false,
+ // Preserve build target strings by disabling optimizations that could remove them
+ dead_code: false,
+ evaluate: false,
+ conditionals: false,
+ // Keep essential build information
+ keep_fnames: /^__(WEBPACK_BUILD_TARGET|SALESFORCE_BUILD|SDK_VERSION|INCLUDE_WS_REQUIRE)__|webpackUniversalModuleDefinition$/,
+ },
+ format: {
+ comments: false,
+ },
+ },
+ extractComments: false,
+ }),
+ ];
+ }
- return {
- ...baseConfig,
- output: {
- ...baseConfig.output,
- filename: actualFilename,
- path: path.resolve(`dist/${outputPath}`)
+ return {
+ ...baseConfig,
+ output: {
+ ...baseConfig.output,
+ filename: actualFilename,
+ path: path.resolve(`dist/${outputPath}`),
+ },
+ plugins: [
+ ...baseConfig.plugins,
+ new BundleAnalyzerPlugin({
+ analyzerMode: ANALYZE_MODE,
+ analyzerHost: 'localhost',
+ analyzerPort: ANALYZE_PORT + (buildTarget === 'browser' ? 1 : 0), // Different ports for different builds
+ openAnalyzer: ANALYZE_OPEN,
+ generateStatsFile: true,
+ statsFilename: path.resolve(`${reportsPath}/${buildTarget}-stats.json`),
+ reportFilename: path.resolve(`${reportsPath}/${buildTarget}-report.html`),
+ logLevel: 'info',
+ // Custom bundle size analysis
+ statsOptions: {
+ source: true,
+ chunks: true,
+ chunkModules: true,
+ modules: true,
+ modulesSpace: 999,
+ reasons: true,
+ usedExports: true,
+ providedExports: true,
+ optimizationBailout: true,
+ errorDetails: true,
+ publicPath: true,
+ exclude: false,
},
- plugins: [
- ...baseConfig.plugins,
- new BundleAnalyzerPlugin({
- analyzerMode: ANALYZE_MODE,
- analyzerHost: 'localhost',
- analyzerPort: ANALYZE_PORT + (buildTarget === 'browser' ? 1 : 0), // Different ports for different builds
- openAnalyzer: ANALYZE_OPEN,
- generateStatsFile: true,
- statsFilename: path.resolve(`${reportsPath}/${buildTarget}-stats.json`),
- reportFilename: path.resolve(`${reportsPath}/${buildTarget}-report.html`),
- logLevel: 'info',
- // Custom bundle size analysis
- statsOptions: {
- source: true,
- chunks: true,
- chunkModules: true,
- modules: true,
- modulesSpace: 999,
- reasons: true,
- usedExports: true,
- providedExports: true,
- optimizationBailout: true,
- errorDetails: true,
- publicPath: true,
- exclude: false
- }
- })
- ]
- };
+ }),
+ ],
+ };
}
// Default exports for different build targets
export const browserAnalyzerConfig = createAnalyzerConfig('browser', {
- filename: 'browser.umd.analysis.js'
+ filename: 'browser.umd.analysis.js',
});
export const serverAnalyzerConfig = createAnalyzerConfig('server', {
- filename: 'server.umd.analysis.js'
+ filename: 'server.umd.analysis.js',
});
export const serverMinAnalyzerConfig = createAnalyzerConfig('server', {
- filename: 'server.umd.min.analysis.js',
- minimize: true
+ filename: 'server.umd.min.analysis.js',
+ minimize: true,
});
// Default export for webpack CLI - function that accepts environment variables
export default (env = {}) => {
- const buildTarget = env.buildTarget || 'server';
- return createAnalyzerConfig(buildTarget, {
- filename: `${buildTarget}.umd.analysis.js`
- }, env);
-};
\ No newline at end of file
+ const buildTarget = env.buildTarget || 'server';
+ return createAnalyzerConfig(buildTarget, {
+ filename: `${buildTarget}.umd.analysis.js`,
+ }, env);
+};
diff --git a/sdks/javascript/webpack.browser.config.js b/sdks/javascript/webpack.browser.config.js
index 20c86e4..c3916b2 100644
--- a/sdks/javascript/webpack.browser.config.js
+++ b/sdks/javascript/webpack.browser.config.js
@@ -13,71 +13,71 @@ const shouldMinify = process.env.FULL !== '1';
const filename = shouldMinify ? 'browser.mjs' : 'browser.full.mjs';
export default {
- entry: './runtime/core/main.js',
- target: 'web',
- output: {
- filename,
- path: path.resolve('dist'),
- library: {
- type: 'module',
- export: 'default',
- },
- environment: {
- module: true,
- },
- chunkFormat: 'module',
- publicPath: '',
+ entry: './runtime/core/main.js',
+ target: 'web',
+ output: {
+ filename,
+ path: path.resolve('dist'),
+ library: {
+ type: 'module',
+ export: 'default',
},
- experiments: {
- outputModule: true,
+ environment: {
+ module: true,
},
- mode: 'production',
- devtool: false, // ESM builds don't generate source maps by default (only UMD builds need source maps for CSP compliance)
- resolve: {
- alias: browserAliases,
- fallback: fallbackBrowser
- },
- module: {
- rules: [
- // No transpilation needed - target browsers support ES6+ natively
- ],
- },
- plugins: [
- new webpack.DefinePlugin({
- __WEBPACK_BUILD_TARGET__: JSON.stringify(BUILD_TARGETS.BROWSER_ESM),
- 'process.versions.node': 'undefined',
- __INCLUDE_WS_REQUIRE__: false,
- __SDK_VERSION__: JSON.stringify(packageJson.version),
- }),
- // Replace AJV with CSP-safe validators for browser builds
- new webpack.NormalModuleReplacementPlugin(/ajv/, path.resolve('./runtime/platform/browser/ajv-stub.js')),
+ chunkFormat: 'module',
+ publicPath: '',
+ },
+ experiments: {
+ outputModule: true,
+ },
+ mode: 'production',
+ devtool: false, // ESM builds don't generate source maps by default (only UMD builds need source maps for CSP compliance)
+ resolve: {
+ alias: browserAliases,
+ fallback: fallbackBrowser,
+ },
+ module: {
+ rules: [
+ // No transpilation needed - target browsers support ES6+ natively
],
- externals: {
- // Don't bundle Node.js specific packages for browser
- },
- optimization: {
- minimize: shouldMinify,
- splitChunks: false, // Disable chunk splitting for single bundle file
- runtimeChunk: false, // Disable runtime chunk
- usedExports: true, // Mark used/unused exports for tree-shaking
- sideEffects: false, // Let package.json sideEffects field control tree-shaking
- providedExports: true, // Determine exports for each module
+ },
+ plugins: [
+ new webpack.DefinePlugin({
+ __WEBPACK_BUILD_TARGET__: JSON.stringify(BUILD_TARGETS.BROWSER_ESM),
+ 'process.versions.node': 'undefined',
+ __INCLUDE_WS_REQUIRE__: false,
+ __SDK_VERSION__: JSON.stringify(packageJson.version),
+ }),
+ // Replace AJV with CSP-safe validators for browser builds
+ new webpack.NormalModuleReplacementPlugin(/ajv/, path.resolve('./runtime/platform/browser/ajv-stub.js')),
+ ],
+ externals: {
+ // Don't bundle Node.js specific packages for browser
+ },
+ optimization: {
+ minimize: shouldMinify,
+ splitChunks: false, // Disable chunk splitting for single bundle file
+ runtimeChunk: false, // Disable runtime chunk
+ usedExports: true, // Mark used/unused exports for tree-shaking
+ sideEffects: false, // Let package.json sideEffects field control tree-shaking
+ providedExports: true, // Determine exports for each module
- // ALWAYS configure TerserPlugin for license extraction (even in non-minified builds)
- // This ensures legal compliance regardless of build type
- minimizer: [
- new TerserPlugin({
- minify: shouldMinify ? TerserPlugin.terserMinify : undefined,
- terserOptions: shouldMinify ? {
- format: {
- // Preserve important comments (comments starting with !)
- comments: /^!/
- }
- } : {},
- // CRITICAL: Extract licenses in ALL builds (minified and full)
- // This will automatically catch and extract licenses from bundled dependencies
- extractComments: true
- })
- ]
- }
-};
\ No newline at end of file
+ // ALWAYS configure TerserPlugin for license extraction (even in non-minified builds)
+ // This ensures legal compliance regardless of build type
+ minimizer: [
+ new TerserPlugin({
+ minify: shouldMinify ? TerserPlugin.terserMinify : undefined,
+ terserOptions: shouldMinify ? {
+ format: {
+ // Preserve important comments (comments starting with !)
+ comments: /^!/,
+ },
+ } : {},
+ // CRITICAL: Extract licenses in ALL builds (minified and full)
+ // This will automatically catch and extract licenses from bundled dependencies
+ extractComments: true,
+ }),
+ ],
+ },
+};
diff --git a/sdks/javascript/webpack.browser.umd.config.js b/sdks/javascript/webpack.browser.umd.config.js
index 1917705..ff372c3 100644
--- a/sdks/javascript/webpack.browser.umd.config.js
+++ b/sdks/javascript/webpack.browser.umd.config.js
@@ -5,8 +5,8 @@ const shouldMinify = process.env.FULL !== '1';
const filename = shouldMinify ? 'browser.umd.js' : 'browser.umd.full.js';
export default createUMDBase({
- buildTarget: 'browser',
- filename,
- minimize: shouldMinify,
- salesforceBuild: false
-});
\ No newline at end of file
+ buildTarget: 'browser',
+ filename,
+ minimize: shouldMinify,
+ salesforceBuild: false,
+});
diff --git a/sdks/javascript/webpack.server.config.js b/sdks/javascript/webpack.server.config.js
index 8aac51c..c9e74ff 100644
--- a/sdks/javascript/webpack.server.config.js
+++ b/sdks/javascript/webpack.server.config.js
@@ -12,74 +12,74 @@ const shouldMinify = process.env.FULL !== '1';
const filename = shouldMinify ? 'server.mjs' : 'server.full.mjs';
export default {
- entry: './runtime/core/main.js',
- target: 'node',
- output: {
- filename,
- path: path.resolve('dist'),
- library: {
- type: 'module',
- export: 'default',
- },
- environment: {
- module: true,
- },
- chunkFormat: 'module',
- publicPath: '',
+ entry: './runtime/core/main.js',
+ target: 'node',
+ output: {
+ filename,
+ path: path.resolve('dist'),
+ library: {
+ type: 'module',
+ export: 'default',
},
- experiments: {
- outputModule: true,
+ environment: {
+ module: true,
},
- mode: 'production',
- devtool: false, // ESM builds don't generate source maps by default (only UMD builds need source maps for CSP compliance)
- externals: {
- // Keep Node.js modules as externals
- 'ws': 'ws',
- 'events': 'events',
- 'crypto': 'crypto',
- 'fs': 'fs',
- 'path': 'path',
- 'util': 'util',
- 'buffer': 'buffer',
- 'stream': 'stream',
- // Bundle AJV and related packages in server builds for full validation capabilities
- // This ensures server.mjs includes AJV validation and is larger than CSP-compliant builds
- },
- module: {
- rules: [
- // No transpilation needed - Node.js 18.17+ supports ES6+ natively
- ],
- },
- plugins: [
- new webpack.DefinePlugin({
- __WEBPACK_BUILD_TARGET__: JSON.stringify(BUILD_TARGETS.SERVER_ESM),
- __INCLUDE_WS_REQUIRE__: true,
- __SDK_VERSION__: JSON.stringify(packageJson.version),
- }),
+ chunkFormat: 'module',
+ publicPath: '',
+ },
+ experiments: {
+ outputModule: true,
+ },
+ mode: 'production',
+ devtool: false, // ESM builds don't generate source maps by default (only UMD builds need source maps for CSP compliance)
+ externals: {
+ // Keep Node.js modules as externals
+ ws: 'ws',
+ events: 'events',
+ crypto: 'crypto',
+ fs: 'fs',
+ path: 'path',
+ util: 'util',
+ buffer: 'buffer',
+ stream: 'stream',
+ // Bundle AJV and related packages in server builds for full validation capabilities
+ // This ensures server.mjs includes AJV validation and is larger than CSP-compliant builds
+ },
+ module: {
+ rules: [
+ // No transpilation needed - Node.js 18.17+ supports ES6+ natively
],
- optimization: {
- minimize: shouldMinify,
- splitChunks: false, // Disable chunk splitting for single bundle file
- runtimeChunk: false, // Disable runtime chunk
- usedExports: true, // Mark used/unused exports for tree-shaking
- sideEffects: false, // Let package.json sideEffects field control tree-shaking
- providedExports: true, // Determine exports for each module
+ },
+ plugins: [
+ new webpack.DefinePlugin({
+ __WEBPACK_BUILD_TARGET__: JSON.stringify(BUILD_TARGETS.SERVER_ESM),
+ __INCLUDE_WS_REQUIRE__: true,
+ __SDK_VERSION__: JSON.stringify(packageJson.version),
+ }),
+ ],
+ optimization: {
+ minimize: shouldMinify,
+ splitChunks: false, // Disable chunk splitting for single bundle file
+ runtimeChunk: false, // Disable runtime chunk
+ usedExports: true, // Mark used/unused exports for tree-shaking
+ sideEffects: false, // Let package.json sideEffects field control tree-shaking
+ providedExports: true, // Determine exports for each module
- // ALWAYS configure TerserPlugin for license extraction (even in non-minified builds)
- // This ensures legal compliance regardless of build type
- minimizer: [
- new TerserPlugin({
- minify: shouldMinify ? TerserPlugin.terserMinify : undefined,
- terserOptions: shouldMinify ? {
- format: {
- // Preserve important comments (comments starting with !)
- comments: /^!/
- }
- } : {},
- // CRITICAL: Extract licenses in ALL builds (minified and full)
- // This will automatically catch and extract licenses from bundled dependencies
- extractComments: true
- })
- ]
- }
-};
\ No newline at end of file
+ // ALWAYS configure TerserPlugin for license extraction (even in non-minified builds)
+ // This ensures legal compliance regardless of build type
+ minimizer: [
+ new TerserPlugin({
+ minify: shouldMinify ? TerserPlugin.terserMinify : undefined,
+ terserOptions: shouldMinify ? {
+ format: {
+ // Preserve important comments (comments starting with !)
+ comments: /^!/,
+ },
+ } : {},
+ // CRITICAL: Extract licenses in ALL builds (minified and full)
+ // This will automatically catch and extract licenses from bundled dependencies
+ extractComments: true,
+ }),
+ ],
+ },
+};
diff --git a/sdks/javascript/webpack.server.umd.config.js b/sdks/javascript/webpack.server.umd.config.js
index 267a1c5..c7f4e6a 100644
--- a/sdks/javascript/webpack.server.umd.config.js
+++ b/sdks/javascript/webpack.server.umd.config.js
@@ -4,18 +4,15 @@ import { createUMDBase } from './webpack.shared.umd.base.js';
const shouldMinify = process.env.FULL !== '1';
const filename = shouldMinify ? 'server.umd.js' : 'server.umd.full.js';
-// Server UMD configuration for Salesforce Lightning deployment
-// - Deploy as .js static resource in Salesforce (NOT for Node.js require())
-// - Access via globalThis.OptaveJavaScriptSDK or window.OptaveJavaScriptSDK
-// - Test using vm.runInNewContext() or browser environment, NOT require()
-
-// Current approach: Using webpack's standard UMD with export:'default' to avoid getter patterns.
-// We also perform an explicit globalThis assignment inside umd-entry.js so that even when
-// the AMD branch runs (define()), the constructor is still reachable via globalThis.OptaveJavaScriptSDK.
+// Server UMD configuration for Node.js environments
+// - Targets Node.js runtime with UMD module format
+// - Use via require() in CommonJS environments
+// - Externalizes Node.js built-in modules (crypto, events, etc.)
+// - Access via require('path/to/server.umd.js') or as UMD global
export default createUMDBase({
- buildTarget: 'server',
- filename,
- minimize: shouldMinify,
- salesforceBuild: true
-});
\ No newline at end of file
+ buildTarget: 'server',
+ filename,
+ minimize: shouldMinify,
+ salesforceBuild: false, // Server UMD is for Node.js, not Salesforce
+});
diff --git a/sdks/javascript/webpack.shared.umd.base.js b/sdks/javascript/webpack.shared.umd.base.js
index a8005eb..7d51e2a 100644
--- a/sdks/javascript/webpack.shared.umd.base.js
+++ b/sdks/javascript/webpack.shared.umd.base.js
@@ -1,155 +1,179 @@
import path from 'path';
import webpack from 'webpack';
-import { readFileSync } from 'fs';
import TerserPlugin from 'terser-webpack-plugin';
+import { readFileSync } from 'fs';
import { BUILD_TARGETS } from './runtime/core/build-targets.js';
-import { umdAliases, browserUmdAliases, fallbackUMD, fallbackBrowserUMD, fallbackServerUMD } from './scripts/prod/webpack/aliases.js';
-import { LWSStrictModeRemovalPlugin } from './scripts/prod/webpack/lws-strict-mode-plugin.js';
+import {
+ browserUmdAliases,
+ serverUmdAliases,
+ fallbackBrowserUMD,
+ fallbackServerUMD,
+} from './scripts/prod/webpack/aliases.js';
+import LWSStrictModeRemovalPlugin from './scripts/prod/webpack/lws-strict-mode-plugin.js';
// Read package.json to get version
const packageJson = JSON.parse(readFileSync(path.resolve('package.json'), 'utf8'));
// Shared UMD base (browser + server)
export const createUMDBase = (options = {}) => {
- const {
- buildTarget = 'browser', // 'browser' or 'server' (legacy)
- filename = 'build.umd.js',
- // Note: Uses 'minimize' as parameter name (not 'shouldMinify' like standalone configs)
- // This follows webpack's standard terminology for reusable factory functions
- // Standalone configs compute their own minification logic and pass it here
- minimize = false,
- salesforceBuild = false
- } = options;
-
- // Convert legacy build target to specific UMD build target
- const umdBuildTarget = buildTarget === 'browser'
- ? BUILD_TARGETS.BROWSER_UMD
- : BUILD_TARGETS.SERVER_UMD;
-
- return {
- entry: './runtime/core/umd-entry.js',
- target: 'web', // UMD must target web environment for browser/Salesforce compatibility
-
- output: {
- filename,
- path: path.resolve('dist'),
- // Traditional UMD wrapper for Salesforce Lightning compatibility
- library: 'OptaveJavaScriptSDK',
- libraryTarget: 'umd', // Use traditional libraryTarget for (function(root, factory) wrapper
- libraryExport: 'default',
- umdNamedDefine: true, // Named AMD define for Salesforce compatibility
- environment: {
- module: false,
- },
- globalObject: buildTarget === 'browser'
- ? '(function() { return typeof globalThis !== \'undefined\' ? globalThis : (typeof self !== \'undefined\' ? self : (typeof window !== \'undefined\' ? window : this)); })()'
- : '(function() { return typeof globalThis !== \'undefined\' ? globalThis : (typeof window !== \'undefined\' ? window : this); })()',
- publicPath: '',
- },
-
- mode: 'production',
- // External source maps for CSP compliance and debugging
- // source-map generates external .map files (required for Salesforce Lightning CSP)
- devtool: 'source-map',
-
- // Lightning Web Security Compliance: Avoid explicit "use strict" injection
- // Server UMD must be completely self-contained with no externals for Salesforce deployment
- externals: {}, // IMPORTANT: Empty = self-contained (do not add external dependencies)
-
- resolve: {
- // Ensure webpack can resolve all modules
- modules: ['node_modules'],
- extensions: ['.js', '.mjs', '.json'],
- // Use centralized alias configuration based on build target
- alias: buildTarget === 'browser' ? browserUmdAliases : umdAliases,
- fallback: buildTarget === 'browser' ? fallbackBrowserUMD : fallbackServerUMD
- },
-
- module: {
- rules: [
- // No transpilation needed - target browsers and Node.js support ES6+ natively
- ],
- },
-
- plugins: [
- new webpack.DefinePlugin({
- __WEBPACK_BUILD_TARGET__: JSON.stringify(umdBuildTarget), // Accurate UMD build target (browser-umd or server-umd)
- __INCLUDE_WS_REQUIRE__: false, // Disable WebSocket require for browser environment
- __SDK_VERSION__: JSON.stringify(packageJson.version),
- __SALESFORCE_BUILD__: salesforceBuild, // Server UMD is specifically for Salesforce deployment
- // Browser builds should not have process.versions.node references
- // Provide minimal process object for third-party library compatibility
- ...(buildTarget === 'browser' && {
- 'process.versions.node': 'undefined',
- 'process.version': 'undefined',
- 'process.env': '{}',
- 'process.versions': '{}'
- })
- }),
-
- // Provide browser APIs for UMD builds
- new webpack.ProvidePlugin({
- URLSearchParams: [path.resolve('./runtime/platform/browser/urlsearchparams-polyfill.js'), 'URLSearchParams'],
- }),
-
- // Browser builds: Replace AJV with CSP-safe validators
- ...(buildTarget === 'browser' ? [
- new webpack.NormalModuleReplacementPlugin(/ajv/, path.resolve('./runtime/platform/browser/ajv-stub.js'))
- ] : []),
-
- // LIGHTNING WEB SECURITY COMPLIANCE: Remove explicit "use strict" declarations
- new LWSStrictModeRemovalPlugin({
- verbose: process.env.NODE_ENV === 'development' || process.env.VERBOSE_BUILD === '1'
- }),
+ const {
+ buildTarget = 'browser', // 'browser' or 'server' (legacy)
+ filename = 'build.umd.js',
+ // Note: Uses 'minimize' as parameter name (not 'shouldMinify' like standalone configs)
+ // This follows webpack's standard terminology for reusable factory functions
+ // Standalone configs compute their own minification logic and pass it here
+ minimize = false,
+ salesforceBuild = false,
+ } = options;
+
+ // Convert legacy build target to specific UMD build target
+ const umdBuildTarget = buildTarget === 'browser' ? BUILD_TARGETS.BROWSER_UMD : BUILD_TARGETS.SERVER_UMD;
+
+ return {
+ entry: './runtime/core/umd-entry.js',
+ // Browser UMD targets web (browser/Salesforce), Server UMD targets Node.js
+ target: buildTarget === 'browser' ? 'web' : 'node',
+
+ output: {
+ filename,
+ path: path.resolve('dist'),
+ // Traditional UMD wrapper for Salesforce Lightning compatibility
+ library: 'OptaveJavaScriptSDK',
+ libraryTarget: 'umd', // Use traditional libraryTarget for (function(root, factory) wrapper
+ libraryExport: 'default',
+ umdNamedDefine: true, // Named AMD define for Salesforce compatibility
+ environment: {
+ module: false,
+ },
+ // Browser UMD is the Salesforce Lightning target: the LWC reads
+ // `window.OptaveJavaScriptSDK`, and under Lightning Locker the component's
+ // global is `window` (SecureWindow), not necessarily `globalThis`. So the
+ // browser branch resolves the UMD root as window -> self -> globalThis.
+ // Server UMD is Node.js: globalThis -> this.
+ globalObject:
+ buildTarget === 'browser'
+ ? "(function() { return typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : (typeof globalThis !== 'undefined' ? globalThis : this)); })()"
+ : "(typeof globalThis !== 'undefined' ? globalThis : this)",
+ publicPath: '',
+ },
+
+ mode: 'production',
+ // External source maps for CSP compliance and debugging
+ // source-map generates external .map files (required for Salesforce Lightning CSP)
+ devtool: 'source-map',
+
+ // Browser UMD: Self-contained (no externals) for Salesforce/CDN deployment
+ // Server UMD: Externalize Node.js built-in modules (they're provided by Node.js runtime)
+ externals: buildTarget === 'server' ? {
+ crypto: 'crypto',
+ events: 'events',
+ stream: 'stream',
+ util: 'util',
+ buffer: 'buffer',
+ ws: 'ws', // WebSocket module for Node.js
+ } : {}, // Browser UMD: Empty = self-contained (bundles everything)
+
+ resolve: {
+ // Ensure webpack can resolve all modules
+ modules: ['node_modules'],
+ extensions: ['.js', '.mjs', '.json'],
+ // Use centralized alias configuration based on build target
+ alias: buildTarget === 'browser' ? browserUmdAliases : serverUmdAliases,
+ fallback: buildTarget === 'browser' ? fallbackBrowserUMD : fallbackServerUMD,
+ },
+
+ module: {
+ rules: [
+ // No transpilation needed - target browsers and Node.js support ES6+ natively
+ ],
+ },
+
+ plugins: [
+ new webpack.DefinePlugin({
+ __WEBPACK_BUILD_TARGET__: JSON.stringify(umdBuildTarget), // Accurate UMD build target (browser-umd or server-umd)
+ __INCLUDE_WS_REQUIRE__: false, // Disable WebSocket require for browser environment
+ __SDK_VERSION__: JSON.stringify(packageJson.version),
+ // Security-exemption flag (consumed in config-validator as `isServerUmd`):
+ // when true, the build may accept a raw clientSecret in a client env.
+ // Kept false for both UMD builds — Salesforce auths with a token, not a
+ // secret, and Server UMD is Node.js. NOT a "this is the Salesforce build" flag.
+ __SALESFORCE_BUILD__: salesforceBuild,
+ // Browser builds should not have process.versions.node references
+ // Provide minimal process object for third-party library compatibility
+ ...(buildTarget === 'browser' && {
+ 'process.versions.node': 'undefined',
+ 'process.version': 'undefined',
+ 'process.env': '{}',
+ 'process.versions': '{}',
+ }),
+ }),
+
+ // Provide browser APIs for UMD builds
+ new webpack.ProvidePlugin({
+ URLSearchParams: [
+ path.resolve('./runtime/platform/browser/urlsearchparams-polyfill.js'),
+ 'URLSearchParams',
],
-
- optimization: {
- minimize, // Enable/disable minification based on build type
- // Simplified optimization settings for source map generation
- splitChunks: false, // Single file UMD bundle
-
- // ALWAYS configure TerserPlugin for license extraction (even in non-minified builds)
- // This ensures legal compliance regardless of build type
- minimizer: [
- new TerserPlugin({
- minify: minimize ? TerserPlugin.terserMinify : undefined,
- terserOptions: minimize ? {
- // Salesforce Lightning compatible minification settings
- mangle: {
- reserved: [
- 'globalThis',
- 'OptaveJavaScriptSDK',
- 'window',
- 'self',
- 'root',
- 'factory',
- 'webpackUniversalModuleDefinition',
- '__WEBPACK_BUILD_TARGET__',
- '__SALESFORCE_BUILD__',
- '__SDK_VERSION__',
- '__INCLUDE_WS_REQUIRE__'
- ]
- },
- compress: {
- // Preserve build flags and UMD wrapper structure
- unused: false,
- side_effects: false,
- // Keep essential build information
- keep_fnames: /^__(WEBPACK_BUILD_TARGET|SALESFORCE_BUILD|SDK_VERSION|INCLUDE_WS_REQUIRE)__|webpackUniversalModuleDefinition$/,
- drop_console: false
- },
- format: {
- // Keep critical comments and preserve UMD format
- comments: /SECURITY|CRITICAL|Salesforce.*Lightning|webpackUniversalModuleDefinition/i
- }
- } : {},
- // CRITICAL: Extract licenses in ALL builds (minified and full)
- // This will automatically catch and extract licenses from bundled dependencies
- extractComments: true
- })
- ]
- }
- };
+ }),
+
+ // Browser builds: Replace AJV with CSP-safe validators
+ ...(buildTarget === 'browser'
+ ? [
+ new webpack.NormalModuleReplacementPlugin(
+ /ajv/,
+ path.resolve('./runtime/platform/browser/ajv-stub.js'),
+ ),
+ ]
+ : []),
+
+ // LIGHTNING WEB SECURITY COMPLIANCE: Remove explicit "use strict" declarations
+ // This plugin is now SOURCE-MAP-AWARE and preserves source map accuracy
+ new LWSStrictModeRemovalPlugin({
+ verbose: process.env.NODE_ENV === 'development' || process.env.VERBOSE_BUILD === '1',
+ }),
+ ],
+
+ optimization: {
+ minimize, // Enable/disable minification based on build type
+ splitChunks: false, // Single file UMD bundle
+ minimizer: [
+ new TerserPlugin({
+ terserOptions: {
+ compress: {
+ // Disable aggressive optimizations that might break code
+ drop_console: false,
+ drop_debugger: false,
+ pure_funcs: [],
+ // Keep essential build information
+ keep_fnames:
+ /^__(WEBPACK_BUILD_TARGET|SALESFORCE_BUILD|SDK_VERSION|INCLUDE_WS_REQUIRE)__|webpackUniversalModuleDefinition$/,
+ },
+ mangle: {
+ reserved: [
+ 'globalThis',
+ 'OptaveJavaScriptSDK',
+ 'window',
+ 'self',
+ 'root',
+ 'factory',
+ 'webpackUniversalModuleDefinition',
+ '__WEBPACK_BUILD_TARGET__',
+ '__SALESFORCE_BUILD__',
+ '__SDK_VERSION__',
+ '__INCLUDE_WS_REQUIRE__',
+ ],
+ keep_classnames: true, // Preserve all class names
+ },
+ format: {
+ // Keep critical comments and preserve UMD format
+ comments: /SECURITY|CRITICAL|Salesforce.*Lightning|webpackUniversalModuleDefinition/i,
+ },
+ },
+ extractComments: true, // Extract comments to separate file
+ }),
+ ],
+ },
+ };
};
-export default createUMDBase;
\ No newline at end of file
+export default createUMDBase;