ttp-agent-sdk 2.44.0 β 2.45.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-widget.dev.js +2131 -646
- package/dist/agent-widget.dev.js.map +1 -1
- package/dist/agent-widget.esm.js +1 -1
- package/dist/agent-widget.esm.js.map +1 -1
- package/dist/agent-widget.js +1 -1
- package/dist/agent-widget.js.map +1 -1
- package/dist/demos/demo-sdk-loader.js +1 -0
- package/dist/demos/test-ecommerce.html +23 -42
- package/dist/demos/test-tour.html +15 -33
- package/dist/demos/test-widget.html +38 -18
- package/dist/demos/widget-customization-dev.html +15 -6
- package/dist/demos/widget-customization.html +14 -6
- package/dist/examples/demo-sdk-loader.js +1 -0
- package/dist/examples/ocado-cart-network-probe.js +1 -0
- package/dist/examples/sobeys-cart-dispatch-probe.js +1 -0
- package/dist/examples/sobeys-cart-read-test.html +112 -0
- package/dist/examples/sobeys-cart-read-test.js +1 -0
- package/dist/examples/sobeys-cart-subscribe-probe.js +1 -0
- package/dist/examples/sobeys-cart-subscribe-test.html +168 -0
- package/dist/examples/sobeys-cart-subscribe-test.js +1 -0
- package/dist/examples/sobeys-inject-probe-min.js +1 -0
- package/dist/examples/sobeys-inject-probe.js +1 -0
- package/dist/examples/test-ecommerce.html +23 -42
- package/dist/examples/test-tour.html +15 -33
- package/dist/examples/test-widget.html +38 -18
- package/dist/examples/widget-customization-dev.html +15 -6
- package/dist/examples/widget-customization.html +14 -6
- package/examples/demo-sdk-loader.js +249 -0
- package/examples/test-ecommerce.html +23 -42
- package/examples/test-tour.html +15 -33
- package/examples/test-widget.html +38 -18
- package/examples/widget-customization-dev.html +15 -6
- package/examples/widget-customization.html +14 -6
- package/package.json +2 -1
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<title>Sobeys cart.subscribe test</title>
|
|
6
|
+
<style>
|
|
7
|
+
body { font-family: system-ui, sans-serif; margin: 24px; max-width: 960px; }
|
|
8
|
+
pre { background: #111; color: #0f0; padding: 16px; overflow: auto; font-size: 12px; }
|
|
9
|
+
button { margin: 4px 8px 4px 0; padding: 8px 12px; cursor: pointer; }
|
|
10
|
+
.pass { color: #0a0; font-weight: bold; }
|
|
11
|
+
.fail { color: #c00; font-weight: bold; }
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>Sobeys <code>cart.subscribe</code> + <code>cart.add</code> integration test</h1>
|
|
16
|
+
<p>Mocks Redux store, cart.read adapter, and <code>netcost:partner-action:cart_mutation</code>.</p>
|
|
17
|
+
<button id="runAll">Run all tests</button>
|
|
18
|
+
<button id="manualAdd">Simulate manual site add</button>
|
|
19
|
+
<button id="voiceAdd">Simulate voice cart.add (with suppression)</button>
|
|
20
|
+
<div id="status"></div>
|
|
21
|
+
<pre id="out">Click Run all testsβ¦</pre>
|
|
22
|
+
|
|
23
|
+
<script>
|
|
24
|
+
window.__TTP_SOBEYS_TEST__ = true;
|
|
25
|
+
|
|
26
|
+
const state = {
|
|
27
|
+
shoppingListSlice: {
|
|
28
|
+
listId: 'mock-list',
|
|
29
|
+
shoppingListProducts: { products: [] },
|
|
30
|
+
taxSummary: { grandTotal: 0 },
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
window.__reduxStore = {
|
|
35
|
+
getState: () => state,
|
|
36
|
+
_subs: [],
|
|
37
|
+
subscribe(fn) {
|
|
38
|
+
this._subs.push(fn);
|
|
39
|
+
return () => { this._subs = this._subs.filter((f) => f !== fn); };
|
|
40
|
+
},
|
|
41
|
+
dispatch(action) {
|
|
42
|
+
if (action.type === 'shoppingListSlice/setItemListData' && action.payload && action.payload.items) {
|
|
43
|
+
const map = {};
|
|
44
|
+
state.shoppingListSlice.shoppingListProducts.products.forEach((p) => { map[p.item_id] = { ...p }; });
|
|
45
|
+
action.payload.items.forEach((item) => {
|
|
46
|
+
const qty = Number(item.quantity) || 0;
|
|
47
|
+
if (qty <= 0) delete map[item.item_id];
|
|
48
|
+
else map[item.item_id] = { ...map[item.item_id], ...item, quantity: qty };
|
|
49
|
+
});
|
|
50
|
+
state.shoppingListSlice.shoppingListProducts.products = Object.values(map);
|
|
51
|
+
}
|
|
52
|
+
this._subs.forEach((fn) => { try { fn(); } catch (e) {} });
|
|
53
|
+
return action;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
async function mockCartRead() {
|
|
58
|
+
const products = state.shoppingListSlice.shoppingListProducts.products || [];
|
|
59
|
+
const items = products.filter((p) => (Number(p.quantity) || 0) > 0).map((p) => ({
|
|
60
|
+
productId: p.item_id,
|
|
61
|
+
productName: p.name || '',
|
|
62
|
+
quantity: Number(p.quantity) || 0,
|
|
63
|
+
price: Number(p.price) || 0,
|
|
64
|
+
subtotal: 0,
|
|
65
|
+
sellBy: String(p.item_id).indexOf('_KG_') >= 0 ? 'weight' : 'quantity',
|
|
66
|
+
}));
|
|
67
|
+
const itemCount = items.reduce((n, i) => n + i.quantity, 0);
|
|
68
|
+
return { ok: true, success: true, items, itemCount, total: 0, currency: 'CAD' };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const emits = [];
|
|
72
|
+
|
|
73
|
+
async function installSubscribe() {
|
|
74
|
+
// Reset for repeatable test runs
|
|
75
|
+
if (typeof window.__ttpSobeysStoreUnsub === 'function') {
|
|
76
|
+
window.__ttpSobeysStoreUnsub();
|
|
77
|
+
window.__ttpSobeysStoreUnsub = null;
|
|
78
|
+
}
|
|
79
|
+
window.__ttpSobeysCartSubscribeInstalled = false;
|
|
80
|
+
window.__ttpSobeysPrevItemMap = new Map();
|
|
81
|
+
window.__ttpSobeysSuppressedIds = new Map();
|
|
82
|
+
|
|
83
|
+
if (!window.__ttpSobeysCartSubscribeInstall) {
|
|
84
|
+
const script = document.createElement('script');
|
|
85
|
+
script.src = 'sobeys-cart-subscribe-test.js';
|
|
86
|
+
document.head.appendChild(script);
|
|
87
|
+
await new Promise((r) => { script.onload = r; });
|
|
88
|
+
}
|
|
89
|
+
const ctx = {
|
|
90
|
+
args: {},
|
|
91
|
+
log: (...a) => console.log('[adapter:cart.subscribe]', ...a),
|
|
92
|
+
emit: (payload) => { emits.push(payload); },
|
|
93
|
+
runAdapter: async (action) => {
|
|
94
|
+
if (action === 'cart.read') return mockCartRead();
|
|
95
|
+
return { ok: false, reason: 'unknown' };
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
await window.__ttpSobeysCartSubscribeInstall(ctx);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function firePartnerMutation(args) {
|
|
102
|
+
window.dispatchEvent(new CustomEvent('netcost:partner-action:cart_mutation', {
|
|
103
|
+
detail: { action: 'cart.add', args },
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function voiceCartAdd(sku, qty) {
|
|
108
|
+
firePartnerMutation({ sku, qty, name: 'voice item' });
|
|
109
|
+
window.__reduxStore.dispatch({
|
|
110
|
+
type: 'shoppingListSlice/setItemListData',
|
|
111
|
+
payload: { items: [{ item_id: sku, product_type: 'Product', quantity: qty, name: 'voice item' }] },
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function manualSiteAdd(sku, name) {
|
|
116
|
+
window.__reduxStore.dispatch({
|
|
117
|
+
type: 'shoppingListSlice/setItemListData',
|
|
118
|
+
payload: { items: [{ item_id: sku, product_type: 'Product', quantity: 1, name }] },
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function runAllTests() {
|
|
123
|
+
emits.length = 0;
|
|
124
|
+
state.shoppingListSlice.shoppingListProducts.products = [];
|
|
125
|
+
await installSubscribe();
|
|
126
|
+
await new Promise((r) => setTimeout(r, 700));
|
|
127
|
+
|
|
128
|
+
const initialCount = emits.filter((e) => e.t === 'cart_change_event' && !e.change).length;
|
|
129
|
+
emits.length = 0;
|
|
130
|
+
|
|
131
|
+
voiceCartAdd('577689_EA_0320', 1);
|
|
132
|
+
await new Promise((r) => setTimeout(r, 700));
|
|
133
|
+
const voiceEmits = emits.filter((e) => e.change).length;
|
|
134
|
+
|
|
135
|
+
manualSiteAdd('247400_EA_0320', 'Bread');
|
|
136
|
+
await new Promise((r) => setTimeout(r, 700));
|
|
137
|
+
const manualEmits = emits.filter((e) => e.change && e.change.added.some((a) => a.id === '247400_EA_0320')).length;
|
|
138
|
+
|
|
139
|
+
const report = {
|
|
140
|
+
initialSnapshot: initialCount === 1,
|
|
141
|
+
voiceAddSuppressed: voiceEmits === 0,
|
|
142
|
+
voiceAddCacheOnly: emits.some(function (e) {
|
|
143
|
+
return e.t === 'cart_change_event' && !e.change &&
|
|
144
|
+
(e.cart && e.cart.items || []).some(function (i) { return i.productId === '577689_EA_0320'; });
|
|
145
|
+
}),
|
|
146
|
+
manualAddEmitted: manualEmits >= 1,
|
|
147
|
+
pass: initialCount === 1 && voiceEmits === 0 && manualEmits >= 1,
|
|
148
|
+
emits,
|
|
149
|
+
};
|
|
150
|
+
document.getElementById('out').textContent = JSON.stringify(report, null, 2);
|
|
151
|
+
document.getElementById('status').innerHTML = report.pass
|
|
152
|
+
? '<span class="pass">PASS</span>'
|
|
153
|
+
: '<span class="fail">FAIL</span>';
|
|
154
|
+
return report;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
document.getElementById('runAll').onclick = runAllTests;
|
|
158
|
+
document.getElementById('manualAdd').onclick = async () => {
|
|
159
|
+
await installSubscribe();
|
|
160
|
+
manualSiteAdd('999999_EA_0320', 'Manual Product');
|
|
161
|
+
};
|
|
162
|
+
document.getElementById('voiceAdd').onclick = async () => {
|
|
163
|
+
await installSubscribe();
|
|
164
|
+
voiceCartAdd('888888_EA_0320', 1);
|
|
165
|
+
};
|
|
166
|
+
</script>
|
|
167
|
+
</body>
|
|
168
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
window.__ttpSobeysCartSubscribeInstall=async t=>{if(!window.__TTP_SOBEYS_TEST__&&!/(^|\.)sobeys\.com$/.test(location.hostname))return{ok:!1,reason:"cross_origin_widget",host:location.hostname};if("function"!=typeof t.emit)return t.log("ctx.emit not available β falling back to on-demand get_cart"),{ok:!0,subscribed:!1,reason:"emit_unavailable"};window.__ttpSobeysSuppressedIds||(window.__ttpSobeysSuppressedIds=new Map);const e=window.__ttpSobeysSuppressedIds;function n(t){if(!t)return!1;const n=String(t).trim(),o=e.get(n);return!(!o||Date.now()>o&&(e.delete(n),1))}function o(){if(window.__reduxStore&&"function"==typeof window.__reduxStore.dispatch)return window.__reduxStore;function t(t,e){const n=[t];for(;n.length&&e-- >0;){const t=n.shift();if(!t)continue;const e=t.memoizedProps&&t.memoizedProps.store||t.memoizedState&&t.memoizedState.store||t.pendingProps&&t.pendingProps.store||t.stateNode&&t.stateNode.store;if(e&&"function"==typeof e.dispatch)return e;t.child&&n.push(t.child),t.sibling&&n.push(t.sibling),t.return&&n.push(t.return)}return null}function e(e){if(!e)return null;const n=Object.keys(e).filter(function(t){return 0===t.indexOf("__reactFiber")||0===t.indexOf("__reactContainer")||0===t.indexOf("__reactInternalInstance")});for(let o=0;o<n.length;o++){const r=n[o],i=t(e[r]&&(e[r].current||e[r])||null,800);if(i)return i}return null}const n=[document.getElementById("root"),document.getElementById("app"),document.body,document.body&&document.body.firstElementChild].filter(Boolean);for(let t=0;t<n.length;t++){const o=e(n[t]);if(o)return o}const o=document.querySelectorAll("body *");for(let t=0;t<Math.min(o.length,200);t++){const n=e(o[t]);if(n)return n}return null}function r(t){const e=new Map,n=t&&t.shoppingListSlice&&t.shoppingListSlice.shoppingListProducts&&t.shoppingListSlice.shoppingListProducts.products;if(!Array.isArray(n))return e;for(let t=0;t<n.length;t++){const o=n[t];if(!o||!o.item_id)continue;const r=Number(o.quantity)||0;r<=0||e.set(String(o.item_id),{qty:r,name:String(o.name||o.product_name||o.productName||"").trim()})}return e}async function i(){window.__ttpSobeysCartReadInFlight=(window.__ttpSobeysCartReadInFlight||0)+1;try{const e=await t.runAdapter("cart.read",{});return e&&!1!==e.ok?e:null}catch(e){return t.log("[cart.subscribe] cart.read error:",String(e&&e.message||e)),null}finally{window.__ttpSobeysCartReadInFlight=Math.max(0,(window.__ttpSobeysCartReadInFlight||1)-1)}}function s(){return window.__ttpSobeysPrevItemMap||new Map}function c(t){window.__ttpSobeysPrevItemMap=t}function a(e,a){window.__ttpSobeysDebounceTimer&&clearTimeout(window.__ttpSobeysDebounceTimer),window.__ttpSobeysDebounceTimer=setTimeout(function(){window.__ttpSobeysDebounceTimer=null,async function(e,a){const u=o(),d=r(u?u.getState():{});let l=s();if(a){const n=await i();return n?(c(d),t.emit({t:"cart_change_event",cart:n}),void t.log("[cart.subscribe] initial snapshot lines="+d.size+" itemCount="+(n.itemCount||0))):void t.log("[cart.subscribe] cart.read null β skip initial emit (source="+e+")")}const p=function(t,e){const n=[],o=[],r=[];for(const o of e){const e=o[0],i=o[1],s=t.get(e);s?s.qty!==i.qty&&r.push({id:e,name:i.name,from:s.qty,to:i.qty}):n.push({id:e,qty:i.qty,name:i.name})}for(const n of t){const t=n[0],r=n[1];e.has(t)||o.push({id:t,qty:r.qty,name:r.name})}return{added:n,removed:o,qtyChanged:r}}(l,d),_=p.added.filter(function(t){return!n(t.id)}),b=p.removed.filter(function(t){return!n(t.id)}),f=p.qtyChanged.filter(function(t){return!n(t.id)});if(t.log("[cart.subscribe] diff source="+e+" raw added="+p.added.length+" removed="+p.removed.length+" qty="+p.qtyChanged.length+" filtered added="+_.length+" removed="+b.length+" qty="+f.length),c(d),!_.length&&!b.length&&!f.length)return void t.log("[cart.subscribe] no emit (suppressed or no cart diff)");const w=await i();w?(t.log("[cart.subscribe] emitting cart_change_event"),t.emit({t:"cart_change_event",cart:w,change:{type:_.length?"add":b.length?"remove":"qty",added:_,removed:b,qtyChanged:f,at:Date.now()}})):t.log("[cart.subscribe] cart.read null β skip emit (source="+e+")")}(e,!!a).catch(function(e){t.log("[cart.subscribe] flush failed:",String(e&&e.message||e))})},500)}function u(){try{const t=sessionStorage.getItem("persist:root");if(!t)return"";const e=JSON.parse(t),n=e.shoppingListSlice?JSON.parse(e.shoppingListSlice):null,o=n&&n.shoppingListProducts&&n.shoppingListProducts.products;return Array.isArray(o)?o.map(function(t){return String(t.item_id||"")+":"+String(t.quantity||0)}).sort().join("|"):"empty"}catch(t){return""}}window.__ttpSobeysSuppressListenerBound||(window.__ttpSobeysSuppressListenerBound=!0,window.addEventListener("netcost:partner-action:cart_mutation",function(t){"function"==typeof window.__ttpSobeysOnPartnerMutation&&window.__ttpSobeysOnPartnerMutation(t)})),window.__ttpSobeysOnPartnerMutation=function(n){const o=function(t){if(!t||"object"!=typeof t)return[];const e=[],n=function(t){if(null==t||""===t)return;const n=String(t).trim();n&&e.push(n)};if(n(t.productId),n(t.sku),Array.isArray(t.items))for(let e=0;e<t.items.length;e++){const o=t.items[e];o&&"object"==typeof o&&(n(o.productId),n(o.sku),n(o.item_id))}return e}(n&&n.detail&&n.detail.args||{}),r=Date.now()+8e3;o.forEach(function(t){e.set(t,r)}),t.log("[cart.subscribe] suppressing productIds="+o.join(",")+" for 8000ms")},window.__ttpSobeysCartSubscribeInstalled?(t.log("[cart.subscribe] re-wiring refresh handler for new session ctx"),"function"==typeof window.__ttpSobeysStoreUnsub&&(window.__ttpSobeysStoreUnsub(),window.__ttpSobeysStoreUnsub=null),window.__ttpSobeysPersistPollId&&(clearInterval(window.__ttpSobeysPersistPollId),window.__ttpSobeysPersistPollId=null),window.__ttpSobeysDebounceTimer&&(clearTimeout(window.__ttpSobeysDebounceTimer),window.__ttpSobeysDebounceTimer=null)):window.__ttpSobeysCartSubscribeInstalled=!0,window.__ttpSobeysPrevItemMap||(window.__ttpSobeysPrevItemMap=new Map),window.__ttpSobeysCartScheduleRefresh=a;const d=await async function(){const e=Date.now()+3e4;let n=0;for(;Date.now()<e;){n++;const e=o();if(e)return t.log("[cart.subscribe] redux store found after "+n+" attempt(s)"),e;await new Promise(function(t){setTimeout(t,250)})}return t.log("[cart.subscribe] redux store not found after "+n+" attempts / 30000ms"),null}();if(!d)return{ok:!1,reason:"redux_store_not_found",detail:"timeout_30000ms"};!function(e){if(!e||e.__ttpSobeysDispatchPatched)return;e.__ttpSobeysDispatchPatched=!0;const n=e.dispatch.bind(e);e.dispatch=function(e){const o=n(e);try{const n=e&&"object"==typeof e?e.type:null;n&&0===String(n).indexOf("shoppingListSlice/")&&(t.log("[cart.subscribe] dispatch-hit "+n),a("dispatch",!1))}catch(t){}return o},t.log("[cart.subscribe] dispatch hook installed on redux store")}(d),c(r(d.getState()));const l=d.subscribe(function(){const t=r(d.getState());(function(t,e){if(t.size!==e.size)return!1;for(const n of t){const t=n[0],o=n[1],r=e.get(t);if(!r||r.qty!==o.qty)return!1}return!0})(s(),t)||a("redux",!1)});return window.__ttpSobeysStoreUnsub=l,window.__ttpSobeysPersistPollId||(window.__ttpSobeysPersistFingerprint=u(),window.__ttpSobeysPersistPollId=setInterval(function(){const e=u();e!==window.__ttpSobeysPersistFingerprint&&(window.__ttpSobeysPersistFingerprint=e,t.log("[cart.subscribe] persist:root fingerprint changed"),a("persist",!1))},400),t.log("[cart.subscribe] sessionStorage persist:root poll installed")),a("initial",!0),{ok:!0,listening:!0,strategy:"redux_dispatch_hook + subscribe + persist_poll",autoRunExpected:!0}};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(){"use strict";const t="ACSYSHF8AU",e="dxp_product_en";function n(t){const e=String(t||"").replace(/\D/g,"");return e?e.length>=4?e.slice(-4):e.padStart(4,"0"):null}function o(t){return t.includes("algolia.net")&&t.includes("/indexes/")}async function r(n,o,r){const i="https://"+t+"-dsn.algolia.net/1/indexes/*/queries?x-algolia-api-key=fe555974f588b3e76ad0f1c548113b22&x-algolia-application-id="+t,s=JSON.stringify({requests:[{indexName:e,query:n,hitsPerPage:r||3,clickAnalytics:!0,filters:"storeId:"+o+" AND isVisible:true AND isMassOffers:false",analyticsTags:["A","website"]}]}),a=await fetch(i,{method:"POST",credentials:"omit",headers:{Accept:"application/json","Content-Type":"application/x-www-form-urlencoded"},body:s});return(((await a.json()).results||[])[0]||{}).hits||[]}function i(t){const e=new URL(location.origin+"/");e.searchParams.set("query",t),e.searchParams.set("tab","products"),history.pushState(null,"",e.toString()),window.dispatchEvent(new PopStateEvent("popstate",{state:null}))}function s(){return document.querySelectorAll('[id^="ObjectID-"]').length}function a(t){return new Promise(function(e){setTimeout(e,t)})}window.__ttpSobeysInjectProbeMin=async function(t){const c=(t=t||{}).hookMode||"both",u=function(){try{const t=JSON.parse(localStorage.getItem("store")||"{}"),e=n(t.storeNumber||t.objectID);if(e)return e}catch(t){}const t=document.cookie.match(/(?:^|;\s*)storeId=([^;]+)/);return t?n(decodeURIComponent(t[1]).split("_")[0]):null}();if(!u)throw new Error("Pick a store first");const l={transport:[],forged:[],hookMode:c,sid:u};if(!(await r("coffee",u,1)).length)throw new Error("Algolia donor failed");const d=[];for(const e of t.queries||["tomatoes","cucumbers"]){const t=await r(e,u,1);if(!t.length)throw new Error("No hits for "+e);d.push(t[0])}const p="spcrt-probe-"+Math.random().toString(36).slice(2,8),f={prefix:p,revision:0,algoliaHits:[],meta:{},index:e};function h(){const t=f.revision?p+"-r"+f.revision:p;return JSON.stringify({results:[{hits:f.algoliaHits,nbHits:f.algoliaHits.length,page:0,nbPages:f.algoliaHits.length?1:0,hitsPerPage:50,exhaustiveNbHits:!0,query:t,index:e,processingTimeMS:1}]})}function g(t,e){return o(t)&&(function(t,e){try{const n=JSON.parse(t).requests;return Array.isArray(n)&&n.some(function(t){return String(t.query||"").includes(e)})}catch(t){return!1}}(e,p)||t.includes(encodeURIComponent(p)))}function y(t,e,n,o,r){const i={kind:e,forged:!!r,q:function(){try{return JSON.parse(o).requests[0].query}catch(t){return null}}()};l[t].push(i)}window.__speacart_inject_state=window.__speacart_inject_state||{},window.__speacart_inject_state[p]=f;const w=window.fetch;"fetch"!==c&&"both"!==c||(window.fetch=function(t,e){const n="string"==typeof t?t:t&&t.url||"",r=e&&null!=e.body?String(e.body):"";return o(n)&&y("transport","fetch",0,r,!1),g(n,r)?(y("forged","fetch",0,r,!0),Promise.resolve(new Response(h(),{status:200,headers:{"content-type":"application/json"}}))):w.apply(this,arguments)});const b=XMLHttpRequest.prototype.open,S=XMLHttpRequest.prototype.send;"xhr"!==c&&"both"!==c||(XMLHttpRequest.prototype.open=function(t,e){return this.__u=e,b.apply(this,arguments)},XMLHttpRequest.prototype.send=function(t){const e=this.__u||"",n=null!=t?String(t):"";if(o(e)&&y("transport","xhr",0,n,!1),g(e,n)){y("forged","xhr",0,n,!0);const t=this,e=h();return void setTimeout(function(){try{Object.defineProperty(t,"readyState",{configurable:!0,writable:!0,value:4}),Object.defineProperty(t,"status",{configurable:!0,writable:!0,value:200}),Object.defineProperty(t,"responseText",{configurable:!0,writable:!0,value:e}),Object.defineProperty(t,"response",{configurable:!0,writable:!0,value:e})}catch(t){}t.dispatchEvent(new Event("readystatechange")),t.dispatchEvent(new Event("load")),t.dispatchEvent(new Event("loadend"))},0)}return S.apply(this,arguments)});const _=s();i(p),await a(2e3);const m=s();for(const t of d)f.algoliaHits.push(JSON.parse(JSON.stringify(t))),f.revision++,i(p+"-r"+f.revision),await a(2e3);const v=s(),O=l.transport.reduce(function(t,e){return t[e.kind]=(t[e.kind]||0)+1,t},{}),E=v>0?"SUCCESS":0===l.forged.length?"NO_FORGE β Sobeys did not Algolia-query the sentinel; try hookMode both":"FORGED_BUT_NO_TILES β hook works, React/grid issue",I={ok:v>0,hookMode:c,prefix:p,sid:u,tiles:{before:_,afterInit:m,afterAppend:v},hitsInState:f.algoliaHits.length,productIds:f.algoliaHits.map(function(t){return t.objectID}),transportByKind:O,forgedCount:l.forged.length,transport:l.transport,forged:l.forged,url:location.href,verdict:E};return console.log("[SOBEYS-INJECT-MIN]",I),window.__ttpSobeysInjectProbeMinLast=I,I},console.log("[SOBEYS-INJECT-MIN] ready β await __ttpSobeysInjectProbeMin()")}();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(){"use strict";if(window.__ttpSobeysInjectProbeInstalled)return void console.warn("[SOBEYS-INJECT-PROBE] already installed");const t="ACSYSHF8AU",e="dxp_product_en",o=[],n=[];let r=null,i=!1;function s(t){if(null==t||""===t)return null;const e=String(t).replace(/\D/g,"");return e?e.length>=4?e.slice(-4):e.padStart(4,"0"):null}function a(t){return"string"==typeof t&&-1!==t.indexOf("algolia.net")&&-1!==t.indexOf("/indexes/")}async function c(o,n,r){const i="https://"+t+"-dsn.algolia.net/1/indexes/*/queries?x-algolia-agent="+encodeURIComponent("Algolia for JavaScript (5.52.1); Search (5.52.1); Browser")+"&x-algolia-api-key=fe555974f588b3e76ad0f1c548113b22&x-algolia-application-id="+t,s={requests:[{indexName:e,query:String(o).trim(),hitsPerPage:r||3,clickAnalytics:!0,userToken:"",filters:"storeId:"+n+" AND isVisible:true AND isMassOffers:false",analyticsTags:["A","website"]}]},a=await fetch(i,{method:"POST",credentials:"omit",headers:{Accept:"application/json","Content-Type":"application/x-www-form-urlencoded"},body:JSON.stringify(s)});if(!a.ok)throw new Error("algolia "+a.status);const c=await a.json(),l=c&&c.results&&c.results[0]||{};return{hits:Array.isArray(l.hits)?l.hits:[],meta:{processingTimeMS:l.processingTimeMS,hitsPerPage:l.hitsPerPage,exhaustiveNbHits:l.exhaustiveNbHits}}}function l(){return document.querySelectorAll('[id^="ObjectID-"]').length}function p(t){return new Promise(function(e){setTimeout(e,t)})}function u(t){const e=new URL(location.origin+"/");e.searchParams.set("query",t),e.searchParams.set("tab","products"),history.pushState(null,"",e.toString()),window.dispatchEvent(new PopStateEvent("popstate",{state:null}))}function h(t,e,o,i){const s={at:(new Date).toISOString(),kind:t,url:String(e).slice(0,120),forged:!!i,bodyHasSentinel:!!o&&-1!==o.indexOf(r&&r.prefix)};return n.push(s),console.log("[SOBEYS-INJECT-PROBE] hook",t,i?"FORGED":"pass-through",s.url),s}function d(t){if(t){try{t.origFetch&&(window.fetch=t.origFetch)}catch(t){}try{t.origXhrOpen&&(XMLHttpRequest.prototype.open=t.origXhrOpen),t.origXhrSend&&(XMLHttpRequest.prototype.send=t.origXhrSend)}catch(t){}try{t.styleEl&&t.styleEl.parentNode&&t.styleEl.parentNode.removeChild(t.styleEl)}catch(t){}try{t.cleanupTimer&&clearTimeout(t.cleanupTimer)}catch(t){}window.__speacart_inject_state&&t.sentinel&&delete window.__speacart_inject_state[t.sentinel]}}window.__ttpSobeysAlgoliaTransportProbeInstall=function(){return/(^|\.)sobeys\.com$/.test(location.hostname)||console.warn("[SOBEYS-INJECT-PROBE] not on sobeys.com"),function(){if(i)return;i=!0;const t=window.fetch;window.__ttpSobeysInjectProbeNativeFetch=t,window.fetch=function(e,n){const r="string"==typeof e?e:e&&e.url||"";if(a(r)){let t="";n&&null!=n.body&&(t="string"==typeof n.body?n.body:String(n.body)),o.push({at:(new Date).toISOString(),kind:"fetch",url:r,query:function(){try{const e=JSON.parse(t).requests;return e&&e[0]&&e[0].query}catch(t){return null}}()}),console.log("[SOBEYS-INJECT-PROBE] transport fetch",r.slice(0,80))}return t.apply(this,arguments)};const e=XMLHttpRequest.prototype.open,n=XMLHttpRequest.prototype.send;window.__ttpSobeysInjectProbeNativeXhrOpen=e,window.__ttpSobeysInjectProbeNativeXhrSend=n,XMLHttpRequest.prototype.open=function(t,o){return this.__ttpProbeMethod=t,this.__ttpProbeUrl="string"==typeof o?o:String(o||""),e.apply(this,arguments)},XMLHttpRequest.prototype.send=function(t){const e=this.__ttpProbeUrl||"";if(a(e)){const n="string"==typeof t?t:t?String(t):"";o.push({at:(new Date).toISOString(),kind:"xhr",url:e,query:function(){try{const t=JSON.parse(n).requests;return t&&t[0]&&t[0].query}catch(t){return null}}()}),console.log("[SOBEYS-INJECT-PROBE] transport xhr",e.slice(0,80))}return n.apply(this,arguments)}}(),console.log("[SOBEYS-INJECT-PROBE] transport logger on β search or soft-nav, then __ttpSobeysAlgoliaTransportProbeReport()"),o},window.__ttpSobeysAlgoliaTransportProbeReport=function(){const t=o.reduce(function(t,e){return t[e.kind]=(t[e.kind]||0)+1,t},{}),e={hitCount:o.length,byKind:t,hits:o.slice(),verdict:t.xhr>0&&!t.fetch?"Sobeys uses XHR for Algolia β fetch-only injectInit will NOT render tiles":t.fetch>0&&!t.xhr?"Sobeys uses fetch for Algolia β fetch hook should work":t.fetch>0&&t.xhr>0?"Both fetch and XHR seen β use both hooks":"No Algolia traffic yet β run a search or inject probe first"};return console.table(o),console.log("[SOBEYS-INJECT-PROBE] transport report",e),e},window.__ttpSobeysInjectProbeRun=async function(t){const o=(t=t||{}).hookMode||"both",i=t.queries||["tomatoes","cucumbers"],f=t.templateQuery||"coffee";if(!/(^|\.)sobeys\.com$/.test(location.hostname))throw new Error("Run on www.sobeys.com top-level tab");const g=function(){let t=null;try{const e=JSON.parse(localStorage.getItem("store")||"{}");e&&(e.storeNumber||e.objectID)&&(t=s(e.storeNumber||e.objectID))}catch(t){}if(!t){const e=document.cookie.match(/(?:^|;\s*)storeId=([^;]+)/);e&&(t=s(decodeURIComponent(e[1]).split("_")[0]))}return t}();if(!g)throw new Error("No store β pick a store on sobeys.com first");r&&d(r),n.length=0,console.log("[SOBEYS-INJECT-PROBE] fetching donor template + probe productsβ¦ storeId="+g);let y=window.__speacart_sobeys_template;const w=Date.now();if(!y||!y.sampleHit||y.storeId!==g){const t=await c(f,g,5);if(!t.hits.length)throw new Error("no donor hit for "+f);y={sampleHit:t.hits[0],resultMeta:t.meta,storeId:g,indexName:e,capturedAt:w},window.__speacart_sobeys_template=y}const b=[];for(let t=0;t<i.length;t++){const e=await c(i[t],g,3);if(!e.hits.length)throw new Error("no hits for "+i[t]);b.push(e.hits[0]),console.log("[SOBEYS-INJECT-PROBE] product",i[t],"β",e.hits[0].objectID,e.hits[0].name)}const S="spcrt-sl-probe-"+Math.random().toString(36).slice(2,10);window.__speacart_inject_state||(window.__speacart_inject_state={});const _={sentinel:S,prefix:S,revision:0,algoliaHits:[],storeId:g,indexName:e,resultMeta:y.resultMeta||{},hookMode:o};window.__speacart_inject_state[S]=_,r=_,function(t,e){const o=t.prefix;function n(){const e=t.revision>0?o+"-r"+t.revision:o;return JSON.stringify({results:[{hits:t.algoliaHits,nbHits:t.algoliaHits.length,page:0,nbPages:t.algoliaHits.length>0?1:0,hitsPerPage:50,exhaustiveNbHits:!0,exhaustiveTypo:!0,query:e,params:"",processingTimeMS:t.resultMeta&&t.resultMeta.processingTimeMS||1,index:t.indexName}]})}function r(t,e){return!!a(t)&&(function(t,e){if(!t||"string"!=typeof t||!e)return!1;try{const o=JSON.parse(t).requests;if(!Array.isArray(o))return!1;for(let t=0;t<o.length;t++)if(-1!==String(o[t]&&o[t].query||"").indexOf(e))return!0}catch(t){}return!1}(e,o)||-1!==t.indexOf(encodeURIComponent(o)))}if("fetch"===e||"both"===e){const e=window.fetch;t.origFetch=e,window.fetch=function(t,o){const i="string"==typeof t?t:t&&t.url||"";let s="";return o&&null!=o.body&&(s="string"==typeof o.body?o.body:String(o.body)),r(i,s)?(h("fetch",i,s,!0),Promise.resolve((c=n(),new Response(c,{status:200,statusText:"OK",headers:{"content-type":"application/json; charset=utf-8"}})))):(a(i)&&h("fetch",i,s,!1),e.apply(this,arguments));var c}}if("xhr"===e||"both"===e){const e=XMLHttpRequest.prototype.open,o=XMLHttpRequest.prototype.send;t.origXhrOpen=e,t.origXhrSend=o,XMLHttpRequest.prototype.open=function(t,o){return this.__ttpInjectUrl="string"==typeof o?o:String(o||""),e.apply(this,arguments)},XMLHttpRequest.prototype.send=function(t){const e=this.__ttpInjectUrl||"",i="string"==typeof t?t:t?String(t):"";if(r(e,i)){h("xhr",e,i,!0);const t=this,o=n();return void setTimeout(function(){!function(t,e){const o=function(e){try{Object.defineProperty(t,"readyState",{configurable:!0,writable:!0,value:e})}catch(t){}t.dispatchEvent(new Event("readystatechange"))};try{Object.defineProperty(t,"status",{configurable:!0,writable:!0,value:200}),Object.defineProperty(t,"statusText",{configurable:!0,writable:!0,value:"OK"}),Object.defineProperty(t,"responseText",{configurable:!0,writable:!0,value:e}),Object.defineProperty(t,"response",{configurable:!0,writable:!0,value:e})}catch(t){}o(2),o(3),o(4),t.dispatchEvent(new Event("load")),t.dispatchEvent(new Event("loadend"))}(t,o)},0)}return a(e)&&h("xhr",e,i,!1),o.apply(this,arguments)}}t.buildForgedAlgoliaJson=n}(_,o);const m=document.createElement("style");m.id="speacart-probe-hide-promo-"+S,m.textContent='[data-testid="in-grid-module"] { display: none !important; }',document.head.appendChild(m),_.styleEl=m,_.cleanupTimer=setTimeout(function(){console.log("[SOBEYS-INJECT-PROBE] auto cleanup after 60s"),window.__ttpSobeysInjectProbeUninstall()},6e4);const I=l();u(S),await p(1500);const O=l();n.filter(function(t){return t.forged}).length;for(let t=0;t<b.length;t++)_.algoliaHits.push(JSON.parse(JSON.stringify(b[t]))),_.revision+=1,u(S+"-r"+_.revision),await p(1200);const E=l(),P=n.filter(function(t){return t.forged}).length,N={ok:E>0,hookMode:o,storeId:g,sentinel:S,tilesBefore:I,tilesAfterInit:O,tilesAfterAppend:E,algoliaHitsInState:_.algoliaHits.length,hookIntercepts:n.slice(),forgedInterceptCount:P,productObjectIds:_.algoliaHits.map(function(t){return t.objectID}),url:location.href,verdict:E>0?"SUCCESS β inject channel rendered "+E+" tile(s) with hookMode="+o:0===P?"FAIL β no forged intercepts; Sobeys never queried Algolia with sentinel (try hookMode both + longer wait)":"FAIL β hook forged "+P+" response(s) but 0 tiles; hit shape or React path issue"};return console.log("[SOBEYS-INJECT-PROBE] run report",N),console.table(n),N},window.__ttpSobeysInjectProbeReport=function(){const t=r,e=t&&t.sentinel,i=e&&window.__speacart_inject_state&&window.__speacart_inject_state[e];return{activeSentinel:e||null,hookMode:t&&t.hookMode,algoliaHits:i?i.algoliaHits.length:0,revision:i?i.revision:null,tiles:l(),hookIntercepts:n.slice(),transportHits:o.slice(),url:location.href}},window.__ttpSobeysInjectProbeUninstall=function(){r&&d(r),r=null,window.__ttpSobeysInjectProbeNativeFetch&&(window.fetch=window.__ttpSobeysInjectProbeNativeFetch),window.__ttpSobeysInjectProbeNativeXhrOpen&&(XMLHttpRequest.prototype.open=window.__ttpSobeysInjectProbeNativeXhrOpen,XMLHttpRequest.prototype.send=window.__ttpSobeysInjectProbeNativeXhrSend),i=!1,console.log("[SOBEYS-INJECT-PROBE] uninstalled")},window.__ttpSobeysInjectProbeInstalled=!0,console.log("[SOBEYS-INJECT-PROBE] installed on",location.hostname,"β await __ttpSobeysInjectProbeRun() (store required)")}();
|
|
@@ -119,16 +119,14 @@
|
|
|
119
119
|
</head>
|
|
120
120
|
<body>
|
|
121
121
|
<div class="container">
|
|
122
|
-
<h1>TTP Hotels
|
|
122
|
+
<h1>TTP Flavor Test (Ecommerce / Hotels / β¦)</h1>
|
|
123
123
|
|
|
124
124
|
<div class="info">
|
|
125
125
|
<strong>How it works:</strong>
|
|
126
126
|
<ul>
|
|
127
|
-
<li>
|
|
128
|
-
<li>
|
|
129
|
-
<li>
|
|
130
|
-
<li>Booking summary updates on <code>booking_updated</code> messages</li>
|
|
131
|
-
<li>Gallery (<code>show_media</code>) opens fullscreen with widget minimized</li>
|
|
127
|
+
<li>Pick an <strong>Agent</strong> below β the demo passes <code>flavor: { type, partnerId, callView: 'minimized' }</code> for every vertical.</li>
|
|
128
|
+
<li>On <strong>desktop</strong> (>768px), <strong><code>callView: 'minimized'</code></strong> uses the bottom voice strip when a call is active (in-panel active call UI is hidden). Mobile keeps the existing minimized bar behavior.</li>
|
|
129
|
+
<li>Each vertical wires WebSocket handlers (e.g. hotels: <code>show_items</code> rooms, <code>booking_updated</code>, <code>show_media</code>).</li>
|
|
132
130
|
</ul>
|
|
133
131
|
</div>
|
|
134
132
|
|
|
@@ -138,8 +136,8 @@
|
|
|
138
136
|
<div class="settings-grid">
|
|
139
137
|
<label>Agent
|
|
140
138
|
<select id="agentSelect" onchange="handleAgentChange()">
|
|
141
|
-
<option value="agent_ed18369b3|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|ecommerce|mock-store">Ecommerce Demo (agent_ed18369b3)</option>
|
|
142
|
-
<option value="agent_d0774f1af|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|hotels|mock-hotel"
|
|
139
|
+
<option value="agent_ed18369b3|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|ecommerce|mock-store" selected>Ecommerce Demo (agent_ed18369b3)</option>
|
|
140
|
+
<option value="agent_d0774f1af|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|hotels|mock-hotel">Hotels Demo (agent_d0774f1af)</option>
|
|
143
141
|
<option value="agent_PHARMA_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|pharma|mock-pharm">Pharma Demo (update agent ID)</option>
|
|
144
142
|
<option value="agent_RESTAURANT_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|restaurants|mock-restaurant">Restaurant Demo (update agent ID)</option>
|
|
145
143
|
<option value="agent_TOUR_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|tours|mock-tour">Tour Demo (update agent ID)</option>
|
|
@@ -233,24 +231,7 @@ window.testWidget._flavor.messageHandlers['show_media']({
|
|
|
233
231
|
});</div>
|
|
234
232
|
</div>
|
|
235
233
|
|
|
236
|
-
<script>
|
|
237
|
-
(function() {
|
|
238
|
-
var isNgrok = window.location.hostname.includes('ngrok');
|
|
239
|
-
if (isNgrok) {
|
|
240
|
-
var s = document.createElement('script');
|
|
241
|
-
s.type = 'text/javascript';
|
|
242
|
-
document.head.appendChild(s);
|
|
243
|
-
fetch('/agent-widget.js', { headers: { 'ngrok-skip-browser-warning': '1' } })
|
|
244
|
-
.then(function(r) { return r.text(); })
|
|
245
|
-
.then(function(code) { s.textContent = code; })
|
|
246
|
-
.catch(function(e) { console.error('SDK fetch failed:', e); });
|
|
247
|
-
} else {
|
|
248
|
-
var s = document.createElement('script');
|
|
249
|
-
s.src = '/agent-widget.js';
|
|
250
|
-
document.head.appendChild(s);
|
|
251
|
-
}
|
|
252
|
-
})();
|
|
253
|
-
</script>
|
|
234
|
+
<script src="demo-sdk-loader.js"></script>
|
|
254
235
|
|
|
255
236
|
<script>
|
|
256
237
|
let chatWidget = null;
|
|
@@ -296,7 +277,7 @@ window.testWidget._flavor.messageHandlers['show_media']({
|
|
|
296
277
|
|
|
297
278
|
const agent = getAgentConfig();
|
|
298
279
|
|
|
299
|
-
|
|
280
|
+
const widgetConfig = window.TTPDemoSdkLoader.applyWebSocketUrl({
|
|
300
281
|
agentId: agent.agentId,
|
|
301
282
|
appId: agent.appId,
|
|
302
283
|
language: document.getElementById('languageSelect').value,
|
|
@@ -313,7 +294,8 @@ window.testWidget._flavor.messageHandlers['show_media']({
|
|
|
313
294
|
},
|
|
314
295
|
flavor: {
|
|
315
296
|
type: agent.flavorType,
|
|
316
|
-
partnerId: agent.partnerId
|
|
297
|
+
partnerId: agent.partnerId,
|
|
298
|
+
callView: 'minimized',
|
|
317
299
|
},
|
|
318
300
|
icon: {
|
|
319
301
|
type: 'custom',
|
|
@@ -326,6 +308,7 @@ window.testWidget._flavor.messageHandlers['show_media']({
|
|
|
326
308
|
text: 'ΧΧΧ, ΧΧ©ΧΧ ΧΧ ΧͺΧΧΧΧ ΧΧ’ΧΧΧ¨ ΧΧ '
|
|
327
309
|
}
|
|
328
310
|
});
|
|
311
|
+
chatWidget = new TTPAgentSDK.TTPChatWidget(widgetConfig);
|
|
329
312
|
|
|
330
313
|
window.testWidget = chatWidget;
|
|
331
314
|
const sttLabel = document.getElementById('sttSelect').selectedOptions[0].text;
|
|
@@ -416,22 +399,20 @@ window.testWidget._flavor.messageHandlers['show_media']({
|
|
|
416
399
|
};
|
|
417
400
|
|
|
418
401
|
// Wait for SDK and auto-create
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const iv = setInterval(() => {
|
|
424
|
-
attempts++;
|
|
425
|
-
if (window.TTPAgentSDK?.TTPChatWidget) { clearInterval(iv); resolve(); }
|
|
426
|
-
else if (attempts >= 150) { clearInterval(iv); reject(new Error('SDK failed to load')); }
|
|
427
|
-
}, 100);
|
|
428
|
-
});
|
|
402
|
+
function boot() {
|
|
403
|
+
const mode = window.TTPDemoSdkLoader?.getMode?.() || 'prod';
|
|
404
|
+
updateStatus('SDK loaded (' + mode + ') β click Create Widget or wait...', '');
|
|
405
|
+
createWidget();
|
|
429
406
|
}
|
|
430
407
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
408
|
+
window.addEventListener('ttp-demo-sdk-ready', () => {
|
|
409
|
+
if (chatWidget) {
|
|
410
|
+
chatWidget.destroy();
|
|
411
|
+
chatWidget = null;
|
|
412
|
+
}
|
|
413
|
+
boot();
|
|
414
|
+
});
|
|
415
|
+
window.TTPDemoSdkLoader.waitForReady().then(boot).catch((e) => {
|
|
435
416
|
updateStatus('SDK load failed: ' + e.message, 'error');
|
|
436
417
|
});
|
|
437
418
|
</script>
|
|
@@ -202,24 +202,7 @@ window.testWidget._flavor.messageHandlers['show_items']({
|
|
|
202
202
|
});</div>
|
|
203
203
|
</div>
|
|
204
204
|
|
|
205
|
-
<script>
|
|
206
|
-
(function() {
|
|
207
|
-
var isNgrok = window.location.hostname.includes('ngrok');
|
|
208
|
-
if (isNgrok) {
|
|
209
|
-
var s = document.createElement('script');
|
|
210
|
-
s.type = 'text/javascript';
|
|
211
|
-
document.head.appendChild(s);
|
|
212
|
-
fetch('/agent-widget.js', { headers: { 'ngrok-skip-browser-warning': '1' } })
|
|
213
|
-
.then(function(r) { return r.text(); })
|
|
214
|
-
.then(function(code) { s.textContent = code; })
|
|
215
|
-
.catch(function(e) { console.error('SDK fetch failed:', e); });
|
|
216
|
-
} else {
|
|
217
|
-
var s = document.createElement('script');
|
|
218
|
-
s.src = '/agent-widget.js';
|
|
219
|
-
document.head.appendChild(s);
|
|
220
|
-
}
|
|
221
|
-
})();
|
|
222
|
-
</script>
|
|
205
|
+
<script src="demo-sdk-loader.js"></script>
|
|
223
206
|
|
|
224
207
|
<script>
|
|
225
208
|
let chatWidget = null;
|
|
@@ -245,7 +228,7 @@ window.testWidget._flavor.messageHandlers['show_items']({
|
|
|
245
228
|
const agentId = document.getElementById('agentId').value;
|
|
246
229
|
const appId = document.getElementById('appId').value;
|
|
247
230
|
|
|
248
|
-
|
|
231
|
+
const widgetConfig = window.TTPDemoSdkLoader.applyWebSocketUrl({
|
|
249
232
|
agentId,
|
|
250
233
|
appId,
|
|
251
234
|
language: document.getElementById('languageSelect').value,
|
|
@@ -274,6 +257,7 @@ window.testWidget._flavor.messageHandlers['show_items']({
|
|
|
274
257
|
text: 'ΧΧΧ, ΧΧ©ΧΧ ΧΧ ΧͺΧΧΧΧ ΧΧ’ΧΧΧ¨ ΧΧ ΧΧΧ©ΧΧ....'
|
|
275
258
|
}
|
|
276
259
|
});
|
|
260
|
+
chatWidget = new TTPAgentSDK.TTPChatWidget(widgetConfig);
|
|
277
261
|
|
|
278
262
|
window.testWidget = chatWidget;
|
|
279
263
|
updateStatus('TTPChatWidget created β tours flavor (mock-tour)', 'success');
|
|
@@ -354,22 +338,20 @@ window.testWidget._flavor.messageHandlers['show_items']({
|
|
|
354
338
|
updateStatus('Booking cleared', '');
|
|
355
339
|
};
|
|
356
340
|
|
|
357
|
-
function
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const iv = setInterval(() => {
|
|
362
|
-
attempts++;
|
|
363
|
-
if (window.TTPAgentSDK?.TTPChatWidget) { clearInterval(iv); resolve(); }
|
|
364
|
-
else if (attempts >= 150) { clearInterval(iv); reject(new Error('SDK failed to load')); }
|
|
365
|
-
}, 100);
|
|
366
|
-
});
|
|
341
|
+
function boot() {
|
|
342
|
+
const mode = window.TTPDemoSdkLoader?.getMode?.() || 'prod';
|
|
343
|
+
updateStatus('SDK loaded (' + mode + ') β creating widget...', '');
|
|
344
|
+
createWidget();
|
|
367
345
|
}
|
|
368
346
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
347
|
+
window.addEventListener('ttp-demo-sdk-ready', () => {
|
|
348
|
+
if (chatWidget) {
|
|
349
|
+
chatWidget.destroy();
|
|
350
|
+
chatWidget = null;
|
|
351
|
+
}
|
|
352
|
+
boot();
|
|
353
|
+
});
|
|
354
|
+
window.TTPDemoSdkLoader.waitForReady().then(boot).catch((e) => {
|
|
373
355
|
updateStatus('SDK load failed: ' + e.message, 'error');
|
|
374
356
|
});
|
|
375
357
|
</script>
|
|
@@ -285,9 +285,11 @@
|
|
|
285
285
|
<input type="text" id="getSessionUrl" value="" placeholder="https://your-api.com/get-session">
|
|
286
286
|
</div>
|
|
287
287
|
|
|
288
|
-
<div class="config-group">
|
|
289
|
-
<label
|
|
290
|
-
<
|
|
288
|
+
<div class="config-group" style="grid-column: 1 / -1;">
|
|
289
|
+
<label>WebSocket URL</label>
|
|
290
|
+
<p id="demoWsUrlDisplay" style="font-size: 13px; color: #4b5563; margin-top: 4px; font-family: monospace;">
|
|
291
|
+
Set by SDK toggle (top-right): Production β speech.talktopc.com Β· Development β speech.bidme.co.il
|
|
292
|
+
</p>
|
|
291
293
|
</div>
|
|
292
294
|
|
|
293
295
|
<div class="config-group">
|
|
@@ -398,16 +400,12 @@
|
|
|
398
400
|
</div>
|
|
399
401
|
</div>
|
|
400
402
|
|
|
401
|
-
|
|
402
|
-
<script src="/agent-widget.js" onload="console.log('β
SDK script loaded, TTPAgentSDK:', typeof window.TTPAgentSDK)" onerror="console.error('β Failed to load SDK script')"></script>
|
|
403
|
+
<script src="demo-sdk-loader.js"></script>
|
|
403
404
|
<script>
|
|
404
|
-
console.log('π΅ Waiting for SDK to load...');
|
|
405
|
-
|
|
406
|
-
// Wait for TTPAgentSDK to be available (UMD library loads as global)
|
|
405
|
+
console.log('π΅ Waiting for SDK to load (use top-right toggle for prod/dev)...');
|
|
406
|
+
|
|
407
407
|
function initSDK() {
|
|
408
408
|
if (typeof window.TTPAgentSDK === 'undefined') {
|
|
409
|
-
console.log('β³ TTPAgentSDK not ready yet, waiting...');
|
|
410
|
-
setTimeout(initSDK, 100);
|
|
411
409
|
return;
|
|
412
410
|
}
|
|
413
411
|
|
|
@@ -427,6 +425,8 @@
|
|
|
427
425
|
|
|
428
426
|
window.TTPChatWidget = TTPChatWidget;
|
|
429
427
|
window.widgetInstance = null;
|
|
428
|
+
const mode = window.TTPDemoSdkLoader?.getMode?.() || '?';
|
|
429
|
+
console.log('β
SDK ready:', window.TTPDemoSdkLoader?.getSrc?.(mode), '(' + mode + ')');
|
|
430
430
|
|
|
431
431
|
// Define functions after module loads
|
|
432
432
|
window.initializeWidget = function() {
|
|
@@ -442,7 +442,6 @@
|
|
|
442
442
|
const agentId = document.getElementById('agentId').value;
|
|
443
443
|
const appId = document.getElementById('appId').value;
|
|
444
444
|
const getSessionUrl = document.getElementById('getSessionUrl').value;
|
|
445
|
-
const websocketUrl = document.getElementById('websocketUrl').value;
|
|
446
445
|
const position = document.getElementById('position').value;
|
|
447
446
|
const language = document.getElementById('language').value;
|
|
448
447
|
const mode = document.getElementById('mode').value;
|
|
@@ -477,9 +476,8 @@
|
|
|
477
476
|
config.getSessionUrl = getSessionUrl;
|
|
478
477
|
}
|
|
479
478
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
479
|
+
window.TTPDemoSdkLoader.applyWebSocketUrl(config);
|
|
480
|
+
console.log('π websocketUrl:', config.websocketUrl, '(SDK mode:', window.TTPDemoSdkLoader.getMode() + ')');
|
|
483
481
|
|
|
484
482
|
// Handle position
|
|
485
483
|
if (position) {
|
|
@@ -549,7 +547,6 @@
|
|
|
549
547
|
document.getElementById('agentId').value = 'agent_e5cf06457';
|
|
550
548
|
document.getElementById('appId').value = 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC';
|
|
551
549
|
document.getElementById('getSessionUrl').value = '';
|
|
552
|
-
document.getElementById('websocketUrl').value = 'wss://speech.talktopc.com/ws/conv';
|
|
553
550
|
document.getElementById('position').value = 'bottom-right';
|
|
554
551
|
document.getElementById('language').value = 'en';
|
|
555
552
|
document.getElementById('mode').value = 'unified';
|
|
@@ -638,9 +635,32 @@
|
|
|
638
635
|
resetConfig: typeof window.resetConfig
|
|
639
636
|
});
|
|
640
637
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
638
|
+
|
|
639
|
+
function updateWsUrlDisplay() {
|
|
640
|
+
const el = document.getElementById('demoWsUrlDisplay');
|
|
641
|
+
if (!el || !window.TTPDemoSdkLoader) return;
|
|
642
|
+
const mode = window.TTPDemoSdkLoader.getMode();
|
|
643
|
+
el.textContent = window.TTPDemoSdkLoader.getWebSocketUrl(mode) + ' (' + mode + ')';
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
window.addEventListener('ttp-demo-sdk-ready', () => {
|
|
647
|
+
updateWsUrlDisplay();
|
|
648
|
+
if (window.widgetInstance && typeof window.destroyWidget === 'function') {
|
|
649
|
+
window.destroyWidget();
|
|
650
|
+
}
|
|
651
|
+
initSDK();
|
|
652
|
+
// Re-create widget if user already initialized (so WS URL matches new SDK mode)
|
|
653
|
+
if (typeof window.initializeWidget === 'function' && document.getElementById('widgetStatus')?.textContent === 'Yes') {
|
|
654
|
+
window.initializeWidget();
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
window.TTPDemoSdkLoader.waitForReady().then(() => {
|
|
658
|
+
updateWsUrlDisplay();
|
|
659
|
+
initSDK();
|
|
660
|
+
}).catch((e) => {
|
|
661
|
+
console.error('β SDK load failed:', e);
|
|
662
|
+
alert('SDK load failed. Check Network for agent-widget*.js');
|
|
663
|
+
});
|
|
644
664
|
</script>
|
|
645
665
|
</body>
|
|
646
666
|
</html>
|
|
@@ -1280,10 +1280,11 @@
|
|
|
1280
1280
|
}
|
|
1281
1281
|
}
|
|
1282
1282
|
</style>
|
|
1283
|
+
<script src="demo-sdk-loader.js"></script>
|
|
1283
1284
|
</head>
|
|
1284
1285
|
<body>
|
|
1285
1286
|
<div class="header">
|
|
1286
|
-
<div class="dev-banner"
|
|
1287
|
+
<div class="dev-banner">π§ Use the SDK toggle (top-right) to switch Production β Development bundles</div>
|
|
1287
1288
|
<a href="test-index.html" class="back-link">β Back to Demos</a>
|
|
1288
1289
|
<h1>π¨ Widget Live Customization (Dev Page)</h1>
|
|
1289
1290
|
<div style="margin-top: 16px; display: flex; align-items: center; justify-content: center; gap: 24px; flex-wrap: wrap;">
|
|
@@ -4126,6 +4127,10 @@
|
|
|
4126
4127
|
}
|
|
4127
4128
|
};
|
|
4128
4129
|
|
|
4130
|
+
if (window.TTPDemoSdkLoader) {
|
|
4131
|
+
window.TTPDemoSdkLoader.applyWebSocketUrl(actualConfig);
|
|
4132
|
+
}
|
|
4133
|
+
|
|
4129
4134
|
try {
|
|
4130
4135
|
// Reset manual close tracking when widget is recreated (unless user manually closed it)
|
|
4131
4136
|
// Don't reset if widget was manually closed and mock panel is also closed
|
|
@@ -4348,8 +4353,15 @@
|
|
|
4348
4353
|
};
|
|
4349
4354
|
|
|
4350
4355
|
// Start checking for SDK (will also be called when script loads)
|
|
4351
|
-
window.
|
|
4352
|
-
|
|
4356
|
+
window.addEventListener('ttp-demo-sdk-ready', () => {
|
|
4357
|
+
if (actualWidgetInstance) {
|
|
4358
|
+
try { actualWidgetInstance.destroy(); } catch (e) { /* ignore */ }
|
|
4359
|
+
actualWidgetInstance = null;
|
|
4360
|
+
}
|
|
4361
|
+
window.checkAndInitWidget();
|
|
4362
|
+
});
|
|
4363
|
+
window.TTPDemoSdkLoader.waitForReady().then(() => window.checkAndInitWidget());
|
|
4364
|
+
|
|
4353
4365
|
// Debug helper - expose widget instance globally for inspection
|
|
4354
4366
|
window.debugWidget = function() {
|
|
4355
4367
|
console.log('=== Widget Debug Info ===');
|
|
@@ -4376,8 +4388,5 @@
|
|
|
4376
4388
|
};
|
|
4377
4389
|
};
|
|
4378
4390
|
</script>
|
|
4379
|
-
|
|
4380
|
-
<!-- Load the widget SDK (production version) -->
|
|
4381
|
-
<script src="/agent-widget.js?v=2.34.2" onload="if (typeof window.checkAndInitWidget === 'function') setTimeout(window.checkAndInitWidget, 100);" onerror="console.error('β Failed to load SDK script from /agent-widget.js'); alert('Failed to load SDK. Check console for details.');"></script>
|
|
4382
4391
|
</body>
|
|
4383
4392
|
</html>
|
|
@@ -1793,6 +1793,7 @@
|
|
|
1793
1793
|
}
|
|
1794
1794
|
}
|
|
1795
1795
|
</style>
|
|
1796
|
+
<script src="demo-sdk-loader.js"></script>
|
|
1796
1797
|
</head>
|
|
1797
1798
|
<body>
|
|
1798
1799
|
<div class="header">
|
|
@@ -5017,6 +5018,10 @@
|
|
|
5017
5018
|
}
|
|
5018
5019
|
};
|
|
5019
5020
|
|
|
5021
|
+
if (window.TTPDemoSdkLoader) {
|
|
5022
|
+
window.TTPDemoSdkLoader.applyWebSocketUrl(actualConfig);
|
|
5023
|
+
}
|
|
5024
|
+
|
|
5020
5025
|
try {
|
|
5021
5026
|
// Reset manual close tracking when widget is recreated (unless user manually closed it)
|
|
5022
5027
|
// Don't reset if widget was manually closed and mock panel is also closed
|
|
@@ -5450,9 +5455,15 @@
|
|
|
5450
5455
|
}
|
|
5451
5456
|
};
|
|
5452
5457
|
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5458
|
+
window.addEventListener('ttp-demo-sdk-ready', () => {
|
|
5459
|
+
if (actualWidgetInstance) {
|
|
5460
|
+
try { actualWidgetInstance.destroy(); } catch (e) { /* ignore */ }
|
|
5461
|
+
actualWidgetInstance = null;
|
|
5462
|
+
}
|
|
5463
|
+
window.checkAndInitWidget();
|
|
5464
|
+
});
|
|
5465
|
+
window.TTPDemoSdkLoader.waitForReady().then(() => window.checkAndInitWidget());
|
|
5466
|
+
|
|
5456
5467
|
// Debug helper - expose widget instance globally for inspection
|
|
5457
5468
|
window.debugWidget = function() {
|
|
5458
5469
|
console.log('=== Widget Debug Info ===');
|
|
@@ -5479,8 +5490,5 @@
|
|
|
5479
5490
|
};
|
|
5480
5491
|
};
|
|
5481
5492
|
</script>
|
|
5482
|
-
|
|
5483
|
-
<!-- Load the widget SDK -->
|
|
5484
|
-
<script src="/agent-widget.js" onload="if (typeof window.checkAndInitWidget === 'function') setTimeout(window.checkAndInitWidget, 100);" onerror="console.error('β Failed to load SDK script from /agent-widget.js'); alert('Failed to load SDK. Check console for details.');"></script>
|
|
5485
5493
|
</body>
|
|
5486
5494
|
</html>
|