PageSourceSearch

https://coffee-labo.co.jp/wp-content/plugins/coffee-labo-webmcp/as…/js/coffee-labo-analytics.js?ver=1788698436

js coffee-labo.co.jp collected 2026-10-02 10:35:45 UTC 2,874 bytes, 120 lines download raw bytes

1(() => {
2  'use strict';
3
4  const runtimeKey = '__clwmcpAnalyticsRuntime';
5  if (window[runtimeKey]?.send) return;
6
7  const queue = [];
8  const maxQueueSize = 100;
9  const pollIntervalMs = 250;
10  const maxPollAttempts = 120;
11  const allowedEvents = new Set([
12    'ai_search_view',
13    'ai_search_expand',
14    'ai_search_collapse',
15    'ai_search_submit',
16    'ai_answer_success',
17    'ai_answer_no_result',
18    'ai_source_click',
19    'ai_followup_submit',
20    'ai_labocafe_product_click',
21    'ai_search_error',
22    'webmcp_tool_call',
23    'ai_placement',
24  ]);
25  const allowedParams = new Set([
26    'ai_search_context',
27    'ai_search_mode',
28    'ai_answer_intent',
29    'ai_response_mode',
30    'ai_answer_source_count',
31    'ai_source_position',
32    'ai_search_error_type',
33    'webmcp_tool_name',
34    'webmcp_status',
35    'webmcp_result_count',
36    'content_type',
37    'content_id',
38    'experiment_id',
39  ]);
40  let pollTimer = 0;
41  let pollAttempts = 0;
42
43  const normalizeParams = (params) => {
44    const normalized = {};
45    Object.entries(params || {}).forEach(([key, value]) => {
46      if (!allowedParams.has(key)) return;
47      if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
48        normalized[key] = value;
49      }
50    });
51    return normalized;
52  };
53
54  const stopPolling = () => {
55    if (pollTimer) window.clearInterval(pollTimer);
56    pollTimer = 0;
57    pollAttempts = 0;
58  };
59
60  const sendNow = (entry) => {
61    if (typeof window.gtag !== 'function') return false;
62    try {
63      window.gtag('event', entry.name, entry.params);
64      return true;
65    } catch (_) {
66      return false;
67    }
68  };
69
70  const flush = () => {
71    if (typeof window.gtag !== 'function') return false;
72
73    while (queue.length) {
74      const entry = queue[0];
75      if (!sendNow(entry)) return false;
76      queue.shift();
77    }
78
79    stopPolling();
80    return true;
81  };
82
83  const scheduleFlush = () => {
84    if (pollTimer) return;
85    pollAttempts = 0;
86    pollTimer = window.setInterval(() => {
87      pollAttempts += 1;
88      if (flush() || pollAttempts >= maxPollAttempts) stopPolling();
89    }, pollIntervalMs);
90  };
91
92  const send = (name, params = {}) => {
93    const eventName = String(name || '').trim();
94    if (!allowedEvents.has(eventName)) return false;
95
96    const entry = {
97      name: eventName,
98      params: normalizeParams(params),
99    };
100
101    if (flush() && sendNow(entry)) return true;
102
103    if (queue.length >= maxQueueSize) queue.shift();
104    queue.push(entry);
105    scheduleFlush();
106    return false;
107  };
108
109  window.addEventListener('load', flush);
110  window.addEventListener('pageshow', flush);
111  document.addEventListener('visibilitychange', () => {
112    if (document.visibilityState === 'visible') flush();
113  });
114
115  window[runtimeKey] = Object.freeze({
116    send,
117    flush,
118    pendingCount: () => queue.length,
119  });
120})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.