zubbl-sdk 1.1.8 → 1.1.11
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/zubbl-sdk.cjs.js +103 -0
- package/dist/zubbl-sdk.esm.js +100 -1
- package/dist/zubbl-sdk.umd.js +103 -0
- package/package.json +1 -1
package/dist/zubbl-sdk.cjs.js
CHANGED
|
@@ -11,6 +11,72 @@ let config = {
|
|
|
11
11
|
workerSecret: null,
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
// ---- Telemetry State ----
|
|
15
|
+
let sampleRatio = 0.1; // default 1 in 10
|
|
16
|
+
let endpointBuffer = [];
|
|
17
|
+
let debounceTimer = null;
|
|
18
|
+
|
|
19
|
+
function shouldSample() {
|
|
20
|
+
return Math.random() < sampleRatio;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function setSamplingRatio(ratio) {
|
|
24
|
+
if (ratio <= 0 || ratio > 1) throw new Error("Sampling ratio must be between 0 and 1");
|
|
25
|
+
sampleRatio = ratio;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function emitEndpoint(payload) {
|
|
29
|
+
if (!shouldSample()) return;
|
|
30
|
+
endpointBuffer.push({ ...payload, ts: Date.now(), source: "sdk" });
|
|
31
|
+
if (!debounceTimer) {
|
|
32
|
+
debounceTimer = setTimeout(flushEndpointBuffer, 200);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function flushEndpointBuffer() {
|
|
37
|
+
if (endpointBuffer.length === 0) {
|
|
38
|
+
debounceTimer = null;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const batch = [...endpointBuffer];
|
|
42
|
+
endpointBuffer = [];
|
|
43
|
+
debounceTimer = null;
|
|
44
|
+
try {
|
|
45
|
+
await fetch("/api/sdk/telemetry/endpoints", {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: { "Content-Type": "application/json" },
|
|
48
|
+
body: JSON.stringify(batch),
|
|
49
|
+
});
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error("[Zubbl SDK] Failed to send endpoint telemetry", err);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function zubblFetch(input, init = {}, context = {}) {
|
|
56
|
+
const start = performance.now();
|
|
57
|
+
let response;
|
|
58
|
+
try {
|
|
59
|
+
response = await fetch(input, init);
|
|
60
|
+
return response;
|
|
61
|
+
} finally {
|
|
62
|
+
const latency_ms = performance.now() - start;
|
|
63
|
+
try {
|
|
64
|
+
const url = new URL(input, window.location.origin);
|
|
65
|
+
emitEndpoint({
|
|
66
|
+
tenant_id: context.tenant_id || config.tenantId,
|
|
67
|
+
app_id: context.app_id || config.appId,
|
|
68
|
+
external_user_id: context.external_user_id,
|
|
69
|
+
method: init.method || "GET",
|
|
70
|
+
pathname: url.pathname,
|
|
71
|
+
status: response?.status ?? 0,
|
|
72
|
+
latency_ms,
|
|
73
|
+
});
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.warn("[Zubbl SDK] Failed to record endpoint telemetry", e);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
14
80
|
/**
|
|
15
81
|
* Initialize SDK with API credentials.
|
|
16
82
|
*/
|
|
@@ -113,6 +179,43 @@ async function getTiles({ external_user_id, app_id = null }) {
|
|
|
113
179
|
return response.data;
|
|
114
180
|
}
|
|
115
181
|
|
|
182
|
+
async function enforce({ external_user_id, app_id = null }) {
|
|
183
|
+
if (!config.apiKey || !config.tenantId || !config.appId) {
|
|
184
|
+
throw new Error("Zubbl SDK not initialized");
|
|
185
|
+
}
|
|
186
|
+
if (!external_user_id) throw new Error("external_user_id is required");
|
|
187
|
+
|
|
188
|
+
const headers = {
|
|
189
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
190
|
+
"X-Tenant-Id": config.tenantId,
|
|
191
|
+
"X-App-Id": app_id || config.appId,
|
|
192
|
+
"X-External-User-Id": external_user_id,
|
|
193
|
+
"Content-Type": "application/json",
|
|
194
|
+
};
|
|
195
|
+
if (config.injectWorkerHeaders && config.workerSecret) {
|
|
196
|
+
headers["X-Zubbl-Worker-Secret"] = config.workerSecret;
|
|
197
|
+
headers["X-Zubbl-Internal-Call"] = "true";
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const resp = await axios.post(
|
|
202
|
+
`${config.baseUrl.replace(/\/$/, "")}/sdk/test-enforcement`,
|
|
203
|
+
{},
|
|
204
|
+
{ headers }
|
|
205
|
+
);
|
|
206
|
+
return { decision: "allow", status: resp.status, data: resp.data };
|
|
207
|
+
} catch (e) {
|
|
208
|
+
if (e.response && e.response.status === 429) {
|
|
209
|
+
return { decision: "block", status: 429, data: e.response.data };
|
|
210
|
+
}
|
|
211
|
+
throw e;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
exports.emitEndpoint = emitEndpoint;
|
|
216
|
+
exports.enforce = enforce;
|
|
116
217
|
exports.getTiles = getTiles;
|
|
117
218
|
exports.identifyUser = identifyUser;
|
|
118
219
|
exports.init = init;
|
|
220
|
+
exports.setSamplingRatio = setSamplingRatio;
|
|
221
|
+
exports.zubblFetch = zubblFetch;
|
package/dist/zubbl-sdk.esm.js
CHANGED
|
@@ -9,6 +9,72 @@ let config = {
|
|
|
9
9
|
workerSecret: null,
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// ---- Telemetry State ----
|
|
13
|
+
let sampleRatio = 0.1; // default 1 in 10
|
|
14
|
+
let endpointBuffer = [];
|
|
15
|
+
let debounceTimer = null;
|
|
16
|
+
|
|
17
|
+
function shouldSample() {
|
|
18
|
+
return Math.random() < sampleRatio;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function setSamplingRatio(ratio) {
|
|
22
|
+
if (ratio <= 0 || ratio > 1) throw new Error("Sampling ratio must be between 0 and 1");
|
|
23
|
+
sampleRatio = ratio;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function emitEndpoint(payload) {
|
|
27
|
+
if (!shouldSample()) return;
|
|
28
|
+
endpointBuffer.push({ ...payload, ts: Date.now(), source: "sdk" });
|
|
29
|
+
if (!debounceTimer) {
|
|
30
|
+
debounceTimer = setTimeout(flushEndpointBuffer, 200);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function flushEndpointBuffer() {
|
|
35
|
+
if (endpointBuffer.length === 0) {
|
|
36
|
+
debounceTimer = null;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const batch = [...endpointBuffer];
|
|
40
|
+
endpointBuffer = [];
|
|
41
|
+
debounceTimer = null;
|
|
42
|
+
try {
|
|
43
|
+
await fetch("/api/sdk/telemetry/endpoints", {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: { "Content-Type": "application/json" },
|
|
46
|
+
body: JSON.stringify(batch),
|
|
47
|
+
});
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.error("[Zubbl SDK] Failed to send endpoint telemetry", err);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function zubblFetch(input, init = {}, context = {}) {
|
|
54
|
+
const start = performance.now();
|
|
55
|
+
let response;
|
|
56
|
+
try {
|
|
57
|
+
response = await fetch(input, init);
|
|
58
|
+
return response;
|
|
59
|
+
} finally {
|
|
60
|
+
const latency_ms = performance.now() - start;
|
|
61
|
+
try {
|
|
62
|
+
const url = new URL(input, window.location.origin);
|
|
63
|
+
emitEndpoint({
|
|
64
|
+
tenant_id: context.tenant_id || config.tenantId,
|
|
65
|
+
app_id: context.app_id || config.appId,
|
|
66
|
+
external_user_id: context.external_user_id,
|
|
67
|
+
method: init.method || "GET",
|
|
68
|
+
pathname: url.pathname,
|
|
69
|
+
status: response?.status ?? 0,
|
|
70
|
+
latency_ms,
|
|
71
|
+
});
|
|
72
|
+
} catch (e) {
|
|
73
|
+
console.warn("[Zubbl SDK] Failed to record endpoint telemetry", e);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
12
78
|
/**
|
|
13
79
|
* Initialize SDK with API credentials.
|
|
14
80
|
*/
|
|
@@ -111,4 +177,37 @@ async function getTiles({ external_user_id, app_id = null }) {
|
|
|
111
177
|
return response.data;
|
|
112
178
|
}
|
|
113
179
|
|
|
114
|
-
|
|
180
|
+
async function enforce({ external_user_id, app_id = null }) {
|
|
181
|
+
if (!config.apiKey || !config.tenantId || !config.appId) {
|
|
182
|
+
throw new Error("Zubbl SDK not initialized");
|
|
183
|
+
}
|
|
184
|
+
if (!external_user_id) throw new Error("external_user_id is required");
|
|
185
|
+
|
|
186
|
+
const headers = {
|
|
187
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
188
|
+
"X-Tenant-Id": config.tenantId,
|
|
189
|
+
"X-App-Id": app_id || config.appId,
|
|
190
|
+
"X-External-User-Id": external_user_id,
|
|
191
|
+
"Content-Type": "application/json",
|
|
192
|
+
};
|
|
193
|
+
if (config.injectWorkerHeaders && config.workerSecret) {
|
|
194
|
+
headers["X-Zubbl-Worker-Secret"] = config.workerSecret;
|
|
195
|
+
headers["X-Zubbl-Internal-Call"] = "true";
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const resp = await axios.post(
|
|
200
|
+
`${config.baseUrl.replace(/\/$/, "")}/sdk/test-enforcement`,
|
|
201
|
+
{},
|
|
202
|
+
{ headers }
|
|
203
|
+
);
|
|
204
|
+
return { decision: "allow", status: resp.status, data: resp.data };
|
|
205
|
+
} catch (e) {
|
|
206
|
+
if (e.response && e.response.status === 429) {
|
|
207
|
+
return { decision: "block", status: 429, data: e.response.data };
|
|
208
|
+
}
|
|
209
|
+
throw e;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export { emitEndpoint, enforce, getTiles, identifyUser, init, setSamplingRatio, zubblFetch };
|
package/dist/zubbl-sdk.umd.js
CHANGED
|
@@ -13,6 +13,72 @@
|
|
|
13
13
|
workerSecret: null,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
// ---- Telemetry State ----
|
|
17
|
+
let sampleRatio = 0.1; // default 1 in 10
|
|
18
|
+
let endpointBuffer = [];
|
|
19
|
+
let debounceTimer = null;
|
|
20
|
+
|
|
21
|
+
function shouldSample() {
|
|
22
|
+
return Math.random() < sampleRatio;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function setSamplingRatio(ratio) {
|
|
26
|
+
if (ratio <= 0 || ratio > 1) throw new Error("Sampling ratio must be between 0 and 1");
|
|
27
|
+
sampleRatio = ratio;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function emitEndpoint(payload) {
|
|
31
|
+
if (!shouldSample()) return;
|
|
32
|
+
endpointBuffer.push({ ...payload, ts: Date.now(), source: "sdk" });
|
|
33
|
+
if (!debounceTimer) {
|
|
34
|
+
debounceTimer = setTimeout(flushEndpointBuffer, 200);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function flushEndpointBuffer() {
|
|
39
|
+
if (endpointBuffer.length === 0) {
|
|
40
|
+
debounceTimer = null;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const batch = [...endpointBuffer];
|
|
44
|
+
endpointBuffer = [];
|
|
45
|
+
debounceTimer = null;
|
|
46
|
+
try {
|
|
47
|
+
await fetch("/api/sdk/telemetry/endpoints", {
|
|
48
|
+
method: "POST",
|
|
49
|
+
headers: { "Content-Type": "application/json" },
|
|
50
|
+
body: JSON.stringify(batch),
|
|
51
|
+
});
|
|
52
|
+
} catch (err) {
|
|
53
|
+
console.error("[Zubbl SDK] Failed to send endpoint telemetry", err);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function zubblFetch(input, init = {}, context = {}) {
|
|
58
|
+
const start = performance.now();
|
|
59
|
+
let response;
|
|
60
|
+
try {
|
|
61
|
+
response = await fetch(input, init);
|
|
62
|
+
return response;
|
|
63
|
+
} finally {
|
|
64
|
+
const latency_ms = performance.now() - start;
|
|
65
|
+
try {
|
|
66
|
+
const url = new URL(input, window.location.origin);
|
|
67
|
+
emitEndpoint({
|
|
68
|
+
tenant_id: context.tenant_id || config.tenantId,
|
|
69
|
+
app_id: context.app_id || config.appId,
|
|
70
|
+
external_user_id: context.external_user_id,
|
|
71
|
+
method: init.method || "GET",
|
|
72
|
+
pathname: url.pathname,
|
|
73
|
+
status: response?.status ?? 0,
|
|
74
|
+
latency_ms,
|
|
75
|
+
});
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.warn("[Zubbl SDK] Failed to record endpoint telemetry", e);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
16
82
|
/**
|
|
17
83
|
* Initialize SDK with API credentials.
|
|
18
84
|
*/
|
|
@@ -115,8 +181,45 @@
|
|
|
115
181
|
return response.data;
|
|
116
182
|
}
|
|
117
183
|
|
|
184
|
+
async function enforce({ external_user_id, app_id = null }) {
|
|
185
|
+
if (!config.apiKey || !config.tenantId || !config.appId) {
|
|
186
|
+
throw new Error("Zubbl SDK not initialized");
|
|
187
|
+
}
|
|
188
|
+
if (!external_user_id) throw new Error("external_user_id is required");
|
|
189
|
+
|
|
190
|
+
const headers = {
|
|
191
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
192
|
+
"X-Tenant-Id": config.tenantId,
|
|
193
|
+
"X-App-Id": app_id || config.appId,
|
|
194
|
+
"X-External-User-Id": external_user_id,
|
|
195
|
+
"Content-Type": "application/json",
|
|
196
|
+
};
|
|
197
|
+
if (config.injectWorkerHeaders && config.workerSecret) {
|
|
198
|
+
headers["X-Zubbl-Worker-Secret"] = config.workerSecret;
|
|
199
|
+
headers["X-Zubbl-Internal-Call"] = "true";
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const resp = await axios.post(
|
|
204
|
+
`${config.baseUrl.replace(/\/$/, "")}/sdk/test-enforcement`,
|
|
205
|
+
{},
|
|
206
|
+
{ headers }
|
|
207
|
+
);
|
|
208
|
+
return { decision: "allow", status: resp.status, data: resp.data };
|
|
209
|
+
} catch (e) {
|
|
210
|
+
if (e.response && e.response.status === 429) {
|
|
211
|
+
return { decision: "block", status: 429, data: e.response.data };
|
|
212
|
+
}
|
|
213
|
+
throw e;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
exports.emitEndpoint = emitEndpoint;
|
|
218
|
+
exports.enforce = enforce;
|
|
118
219
|
exports.getTiles = getTiles;
|
|
119
220
|
exports.identifyUser = identifyUser;
|
|
120
221
|
exports.init = init;
|
|
222
|
+
exports.setSamplingRatio = setSamplingRatio;
|
|
223
|
+
exports.zubblFetch = zubblFetch;
|
|
121
224
|
|
|
122
225
|
}));
|