@socwarden/browser 1.0.0-alpha.1
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 +73 -0
- package/dist/index.d.mts +76 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# @socwarden/browser
|
|
2
|
+
|
|
3
|
+
Lightweight browser SDK for SOCWarden client-side context collection. Under 3KB minified.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @socwarden/browser
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or include via CDN (UMD):
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<script src="https://cdn.jsdelivr.net/npm/@socwarden/browser/dist/socwarden.min.js"></script>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Modes
|
|
18
|
+
|
|
19
|
+
### Relay Mode (recommended)
|
|
20
|
+
|
|
21
|
+
Collects client context and attaches it as a `X-SOCWarden-Context` header on your app's own requests. Your server-side SDK (e.g. `@socwarden/laravel`) merges this into events automatically.
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { SOCWardenBrowser } from '@socwarden/browser';
|
|
25
|
+
|
|
26
|
+
const sw = new SOCWardenBrowser({ mode: 'relay' });
|
|
27
|
+
sw.installRelay();
|
|
28
|
+
// All subsequent fetch() and XMLHttpRequest calls include the context header.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Direct Mode
|
|
32
|
+
|
|
33
|
+
Sends events directly to the SOCWarden ingestor. Useful for SPAs without a backend.
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
import { SOCWardenBrowser } from '@socwarden/browser';
|
|
37
|
+
|
|
38
|
+
const sw = new SOCWardenBrowser({
|
|
39
|
+
mode: 'direct',
|
|
40
|
+
apiKey: 'sw_live_xxxxxxxxxxxxxxxxxxxx',
|
|
41
|
+
endpoint: 'https://ingest.socwarden.io',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await sw.track('auth.login.success', { user_id: '42' });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Collected Context
|
|
48
|
+
|
|
49
|
+
| Field | Source |
|
|
50
|
+
|-------|--------|
|
|
51
|
+
| `timezone` | `Intl.DateTimeFormat().resolvedOptions().timeZone` |
|
|
52
|
+
| `language` | `navigator.language` |
|
|
53
|
+
| `platform` | `navigator.platform` |
|
|
54
|
+
| `screen` | `screen.width` x `screen.height` |
|
|
55
|
+
| `viewport` | `window.innerWidth` x `window.innerHeight` |
|
|
56
|
+
| `color_depth` | `screen.colorDepth` |
|
|
57
|
+
| `cookie_enabled` | `navigator.cookieEnabled` |
|
|
58
|
+
| `do_not_track` | `navigator.doNotTrack === '1'` |
|
|
59
|
+
| `connection_type` | `navigator.connection?.effectiveType` |
|
|
60
|
+
| `downlink` | `navigator.connection?.downlink` |
|
|
61
|
+
|
|
62
|
+
## Custom Header Name
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
const sw = new SOCWardenBrowser({
|
|
66
|
+
mode: 'relay',
|
|
67
|
+
headerName: 'X-My-Custom-Header',
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SOCWarden Browser SDK
|
|
3
|
+
*
|
|
4
|
+
* Lightweight client-side context collection (<3KB minified).
|
|
5
|
+
* Two modes:
|
|
6
|
+
* - relay: Collects context and injects it as X-SOCWarden-Context header
|
|
7
|
+
* on the app's own fetch/XHR requests. Server-side SDK merges it.
|
|
8
|
+
* - direct: Sends events straight to the SOCWarden ingestor (for SPAs).
|
|
9
|
+
*/
|
|
10
|
+
interface SOCWardenBrowserConfig {
|
|
11
|
+
/** Operating mode. */
|
|
12
|
+
mode: 'relay' | 'direct';
|
|
13
|
+
/** API key — required for direct mode. */
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
/** Ingestor endpoint URL — required for direct mode. */
|
|
16
|
+
endpoint?: string;
|
|
17
|
+
/** Header name used in relay mode. Default: X-SOCWarden-Context */
|
|
18
|
+
headerName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* D5 FIX (GDPR): Controls how much device data is collected.
|
|
21
|
+
*
|
|
22
|
+
* - 'none' — collect nothing (SDK is effectively disabled for context).
|
|
23
|
+
* - 'basic' — collect only page URL, referrer, browser language, viewport size.
|
|
24
|
+
* No fingerprinting data. **Default.**
|
|
25
|
+
* - 'full' — collect all data including WebGL GPU renderer, hardware
|
|
26
|
+
* concurrency, device memory, and screen resolution.
|
|
27
|
+
* Only use with explicit user consent.
|
|
28
|
+
*/
|
|
29
|
+
consentLevel?: 'none' | 'basic' | 'full';
|
|
30
|
+
}
|
|
31
|
+
interface ClientContext {
|
|
32
|
+
timezone: string;
|
|
33
|
+
language: string;
|
|
34
|
+
languages: string[];
|
|
35
|
+
touch: boolean;
|
|
36
|
+
platform: string;
|
|
37
|
+
screen: string;
|
|
38
|
+
viewport: string;
|
|
39
|
+
color_depth: number;
|
|
40
|
+
cookie_enabled: boolean;
|
|
41
|
+
do_not_track: boolean;
|
|
42
|
+
connection_type: string | undefined;
|
|
43
|
+
downlink: number | undefined;
|
|
44
|
+
gpu_renderer: string | undefined;
|
|
45
|
+
device_memory: number | undefined;
|
|
46
|
+
cpu_cores: number | undefined;
|
|
47
|
+
page_url: string;
|
|
48
|
+
page_referrer: string;
|
|
49
|
+
page_title: string;
|
|
50
|
+
}
|
|
51
|
+
declare class SOCWardenBrowser {
|
|
52
|
+
private readonly config;
|
|
53
|
+
private readonly headerName;
|
|
54
|
+
private ctx;
|
|
55
|
+
private encoded;
|
|
56
|
+
private _backedOff;
|
|
57
|
+
private _backoffTimer;
|
|
58
|
+
constructor(config: SOCWardenBrowserConfig);
|
|
59
|
+
/** Return the current client context snapshot (respects configured consentLevel). */
|
|
60
|
+
collectContext(): ClientContext;
|
|
61
|
+
/**
|
|
62
|
+
* Relay mode — monkey-patch `fetch` and `XMLHttpRequest` so that every
|
|
63
|
+
* outgoing request automatically carries the context header.
|
|
64
|
+
*/
|
|
65
|
+
installRelay(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Direct mode — POST an event to the SOCWarden ingestor.
|
|
68
|
+
* Never throws — errors are silently logged via console.warn.
|
|
69
|
+
*
|
|
70
|
+
* @param event Event type, e.g. "auth.login.success"
|
|
71
|
+
* @param metadata Arbitrary key-value metadata to attach
|
|
72
|
+
*/
|
|
73
|
+
track(event: string, metadata?: Record<string, any>): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { type ClientContext, SOCWardenBrowser, type SOCWardenBrowserConfig, SOCWardenBrowser as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SOCWarden Browser SDK
|
|
3
|
+
*
|
|
4
|
+
* Lightweight client-side context collection (<3KB minified).
|
|
5
|
+
* Two modes:
|
|
6
|
+
* - relay: Collects context and injects it as X-SOCWarden-Context header
|
|
7
|
+
* on the app's own fetch/XHR requests. Server-side SDK merges it.
|
|
8
|
+
* - direct: Sends events straight to the SOCWarden ingestor (for SPAs).
|
|
9
|
+
*/
|
|
10
|
+
interface SOCWardenBrowserConfig {
|
|
11
|
+
/** Operating mode. */
|
|
12
|
+
mode: 'relay' | 'direct';
|
|
13
|
+
/** API key — required for direct mode. */
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
/** Ingestor endpoint URL — required for direct mode. */
|
|
16
|
+
endpoint?: string;
|
|
17
|
+
/** Header name used in relay mode. Default: X-SOCWarden-Context */
|
|
18
|
+
headerName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* D5 FIX (GDPR): Controls how much device data is collected.
|
|
21
|
+
*
|
|
22
|
+
* - 'none' — collect nothing (SDK is effectively disabled for context).
|
|
23
|
+
* - 'basic' — collect only page URL, referrer, browser language, viewport size.
|
|
24
|
+
* No fingerprinting data. **Default.**
|
|
25
|
+
* - 'full' — collect all data including WebGL GPU renderer, hardware
|
|
26
|
+
* concurrency, device memory, and screen resolution.
|
|
27
|
+
* Only use with explicit user consent.
|
|
28
|
+
*/
|
|
29
|
+
consentLevel?: 'none' | 'basic' | 'full';
|
|
30
|
+
}
|
|
31
|
+
interface ClientContext {
|
|
32
|
+
timezone: string;
|
|
33
|
+
language: string;
|
|
34
|
+
languages: string[];
|
|
35
|
+
touch: boolean;
|
|
36
|
+
platform: string;
|
|
37
|
+
screen: string;
|
|
38
|
+
viewport: string;
|
|
39
|
+
color_depth: number;
|
|
40
|
+
cookie_enabled: boolean;
|
|
41
|
+
do_not_track: boolean;
|
|
42
|
+
connection_type: string | undefined;
|
|
43
|
+
downlink: number | undefined;
|
|
44
|
+
gpu_renderer: string | undefined;
|
|
45
|
+
device_memory: number | undefined;
|
|
46
|
+
cpu_cores: number | undefined;
|
|
47
|
+
page_url: string;
|
|
48
|
+
page_referrer: string;
|
|
49
|
+
page_title: string;
|
|
50
|
+
}
|
|
51
|
+
declare class SOCWardenBrowser {
|
|
52
|
+
private readonly config;
|
|
53
|
+
private readonly headerName;
|
|
54
|
+
private ctx;
|
|
55
|
+
private encoded;
|
|
56
|
+
private _backedOff;
|
|
57
|
+
private _backoffTimer;
|
|
58
|
+
constructor(config: SOCWardenBrowserConfig);
|
|
59
|
+
/** Return the current client context snapshot (respects configured consentLevel). */
|
|
60
|
+
collectContext(): ClientContext;
|
|
61
|
+
/**
|
|
62
|
+
* Relay mode — monkey-patch `fetch` and `XMLHttpRequest` so that every
|
|
63
|
+
* outgoing request automatically carries the context header.
|
|
64
|
+
*/
|
|
65
|
+
installRelay(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Direct mode — POST an event to the SOCWarden ingestor.
|
|
68
|
+
* Never throws — errors are silently logged via console.warn.
|
|
69
|
+
*
|
|
70
|
+
* @param event Event type, e.g. "auth.login.success"
|
|
71
|
+
* @param metadata Arbitrary key-value metadata to attach
|
|
72
|
+
*/
|
|
73
|
+
track(event: string, metadata?: Record<string, any>): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { type ClientContext, SOCWardenBrowser, type SOCWardenBrowserConfig, SOCWardenBrowser as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var u=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var _=(t,e)=>{for(var n in e)u(t,n,{get:e[n],enumerable:!0})},y=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of h(e))!m.call(t,o)&&o!==n&&u(t,o,{get:()=>e[o],enumerable:!(r=g(e,o))||r.enumerable});return t};var w=t=>y(u({},"__esModule",{value:!0}),t);var x={};_(x,{SOCWardenBrowser:()=>d,default:()=>k});module.exports=w(x);function v(){try{let t=document.createElement("canvas"),e=t.getContext("webgl")||t.getContext("experimental-webgl");if(e&&e instanceof WebGLRenderingContext){let n=e.getExtension("WEBGL_debug_renderer_info");if(n)return e.getParameter(n.UNMASKED_RENDERER_WEBGL)}}catch{}}var b=/^[a-z][a-z0-9]{0,29}(\.[a-z][a-z0-9_]{0,29}){1,3}$/;function C(t){try{let e=new URL(t),n=["token","key","password","secret","code","api_key","apikey","access_token","refresh_token"];for(let r of n)e.searchParams.has(r)&&e.searchParams.set(r,"[REDACTED]");return e.toString()}catch{return t}}function p(t="basic"){if(t==="none")return{timezone:"",language:"",languages:[],touch:!1,platform:"",screen:"",viewport:"",color_depth:0,cookie_enabled:!1,do_not_track:!1,connection_type:void 0,downlink:void 0,gpu_renderer:void 0,device_memory:void 0,cpu_cores:void 0,page_url:"",page_referrer:"",page_title:""};let e={timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,language:navigator.language,languages:Array.from(navigator.languages||[navigator.language]),touch:!1,platform:"",screen:"",viewport:`${window.innerWidth}x${window.innerHeight}`,color_depth:0,cookie_enabled:!1,do_not_track:navigator.doNotTrack==="1",connection_type:void 0,downlink:void 0,gpu_renderer:void 0,device_memory:void 0,cpu_cores:void 0,page_url:C(location.href),page_referrer:document.referrer,page_title:document.title};return t!=="full"?e:{...e,touch:navigator.maxTouchPoints>0,platform:navigator.platform,screen:`${screen.width}x${screen.height}`,color_depth:screen.colorDepth,cookie_enabled:navigator.cookieEnabled,connection_type:navigator.connection?.effectiveType,downlink:navigator.connection?.downlink,gpu_renderer:v(),device_memory:navigator.deviceMemory,cpu_cores:navigator.hardwareConcurrency}}function f(t){return btoa(JSON.stringify(t))}var d=class{constructor(e){this._backedOff=!1;this._backoffTimer=null;if(e.mode==="direct"){if(!e.apiKey)throw new Error("SOCWarden: apiKey is required in direct mode");if(!e.endpoint)throw new Error("SOCWarden: endpoint is required in direct mode");if(e.endpoint&&!e.endpoint.startsWith("https://")){if(!(e.endpoint.startsWith("http://localhost")||e.endpoint.startsWith("http://127.0.0.1")))throw new Error("SOCWarden: endpoint must use HTTPS. API keys must not be transmitted in cleartext.");console.warn("[SOCWarden] WARNING: Endpoint is using HTTP. API keys will be transmitted in cleartext.")}}this.config=e,this.headerName=e.headerName??"X-SOCWarden-Context",this.ctx=p(e.consentLevel??"basic"),this.encoded=f(this.ctx)}collectContext(){return this.ctx=p(this.config.consentLevel??"basic"),this.encoded=f(this.ctx),this.ctx}installRelay(){let e=this.headerName,n=()=>this.encoded,r=window.fetch;window.fetch=function(c,a){a=a??{};let l=new Headers(a.headers);return l.has(e)||l.set(e,n()),a.headers=l,r.call(window,c,a)};let o=XMLHttpRequest.prototype.open,i=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(...s){return this.__socwardenPatched=!1,o.apply(this,s)},XMLHttpRequest.prototype.send=function(...s){if(!this.__socwardenPatched){try{this.setRequestHeader(e,n())}catch{}this.__socwardenPatched=!0}return i.apply(this,s)}}async track(e,n){if(this.config.mode!=="direct"){console.warn("SOCWarden: track() is only available in direct mode");return}if(!b.test(e)){console.warn(`[SOCWarden] Invalid event type format, dropping event: "${e}". Event types must match ^[a-z][a-z0-9]{0,29}(\\.[a-z][a-z0-9_]{0,29}){1,3}$`);return}if(this._backedOff){console.warn("SOCWarden: rate-limited, skipping event");return}try{let r=this.config.endpoint.replace(/\/+$/,""),o={event:e,source:"browser",metadata:n??{},context:this.ctx,timestamp:new Date().toISOString()},i=await fetch(`${r}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify(o),keepalive:!0});if(i.status===429){this._backedOff=!0;let s=i.headers?.get?.("Retry-After"),c=60;if(s){let a=parseInt(s,10);!isNaN(a)&&a>0&&(c=Math.min(a,300))}this._backoffTimer=setTimeout(()=>{this._backedOff=!1,this._backoffTimer=null},c*1e3),console.warn(`SOCWarden: rate-limited, backing off for ${c}s`);return}if(!i.ok&&i.status!==202){console.warn(`SOCWarden: ingestor responded with ${i.status}`);return}}catch(r){console.warn("SOCWarden: failed to send event",r);return}}},k=d;0&&(module.exports={SOCWardenBrowser});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function f(){try{let t=document.createElement("canvas"),e=t.getContext("webgl")||t.getContext("experimental-webgl");if(e&&e instanceof WebGLRenderingContext){let n=e.getExtension("WEBGL_debug_renderer_info");if(n)return e.getParameter(n.UNMASKED_RENDERER_WEBGL)}}catch{}}var g=/^[a-z][a-z0-9]{0,29}(\.[a-z][a-z0-9_]{0,29}){1,3}$/;function h(t){try{let e=new URL(t),n=["token","key","password","secret","code","api_key","apikey","access_token","refresh_token"];for(let o of n)e.searchParams.has(o)&&e.searchParams.set(o,"[REDACTED]");return e.toString()}catch{return t}}function u(t="basic"){if(t==="none")return{timezone:"",language:"",languages:[],touch:!1,platform:"",screen:"",viewport:"",color_depth:0,cookie_enabled:!1,do_not_track:!1,connection_type:void 0,downlink:void 0,gpu_renderer:void 0,device_memory:void 0,cpu_cores:void 0,page_url:"",page_referrer:"",page_title:""};let e={timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,language:navigator.language,languages:Array.from(navigator.languages||[navigator.language]),touch:!1,platform:"",screen:"",viewport:`${window.innerWidth}x${window.innerHeight}`,color_depth:0,cookie_enabled:!1,do_not_track:navigator.doNotTrack==="1",connection_type:void 0,downlink:void 0,gpu_renderer:void 0,device_memory:void 0,cpu_cores:void 0,page_url:h(location.href),page_referrer:document.referrer,page_title:document.title};return t!=="full"?e:{...e,touch:navigator.maxTouchPoints>0,platform:navigator.platform,screen:`${screen.width}x${screen.height}`,color_depth:screen.colorDepth,cookie_enabled:navigator.cookieEnabled,connection_type:navigator.connection?.effectiveType,downlink:navigator.connection?.downlink,gpu_renderer:f(),device_memory:navigator.deviceMemory,cpu_cores:navigator.hardwareConcurrency}}function p(t){return btoa(JSON.stringify(t))}var l=class{constructor(e){this._backedOff=!1;this._backoffTimer=null;if(e.mode==="direct"){if(!e.apiKey)throw new Error("SOCWarden: apiKey is required in direct mode");if(!e.endpoint)throw new Error("SOCWarden: endpoint is required in direct mode");if(e.endpoint&&!e.endpoint.startsWith("https://")){if(!(e.endpoint.startsWith("http://localhost")||e.endpoint.startsWith("http://127.0.0.1")))throw new Error("SOCWarden: endpoint must use HTTPS. API keys must not be transmitted in cleartext.");console.warn("[SOCWarden] WARNING: Endpoint is using HTTP. API keys will be transmitted in cleartext.")}}this.config=e,this.headerName=e.headerName??"X-SOCWarden-Context",this.ctx=u(e.consentLevel??"basic"),this.encoded=p(this.ctx)}collectContext(){return this.ctx=u(this.config.consentLevel??"basic"),this.encoded=p(this.ctx),this.ctx}installRelay(){let e=this.headerName,n=()=>this.encoded,o=window.fetch;window.fetch=function(s,r){r=r??{};let d=new Headers(r.headers);return d.has(e)||d.set(e,n()),r.headers=d,o.call(window,s,r)};let c=XMLHttpRequest.prototype.open,a=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(...i){return this.__socwardenPatched=!1,c.apply(this,i)},XMLHttpRequest.prototype.send=function(...i){if(!this.__socwardenPatched){try{this.setRequestHeader(e,n())}catch{}this.__socwardenPatched=!0}return a.apply(this,i)}}async track(e,n){if(this.config.mode!=="direct"){console.warn("SOCWarden: track() is only available in direct mode");return}if(!g.test(e)){console.warn(`[SOCWarden] Invalid event type format, dropping event: "${e}". Event types must match ^[a-z][a-z0-9]{0,29}(\\.[a-z][a-z0-9_]{0,29}){1,3}$`);return}if(this._backedOff){console.warn("SOCWarden: rate-limited, skipping event");return}try{let o=this.config.endpoint.replace(/\/+$/,""),c={event:e,source:"browser",metadata:n??{},context:this.ctx,timestamp:new Date().toISOString()},a=await fetch(`${o}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify(c),keepalive:!0});if(a.status===429){this._backedOff=!0;let i=a.headers?.get?.("Retry-After"),s=60;if(i){let r=parseInt(i,10);!isNaN(r)&&r>0&&(s=Math.min(r,300))}this._backoffTimer=setTimeout(()=>{this._backedOff=!1,this._backoffTimer=null},s*1e3),console.warn(`SOCWarden: rate-limited, backing off for ${s}s`);return}if(!a.ok&&a.status!==202){console.warn(`SOCWarden: ingestor responded with ${a.status}`);return}}catch(o){console.warn("SOCWarden: failed to send event",o);return}}},m=l;export{l as SOCWardenBrowser,m as default};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@socwarden/browser",
|
|
3
|
+
"version": "1.0.0-alpha.1",
|
|
4
|
+
"description": "Lightweight browser SDK for SOCWarden client-side context collection",
|
|
5
|
+
"main": "dist/socwarden.min.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsup src/index.ts --format cjs,esm --minify --dts --global-name SOCWarden",
|
|
13
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
14
|
+
"test": "npx tsx --test src/__tests__/*.test.ts"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"socwarden",
|
|
18
|
+
"security",
|
|
19
|
+
"observability",
|
|
20
|
+
"browser",
|
|
21
|
+
"sdk"
|
|
22
|
+
],
|
|
23
|
+
"author": "SOCWarden",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"tsx": "^4.21.0",
|
|
28
|
+
"typescript": "^5.4.0"
|
|
29
|
+
}
|
|
30
|
+
}
|