@oxy.so/telemetry 1.1.1 → 2.0.0
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/LICENSE +676 -0
- package/README.md +6 -3
- package/dist/cjs/browser.js +46 -8
- package/dist/cjs/collector.js +111 -26
- package/dist/cjs/server.js +3 -1
- package/dist/cjs/socket.js +38 -9
- package/dist/esm/browser.js +44 -7
- package/dist/esm/collector.js +111 -26
- package/dist/esm/server.js +3 -1
- package/dist/esm/socket.js +38 -9
- package/dist/types/browser.d.ts +14 -0
- package/package.json +5 -17
- package/src/__tests__/browser.test.ts +42 -4
- package/src/__tests__/collector.test.ts +132 -27
- package/src/__tests__/server.test.ts +7 -5
- package/src/__tests__/socket.test.ts +80 -29
- package/src/browser.ts +71 -10
- package/src/collector.ts +152 -35
- package/src/server.ts +8 -2
- package/src/socket.ts +43 -11
- package/dist/cjs/edge.js +0 -137
- package/dist/esm/edge.js +0 -134
- package/dist/types/edge.d.ts +0 -32
- package/src/__tests__/edge.test.ts +0 -110
- package/src/edge.ts +0 -117
package/dist/cjs/browser.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getBrowserTelemetryHeaders = exports.getBrowserEdgeRegionHeader = exports.getBrowserActivityIdHeader = exports.DEFAULT_EDGE_CACHE_MS = exports.DEFAULT_EDGE_TRACE_TIMEOUT_MS = exports.DEFAULT_ACTIVITY_ID_ROTATION_MS = void 0;
|
|
3
|
+
exports.getBrowserTelemetryHeaders = exports.peekBrowserEdgeRegionHeader = exports.getBrowserEdgeRegionHeader = exports.getBrowserActivityIdHeader = exports.DEFAULT_EDGE_PEEK_REFRESH_MS = exports.DEFAULT_EDGE_CACHE_MS = exports.DEFAULT_EDGE_TRACE_TIMEOUT_MS = exports.DEFAULT_ACTIVITY_ID_ROTATION_MS = void 0;
|
|
4
4
|
exports.createBrowserTelemetry = createBrowserTelemetry;
|
|
5
5
|
const index_js_1 = require("./index.js");
|
|
6
6
|
exports.DEFAULT_ACTIVITY_ID_ROTATION_MS = 5 * 60 * 1000;
|
|
7
7
|
exports.DEFAULT_EDGE_TRACE_TIMEOUT_MS = 1000;
|
|
8
8
|
exports.DEFAULT_EDGE_CACHE_MS = 15000;
|
|
9
|
+
/**
|
|
10
|
+
* How long `peekEdgeRegionHeader` trusts a known PoP before refreshing it in the
|
|
11
|
+
* background. A client's serving PoP rarely changes within minutes, and the
|
|
12
|
+
* peek never blocks, so this only bounds the trace traffic.
|
|
13
|
+
*/
|
|
14
|
+
exports.DEFAULT_EDGE_PEEK_REFRESH_MS = 10 * 60000;
|
|
9
15
|
function createUuid(cryptoApi) {
|
|
10
16
|
if (!cryptoApi)
|
|
11
17
|
return null;
|
|
@@ -20,9 +26,9 @@ function createUuid(cryptoApi) {
|
|
|
20
26
|
function eligibleLocation(location) {
|
|
21
27
|
if (!location || (location.protocol !== 'https:' && location.protocol !== 'http:'))
|
|
22
28
|
return false;
|
|
23
|
-
return location.hostname !== 'localhost'
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
return (location.hostname !== 'localhost' &&
|
|
30
|
+
location.hostname !== '127.0.0.1' &&
|
|
31
|
+
location.hostname !== '[::1]');
|
|
26
32
|
}
|
|
27
33
|
function createBrowserTelemetry(options = {}) {
|
|
28
34
|
let activityId = null;
|
|
@@ -35,7 +41,9 @@ function createBrowserTelemetry(options = {}) {
|
|
|
35
41
|
if (!hasInjectedBrowser && !hasBrowserRuntime)
|
|
36
42
|
return {};
|
|
37
43
|
const now = (options.now ?? Date.now)();
|
|
38
|
-
if (!activityId ||
|
|
44
|
+
if (!activityId ||
|
|
45
|
+
now < activityIdCreatedAt ||
|
|
46
|
+
now - activityIdCreatedAt >= (options.activityIdRotationMs ?? exports.DEFAULT_ACTIVITY_ID_ROTATION_MS)) {
|
|
39
47
|
activityId = createUuid(options.crypto ?? globalThis.crypto);
|
|
40
48
|
if (!activityId)
|
|
41
49
|
return {};
|
|
@@ -52,7 +60,11 @@ function createBrowserTelemetry(options = {}) {
|
|
|
52
60
|
try {
|
|
53
61
|
const response = await (options.fetchTrace
|
|
54
62
|
? options.fetchTrace(controller.signal)
|
|
55
|
-
: fetch('/cdn-cgi/trace', {
|
|
63
|
+
: fetch('/cdn-cgi/trace', {
|
|
64
|
+
cache: 'no-store',
|
|
65
|
+
credentials: 'omit',
|
|
66
|
+
signal: controller.signal,
|
|
67
|
+
}));
|
|
56
68
|
if (!response.ok)
|
|
57
69
|
return null;
|
|
58
70
|
const match = (await response.text()).match(/^colo=([a-z]{3})$/im);
|
|
@@ -67,18 +79,42 @@ function createBrowserTelemetry(options = {}) {
|
|
|
67
79
|
};
|
|
68
80
|
const getEdgeRegionHeader = async () => {
|
|
69
81
|
const now = (options.now ?? Date.now)();
|
|
70
|
-
if (!edgePopPromise ||
|
|
82
|
+
if (!edgePopPromise ||
|
|
83
|
+
now < edgePopReadAt ||
|
|
84
|
+
now - edgePopReadAt >= (options.edgeCacheMs ?? exports.DEFAULT_EDGE_CACHE_MS)) {
|
|
71
85
|
edgePopReadAt = now;
|
|
72
86
|
edgePopPromise = discoverEdgePop();
|
|
73
87
|
}
|
|
74
88
|
const edgePop = await edgePopPromise;
|
|
75
89
|
return edgePop ? { [index_js_1.OXY_EDGE_REGION_HEADER]: edgePop } : {};
|
|
76
90
|
};
|
|
91
|
+
let peekedPop = null;
|
|
92
|
+
let peekRefreshAt = -Infinity;
|
|
93
|
+
let peekInFlight = false;
|
|
94
|
+
const peekEdgeRegionHeader = () => {
|
|
95
|
+
const now = (options.now ?? Date.now)();
|
|
96
|
+
if (!peekInFlight &&
|
|
97
|
+
(now < peekRefreshAt ||
|
|
98
|
+
now - peekRefreshAt >= (options.edgePeekRefreshMs ?? exports.DEFAULT_EDGE_PEEK_REFRESH_MS))) {
|
|
99
|
+
peekRefreshAt = now;
|
|
100
|
+
peekInFlight = true;
|
|
101
|
+
void discoverEdgePop()
|
|
102
|
+
.then((pop) => {
|
|
103
|
+
if (pop)
|
|
104
|
+
peekedPop = pop;
|
|
105
|
+
})
|
|
106
|
+
.finally(() => {
|
|
107
|
+
peekInFlight = false;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return peekedPop ? { [index_js_1.OXY_EDGE_REGION_HEADER]: peekedPop } : {};
|
|
111
|
+
};
|
|
77
112
|
return {
|
|
78
113
|
getActivityIdHeader,
|
|
79
114
|
getEdgeRegionHeader,
|
|
115
|
+
peekEdgeRegionHeader,
|
|
80
116
|
async getHeaders() {
|
|
81
|
-
return { ...await getEdgeRegionHeader(), ...getActivityIdHeader() };
|
|
117
|
+
return { ...(await getEdgeRegionHeader()), ...getActivityIdHeader() };
|
|
82
118
|
},
|
|
83
119
|
};
|
|
84
120
|
}
|
|
@@ -87,5 +123,7 @@ const getBrowserActivityIdHeader = () => defaultBrowserTelemetry.getActivityIdHe
|
|
|
87
123
|
exports.getBrowserActivityIdHeader = getBrowserActivityIdHeader;
|
|
88
124
|
const getBrowserEdgeRegionHeader = () => defaultBrowserTelemetry.getEdgeRegionHeader();
|
|
89
125
|
exports.getBrowserEdgeRegionHeader = getBrowserEdgeRegionHeader;
|
|
126
|
+
const peekBrowserEdgeRegionHeader = () => defaultBrowserTelemetry.peekEdgeRegionHeader();
|
|
127
|
+
exports.peekBrowserEdgeRegionHeader = peekBrowserEdgeRegionHeader;
|
|
90
128
|
const getBrowserTelemetryHeaders = () => defaultBrowserTelemetry.getHeaders();
|
|
91
129
|
exports.getBrowserTelemetryHeaders = getBrowserTelemetryHeaders;
|
package/dist/cjs/collector.js
CHANGED
|
@@ -9,11 +9,34 @@ exports.infrastructureLocation = infrastructureLocation;
|
|
|
9
9
|
exports.normalizeInfrastructureRegion = normalizeInfrastructureRegion;
|
|
10
10
|
const server_js_1 = require("./server.js");
|
|
11
11
|
const TYPES = {
|
|
12
|
-
auth: 'identity',
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
auth: 'identity',
|
|
13
|
+
session: 'identity',
|
|
14
|
+
users: 'identity',
|
|
15
|
+
profiles: 'identity',
|
|
16
|
+
accounts: 'identity',
|
|
17
|
+
ai: 'ai',
|
|
18
|
+
inference: 'ai',
|
|
19
|
+
models: 'ai',
|
|
20
|
+
chat: 'ai',
|
|
21
|
+
completions: 'ai',
|
|
22
|
+
stream: 'media',
|
|
23
|
+
tracks: 'media',
|
|
24
|
+
episodes: 'media',
|
|
25
|
+
recordings: 'media',
|
|
26
|
+
rooms: 'media',
|
|
27
|
+
messages: 'communication',
|
|
28
|
+
notifications: 'communication',
|
|
29
|
+
mail: 'communication',
|
|
30
|
+
media: 'media',
|
|
31
|
+
files: 'media',
|
|
32
|
+
assets: 'media',
|
|
33
|
+
upload: 'media',
|
|
34
|
+
uploads: 'media',
|
|
35
|
+
cdn: 'media',
|
|
36
|
+
storage: 'media',
|
|
37
|
+
images: 'media',
|
|
38
|
+
audio: 'media',
|
|
39
|
+
videos: 'media',
|
|
17
40
|
};
|
|
18
41
|
function trafficType(path) {
|
|
19
42
|
const parts = path.split('?')[0].split('/').filter(Boolean);
|
|
@@ -43,7 +66,12 @@ function createTrafficCollector(publish, now = Date.now) {
|
|
|
43
66
|
if (pending.size === 0)
|
|
44
67
|
return;
|
|
45
68
|
const emittedAt = new Date(now()).toISOString();
|
|
46
|
-
const events = [...pending.values()].map(({ flow, requests, startedAt }) => ({
|
|
69
|
+
const events = [...pending.values()].map(({ flow, requests, startedAt }) => ({
|
|
70
|
+
...flow,
|
|
71
|
+
requests,
|
|
72
|
+
windowStartedAt: new Date(startedAt).toISOString(),
|
|
73
|
+
emittedAt,
|
|
74
|
+
}));
|
|
47
75
|
pending.clear();
|
|
48
76
|
flushing = (async () => {
|
|
49
77
|
for (let offset = 0; offset < events.length; offset += 256)
|
|
@@ -63,7 +91,10 @@ function trafficMiddleware(collector, service, region) {
|
|
|
63
91
|
response.setHeader?.('X-Oxy-Region', region);
|
|
64
92
|
const path = request.path ?? request.url ?? '/';
|
|
65
93
|
// Never report collection itself, probes or the dashboard transport.
|
|
66
|
-
if (/^\/(?:api\/)?(?:health|ready|live|platform-stats|platform-activity|platform-infrastructure|infra-status)(?:\/|$)/.test(path) ||
|
|
94
|
+
if (/^\/(?:api\/)?(?:health|ready|live|platform-stats|platform-activity|platform-infrastructure|infra-status)(?:\/|$)/.test(path) ||
|
|
95
|
+
path.startsWith('/internal/activity') ||
|
|
96
|
+
path.startsWith('/auth/service-token') ||
|
|
97
|
+
path.startsWith('/cdn-cgi/')) {
|
|
67
98
|
next();
|
|
68
99
|
return;
|
|
69
100
|
}
|
|
@@ -72,11 +103,28 @@ function trafficMiddleware(collector, service, region) {
|
|
|
72
103
|
let finished = false;
|
|
73
104
|
const inboundFlow = () => {
|
|
74
105
|
// Read service identity AFTER the route's shared auth middleware resolved it.
|
|
75
|
-
const name = request.serviceApp?.appName
|
|
106
|
+
const name = request.serviceApp?.appName
|
|
107
|
+
?.toLowerCase()
|
|
108
|
+
.replace(/[^a-z0-9-]/g, '-')
|
|
109
|
+
.slice(0, 40);
|
|
76
110
|
const internal = Boolean(name);
|
|
77
111
|
const forwardedRegion = request.headers['x-oxy-source-region'];
|
|
78
|
-
const peerRegion = internal
|
|
79
|
-
|
|
112
|
+
const peerRegion = internal
|
|
113
|
+
? normalizeInfrastructureRegion(forwardedRegion)
|
|
114
|
+
: edgePop
|
|
115
|
+
? `edge-${edgePop}`
|
|
116
|
+
: undefined;
|
|
117
|
+
return {
|
|
118
|
+
region,
|
|
119
|
+
service,
|
|
120
|
+
activityType,
|
|
121
|
+
scope: internal ? 'internal' : 'external',
|
|
122
|
+
direction: 'inbound',
|
|
123
|
+
sourceRegion: peerRegion,
|
|
124
|
+
targetRegion: region,
|
|
125
|
+
sourceService: name,
|
|
126
|
+
targetService: service,
|
|
127
|
+
};
|
|
80
128
|
};
|
|
81
129
|
const finish = () => {
|
|
82
130
|
if (finished)
|
|
@@ -84,7 +132,14 @@ function trafficMiddleware(collector, service, region) {
|
|
|
84
132
|
finished = true;
|
|
85
133
|
const flow = inboundFlow();
|
|
86
134
|
collector.record(flow);
|
|
87
|
-
collector.record({
|
|
135
|
+
collector.record({
|
|
136
|
+
...flow,
|
|
137
|
+
direction: 'outbound',
|
|
138
|
+
sourceRegion: region,
|
|
139
|
+
targetRegion: flow.sourceRegion,
|
|
140
|
+
sourceService: service,
|
|
141
|
+
targetService: flow.sourceService,
|
|
142
|
+
});
|
|
88
143
|
};
|
|
89
144
|
response.once('finish', finish);
|
|
90
145
|
// Failed/aborted requests are still real inbound activity. Do not invent a
|
|
@@ -102,13 +157,21 @@ function instrumentTrafficFetch(fetcher, collector, service, region, resolveEndp
|
|
|
102
157
|
return Object.assign(async (input, init) => {
|
|
103
158
|
const url = new URL(typeof input === 'string' ? input : input instanceof URL ? input.href : input.url);
|
|
104
159
|
// Collection/auth control traffic cannot generate a feedback loop.
|
|
105
|
-
if (url.pathname.startsWith('/internal/activity') ||
|
|
160
|
+
if (url.pathname.startsWith('/internal/activity') ||
|
|
161
|
+
url.pathname.startsWith('/auth/service-token') ||
|
|
162
|
+
url.pathname === '/platform-infrastructure')
|
|
106
163
|
return fetcher(input, init);
|
|
107
164
|
const peer = resolveEndpoint(url);
|
|
108
165
|
const flow = {
|
|
109
|
-
service,
|
|
110
|
-
|
|
111
|
-
|
|
166
|
+
service,
|
|
167
|
+
region,
|
|
168
|
+
scope: peer ? 'internal' : 'external',
|
|
169
|
+
direction: 'outbound',
|
|
170
|
+
activityType: trafficType(url.pathname),
|
|
171
|
+
sourceRegion: region,
|
|
172
|
+
targetRegion: peer?.region,
|
|
173
|
+
sourceService: service,
|
|
174
|
+
targetService: peer?.service,
|
|
112
175
|
};
|
|
113
176
|
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
|
|
114
177
|
if (peer)
|
|
@@ -121,23 +184,43 @@ function instrumentTrafficFetch(fetcher, collector, service, region, resolveEndp
|
|
|
121
184
|
collector.record({ ...flow, targetRegion: undefined });
|
|
122
185
|
throw error;
|
|
123
186
|
}
|
|
124
|
-
const targetRegion = peer
|
|
187
|
+
const targetRegion = peer
|
|
188
|
+
? normalizeInfrastructureRegion(response.headers.get('X-Oxy-Region') ?? undefined)
|
|
189
|
+
: undefined;
|
|
125
190
|
collector.record({ ...flow, targetRegion });
|
|
126
|
-
collector.record({
|
|
191
|
+
collector.record({
|
|
192
|
+
...flow,
|
|
193
|
+
direction: 'inbound',
|
|
194
|
+
sourceRegion: targetRegion,
|
|
195
|
+
targetRegion: region,
|
|
196
|
+
sourceService: peer?.service,
|
|
197
|
+
targetService: service,
|
|
198
|
+
});
|
|
127
199
|
return response;
|
|
128
200
|
}, fetcher);
|
|
129
201
|
}
|
|
130
202
|
// Exact deployed API hosts; an arbitrary caller-supplied hostname cannot claim
|
|
131
203
|
// to be an internal service. Region is infrastructure metadata, never IP geo.
|
|
132
204
|
const OXY_API_SERVICES = {
|
|
133
|
-
'api.oxy.so': 'oxy-api',
|
|
134
|
-
'
|
|
135
|
-
'api.
|
|
136
|
-
'api.
|
|
137
|
-
'
|
|
138
|
-
'api.
|
|
139
|
-
'
|
|
140
|
-
'api.
|
|
205
|
+
'api.oxy.so': 'oxy-api',
|
|
206
|
+
'api.website.oxy.so': 'website',
|
|
207
|
+
'website-api.oxy.so': 'website',
|
|
208
|
+
'api.mention.earth': 'mention',
|
|
209
|
+
'api.mercaria.co': 'mercaria',
|
|
210
|
+
'api.alia.onl': 'alia',
|
|
211
|
+
'kaana.ai': 'kaana',
|
|
212
|
+
'api.homiio.com': 'homiio',
|
|
213
|
+
'api.syra.fm': 'syra',
|
|
214
|
+
'mention.earth': 'mention',
|
|
215
|
+
'mcp.mention.earth': 'mention-mcp',
|
|
216
|
+
'api.clarity.surf': 'clarity',
|
|
217
|
+
'api.peable.to': 'peable',
|
|
218
|
+
'api.crowdsource.oxy.so': 'crowdsource',
|
|
219
|
+
'api.moovo.now': 'moovo',
|
|
220
|
+
'api.allo.you': 'allo',
|
|
221
|
+
'api.noted.oxy.so': 'noted',
|
|
222
|
+
'api.schedio.app': 'schedio',
|
|
223
|
+
'api.tnp.network': 'tnp-api',
|
|
141
224
|
};
|
|
142
225
|
function resolveOxyServiceEndpoint(url) {
|
|
143
226
|
const service = OXY_API_SERVICES[url.hostname];
|
|
@@ -174,7 +257,9 @@ const REGION_LOCATIONS = {
|
|
|
174
257
|
'me-central-1': { label: 'UAE', coordinates: [54.37, 24.45] },
|
|
175
258
|
'il-central-1': { label: 'Tel Aviv', coordinates: [34.78, 32.09] },
|
|
176
259
|
};
|
|
177
|
-
function infrastructureLocation(region) {
|
|
260
|
+
function infrastructureLocation(region) {
|
|
261
|
+
return REGION_LOCATIONS[region];
|
|
262
|
+
}
|
|
178
263
|
function normalizeInfrastructureRegion(value) {
|
|
179
264
|
return typeof value === 'string' && /^[a-z]{2}(?:-[a-z]+)+-\d$/.test(value) ? value : undefined;
|
|
180
265
|
}
|
package/dist/cjs/server.js
CHANGED
|
@@ -17,7 +17,9 @@ function firstHeaderValue(value) {
|
|
|
17
17
|
return typeof first === 'string' ? first : undefined;
|
|
18
18
|
}
|
|
19
19
|
function normalizeEdgePop(value) {
|
|
20
|
-
return firstHeaderValue(value)
|
|
20
|
+
return firstHeaderValue(value)
|
|
21
|
+
?.match(/^[a-z]{3}$/i)?.[0]
|
|
22
|
+
?.toLowerCase();
|
|
21
23
|
}
|
|
22
24
|
function normalizeActivityId(value) {
|
|
23
25
|
const candidate = firstHeaderValue(value);
|
package/dist/cjs/socket.js
CHANGED
|
@@ -6,11 +6,26 @@ exports.observeTrafficWebSocket = observeTrafficWebSocket;
|
|
|
6
6
|
const collector_js_1 = require("./collector.js");
|
|
7
7
|
const server_js_1 = require("./server.js");
|
|
8
8
|
const CATEGORIES = {
|
|
9
|
-
auth: 'identity',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
auth: 'identity',
|
|
10
|
+
session: 'identity',
|
|
11
|
+
user: 'identity',
|
|
12
|
+
profile: 'identity',
|
|
13
|
+
chat: 'ai',
|
|
14
|
+
agent: 'ai',
|
|
15
|
+
inference: 'ai',
|
|
16
|
+
completion: 'ai',
|
|
17
|
+
message: 'communication',
|
|
18
|
+
notification: 'communication',
|
|
19
|
+
typing: 'communication',
|
|
20
|
+
media: 'media',
|
|
21
|
+
audio: 'media',
|
|
22
|
+
video: 'media',
|
|
23
|
+
stream: 'media',
|
|
24
|
+
player: 'media',
|
|
25
|
+
track: 'media',
|
|
26
|
+
playback: 'media',
|
|
27
|
+
playlist: 'media',
|
|
28
|
+
room: 'media',
|
|
14
29
|
};
|
|
15
30
|
/** Event names are reduced locally to five categories; payloads are never read. */
|
|
16
31
|
function socketTrafficType(event) {
|
|
@@ -32,9 +47,16 @@ function observeTrafficSocket(socket, collector, service, region, options = {})
|
|
|
32
47
|
const peer = options.getPeer?.();
|
|
33
48
|
const peerService = peer && /^[a-z][a-z0-9-]{0,39}$/.test(peer.service) ? peer.service : undefined;
|
|
34
49
|
const edgePop = (0, server_js_1.metadataFromHeaders)(socket.handshake.headers).edgePop;
|
|
35
|
-
const peerRegion = peerService
|
|
50
|
+
const peerRegion = peerService
|
|
51
|
+
? (0, collector_js_1.normalizeInfrastructureRegion)(peer?.region)
|
|
52
|
+
: edgePop
|
|
53
|
+
? `edge-${edgePop}`
|
|
54
|
+
: undefined;
|
|
36
55
|
collector.record({
|
|
37
|
-
region,
|
|
56
|
+
region,
|
|
57
|
+
service,
|
|
58
|
+
scope: peerService ? 'internal' : 'external',
|
|
59
|
+
direction,
|
|
38
60
|
activityType: socketTrafficType(event),
|
|
39
61
|
sourceRegion: direction === 'inbound' ? peerRegion : region,
|
|
40
62
|
targetRegion: direction === 'inbound' ? region : peerRegion,
|
|
@@ -66,9 +88,16 @@ function observeTrafficWebSocket(socket, collector, service, region, options = {
|
|
|
66
88
|
const peer = options.getPeer?.();
|
|
67
89
|
const peerService = peer && /^[a-z][a-z0-9-]{0,39}$/.test(peer.service) ? peer.service : undefined;
|
|
68
90
|
const edgePop = (0, server_js_1.metadataFromHeaders)(options.headers ?? {}).edgePop;
|
|
69
|
-
const peerRegion = peerService
|
|
91
|
+
const peerRegion = peerService
|
|
92
|
+
? (0, collector_js_1.normalizeInfrastructureRegion)(peer?.region)
|
|
93
|
+
: edgePop
|
|
94
|
+
? `edge-${edgePop}`
|
|
95
|
+
: undefined;
|
|
70
96
|
collector.record({
|
|
71
|
-
service,
|
|
97
|
+
service,
|
|
98
|
+
region,
|
|
99
|
+
scope: peerService ? 'internal' : 'external',
|
|
100
|
+
direction,
|
|
72
101
|
activityType: options.activityType ?? 'communication',
|
|
73
102
|
sourceRegion: direction === 'inbound' ? peerRegion : region,
|
|
74
103
|
targetRegion: direction === 'inbound' ? region : peerRegion,
|
package/dist/esm/browser.js
CHANGED
|
@@ -2,6 +2,12 @@ import { OXY_ACTIVITY_ID_HEADER, OXY_EDGE_REGION_HEADER } from './index.js';
|
|
|
2
2
|
export const DEFAULT_ACTIVITY_ID_ROTATION_MS = 5 * 60 * 1000;
|
|
3
3
|
export const DEFAULT_EDGE_TRACE_TIMEOUT_MS = 1000;
|
|
4
4
|
export const DEFAULT_EDGE_CACHE_MS = 15000;
|
|
5
|
+
/**
|
|
6
|
+
* How long `peekEdgeRegionHeader` trusts a known PoP before refreshing it in the
|
|
7
|
+
* background. A client's serving PoP rarely changes within minutes, and the
|
|
8
|
+
* peek never blocks, so this only bounds the trace traffic.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_EDGE_PEEK_REFRESH_MS = 10 * 60000;
|
|
5
11
|
function createUuid(cryptoApi) {
|
|
6
12
|
if (!cryptoApi)
|
|
7
13
|
return null;
|
|
@@ -16,9 +22,9 @@ function createUuid(cryptoApi) {
|
|
|
16
22
|
function eligibleLocation(location) {
|
|
17
23
|
if (!location || (location.protocol !== 'https:' && location.protocol !== 'http:'))
|
|
18
24
|
return false;
|
|
19
|
-
return location.hostname !== 'localhost'
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
return (location.hostname !== 'localhost' &&
|
|
26
|
+
location.hostname !== '127.0.0.1' &&
|
|
27
|
+
location.hostname !== '[::1]');
|
|
22
28
|
}
|
|
23
29
|
export function createBrowserTelemetry(options = {}) {
|
|
24
30
|
let activityId = null;
|
|
@@ -31,7 +37,9 @@ export function createBrowserTelemetry(options = {}) {
|
|
|
31
37
|
if (!hasInjectedBrowser && !hasBrowserRuntime)
|
|
32
38
|
return {};
|
|
33
39
|
const now = (options.now ?? Date.now)();
|
|
34
|
-
if (!activityId ||
|
|
40
|
+
if (!activityId ||
|
|
41
|
+
now < activityIdCreatedAt ||
|
|
42
|
+
now - activityIdCreatedAt >= (options.activityIdRotationMs ?? DEFAULT_ACTIVITY_ID_ROTATION_MS)) {
|
|
35
43
|
activityId = createUuid(options.crypto ?? globalThis.crypto);
|
|
36
44
|
if (!activityId)
|
|
37
45
|
return {};
|
|
@@ -48,7 +56,11 @@ export function createBrowserTelemetry(options = {}) {
|
|
|
48
56
|
try {
|
|
49
57
|
const response = await (options.fetchTrace
|
|
50
58
|
? options.fetchTrace(controller.signal)
|
|
51
|
-
: fetch('/cdn-cgi/trace', {
|
|
59
|
+
: fetch('/cdn-cgi/trace', {
|
|
60
|
+
cache: 'no-store',
|
|
61
|
+
credentials: 'omit',
|
|
62
|
+
signal: controller.signal,
|
|
63
|
+
}));
|
|
52
64
|
if (!response.ok)
|
|
53
65
|
return null;
|
|
54
66
|
const match = (await response.text()).match(/^colo=([a-z]{3})$/im);
|
|
@@ -63,22 +75,47 @@ export function createBrowserTelemetry(options = {}) {
|
|
|
63
75
|
};
|
|
64
76
|
const getEdgeRegionHeader = async () => {
|
|
65
77
|
const now = (options.now ?? Date.now)();
|
|
66
|
-
if (!edgePopPromise ||
|
|
78
|
+
if (!edgePopPromise ||
|
|
79
|
+
now < edgePopReadAt ||
|
|
80
|
+
now - edgePopReadAt >= (options.edgeCacheMs ?? DEFAULT_EDGE_CACHE_MS)) {
|
|
67
81
|
edgePopReadAt = now;
|
|
68
82
|
edgePopPromise = discoverEdgePop();
|
|
69
83
|
}
|
|
70
84
|
const edgePop = await edgePopPromise;
|
|
71
85
|
return edgePop ? { [OXY_EDGE_REGION_HEADER]: edgePop } : {};
|
|
72
86
|
};
|
|
87
|
+
let peekedPop = null;
|
|
88
|
+
let peekRefreshAt = -Infinity;
|
|
89
|
+
let peekInFlight = false;
|
|
90
|
+
const peekEdgeRegionHeader = () => {
|
|
91
|
+
const now = (options.now ?? Date.now)();
|
|
92
|
+
if (!peekInFlight &&
|
|
93
|
+
(now < peekRefreshAt ||
|
|
94
|
+
now - peekRefreshAt >= (options.edgePeekRefreshMs ?? DEFAULT_EDGE_PEEK_REFRESH_MS))) {
|
|
95
|
+
peekRefreshAt = now;
|
|
96
|
+
peekInFlight = true;
|
|
97
|
+
void discoverEdgePop()
|
|
98
|
+
.then((pop) => {
|
|
99
|
+
if (pop)
|
|
100
|
+
peekedPop = pop;
|
|
101
|
+
})
|
|
102
|
+
.finally(() => {
|
|
103
|
+
peekInFlight = false;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return peekedPop ? { [OXY_EDGE_REGION_HEADER]: peekedPop } : {};
|
|
107
|
+
};
|
|
73
108
|
return {
|
|
74
109
|
getActivityIdHeader,
|
|
75
110
|
getEdgeRegionHeader,
|
|
111
|
+
peekEdgeRegionHeader,
|
|
76
112
|
async getHeaders() {
|
|
77
|
-
return { ...await getEdgeRegionHeader(), ...getActivityIdHeader() };
|
|
113
|
+
return { ...(await getEdgeRegionHeader()), ...getActivityIdHeader() };
|
|
78
114
|
},
|
|
79
115
|
};
|
|
80
116
|
}
|
|
81
117
|
const defaultBrowserTelemetry = createBrowserTelemetry();
|
|
82
118
|
export const getBrowserActivityIdHeader = () => defaultBrowserTelemetry.getActivityIdHeader();
|
|
83
119
|
export const getBrowserEdgeRegionHeader = () => defaultBrowserTelemetry.getEdgeRegionHeader();
|
|
120
|
+
export const peekBrowserEdgeRegionHeader = () => defaultBrowserTelemetry.peekEdgeRegionHeader();
|
|
84
121
|
export const getBrowserTelemetryHeaders = () => defaultBrowserTelemetry.getHeaders();
|