@observa/sdk 2.3.1 → 2.4.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/README.md +33 -14
- package/dist/index.d.ts +18 -5
- package/dist/index.js +24 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/apis/ingestApi.ts +19 -5
- package/src/domain/ingest.ts +4 -0
- package/src/http/httpClient.ts +7 -0
- package/src/sdk.ts +10 -6
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Official SDK for sending ingest events and uptime heartbeats to Observa.
|
|
|
5
5
|
## Who is this for?
|
|
6
6
|
|
|
7
7
|
This SDK is intended for backend services, workers, and server-side applications.
|
|
8
|
-
It
|
|
8
|
+
It now also supports browser environments using `publicKey`.
|
|
9
9
|
|
|
10
10
|
## SDK Contract
|
|
11
11
|
|
|
@@ -14,7 +14,8 @@ You can optionally override the backend `baseUrl`; the SDK ensures the `/v1` pre
|
|
|
14
14
|
|
|
15
15
|
## Concepts
|
|
16
16
|
|
|
17
|
-
- **apiKey**: Organization-level credential used for authentication.
|
|
17
|
+
- **apiKey**: Organization-level credential used for authentication (Backend).
|
|
18
|
+
- **publicKey**: Project-level credential for public ingestion (Frontend/Mobile).
|
|
18
19
|
- **dsnKey**: Project-level identifier used to route events and heartbeats.
|
|
19
20
|
|
|
20
21
|
## Installation
|
|
@@ -25,6 +26,8 @@ npm install @observa/sdk
|
|
|
25
26
|
|
|
26
27
|
## Usage
|
|
27
28
|
|
|
29
|
+
### Backend (Server-side)
|
|
30
|
+
|
|
28
31
|
```ts
|
|
29
32
|
import { ObservaSDK } from '@observa/sdk'
|
|
30
33
|
|
|
@@ -35,6 +38,20 @@ const sdk = new ObservaSDK({
|
|
|
35
38
|
})
|
|
36
39
|
```
|
|
37
40
|
|
|
41
|
+
### Frontend (Browser)
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { ObservaSDK } from '@observa/sdk'
|
|
45
|
+
|
|
46
|
+
const sdk = new ObservaSDK({
|
|
47
|
+
publicKey: 'project_public_key',
|
|
48
|
+
dsnKey: 'project_dsn',
|
|
49
|
+
baseUrl: 'https://backend-observa-production.up.railway.app',
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Note**: Mobile support is coming soon.
|
|
54
|
+
|
|
38
55
|
The SDK validates credentials through the ingest health endpoint.
|
|
39
56
|
|
|
40
57
|
## Defaults
|
|
@@ -43,13 +60,15 @@ The SDK validates credentials through the ingest health endpoint.
|
|
|
43
60
|
- Retries: disabled by default
|
|
44
61
|
- `baseUrl` defaults to the Observa backend and is normalized to `/v1`
|
|
45
62
|
- `dsnKey` is required for ingest and uptime writes
|
|
63
|
+
- `apiKey` is required for backend usage
|
|
64
|
+
- `publicKey` is required for frontend usage
|
|
46
65
|
|
|
47
66
|
## Ingest Events
|
|
48
67
|
|
|
49
68
|
```ts
|
|
50
69
|
const result = await sdk.ingest.event({
|
|
51
70
|
event: {
|
|
52
|
-
schema_version: 1,
|
|
71
|
+
schema_version: 1,
|
|
53
72
|
level: 'error',
|
|
54
73
|
message: 'Something went wrong',
|
|
55
74
|
exception: {
|
|
@@ -61,11 +80,11 @@ const result = await sdk.ingest.event({
|
|
|
61
80
|
},
|
|
62
81
|
tags: { service: 'billing' },
|
|
63
82
|
extra: { requestId: 'req_123' },
|
|
64
|
-
context: {
|
|
65
|
-
system: sdk.getProcessContextDynamic(),
|
|
66
|
-
runtime: sdk.getProcessContextStatic({ includeVersions: false }),
|
|
67
|
-
request: { requestId: 'req_123' },
|
|
68
|
-
},
|
|
83
|
+
context: {
|
|
84
|
+
system: sdk.getProcessContextDynamic(),
|
|
85
|
+
runtime: sdk.getProcessContextStatic({ includeVersions: false }),
|
|
86
|
+
request: { requestId: 'req_123' },
|
|
87
|
+
},
|
|
69
88
|
},
|
|
70
89
|
idempotencyKey: 'req_123',
|
|
71
90
|
sdkVersion: '2.0.0',
|
|
@@ -81,12 +100,12 @@ Required:
|
|
|
81
100
|
Optional:
|
|
82
101
|
- `idempotencyKey` is sent as `x-idempotency-key` header (max 128 chars)
|
|
83
102
|
- `sdkVersion` is sent as `x-sdk-version` header
|
|
84
|
-
|
|
85
|
-
Event context:
|
|
86
|
-
- `schema_version` identifies the event schema version.
|
|
87
|
-
- `context.system` carries dynamic process info (pid, uptime, memory).
|
|
88
|
-
- `context.runtime` carries static runtime info (node, arch, platform, release).
|
|
89
|
-
- `context.request` carries request-scoped metadata (requestId, userId, etc.).
|
|
103
|
+
|
|
104
|
+
Event context:
|
|
105
|
+
- `schema_version` identifies the event schema version.
|
|
106
|
+
- `context.system` carries dynamic process info (pid, uptime, memory).
|
|
107
|
+
- `context.runtime` carries static runtime info (node, arch, platform, release).
|
|
108
|
+
- `context.request` carries request-scoped metadata (requestId, userId, etc.).
|
|
90
109
|
|
|
91
110
|
## Uptime Heartbeats
|
|
92
111
|
|
package/dist/index.d.ts
CHANGED
|
@@ -96,6 +96,10 @@ type IngestRequest = {
|
|
|
96
96
|
* Project DSN. Uses the SDK default when omitted.
|
|
97
97
|
*/
|
|
98
98
|
dsnKey?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Public key for frontend/mobile projects.
|
|
101
|
+
*/
|
|
102
|
+
publicKey?: string;
|
|
99
103
|
/**
|
|
100
104
|
* Event to record.
|
|
101
105
|
*/
|
|
@@ -199,6 +203,10 @@ declare class HttpClient {
|
|
|
199
203
|
* Updates the API key at runtime.
|
|
200
204
|
*/
|
|
201
205
|
setApiKey(apiKey?: string): void;
|
|
206
|
+
/**
|
|
207
|
+
* Checks if an API key is configured.
|
|
208
|
+
*/
|
|
209
|
+
hasApiKey(): boolean;
|
|
202
210
|
startHealthCheck(healthCheck: () => Promise<unknown>): void;
|
|
203
211
|
/**
|
|
204
212
|
* GET request.
|
|
@@ -260,15 +268,16 @@ declare class IngestApi {
|
|
|
260
268
|
private readonly http;
|
|
261
269
|
private readonly defaultDsnKey?;
|
|
262
270
|
private readonly normalization?;
|
|
271
|
+
private readonly defaultPublicKey?;
|
|
263
272
|
/**
|
|
264
|
-
* Creates the ingestion client with an optional default DSN.
|
|
273
|
+
* Creates the ingestion client with an optional default DSN and PublicKey.
|
|
265
274
|
*/
|
|
266
|
-
constructor(http: HttpClient, defaultDsnKey?: string | undefined, normalization?: IngestNormalizationOptions | undefined);
|
|
275
|
+
constructor(http: HttpClient, defaultDsnKey?: string | undefined, normalization?: IngestNormalizationOptions | undefined, defaultPublicKey?: string | undefined);
|
|
267
276
|
/**
|
|
268
277
|
* Sends an event to the ingestion backend.
|
|
269
278
|
*/
|
|
270
279
|
event(input: IngestRequest): Promise<IngestResponse>;
|
|
271
|
-
health(dsnKey?: string): Promise<{
|
|
280
|
+
health(dsnKey?: string, publicKey?: string): Promise<{
|
|
272
281
|
ok: boolean;
|
|
273
282
|
}>;
|
|
274
283
|
}
|
|
@@ -392,11 +401,15 @@ type ObservaSDKOptions = {
|
|
|
392
401
|
/**
|
|
393
402
|
* Organization API key used to authenticate SDK requests.
|
|
394
403
|
*/
|
|
395
|
-
apiKey
|
|
404
|
+
apiKey?: string;
|
|
396
405
|
/**
|
|
397
406
|
* Project DSN used to identify the destination of events and heartbeats.
|
|
398
407
|
*/
|
|
399
408
|
dsnKey: string;
|
|
409
|
+
/**
|
|
410
|
+
* Public key for frontend/mobile projects.
|
|
411
|
+
*/
|
|
412
|
+
publicKey?: string;
|
|
400
413
|
baseUrl?: string;
|
|
401
414
|
/**
|
|
402
415
|
* HTTP request timeout in milliseconds.
|
|
@@ -426,7 +439,7 @@ declare class ObservaSDK {
|
|
|
426
439
|
readonly ingest: IngestApi;
|
|
427
440
|
private readonly http;
|
|
428
441
|
/**
|
|
429
|
-
* Creates an SDK instance with required
|
|
442
|
+
* Creates an SDK instance with required dsnKey and either apiKey or publicKey.
|
|
430
443
|
*/
|
|
431
444
|
constructor(options: ObservaSDKOptions);
|
|
432
445
|
/**
|
package/dist/index.js
CHANGED
|
@@ -121,12 +121,13 @@ var DEFAULT_NORMALIZATION = {
|
|
|
121
121
|
};
|
|
122
122
|
var IngestApi = class {
|
|
123
123
|
/**
|
|
124
|
-
* Creates the ingestion client with an optional default DSN.
|
|
124
|
+
* Creates the ingestion client with an optional default DSN and PublicKey.
|
|
125
125
|
*/
|
|
126
|
-
constructor(http, defaultDsnKey, normalization) {
|
|
126
|
+
constructor(http, defaultDsnKey, normalization, defaultPublicKey) {
|
|
127
127
|
this.http = http;
|
|
128
128
|
this.defaultDsnKey = defaultDsnKey;
|
|
129
129
|
this.normalization = normalization;
|
|
130
|
+
this.defaultPublicKey = defaultPublicKey;
|
|
130
131
|
}
|
|
131
132
|
/**
|
|
132
133
|
* Sends an event to the ingestion backend.
|
|
@@ -134,9 +135,13 @@ var IngestApi = class {
|
|
|
134
135
|
async event(input) {
|
|
135
136
|
ensureDefined(input, "input");
|
|
136
137
|
const dsnKey = input.dsnKey ?? this.defaultDsnKey;
|
|
138
|
+
const publicKey = input.publicKey ?? this.defaultPublicKey;
|
|
137
139
|
ensureDefined(dsnKey, "dsnKey");
|
|
138
140
|
ensureNonEmpty(dsnKey, "dsnKey");
|
|
139
141
|
ensureDefined(input.event, "event");
|
|
142
|
+
if (!this.http.hasApiKey() && !publicKey) {
|
|
143
|
+
throw new ValidationError("publicKey is required when apiKey is not provided");
|
|
144
|
+
}
|
|
140
145
|
if (input.idempotencyKey && input.idempotencyKey.length > 128) {
|
|
141
146
|
throw new ValidationError("idempotencyKey must be at most 128 characters");
|
|
142
147
|
}
|
|
@@ -145,13 +150,16 @@ var IngestApi = class {
|
|
|
145
150
|
if (input.sdkVersion) headers["x-sdk-version"] = input.sdkVersion;
|
|
146
151
|
const { idempotencyKey, sdkVersion, event, ...body } = input;
|
|
147
152
|
const normalizedEvent = normalizeEvent(event, this.normalization);
|
|
148
|
-
|
|
153
|
+
const authMode = this.http.hasApiKey() ? "apiKey" : "none";
|
|
154
|
+
return this.http.post("/ingest/events", { ...body, dsnKey, publicKey, event: normalizedEvent }, { auth: authMode, headers });
|
|
149
155
|
}
|
|
150
|
-
async health(dsnKey) {
|
|
156
|
+
async health(dsnKey, publicKey) {
|
|
151
157
|
const resolvedDsnKey = dsnKey ?? this.defaultDsnKey;
|
|
158
|
+
const resolvedPublicKey = publicKey ?? this.defaultPublicKey;
|
|
152
159
|
ensureDefined(resolvedDsnKey, "dsnKey");
|
|
153
160
|
ensureNonEmpty(resolvedDsnKey, "dsnKey");
|
|
154
|
-
|
|
161
|
+
const authMode = this.http.hasApiKey() ? "apiKey" : "none";
|
|
162
|
+
return this.http.post("/ingest/health", { dsnKey: resolvedDsnKey, publicKey: resolvedPublicKey }, { auth: authMode });
|
|
155
163
|
}
|
|
156
164
|
};
|
|
157
165
|
function normalizeEvent(event, options) {
|
|
@@ -339,6 +347,12 @@ var HttpClient = class {
|
|
|
339
347
|
setApiKey(apiKey) {
|
|
340
348
|
this.apiKey = apiKey;
|
|
341
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* Checks if an API key is configured.
|
|
352
|
+
*/
|
|
353
|
+
hasApiKey() {
|
|
354
|
+
return !!this.apiKey;
|
|
355
|
+
}
|
|
342
356
|
startHealthCheck(healthCheck) {
|
|
343
357
|
if (!this.healthCheckPromise) {
|
|
344
358
|
const promise = healthCheck();
|
|
@@ -512,11 +526,11 @@ var ObservaSDK = class {
|
|
|
512
526
|
ingest;
|
|
513
527
|
http;
|
|
514
528
|
/**
|
|
515
|
-
* Creates an SDK instance with required
|
|
529
|
+
* Creates an SDK instance with required dsnKey and either apiKey or publicKey.
|
|
516
530
|
*/
|
|
517
531
|
constructor(options) {
|
|
518
|
-
if (!options || !options.apiKey || !options.dsnKey) {
|
|
519
|
-
throw new Error("ObservaSDK requires
|
|
532
|
+
if (!options || !options.apiKey && !options.publicKey || !options.dsnKey) {
|
|
533
|
+
throw new Error("ObservaSDK requires dsnKey and either apiKey or publicKey");
|
|
520
534
|
}
|
|
521
535
|
const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
522
536
|
const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`;
|
|
@@ -527,9 +541,9 @@ var ObservaSDK = class {
|
|
|
527
541
|
retry: options.retry,
|
|
528
542
|
headers: options.headers
|
|
529
543
|
});
|
|
530
|
-
this.ingest = new IngestApi(this.http, options.dsnKey, options.ingest);
|
|
544
|
+
this.ingest = new IngestApi(this.http, options.dsnKey, options.ingest, options.publicKey);
|
|
531
545
|
this.uptime = new UptimeApi(this.http, options.dsnKey);
|
|
532
|
-
this.http.startHealthCheck(() => this.ingest.health(options.dsnKey));
|
|
546
|
+
this.http.startHealthCheck(() => this.ingest.health(options.dsnKey, options.publicKey));
|
|
533
547
|
}
|
|
534
548
|
/**
|
|
535
549
|
* Updates the API key used by the SDK at runtime.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apis/ingestApi.ts","../src/http/errors.ts","../src/utils/processContext.ts","../src/utils/validate.ts","../src/apis/uptimeApi.ts","../src/http/httpClient.ts","../src/sdk.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport type { IngestEvent, IngestRequest, IngestResponse, StacktraceFrame } from '../domain/ingest'\nimport { ValidationError } from '../http/errors'\nimport { getProcessContextDynamic, getProcessContextStatic } from '../utils/processContext'\nimport { ensureDefined, ensureNonEmpty } from '../utils/validate'\nimport type { HttpClient } from '../http/httpClient'\n\nexport type IngestNormalizationOptions = {\n schemaVersion?: number\n includeContext?: boolean\n includeSystemContext?: boolean\n includeRuntimeContext?: boolean\n maxEventBytes?: number\n maxFrames?: number\n maxMessageLength?: number\n maxExceptionValueLength?: number\n}\n\nconst DEFAULT_NORMALIZATION: Required<IngestNormalizationOptions> = {\n schemaVersion: 1,\n includeContext: true,\n includeSystemContext: true,\n includeRuntimeContext: true,\n maxEventBytes: 64 * 1024,\n maxFrames: 60,\n maxMessageLength: 4000,\n maxExceptionValueLength: 4000,\n}\n\n/**\n * Event ingestion API.\n */\nexport class IngestApi {\n /**\n * Creates the ingestion client with an optional default DSN.\n */\n constructor(\n private readonly http: HttpClient,\n private readonly defaultDsnKey?: string,\n private readonly normalization?: IngestNormalizationOptions\n ) { }\n\n /**\n * Sends an event to the ingestion backend.\n */\n async event(input: IngestRequest): Promise<IngestResponse> {\n ensureDefined(input, 'input')\n const dsnKey = input.dsnKey ?? this.defaultDsnKey\n ensureDefined(dsnKey, 'dsnKey')\n ensureNonEmpty(dsnKey, 'dsnKey')\n ensureDefined(input.event, 'event')\n if (input.idempotencyKey && input.idempotencyKey.length > 128) {\n throw new ValidationError('idempotencyKey must be at most 128 characters')\n }\n const headers: Record<string, string> = {}\n if (input.idempotencyKey) headers['x-idempotency-key'] = input.idempotencyKey\n if (input.sdkVersion) headers['x-sdk-version'] = input.sdkVersion\n const { idempotencyKey, sdkVersion, event, ...body } = input\n const normalizedEvent = normalizeEvent(event, this.normalization)\n return this.http.post<IngestResponse>('/ingest/events', { ...body, dsnKey, event: normalizedEvent }, { auth: 'apiKey', headers })\n }\n\n async health(dsnKey?: string): Promise<{ ok: boolean }> {\n const resolvedDsnKey = dsnKey ?? this.defaultDsnKey\n ensureDefined(resolvedDsnKey, 'dsnKey')\n ensureNonEmpty(resolvedDsnKey, 'dsnKey')\n return this.http.post<{ ok: boolean }>('/ingest/health', { dsnKey: resolvedDsnKey }, { auth: 'apiKey' })\n }\n}\n\nfunction normalizeEvent(event: IngestEvent, options?: IngestNormalizationOptions): IngestEvent {\n const config = { ...DEFAULT_NORMALIZATION, ...options }\n const normalizedTimestamp = normalizeTimestamp(event.timestamp)\n const normalizedLevel = event.level ? event.level.toLowerCase() : undefined\n const normalizedMessage = event.message ? truncate(event.message, config.maxMessageLength) : undefined\n const normalizedException = normalizeException(event.exception, config)\n if (!normalizedMessage && !normalizedException) {\n throw new ValidationError('event message or exception is required')\n }\n const normalizedContext = normalizeContext(event.context, config)\n const normalizedEvent: IngestEvent = {\n ...event,\n event_id: event.event_id ?? randomUUID(),\n timestamp: normalizedTimestamp,\n schema_version: event.schema_version ?? config.schemaVersion,\n level: normalizedLevel as IngestEvent['level'],\n message: normalizedMessage,\n exception: normalizedException,\n context: normalizedContext,\n }\n return enforceSizeLimit(normalizedEvent, config)\n}\n\nfunction normalizeTimestamp(timestamp?: string) {\n if (!timestamp) return new Date().toISOString()\n const parsed = new Date(timestamp)\n if (Number.isNaN(parsed.getTime())) {\n throw new ValidationError('timestamp must be a valid ISO date')\n }\n return parsed.toISOString()\n}\n\nfunction normalizeException(exception: IngestEvent['exception'], config: Required<IngestNormalizationOptions>) {\n if (!exception) return undefined\n if (!exception.type || !exception.value) {\n throw new ValidationError('exception.type and exception.value are required')\n }\n return {\n ...exception,\n value: truncate(exception.value, config.maxExceptionValueLength),\n stacktrace: normalizeStacktrace(exception.stacktrace, config.maxFrames),\n }\n}\n\nfunction normalizeStacktrace(stacktrace: { frames?: StacktraceFrame[] } | undefined, maxFrames: number) {\n if (!stacktrace || !Array.isArray(stacktrace.frames)) return undefined\n const frames = stacktrace.frames\n const normalizedFrames = frames.slice(0, maxFrames).map((frame) => {\n const filename = typeof frame?.filename === 'string' ? frame.filename : undefined\n const functionName = typeof frame?.function === 'string' ? frame.function : undefined\n const lineno = typeof frame?.lineno === 'number' ? frame.lineno : undefined\n const colno = typeof frame?.colno === 'number' ? frame.colno : undefined\n const inferredInApp = filename ? !filename.includes('node_modules') : false\n return {\n filename,\n function: functionName,\n lineno,\n colno,\n in_app: typeof frame?.in_app === 'boolean' ? frame.in_app : inferredInApp,\n }\n })\n return { frames: normalizedFrames }\n}\n\nfunction normalizeContext(context: IngestEvent['context'] | undefined, config: Required<IngestNormalizationOptions>) {\n if (!config.includeContext) return context\n const systemContext = config.includeSystemContext ? getProcessContextDynamic() : undefined\n const runtimeContext = config.includeRuntimeContext ? getProcessContextStatic({ includeVersions: false }) : undefined\n const mergedContext = {\n ...context,\n system: context?.system ?? systemContext,\n runtime: context?.runtime ?? runtimeContext,\n }\n return mergedContext\n}\n\nfunction enforceSizeLimit(event: IngestEvent, config: Required<IngestNormalizationOptions>) {\n let normalized = event\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n if (normalized.extra) {\n normalized = { ...normalized, extra: undefined }\n }\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n if (normalized.tags) {\n normalized = { ...normalized, tags: undefined }\n }\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n if (normalized.exception?.stacktrace) {\n normalized = {\n ...normalized,\n exception: { ...normalized.exception, stacktrace: undefined },\n }\n }\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n if (normalized.message) {\n normalized = { ...normalized, message: truncate(normalized.message, config.maxMessageLength) }\n }\n if (normalized.exception?.value) {\n normalized = {\n ...normalized,\n exception: { ...normalized.exception, value: truncate(normalized.exception.value, config.maxExceptionValueLength) },\n }\n }\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n throw new ValidationError('event payload exceeds size limit')\n}\n\nfunction getSize(value: unknown) {\n return Buffer.byteLength(JSON.stringify(value), 'utf8')\n}\n\nfunction truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) return value\n return value.slice(0, maxLength)\n}\n","/**\r\n * Additional data to enrich SDK errors.\r\n */\r\nexport type ErrorDetails = {\r\n status?: number\r\n code?: string\r\n details?: unknown\r\n retryAfter?: number\r\n}\r\n\r\n/**\r\n * Base SDK error.\r\n */\r\nexport class SdkError extends Error {\r\n readonly status?: number\r\n readonly code?: string\r\n readonly details?: unknown\r\n\r\n /**\r\n * Creates an error with optional metadata.\r\n */\r\n constructor(message: string, details?: ErrorDetails) {\r\n super(message)\r\n this.name = new.target.name\r\n this.status = details?.status\r\n this.code = details?.code\r\n this.details = details?.details\r\n }\r\n}\r\n\r\n/**\r\n * Input validation error.\r\n */\r\nexport class ValidationError extends SdkError { }\r\n/**\r\n * Authentication error.\r\n */\r\nexport class AuthError extends SdkError { }\r\n/**\r\n * Error caused by insufficient permissions.\r\n */\r\nexport class ForbiddenError extends SdkError { }\r\n/**\r\n * Error when a resource does not exist.\r\n */\r\nexport class NotFoundError extends SdkError { }\r\n/**\r\n * Error caused by a state conflict.\r\n */\r\nexport class ConflictError extends SdkError { }\r\n/**\r\n * Error caused by rate limiting.\r\n */\r\nexport class RateLimitError extends SdkError {\r\n readonly retryAfter?: number\r\n\r\n constructor(message: string, details?: ErrorDetails) {\r\n super(message, details)\r\n this.retryAfter = details?.retryAfter\r\n }\r\n}\r\n/**\r\n * Server-side error.\r\n */\r\nexport class ServerError extends SdkError { }\r\n/**\r\n * Network error.\r\n */\r\nexport class NetworkError extends SdkError { }\r\n/**\r\n * Request timeout error.\r\n */\r\nexport class TimeoutError extends SdkError { }\r\n\r\n/**\r\n * Maps HTTP status codes to typed SDK errors.\r\n */\r\nexport function mapHttpError(status: number, details?: unknown, retryAfter?: number): SdkError {\r\n const info = { status, details, retryAfter }\r\n if (status === 400) return new ValidationError('Invalid request', info)\r\n if (status === 401) return new AuthError('Unauthorized', info)\r\n if (status === 403) return new ForbiddenError('Forbidden', info)\r\n if (status === 404) return new NotFoundError('Resource not found', info)\r\n if (status === 409) return new ConflictError('Conflict', info)\r\n if (status === 429) return new RateLimitError('Rate limit exceeded', info)\r\n if (status >= 500) return new ServerError('Server error', info)\r\n return new SdkError('HTTP error', info)\r\n}\r\n","export type ProcessContextStatic = {\r\n versions?: NodeJS.ProcessVersions\r\n node?: string\r\n platform?: NodeJS.Platform\r\n arch?: string\r\n releaseName?: string\r\n}\r\n\r\nexport type ProcessContextDynamic = {\r\n pid?: number\r\n uptimeSeconds?: number\r\n memory?: NodeJS.MemoryUsage\r\n}\r\n\r\nexport type ProcessContext = ProcessContextStatic & ProcessContextDynamic\r\n\r\nexport type ProcessContextOptions = {\r\n includeStatic?: boolean\r\n includeDynamic?: boolean\r\n includeVersions?: boolean\r\n includeRuntime?: boolean\r\n includePid?: boolean\r\n includeUptime?: boolean\r\n includeMemory?: boolean\r\n}\r\n\r\nexport type ProcessContextStaticOptions = {\r\n includeVersions?: boolean\r\n includeRuntime?: boolean\r\n}\r\n\r\nexport type ProcessContextDynamicOptions = {\r\n includePid?: boolean\r\n includeUptime?: boolean\r\n includeMemory?: boolean\r\n}\r\n\r\nexport function getProcessContext(options?: ProcessContextOptions): ProcessContext {\r\n const includeStatic = options?.includeStatic ?? true\r\n const includeDynamic = options?.includeDynamic ?? true\r\n const includeVersions = options?.includeVersions ?? true\r\n const includeRuntime = options?.includeRuntime ?? true\r\n const includePid = options?.includePid ?? true\r\n const includeUptime = options?.includeUptime ?? true\r\n const includeMemory = options?.includeMemory ?? true\r\n const context: ProcessContext = {}\r\n\r\n if (includeDynamic) {\r\n if (includePid) context.pid = process.pid\r\n if (includeUptime) context.uptimeSeconds = Math.round(process.uptime())\r\n if (includeMemory) context.memory = process.memoryUsage()\r\n }\r\n\r\n if (includeStatic) {\r\n if (includeVersions) context.versions = process.versions\r\n if (includeRuntime) {\r\n context.node = process.versions.node\r\n context.platform = process.platform\r\n context.arch = process.arch\r\n context.releaseName = process.release?.name\r\n }\r\n }\r\n\r\n return context\r\n}\r\n\r\nexport function getProcessContextStatic(options?: ProcessContextStaticOptions): ProcessContextStatic {\r\n return getProcessContext({\r\n includeDynamic: false,\r\n includeStatic: true,\r\n includeVersions: options?.includeVersions,\r\n includeRuntime: options?.includeRuntime,\r\n })\r\n}\r\n\r\nexport function getProcessContextDynamic(options?: ProcessContextDynamicOptions): ProcessContextDynamic {\r\n return getProcessContext({\r\n includeStatic: false,\r\n includeDynamic: true,\r\n includePid: options?.includePid,\r\n includeUptime: options?.includeUptime,\r\n includeMemory: options?.includeMemory,\r\n })\r\n}\r\n","import { ValidationError } from '../http/errors'\n\n/**\n * Ensures a string is present and non-empty.\n */\nexport function ensureNonEmpty(value: string, name: string) {\n if (!value || value.trim().length === 0) {\n throw new ValidationError(`${name} is required`)\n }\n}\n\n/**\n * Ensures a value is neither null nor undefined.\n */\nexport function ensureDefined<T>(value: T | null | undefined, name: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new ValidationError(`${name} is required`)\n }\n}\n","import type { UptimeEvent, UptimeHeartbeatInput, UptimeSummary } from '../domain/uptime'\nimport { ensureDefined, ensureNonEmpty } from '../utils/validate'\nimport type { HttpClient } from '../http/httpClient'\n\n/**\n * Uptime API for heartbeats and public reads.\n */\nexport class UptimeApi {\n /**\n * Creates the uptime client with an optional default DSN.\n */\n constructor(private readonly http: HttpClient, private readonly defaultDsnKey?: string) { }\n\n /**\n * Records an uptime heartbeat.\n */\n async recordHeartbeat(input: UptimeHeartbeatInput): Promise<UptimeEvent> {\n ensureDefined(input, 'input')\n const dsnKey = input.dsnKey ?? this.defaultDsnKey\n ensureDefined(dsnKey, 'dsnKey')\n ensureNonEmpty(dsnKey, 'dsnKey')\n ensureNonEmpty(input.status, 'status')\n return this.http.post<UptimeEvent>('/uptime/heartbeats', { ...input, dsnKey }, { auth: 'apiKey' })\n }\n\n /**\n * Lists a project's daily uptime history.\n */\n async history(projectId: string, date: string): Promise<UptimeEvent[]> {\n ensureNonEmpty(projectId, 'projectId')\n ensureNonEmpty(date, 'date')\n return this.http.get<UptimeEvent[]>(`/projects/${encodeURIComponent(projectId)}/uptime/history`, {\n query: { date },\n auth: 'none',\n })\n }\n\n /**\n * Gets the latest uptime event for a project.\n */\n async latest(projectId: string): Promise<UptimeEvent | null> {\n ensureNonEmpty(projectId, 'projectId')\n return this.http.get<UptimeEvent | null>(`/projects/${encodeURIComponent(projectId)}/uptime/latest`, {\n auth: 'none',\n })\n }\n\n /**\n * Summarizes daily uptime.\n */\n async summary(projectId: string, days?: number, delayThresholdMinutes?: number): Promise<UptimeSummary[]> {\n ensureNonEmpty(projectId, 'projectId')\n return this.http.get<UptimeSummary[]>(`/projects/${encodeURIComponent(projectId)}/uptime/summary`, {\n query: { days, delayThresholdMinutes },\n auth: 'none',\n })\n }\n}\n","import { AuthError, NetworkError, TimeoutError, mapHttpError } from './errors'\n\n/**\n * Authentication mode per request.\n */\nexport type AuthMode = 'apiKey' | 'none'\n/**\n * Supported HTTP methods.\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n/**\n * Serializable query parameters.\n */\nexport type QueryParams = Record<string, string | number | boolean | undefined>\n\n/**\n * Retry policy for transient errors.\n */\nexport type RetryPolicy = {\n /**\n * Number of additional retries.\n */\n retries: number\n /**\n * Computes the delay between retries.\n */\n retryDelayMs?: (attempt: number, response?: Response, error?: unknown) => number\n /**\n * Determines whether a response or error should be retried.\n */\n retryOn?: (response?: Response, error?: unknown) => boolean\n}\n\n/**\n * Base HTTP client configuration.\n */\nexport type HttpClientOptions = {\n /**\n * Backend base URL.\n */\n baseUrl: string\n /**\n * API key used for SDK authentication.\n */\n apiKey?: string\n /**\n * Request timeout in milliseconds.\n */\n timeoutMs?: number\n /**\n * Global headers.\n */\n headers?: Record<string, string>\n /**\n * Retry policy.\n */\n retry?: RetryPolicy\n}\n\n/**\n * Per-request options.\n */\nexport type RequestOptions = {\n method: HttpMethod\n path: string\n query?: QueryParams\n body?: unknown\n headers?: Record<string, string>\n /**\n * Defines whether the request requires an apiKey or is public.\n */\n auth?: AuthMode\n}\n\n/**\n * Base HTTP client for the SDK.\n */\nexport class HttpClient {\n private apiKey?: string\n private readonly baseUrl: string\n private readonly timeoutMs: number\n private readonly headers: Record<string, string>\n private readonly retry?: RetryPolicy\n private healthCheckPromise?: Promise<unknown>\n\n /**\n * Creates an HTTP client with baseUrl and optional apiKey.\n */\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.apiKey = options.apiKey\n this.timeoutMs = options.timeoutMs ?? 5000\n this.headers = options.headers ?? {}\n this.retry = options.retry\n }\n\n /**\n * Updates the API key at runtime.\n */\n setApiKey(apiKey?: string) {\n this.apiKey = apiKey\n }\n\n startHealthCheck(healthCheck: () => Promise<unknown>) {\n if (!this.healthCheckPromise) {\n const promise = healthCheck()\n this.healthCheckPromise = promise\n promise.catch(() => undefined)\n }\n }\n\n /**\n * GET request.\n */\n async get<T>(path: string, options?: Omit<RequestOptions, 'method' | 'path'>): Promise<T> {\n return this.request<T>({ method: 'GET', path, ...options })\n }\n\n /**\n * POST request.\n */\n async post<T>(path: string, body?: unknown, options?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<T> {\n return this.request<T>({ method: 'POST', path, body, ...options })\n }\n\n /**\n * PUT request.\n */\n async put<T>(path: string, body?: unknown, options?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<T> {\n return this.request<T>({ method: 'PUT', path, body, ...options })\n }\n\n /**\n * PATCH request.\n */\n async patch<T>(path: string, body?: unknown, options?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<T> {\n return this.request<T>({ method: 'PATCH', path, body, ...options })\n }\n\n /**\n * DELETE request.\n */\n async delete<T>(path: string, options?: Omit<RequestOptions, 'method' | 'path'>): Promise<T> {\n return this.request<T>({ method: 'DELETE', path, ...options })\n }\n\n /**\n * Executes a request with retry logic.\n */\n async request<T>(options: RequestOptions): Promise<T> {\n if (this.healthCheckPromise) {\n await this.healthCheckPromise\n }\n const retry = this.retry ?? { retries: 0 }\n const retryOn = retry.retryOn ?? ((response?: Response, error?: unknown) => {\n if (response) return response.status === 429 || response.status >= 500\n return error instanceof NetworkError || error instanceof TimeoutError || error instanceof TypeError\n })\n const retryDelayMs = retry.retryDelayMs ?? ((attempt: number) => Math.min(1000 * 2 ** (attempt - 1), 8000))\n let lastError: unknown\n\n for (let attempt = 0; attempt <= retry.retries; attempt += 1) {\n try {\n const { response, data } = await this.execute(options)\n if (!response.ok) {\n const retryAfter = this.parseRetryAfter(response.headers.get('retry-after'))\n const error = mapHttpError(response.status, data, retryAfter)\n if (retryOn(response, error) && attempt < retry.retries) {\n await this.delay(retryDelayMs(attempt + 1, response, error))\n continue\n }\n throw error\n }\n return data as T\n } catch (error) {\n lastError = error\n if (retryOn(undefined, error) && attempt < retry.retries) {\n await this.delay(retryDelayMs(attempt + 1, undefined, error))\n continue\n }\n throw error\n }\n }\n\n throw lastError\n }\n\n /**\n * Executes a request without retry and returns response + data.\n */\n private async execute(options: RequestOptions): Promise<{ response: Response; data: unknown }> {\n const url = this.buildUrl(options.path, options.query)\n const headers: Record<string, string> = { ...this.headers, ...options.headers }\n if (options.body !== undefined) headers['content-type'] = 'application/json'\n const authMode = options.auth ?? 'none'\n if (authMode === 'apiKey') {\n if (!this.apiKey) throw new AuthError('API key is required')\n headers['x-api-key'] = this.apiKey\n }\n\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), this.timeoutMs)\n\n try {\n const response = await fetch(url, {\n method: options.method,\n headers,\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n signal: controller.signal,\n })\n const data = await this.readBody(response)\n return { response, data }\n } catch (error: any) {\n if (error?.name === 'AbortError') {\n throw new TimeoutError('Request timeout')\n }\n if (error instanceof NetworkError || error instanceof TimeoutError) throw error\n if (error instanceof Error) {\n if (error instanceof AuthError) throw error\n }\n if (error instanceof Error && 'status' in error) throw error\n throw new NetworkError('Network error', { details: error })\n } finally {\n clearTimeout(timer)\n }\n }\n\n /**\n * Builds the final URL with query params.\n */\n private buildUrl(path: string, query?: QueryParams): string {\n const base = this.baseUrl\n const fullPath = path.startsWith('http') ? path : `${base}${path.startsWith('/') ? '' : '/'}${path}`\n if (!query) return fullPath\n const params = new URLSearchParams()\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) continue\n params.set(key, String(value))\n }\n const suffix = params.toString()\n return suffix ? `${fullPath}?${suffix}` : fullPath\n }\n\n /**\n * Parses the body as JSON when possible.\n */\n private async readBody(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined\n const text = await response.text()\n if (!text) return undefined\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n }\n\n private parseRetryAfter(value: string | null): number | undefined {\n if (!value) return undefined\n const seconds = Number(value)\n if (!Number.isNaN(seconds) && Number.isFinite(seconds)) {\n return Math.max(0, seconds)\n }\n const parsedDate = Date.parse(value)\n if (Number.isNaN(parsedDate)) return undefined\n const diffMs = parsedDate - Date.now()\n if (diffMs <= 0) return 0\n return Math.ceil(diffMs / 1000)\n }\n\n /**\n * Simple delay for retries.\n */\n private async delay(ms: number): Promise<void> {\n await new Promise(resolve => setTimeout(resolve, ms))\n }\n}\n","import { IngestApi, type IngestNormalizationOptions } from './apis/ingestApi'\nimport { UptimeApi } from './apis/uptimeApi'\nimport { HttpClient, type RetryPolicy } from './http/httpClient'\nimport {\n getProcessContext,\n getProcessContextDynamic,\n getProcessContextStatic,\n type ProcessContext,\n type ProcessContextDynamic,\n type ProcessContextDynamicOptions,\n type ProcessContextOptions,\n type ProcessContextStatic,\n type ProcessContextStaticOptions,\n} from './utils/processContext'\n\n/**\n * SDK configuration options.\n */\nexport type ObservaSDKOptions = {\n /**\n * Organization API key used to authenticate SDK requests.\n */\n apiKey: string\n /**\n * Project DSN used to identify the destination of events and heartbeats.\n */\n dsnKey: string\n baseUrl?: string\n /**\n * HTTP request timeout in milliseconds.\n */\n timeoutMs?: number\n /**\n * Retry policy for transient errors.\n */\n retry?: RetryPolicy\n /**\n * Additional headers sent with every request.\n */\n headers?: Record<string, string>\n ingest?: IngestNormalizationOptions\n}\n\n/**\n * Fixed backend target for the SDK.\n */\nconst DEFAULT_BASE_URL = 'https://backend-observa-production.up.railway.app/v1'\n\n/**\n * Main SDK for error ingestion and uptime heartbeats.\n */\nexport class ObservaSDK {\n /**\n * Uptime API (heartbeats and public reads).\n */\n readonly uptime: UptimeApi\n /**\n * Event ingestion API.\n */\n readonly ingest: IngestApi\n\n private readonly http: HttpClient\n\n /**\n * Creates an SDK instance with required apiKey and dsnKey.\n */\n constructor(options: ObservaSDKOptions) {\n if (!options || !options.apiKey || !options.dsnKey) {\n throw new Error('ObservaSDK requires both apiKey and dsnKey')\n }\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '')\n const normalizedBaseUrl = baseUrl.endsWith('/v1') ? baseUrl : `${baseUrl}/v1`\n this.http = new HttpClient({\n baseUrl: normalizedBaseUrl,\n apiKey: options.apiKey,\n timeoutMs: options.timeoutMs,\n retry: options.retry,\n headers: options.headers,\n })\n this.ingest = new IngestApi(this.http, options.dsnKey, options.ingest)\n this.uptime = new UptimeApi(this.http, options.dsnKey)\n this.http.startHealthCheck(() => this.ingest.health(options.dsnKey))\n }\n\n /**\n * Updates the API key used by the SDK at runtime.\n */\n setApiKey(apiKey: string) {\n this.http.setApiKey(apiKey)\n }\n\n getProcessContext(options?: ProcessContextOptions): ProcessContext {\n return getProcessContext(options)\n }\n\n getProcessContextStatic(options?: ProcessContextStaticOptions): ProcessContextStatic {\n return getProcessContextStatic(options)\n }\n\n getProcessContextDynamic(options?: ProcessContextDynamicOptions): ProcessContextDynamic {\n return getProcessContextDynamic(options)\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/apis/ingestApi.ts","../src/http/errors.ts","../src/utils/processContext.ts","../src/utils/validate.ts","../src/apis/uptimeApi.ts","../src/http/httpClient.ts","../src/sdk.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport type { IngestEvent, IngestRequest, IngestResponse, StacktraceFrame } from '../domain/ingest'\nimport { ValidationError } from '../http/errors'\nimport { getProcessContextDynamic, getProcessContextStatic } from '../utils/processContext'\nimport { ensureDefined, ensureNonEmpty } from '../utils/validate'\nimport type { HttpClient } from '../http/httpClient'\n\nexport type IngestNormalizationOptions = {\n schemaVersion?: number\n includeContext?: boolean\n includeSystemContext?: boolean\n includeRuntimeContext?: boolean\n maxEventBytes?: number\n maxFrames?: number\n maxMessageLength?: number\n maxExceptionValueLength?: number\n}\n\nconst DEFAULT_NORMALIZATION: Required<IngestNormalizationOptions> = {\n schemaVersion: 1,\n includeContext: true,\n includeSystemContext: true,\n includeRuntimeContext: true,\n maxEventBytes: 64 * 1024,\n maxFrames: 60,\n maxMessageLength: 4000,\n maxExceptionValueLength: 4000,\n}\n\n/**\n * Event ingestion API.\n */\nexport class IngestApi {\n /**\n * Creates the ingestion client with an optional default DSN and PublicKey.\n */\n constructor(\n private readonly http: HttpClient,\n private readonly defaultDsnKey?: string,\n private readonly normalization?: IngestNormalizationOptions,\n private readonly defaultPublicKey?: string\n ) { }\n\n /**\n * Sends an event to the ingestion backend.\n */\n async event(input: IngestRequest): Promise<IngestResponse> {\n ensureDefined(input, 'input')\n const dsnKey = input.dsnKey ?? this.defaultDsnKey\n const publicKey = input.publicKey ?? this.defaultPublicKey\n\n ensureDefined(dsnKey, 'dsnKey')\n ensureNonEmpty(dsnKey, 'dsnKey')\n ensureDefined(input.event, 'event')\n\n if (!this.http.hasApiKey() && !publicKey) {\n throw new ValidationError('publicKey is required when apiKey is not provided')\n }\n\n if (input.idempotencyKey && input.idempotencyKey.length > 128) {\n throw new ValidationError('idempotencyKey must be at most 128 characters')\n }\n const headers: Record<string, string> = {}\n if (input.idempotencyKey) headers['x-idempotency-key'] = input.idempotencyKey\n if (input.sdkVersion) headers['x-sdk-version'] = input.sdkVersion\n const { idempotencyKey, sdkVersion, event, ...body } = input\n const normalizedEvent = normalizeEvent(event, this.normalization)\n \n const authMode = this.http.hasApiKey() ? 'apiKey' : 'none'\n return this.http.post<IngestResponse>('/ingest/events', { ...body, dsnKey, publicKey, event: normalizedEvent }, { auth: authMode, headers })\n }\n\n async health(dsnKey?: string, publicKey?: string): Promise<{ ok: boolean }> {\n const resolvedDsnKey = dsnKey ?? this.defaultDsnKey\n const resolvedPublicKey = publicKey ?? this.defaultPublicKey\n\n ensureDefined(resolvedDsnKey, 'dsnKey')\n ensureNonEmpty(resolvedDsnKey, 'dsnKey')\n \n const authMode = this.http.hasApiKey() ? 'apiKey' : 'none'\n return this.http.post<{ ok: boolean }>('/ingest/health', { dsnKey: resolvedDsnKey, publicKey: resolvedPublicKey }, { auth: authMode })\n }\n}\n\nfunction normalizeEvent(event: IngestEvent, options?: IngestNormalizationOptions): IngestEvent {\n const config = { ...DEFAULT_NORMALIZATION, ...options }\n const normalizedTimestamp = normalizeTimestamp(event.timestamp)\n const normalizedLevel = event.level ? event.level.toLowerCase() : undefined\n const normalizedMessage = event.message ? truncate(event.message, config.maxMessageLength) : undefined\n const normalizedException = normalizeException(event.exception, config)\n if (!normalizedMessage && !normalizedException) {\n throw new ValidationError('event message or exception is required')\n }\n const normalizedContext = normalizeContext(event.context, config)\n const normalizedEvent: IngestEvent = {\n ...event,\n event_id: event.event_id ?? randomUUID(),\n timestamp: normalizedTimestamp,\n schema_version: event.schema_version ?? config.schemaVersion,\n level: normalizedLevel as IngestEvent['level'],\n message: normalizedMessage,\n exception: normalizedException,\n context: normalizedContext,\n }\n return enforceSizeLimit(normalizedEvent, config)\n}\n\nfunction normalizeTimestamp(timestamp?: string) {\n if (!timestamp) return new Date().toISOString()\n const parsed = new Date(timestamp)\n if (Number.isNaN(parsed.getTime())) {\n throw new ValidationError('timestamp must be a valid ISO date')\n }\n return parsed.toISOString()\n}\n\nfunction normalizeException(exception: IngestEvent['exception'], config: Required<IngestNormalizationOptions>) {\n if (!exception) return undefined\n if (!exception.type || !exception.value) {\n throw new ValidationError('exception.type and exception.value are required')\n }\n return {\n ...exception,\n value: truncate(exception.value, config.maxExceptionValueLength),\n stacktrace: normalizeStacktrace(exception.stacktrace, config.maxFrames),\n }\n}\n\nfunction normalizeStacktrace(stacktrace: { frames?: StacktraceFrame[] } | undefined, maxFrames: number) {\n if (!stacktrace || !Array.isArray(stacktrace.frames)) return undefined\n const frames = stacktrace.frames\n const normalizedFrames = frames.slice(0, maxFrames).map((frame) => {\n const filename = typeof frame?.filename === 'string' ? frame.filename : undefined\n const functionName = typeof frame?.function === 'string' ? frame.function : undefined\n const lineno = typeof frame?.lineno === 'number' ? frame.lineno : undefined\n const colno = typeof frame?.colno === 'number' ? frame.colno : undefined\n const inferredInApp = filename ? !filename.includes('node_modules') : false\n return {\n filename,\n function: functionName,\n lineno,\n colno,\n in_app: typeof frame?.in_app === 'boolean' ? frame.in_app : inferredInApp,\n }\n })\n return { frames: normalizedFrames }\n}\n\nfunction normalizeContext(context: IngestEvent['context'] | undefined, config: Required<IngestNormalizationOptions>) {\n if (!config.includeContext) return context\n const systemContext = config.includeSystemContext ? getProcessContextDynamic() : undefined\n const runtimeContext = config.includeRuntimeContext ? getProcessContextStatic({ includeVersions: false }) : undefined\n const mergedContext = {\n ...context,\n system: context?.system ?? systemContext,\n runtime: context?.runtime ?? runtimeContext,\n }\n return mergedContext\n}\n\nfunction enforceSizeLimit(event: IngestEvent, config: Required<IngestNormalizationOptions>) {\n let normalized = event\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n if (normalized.extra) {\n normalized = { ...normalized, extra: undefined }\n }\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n if (normalized.tags) {\n normalized = { ...normalized, tags: undefined }\n }\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n if (normalized.exception?.stacktrace) {\n normalized = {\n ...normalized,\n exception: { ...normalized.exception, stacktrace: undefined },\n }\n }\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n if (normalized.message) {\n normalized = { ...normalized, message: truncate(normalized.message, config.maxMessageLength) }\n }\n if (normalized.exception?.value) {\n normalized = {\n ...normalized,\n exception: { ...normalized.exception, value: truncate(normalized.exception.value, config.maxExceptionValueLength) },\n }\n }\n if (getSize(normalized) <= config.maxEventBytes) return normalized\n throw new ValidationError('event payload exceeds size limit')\n}\n\nfunction getSize(value: unknown) {\n return Buffer.byteLength(JSON.stringify(value), 'utf8')\n}\n\nfunction truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) return value\n return value.slice(0, maxLength)\n}\n","/**\r\n * Additional data to enrich SDK errors.\r\n */\r\nexport type ErrorDetails = {\r\n status?: number\r\n code?: string\r\n details?: unknown\r\n retryAfter?: number\r\n}\r\n\r\n/**\r\n * Base SDK error.\r\n */\r\nexport class SdkError extends Error {\r\n readonly status?: number\r\n readonly code?: string\r\n readonly details?: unknown\r\n\r\n /**\r\n * Creates an error with optional metadata.\r\n */\r\n constructor(message: string, details?: ErrorDetails) {\r\n super(message)\r\n this.name = new.target.name\r\n this.status = details?.status\r\n this.code = details?.code\r\n this.details = details?.details\r\n }\r\n}\r\n\r\n/**\r\n * Input validation error.\r\n */\r\nexport class ValidationError extends SdkError { }\r\n/**\r\n * Authentication error.\r\n */\r\nexport class AuthError extends SdkError { }\r\n/**\r\n * Error caused by insufficient permissions.\r\n */\r\nexport class ForbiddenError extends SdkError { }\r\n/**\r\n * Error when a resource does not exist.\r\n */\r\nexport class NotFoundError extends SdkError { }\r\n/**\r\n * Error caused by a state conflict.\r\n */\r\nexport class ConflictError extends SdkError { }\r\n/**\r\n * Error caused by rate limiting.\r\n */\r\nexport class RateLimitError extends SdkError {\r\n readonly retryAfter?: number\r\n\r\n constructor(message: string, details?: ErrorDetails) {\r\n super(message, details)\r\n this.retryAfter = details?.retryAfter\r\n }\r\n}\r\n/**\r\n * Server-side error.\r\n */\r\nexport class ServerError extends SdkError { }\r\n/**\r\n * Network error.\r\n */\r\nexport class NetworkError extends SdkError { }\r\n/**\r\n * Request timeout error.\r\n */\r\nexport class TimeoutError extends SdkError { }\r\n\r\n/**\r\n * Maps HTTP status codes to typed SDK errors.\r\n */\r\nexport function mapHttpError(status: number, details?: unknown, retryAfter?: number): SdkError {\r\n const info = { status, details, retryAfter }\r\n if (status === 400) return new ValidationError('Invalid request', info)\r\n if (status === 401) return new AuthError('Unauthorized', info)\r\n if (status === 403) return new ForbiddenError('Forbidden', info)\r\n if (status === 404) return new NotFoundError('Resource not found', info)\r\n if (status === 409) return new ConflictError('Conflict', info)\r\n if (status === 429) return new RateLimitError('Rate limit exceeded', info)\r\n if (status >= 500) return new ServerError('Server error', info)\r\n return new SdkError('HTTP error', info)\r\n}\r\n","export type ProcessContextStatic = {\r\n versions?: NodeJS.ProcessVersions\r\n node?: string\r\n platform?: NodeJS.Platform\r\n arch?: string\r\n releaseName?: string\r\n}\r\n\r\nexport type ProcessContextDynamic = {\r\n pid?: number\r\n uptimeSeconds?: number\r\n memory?: NodeJS.MemoryUsage\r\n}\r\n\r\nexport type ProcessContext = ProcessContextStatic & ProcessContextDynamic\r\n\r\nexport type ProcessContextOptions = {\r\n includeStatic?: boolean\r\n includeDynamic?: boolean\r\n includeVersions?: boolean\r\n includeRuntime?: boolean\r\n includePid?: boolean\r\n includeUptime?: boolean\r\n includeMemory?: boolean\r\n}\r\n\r\nexport type ProcessContextStaticOptions = {\r\n includeVersions?: boolean\r\n includeRuntime?: boolean\r\n}\r\n\r\nexport type ProcessContextDynamicOptions = {\r\n includePid?: boolean\r\n includeUptime?: boolean\r\n includeMemory?: boolean\r\n}\r\n\r\nexport function getProcessContext(options?: ProcessContextOptions): ProcessContext {\r\n const includeStatic = options?.includeStatic ?? true\r\n const includeDynamic = options?.includeDynamic ?? true\r\n const includeVersions = options?.includeVersions ?? true\r\n const includeRuntime = options?.includeRuntime ?? true\r\n const includePid = options?.includePid ?? true\r\n const includeUptime = options?.includeUptime ?? true\r\n const includeMemory = options?.includeMemory ?? true\r\n const context: ProcessContext = {}\r\n\r\n if (includeDynamic) {\r\n if (includePid) context.pid = process.pid\r\n if (includeUptime) context.uptimeSeconds = Math.round(process.uptime())\r\n if (includeMemory) context.memory = process.memoryUsage()\r\n }\r\n\r\n if (includeStatic) {\r\n if (includeVersions) context.versions = process.versions\r\n if (includeRuntime) {\r\n context.node = process.versions.node\r\n context.platform = process.platform\r\n context.arch = process.arch\r\n context.releaseName = process.release?.name\r\n }\r\n }\r\n\r\n return context\r\n}\r\n\r\nexport function getProcessContextStatic(options?: ProcessContextStaticOptions): ProcessContextStatic {\r\n return getProcessContext({\r\n includeDynamic: false,\r\n includeStatic: true,\r\n includeVersions: options?.includeVersions,\r\n includeRuntime: options?.includeRuntime,\r\n })\r\n}\r\n\r\nexport function getProcessContextDynamic(options?: ProcessContextDynamicOptions): ProcessContextDynamic {\r\n return getProcessContext({\r\n includeStatic: false,\r\n includeDynamic: true,\r\n includePid: options?.includePid,\r\n includeUptime: options?.includeUptime,\r\n includeMemory: options?.includeMemory,\r\n })\r\n}\r\n","import { ValidationError } from '../http/errors'\n\n/**\n * Ensures a string is present and non-empty.\n */\nexport function ensureNonEmpty(value: string, name: string) {\n if (!value || value.trim().length === 0) {\n throw new ValidationError(`${name} is required`)\n }\n}\n\n/**\n * Ensures a value is neither null nor undefined.\n */\nexport function ensureDefined<T>(value: T | null | undefined, name: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new ValidationError(`${name} is required`)\n }\n}\n","import type { UptimeEvent, UptimeHeartbeatInput, UptimeSummary } from '../domain/uptime'\nimport { ensureDefined, ensureNonEmpty } from '../utils/validate'\nimport type { HttpClient } from '../http/httpClient'\n\n/**\n * Uptime API for heartbeats and public reads.\n */\nexport class UptimeApi {\n /**\n * Creates the uptime client with an optional default DSN.\n */\n constructor(private readonly http: HttpClient, private readonly defaultDsnKey?: string) { }\n\n /**\n * Records an uptime heartbeat.\n */\n async recordHeartbeat(input: UptimeHeartbeatInput): Promise<UptimeEvent> {\n ensureDefined(input, 'input')\n const dsnKey = input.dsnKey ?? this.defaultDsnKey\n ensureDefined(dsnKey, 'dsnKey')\n ensureNonEmpty(dsnKey, 'dsnKey')\n ensureNonEmpty(input.status, 'status')\n return this.http.post<UptimeEvent>('/uptime/heartbeats', { ...input, dsnKey }, { auth: 'apiKey' })\n }\n\n /**\n * Lists a project's daily uptime history.\n */\n async history(projectId: string, date: string): Promise<UptimeEvent[]> {\n ensureNonEmpty(projectId, 'projectId')\n ensureNonEmpty(date, 'date')\n return this.http.get<UptimeEvent[]>(`/projects/${encodeURIComponent(projectId)}/uptime/history`, {\n query: { date },\n auth: 'none',\n })\n }\n\n /**\n * Gets the latest uptime event for a project.\n */\n async latest(projectId: string): Promise<UptimeEvent | null> {\n ensureNonEmpty(projectId, 'projectId')\n return this.http.get<UptimeEvent | null>(`/projects/${encodeURIComponent(projectId)}/uptime/latest`, {\n auth: 'none',\n })\n }\n\n /**\n * Summarizes daily uptime.\n */\n async summary(projectId: string, days?: number, delayThresholdMinutes?: number): Promise<UptimeSummary[]> {\n ensureNonEmpty(projectId, 'projectId')\n return this.http.get<UptimeSummary[]>(`/projects/${encodeURIComponent(projectId)}/uptime/summary`, {\n query: { days, delayThresholdMinutes },\n auth: 'none',\n })\n }\n}\n","import { AuthError, NetworkError, TimeoutError, mapHttpError } from './errors'\n\n/**\n * Authentication mode per request.\n */\nexport type AuthMode = 'apiKey' | 'none'\n/**\n * Supported HTTP methods.\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n/**\n * Serializable query parameters.\n */\nexport type QueryParams = Record<string, string | number | boolean | undefined>\n\n/**\n * Retry policy for transient errors.\n */\nexport type RetryPolicy = {\n /**\n * Number of additional retries.\n */\n retries: number\n /**\n * Computes the delay between retries.\n */\n retryDelayMs?: (attempt: number, response?: Response, error?: unknown) => number\n /**\n * Determines whether a response or error should be retried.\n */\n retryOn?: (response?: Response, error?: unknown) => boolean\n}\n\n/**\n * Base HTTP client configuration.\n */\nexport type HttpClientOptions = {\n /**\n * Backend base URL.\n */\n baseUrl: string\n /**\n * API key used for SDK authentication.\n */\n apiKey?: string\n /**\n * Request timeout in milliseconds.\n */\n timeoutMs?: number\n /**\n * Global headers.\n */\n headers?: Record<string, string>\n /**\n * Retry policy.\n */\n retry?: RetryPolicy\n}\n\n/**\n * Per-request options.\n */\nexport type RequestOptions = {\n method: HttpMethod\n path: string\n query?: QueryParams\n body?: unknown\n headers?: Record<string, string>\n /**\n * Defines whether the request requires an apiKey or is public.\n */\n auth?: AuthMode\n}\n\n/**\n * Base HTTP client for the SDK.\n */\nexport class HttpClient {\n private apiKey?: string\n private readonly baseUrl: string\n private readonly timeoutMs: number\n private readonly headers: Record<string, string>\n private readonly retry?: RetryPolicy\n private healthCheckPromise?: Promise<unknown>\n\n /**\n * Creates an HTTP client with baseUrl and optional apiKey.\n */\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.apiKey = options.apiKey\n this.timeoutMs = options.timeoutMs ?? 5000\n this.headers = options.headers ?? {}\n this.retry = options.retry\n }\n\n /**\n * Updates the API key at runtime.\n */\n setApiKey(apiKey?: string) {\n this.apiKey = apiKey\n }\n\n /**\n * Checks if an API key is configured.\n */\n hasApiKey(): boolean {\n return !!this.apiKey\n }\n\n startHealthCheck(healthCheck: () => Promise<unknown>) {\n if (!this.healthCheckPromise) {\n const promise = healthCheck()\n this.healthCheckPromise = promise\n promise.catch(() => undefined)\n }\n }\n\n /**\n * GET request.\n */\n async get<T>(path: string, options?: Omit<RequestOptions, 'method' | 'path'>): Promise<T> {\n return this.request<T>({ method: 'GET', path, ...options })\n }\n\n /**\n * POST request.\n */\n async post<T>(path: string, body?: unknown, options?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<T> {\n return this.request<T>({ method: 'POST', path, body, ...options })\n }\n\n /**\n * PUT request.\n */\n async put<T>(path: string, body?: unknown, options?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<T> {\n return this.request<T>({ method: 'PUT', path, body, ...options })\n }\n\n /**\n * PATCH request.\n */\n async patch<T>(path: string, body?: unknown, options?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<T> {\n return this.request<T>({ method: 'PATCH', path, body, ...options })\n }\n\n /**\n * DELETE request.\n */\n async delete<T>(path: string, options?: Omit<RequestOptions, 'method' | 'path'>): Promise<T> {\n return this.request<T>({ method: 'DELETE', path, ...options })\n }\n\n /**\n * Executes a request with retry logic.\n */\n async request<T>(options: RequestOptions): Promise<T> {\n if (this.healthCheckPromise) {\n await this.healthCheckPromise\n }\n const retry = this.retry ?? { retries: 0 }\n const retryOn = retry.retryOn ?? ((response?: Response, error?: unknown) => {\n if (response) return response.status === 429 || response.status >= 500\n return error instanceof NetworkError || error instanceof TimeoutError || error instanceof TypeError\n })\n const retryDelayMs = retry.retryDelayMs ?? ((attempt: number) => Math.min(1000 * 2 ** (attempt - 1), 8000))\n let lastError: unknown\n\n for (let attempt = 0; attempt <= retry.retries; attempt += 1) {\n try {\n const { response, data } = await this.execute(options)\n if (!response.ok) {\n const retryAfter = this.parseRetryAfter(response.headers.get('retry-after'))\n const error = mapHttpError(response.status, data, retryAfter)\n if (retryOn(response, error) && attempt < retry.retries) {\n await this.delay(retryDelayMs(attempt + 1, response, error))\n continue\n }\n throw error\n }\n return data as T\n } catch (error) {\n lastError = error\n if (retryOn(undefined, error) && attempt < retry.retries) {\n await this.delay(retryDelayMs(attempt + 1, undefined, error))\n continue\n }\n throw error\n }\n }\n\n throw lastError\n }\n\n /**\n * Executes a request without retry and returns response + data.\n */\n private async execute(options: RequestOptions): Promise<{ response: Response; data: unknown }> {\n const url = this.buildUrl(options.path, options.query)\n const headers: Record<string, string> = { ...this.headers, ...options.headers }\n if (options.body !== undefined) headers['content-type'] = 'application/json'\n const authMode = options.auth ?? 'none'\n if (authMode === 'apiKey') {\n if (!this.apiKey) throw new AuthError('API key is required')\n headers['x-api-key'] = this.apiKey\n }\n\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), this.timeoutMs)\n\n try {\n const response = await fetch(url, {\n method: options.method,\n headers,\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n signal: controller.signal,\n })\n const data = await this.readBody(response)\n return { response, data }\n } catch (error: any) {\n if (error?.name === 'AbortError') {\n throw new TimeoutError('Request timeout')\n }\n if (error instanceof NetworkError || error instanceof TimeoutError) throw error\n if (error instanceof Error) {\n if (error instanceof AuthError) throw error\n }\n if (error instanceof Error && 'status' in error) throw error\n throw new NetworkError('Network error', { details: error })\n } finally {\n clearTimeout(timer)\n }\n }\n\n /**\n * Builds the final URL with query params.\n */\n private buildUrl(path: string, query?: QueryParams): string {\n const base = this.baseUrl\n const fullPath = path.startsWith('http') ? path : `${base}${path.startsWith('/') ? '' : '/'}${path}`\n if (!query) return fullPath\n const params = new URLSearchParams()\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) continue\n params.set(key, String(value))\n }\n const suffix = params.toString()\n return suffix ? `${fullPath}?${suffix}` : fullPath\n }\n\n /**\n * Parses the body as JSON when possible.\n */\n private async readBody(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined\n const text = await response.text()\n if (!text) return undefined\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n }\n\n private parseRetryAfter(value: string | null): number | undefined {\n if (!value) return undefined\n const seconds = Number(value)\n if (!Number.isNaN(seconds) && Number.isFinite(seconds)) {\n return Math.max(0, seconds)\n }\n const parsedDate = Date.parse(value)\n if (Number.isNaN(parsedDate)) return undefined\n const diffMs = parsedDate - Date.now()\n if (diffMs <= 0) return 0\n return Math.ceil(diffMs / 1000)\n }\n\n /**\n * Simple delay for retries.\n */\n private async delay(ms: number): Promise<void> {\n await new Promise(resolve => setTimeout(resolve, ms))\n }\n}\n","import { IngestApi, type IngestNormalizationOptions } from './apis/ingestApi'\nimport { UptimeApi } from './apis/uptimeApi'\nimport { HttpClient, type RetryPolicy } from './http/httpClient'\nimport {\n getProcessContext,\n getProcessContextDynamic,\n getProcessContextStatic,\n type ProcessContext,\n type ProcessContextDynamic,\n type ProcessContextDynamicOptions,\n type ProcessContextOptions,\n type ProcessContextStatic,\n type ProcessContextStaticOptions,\n} from './utils/processContext'\n\n/**\n * SDK configuration options.\n */\nexport type ObservaSDKOptions = {\n /**\n * Organization API key used to authenticate SDK requests.\n */\n apiKey?: string\n /**\n * Project DSN used to identify the destination of events and heartbeats.\n */\n dsnKey: string\n /**\n * Public key for frontend/mobile projects.\n */\n publicKey?: string\n baseUrl?: string\n /**\n * HTTP request timeout in milliseconds.\n */\n timeoutMs?: number\n /**\n * Retry policy for transient errors.\n */\n retry?: RetryPolicy\n /**\n * Additional headers sent with every request.\n */\n headers?: Record<string, string>\n ingest?: IngestNormalizationOptions\n}\n\n/**\n * Fixed backend target for the SDK.\n */\nconst DEFAULT_BASE_URL = 'https://backend-observa-production.up.railway.app/v1'\n\n/**\n * Main SDK for error ingestion and uptime heartbeats.\n */\nexport class ObservaSDK {\n /**\n * Uptime API (heartbeats and public reads).\n */\n readonly uptime: UptimeApi\n /**\n * Event ingestion API.\n */\n readonly ingest: IngestApi\n\n private readonly http: HttpClient\n\n /**\n * Creates an SDK instance with required dsnKey and either apiKey or publicKey.\n */\n constructor(options: ObservaSDKOptions) {\n if (!options || (!options.apiKey && !options.publicKey) || !options.dsnKey) {\n throw new Error('ObservaSDK requires dsnKey and either apiKey or publicKey')\n }\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '')\n const normalizedBaseUrl = baseUrl.endsWith('/v1') ? baseUrl : `${baseUrl}/v1`\n this.http = new HttpClient({\n baseUrl: normalizedBaseUrl,\n apiKey: options.apiKey,\n timeoutMs: options.timeoutMs,\n retry: options.retry,\n headers: options.headers,\n })\n this.ingest = new IngestApi(this.http, options.dsnKey, options.ingest, options.publicKey)\n this.uptime = new UptimeApi(this.http, options.dsnKey)\n this.http.startHealthCheck(() => this.ingest.health(options.dsnKey, options.publicKey))\n }\n\n /**\n * Updates the API key used by the SDK at runtime.\n */\n setApiKey(apiKey: string) {\n this.http.setApiKey(apiKey)\n }\n\n getProcessContext(options?: ProcessContextOptions): ProcessContext {\n return getProcessContext(options)\n }\n\n getProcessContextStatic(options?: ProcessContextStaticOptions): ProcessContextStatic {\n return getProcessContextStatic(options)\n }\n\n getProcessContextDynamic(options?: ProcessContextDynamicOptions): ProcessContextDynamic {\n return getProcessContextDynamic(options)\n }\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;;;ACapB,IAAM,WAAN,cAAuB,MAAM;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKT,YAAY,SAAiB,SAAwB;AACjD,UAAM,OAAO;AACb,SAAK,OAAO,WAAW;AACvB,SAAK,SAAS,SAAS;AACvB,SAAK,OAAO,SAAS;AACrB,SAAK,UAAU,SAAS;AAAA,EAC5B;AACJ;AAKO,IAAM,kBAAN,cAA8B,SAAS;AAAE;AAIzC,IAAM,YAAN,cAAwB,SAAS;AAAE;AAInC,IAAM,iBAAN,cAA6B,SAAS;AAAE;AAIxC,IAAM,gBAAN,cAA4B,SAAS;AAAE;AAIvC,IAAM,gBAAN,cAA4B,SAAS;AAAE;AAIvC,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAChC;AAAA,EAET,YAAY,SAAiB,SAAwB;AACjD,UAAM,SAAS,OAAO;AACtB,SAAK,aAAa,SAAS;AAAA,EAC/B;AACJ;AAIO,IAAM,cAAN,cAA0B,SAAS;AAAE;AAIrC,IAAM,eAAN,cAA2B,SAAS;AAAE;AAItC,IAAM,eAAN,cAA2B,SAAS;AAAE;AAKtC,SAAS,aAAa,QAAgB,SAAmB,YAA+B;AAC3F,QAAM,OAAO,EAAE,QAAQ,SAAS,WAAW;AAC3C,MAAI,WAAW,IAAK,QAAO,IAAI,gBAAgB,mBAAmB,IAAI;AACtE,MAAI,WAAW,IAAK,QAAO,IAAI,UAAU,gBAAgB,IAAI;AAC7D,MAAI,WAAW,IAAK,QAAO,IAAI,eAAe,aAAa,IAAI;AAC/D,MAAI,WAAW,IAAK,QAAO,IAAI,cAAc,sBAAsB,IAAI;AACvE,MAAI,WAAW,IAAK,QAAO,IAAI,cAAc,YAAY,IAAI;AAC7D,MAAI,WAAW,IAAK,QAAO,IAAI,eAAe,uBAAuB,IAAI;AACzE,MAAI,UAAU,IAAK,QAAO,IAAI,YAAY,gBAAgB,IAAI;AAC9D,SAAO,IAAI,SAAS,cAAc,IAAI;AAC1C;;;AClDO,SAAS,kBAAkB,SAAiD;AAC/E,QAAM,gBAAgB,SAAS,iBAAiB;AAChD,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,QAAM,kBAAkB,SAAS,mBAAmB;AACpD,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,QAAM,aAAa,SAAS,cAAc;AAC1C,QAAM,gBAAgB,SAAS,iBAAiB;AAChD,QAAM,gBAAgB,SAAS,iBAAiB;AAChD,QAAM,UAA0B,CAAC;AAEjC,MAAI,gBAAgB;AAChB,QAAI,WAAY,SAAQ,MAAM,QAAQ;AACtC,QAAI,cAAe,SAAQ,gBAAgB,KAAK,MAAM,QAAQ,OAAO,CAAC;AACtE,QAAI,cAAe,SAAQ,SAAS,QAAQ,YAAY;AAAA,EAC5D;AAEA,MAAI,eAAe;AACf,QAAI,gBAAiB,SAAQ,WAAW,QAAQ;AAChD,QAAI,gBAAgB;AAChB,cAAQ,OAAO,QAAQ,SAAS;AAChC,cAAQ,WAAW,QAAQ;AAC3B,cAAQ,OAAO,QAAQ;AACvB,cAAQ,cAAc,QAAQ,SAAS;AAAA,IAC3C;AAAA,EACJ;AAEA,SAAO;AACX;AAEO,SAAS,wBAAwB,SAA6D;AACjG,SAAO,kBAAkB;AAAA,IACrB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB,SAAS;AAAA,IAC1B,gBAAgB,SAAS;AAAA,EAC7B,CAAC;AACL;AAEO,SAAS,yBAAyB,SAA+D;AACpG,SAAO,kBAAkB;AAAA,IACrB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,YAAY,SAAS;AAAA,IACrB,eAAe,SAAS;AAAA,IACxB,eAAe,SAAS;AAAA,EAC5B,CAAC;AACL;;;AC9EO,SAAS,eAAe,OAAe,MAAc;AACxD,MAAI,CAAC,SAAS,MAAM,KAAK,EAAE,WAAW,GAAG;AACrC,UAAM,IAAI,gBAAgB,GAAG,IAAI,cAAc;AAAA,EACnD;AACJ;AAKO,SAAS,cAAiB,OAA6B,MAAkC;AAC5F,MAAI,UAAU,QAAQ,UAAU,QAAW;AACvC,UAAM,IAAI,gBAAgB,GAAG,IAAI,cAAc;AAAA,EACnD;AACJ;;;AHAA,IAAM,wBAA8D;AAAA,EAChE,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,eAAe,KAAK;AAAA,EACpB,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB,yBAAyB;AAC7B;AAKO,IAAM,YAAN,MAAgB;AAAA;AAAA;AAAA;AAAA,EAInB,YACqB,MACA,eACA,eACA,kBACnB;AAJmB;AACA;AACA;AACA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKJ,MAAM,MAAM,OAA+C;AACvD,kBAAc,OAAO,OAAO;AAC5B,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,UAAM,YAAY,MAAM,aAAa,KAAK;AAE1C,kBAAc,QAAQ,QAAQ;AAC9B,mBAAe,QAAQ,QAAQ;AAC/B,kBAAc,MAAM,OAAO,OAAO;AAElC,QAAI,CAAC,KAAK,KAAK,UAAU,KAAK,CAAC,WAAW;AACtC,YAAM,IAAI,gBAAgB,mDAAmD;AAAA,IACjF;AAEA,QAAI,MAAM,kBAAkB,MAAM,eAAe,SAAS,KAAK;AAC3D,YAAM,IAAI,gBAAgB,+CAA+C;AAAA,IAC7E;AACA,UAAM,UAAkC,CAAC;AACzC,QAAI,MAAM,eAAgB,SAAQ,mBAAmB,IAAI,MAAM;AAC/D,QAAI,MAAM,WAAY,SAAQ,eAAe,IAAI,MAAM;AACvD,UAAM,EAAE,gBAAgB,YAAY,OAAO,GAAG,KAAK,IAAI;AACvD,UAAM,kBAAkB,eAAe,OAAO,KAAK,aAAa;AAEhE,UAAM,WAAW,KAAK,KAAK,UAAU,IAAI,WAAW;AACpD,WAAO,KAAK,KAAK,KAAqB,kBAAkB,EAAE,GAAG,MAAM,QAAQ,WAAW,OAAO,gBAAgB,GAAG,EAAE,MAAM,UAAU,QAAQ,CAAC;AAAA,EAC/I;AAAA,EAEA,MAAM,OAAO,QAAiB,WAA8C;AACxE,UAAM,iBAAiB,UAAU,KAAK;AACtC,UAAM,oBAAoB,aAAa,KAAK;AAE5C,kBAAc,gBAAgB,QAAQ;AACtC,mBAAe,gBAAgB,QAAQ;AAEvC,UAAM,WAAW,KAAK,KAAK,UAAU,IAAI,WAAW;AACpD,WAAO,KAAK,KAAK,KAAsB,kBAAkB,EAAE,QAAQ,gBAAgB,WAAW,kBAAkB,GAAG,EAAE,MAAM,SAAS,CAAC;AAAA,EACzI;AACJ;AAEA,SAAS,eAAe,OAAoB,SAAmD;AAC3F,QAAM,SAAS,EAAE,GAAG,uBAAuB,GAAG,QAAQ;AACtD,QAAM,sBAAsB,mBAAmB,MAAM,SAAS;AAC9D,QAAM,kBAAkB,MAAM,QAAQ,MAAM,MAAM,YAAY,IAAI;AAClE,QAAM,oBAAoB,MAAM,UAAU,SAAS,MAAM,SAAS,OAAO,gBAAgB,IAAI;AAC7F,QAAM,sBAAsB,mBAAmB,MAAM,WAAW,MAAM;AACtE,MAAI,CAAC,qBAAqB,CAAC,qBAAqB;AAC5C,UAAM,IAAI,gBAAgB,wCAAwC;AAAA,EACtE;AACA,QAAM,oBAAoB,iBAAiB,MAAM,SAAS,MAAM;AAChE,QAAM,kBAA+B;AAAA,IACjC,GAAG;AAAA,IACH,UAAU,MAAM,YAAY,WAAW;AAAA,IACvC,WAAW;AAAA,IACX,gBAAgB,MAAM,kBAAkB,OAAO;AAAA,IAC/C,OAAO;AAAA,IACP,SAAS;AAAA,IACT,WAAW;AAAA,IACX,SAAS;AAAA,EACb;AACA,SAAO,iBAAiB,iBAAiB,MAAM;AACnD;AAEA,SAAS,mBAAmB,WAAoB;AAC5C,MAAI,CAAC,UAAW,SAAO,oBAAI,KAAK,GAAE,YAAY;AAC9C,QAAM,SAAS,IAAI,KAAK,SAAS;AACjC,MAAI,OAAO,MAAM,OAAO,QAAQ,CAAC,GAAG;AAChC,UAAM,IAAI,gBAAgB,oCAAoC;AAAA,EAClE;AACA,SAAO,OAAO,YAAY;AAC9B;AAEA,SAAS,mBAAmB,WAAqC,QAA8C;AAC3G,MAAI,CAAC,UAAW,QAAO;AACvB,MAAI,CAAC,UAAU,QAAQ,CAAC,UAAU,OAAO;AACrC,UAAM,IAAI,gBAAgB,iDAAiD;AAAA,EAC/E;AACA,SAAO;AAAA,IACH,GAAG;AAAA,IACH,OAAO,SAAS,UAAU,OAAO,OAAO,uBAAuB;AAAA,IAC/D,YAAY,oBAAoB,UAAU,YAAY,OAAO,SAAS;AAAA,EAC1E;AACJ;AAEA,SAAS,oBAAoB,YAAwD,WAAmB;AACpG,MAAI,CAAC,cAAc,CAAC,MAAM,QAAQ,WAAW,MAAM,EAAG,QAAO;AAC7D,QAAM,SAAS,WAAW;AAC1B,QAAM,mBAAmB,OAAO,MAAM,GAAG,SAAS,EAAE,IAAI,CAAC,UAAU;AAC/D,UAAM,WAAW,OAAO,OAAO,aAAa,WAAW,MAAM,WAAW;AACxE,UAAM,eAAe,OAAO,OAAO,aAAa,WAAW,MAAM,WAAW;AAC5E,UAAM,SAAS,OAAO,OAAO,WAAW,WAAW,MAAM,SAAS;AAClE,UAAM,QAAQ,OAAO,OAAO,UAAU,WAAW,MAAM,QAAQ;AAC/D,UAAM,gBAAgB,WAAW,CAAC,SAAS,SAAS,cAAc,IAAI;AACtE,WAAO;AAAA,MACH;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA,QAAQ,OAAO,OAAO,WAAW,YAAY,MAAM,SAAS;AAAA,IAChE;AAAA,EACJ,CAAC;AACD,SAAO,EAAE,QAAQ,iBAAiB;AACtC;AAEA,SAAS,iBAAiB,SAA6C,QAA8C;AACjH,MAAI,CAAC,OAAO,eAAgB,QAAO;AACnC,QAAM,gBAAgB,OAAO,uBAAuB,yBAAyB,IAAI;AACjF,QAAM,iBAAiB,OAAO,wBAAwB,wBAAwB,EAAE,iBAAiB,MAAM,CAAC,IAAI;AAC5G,QAAM,gBAAgB;AAAA,IAClB,GAAG;AAAA,IACH,QAAQ,SAAS,UAAU;AAAA,IAC3B,SAAS,SAAS,WAAW;AAAA,EACjC;AACA,SAAO;AACX;AAEA,SAAS,iBAAiB,OAAoB,QAA8C;AACxF,MAAI,aAAa;AACjB,MAAI,QAAQ,UAAU,KAAK,OAAO,cAAe,QAAO;AACxD,MAAI,WAAW,OAAO;AAClB,iBAAa,EAAE,GAAG,YAAY,OAAO,OAAU;AAAA,EACnD;AACA,MAAI,QAAQ,UAAU,KAAK,OAAO,cAAe,QAAO;AACxD,MAAI,WAAW,MAAM;AACjB,iBAAa,EAAE,GAAG,YAAY,MAAM,OAAU;AAAA,EAClD;AACA,MAAI,QAAQ,UAAU,KAAK,OAAO,cAAe,QAAO;AACxD,MAAI,WAAW,WAAW,YAAY;AAClC,iBAAa;AAAA,MACT,GAAG;AAAA,MACH,WAAW,EAAE,GAAG,WAAW,WAAW,YAAY,OAAU;AAAA,IAChE;AAAA,EACJ;AACA,MAAI,QAAQ,UAAU,KAAK,OAAO,cAAe,QAAO;AACxD,MAAI,WAAW,SAAS;AACpB,iBAAa,EAAE,GAAG,YAAY,SAAS,SAAS,WAAW,SAAS,OAAO,gBAAgB,EAAE;AAAA,EACjG;AACA,MAAI,WAAW,WAAW,OAAO;AAC7B,iBAAa;AAAA,MACT,GAAG;AAAA,MACH,WAAW,EAAE,GAAG,WAAW,WAAW,OAAO,SAAS,WAAW,UAAU,OAAO,OAAO,uBAAuB,EAAE;AAAA,IACtH;AAAA,EACJ;AACA,MAAI,QAAQ,UAAU,KAAK,OAAO,cAAe,QAAO;AACxD,QAAM,IAAI,gBAAgB,kCAAkC;AAChE;AAEA,SAAS,QAAQ,OAAgB;AAC7B,SAAO,OAAO,WAAW,KAAK,UAAU,KAAK,GAAG,MAAM;AAC1D;AAEA,SAAS,SAAS,OAAe,WAAmB;AAChD,MAAI,MAAM,UAAU,UAAW,QAAO;AACtC,SAAO,MAAM,MAAM,GAAG,SAAS;AACnC;;;AI/LO,IAAM,YAAN,MAAgB;AAAA;AAAA;AAAA;AAAA,EAInB,YAA6B,MAAmC,eAAwB;AAA3D;AAAmC;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA,EAK1F,MAAM,gBAAgB,OAAmD;AACrE,kBAAc,OAAO,OAAO;AAC5B,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,kBAAc,QAAQ,QAAQ;AAC9B,mBAAe,QAAQ,QAAQ;AAC/B,mBAAe,MAAM,QAAQ,QAAQ;AACrC,WAAO,KAAK,KAAK,KAAkB,sBAAsB,EAAE,GAAG,OAAO,OAAO,GAAG,EAAE,MAAM,SAAS,CAAC;AAAA,EACrG;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,WAAmB,MAAsC;AACnE,mBAAe,WAAW,WAAW;AACrC,mBAAe,MAAM,MAAM;AAC3B,WAAO,KAAK,KAAK,IAAmB,aAAa,mBAAmB,SAAS,CAAC,mBAAmB;AAAA,MAC7F,OAAO,EAAE,KAAK;AAAA,MACd,MAAM;AAAA,IACV,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,WAAgD;AACzD,mBAAe,WAAW,WAAW;AACrC,WAAO,KAAK,KAAK,IAAwB,aAAa,mBAAmB,SAAS,CAAC,kBAAkB;AAAA,MACjG,MAAM;AAAA,IACV,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,WAAmB,MAAe,uBAA0D;AACtG,mBAAe,WAAW,WAAW;AACrC,WAAO,KAAK,KAAK,IAAqB,aAAa,mBAAmB,SAAS,CAAC,mBAAmB;AAAA,MAC/F,OAAO,EAAE,MAAM,sBAAsB;AAAA,MACrC,MAAM;AAAA,IACV,CAAC;AAAA,EACL;AACJ;;;ACoBO,IAAM,aAAN,MAAiB;AAAA,EACZ;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKR,YAAY,SAA4B;AACpC,SAAK,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AACjD,SAAK,SAAS,QAAQ;AACtB,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,UAAU,QAAQ,WAAW,CAAC;AACnC,SAAK,QAAQ,QAAQ;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,QAAiB;AACvB,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAqB;AACjB,WAAO,CAAC,CAAC,KAAK;AAAA,EAClB;AAAA,EAEA,iBAAiB,aAAqC;AAClD,QAAI,CAAC,KAAK,oBAAoB;AAC1B,YAAM,UAAU,YAAY;AAC5B,WAAK,qBAAqB;AAC1B,cAAQ,MAAM,MAAM,MAAS;AAAA,IACjC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAO,MAAc,SAA+D;AACtF,WAAO,KAAK,QAAW,EAAE,QAAQ,OAAO,MAAM,GAAG,QAAQ,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAQ,MAAc,MAAgB,SAAwE;AAChH,WAAO,KAAK,QAAW,EAAE,QAAQ,QAAQ,MAAM,MAAM,GAAG,QAAQ,CAAC;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAO,MAAc,MAAgB,SAAwE;AAC/G,WAAO,KAAK,QAAW,EAAE,QAAQ,OAAO,MAAM,MAAM,GAAG,QAAQ,CAAC;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAS,MAAc,MAAgB,SAAwE;AACjH,WAAO,KAAK,QAAW,EAAE,QAAQ,SAAS,MAAM,MAAM,GAAG,QAAQ,CAAC;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAU,MAAc,SAA+D;AACzF,WAAO,KAAK,QAAW,EAAE,QAAQ,UAAU,MAAM,GAAG,QAAQ,CAAC;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAW,SAAqC;AAClD,QAAI,KAAK,oBAAoB;AACzB,YAAM,KAAK;AAAA,IACf;AACA,UAAM,QAAQ,KAAK,SAAS,EAAE,SAAS,EAAE;AACzC,UAAM,UAAU,MAAM,YAAY,CAAC,UAAqB,UAAoB;AACxE,UAAI,SAAU,QAAO,SAAS,WAAW,OAAO,SAAS,UAAU;AACnE,aAAO,iBAAiB,gBAAgB,iBAAiB,gBAAgB,iBAAiB;AAAA,IAC9F;AACA,UAAM,eAAe,MAAM,iBAAiB,CAAC,YAAoB,KAAK,IAAI,MAAO,MAAM,UAAU,IAAI,GAAI;AACzG,QAAI;AAEJ,aAAS,UAAU,GAAG,WAAW,MAAM,SAAS,WAAW,GAAG;AAC1D,UAAI;AACA,cAAM,EAAE,UAAU,KAAK,IAAI,MAAM,KAAK,QAAQ,OAAO;AACrD,YAAI,CAAC,SAAS,IAAI;AACd,gBAAM,aAAa,KAAK,gBAAgB,SAAS,QAAQ,IAAI,aAAa,CAAC;AAC3E,gBAAM,QAAQ,aAAa,SAAS,QAAQ,MAAM,UAAU;AAC5D,cAAI,QAAQ,UAAU,KAAK,KAAK,UAAU,MAAM,SAAS;AACrD,kBAAM,KAAK,MAAM,aAAa,UAAU,GAAG,UAAU,KAAK,CAAC;AAC3D;AAAA,UACJ;AACA,gBAAM;AAAA,QACV;AACA,eAAO;AAAA,MACX,SAAS,OAAO;AACZ,oBAAY;AACZ,YAAI,QAAQ,QAAW,KAAK,KAAK,UAAU,MAAM,SAAS;AACtD,gBAAM,KAAK,MAAM,aAAa,UAAU,GAAG,QAAW,KAAK,CAAC;AAC5D;AAAA,QACJ;AACA,cAAM;AAAA,MACV;AAAA,IACJ;AAEA,UAAM;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,QAAQ,SAAyE;AAC3F,UAAM,MAAM,KAAK,SAAS,QAAQ,MAAM,QAAQ,KAAK;AACrD,UAAM,UAAkC,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ,QAAQ;AAC9E,QAAI,QAAQ,SAAS,OAAW,SAAQ,cAAc,IAAI;AAC1D,UAAM,WAAW,QAAQ,QAAQ;AACjC,QAAI,aAAa,UAAU;AACvB,UAAI,CAAC,KAAK,OAAQ,OAAM,IAAI,UAAU,qBAAqB;AAC3D,cAAQ,WAAW,IAAI,KAAK;AAAA,IAChC;AAEA,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,SAAS;AAEjE,QAAI;AACA,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAC9B,QAAQ,QAAQ;AAAA,QAChB;AAAA,QACA,MAAM,QAAQ,SAAS,SAAY,SAAY,KAAK,UAAU,QAAQ,IAAI;AAAA,QAC1E,QAAQ,WAAW;AAAA,MACvB,CAAC;AACD,YAAM,OAAO,MAAM,KAAK,SAAS,QAAQ;AACzC,aAAO,EAAE,UAAU,KAAK;AAAA,IAC5B,SAAS,OAAY;AACjB,UAAI,OAAO,SAAS,cAAc;AAC9B,cAAM,IAAI,aAAa,iBAAiB;AAAA,MAC5C;AACA,UAAI,iBAAiB,gBAAgB,iBAAiB,aAAc,OAAM;AAC1E,UAAI,iBAAiB,OAAO;AACxB,YAAI,iBAAiB,UAAW,OAAM;AAAA,MAC1C;AACA,UAAI,iBAAiB,SAAS,YAAY,MAAO,OAAM;AACvD,YAAM,IAAI,aAAa,iBAAiB,EAAE,SAAS,MAAM,CAAC;AAAA,IAC9D,UAAE;AACE,mBAAa,KAAK;AAAA,IACtB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAS,MAAc,OAA6B;AACxD,UAAM,OAAO,KAAK;AAClB,UAAM,WAAW,KAAK,WAAW,MAAM,IAAI,OAAO,GAAG,IAAI,GAAG,KAAK,WAAW,GAAG,IAAI,KAAK,GAAG,GAAG,IAAI;AAClG,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,SAAS,IAAI,gBAAgB;AACnC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC9C,UAAI,UAAU,OAAW;AACzB,aAAO,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IACjC;AACA,UAAM,SAAS,OAAO,SAAS;AAC/B,WAAO,SAAS,GAAG,QAAQ,IAAI,MAAM,KAAK;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,SAAS,UAAsC;AACzD,QAAI,SAAS,WAAW,IAAK,QAAO;AACpC,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI;AACA,aAAO,KAAK,MAAM,IAAI;AAAA,IAC1B,QAAQ;AACJ,aAAO;AAAA,IACX;AAAA,EACJ;AAAA,EAEQ,gBAAgB,OAA0C;AAC9D,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,UAAU,OAAO,KAAK;AAC5B,QAAI,CAAC,OAAO,MAAM,OAAO,KAAK,OAAO,SAAS,OAAO,GAAG;AACpD,aAAO,KAAK,IAAI,GAAG,OAAO;AAAA,IAC9B;AACA,UAAM,aAAa,KAAK,MAAM,KAAK;AACnC,QAAI,OAAO,MAAM,UAAU,EAAG,QAAO;AACrC,UAAM,SAAS,aAAa,KAAK,IAAI;AACrC,QAAI,UAAU,EAAG,QAAO;AACxB,WAAO,KAAK,KAAK,SAAS,GAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,MAAM,IAA2B;AAC3C,UAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;AAAA,EACxD;AACJ;;;ACzOA,IAAM,mBAAmB;AAKlB,IAAM,aAAN,MAAiB;AAAA;AAAA;AAAA;AAAA,EAIX;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA,EAEQ;AAAA;AAAA;AAAA;AAAA,EAKjB,YAAY,SAA4B;AACpC,QAAI,CAAC,WAAY,CAAC,QAAQ,UAAU,CAAC,QAAQ,aAAc,CAAC,QAAQ,QAAQ;AACxE,YAAM,IAAI,MAAM,2DAA2D;AAAA,IAC/E;AACA,UAAM,WAAW,QAAQ,WAAW,kBAAkB,QAAQ,QAAQ,EAAE;AACxE,UAAM,oBAAoB,QAAQ,SAAS,KAAK,IAAI,UAAU,GAAG,OAAO;AACxE,SAAK,OAAO,IAAI,WAAW;AAAA,MACvB,SAAS;AAAA,MACT,QAAQ,QAAQ;AAAA,MAChB,WAAW,QAAQ;AAAA,MACnB,OAAO,QAAQ;AAAA,MACf,SAAS,QAAQ;AAAA,IACrB,CAAC;AACD,SAAK,SAAS,IAAI,UAAU,KAAK,MAAM,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,SAAS;AACxF,SAAK,SAAS,IAAI,UAAU,KAAK,MAAM,QAAQ,MAAM;AACrD,SAAK,KAAK,iBAAiB,MAAM,KAAK,OAAO,OAAO,QAAQ,QAAQ,QAAQ,SAAS,CAAC;AAAA,EAC1F;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,QAAgB;AACtB,SAAK,KAAK,UAAU,MAAM;AAAA,EAC9B;AAAA,EAEA,kBAAkB,SAAiD;AAC/D,WAAO,kBAAkB,OAAO;AAAA,EACpC;AAAA,EAEA,wBAAwB,SAA6D;AACjF,WAAO,wBAAwB,OAAO;AAAA,EAC1C;AAAA,EAEA,yBAAyB,SAA+D;AACpF,WAAO,yBAAyB,OAAO;AAAA,EAC3C;AACJ;","names":[]}
|
package/package.json
CHANGED
package/src/apis/ingestApi.ts
CHANGED
|
@@ -32,12 +32,13 @@ const DEFAULT_NORMALIZATION: Required<IngestNormalizationOptions> = {
|
|
|
32
32
|
*/
|
|
33
33
|
export class IngestApi {
|
|
34
34
|
/**
|
|
35
|
-
* Creates the ingestion client with an optional default DSN.
|
|
35
|
+
* Creates the ingestion client with an optional default DSN and PublicKey.
|
|
36
36
|
*/
|
|
37
37
|
constructor(
|
|
38
38
|
private readonly http: HttpClient,
|
|
39
39
|
private readonly defaultDsnKey?: string,
|
|
40
|
-
private readonly normalization?: IngestNormalizationOptions
|
|
40
|
+
private readonly normalization?: IngestNormalizationOptions,
|
|
41
|
+
private readonly defaultPublicKey?: string
|
|
41
42
|
) { }
|
|
42
43
|
|
|
43
44
|
/**
|
|
@@ -46,9 +47,16 @@ export class IngestApi {
|
|
|
46
47
|
async event(input: IngestRequest): Promise<IngestResponse> {
|
|
47
48
|
ensureDefined(input, 'input')
|
|
48
49
|
const dsnKey = input.dsnKey ?? this.defaultDsnKey
|
|
50
|
+
const publicKey = input.publicKey ?? this.defaultPublicKey
|
|
51
|
+
|
|
49
52
|
ensureDefined(dsnKey, 'dsnKey')
|
|
50
53
|
ensureNonEmpty(dsnKey, 'dsnKey')
|
|
51
54
|
ensureDefined(input.event, 'event')
|
|
55
|
+
|
|
56
|
+
if (!this.http.hasApiKey() && !publicKey) {
|
|
57
|
+
throw new ValidationError('publicKey is required when apiKey is not provided')
|
|
58
|
+
}
|
|
59
|
+
|
|
52
60
|
if (input.idempotencyKey && input.idempotencyKey.length > 128) {
|
|
53
61
|
throw new ValidationError('idempotencyKey must be at most 128 characters')
|
|
54
62
|
}
|
|
@@ -57,14 +65,20 @@ export class IngestApi {
|
|
|
57
65
|
if (input.sdkVersion) headers['x-sdk-version'] = input.sdkVersion
|
|
58
66
|
const { idempotencyKey, sdkVersion, event, ...body } = input
|
|
59
67
|
const normalizedEvent = normalizeEvent(event, this.normalization)
|
|
60
|
-
|
|
68
|
+
|
|
69
|
+
const authMode = this.http.hasApiKey() ? 'apiKey' : 'none'
|
|
70
|
+
return this.http.post<IngestResponse>('/ingest/events', { ...body, dsnKey, publicKey, event: normalizedEvent }, { auth: authMode, headers })
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
async health(dsnKey?: string): Promise<{ ok: boolean }> {
|
|
73
|
+
async health(dsnKey?: string, publicKey?: string): Promise<{ ok: boolean }> {
|
|
64
74
|
const resolvedDsnKey = dsnKey ?? this.defaultDsnKey
|
|
75
|
+
const resolvedPublicKey = publicKey ?? this.defaultPublicKey
|
|
76
|
+
|
|
65
77
|
ensureDefined(resolvedDsnKey, 'dsnKey')
|
|
66
78
|
ensureNonEmpty(resolvedDsnKey, 'dsnKey')
|
|
67
|
-
|
|
79
|
+
|
|
80
|
+
const authMode = this.http.hasApiKey() ? 'apiKey' : 'none'
|
|
81
|
+
return this.http.post<{ ok: boolean }>('/ingest/health', { dsnKey: resolvedDsnKey, publicKey: resolvedPublicKey }, { auth: authMode })
|
|
68
82
|
}
|
|
69
83
|
}
|
|
70
84
|
|
package/src/domain/ingest.ts
CHANGED
package/src/http/httpClient.ts
CHANGED
|
@@ -101,6 +101,13 @@ export class HttpClient {
|
|
|
101
101
|
this.apiKey = apiKey
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Checks if an API key is configured.
|
|
106
|
+
*/
|
|
107
|
+
hasApiKey(): boolean {
|
|
108
|
+
return !!this.apiKey
|
|
109
|
+
}
|
|
110
|
+
|
|
104
111
|
startHealthCheck(healthCheck: () => Promise<unknown>) {
|
|
105
112
|
if (!this.healthCheckPromise) {
|
|
106
113
|
const promise = healthCheck()
|
package/src/sdk.ts
CHANGED
|
@@ -20,11 +20,15 @@ export type ObservaSDKOptions = {
|
|
|
20
20
|
/**
|
|
21
21
|
* Organization API key used to authenticate SDK requests.
|
|
22
22
|
*/
|
|
23
|
-
apiKey
|
|
23
|
+
apiKey?: string
|
|
24
24
|
/**
|
|
25
25
|
* Project DSN used to identify the destination of events and heartbeats.
|
|
26
26
|
*/
|
|
27
27
|
dsnKey: string
|
|
28
|
+
/**
|
|
29
|
+
* Public key for frontend/mobile projects.
|
|
30
|
+
*/
|
|
31
|
+
publicKey?: string
|
|
28
32
|
baseUrl?: string
|
|
29
33
|
/**
|
|
30
34
|
* HTTP request timeout in milliseconds.
|
|
@@ -62,11 +66,11 @@ export class ObservaSDK {
|
|
|
62
66
|
private readonly http: HttpClient
|
|
63
67
|
|
|
64
68
|
/**
|
|
65
|
-
* Creates an SDK instance with required
|
|
69
|
+
* Creates an SDK instance with required dsnKey and either apiKey or publicKey.
|
|
66
70
|
*/
|
|
67
71
|
constructor(options: ObservaSDKOptions) {
|
|
68
|
-
if (!options || !options.apiKey || !options.dsnKey) {
|
|
69
|
-
throw new Error('ObservaSDK requires
|
|
72
|
+
if (!options || (!options.apiKey && !options.publicKey) || !options.dsnKey) {
|
|
73
|
+
throw new Error('ObservaSDK requires dsnKey and either apiKey or publicKey')
|
|
70
74
|
}
|
|
71
75
|
const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '')
|
|
72
76
|
const normalizedBaseUrl = baseUrl.endsWith('/v1') ? baseUrl : `${baseUrl}/v1`
|
|
@@ -77,9 +81,9 @@ export class ObservaSDK {
|
|
|
77
81
|
retry: options.retry,
|
|
78
82
|
headers: options.headers,
|
|
79
83
|
})
|
|
80
|
-
this.ingest = new IngestApi(this.http, options.dsnKey, options.ingest)
|
|
84
|
+
this.ingest = new IngestApi(this.http, options.dsnKey, options.ingest, options.publicKey)
|
|
81
85
|
this.uptime = new UptimeApi(this.http, options.dsnKey)
|
|
82
|
-
this.http.startHealthCheck(() => this.ingest.health(options.dsnKey))
|
|
86
|
+
this.http.startHealthCheck(() => this.ingest.health(options.dsnKey, options.publicKey))
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
/**
|