@ihyeon/browser-error-log-protocol 0.1.15 → 0.1.17

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.ko.md CHANGED
@@ -10,7 +10,7 @@ Browser Error Log SDK·수집기·뷰어를 위한 버전이 있는 TypeScript
10
10
  npm install @ihyeon/browser-error-log-protocol
11
11
  ```
12
12
 
13
- 게시 패키지 대신 로컬 소스 tarball을 사용하려면 Node.js 24에서 `npm ci`, `npm run check:package`를 실행하고 `output/packages/ihyeon-browser-error-log-protocol-0.1.15.tgz`를 절대 경로로 설치합니다. [SDK 가이드](https://github.com/hyeonse-swing/browser-error-log/blob/main/docs/ko/personal-sdk.md)를 참고하세요.
13
+ 게시 패키지 대신 로컬 소스 tarball을 사용하려면 Node.js 24에서 `npm ci`, `npm run check:package`를 실행하고 `output/packages/ihyeon-browser-error-log-protocol-0.1.17.tgz`를 절대 경로로 설치합니다. [SDK 가이드](https://github.com/hyeonse-swing/browser-error-log/blob/main/docs/ko/personal-sdk.md)를 참고하세요.
14
14
 
15
15
  ## 이벤트·조회 계약
16
16
 
@@ -37,7 +37,9 @@ function makeBatch(events: ErrorEventRecord[]): EventBatch {
37
37
  - `EventDataSource`는 뷰어용 `listEvents(filter, signal?)`, `getEvent(project, eventId, signal?)`을 정의합니다.
38
38
  - `EVENT_LABELS`는 영어 표시 이름을 제공합니다. 이벤트 종류 식별자는 바뀌지 않습니다.
39
39
 
40
- 이 패키지는 타입과 상수를 제공하며 런타임 검증기·DB·HTTP 서버는 아닙니다. 수집기의 입력은 신뢰할 수 없는 데이터로 보고 검증하세요. 중복 제거와 조회는 `(project, eventId)`로 범위를 정합니다. 다른 프로젝트에서 같은 eventId를 사용할 수 있습니다. ISO 시각을 사용하고 클라이언트의 `occurredAt`과 서버의 `receivedAt`을 구분하세요.
40
+ `Breadcrumb`는 선택적인 `ErrorEventRecord.breadcrumbs` 타입입니다. `BREADCRUMB_LIMITS`와 `isBreadcrumbTrail(value)`는 최대 20개·UTF-8 JSON 12,000바이트, 표준 UTC `occurredAt`(`Date.toISOString()`), 비어 있지 않은 분류·메시지(40자·256자), 선택적인 단일 값 `data`(6개 키, 키 80자·문자열 값 200자)를 검증합니다. 알 수 없는 작업 필드, 중첩 데이터, 유한하지 않은 숫자는 거부하고 빈 배열은 허용합니다. 검증은 내용을 가리지 않으므로 SDK 필터나 앱의 서버 측 제거 정책을 함께 사용하세요.
41
+
42
+ 이 패키지는 전체 이벤트를 검증하거나 DB·HTTP 서버를 제공하지 않습니다. 수집기의 입력을 검증하고 중복 제거·조회는 `(project, eventId)`로 범위를 정하세요. 클라이언트의 `occurredAt`과 서버의 `receivedAt`을 구분합니다.
41
43
 
42
44
  [연동 계약](https://github.com/hyeonse-swing/browser-error-log/blob/main/docs/ko/integration.md)은 HTTP API를 설명합니다. `examples/micro-server`는 영속 SQLite 또는 로그 전용 JSONL 수집기를 구현합니다. 메모리 기반 개발 수집기는 데모입니다.
43
45
 
package/README.md CHANGED
@@ -10,7 +10,7 @@ Install directly when implementing your own collector or viewer; `@ihyeon/browse
10
10
  npm install @ihyeon/browser-error-log-protocol
11
11
  ```
12
12
 
13
- For local source-checkout development, use Node.js 24, `npm ci`, and `npm run check:package`, then install `output/packages/ihyeon-browser-error-log-protocol-0.1.15.tgz` by absolute path. See the [SDK guide](https://github.com/hyeonse-swing/browser-error-log/blob/main/docs/personal-sdk.md).
13
+ For local source-checkout development, use Node.js 24, `npm ci`, and `npm run check:package`, then install `output/packages/ihyeon-browser-error-log-protocol-0.1.17.tgz` by absolute path. See the [SDK guide](https://github.com/hyeonse-swing/browser-error-log/blob/main/docs/personal-sdk.md).
14
14
 
15
15
  ## Event and query contracts
16
16
 
@@ -37,7 +37,9 @@ function makeBatch(events: ErrorEventRecord[]): EventBatch {
37
37
  - `EventDataSource` exposes `listEvents(filter, signal?)` and `getEvent(project, eventId, signal?)` for the viewer.
38
38
  - `EVENT_LABELS` provides English display labels. The underlying event type identifiers stay unchanged.
39
39
 
40
- These are types and constants, not a runtime validator, database, or HTTP server. Treat all incoming data as untrusted and validate it at your collector. Scope deduplication and event lookup by `(project, eventId)`; different projects may use the same event ID. Use ISO timestamps and distinguish client-supplied `occurredAt` from server-owned `receivedAt`.
40
+ `Breadcrumb` describes optional `ErrorEventRecord.breadcrumbs`. `BREADCRUMB_LIMITS` and `isBreadcrumbTrail(value)` provide shared bounds and validation: at most 20 entries and 12,000 UTF-8 JSON bytes, canonical UTC `occurredAt` (`Date.toISOString()`), nonempty category/message (40/256 characters), and optional scalar `data` (six keys, key length 80, string length 200). Unknown breadcrumb properties, nested data, and non-finite numbers are rejected. Empty arrays are valid. Validation does not redact content; SDK filters or application-specific server controls handle removal.
41
+
42
+ The package does not validate complete events or provide a database or HTTP server. Validate incoming events at your collector. Deduplicate and look up by `(project, eventId)`; distinguish client-supplied `occurredAt` from server-owned `receivedAt`.
41
43
 
42
44
  The [integration contract](https://github.com/hyeonse-swing/browser-error-log/blob/main/docs/integration.md) describes the HTTP API; `examples/micro-server` implements a small self-hosted collector with persistent SQLite or log-only JSONL storage. The in-memory development collector is only a demo.
43
45
 
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var s=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var g=(r,e)=>{for(var n in e)s(r,n,{get:e[n],enumerable:!0})},p=(r,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of a(e))!c.call(r,t)&&t!==n&&s(r,t,{get:()=>e[t],enumerable:!(o=i(e,t))||o.enumerable});return r};var v=r=>p(s({},"__esModule",{value:!0}),r);var l={};g(l,{EVENT_LABELS:()=>u,SCHEMA_VERSION:()=>m,SDK_VERSION:()=>E});module.exports=v(l);var m=1,E="0.1.15",u={javascript:"JavaScript",promise:"Promise",react:"React",console:"Console",http:"HTTP error",network:"Network failure",manual:"Manual"};
1
+ "use strict";var a=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var u=(t,e)=>{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},m=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of c(e))!g.call(t,r)&&r!==n&&a(t,r,{get:()=>e[r],enumerable:!(o=i(e,r))||o.enumerable});return t};var p=t=>m(a({},"__esModule",{value:!0}),t);var b={};u(b,{BREADCRUMB_LIMITS:()=>s,EVENT_LABELS:()=>f,SCHEMA_VERSION:()=>d,SDK_VERSION:()=>l,isBreadcrumbTrail:()=>y});module.exports=p(b);var d=1,l="0.1.17",s={count:20,bytes:12e3,category:40,message:256,dataKeys:6,dataKey:80,dataString:200};function y(t){try{if(!Array.isArray(t)||t.length>s.count)return!1;for(let e of t){if(!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).some(n=>!["occurredAt","category","message","data"].includes(n))||typeof e.occurredAt!="string"||!Number.isFinite(Date.parse(e.occurredAt))||new Date(e.occurredAt).toISOString()!==e.occurredAt||typeof e.category!="string"||!e.category.trim()||e.category.length>s.category||typeof e.message!="string"||!e.message.trim()||e.message.length>s.message)return!1;if(e.data!==void 0){if(!e.data||typeof e.data!="object"||Array.isArray(e.data))return!1;let n=Object.entries(e.data);if(n.length>s.dataKeys||n.some(([o,r])=>o.length>s.dataKey||!(r===null||typeof r=="boolean"||typeof r=="string"&&r.length<=s.dataString||typeof r=="number"&&Number.isFinite(r))))return!1}}return new TextEncoder().encode(JSON.stringify(t)).length<=s.bytes}catch{return!1}}var f={javascript:"JavaScript",promise:"Promise",react:"React",console:"Console",http:"HTTP error",network:"Network failure",manual:"Manual"};
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["export const SCHEMA_VERSION = 1 as const;\nexport const SDK_VERSION = '0.1.15';\n\nexport type EventType = 'javascript' | 'promise' | 'react' | 'console' | 'http' | 'network' | 'manual';\nexport type Runtime = 'browser' | 'webview-ios' | 'webview-android' | 'unknown';\nexport interface ErrorEventRecord {\n schemaVersion: 1;\n eventId: string;\n project: string;\n environment: string;\n release: string;\n sdkVersion: string;\n occurredAt: string;\n receivedAt?: string;\n viewId: string;\n sequence: number;\n elapsedMs: number;\n type: EventType;\n message: string;\n name?: string;\n stack?: string;\n componentStack?: string;\n page: string;\n runtime: Runtime;\n browser?: string;\n context?: Record<string, string | number | boolean | null>;\n network?: { method: string; url: string; status?: number; durationMs: number };\n}\n\nexport interface EventBatch { schemaVersion: 1; events: ErrorEventRecord[] }\nexport interface EventFilter {\n project?: string;\n environment?: string;\n type?: EventType;\n query?: string;\n from?: string;\n to?: string;\n cursor?: string;\n limit?: number;\n}\nexport interface EventPage { events: ErrorEventRecord[]; nextCursor?: string }\nexport interface EventDataSource {\n listEvents(filter: EventFilter, signal?: AbortSignal): Promise<EventPage>;\n getEvent(project: string, eventId: string, signal?: AbortSignal): Promise<ErrorEventRecord | null>;\n}\n\nexport const EVENT_LABELS: Record<EventType, string> = {\n javascript: 'JavaScript', promise: 'Promise', react: 'React', console: 'Console',\n http: 'HTTP error', network: 'Network failure', manual: 'Manual',\n};\n"],
5
- "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,kBAAAE,EAAA,mBAAAC,EAAA,gBAAAC,IAAA,eAAAC,EAAAL,GAAO,IAAMG,EAAiB,EACjBC,EAAc,SA6CdF,EAA0C,CACrD,WAAY,aAAc,QAAS,UAAW,MAAO,QAAS,QAAS,UACvE,KAAM,aAAc,QAAS,kBAAmB,OAAQ,QAC1D",
6
- "names": ["index_exports", "__export", "EVENT_LABELS", "SCHEMA_VERSION", "SDK_VERSION", "__toCommonJS"]
4
+ "sourcesContent": ["export const SCHEMA_VERSION = 1 as const;\nexport const SDK_VERSION = '0.1.17';\n\nexport type EventType = 'javascript' | 'promise' | 'react' | 'console' | 'http' | 'network' | 'manual';\nexport type Runtime = 'browser' | 'webview-ios' | 'webview-android' | 'unknown';\n\nexport const BREADCRUMB_LIMITS = {\n count: 20, bytes: 12_000, category: 40, message: 256,\n dataKeys: 6, dataKey: 80, dataString: 200,\n} as const;\n\nexport interface Breadcrumb {\n occurredAt: string;\n category: string;\n message: string;\n data?: Record<string, string | number | boolean | null>;\n}\n\n/** Validates the bounded, canonical UTC breadcrumb representation on the wire. */\nexport function isBreadcrumbTrail(value: unknown): value is Breadcrumb[] {\n try {\n if (!Array.isArray(value) || value.length > BREADCRUMB_LIMITS.count) return false;\n for (const item of value) {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return false;\n if (Object.keys(item).some(key => !['occurredAt', 'category', 'message', 'data'].includes(key))) return false;\n if (typeof item.occurredAt !== 'string' || !Number.isFinite(Date.parse(item.occurredAt)) ||\n new Date(item.occurredAt).toISOString() !== item.occurredAt) return false;\n if (typeof item.category !== 'string' || !item.category.trim() || item.category.length > BREADCRUMB_LIMITS.category ||\n typeof item.message !== 'string' || !item.message.trim() || item.message.length > BREADCRUMB_LIMITS.message) return false;\n if (item.data !== undefined) {\n if (!item.data || typeof item.data !== 'object' || Array.isArray(item.data)) return false;\n const entries = Object.entries(item.data);\n if (entries.length > BREADCRUMB_LIMITS.dataKeys || entries.some(([key, field]) =>\n key.length > BREADCRUMB_LIMITS.dataKey || !(field === null || typeof field === 'boolean' ||\n (typeof field === 'string' && field.length <= BREADCRUMB_LIMITS.dataString) ||\n (typeof field === 'number' && Number.isFinite(field))))) return false;\n }\n }\n return new TextEncoder().encode(JSON.stringify(value)).length <= BREADCRUMB_LIMITS.bytes;\n } catch { return false; }\n}\n\nexport interface ErrorEventRecord {\n schemaVersion: 1;\n eventId: string;\n project: string;\n environment: string;\n release: string;\n sdkVersion: string;\n occurredAt: string;\n receivedAt?: string;\n viewId: string;\n sequence: number;\n elapsedMs: number;\n type: EventType;\n message: string;\n name?: string;\n stack?: string;\n componentStack?: string;\n page: string;\n runtime: Runtime;\n browser?: string;\n context?: Record<string, string | number | boolean | null>;\n breadcrumbs?: Breadcrumb[];\n network?: { method: string; url: string; status?: number; durationMs: number };\n}\n\nexport interface EventBatch { schemaVersion: 1; events: ErrorEventRecord[] }\nexport interface EventFilter {\n project?: string;\n environment?: string;\n type?: EventType;\n query?: string;\n from?: string;\n to?: string;\n cursor?: string;\n limit?: number;\n}\nexport interface EventPage { events: ErrorEventRecord[]; nextCursor?: string }\nexport interface EventDataSource {\n listEvents(filter: EventFilter, signal?: AbortSignal): Promise<EventPage>;\n getEvent(project: string, eventId: string, signal?: AbortSignal): Promise<ErrorEventRecord | null>;\n}\n\nexport const EVENT_LABELS: Record<EventType, string> = {\n javascript: 'JavaScript', promise: 'Promise', react: 'React', console: 'Console',\n http: 'HTTP error', network: 'Network failure', manual: 'Manual',\n};\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,uBAAAE,EAAA,iBAAAC,EAAA,mBAAAC,EAAA,gBAAAC,EAAA,sBAAAC,IAAA,eAAAC,EAAAP,GAAO,IAAMI,EAAiB,EACjBC,EAAc,SAKdH,EAAoB,CAC/B,MAAO,GAAI,MAAO,KAAQ,SAAU,GAAI,QAAS,IACjD,SAAU,EAAG,QAAS,GAAI,WAAY,GACxC,EAUO,SAASI,EAAkBE,EAAuC,CACvE,GAAI,CACF,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAASN,EAAkB,MAAO,MAAO,GAC5E,QAAWO,KAAQD,EAAO,CAKxB,GAJI,CAACC,GAAQ,OAAOA,GAAS,UAAY,MAAM,QAAQA,CAAI,GACvD,OAAO,KAAKA,CAAI,EAAE,KAAKC,GAAO,CAAC,CAAC,aAAc,WAAY,UAAW,MAAM,EAAE,SAASA,CAAG,CAAC,GAC1F,OAAOD,EAAK,YAAe,UAAY,CAAC,OAAO,SAAS,KAAK,MAAMA,EAAK,UAAU,CAAC,GACnF,IAAI,KAAKA,EAAK,UAAU,EAAE,YAAY,IAAMA,EAAK,YACjD,OAAOA,EAAK,UAAa,UAAY,CAACA,EAAK,SAAS,KAAK,GAAKA,EAAK,SAAS,OAASP,EAAkB,UACvG,OAAOO,EAAK,SAAY,UAAY,CAACA,EAAK,QAAQ,KAAK,GAAKA,EAAK,QAAQ,OAASP,EAAkB,QAAS,MAAO,GACxH,GAAIO,EAAK,OAAS,OAAW,CAC3B,GAAI,CAACA,EAAK,MAAQ,OAAOA,EAAK,MAAS,UAAY,MAAM,QAAQA,EAAK,IAAI,EAAG,MAAO,GACpF,IAAME,EAAU,OAAO,QAAQF,EAAK,IAAI,EACxC,GAAIE,EAAQ,OAAST,EAAkB,UAAYS,EAAQ,KAAK,CAAC,CAACD,EAAKE,CAAK,IAC1EF,EAAI,OAASR,EAAkB,SAAW,EAAEU,IAAU,MAAQ,OAAOA,GAAU,WAC5E,OAAOA,GAAU,UAAYA,EAAM,QAAUV,EAAkB,YAC/D,OAAOU,GAAU,UAAY,OAAO,SAASA,CAAK,EAAG,EAAG,MAAO,EACtE,CACF,CACA,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK,UAAUJ,CAAK,CAAC,EAAE,QAAUN,EAAkB,KACrF,MAAQ,CAAE,MAAO,EAAO,CAC1B,CA4CO,IAAMC,EAA0C,CACrD,WAAY,aAAc,QAAS,UAAW,MAAO,QAAS,QAAS,UACvE,KAAM,aAAc,QAAS,kBAAmB,OAAQ,QAC1D",
6
+ "names": ["index_exports", "__export", "BREADCRUMB_LIMITS", "EVENT_LABELS", "SCHEMA_VERSION", "SDK_VERSION", "isBreadcrumbTrail", "__toCommonJS", "value", "item", "key", "entries", "field"]
7
7
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,24 @@
1
1
  export declare const SCHEMA_VERSION: 1;
2
- export declare const SDK_VERSION = "0.1.15";
2
+ export declare const SDK_VERSION = "0.1.17";
3
3
  export type EventType = 'javascript' | 'promise' | 'react' | 'console' | 'http' | 'network' | 'manual';
4
4
  export type Runtime = 'browser' | 'webview-ios' | 'webview-android' | 'unknown';
5
+ export declare const BREADCRUMB_LIMITS: {
6
+ readonly count: 20;
7
+ readonly bytes: 12000;
8
+ readonly category: 40;
9
+ readonly message: 256;
10
+ readonly dataKeys: 6;
11
+ readonly dataKey: 80;
12
+ readonly dataString: 200;
13
+ };
14
+ export interface Breadcrumb {
15
+ occurredAt: string;
16
+ category: string;
17
+ message: string;
18
+ data?: Record<string, string | number | boolean | null>;
19
+ }
20
+ /** Validates the bounded, canonical UTC breadcrumb representation on the wire. */
21
+ export declare function isBreadcrumbTrail(value: unknown): value is Breadcrumb[];
5
22
  export interface ErrorEventRecord {
6
23
  schemaVersion: 1;
7
24
  eventId: string;
@@ -23,6 +40,7 @@ export interface ErrorEventRecord {
23
40
  runtime: Runtime;
24
41
  browser?: string;
25
42
  context?: Record<string, string | number | boolean | null>;
43
+ breadcrumbs?: Breadcrumb[];
26
44
  network?: {
27
45
  method: string;
28
46
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/protocol/src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,EAAG,CAAU,CAAC;AACzC,eAAO,MAAM,WAAW,WAAW,CAAC;AAEpC,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AACvG,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAChF,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;IAC3D,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAChF;AAED,MAAM,WAAW,UAAU;IAAG,aAAa,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAE;AAC5E,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,SAAS;IAAG,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AAC9E,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1E,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CACpG;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAGlD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/protocol/src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,EAAG,CAAU,CAAC;AACzC,eAAO,MAAM,WAAW,WAAW,CAAC;AAEpC,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AACvG,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAEhF,eAAO,MAAM,iBAAiB;aAC5B,KAAK,EAAE,EAAE;aAAE,KAAK,EAAE,KAAM;aAAE,QAAQ,EAAE,EAAE;aAAE,OAAO,EAAE,GAAG;aACpD,QAAQ,EAAE,CAAC;aAAE,OAAO,EAAE,EAAE;aAAE,UAAU,EAAE,GAAG;CACjC,CAAC;AAEX,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;CACzD;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,EAAE,CAqBvE;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;IAC3D,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAChF;AAED,MAAM,WAAW,UAAU;IAAG,aAAa,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAE;AAC5E,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,SAAS;IAAG,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AAC9E,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1E,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CACpG;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAGlD,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var e=1,r="0.1.15",t={javascript:"JavaScript",promise:"Promise",react:"React",console:"Console",http:"HTTP error",network:"Network failure",manual:"Manual"};export{t as EVENT_LABELS,e as SCHEMA_VERSION,r as SDK_VERSION};
1
+ var a=1,i="0.1.17",t={count:20,bytes:12e3,category:40,message:256,dataKeys:6,dataKey:80,dataString:200};function c(n){try{if(!Array.isArray(n)||n.length>t.count)return!1;for(let e of n){if(!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).some(s=>!["occurredAt","category","message","data"].includes(s))||typeof e.occurredAt!="string"||!Number.isFinite(Date.parse(e.occurredAt))||new Date(e.occurredAt).toISOString()!==e.occurredAt||typeof e.category!="string"||!e.category.trim()||e.category.length>t.category||typeof e.message!="string"||!e.message.trim()||e.message.length>t.message)return!1;if(e.data!==void 0){if(!e.data||typeof e.data!="object"||Array.isArray(e.data))return!1;let s=Object.entries(e.data);if(s.length>t.dataKeys||s.some(([o,r])=>o.length>t.dataKey||!(r===null||typeof r=="boolean"||typeof r=="string"&&r.length<=t.dataString||typeof r=="number"&&Number.isFinite(r))))return!1}}return new TextEncoder().encode(JSON.stringify(n)).length<=t.bytes}catch{return!1}}var g={javascript:"JavaScript",promise:"Promise",react:"React",console:"Console",http:"HTTP error",network:"Network failure",manual:"Manual"};export{t as BREADCRUMB_LIMITS,g as EVENT_LABELS,a as SCHEMA_VERSION,i as SDK_VERSION,c as isBreadcrumbTrail};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["export const SCHEMA_VERSION = 1 as const;\nexport const SDK_VERSION = '0.1.15';\n\nexport type EventType = 'javascript' | 'promise' | 'react' | 'console' | 'http' | 'network' | 'manual';\nexport type Runtime = 'browser' | 'webview-ios' | 'webview-android' | 'unknown';\nexport interface ErrorEventRecord {\n schemaVersion: 1;\n eventId: string;\n project: string;\n environment: string;\n release: string;\n sdkVersion: string;\n occurredAt: string;\n receivedAt?: string;\n viewId: string;\n sequence: number;\n elapsedMs: number;\n type: EventType;\n message: string;\n name?: string;\n stack?: string;\n componentStack?: string;\n page: string;\n runtime: Runtime;\n browser?: string;\n context?: Record<string, string | number | boolean | null>;\n network?: { method: string; url: string; status?: number; durationMs: number };\n}\n\nexport interface EventBatch { schemaVersion: 1; events: ErrorEventRecord[] }\nexport interface EventFilter {\n project?: string;\n environment?: string;\n type?: EventType;\n query?: string;\n from?: string;\n to?: string;\n cursor?: string;\n limit?: number;\n}\nexport interface EventPage { events: ErrorEventRecord[]; nextCursor?: string }\nexport interface EventDataSource {\n listEvents(filter: EventFilter, signal?: AbortSignal): Promise<EventPage>;\n getEvent(project: string, eventId: string, signal?: AbortSignal): Promise<ErrorEventRecord | null>;\n}\n\nexport const EVENT_LABELS: Record<EventType, string> = {\n javascript: 'JavaScript', promise: 'Promise', react: 'React', console: 'Console',\n http: 'HTTP error', network: 'Network failure', manual: 'Manual',\n};\n"],
5
- "mappings": "AAAO,IAAMA,EAAiB,EACjBC,EAAc,SA6CdC,EAA0C,CACrD,WAAY,aAAc,QAAS,UAAW,MAAO,QAAS,QAAS,UACvE,KAAM,aAAc,QAAS,kBAAmB,OAAQ,QAC1D",
6
- "names": ["SCHEMA_VERSION", "SDK_VERSION", "EVENT_LABELS"]
4
+ "sourcesContent": ["export const SCHEMA_VERSION = 1 as const;\nexport const SDK_VERSION = '0.1.17';\n\nexport type EventType = 'javascript' | 'promise' | 'react' | 'console' | 'http' | 'network' | 'manual';\nexport type Runtime = 'browser' | 'webview-ios' | 'webview-android' | 'unknown';\n\nexport const BREADCRUMB_LIMITS = {\n count: 20, bytes: 12_000, category: 40, message: 256,\n dataKeys: 6, dataKey: 80, dataString: 200,\n} as const;\n\nexport interface Breadcrumb {\n occurredAt: string;\n category: string;\n message: string;\n data?: Record<string, string | number | boolean | null>;\n}\n\n/** Validates the bounded, canonical UTC breadcrumb representation on the wire. */\nexport function isBreadcrumbTrail(value: unknown): value is Breadcrumb[] {\n try {\n if (!Array.isArray(value) || value.length > BREADCRUMB_LIMITS.count) return false;\n for (const item of value) {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return false;\n if (Object.keys(item).some(key => !['occurredAt', 'category', 'message', 'data'].includes(key))) return false;\n if (typeof item.occurredAt !== 'string' || !Number.isFinite(Date.parse(item.occurredAt)) ||\n new Date(item.occurredAt).toISOString() !== item.occurredAt) return false;\n if (typeof item.category !== 'string' || !item.category.trim() || item.category.length > BREADCRUMB_LIMITS.category ||\n typeof item.message !== 'string' || !item.message.trim() || item.message.length > BREADCRUMB_LIMITS.message) return false;\n if (item.data !== undefined) {\n if (!item.data || typeof item.data !== 'object' || Array.isArray(item.data)) return false;\n const entries = Object.entries(item.data);\n if (entries.length > BREADCRUMB_LIMITS.dataKeys || entries.some(([key, field]) =>\n key.length > BREADCRUMB_LIMITS.dataKey || !(field === null || typeof field === 'boolean' ||\n (typeof field === 'string' && field.length <= BREADCRUMB_LIMITS.dataString) ||\n (typeof field === 'number' && Number.isFinite(field))))) return false;\n }\n }\n return new TextEncoder().encode(JSON.stringify(value)).length <= BREADCRUMB_LIMITS.bytes;\n } catch { return false; }\n}\n\nexport interface ErrorEventRecord {\n schemaVersion: 1;\n eventId: string;\n project: string;\n environment: string;\n release: string;\n sdkVersion: string;\n occurredAt: string;\n receivedAt?: string;\n viewId: string;\n sequence: number;\n elapsedMs: number;\n type: EventType;\n message: string;\n name?: string;\n stack?: string;\n componentStack?: string;\n page: string;\n runtime: Runtime;\n browser?: string;\n context?: Record<string, string | number | boolean | null>;\n breadcrumbs?: Breadcrumb[];\n network?: { method: string; url: string; status?: number; durationMs: number };\n}\n\nexport interface EventBatch { schemaVersion: 1; events: ErrorEventRecord[] }\nexport interface EventFilter {\n project?: string;\n environment?: string;\n type?: EventType;\n query?: string;\n from?: string;\n to?: string;\n cursor?: string;\n limit?: number;\n}\nexport interface EventPage { events: ErrorEventRecord[]; nextCursor?: string }\nexport interface EventDataSource {\n listEvents(filter: EventFilter, signal?: AbortSignal): Promise<EventPage>;\n getEvent(project: string, eventId: string, signal?: AbortSignal): Promise<ErrorEventRecord | null>;\n}\n\nexport const EVENT_LABELS: Record<EventType, string> = {\n javascript: 'JavaScript', promise: 'Promise', react: 'React', console: 'Console',\n http: 'HTTP error', network: 'Network failure', manual: 'Manual',\n};\n"],
5
+ "mappings": "AAAO,IAAMA,EAAiB,EACjBC,EAAc,SAKdC,EAAoB,CAC/B,MAAO,GAAI,MAAO,KAAQ,SAAU,GAAI,QAAS,IACjD,SAAU,EAAG,QAAS,GAAI,WAAY,GACxC,EAUO,SAASC,EAAkBC,EAAuC,CACvE,GAAI,CACF,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAASF,EAAkB,MAAO,MAAO,GAC5E,QAAWG,KAAQD,EAAO,CAKxB,GAJI,CAACC,GAAQ,OAAOA,GAAS,UAAY,MAAM,QAAQA,CAAI,GACvD,OAAO,KAAKA,CAAI,EAAE,KAAKC,GAAO,CAAC,CAAC,aAAc,WAAY,UAAW,MAAM,EAAE,SAASA,CAAG,CAAC,GAC1F,OAAOD,EAAK,YAAe,UAAY,CAAC,OAAO,SAAS,KAAK,MAAMA,EAAK,UAAU,CAAC,GACnF,IAAI,KAAKA,EAAK,UAAU,EAAE,YAAY,IAAMA,EAAK,YACjD,OAAOA,EAAK,UAAa,UAAY,CAACA,EAAK,SAAS,KAAK,GAAKA,EAAK,SAAS,OAASH,EAAkB,UACvG,OAAOG,EAAK,SAAY,UAAY,CAACA,EAAK,QAAQ,KAAK,GAAKA,EAAK,QAAQ,OAASH,EAAkB,QAAS,MAAO,GACxH,GAAIG,EAAK,OAAS,OAAW,CAC3B,GAAI,CAACA,EAAK,MAAQ,OAAOA,EAAK,MAAS,UAAY,MAAM,QAAQA,EAAK,IAAI,EAAG,MAAO,GACpF,IAAME,EAAU,OAAO,QAAQF,EAAK,IAAI,EACxC,GAAIE,EAAQ,OAASL,EAAkB,UAAYK,EAAQ,KAAK,CAAC,CAACD,EAAKE,CAAK,IAC1EF,EAAI,OAASJ,EAAkB,SAAW,EAAEM,IAAU,MAAQ,OAAOA,GAAU,WAC5E,OAAOA,GAAU,UAAYA,EAAM,QAAUN,EAAkB,YAC/D,OAAOM,GAAU,UAAY,OAAO,SAASA,CAAK,EAAG,EAAG,MAAO,EACtE,CACF,CACA,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK,UAAUJ,CAAK,CAAC,EAAE,QAAUF,EAAkB,KACrF,MAAQ,CAAE,MAAO,EAAO,CAC1B,CA4CO,IAAMO,EAA0C,CACrD,WAAY,aAAc,QAAS,UAAW,MAAO,QAAS,QAAS,UACvE,KAAM,aAAc,QAAS,kBAAmB,OAAQ,QAC1D",
6
+ "names": ["SCHEMA_VERSION", "SDK_VERSION", "BREADCRUMB_LIMITS", "isBreadcrumbTrail", "value", "item", "key", "entries", "field", "EVENT_LABELS"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ihyeon/browser-error-log-protocol",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "Versioned event and query contracts for Browser Error Log collectors and viewers.",
5
5
  "keywords": [
6
6
  "error-monitoring",