@drakkar.software/sunglasses-core 0.8.0 → 0.10.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.
package/dist/index.d.mts CHANGED
@@ -55,6 +55,39 @@ interface IMiddleware {
55
55
  process(event: SunglassesEvent, next: MiddlewareNext): Promise<SunglassesEvent | null>;
56
56
  }
57
57
  type EventType = 'capture' | 'screen' | 'identify' | 'alias' | 'group';
58
+ /**
59
+ * Over-the-air (OTA) / app update information, e.g. an Expo EAS Update or a web
60
+ * deploy identifier. Useful for correlating events with a specific shipped bundle.
61
+ */
62
+ interface AppUpdateInfo {
63
+ /** Unique identifier of the applied update (e.g. EAS update ID). */
64
+ id?: string;
65
+ /** Release channel the update was published to (e.g. 'production'). */
66
+ channel?: string;
67
+ /** Runtime/native version the update is compatible with. */
68
+ runtimeVersion?: string;
69
+ /** True when running the bundle shipped in the binary (no OTA applied). */
70
+ embedded?: boolean;
71
+ /** ISO-8601 timestamp of when the update was created/published. */
72
+ createdAt?: string;
73
+ }
74
+ /**
75
+ * Mutable global metadata attached to every event's `context`. Set via
76
+ * `SunglassesConfig` at init and updatable at runtime. In-memory only — the host
77
+ * app must re-supply these values on each boot.
78
+ */
79
+ interface AppMetadata {
80
+ /** Deployment environment, e.g. 'production' | 'staging' | 'development'. */
81
+ environment?: string;
82
+ /** App variant / build flavor, e.g. 'pro' | 'lite' | 'beta'. */
83
+ appVariant?: string;
84
+ /** OTA / app update info for the currently running bundle. */
85
+ appUpdate?: AppUpdateInfo;
86
+ /** Enabled features / experiment variants (app-scoped). */
87
+ features?: string[];
88
+ /** Active user entitlements (user-scoped, cleared on reset()). */
89
+ entitlements?: string[];
90
+ }
58
91
  interface EventContext {
59
92
  library: {
60
93
  name: string;
@@ -65,6 +98,8 @@ interface EventContext {
65
98
  name?: string;
66
99
  version?: string;
67
100
  build?: string;
101
+ variant?: string;
102
+ update?: AppUpdateInfo;
68
103
  };
69
104
  device?: {
70
105
  type?: string;
@@ -75,6 +110,12 @@ interface EventContext {
75
110
  height?: number;
76
111
  };
77
112
  locale?: string;
113
+ /** Deployment environment, e.g. 'production' | 'staging' | 'development'. */
114
+ environment?: string;
115
+ /** Enabled features / experiment variants (app-scoped). */
116
+ features?: string[];
117
+ /** Active user entitlements (user-scoped). */
118
+ entitlements?: string[];
78
119
  /** Current session ID. Present when enableSessionTracking is true. */
79
120
  sessionId?: string;
80
121
  /** Persisted user traits set via identify(). Forwarded to backends for segmentation. */
@@ -171,6 +212,16 @@ interface SunglassesConfig {
171
212
  appName?: string;
172
213
  appVersion?: string;
173
214
  appBuild?: string;
215
+ /** App variant / build flavor, e.g. 'pro' | 'lite' | 'beta'. Attached to context.app.variant. */
216
+ appVariant?: string;
217
+ /** OTA / app update info for the currently running bundle. Attached to context.app.update. */
218
+ appUpdate?: AppUpdateInfo;
219
+ /** Deployment environment, e.g. 'production' | 'staging'. Attached to context.environment. */
220
+ environment?: string;
221
+ /** Enabled features / experiment variants (app-scoped). Attached to context.features. */
222
+ features?: string[];
223
+ /** Active user entitlements (user-scoped). Attached to context.entitlements. */
224
+ entitlements?: string[];
174
225
  /** Enables verbose console logging. Never enable in production. */
175
226
  debug?: boolean;
176
227
  /** Hard-disables all tracking (e.g. CI environments, test suites). */
@@ -269,6 +320,34 @@ interface ISunglassesClient {
269
320
  unregister(...keys: string[]): void;
270
321
  /** Returns a snapshot of all currently registered super properties. */
271
322
  getRegisteredProperties(): Record<string, unknown>;
323
+ /**
324
+ * Set the deployment environment (e.g. 'production', 'staging'). Attached to
325
+ * every subsequent event's `context.environment`. In-memory only.
326
+ */
327
+ setEnvironment(environment: string): void;
328
+ /**
329
+ * Set OTA / app update info for the currently running bundle. Attached to
330
+ * every subsequent event's `context.app.update`. In-memory only.
331
+ */
332
+ setAppUpdate(update: AppUpdateInfo): void;
333
+ /**
334
+ * Set the list of enabled features / experiment variants (app-scoped).
335
+ * Attached to every subsequent event's `context.features`. In-memory only.
336
+ */
337
+ setFeatures(features: string[]): void;
338
+ /**
339
+ * Set the active user entitlements (user-scoped). Attached to every subsequent
340
+ * event's `context.entitlements`. Cleared by `reset()` and `deleteUserData()`.
341
+ * In-memory only.
342
+ */
343
+ setEntitlements(entitlements: string[]): void;
344
+ /**
345
+ * Merge a partial set of global app metadata. Only the provided keys are
346
+ * updated; omitted keys keep their current value. In-memory only.
347
+ */
348
+ setAppMetadata(meta: Partial<AppMetadata>): void;
349
+ /** Returns a snapshot of the current global app metadata. */
350
+ getAppMetadata(): AppMetadata;
272
351
  optIn(): Promise<void>;
273
352
  optOut(): Promise<void>;
274
353
  hasOptedIn(): boolean;
@@ -498,6 +577,12 @@ declare class SunglassesCore implements ISunglassesClient {
498
577
  private readonly superProperties;
499
578
  /** In-memory group ID attached to every event's context after group() is called. */
500
579
  private groupId;
580
+ /** In-memory global app metadata attached to every event's context. */
581
+ private environment;
582
+ private appVariant;
583
+ private appUpdate;
584
+ private features;
585
+ private entitlements;
501
586
  private constructor();
502
587
  /**
503
588
  * Create and initialize a SunglassesCore instance.
@@ -512,6 +597,12 @@ declare class SunglassesCore implements ISunglassesClient {
512
597
  register(properties: Record<string, unknown>): void;
513
598
  unregister(...keys: string[]): void;
514
599
  getRegisteredProperties(): Record<string, unknown>;
600
+ setEnvironment(environment: string): void;
601
+ setAppUpdate(update: AppUpdateInfo): void;
602
+ setFeatures(features: string[]): void;
603
+ setEntitlements(entitlements: string[]): void;
604
+ setAppMetadata(meta: Partial<AppMetadata>): void;
605
+ getAppMetadata(): AppMetadata;
515
606
  reset(): Promise<void>;
516
607
  optIn(): Promise<void>;
517
608
  optOut(): Promise<void>;
@@ -1045,6 +1136,73 @@ declare class LocalEventArchive {
1045
1136
  */
1046
1137
  declare function asTyped<T extends EventMap>(client: ISunglassesClient): ISunglassesTypedClient<T>;
1047
1138
 
1139
+ /**
1140
+ * Options for {@link captureException}. Mirrors the privacy-safe defaults used
1141
+ * by the error-capturing adapters so behaviour is consistent everywhere.
1142
+ */
1143
+ interface CaptureExceptionOptions {
1144
+ /**
1145
+ * Whether the error was handled (caught by an error boundary / try-catch) or
1146
+ * unhandled (surfaced by a global error handler). Default: `true`.
1147
+ */
1148
+ handled?: boolean;
1149
+ /** Sentry-compatible severity level. Default: `'error'`. */
1150
+ level?: string;
1151
+ /**
1152
+ * Include the stack trace in `$error_stack`. Default: `false` (privacy-safe).
1153
+ * Stack traces may expose internal file paths and function names.
1154
+ */
1155
+ includeStack?: boolean;
1156
+ /**
1157
+ * Maximum number of stack frames to include when `includeStack` is `true`.
1158
+ * Default: `5`.
1159
+ */
1160
+ maxStackFrames?: number;
1161
+ /**
1162
+ * Truncate error messages to this many characters. Default: `200`.
1163
+ * Error messages sometimes contain user data ("User foo@bar.com not found").
1164
+ */
1165
+ maxMessageLength?: number;
1166
+ /**
1167
+ * Skip errors whose message matches any of these patterns.
1168
+ * Pattern is tested against the raw (pre-truncation) message.
1169
+ */
1170
+ ignorePatterns?: RegExp[];
1171
+ /**
1172
+ * Extra properties merged into the captured `$error` event. Lower precedence
1173
+ * than the computed `$error_*` properties.
1174
+ */
1175
+ properties?: Record<string, unknown>;
1176
+ /**
1177
+ * Optional transform applied before `client.capture()`.
1178
+ * Receives typed `ErrorEventProperties`; return a (possibly extended) props
1179
+ * object to capture, or `null` to skip capture entirely.
1180
+ */
1181
+ beforeCapture?: (props: ErrorEventProperties) => Record<string, unknown> | null;
1182
+ }
1183
+ /**
1184
+ * Normalize any thrown value into a SunGlasses `$error` event and capture it
1185
+ * via `client.capture()`.
1186
+ *
1187
+ * This is the single source of error-event construction shared by the built-in
1188
+ * error boundaries and the provider global error handlers. It never throws and
1189
+ * respects consent automatically (capture is consent-gated in the core).
1190
+ *
1191
+ * @param client - SunGlasses client instance.
1192
+ * @param error - The thrown value (an `Error`, string, or arbitrary object).
1193
+ * @param options - Optional capture configuration.
1194
+ *
1195
+ * @example
1196
+ * ```ts
1197
+ * try {
1198
+ * doRiskyThing();
1199
+ * } catch (err) {
1200
+ * captureException(client, err); // $error_handled: true
1201
+ * }
1202
+ * ```
1203
+ */
1204
+ declare function captureException(client: ISunglassesClient, error: unknown, options?: CaptureExceptionOptions): void;
1205
+
1048
1206
  /**
1049
1207
  * A typed analytics stub that is safe to use before the SDK initialises.
1050
1208
  *
@@ -1117,4 +1275,4 @@ declare function sha256Hex(input: string): Promise<string>;
1117
1275
  */
1118
1276
  declare function nowISO(): string;
1119
1277
 
1120
- export { type CleanupConfig, type ConsentHistoryEntry, ConsentManager, type ConsentState, type ConsentStatus, type ErrorEventProperties, type EventContext, type EventCountPeriod, EventCounter, type EventMap, EventQueue, type EventType, FrequencyMiddleware, type FrequencyMiddlewareOptions, type HttpAdapterConfig, type IAnalyticsAdapter, type IEventCounter, type IMiddleware, type IStorageAdapter, type ISunglassesClient, type ISunglassesTypedClient, IdentityManager, type IdentityState, LocalEventArchive, type Logger, type MiddlewareNext, MiddlewarePipeline, PiiSanitizer, SamplingMiddleware, type SamplingMiddlewareOptions, type ScreenTrackingOptions, SessionManager, type SessionState, type SunglassesConfig, SunglassesCore, type SunglassesEvent, TraitManager, type UserDataExport, asTyped, createLazyClient, createLogger, generateUUID, nowISO, sha256Hex };
1278
+ export { type AppMetadata, type AppUpdateInfo, type CaptureExceptionOptions, type CleanupConfig, type ConsentHistoryEntry, ConsentManager, type ConsentState, type ConsentStatus, type ErrorEventProperties, type EventContext, type EventCountPeriod, EventCounter, type EventMap, EventQueue, type EventType, FrequencyMiddleware, type FrequencyMiddlewareOptions, type HttpAdapterConfig, type IAnalyticsAdapter, type IEventCounter, type IMiddleware, type IStorageAdapter, type ISunglassesClient, type ISunglassesTypedClient, IdentityManager, type IdentityState, LocalEventArchive, type Logger, type MiddlewareNext, MiddlewarePipeline, PiiSanitizer, SamplingMiddleware, type SamplingMiddlewareOptions, type ScreenTrackingOptions, SessionManager, type SessionState, type SunglassesConfig, SunglassesCore, type SunglassesEvent, TraitManager, type UserDataExport, asTyped, captureException, createLazyClient, createLogger, generateUUID, nowISO, sha256Hex };
package/dist/index.d.ts CHANGED
@@ -55,6 +55,39 @@ interface IMiddleware {
55
55
  process(event: SunglassesEvent, next: MiddlewareNext): Promise<SunglassesEvent | null>;
56
56
  }
57
57
  type EventType = 'capture' | 'screen' | 'identify' | 'alias' | 'group';
58
+ /**
59
+ * Over-the-air (OTA) / app update information, e.g. an Expo EAS Update or a web
60
+ * deploy identifier. Useful for correlating events with a specific shipped bundle.
61
+ */
62
+ interface AppUpdateInfo {
63
+ /** Unique identifier of the applied update (e.g. EAS update ID). */
64
+ id?: string;
65
+ /** Release channel the update was published to (e.g. 'production'). */
66
+ channel?: string;
67
+ /** Runtime/native version the update is compatible with. */
68
+ runtimeVersion?: string;
69
+ /** True when running the bundle shipped in the binary (no OTA applied). */
70
+ embedded?: boolean;
71
+ /** ISO-8601 timestamp of when the update was created/published. */
72
+ createdAt?: string;
73
+ }
74
+ /**
75
+ * Mutable global metadata attached to every event's `context`. Set via
76
+ * `SunglassesConfig` at init and updatable at runtime. In-memory only — the host
77
+ * app must re-supply these values on each boot.
78
+ */
79
+ interface AppMetadata {
80
+ /** Deployment environment, e.g. 'production' | 'staging' | 'development'. */
81
+ environment?: string;
82
+ /** App variant / build flavor, e.g. 'pro' | 'lite' | 'beta'. */
83
+ appVariant?: string;
84
+ /** OTA / app update info for the currently running bundle. */
85
+ appUpdate?: AppUpdateInfo;
86
+ /** Enabled features / experiment variants (app-scoped). */
87
+ features?: string[];
88
+ /** Active user entitlements (user-scoped, cleared on reset()). */
89
+ entitlements?: string[];
90
+ }
58
91
  interface EventContext {
59
92
  library: {
60
93
  name: string;
@@ -65,6 +98,8 @@ interface EventContext {
65
98
  name?: string;
66
99
  version?: string;
67
100
  build?: string;
101
+ variant?: string;
102
+ update?: AppUpdateInfo;
68
103
  };
69
104
  device?: {
70
105
  type?: string;
@@ -75,6 +110,12 @@ interface EventContext {
75
110
  height?: number;
76
111
  };
77
112
  locale?: string;
113
+ /** Deployment environment, e.g. 'production' | 'staging' | 'development'. */
114
+ environment?: string;
115
+ /** Enabled features / experiment variants (app-scoped). */
116
+ features?: string[];
117
+ /** Active user entitlements (user-scoped). */
118
+ entitlements?: string[];
78
119
  /** Current session ID. Present when enableSessionTracking is true. */
79
120
  sessionId?: string;
80
121
  /** Persisted user traits set via identify(). Forwarded to backends for segmentation. */
@@ -171,6 +212,16 @@ interface SunglassesConfig {
171
212
  appName?: string;
172
213
  appVersion?: string;
173
214
  appBuild?: string;
215
+ /** App variant / build flavor, e.g. 'pro' | 'lite' | 'beta'. Attached to context.app.variant. */
216
+ appVariant?: string;
217
+ /** OTA / app update info for the currently running bundle. Attached to context.app.update. */
218
+ appUpdate?: AppUpdateInfo;
219
+ /** Deployment environment, e.g. 'production' | 'staging'. Attached to context.environment. */
220
+ environment?: string;
221
+ /** Enabled features / experiment variants (app-scoped). Attached to context.features. */
222
+ features?: string[];
223
+ /** Active user entitlements (user-scoped). Attached to context.entitlements. */
224
+ entitlements?: string[];
174
225
  /** Enables verbose console logging. Never enable in production. */
175
226
  debug?: boolean;
176
227
  /** Hard-disables all tracking (e.g. CI environments, test suites). */
@@ -269,6 +320,34 @@ interface ISunglassesClient {
269
320
  unregister(...keys: string[]): void;
270
321
  /** Returns a snapshot of all currently registered super properties. */
271
322
  getRegisteredProperties(): Record<string, unknown>;
323
+ /**
324
+ * Set the deployment environment (e.g. 'production', 'staging'). Attached to
325
+ * every subsequent event's `context.environment`. In-memory only.
326
+ */
327
+ setEnvironment(environment: string): void;
328
+ /**
329
+ * Set OTA / app update info for the currently running bundle. Attached to
330
+ * every subsequent event's `context.app.update`. In-memory only.
331
+ */
332
+ setAppUpdate(update: AppUpdateInfo): void;
333
+ /**
334
+ * Set the list of enabled features / experiment variants (app-scoped).
335
+ * Attached to every subsequent event's `context.features`. In-memory only.
336
+ */
337
+ setFeatures(features: string[]): void;
338
+ /**
339
+ * Set the active user entitlements (user-scoped). Attached to every subsequent
340
+ * event's `context.entitlements`. Cleared by `reset()` and `deleteUserData()`.
341
+ * In-memory only.
342
+ */
343
+ setEntitlements(entitlements: string[]): void;
344
+ /**
345
+ * Merge a partial set of global app metadata. Only the provided keys are
346
+ * updated; omitted keys keep their current value. In-memory only.
347
+ */
348
+ setAppMetadata(meta: Partial<AppMetadata>): void;
349
+ /** Returns a snapshot of the current global app metadata. */
350
+ getAppMetadata(): AppMetadata;
272
351
  optIn(): Promise<void>;
273
352
  optOut(): Promise<void>;
274
353
  hasOptedIn(): boolean;
@@ -498,6 +577,12 @@ declare class SunglassesCore implements ISunglassesClient {
498
577
  private readonly superProperties;
499
578
  /** In-memory group ID attached to every event's context after group() is called. */
500
579
  private groupId;
580
+ /** In-memory global app metadata attached to every event's context. */
581
+ private environment;
582
+ private appVariant;
583
+ private appUpdate;
584
+ private features;
585
+ private entitlements;
501
586
  private constructor();
502
587
  /**
503
588
  * Create and initialize a SunglassesCore instance.
@@ -512,6 +597,12 @@ declare class SunglassesCore implements ISunglassesClient {
512
597
  register(properties: Record<string, unknown>): void;
513
598
  unregister(...keys: string[]): void;
514
599
  getRegisteredProperties(): Record<string, unknown>;
600
+ setEnvironment(environment: string): void;
601
+ setAppUpdate(update: AppUpdateInfo): void;
602
+ setFeatures(features: string[]): void;
603
+ setEntitlements(entitlements: string[]): void;
604
+ setAppMetadata(meta: Partial<AppMetadata>): void;
605
+ getAppMetadata(): AppMetadata;
515
606
  reset(): Promise<void>;
516
607
  optIn(): Promise<void>;
517
608
  optOut(): Promise<void>;
@@ -1045,6 +1136,73 @@ declare class LocalEventArchive {
1045
1136
  */
1046
1137
  declare function asTyped<T extends EventMap>(client: ISunglassesClient): ISunglassesTypedClient<T>;
1047
1138
 
1139
+ /**
1140
+ * Options for {@link captureException}. Mirrors the privacy-safe defaults used
1141
+ * by the error-capturing adapters so behaviour is consistent everywhere.
1142
+ */
1143
+ interface CaptureExceptionOptions {
1144
+ /**
1145
+ * Whether the error was handled (caught by an error boundary / try-catch) or
1146
+ * unhandled (surfaced by a global error handler). Default: `true`.
1147
+ */
1148
+ handled?: boolean;
1149
+ /** Sentry-compatible severity level. Default: `'error'`. */
1150
+ level?: string;
1151
+ /**
1152
+ * Include the stack trace in `$error_stack`. Default: `false` (privacy-safe).
1153
+ * Stack traces may expose internal file paths and function names.
1154
+ */
1155
+ includeStack?: boolean;
1156
+ /**
1157
+ * Maximum number of stack frames to include when `includeStack` is `true`.
1158
+ * Default: `5`.
1159
+ */
1160
+ maxStackFrames?: number;
1161
+ /**
1162
+ * Truncate error messages to this many characters. Default: `200`.
1163
+ * Error messages sometimes contain user data ("User foo@bar.com not found").
1164
+ */
1165
+ maxMessageLength?: number;
1166
+ /**
1167
+ * Skip errors whose message matches any of these patterns.
1168
+ * Pattern is tested against the raw (pre-truncation) message.
1169
+ */
1170
+ ignorePatterns?: RegExp[];
1171
+ /**
1172
+ * Extra properties merged into the captured `$error` event. Lower precedence
1173
+ * than the computed `$error_*` properties.
1174
+ */
1175
+ properties?: Record<string, unknown>;
1176
+ /**
1177
+ * Optional transform applied before `client.capture()`.
1178
+ * Receives typed `ErrorEventProperties`; return a (possibly extended) props
1179
+ * object to capture, or `null` to skip capture entirely.
1180
+ */
1181
+ beforeCapture?: (props: ErrorEventProperties) => Record<string, unknown> | null;
1182
+ }
1183
+ /**
1184
+ * Normalize any thrown value into a SunGlasses `$error` event and capture it
1185
+ * via `client.capture()`.
1186
+ *
1187
+ * This is the single source of error-event construction shared by the built-in
1188
+ * error boundaries and the provider global error handlers. It never throws and
1189
+ * respects consent automatically (capture is consent-gated in the core).
1190
+ *
1191
+ * @param client - SunGlasses client instance.
1192
+ * @param error - The thrown value (an `Error`, string, or arbitrary object).
1193
+ * @param options - Optional capture configuration.
1194
+ *
1195
+ * @example
1196
+ * ```ts
1197
+ * try {
1198
+ * doRiskyThing();
1199
+ * } catch (err) {
1200
+ * captureException(client, err); // $error_handled: true
1201
+ * }
1202
+ * ```
1203
+ */
1204
+ declare function captureException(client: ISunglassesClient, error: unknown, options?: CaptureExceptionOptions): void;
1205
+
1048
1206
  /**
1049
1207
  * A typed analytics stub that is safe to use before the SDK initialises.
1050
1208
  *
@@ -1117,4 +1275,4 @@ declare function sha256Hex(input: string): Promise<string>;
1117
1275
  */
1118
1276
  declare function nowISO(): string;
1119
1277
 
1120
- export { type CleanupConfig, type ConsentHistoryEntry, ConsentManager, type ConsentState, type ConsentStatus, type ErrorEventProperties, type EventContext, type EventCountPeriod, EventCounter, type EventMap, EventQueue, type EventType, FrequencyMiddleware, type FrequencyMiddlewareOptions, type HttpAdapterConfig, type IAnalyticsAdapter, type IEventCounter, type IMiddleware, type IStorageAdapter, type ISunglassesClient, type ISunglassesTypedClient, IdentityManager, type IdentityState, LocalEventArchive, type Logger, type MiddlewareNext, MiddlewarePipeline, PiiSanitizer, SamplingMiddleware, type SamplingMiddlewareOptions, type ScreenTrackingOptions, SessionManager, type SessionState, type SunglassesConfig, SunglassesCore, type SunglassesEvent, TraitManager, type UserDataExport, asTyped, createLazyClient, createLogger, generateUUID, nowISO, sha256Hex };
1278
+ export { type AppMetadata, type AppUpdateInfo, type CaptureExceptionOptions, type CleanupConfig, type ConsentHistoryEntry, ConsentManager, type ConsentState, type ConsentStatus, type ErrorEventProperties, type EventContext, type EventCountPeriod, EventCounter, type EventMap, EventQueue, type EventType, FrequencyMiddleware, type FrequencyMiddlewareOptions, type HttpAdapterConfig, type IAnalyticsAdapter, type IEventCounter, type IMiddleware, type IStorageAdapter, type ISunglassesClient, type ISunglassesTypedClient, IdentityManager, type IdentityState, LocalEventArchive, type Logger, type MiddlewareNext, MiddlewarePipeline, PiiSanitizer, SamplingMiddleware, type SamplingMiddlewareOptions, type ScreenTrackingOptions, SessionManager, type SessionState, type SunglassesConfig, SunglassesCore, type SunglassesEvent, TraitManager, type UserDataExport, asTyped, captureException, createLazyClient, createLogger, generateUUID, nowISO, sha256Hex };
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  SunglassesCore: () => SunglassesCore,
34
34
  TraitManager: () => TraitManager,
35
35
  asTyped: () => asTyped,
36
+ captureException: () => captureException,
36
37
  createLazyClient: () => createLazyClient,
37
38
  createLogger: () => createLogger,
38
39
  generateUUID: () => generateUUID,
@@ -1013,6 +1014,11 @@ var SunglassesCore = class _SunglassesCore {
1013
1014
  this.sessionManager = sessionManager;
1014
1015
  this.traitManager = traitManager;
1015
1016
  this.localArchive = localArchive;
1017
+ this.environment = config.environment;
1018
+ this.appVariant = config.appVariant;
1019
+ this.appUpdate = config.appUpdate;
1020
+ this.features = config.features;
1021
+ this.entitlements = config.entitlements;
1016
1022
  }
1017
1023
  /**
1018
1024
  * Create and initialize a SunglassesCore instance.
@@ -1145,11 +1151,41 @@ var SunglassesCore = class _SunglassesCore {
1145
1151
  getRegisteredProperties() {
1146
1152
  return Object.fromEntries(this.superProperties);
1147
1153
  }
1154
+ // ── App metadata ───────────────────────────────────────────────────────────
1155
+ setEnvironment(environment) {
1156
+ this.environment = environment;
1157
+ }
1158
+ setAppUpdate(update) {
1159
+ this.appUpdate = update;
1160
+ }
1161
+ setFeatures(features) {
1162
+ this.features = features;
1163
+ }
1164
+ setEntitlements(entitlements) {
1165
+ this.entitlements = entitlements;
1166
+ }
1167
+ setAppMetadata(meta) {
1168
+ if ("environment" in meta) this.environment = meta.environment;
1169
+ if ("appVariant" in meta) this.appVariant = meta.appVariant;
1170
+ if ("appUpdate" in meta) this.appUpdate = meta.appUpdate;
1171
+ if ("features" in meta) this.features = meta.features;
1172
+ if ("entitlements" in meta) this.entitlements = meta.entitlements;
1173
+ }
1174
+ getAppMetadata() {
1175
+ return {
1176
+ environment: this.environment,
1177
+ appVariant: this.appVariant,
1178
+ appUpdate: this.appUpdate,
1179
+ features: this.features,
1180
+ entitlements: this.entitlements
1181
+ };
1182
+ }
1148
1183
  async reset() {
1149
1184
  await this.identity.reset();
1150
1185
  await this.queue.clear();
1151
1186
  await this.traitManager.clearTraits();
1152
1187
  this.groupId = null;
1188
+ this.entitlements = void 0;
1153
1189
  if (this.sessionManager) {
1154
1190
  await this.sessionManager.end();
1155
1191
  }
@@ -1267,6 +1303,7 @@ var SunglassesCore = class _SunglassesCore {
1267
1303
  await this.identity.reset();
1268
1304
  this.groupId = null;
1269
1305
  this.superProperties.clear();
1306
+ this.entitlements = void 0;
1270
1307
  if (options.resetConsent) {
1271
1308
  await this.consent.resetToUnknown(this.config.consentPolicyVersion);
1272
1309
  this.stopFlushTimer();
@@ -1352,13 +1389,24 @@ var SunglassesCore = class _SunglassesCore {
1352
1389
  library: { name: LIBRARY_NAME, version: LIBRARY_VERSION },
1353
1390
  platform: this.config.platform
1354
1391
  };
1355
- if (this.config.appName || this.config.appVersion) {
1392
+ if (this.config.appName || this.config.appVersion || this.appVariant || this.appUpdate) {
1356
1393
  ctx.app = {
1357
1394
  name: this.config.appName || void 0,
1358
1395
  version: this.config.appVersion || void 0,
1359
- build: this.config.appBuild || void 0
1396
+ build: this.config.appBuild || void 0,
1397
+ variant: this.appVariant || void 0,
1398
+ update: this.appUpdate || void 0
1360
1399
  };
1361
1400
  }
1401
+ if (this.environment) {
1402
+ ctx.environment = this.environment;
1403
+ }
1404
+ if (this.features && this.features.length > 0) {
1405
+ ctx.features = this.features;
1406
+ }
1407
+ if (this.entitlements && this.entitlements.length > 0) {
1408
+ ctx.entitlements = this.entitlements;
1409
+ }
1362
1410
  if (sessionId !== void 0) {
1363
1411
  ctx.sessionId = sessionId;
1364
1412
  }
@@ -1532,6 +1580,71 @@ function asTyped(client) {
1532
1580
  return client;
1533
1581
  }
1534
1582
 
1583
+ // src/captureException.ts
1584
+ function normalizeError(error) {
1585
+ if (error instanceof Error) {
1586
+ return { message: error.message, name: error.name || "Error", stack: error.stack };
1587
+ }
1588
+ if (typeof error === "string") {
1589
+ return { message: error, name: "Error" };
1590
+ }
1591
+ if (error && typeof error === "object") {
1592
+ const maybe = error;
1593
+ return {
1594
+ message: typeof maybe.message === "string" ? maybe.message : String(error),
1595
+ name: typeof maybe.name === "string" && maybe.name ? maybe.name : "Error",
1596
+ stack: typeof maybe.stack === "string" ? maybe.stack : void 0
1597
+ };
1598
+ }
1599
+ return { message: String(error), name: "Error" };
1600
+ }
1601
+ function extractStack(stack, maxFrames) {
1602
+ if (!stack) return void 0;
1603
+ const lines = stack.split("\n").map((l) => l.trim());
1604
+ const v8Frames = lines.filter((l) => l.startsWith("at "));
1605
+ if (v8Frames.length > 0) {
1606
+ return v8Frames.slice(0, maxFrames).join("\n");
1607
+ }
1608
+ const rnFrames = lines.filter((l) => l.includes("@") && !l.includes(" "));
1609
+ if (rnFrames.length > 0) {
1610
+ return rnFrames.slice(0, maxFrames).join("\n");
1611
+ }
1612
+ return void 0;
1613
+ }
1614
+ function captureException(client, error, options = {}) {
1615
+ const {
1616
+ handled = true,
1617
+ level = "error",
1618
+ includeStack = false,
1619
+ maxStackFrames = 5,
1620
+ maxMessageLength = 200,
1621
+ ignorePatterns = [],
1622
+ properties,
1623
+ beforeCapture
1624
+ } = options;
1625
+ const normalized = normalizeError(error);
1626
+ const rawMessage = normalized.message;
1627
+ if (ignorePatterns.some((p) => p.test(rawMessage))) return;
1628
+ let props = {
1629
+ ...properties,
1630
+ $error_message: rawMessage.slice(0, maxMessageLength),
1631
+ $error_type: normalized.name,
1632
+ $error_handled: handled,
1633
+ $error_level: level
1634
+ };
1635
+ if (includeStack) {
1636
+ const frames = extractStack(normalized.stack, maxStackFrames);
1637
+ if (frames) props = { ...props, $error_stack: frames };
1638
+ }
1639
+ if (beforeCapture) {
1640
+ const transformed = beforeCapture(props);
1641
+ if (!transformed) return;
1642
+ client.capture("$error", transformed);
1643
+ } else {
1644
+ client.capture("$error", props);
1645
+ }
1646
+ }
1647
+
1535
1648
  // src/LazyClient.ts
1536
1649
  function createLazyClient() {
1537
1650
  let _inner = null;
@@ -1568,6 +1681,25 @@ function createLazyClient() {
1568
1681
  getRegisteredProperties() {
1569
1682
  return _inner?.getRegisteredProperties() ?? {};
1570
1683
  },
1684
+ // ── App metadata ──────────────────────────────────────────────────────────
1685
+ setEnvironment(environment) {
1686
+ _inner?.setEnvironment(environment);
1687
+ },
1688
+ setAppUpdate(update) {
1689
+ _inner?.setAppUpdate(update);
1690
+ },
1691
+ setFeatures(features) {
1692
+ _inner?.setFeatures(features);
1693
+ },
1694
+ setEntitlements(entitlements) {
1695
+ _inner?.setEntitlements(entitlements);
1696
+ },
1697
+ setAppMetadata(meta) {
1698
+ _inner?.setAppMetadata(meta);
1699
+ },
1700
+ getAppMetadata() {
1701
+ return _inner?.getAppMetadata() ?? {};
1702
+ },
1571
1703
  // ── Consent ───────────────────────────────────────────────────────────────
1572
1704
  async optIn() {
1573
1705
  await _inner?.optIn();
@@ -1645,6 +1777,7 @@ function createLazyClient() {
1645
1777
  SunglassesCore,
1646
1778
  TraitManager,
1647
1779
  asTyped,
1780
+ captureException,
1648
1781
  createLazyClient,
1649
1782
  createLogger,
1650
1783
  generateUUID,
package/dist/index.mjs CHANGED
@@ -970,6 +970,11 @@ var SunglassesCore = class _SunglassesCore {
970
970
  this.sessionManager = sessionManager;
971
971
  this.traitManager = traitManager;
972
972
  this.localArchive = localArchive;
973
+ this.environment = config.environment;
974
+ this.appVariant = config.appVariant;
975
+ this.appUpdate = config.appUpdate;
976
+ this.features = config.features;
977
+ this.entitlements = config.entitlements;
973
978
  }
974
979
  /**
975
980
  * Create and initialize a SunglassesCore instance.
@@ -1102,11 +1107,41 @@ var SunglassesCore = class _SunglassesCore {
1102
1107
  getRegisteredProperties() {
1103
1108
  return Object.fromEntries(this.superProperties);
1104
1109
  }
1110
+ // ── App metadata ───────────────────────────────────────────────────────────
1111
+ setEnvironment(environment) {
1112
+ this.environment = environment;
1113
+ }
1114
+ setAppUpdate(update) {
1115
+ this.appUpdate = update;
1116
+ }
1117
+ setFeatures(features) {
1118
+ this.features = features;
1119
+ }
1120
+ setEntitlements(entitlements) {
1121
+ this.entitlements = entitlements;
1122
+ }
1123
+ setAppMetadata(meta) {
1124
+ if ("environment" in meta) this.environment = meta.environment;
1125
+ if ("appVariant" in meta) this.appVariant = meta.appVariant;
1126
+ if ("appUpdate" in meta) this.appUpdate = meta.appUpdate;
1127
+ if ("features" in meta) this.features = meta.features;
1128
+ if ("entitlements" in meta) this.entitlements = meta.entitlements;
1129
+ }
1130
+ getAppMetadata() {
1131
+ return {
1132
+ environment: this.environment,
1133
+ appVariant: this.appVariant,
1134
+ appUpdate: this.appUpdate,
1135
+ features: this.features,
1136
+ entitlements: this.entitlements
1137
+ };
1138
+ }
1105
1139
  async reset() {
1106
1140
  await this.identity.reset();
1107
1141
  await this.queue.clear();
1108
1142
  await this.traitManager.clearTraits();
1109
1143
  this.groupId = null;
1144
+ this.entitlements = void 0;
1110
1145
  if (this.sessionManager) {
1111
1146
  await this.sessionManager.end();
1112
1147
  }
@@ -1224,6 +1259,7 @@ var SunglassesCore = class _SunglassesCore {
1224
1259
  await this.identity.reset();
1225
1260
  this.groupId = null;
1226
1261
  this.superProperties.clear();
1262
+ this.entitlements = void 0;
1227
1263
  if (options.resetConsent) {
1228
1264
  await this.consent.resetToUnknown(this.config.consentPolicyVersion);
1229
1265
  this.stopFlushTimer();
@@ -1309,13 +1345,24 @@ var SunglassesCore = class _SunglassesCore {
1309
1345
  library: { name: LIBRARY_NAME, version: LIBRARY_VERSION },
1310
1346
  platform: this.config.platform
1311
1347
  };
1312
- if (this.config.appName || this.config.appVersion) {
1348
+ if (this.config.appName || this.config.appVersion || this.appVariant || this.appUpdate) {
1313
1349
  ctx.app = {
1314
1350
  name: this.config.appName || void 0,
1315
1351
  version: this.config.appVersion || void 0,
1316
- build: this.config.appBuild || void 0
1352
+ build: this.config.appBuild || void 0,
1353
+ variant: this.appVariant || void 0,
1354
+ update: this.appUpdate || void 0
1317
1355
  };
1318
1356
  }
1357
+ if (this.environment) {
1358
+ ctx.environment = this.environment;
1359
+ }
1360
+ if (this.features && this.features.length > 0) {
1361
+ ctx.features = this.features;
1362
+ }
1363
+ if (this.entitlements && this.entitlements.length > 0) {
1364
+ ctx.entitlements = this.entitlements;
1365
+ }
1319
1366
  if (sessionId !== void 0) {
1320
1367
  ctx.sessionId = sessionId;
1321
1368
  }
@@ -1489,6 +1536,71 @@ function asTyped(client) {
1489
1536
  return client;
1490
1537
  }
1491
1538
 
1539
+ // src/captureException.ts
1540
+ function normalizeError(error) {
1541
+ if (error instanceof Error) {
1542
+ return { message: error.message, name: error.name || "Error", stack: error.stack };
1543
+ }
1544
+ if (typeof error === "string") {
1545
+ return { message: error, name: "Error" };
1546
+ }
1547
+ if (error && typeof error === "object") {
1548
+ const maybe = error;
1549
+ return {
1550
+ message: typeof maybe.message === "string" ? maybe.message : String(error),
1551
+ name: typeof maybe.name === "string" && maybe.name ? maybe.name : "Error",
1552
+ stack: typeof maybe.stack === "string" ? maybe.stack : void 0
1553
+ };
1554
+ }
1555
+ return { message: String(error), name: "Error" };
1556
+ }
1557
+ function extractStack(stack, maxFrames) {
1558
+ if (!stack) return void 0;
1559
+ const lines = stack.split("\n").map((l) => l.trim());
1560
+ const v8Frames = lines.filter((l) => l.startsWith("at "));
1561
+ if (v8Frames.length > 0) {
1562
+ return v8Frames.slice(0, maxFrames).join("\n");
1563
+ }
1564
+ const rnFrames = lines.filter((l) => l.includes("@") && !l.includes(" "));
1565
+ if (rnFrames.length > 0) {
1566
+ return rnFrames.slice(0, maxFrames).join("\n");
1567
+ }
1568
+ return void 0;
1569
+ }
1570
+ function captureException(client, error, options = {}) {
1571
+ const {
1572
+ handled = true,
1573
+ level = "error",
1574
+ includeStack = false,
1575
+ maxStackFrames = 5,
1576
+ maxMessageLength = 200,
1577
+ ignorePatterns = [],
1578
+ properties,
1579
+ beforeCapture
1580
+ } = options;
1581
+ const normalized = normalizeError(error);
1582
+ const rawMessage = normalized.message;
1583
+ if (ignorePatterns.some((p) => p.test(rawMessage))) return;
1584
+ let props = {
1585
+ ...properties,
1586
+ $error_message: rawMessage.slice(0, maxMessageLength),
1587
+ $error_type: normalized.name,
1588
+ $error_handled: handled,
1589
+ $error_level: level
1590
+ };
1591
+ if (includeStack) {
1592
+ const frames = extractStack(normalized.stack, maxStackFrames);
1593
+ if (frames) props = { ...props, $error_stack: frames };
1594
+ }
1595
+ if (beforeCapture) {
1596
+ const transformed = beforeCapture(props);
1597
+ if (!transformed) return;
1598
+ client.capture("$error", transformed);
1599
+ } else {
1600
+ client.capture("$error", props);
1601
+ }
1602
+ }
1603
+
1492
1604
  // src/LazyClient.ts
1493
1605
  function createLazyClient() {
1494
1606
  let _inner = null;
@@ -1525,6 +1637,25 @@ function createLazyClient() {
1525
1637
  getRegisteredProperties() {
1526
1638
  return _inner?.getRegisteredProperties() ?? {};
1527
1639
  },
1640
+ // ── App metadata ──────────────────────────────────────────────────────────
1641
+ setEnvironment(environment) {
1642
+ _inner?.setEnvironment(environment);
1643
+ },
1644
+ setAppUpdate(update) {
1645
+ _inner?.setAppUpdate(update);
1646
+ },
1647
+ setFeatures(features) {
1648
+ _inner?.setFeatures(features);
1649
+ },
1650
+ setEntitlements(entitlements) {
1651
+ _inner?.setEntitlements(entitlements);
1652
+ },
1653
+ setAppMetadata(meta) {
1654
+ _inner?.setAppMetadata(meta);
1655
+ },
1656
+ getAppMetadata() {
1657
+ return _inner?.getAppMetadata() ?? {};
1658
+ },
1528
1659
  // ── Consent ───────────────────────────────────────────────────────────────
1529
1660
  async optIn() {
1530
1661
  await _inner?.optIn();
@@ -1601,6 +1732,7 @@ export {
1601
1732
  SunglassesCore,
1602
1733
  TraitManager,
1603
1734
  asTyped,
1735
+ captureException,
1604
1736
  createLazyClient,
1605
1737
  createLogger,
1606
1738
  generateUUID,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drakkar.software/sunglasses-core",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Platform-agnostic event tracking engine for SunGlasses",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",