testchimp-rum-js 0.0.2 → 0.0.4
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/README.md +11 -5
- package/dist/http.d.ts +9 -2
- package/dist/http.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/session.d.ts +4 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/testchimp-rum.min.js +1 -1
- package/dist/testchimp-rum.mjs +1 -1
- package/dist/validation.d.ts +8 -3
- package/dist/validation.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ Initializes the RUM client. Call once before using `emit`, `flush`, or `resetSes
|
|
|
53
53
|
| `config.environment` | `string` | No | Logical environment for the session (e.g. `'production'`, `'staging'`). |
|
|
54
54
|
| `config.release` | `string` | No | Application release/version identifier (e.g. `'2.1.0'`). |
|
|
55
55
|
| `config.branchName` | `string` | No | Git branch name associated with this session (e.g. `'feature/checkout'`). |
|
|
56
|
-
| `config.sessionMetadata` | `
|
|
56
|
+
| `config.sessionMetadata` | `Struct` | No | Additional immutable metadata for the session (same validation as event metadata). Do **not** put `environment`, `release`, or `branch_name` here—use the top-level fields above. |
|
|
57
57
|
| `config.config` | `object` | No | Optional tuning; see [Configuration options](#configuration-options). |
|
|
58
58
|
|
|
59
59
|
**Example with options**
|
|
@@ -82,7 +82,7 @@ Records one event. Events are validated, then buffered and sent in batches. Inva
|
|
|
82
82
|
| Parameter | Type | Required | Description |
|
|
83
83
|
|-----------|------|----------|--------------|
|
|
84
84
|
| `input.title` | `string` | Yes | Event name (e.g. `'button_clicked'`). Max 100 characters. |
|
|
85
|
-
| `input.metadata` | `
|
|
85
|
+
| `input.metadata` | `Struct` | No | Optional metadata (key-value; values are primitive or array of primitives only—no nested objects). See [Event constraints](#event-constraints). |
|
|
86
86
|
|
|
87
87
|
**Examples**
|
|
88
88
|
|
|
@@ -93,9 +93,15 @@ testchimp.emit({
|
|
|
93
93
|
title: 'form_submitted',
|
|
94
94
|
metadata: {
|
|
95
95
|
form_id: 'signup',
|
|
96
|
-
step:
|
|
96
|
+
step: 2,
|
|
97
97
|
},
|
|
98
98
|
});
|
|
99
|
+
|
|
100
|
+
// Values: primitive or array of primitives only
|
|
101
|
+
testchimp.emit({
|
|
102
|
+
title: 'checkout_step',
|
|
103
|
+
metadata: { step_index: 1, total: 3, tags: ['cart', 'checkout'] },
|
|
104
|
+
});
|
|
99
105
|
```
|
|
100
106
|
|
|
101
107
|
### `testchimp.flush()`
|
|
@@ -150,9 +156,9 @@ testchimp.init({
|
|
|
150
156
|
Events that exceed these limits are dropped and a warning is logged:
|
|
151
157
|
|
|
152
158
|
- **title**: Required, non-empty string, max **100** characters.
|
|
153
|
-
- **metadata**: Optional. Max **10** keys; each key max **50** chars
|
|
159
|
+
- **metadata**: Optional. Values must be primitive (string, number, boolean, null) or array of primitives—no nested objects. Max **10** keys; each key max **50** chars; string values max **200** chars; arrays max **50** elements. Total serialized event size max **5 KB**.
|
|
154
160
|
|
|
155
|
-
Session metadata (in `init`) uses the same metadata
|
|
161
|
+
Session metadata (in `init`) uses the same metadata rules. The type `Struct` is exported for TypeScript users.
|
|
156
162
|
|
|
157
163
|
## Session and batching
|
|
158
164
|
|
package/dist/http.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple HTTP client for browser or Node.
|
|
3
|
+
* Uses global fetch (browser, or Node 18+).
|
|
4
|
+
*/
|
|
1
5
|
export interface HttpConfig {
|
|
2
6
|
baseUrl: string;
|
|
3
7
|
projectId: string;
|
|
4
8
|
apiKey: string;
|
|
5
9
|
}
|
|
6
|
-
|
|
10
|
+
/**
|
|
11
|
+
* POST to a path under config.baseUrl with auth headers (projectId, apiKey) and optional ci-test-info.
|
|
12
|
+
*/
|
|
13
|
+
export declare function post(config: HttpConfig, path: string, body: unknown, options?: {
|
|
7
14
|
keepalive?: boolean;
|
|
8
|
-
}):
|
|
15
|
+
}): Promise<boolean>;
|
|
9
16
|
//# sourceMappingURL=http.d.ts.map
|
package/dist/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAkBD;;GAEG;AACH,wBAAsB,IAAI,CACxB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAChC,OAAO,CAAC,OAAO,CAAC,CAsBlB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { EmitInput } from "./validation";
|
|
1
|
+
import type { EmitInput, Struct } from "./validation";
|
|
2
|
+
export type { Struct, EmitInput };
|
|
2
3
|
export interface InitConfig {
|
|
3
4
|
projectId: string;
|
|
4
5
|
apiKey: string;
|
|
@@ -6,7 +7,7 @@ export interface InitConfig {
|
|
|
6
7
|
environment?: string;
|
|
7
8
|
release?: string;
|
|
8
9
|
branchName?: string;
|
|
9
|
-
sessionMetadata?:
|
|
10
|
+
sessionMetadata?: Struct;
|
|
10
11
|
config?: {
|
|
11
12
|
captureEnabled?: boolean;
|
|
12
13
|
maxEventsPerSession?: number;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAOlC,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE;QACP,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,uBAAuB,CAAC,EAAE,MAAM,CAAC;QACjC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CACH;AAsCD,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAiF7C;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAkB3C;AAED,wBAAgB,KAAK,IAAI,IAAI,CAI5B;AAED,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAgBnC;AAGD,QAAA,MAAM,SAAS;;;;;;CAMd,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
package/dist/session.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { type Struct } from "./validation";
|
|
1
2
|
export declare function getStorage(): Storage | null;
|
|
2
|
-
export declare function resolveSessionId(providedSessionId: string | undefined, sessionMetadata:
|
|
3
|
+
export declare function resolveSessionId(providedSessionId: string | undefined, sessionMetadata: Struct | undefined, inactivityTimeoutMillis: number): {
|
|
3
4
|
sessionId: string;
|
|
4
5
|
isNew: boolean;
|
|
5
6
|
};
|
|
6
|
-
export declare function persistSession(sessionId: string, sessionMetadata?:
|
|
7
|
+
export declare function persistSession(sessionId: string, sessionMetadata?: Struct): void;
|
|
7
8
|
export declare function updateLastActivity(): void;
|
|
8
9
|
export declare function getEventCount(): number;
|
|
9
10
|
export declare function setEventCount(count: number): void;
|
|
10
11
|
export declare function getEventTypeCounts(): Record<string, number>;
|
|
11
12
|
export declare function setEventTypeCounts(counts: Record<string, number>): void;
|
|
12
|
-
export declare function getSessionMetadata():
|
|
13
|
+
export declare function getSessionMetadata(): Struct | undefined;
|
|
13
14
|
export declare function resetSession(): void;
|
|
14
15
|
//# sourceMappingURL=session.d.ts.map
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAOpE,wBAAgB,UAAU,IAAI,OAAO,GAAG,IAAI,CAM3C;AAED,wBAAgB,gBAAgB,CAC9B,iBAAiB,EAAE,MAAM,GAAG,SAAS,EACrC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,uBAAuB,EAAE,MAAM,GAC9B;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAsBvC;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,eAAe,CAAC,EAAE,MAAM,GACvB,IAAI,CAwBN;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAMtC;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAW3D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAQvE;AAED,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAWvD;AAED,wBAAgB,YAAY,IAAI,IAAI,CAQnC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var testchimp=(()=>{var
|
|
1
|
+
"use strict";var testchimp=(()=>{var y=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var q=(e,t)=>{for(var n in t)y(e,n,{get:t[n],enumerable:!0})},W=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of J(t))!Z.call(e,s)&&s!==n&&y(e,s,{get:()=>t[s],enumerable:!(r=$(t,s))||r.enumerable});return e};var Q=e=>W(y({},"__esModule",{value:!0}),e);var pe={};q(pe,{default:()=>me,emit:()=>j,flush:()=>K,getSessionId:()=>Y,init:()=>z,resetSession:()=>F});function ee(){if(typeof fetch<"u")return fetch;throw new Error("testchimp-rum-js: fetch is not available. Use a browser or Node 18+.")}function te(){if(typeof window>"u")return;let t=window.__TC_CI_TEST_INFO;return typeof t=="string"&&t.length>0?t:void 0}function ne(e,t){let n=e.baseUrl.replace(/\/$/,""),r=t.startsWith("/")?t:`/${t}`;return`${n}${r}`}async function E(e,t,n,r){try{let s=ne(e,t),o={"Content-Type":"application/json","Project-Id":e.projectId,"TestChimp-Api-Key":e.apiKey,...r?.keepalive&&{"Keep-Alive":"true"}},f=te();return f&&(o["ci-test-info"]=f),(await ee()(s,{method:"POST",headers:o,body:JSON.stringify(n)})).ok}catch{return!1}}var N="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function I(){let e=Date.now(),t=re(e,10),n=ie(16);return t+n}function re(e,t){let n="";for(let r=t;r>0;r--)n=N[e%32]+n,e=Math.floor(e/32);return n}function ie(e){let t=new Uint8Array(e);if(typeof crypto<"u"&&crypto.getRandomValues)crypto.getRandomValues(t);else for(let r=0;r<e;r++)t[r]=Math.floor(Math.random()*256);let n="";for(let r=0;r<e;r++)n+=N[t[r]%32];return n}function w(e){return e===null||typeof e=="string"||typeof e=="number"||typeof e=="boolean"}function M(e){if(typeof e!="object"||e===null||Array.isArray(e))return{ok:!1,reason:"metadata must be a plain object"};let t=Object.keys(e);if(t.length>10)return{ok:!1,reason:"metadata has more than 10 keys"};let n={};for(let r of t){if(r.length>50)return{ok:!1,reason:"metadata key exceeds 50 chars"};let s=e[r];if(Array.isArray(s)){if(s.length>50)return{ok:!1,reason:"metadata array length exceeds 50"};for(let o=0;o<s.length;o++){let f=s[o];if(!w(f))return{ok:!1,reason:"metadata array values must be string, number, boolean, or null"};if(typeof f=="string"&&f.length>200)return{ok:!1,reason:"metadata string in array exceeds 200 chars"}}n[r]=s}else if(w(s)){if(typeof s=="string"&&s.length>200)return{ok:!1,reason:"metadata string value exceeds 200 chars"};n[r]=s}else return{ok:!1,reason:"metadata values must be primitive or array of primitives (no nested objects)"}}return{ok:!0,value:n}}function C(e){if(!e.title||typeof e.title!="string")return console.warn("[testchimp-rum] Event dropped: title is required"),null;if(e.title.length>100)return console.warn("[testchimp-rum] Event dropped: title exceeds 100 chars"),null;let t;if(e.metadata!=null&&typeof e.metadata=="object"&&!Array.isArray(e.metadata)){let s=M(e.metadata);if(!s.ok)return console.warn(`[testchimp-rum] Event dropped: ${s.reason}`),null;t=Object.keys(s.value).length>0?s.value:void 0}let n={title:e.title,timestampMillis:Date.now(),metadata:t},r=JSON.stringify(n);return new TextEncoder().encode(r).length>5120?(console.warn("[testchimp-rum] Event dropped: total size exceeds 5120 bytes"),null):n}function v(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t=M(e);if(t.ok)return Object.keys(t.value).length>0?t.value:void 0}var h="testchimp_session_id",g="testchimp_last_activity",T="testchimp_event_count",_="testchimp_event_type_counts";function l(){try{return typeof window<"u"&&window.localStorage?window.localStorage:null}catch{return null}}function L(e,t,n){if(e&&typeof e=="string"&&e.length>0)return{sessionId:e,isNew:!1};let r=l();if(!r)return{sessionId:I(),isNew:!0};let s=r.getItem(h),o=r.getItem(g),f=Date.now();if(s&&o){let d=parseInt(o,10);if(!isNaN(d)&&f-d<n)return{sessionId:s,isNew:!1}}return{sessionId:I(),isNew:!0}}function R(e,t){let n=l();if(!n)return;let r=Date.now();n.setItem(h,e),n.setItem(g,String(r)),n.setItem(T,"0");let s=v(t);if(s)try{n.setItem("testchimp_session_metadata",JSON.stringify(s))}catch{}let o={};try{n.setItem(_,JSON.stringify(o))}catch{}}function D(){let e=l();e&&e.setItem(g,String(Date.now()))}function b(){let e=l();if(!e)return 0;let t=e.getItem(T),n=parseInt(t??"0",10);return isNaN(n)?0:n}function B(e){let t=l();t&&t.setItem(T,String(e))}function x(){let e=l();if(!e)return{};try{let t=e.getItem(_);if(!t)return{};let n=JSON.parse(t);return typeof n=="object"&&n!==null?n:{}}catch{return{}}}function k(e){let t=l();if(t)try{t.setItem(_,JSON.stringify(e))}catch{}}function V(){let e=l();if(e)try{let t=e.getItem("testchimp_session_metadata");if(!t)return;let n=JSON.parse(t);return typeof n=="object"&&n!==null?n:void 0}catch{return}}function P(){let e=l();e&&(e.removeItem(h),e.removeItem(g),e.removeItem(T),e.removeItem(_),e.removeItem("testchimp_session_metadata"))}var se=100,oe=3;function G(e,t,n){let r=[],s=!1;function o(a){return!(b()>=n.maxEventsPerSession||(x()[a]??0)>=n.maxRepeatsPerEvent)}function f(a){let c=b()+1;B(c);let u=x();return u[a]=(u[a]??0)+1,k(u),c}function d(a,c=!1){a.length!==0&&E(e,"/rum/events",{session_id:t,events:a.map(u=>({title:u.title,event_index:u.eventIndex,timestamp_millis:u.timestampMillis,metadata:u.metadata??{}}))},{keepalive:c})}function m(a=!1){if(r.length===0)return;let c=[...r];r=[],d(c,a)}function A(a){if(!o(a.title))return!1;let c=f(a.title);return r.push({...a,eventIndex:c}),!0}function p(){return r.length}function S(){return r}return{add:A,flush:m,getBufferSize:p,getBuffer:S,get maxBufferSize(){return n.maxBufferSize}}}function H(){return{maxEventsPerSession:se,maxRepeatsPerEvent:oe,maxBufferSize:100}}var ae="https://ingress.testchimp.io",ue=1e4,fe=100,ce=30*60*1e3,i=null;function de(e){i.flushTimerId&&clearInterval(i.flushTimerId),i.flushTimerId=setInterval(()=>{i&&i.buffer.getBufferSize()>0&&i.buffer.flush(!1)},e)}function O(){document.visibilityState==="hidden"&&i&&i.buffer.flush(!0)}function U(){i&&i.buffer.flush(!0)}function X(e){e.key==="testchimp_session_id"&&e.newValue&&i&&(i.sessionId=e.newValue)}function z(e){if(!e.projectId||!e.apiKey){console.warn("[testchimp-rum] init: projectId and apiKey are required");return}let t=e.config??{},n=t.captureEnabled!==!1,r=t.testchimpEndpoint??ae,s=t.inactivityTimeoutMillis??ce,o=t.eventSendInterval??ue,f=t.maxBufferSize??fe,d=v(e.sessionMetadata),{sessionId:m,isNew:A}=L(e.sessionId,d,s);R(m,d??e.sessionMetadata);let p={baseUrl:r,projectId:e.projectId,apiKey:e.apiKey},S={...H(),maxEventsPerSession:t.maxEventsPerSession??100,maxRepeatsPerEvent:t.maxRepeatsPerEvent??3,maxBufferSize:f},a=G(p,m,S);if(i&&i.flushTimerId&&clearInterval(i.flushTimerId),i={httpConfig:p,sessionId:m,buffer:a,captureEnabled:n,flushTimerId:null,initialized:!0},de(o),typeof document<"u"&&(document.addEventListener("visibilitychange",O),window.addEventListener("beforeunload",U)),typeof window<"u"&&window.addEventListener("storage",X),A&&n){let c=V()??d??{},u={session_id:m,started_at:Date.now(),metadata:c};e.environment&&(u.environment=e.environment),e.release&&(u.release=e.release),e.branchName&&(u.branch_name=e.branchName),E(p,"/rum/session/start",u)}}function j(e){if(!i||!i.initialized){console.warn("[testchimp-rum] emit: call init() first");return}if(!i.captureEnabled)return;let t=C(e);!t||(D(),!i.buffer.add(t))||i.buffer.getBufferSize()>=i.buffer.maxBufferSize&&i.buffer.flush(!1)}function K(){i&&i.initialized&&i.buffer.flush(!1)}function Y(){return!i||!i.initialized?"":i.sessionId}function F(){i&&(i.flushTimerId&&(clearInterval(i.flushTimerId),i.flushTimerId=null),i=null),typeof document<"u"&&(document.removeEventListener("visibilitychange",O),window.removeEventListener("beforeunload",U)),typeof window<"u"&&window.removeEventListener("storage",X),P()}var le={init:z,emit:j,flush:K,getSessionId:Y,resetSession:F},me=le;return Q(pe);})();
|
package/dist/testchimp-rum.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function X(){if(typeof fetch<"u")return fetch;throw new Error("testchimp-rum-js: fetch is not available. Use a browser or Node 18+.")}function z(){if(typeof window>"u")return;let t=window.__TC_CI_TEST_INFO;return typeof t=="string"&&t.length>0?t:void 0}function j(e,t){let n=e.baseUrl.replace(/\/$/,""),r=t.startsWith("/")?t:`/${t}`;return`${n}${r}`}async function E(e,t,n,r){try{let s=j(e,t),o={"Content-Type":"application/json","Project-Id":e.projectId,"TestChimp-Api-Key":e.apiKey,...r?.keepalive&&{"Keep-Alive":"true"}},f=z();return f&&(o["ci-test-info"]=f),(await X()(s,{method:"POST",headers:o,body:JSON.stringify(n)})).ok}catch{return!1}}var x="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function y(){let e=Date.now(),t=K(e,10),n=Y(16);return t+n}function K(e,t){let n="";for(let r=t;r>0;r--)n=x[e%32]+n,e=Math.floor(e/32);return n}function Y(e){let t=new Uint8Array(e);if(typeof crypto<"u"&&crypto.getRandomValues)crypto.getRandomValues(t);else for(let r=0;r<e;r++)t[r]=Math.floor(Math.random()*256);let n="";for(let r=0;r<e;r++)n+=x[t[r]%32];return n}function N(e){return e===null||typeof e=="string"||typeof e=="number"||typeof e=="boolean"}function w(e){if(typeof e!="object"||e===null||Array.isArray(e))return{ok:!1,reason:"metadata must be a plain object"};let t=Object.keys(e);if(t.length>10)return{ok:!1,reason:"metadata has more than 10 keys"};let n={};for(let r of t){if(r.length>50)return{ok:!1,reason:"metadata key exceeds 50 chars"};let s=e[r];if(Array.isArray(s)){if(s.length>50)return{ok:!1,reason:"metadata array length exceeds 50"};for(let o=0;o<s.length;o++){let f=s[o];if(!N(f))return{ok:!1,reason:"metadata array values must be string, number, boolean, or null"};if(typeof f=="string"&&f.length>200)return{ok:!1,reason:"metadata string in array exceeds 200 chars"}}n[r]=s}else if(N(s)){if(typeof s=="string"&&s.length>200)return{ok:!1,reason:"metadata string value exceeds 200 chars"};n[r]=s}else return{ok:!1,reason:"metadata values must be primitive or array of primitives (no nested objects)"}}return{ok:!0,value:n}}function M(e){if(!e.title||typeof e.title!="string")return console.warn("[testchimp-rum] Event dropped: title is required"),null;if(e.title.length>100)return console.warn("[testchimp-rum] Event dropped: title exceeds 100 chars"),null;let t;if(e.metadata!=null&&typeof e.metadata=="object"&&!Array.isArray(e.metadata)){let s=w(e.metadata);if(!s.ok)return console.warn(`[testchimp-rum] Event dropped: ${s.reason}`),null;t=Object.keys(s.value).length>0?s.value:void 0}let n={title:e.title,timestampMillis:Date.now(),metadata:t},r=JSON.stringify(n);return new TextEncoder().encode(r).length>5120?(console.warn("[testchimp-rum] Event dropped: total size exceeds 5120 bytes"),null):n}function v(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t=w(e);if(t.ok)return Object.keys(t.value).length>0?t.value:void 0}var I="testchimp_session_id",g="testchimp_last_activity",T="testchimp_event_count",_="testchimp_event_type_counts";function l(){try{return typeof window<"u"&&window.localStorage?window.localStorage:null}catch{return null}}function C(e,t,n){if(e&&typeof e=="string"&&e.length>0)return{sessionId:e,isNew:!1};let r=l();if(!r)return{sessionId:y(),isNew:!0};let s=r.getItem(I),o=r.getItem(g),f=Date.now();if(s&&o){let d=parseInt(o,10);if(!isNaN(d)&&f-d<n)return{sessionId:s,isNew:!1}}return{sessionId:y(),isNew:!0}}function L(e,t){let n=l();if(!n)return;let r=Date.now();n.setItem(I,e),n.setItem(g,String(r)),n.setItem(T,"0");let s=v(t);if(s)try{n.setItem("testchimp_session_metadata",JSON.stringify(s))}catch{}let o={};try{n.setItem(_,JSON.stringify(o))}catch{}}function R(){let e=l();e&&e.setItem(g,String(Date.now()))}function h(){let e=l();if(!e)return 0;let t=e.getItem(T),n=parseInt(t??"0",10);return isNaN(n)?0:n}function D(e){let t=l();t&&t.setItem(T,String(e))}function b(){let e=l();if(!e)return{};try{let t=e.getItem(_);if(!t)return{};let n=JSON.parse(t);return typeof n=="object"&&n!==null?n:{}}catch{return{}}}function B(e){let t=l();if(t)try{t.setItem(_,JSON.stringify(e))}catch{}}function k(){let e=l();if(e)try{let t=e.getItem("testchimp_session_metadata");if(!t)return;let n=JSON.parse(t);return typeof n=="object"&&n!==null?n:void 0}catch{return}}function V(){let e=l();e&&(e.removeItem(I),e.removeItem(g),e.removeItem(T),e.removeItem(_),e.removeItem("testchimp_session_metadata"))}var F=100,$=3;function P(e,t,n){let r=[],s=!1;function o(a){return!(h()>=n.maxEventsPerSession||(b()[a]??0)>=n.maxRepeatsPerEvent)}function f(a){let c=h()+1;D(c);let u=b();return u[a]=(u[a]??0)+1,B(u),c}function d(a,c=!1){a.length!==0&&E(e,"/rum/events",{session_id:t,events:a.map(u=>({title:u.title,event_index:u.eventIndex,timestamp_millis:u.timestampMillis,metadata:u.metadata??{}}))},{keepalive:c})}function m(a=!1){if(r.length===0)return;let c=[...r];r=[],d(c,a)}function A(a){if(!o(a.title))return!1;let c=f(a.title);return r.push({...a,eventIndex:c}),!0}function p(){return r.length}function S(){return r}return{add:A,flush:m,getBufferSize:p,getBuffer:S,get maxBufferSize(){return n.maxBufferSize}}}function G(){return{maxEventsPerSession:F,maxRepeatsPerEvent:$,maxBufferSize:100}}var J="https://ingress.testchimp.io",Z=1e4,q=100,W=30*60*1e3,i=null;function Q(e){i.flushTimerId&&clearInterval(i.flushTimerId),i.flushTimerId=setInterval(()=>{i&&i.buffer.getBufferSize()>0&&i.buffer.flush(!1)},e)}function H(){document.visibilityState==="hidden"&&i&&i.buffer.flush(!0)}function O(){i&&i.buffer.flush(!0)}function U(e){e.key==="testchimp_session_id"&&e.newValue&&i&&(i.sessionId=e.newValue)}function ee(e){if(!e.projectId||!e.apiKey){console.warn("[testchimp-rum] init: projectId and apiKey are required");return}let t=e.config??{},n=t.captureEnabled!==!1,r=t.testchimpEndpoint??J,s=t.inactivityTimeoutMillis??W,o=t.eventSendInterval??Z,f=t.maxBufferSize??q,d=v(e.sessionMetadata),{sessionId:m,isNew:A}=C(e.sessionId,d,s);L(m,d??e.sessionMetadata);let p={baseUrl:r,projectId:e.projectId,apiKey:e.apiKey},S={...G(),maxEventsPerSession:t.maxEventsPerSession??100,maxRepeatsPerEvent:t.maxRepeatsPerEvent??3,maxBufferSize:f},a=P(p,m,S);if(i&&i.flushTimerId&&clearInterval(i.flushTimerId),i={httpConfig:p,sessionId:m,buffer:a,captureEnabled:n,flushTimerId:null,initialized:!0},Q(o),typeof document<"u"&&(document.addEventListener("visibilitychange",H),window.addEventListener("beforeunload",O)),typeof window<"u"&&window.addEventListener("storage",U),A&&n){let c=k()??d??{},u={session_id:m,started_at:Date.now(),metadata:c};e.environment&&(u.environment=e.environment),e.release&&(u.release=e.release),e.branchName&&(u.branch_name=e.branchName),E(p,"/rum/session/start",u)}}function te(e){if(!i||!i.initialized){console.warn("[testchimp-rum] emit: call init() first");return}if(!i.captureEnabled)return;let t=M(e);!t||(R(),!i.buffer.add(t))||i.buffer.getBufferSize()>=i.buffer.maxBufferSize&&i.buffer.flush(!1)}function ne(){i&&i.initialized&&i.buffer.flush(!1)}function re(){return!i||!i.initialized?"":i.sessionId}function ie(){i&&(i.flushTimerId&&(clearInterval(i.flushTimerId),i.flushTimerId=null),i=null),typeof document<"u"&&(document.removeEventListener("visibilitychange",H),window.removeEventListener("beforeunload",O)),typeof window<"u"&&window.removeEventListener("storage",U),V()}var se={init:ee,emit:te,flush:ne,getSessionId:re,resetSession:ie},ye=se;export{ye as default,te as emit,ne as flush,re as getSessionId,ee as init,ie as resetSession};
|
package/dist/validation.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata shape for events/session: keys with primitive or primitive[] values only.
|
|
3
|
+
* No nested objects; invalid entries are dropped at runtime.
|
|
4
|
+
*/
|
|
5
|
+
export type Struct = Record<string, unknown>;
|
|
1
6
|
export interface EmitInput {
|
|
2
7
|
title: string;
|
|
3
|
-
metadata?:
|
|
8
|
+
metadata?: Struct;
|
|
4
9
|
}
|
|
5
10
|
export interface ValidatedEvent {
|
|
6
11
|
title: string;
|
|
7
12
|
timestampMillis: number;
|
|
8
|
-
metadata?:
|
|
13
|
+
metadata?: Struct;
|
|
9
14
|
}
|
|
10
15
|
export declare function validateEvent(input: EmitInput): ValidatedEvent | null;
|
|
11
|
-
export declare function validateSessionMetadata(metadata?:
|
|
16
|
+
export declare function validateSessionMetadata(metadata?: Struct): Struct | undefined;
|
|
12
17
|
//# sourceMappingURL=validation.d.ts.map
|
package/dist/validation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAWA;;;GAGG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA8CD,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,GAAG,IAAI,CAiCrE;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK7E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testchimp-rum-js",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Lightweight browser library for emitting structured user interaction events to TestChimp",
|
|
5
5
|
"main": "dist/testchimp-rum.min.js",
|
|
6
6
|
"module": "dist/testchimp-rum.mjs",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"clean": "rm -rf dist"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
+
"@types/node": "^25.3.5",
|
|
20
21
|
"esbuild": "^0.19.0",
|
|
21
22
|
"typescript": "^5.3.0"
|
|
22
23
|
},
|