@goliapkg/sentori-react-native 0.1.2 → 0.2.0

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.
@@ -18,4 +18,7 @@ Pod::Spec.new do |s|
18
18
  s.dependency 'ExpoModulesCore'
19
19
 
20
20
  s.source_files = 'ios/**/*.{h,m,mm,swift,hpp,cpp}'
21
+ # XCTest only links into test targets; including ios/Tests/** in the
22
+ # main pod target makes app builds fail with `no such module 'XCTest'`.
23
+ s.exclude_files = 'ios/Tests/**'
21
24
  end
@@ -1,8 +1,8 @@
1
1
  import type { Breadcrumb, BreadcrumbType } from './types';
2
2
  export type AddBreadcrumbInput = {
3
- type: BreadcrumbType;
4
3
  data: Record<string, unknown>;
5
4
  timestamp?: string;
5
+ type: BreadcrumbType;
6
6
  };
7
7
  export declare const addBreadcrumb: (input: AddBreadcrumbInput) => void;
8
8
  export declare const getBreadcrumbs: () => Breadcrumb[];
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAM1D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,kBAAkB,KAAG,IAUzD,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,UAAU,EAAkB,CAAC;AAE/D,eAAO,MAAM,gBAAgB,QAAO,IAEnC,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
1
+ {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,cAAc,CAAA;CACrB,CAAA;AAID,eAAO,MAAM,aAAa,GAAI,OAAO,kBAAkB,KAAG,IAWzD,CAAA;AAED,eAAO,MAAM,cAAc,QAAO,UAAU,EAAe,CAAA;AAE3D,eAAO,MAAM,gBAAgB,QAAO,IAGnC,CAAA;AAED,eAAO,MAAM,eAAe,QAAO,IAA0B,CAAA"}
@@ -1,21 +1,26 @@
1
- const MAX_BREADCRUMBS = 100;
2
- let _buffer = [];
1
+ // Phase 21: ring buffer logic lives in @goliapkg/sentori-core. The
2
+ // public surface here keeps its object-form `addBreadcrumb({ type,
3
+ // data, timestamp? })` so existing callers don't break, and we
4
+ // expose `__resetForTests` for the test suite.
5
+ import { BreadcrumbBuffer, clearBreadcrumbs as clearCore, getBreadcrumbs as getCore, addBreadcrumb as pushCore, } from '@goliapkg/sentori-core';
6
+ const _shadow = new BreadcrumbBuffer();
3
7
  export const addBreadcrumb = (input) => {
4
- const crumb = {
5
- timestamp: input.timestamp ?? new Date().toISOString(),
6
- type: input.type,
7
- data: input.data,
8
- };
9
- _buffer.push(crumb);
10
- if (_buffer.length > MAX_BREADCRUMBS) {
11
- _buffer.shift();
8
+ if (input.timestamp) {
9
+ // Caller wants a specific timestamp pushCore stamps `now()`, so
10
+ // we go through a private buffer to preserve that field. This path
11
+ // is rarely used (most callers omit timestamp).
12
+ _shadow.push(input.type, input.data);
13
+ const last = _shadow.snapshot().at(-1);
14
+ if (last)
15
+ last.timestamp = input.timestamp;
16
+ return;
12
17
  }
18
+ pushCore(input.type, input.data);
13
19
  };
14
- export const getBreadcrumbs = () => [..._buffer];
20
+ export const getBreadcrumbs = () => getCore();
15
21
  export const clearBreadcrumbs = () => {
16
- _buffer = [];
17
- };
18
- export const __resetForTests = () => {
19
- _buffer = [];
22
+ clearCore();
23
+ _shadow.clear();
20
24
  };
25
+ export const __resetForTests = () => clearBreadcrumbs();
21
26
  //# sourceMappingURL=breadcrumbs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumbs.js","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,IAAI,OAAO,GAAiB,EAAE,CAAC;AAQ/B,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAyB,EAAQ,EAAE;IAC/D,MAAM,KAAK,GAAe;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACtD,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,IAAI,OAAO,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAiB,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;AAE/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAS,EAAE;IACzC,OAAO,GAAG,EAAE,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAS,EAAE;IACxC,OAAO,GAAG,EAAE,CAAC;AACf,CAAC,CAAC"}
1
+ {"version":3,"file":"breadcrumbs.js","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,mEAAmE;AACnE,+DAA+D;AAC/D,+CAA+C;AAC/C,OAAO,EACL,gBAAgB,EAChB,gBAAgB,IAAI,SAAS,EAC7B,cAAc,IAAI,OAAO,EACzB,aAAa,IAAI,QAAQ,GAC1B,MAAM,wBAAwB,CAAA;AAU/B,MAAM,OAAO,GAAG,IAAI,gBAAgB,EAAE,CAAA;AAEtC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAyB,EAAQ,EAAE;IAC/D,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,kEAAkE;QAClE,mEAAmE;QACnE,gDAAgD;QAChD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACtC,IAAI,IAAI;YAAE,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAA;QAC1C,OAAM;IACR,CAAC;IACD,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;AAClC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,GAAiB,EAAE,CAAC,OAAO,EAAE,CAAA;AAE3D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAS,EAAE;IACzC,SAAS,EAAE,CAAA;IACX,OAAO,CAAC,KAAK,EAAE,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,GAAS,EAAE,CAAC,gBAAgB,EAAE,CAAA"}
package/lib/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import { ErrorBoundary } from './error-boundary';
2
2
  export declare const sentori: {
3
3
  init: (options: import("./init").InitOptions) => void;
4
4
  addBreadcrumb: (input: import("./breadcrumbs").AddBreadcrumbInput) => void;
5
- setUser: (user: import("./types").User | null) => void;
6
- getUser: () => import("./types").User | null;
5
+ setUser: (user: import("@goliapkg/sentori-core").User | null) => void;
6
+ getUser: () => import("@goliapkg/sentori-core").User | null;
7
7
  captureError: (error: Error, extras?: import("./capture").CaptureExtras) => void;
8
8
  captureException: (error: Error, extras?: import("./capture").CaptureExtras) => void;
9
9
  ErrorBoundary: typeof ErrorBoundary;
@@ -1 +1 @@
1
- {"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAWrC,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,KAAK,EAgB3D,CAAC"}
1
+ {"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,KAAK,EACrC,CAAA"}
package/lib/stack.js CHANGED
@@ -1,69 +1,7 @@
1
- // V8 / Hermes (RN 0.71+):
2
- // " at functionName (file:line:col)"
3
- // " at file:line:col"
4
- const V8_FRAME = /^\s*at\s+(?:(.+?)\s+\()?(.+?)(?::(\d+))?(?::(\d+))?\)?\s*$/;
5
- // SpiderMonkey / older Hermes:
6
- // "functionName@file:line:col"
7
- const AT_FRAME = /^(.+?)@(.+?)(?::(\d+))?(?::(\d+))?$/;
8
- export const parseStack = (stack) => {
9
- if (!stack || typeof stack !== 'string')
10
- return [];
11
- const lines = stack.split('\n');
12
- const frames = [];
13
- for (const raw of lines) {
14
- const line = raw.trim();
15
- if (!line)
16
- continue;
17
- // Skip the "ErrorType: message" header line.
18
- if (!line.startsWith('at ') && !line.includes('@'))
19
- continue;
20
- const frame = parseV8(line) ?? parseAt(line);
21
- if (frame)
22
- frames.push(frame);
23
- }
24
- return frames;
25
- };
26
- const parseV8 = (line) => {
27
- if (!line.startsWith('at '))
28
- return null;
29
- const m = V8_FRAME.exec(line);
30
- if (!m)
31
- return null;
32
- const fn = m[1] ? m[1].trim() : undefined;
33
- const file = m[2] ? m[2].trim() : '<anonymous>';
34
- const lineNo = m[3] ? parseInt(m[3], 10) : 0;
35
- const col = m[4] ? parseInt(m[4], 10) : undefined;
36
- return {
37
- function: fn,
38
- file,
39
- line: lineNo,
40
- column: col,
41
- inApp: isInApp(file),
42
- };
43
- };
44
- const parseAt = (line) => {
45
- const m = AT_FRAME.exec(line);
46
- if (!m)
47
- return null;
48
- const fn = m[1] ? m[1].trim() : undefined;
49
- const file = m[2] ? m[2].trim() : '<anonymous>';
50
- const lineNo = m[3] ? parseInt(m[3], 10) : 0;
51
- const col = m[4] ? parseInt(m[4], 10) : undefined;
52
- return {
53
- function: fn,
54
- file,
55
- line: lineNo,
56
- column: col,
57
- inApp: isInApp(file),
58
- };
59
- };
60
- const isInApp = (file) => {
61
- if (!file || file === '<anonymous>')
62
- return false;
63
- if (file.includes('node_modules/'))
64
- return false;
65
- if (/^https?:\/\//.test(file))
66
- return false;
67
- return true;
68
- };
1
+ // Phase 21: regex + parse loop moved to @goliapkg/sentori-core.
2
+ // RN keeps the long path (no shortFilenames option) because Hermes
3
+ // paths are already short and native symbolication needs the
4
+ // absolute form.
5
+ import { parseStack as parseStackCore } from '@goliapkg/sentori-core';
6
+ export const parseStack = (stack) => parseStackCore(stack);
69
7
  //# sourceMappingURL=stack.js.map
package/lib/stack.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"stack.js","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stack.js","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,mEAAmE;AACnE,6DAA6D;AAC7D,iBAAiB;AACjB,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAIrE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAyB,EAAW,EAAE,CAC/D,cAAc,CAAC,KAAK,CAAC,CAAA"}
package/lib/types.d.ts CHANGED
@@ -1,62 +1,2 @@
1
- export type Platform = 'javascript' | 'ios' | 'android';
2
- export type DeviceOS = 'ios' | 'android' | 'web' | 'other';
3
- export type EventKind = 'error';
4
- export type BreadcrumbType = 'nav' | 'net' | 'log' | 'user' | 'custom';
5
- export type Event = {
6
- id: string;
7
- timestamp: string;
8
- kind: EventKind;
9
- platform: Platform;
10
- release: string;
11
- environment: string;
12
- device: Device;
13
- app: App;
14
- user?: User | null;
15
- tags?: Tags;
16
- breadcrumbs?: Breadcrumb[];
17
- error: SentoriError;
18
- fingerprint?: string[];
19
- traceId?: string | null;
20
- spanId?: string | null;
21
- };
22
- export type Device = {
23
- os: DeviceOS;
24
- osVersion: string;
25
- model?: string;
26
- locale?: string;
27
- };
28
- export type App = {
29
- version: string;
30
- build?: string;
31
- framework?: {
32
- name: string;
33
- version: string;
34
- };
35
- };
36
- export type User = {
37
- id?: string;
38
- anonymous?: boolean;
39
- };
40
- export type Tags = Record<string, string>;
41
- export type SentoriError = {
42
- type: string;
43
- message: string;
44
- stack: Frame[];
45
- cause?: SentoriError | null;
46
- };
47
- export type Frame = {
48
- function?: string;
49
- file: string;
50
- line: number;
51
- column?: number;
52
- inApp: boolean;
53
- absolutePath?: string;
54
- preContext?: string[];
55
- postContext?: string[];
56
- };
57
- export type Breadcrumb = {
58
- timestamp: string;
59
- type: BreadcrumbType;
60
- data: Record<string, unknown>;
61
- };
1
+ export type { App, Breadcrumb, BreadcrumbType, CaptureExtras, Device, DeviceOS, Event, EventKind, Frame, Platform, SentoriError, Tags, User, } from '@goliapkg/sentori-core';
62
2
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,KAAK,GAAG,SAAS,CAAC;AACxD,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,OAAO,CAAC;AAC3D,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC;AAChC,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvE,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,KAAK,EAAE,YAAY,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,EAAE,EAAE,QAAQ,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE1C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,GAAG,EACH,UAAU,EACV,cAAc,EACd,aAAa,EACb,MAAM,EACN,QAAQ,EACR,KAAK,EACL,SAAS,EACT,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,IAAI,EACJ,IAAI,GACL,MAAM,wBAAwB,CAAA"}
package/lib/types.js CHANGED
@@ -1,2 +1,4 @@
1
+ // Phase 21: wire-format types moved to @goliapkg/sentori-core. Re-
2
+ // exported here so existing relative imports keep working.
1
3
  export {};
2
4
  //# sourceMappingURL=types.js.map
package/lib/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,2DAA2D"}
package/lib/uuid.d.ts CHANGED
@@ -1,11 +1,2 @@
1
- /**
2
- * RFC 9562 UUID v7 generator.
3
- * Layout:
4
- * bytes 0-5 (48 bits) — Unix epoch milliseconds, big-endian
5
- * byte 6 (high nibble) — version 7 (0x70)
6
- * byte 6 (low nibble) + byte 7 — 12 random bits
7
- * byte 8 (high 2 bits) — variant 10
8
- * byte 8 (low 6 bits) + bytes 9-15 — 62 random bits
9
- */
10
- export declare const uuidV7: () => string;
1
+ export { uuidV7 } from '@goliapkg/sentori-core';
11
2
  //# sourceMappingURL=uuid.d.ts.map
package/lib/uuid.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../src/uuid.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,QAAO,MA4BzB,CAAC"}
1
+ {"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../src/uuid.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA"}
package/lib/uuid.js CHANGED
@@ -1,46 +1,3 @@
1
- /**
2
- * RFC 9562 UUID v7 generator.
3
- * Layout:
4
- * bytes 0-5 (48 bits) — Unix epoch milliseconds, big-endian
5
- * byte 6 (high nibble) — version 7 (0x70)
6
- * byte 6 (low nibble) + byte 7 — 12 random bits
7
- * byte 8 (high 2 bits) — variant 10
8
- * byte 8 (low 6 bits) + bytes 9-15 — 62 random bits
9
- */
10
- export const uuidV7 = () => {
11
- const ts = Date.now();
12
- const buf = new Uint8Array(16);
13
- buf[0] = Math.floor(ts / 0x10000000000) & 0xff;
14
- buf[1] = Math.floor(ts / 0x100000000) & 0xff;
15
- buf[2] = Math.floor(ts / 0x1000000) & 0xff;
16
- buf[3] = Math.floor(ts / 0x10000) & 0xff;
17
- buf[4] = Math.floor(ts / 0x100) & 0xff;
18
- buf[5] = ts & 0xff;
19
- fillRandom(buf.subarray(6));
20
- buf[6] = (buf[6] & 0x0f) | 0x70; // version 7
21
- buf[8] = (buf[8] & 0x3f) | 0x80; // variant 10xx
22
- const hex = Array.from(buf, (b) => b.toString(16).padStart(2, '0')).join('');
23
- return (hex.slice(0, 8) +
24
- '-' +
25
- hex.slice(8, 12) +
26
- '-' +
27
- hex.slice(12, 16) +
28
- '-' +
29
- hex.slice(16, 20) +
30
- '-' +
31
- hex.slice(20, 32));
32
- };
33
- const fillRandom = (buf) => {
34
- // Prefer crypto.getRandomValues (Hermes 0.74+, browsers, Node, Bun).
35
- // RN apps targeting older Hermes should add `react-native-get-random-values`
36
- // before importing the SDK.
37
- const cryptoObj = globalThis.crypto;
38
- if (cryptoObj && typeof cryptoObj.getRandomValues === 'function') {
39
- cryptoObj.getRandomValues(buf);
40
- return;
41
- }
42
- for (let i = 0; i < buf.length; i++) {
43
- buf[i] = Math.floor(Math.random() * 256);
44
- }
45
- };
1
+ // Phase 21: moved to @goliapkg/sentori-core.
2
+ export { uuidV7 } from '@goliapkg/sentori-core';
46
3
  //# sourceMappingURL=uuid.js.map
package/lib/uuid.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"uuid.js","sourceRoot":"","sources":["../src/uuid.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,GAAW,EAAE;IACjC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAE/B,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,aAAa,CAAC,GAAG,IAAI,CAAC;IAC/C,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC;IAC7C,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;IAC3C,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC;IACvC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IAEnB,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5B,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,YAAY;IAC9C,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,eAAe;IAEjD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7E,OAAO,CACL,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACf,GAAG;QACH,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChB,GAAG;QACH,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACjB,GAAG;QACH,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACjB,GAAG;QACH,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAClB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,GAAe,EAAQ,EAAE;IAC3C,qEAAqE;IACrE,6EAA6E;IAC7E,4BAA4B;IAC5B,MAAM,SAAS,GACb,UAGD,CAAC,MAAM,CAAC;IACT,IAAI,SAAS,IAAI,OAAO,SAAS,CAAC,eAAe,KAAK,UAAU,EAAE,CAAC;QACjE,SAAS,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO;IACT,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"uuid.js","sourceRoot":"","sources":["../src/uuid.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@goliapkg/sentori-react-native",
3
- "version": "0.1.2",
4
- "description": "Sentori SDK for React Native JS-layer error capture, native crash handlers (iOS / Android), batched transport.",
3
+ "version": "0.2.0",
4
+ "description": "Sentori SDK for React Native \u2014 JS-layer error capture, native crash handlers (iOS / Android), batched transport.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://sentori.golia.jp",
7
7
  "repository": {
@@ -62,5 +62,8 @@
62
62
  },
63
63
  "publishConfig": {
64
64
  "access": "public"
65
+ },
66
+ "dependencies": {
67
+ "@goliapkg/sentori-core": "0.1.0"
65
68
  }
66
69
  }
@@ -17,12 +17,14 @@ describe('parseStack', () => {
17
17
  at onPress (src/components/Button.tsx:15:5)`;
18
18
  const frames = parseStack(stack);
19
19
  expect(frames).toHaveLength(2);
20
- expect(frames[0]).toEqual({
21
- function: 'handleSubmit',
22
- file: 'src/screens/Checkout.tsx',
23
- line: 42,
20
+ // Phase 21: core's parseStack also populates absolutePath, so we
21
+ // match the subset of fields rather than full equality.
22
+ expect(frames[0]).toMatchObject({
24
23
  column: 10,
24
+ file: 'src/screens/Checkout.tsx',
25
+ function: 'handleSubmit',
25
26
  inApp: true,
27
+ line: 42,
26
28
  });
27
29
  expect(frames[1]?.function).toBe('onPress');
28
30
  });
@@ -1,33 +1,42 @@
1
- import type { Breadcrumb, BreadcrumbType } from './types';
1
+ // Phase 21: ring buffer logic lives in @goliapkg/sentori-core. The
2
+ // public surface here keeps its object-form `addBreadcrumb({ type,
3
+ // data, timestamp? })` so existing callers don't break, and we
4
+ // expose `__resetForTests` for the test suite.
5
+ import {
6
+ BreadcrumbBuffer,
7
+ clearBreadcrumbs as clearCore,
8
+ getBreadcrumbs as getCore,
9
+ addBreadcrumb as pushCore,
10
+ } from '@goliapkg/sentori-core'
2
11
 
3
- const MAX_BREADCRUMBS = 100;
4
-
5
- let _buffer: Breadcrumb[] = [];
12
+ import type { Breadcrumb, BreadcrumbType } from './types'
6
13
 
7
14
  export type AddBreadcrumbInput = {
8
- type: BreadcrumbType;
9
- data: Record<string, unknown>;
10
- timestamp?: string;
11
- };
15
+ data: Record<string, unknown>
16
+ timestamp?: string
17
+ type: BreadcrumbType
18
+ }
19
+
20
+ const _shadow = new BreadcrumbBuffer()
12
21
 
13
22
  export const addBreadcrumb = (input: AddBreadcrumbInput): void => {
14
- const crumb: Breadcrumb = {
15
- timestamp: input.timestamp ?? new Date().toISOString(),
16
- type: input.type,
17
- data: input.data,
18
- };
19
- _buffer.push(crumb);
20
- if (_buffer.length > MAX_BREADCRUMBS) {
21
- _buffer.shift();
23
+ if (input.timestamp) {
24
+ // Caller wants a specific timestamp pushCore stamps `now()`, so
25
+ // we go through a private buffer to preserve that field. This path
26
+ // is rarely used (most callers omit timestamp).
27
+ _shadow.push(input.type, input.data)
28
+ const last = _shadow.snapshot().at(-1)
29
+ if (last) last.timestamp = input.timestamp
30
+ return
22
31
  }
23
- };
32
+ pushCore(input.type, input.data)
33
+ }
24
34
 
25
- export const getBreadcrumbs = (): Breadcrumb[] => [..._buffer];
35
+ export const getBreadcrumbs = (): Breadcrumb[] => getCore()
26
36
 
27
37
  export const clearBreadcrumbs = (): void => {
28
- _buffer = [];
29
- };
38
+ clearCore()
39
+ _shadow.clear()
40
+ }
30
41
 
31
- export const __resetForTests = (): void => {
32
- _buffer = [];
33
- };
42
+ export const __resetForTests = (): void => clearBreadcrumbs()
package/src/stack.ts CHANGED
@@ -1,72 +1,10 @@
1
- import type { Frame } from './types';
1
+ // Phase 21: regex + parse loop moved to @goliapkg/sentori-core.
2
+ // RN keeps the long path (no shortFilenames option) because Hermes
3
+ // paths are already short and native symbolication needs the
4
+ // absolute form.
5
+ import { parseStack as parseStackCore } from '@goliapkg/sentori-core'
2
6
 
3
- // V8 / Hermes (RN 0.71+):
4
- // " at functionName (file:line:col)"
5
- // " at file:line:col"
6
- const V8_FRAME = /^\s*at\s+(?:(.+?)\s+\()?(.+?)(?::(\d+))?(?::(\d+))?\)?\s*$/;
7
+ import type { Frame } from './types'
7
8
 
8
- // SpiderMonkey / older Hermes:
9
- // "functionName@file:line:col"
10
- const AT_FRAME = /^(.+?)@(.+?)(?::(\d+))?(?::(\d+))?$/;
11
-
12
- export const parseStack = (stack: string | undefined): Frame[] => {
13
- if (!stack || typeof stack !== 'string') return [];
14
- const lines = stack.split('\n');
15
- const frames: Frame[] = [];
16
-
17
- for (const raw of lines) {
18
- const line = raw.trim();
19
- if (!line) continue;
20
- // Skip the "ErrorType: message" header line.
21
- if (!line.startsWith('at ') && !line.includes('@')) continue;
22
-
23
- const frame = parseV8(line) ?? parseAt(line);
24
- if (frame) frames.push(frame);
25
- }
26
-
27
- return frames;
28
- };
29
-
30
- const parseV8 = (line: string): Frame | null => {
31
- if (!line.startsWith('at ')) return null;
32
- const m = V8_FRAME.exec(line);
33
- if (!m) return null;
34
-
35
- const fn = m[1] ? m[1].trim() : undefined;
36
- const file = m[2] ? m[2].trim() : '<anonymous>';
37
- const lineNo = m[3] ? parseInt(m[3], 10) : 0;
38
- const col = m[4] ? parseInt(m[4], 10) : undefined;
39
-
40
- return {
41
- function: fn,
42
- file,
43
- line: lineNo,
44
- column: col,
45
- inApp: isInApp(file),
46
- };
47
- };
48
-
49
- const parseAt = (line: string): Frame | null => {
50
- const m = AT_FRAME.exec(line);
51
- if (!m) return null;
52
-
53
- const fn = m[1] ? m[1].trim() : undefined;
54
- const file = m[2] ? m[2].trim() : '<anonymous>';
55
- const lineNo = m[3] ? parseInt(m[3], 10) : 0;
56
- const col = m[4] ? parseInt(m[4], 10) : undefined;
57
-
58
- return {
59
- function: fn,
60
- file,
61
- line: lineNo,
62
- column: col,
63
- inApp: isInApp(file),
64
- };
65
- };
66
-
67
- const isInApp = (file: string): boolean => {
68
- if (!file || file === '<anonymous>') return false;
69
- if (file.includes('node_modules/')) return false;
70
- if (/^https?:\/\//.test(file)) return false;
71
- return true;
72
- };
9
+ export const parseStack = (stack: string | undefined): Frame[] =>
10
+ parseStackCore(stack)
package/src/types.ts CHANGED
@@ -1,63 +1,18 @@
1
- export type Platform = 'javascript' | 'ios' | 'android';
2
- export type DeviceOS = 'ios' | 'android' | 'web' | 'other';
3
- export type EventKind = 'error';
4
- export type BreadcrumbType = 'nav' | 'net' | 'log' | 'user' | 'custom';
5
-
6
- export type Event = {
7
- id: string;
8
- timestamp: string;
9
- kind: EventKind;
10
- platform: Platform;
11
- release: string;
12
- environment: string;
13
- device: Device;
14
- app: App;
15
- user?: User | null;
16
- tags?: Tags;
17
- breadcrumbs?: Breadcrumb[];
18
- error: SentoriError;
19
- fingerprint?: string[];
20
- traceId?: string | null;
21
- spanId?: string | null;
22
- };
23
-
24
- export type Device = {
25
- os: DeviceOS;
26
- osVersion: string;
27
- model?: string;
28
- locale?: string;
29
- };
30
-
31
- export type App = {
32
- version: string;
33
- build?: string;
34
- framework?: { name: string; version: string };
35
- };
36
-
37
- export type User = { id?: string; anonymous?: boolean };
38
-
39
- export type Tags = Record<string, string>;
40
-
41
- export type SentoriError = {
42
- type: string;
43
- message: string;
44
- stack: Frame[];
45
- cause?: SentoriError | null;
46
- };
47
-
48
- export type Frame = {
49
- function?: string;
50
- file: string;
51
- line: number;
52
- column?: number;
53
- inApp: boolean;
54
- absolutePath?: string;
55
- preContext?: string[];
56
- postContext?: string[];
57
- };
58
-
59
- export type Breadcrumb = {
60
- timestamp: string;
61
- type: BreadcrumbType;
62
- data: Record<string, unknown>;
63
- };
1
+ // Phase 21: wire-format types moved to @goliapkg/sentori-core. Re-
2
+ // exported here so existing relative imports keep working.
3
+
4
+ export type {
5
+ App,
6
+ Breadcrumb,
7
+ BreadcrumbType,
8
+ CaptureExtras,
9
+ Device,
10
+ DeviceOS,
11
+ Event,
12
+ EventKind,
13
+ Frame,
14
+ Platform,
15
+ SentoriError,
16
+ Tags,
17
+ User,
18
+ } from '@goliapkg/sentori-core'
package/src/uuid.ts CHANGED
@@ -1,56 +1,2 @@
1
- /**
2
- * RFC 9562 UUID v7 generator.
3
- * Layout:
4
- * bytes 0-5 (48 bits) — Unix epoch milliseconds, big-endian
5
- * byte 6 (high nibble) — version 7 (0x70)
6
- * byte 6 (low nibble) + byte 7 — 12 random bits
7
- * byte 8 (high 2 bits) — variant 10
8
- * byte 8 (low 6 bits) + bytes 9-15 — 62 random bits
9
- */
10
- export const uuidV7 = (): string => {
11
- const ts = Date.now();
12
- const buf = new Uint8Array(16);
13
-
14
- buf[0] = Math.floor(ts / 0x10000000000) & 0xff;
15
- buf[1] = Math.floor(ts / 0x100000000) & 0xff;
16
- buf[2] = Math.floor(ts / 0x1000000) & 0xff;
17
- buf[3] = Math.floor(ts / 0x10000) & 0xff;
18
- buf[4] = Math.floor(ts / 0x100) & 0xff;
19
- buf[5] = ts & 0xff;
20
-
21
- fillRandom(buf.subarray(6));
22
-
23
- buf[6] = (buf[6]! & 0x0f) | 0x70; // version 7
24
- buf[8] = (buf[8]! & 0x3f) | 0x80; // variant 10xx
25
-
26
- const hex = Array.from(buf, (b) => b.toString(16).padStart(2, '0')).join('');
27
- return (
28
- hex.slice(0, 8) +
29
- '-' +
30
- hex.slice(8, 12) +
31
- '-' +
32
- hex.slice(12, 16) +
33
- '-' +
34
- hex.slice(16, 20) +
35
- '-' +
36
- hex.slice(20, 32)
37
- );
38
- };
39
-
40
- const fillRandom = (buf: Uint8Array): void => {
41
- // Prefer crypto.getRandomValues (Hermes 0.74+, browsers, Node, Bun).
42
- // RN apps targeting older Hermes should add `react-native-get-random-values`
43
- // before importing the SDK.
44
- const cryptoObj = (
45
- globalThis as {
46
- crypto?: { getRandomValues?: (b: Uint8Array) => Uint8Array };
47
- }
48
- ).crypto;
49
- if (cryptoObj && typeof cryptoObj.getRandomValues === 'function') {
50
- cryptoObj.getRandomValues(buf);
51
- return;
52
- }
53
- for (let i = 0; i < buf.length; i++) {
54
- buf[i] = Math.floor(Math.random() * 256);
55
- }
56
- };
1
+ // Phase 21: moved to @goliapkg/sentori-core.
2
+ export { uuidV7 } from '@goliapkg/sentori-core'