zubbl-sdk 1.1.9 → 1.1.12

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.
@@ -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(`${config.baseUrl}/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
  */
@@ -112,6 +178,7 @@ async function getTiles({ external_user_id, app_id = null }) {
112
178
  );
113
179
  return response.data;
114
180
  }
181
+
115
182
  async function enforce({ external_user_id, app_id = null }) {
116
183
  if (!config.apiKey || !config.tenantId || !config.appId) {
117
184
  throw new Error("Zubbl SDK not initialized");
@@ -145,7 +212,10 @@ async function enforce({ external_user_id, app_id = null }) {
145
212
  }
146
213
  }
147
214
 
215
+ exports.emitEndpoint = emitEndpoint;
148
216
  exports.enforce = enforce;
149
217
  exports.getTiles = getTiles;
150
218
  exports.identifyUser = identifyUser;
151
219
  exports.init = init;
220
+ exports.setSamplingRatio = setSamplingRatio;
221
+ exports.zubblFetch = zubblFetch;
@@ -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(`${config.baseUrl}/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
  */
@@ -110,6 +176,7 @@ async function getTiles({ external_user_id, app_id = null }) {
110
176
  );
111
177
  return response.data;
112
178
  }
179
+
113
180
  async function enforce({ external_user_id, app_id = null }) {
114
181
  if (!config.apiKey || !config.tenantId || !config.appId) {
115
182
  throw new Error("Zubbl SDK not initialized");
@@ -143,4 +210,4 @@ async function enforce({ external_user_id, app_id = null }) {
143
210
  }
144
211
  }
145
212
 
146
- export { enforce, getTiles, identifyUser, init };
213
+ export { emitEndpoint, enforce, getTiles, identifyUser, init, setSamplingRatio, zubblFetch };
@@ -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(`${config.baseUrl}/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
  */
@@ -114,6 +180,7 @@
114
180
  );
115
181
  return response.data;
116
182
  }
183
+
117
184
  async function enforce({ external_user_id, app_id = null }) {
118
185
  if (!config.apiKey || !config.tenantId || !config.appId) {
119
186
  throw new Error("Zubbl SDK not initialized");
@@ -147,9 +214,12 @@
147
214
  }
148
215
  }
149
216
 
217
+ exports.emitEndpoint = emitEndpoint;
150
218
  exports.enforce = enforce;
151
219
  exports.getTiles = getTiles;
152
220
  exports.identifyUser = identifyUser;
153
221
  exports.init = init;
222
+ exports.setSamplingRatio = setSamplingRatio;
223
+ exports.zubblFetch = zubblFetch;
154
224
 
155
225
  }));
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "zubbl-sdk",
3
- "version": "1.1.9",
3
+ "version": "1.1.12",
4
+ "type": "module",
4
5
  "description": "Zubbl SDK for secure policy enforcement (browser, Node, universal)",
5
6
  "main": "dist/zubbl-sdk.cjs.js",
6
7
  "module": "dist/zubbl-sdk.esm.js",
@@ -21,13 +22,14 @@
21
22
  "scripts": {
22
23
  "build": "rollup -c",
23
24
  "prepublishOnly": "npm run build",
24
- "test": "echo 'Add tests!'"
25
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest"
25
26
  },
26
27
  "repository": "https://github.com/zubbl/zubbl-sdk",
27
28
  "author": "Zubbl",
28
29
  "license": "MIT",
29
30
  "devDependencies": {
30
31
  "@rollup/plugin-node-resolve": "^16.0.1",
32
+ "jest": "^30.1.3",
31
33
  "rollup": "^4.2.0"
32
34
  },
33
35
  "dependencies": {