@dispatchitapp/core 1.0.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/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/index.cjs +457 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +288 -0
- package/dist/index.d.ts +288 -0
- package/dist/index.js +401 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
// src/version.ts
|
|
2
|
+
var SDK_NAME = "dispatch-js";
|
|
3
|
+
var SDK_VERSION = "1.0.0";
|
|
4
|
+
var CONTRACT_VERSION = "1";
|
|
5
|
+
|
|
6
|
+
// src/config.ts
|
|
7
|
+
var DEFAULT_ENDPOINT = "https://dispatchit.app/api/v1/tickets";
|
|
8
|
+
var DEFAULT_ENABLED_ENVIRONMENTS = ["production", "staging"];
|
|
9
|
+
function deriveErrorEndpoint(endpoint) {
|
|
10
|
+
return endpoint.replace(/\/[^/]+$/, "/store");
|
|
11
|
+
}
|
|
12
|
+
function deriveReportBaseUrl(endpoint) {
|
|
13
|
+
try {
|
|
14
|
+
return new URL(endpoint).origin;
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function defaultEnvironment() {
|
|
20
|
+
const env = globalThis.process?.env?.NODE_ENV;
|
|
21
|
+
return env && env.length > 0 ? env : "production";
|
|
22
|
+
}
|
|
23
|
+
function resolveConfig(options) {
|
|
24
|
+
const endpoint = options.endpoint ?? DEFAULT_ENDPOINT;
|
|
25
|
+
return {
|
|
26
|
+
apiKey: options.apiKey,
|
|
27
|
+
endpoint,
|
|
28
|
+
errorEndpoint: options.errorEndpoint ?? deriveErrorEndpoint(endpoint),
|
|
29
|
+
reportBaseUrl: options.reportBaseUrl ?? deriveReportBaseUrl(endpoint),
|
|
30
|
+
environment: options.environment ?? defaultEnvironment(),
|
|
31
|
+
release: options.release ?? null,
|
|
32
|
+
enabledEnvironments: options.enabledEnvironments ?? DEFAULT_ENABLED_ENVIRONMENTS,
|
|
33
|
+
captureExceptions: options.captureExceptions ?? true,
|
|
34
|
+
errorSampleRate: options.errorSampleRate ?? 1,
|
|
35
|
+
beforeSend: options.beforeSend ?? null,
|
|
36
|
+
user: options.user ?? null,
|
|
37
|
+
tags: options.tags ?? {},
|
|
38
|
+
sdk: options.sdk ?? { name: SDK_NAME, version: SDK_VERSION },
|
|
39
|
+
debug: options.debug ?? false,
|
|
40
|
+
shutdownTimeout: options.shutdownTimeout ?? 3e3
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function configured(c) {
|
|
44
|
+
return Boolean(c.apiKey) && Boolean(c.endpoint);
|
|
45
|
+
}
|
|
46
|
+
function environmentEnabled(c) {
|
|
47
|
+
return c.enabledEnvironments.length === 0 || c.enabledEnvironments.includes(c.environment);
|
|
48
|
+
}
|
|
49
|
+
function errorTrackingEnabled(c) {
|
|
50
|
+
return configured(c) && c.captureExceptions;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/dedup.ts
|
|
54
|
+
var captured = /* @__PURE__ */ new WeakSet();
|
|
55
|
+
function isObject(value) {
|
|
56
|
+
return typeof value === "object" && value !== null;
|
|
57
|
+
}
|
|
58
|
+
function alreadyCaptured(error) {
|
|
59
|
+
return isObject(error) && captured.has(error);
|
|
60
|
+
}
|
|
61
|
+
function markCaptured(error) {
|
|
62
|
+
if (isObject(error)) captured.add(error);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/stacktrace.ts
|
|
66
|
+
var MAX_FRAMES = 100;
|
|
67
|
+
function isInApp(file) {
|
|
68
|
+
if (!file) return false;
|
|
69
|
+
if (file.includes("node_modules")) return false;
|
|
70
|
+
if (file.startsWith("node:") || file.startsWith("internal/")) return false;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
function parseStack(stack) {
|
|
74
|
+
if (!stack) return [];
|
|
75
|
+
const frames = [];
|
|
76
|
+
for (const raw of stack.split("\n")) {
|
|
77
|
+
const line = raw.trim();
|
|
78
|
+
if (!line) continue;
|
|
79
|
+
const v8WithFn = /^at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)$/.exec(line);
|
|
80
|
+
const v8NoFn = v8WithFn ? null : /^at\s+(.+?):(\d+):(\d+)$/.exec(line);
|
|
81
|
+
const mozilla = v8WithFn || v8NoFn ? null : /^(.*?)@(.+?):(\d+):(\d+)$/.exec(line);
|
|
82
|
+
let fn;
|
|
83
|
+
let file;
|
|
84
|
+
let lineno;
|
|
85
|
+
let colno;
|
|
86
|
+
if (v8WithFn) {
|
|
87
|
+
fn = v8WithFn[1];
|
|
88
|
+
file = v8WithFn[2];
|
|
89
|
+
lineno = Number(v8WithFn[3]);
|
|
90
|
+
colno = Number(v8WithFn[4]);
|
|
91
|
+
} else if (v8NoFn) {
|
|
92
|
+
fn = "?";
|
|
93
|
+
file = v8NoFn[1];
|
|
94
|
+
lineno = Number(v8NoFn[2]);
|
|
95
|
+
colno = Number(v8NoFn[3]);
|
|
96
|
+
} else if (mozilla) {
|
|
97
|
+
fn = mozilla[1] || "?";
|
|
98
|
+
file = mozilla[2];
|
|
99
|
+
lineno = Number(mozilla[3]);
|
|
100
|
+
colno = Number(mozilla[4]);
|
|
101
|
+
} else {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
frames.push({
|
|
105
|
+
function: fn,
|
|
106
|
+
filename: file,
|
|
107
|
+
abs_path: file,
|
|
108
|
+
lineno,
|
|
109
|
+
colno,
|
|
110
|
+
in_app: isInApp(file)
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return frames.slice(0, MAX_FRAMES).reverse();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/util.ts
|
|
117
|
+
function compact(obj) {
|
|
118
|
+
const out = {};
|
|
119
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
120
|
+
if (v !== null && v !== void 0) out[k] = v;
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
function uuid32() {
|
|
125
|
+
return globalThis.crypto.randomUUID().replace(/-/g, "");
|
|
126
|
+
}
|
|
127
|
+
function epochSeconds() {
|
|
128
|
+
return Date.now() / 1e3;
|
|
129
|
+
}
|
|
130
|
+
function delay(ms) {
|
|
131
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/event.ts
|
|
135
|
+
var MAX_CAUSES = 5;
|
|
136
|
+
var VALUE_MAX_LENGTH = 2e3;
|
|
137
|
+
function asError(value) {
|
|
138
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
139
|
+
}
|
|
140
|
+
function exceptionValue(error, handled, parse) {
|
|
141
|
+
const err = asError(error);
|
|
142
|
+
const type = err && typeof err.name === "string" && err.name || "Error";
|
|
143
|
+
const rawMessage = err && typeof err.message === "string" ? err.message : String(error ?? "");
|
|
144
|
+
const stack = err && typeof err.stack === "string" ? err.stack : void 0;
|
|
145
|
+
return {
|
|
146
|
+
type,
|
|
147
|
+
value: rawMessage.slice(0, VALUE_MAX_LENGTH),
|
|
148
|
+
mechanism: { type: "generic", handled },
|
|
149
|
+
stacktrace: { frames: parse(stack) }
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function exceptionValues(error, handled, parse) {
|
|
153
|
+
const chain = [];
|
|
154
|
+
let current = error;
|
|
155
|
+
for (let depth = 0; depth < MAX_CAUSES && current != null; depth++) {
|
|
156
|
+
chain.push(current);
|
|
157
|
+
current = asError(current)?.cause;
|
|
158
|
+
}
|
|
159
|
+
chain.reverse();
|
|
160
|
+
return chain.map((e) => exceptionValue(e, handled, parse));
|
|
161
|
+
}
|
|
162
|
+
function buildEvent(error, input) {
|
|
163
|
+
const parse = input.parseStack ?? parseStack;
|
|
164
|
+
const now = input.now ?? epochSeconds;
|
|
165
|
+
const id = input.uuid ?? uuid32;
|
|
166
|
+
const c = input.config;
|
|
167
|
+
const derivedTags = {};
|
|
168
|
+
if (input.transaction) derivedTags["transaction"] = input.transaction;
|
|
169
|
+
const tags = { ...derivedTags, ...c.tags, ...input.tags ?? {} };
|
|
170
|
+
const event = {
|
|
171
|
+
event_id: id(),
|
|
172
|
+
timestamp: now(),
|
|
173
|
+
platform: input.platform ?? "javascript",
|
|
174
|
+
level: input.level ?? "error",
|
|
175
|
+
environment: c.environment,
|
|
176
|
+
exception: { values: exceptionValues(error, input.handled, parse) }
|
|
177
|
+
};
|
|
178
|
+
if (c.release != null) event.release = c.release;
|
|
179
|
+
if (input.serverName != null) event.server_name = input.serverName;
|
|
180
|
+
if (input.transaction != null) event.transaction = input.transaction;
|
|
181
|
+
if (input.request) event.request = input.request;
|
|
182
|
+
const user = input.user ?? c.user;
|
|
183
|
+
if (user != null) event.user = user;
|
|
184
|
+
if (Object.keys(tags).length > 0) event.tags = tags;
|
|
185
|
+
event.sdk = c.sdk;
|
|
186
|
+
return event;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/sampling.ts
|
|
190
|
+
function sampledOut(rate, rng = Math.random) {
|
|
191
|
+
if (rate >= 1) return false;
|
|
192
|
+
if (rate <= 0) return true;
|
|
193
|
+
return rng() > rate;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/ticket.ts
|
|
197
|
+
function buildTicketPayload(input) {
|
|
198
|
+
const metadata = { ...input.metadata ?? {} };
|
|
199
|
+
if (input.correlationId) metadata["correlation_id"] = input.correlationId;
|
|
200
|
+
const ticket = compact({
|
|
201
|
+
description: input.description,
|
|
202
|
+
title: input.title,
|
|
203
|
+
source: input.source ?? "api",
|
|
204
|
+
severity: input.severity ?? void 0,
|
|
205
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
|
|
206
|
+
reporter: input.reporter ?? void 0,
|
|
207
|
+
attachments: input.attachments
|
|
208
|
+
});
|
|
209
|
+
return { ticket };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/transport.ts
|
|
213
|
+
var QUEUE_LIMIT = 100;
|
|
214
|
+
var DEFAULT_FLUSH_TIMEOUT = 2e3;
|
|
215
|
+
function sdkHeader(config) {
|
|
216
|
+
return `${config.sdk.name}/${config.sdk.version} (contract/${CONTRACT_VERSION})`;
|
|
217
|
+
}
|
|
218
|
+
var FetchTransport = class {
|
|
219
|
+
constructor(config, fetchImpl) {
|
|
220
|
+
this.config = config;
|
|
221
|
+
this.fetchImpl = fetchImpl ?? globalThis.fetch;
|
|
222
|
+
}
|
|
223
|
+
config;
|
|
224
|
+
queue = [];
|
|
225
|
+
draining = null;
|
|
226
|
+
fetchImpl;
|
|
227
|
+
sendEvent(event) {
|
|
228
|
+
if (this.queue.length >= QUEUE_LIMIT) {
|
|
229
|
+
this.warn(`queue full (${QUEUE_LIMIT}), dropping event ${event.event_id}`);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this.queue.push(event);
|
|
233
|
+
this.kick();
|
|
234
|
+
}
|
|
235
|
+
async postTicket(payload) {
|
|
236
|
+
const res = await this.post(this.config.endpoint, payload);
|
|
237
|
+
if (!res || !res.ok) return null;
|
|
238
|
+
try {
|
|
239
|
+
return await res.json();
|
|
240
|
+
} catch {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async flush(timeoutMs = DEFAULT_FLUSH_TIMEOUT) {
|
|
245
|
+
if (this.draining) {
|
|
246
|
+
await Promise.race([this.draining, delay(timeoutMs)]);
|
|
247
|
+
}
|
|
248
|
+
return this.queue.length === 0;
|
|
249
|
+
}
|
|
250
|
+
kick() {
|
|
251
|
+
if (this.draining) return;
|
|
252
|
+
this.draining = this.drain().finally(() => {
|
|
253
|
+
this.draining = null;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
async drain() {
|
|
257
|
+
while (this.queue.length > 0) {
|
|
258
|
+
const event = this.queue.shift();
|
|
259
|
+
await this.post(this.config.errorEndpoint, event);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async post(url, body) {
|
|
263
|
+
if (!this.fetchImpl) {
|
|
264
|
+
this.warn("no fetch implementation available");
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
return await this.fetchImpl(url, {
|
|
269
|
+
method: "POST",
|
|
270
|
+
headers: {
|
|
271
|
+
"Content-Type": "application/json",
|
|
272
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
273
|
+
"X-Dispatch-Sdk": sdkHeader(this.config)
|
|
274
|
+
},
|
|
275
|
+
body: JSON.stringify(body),
|
|
276
|
+
keepalive: true
|
|
277
|
+
});
|
|
278
|
+
} catch (err) {
|
|
279
|
+
this.warn(`delivery failed: ${String(err)}`);
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
warn(message) {
|
|
284
|
+
if (this.config.debug) console.warn(`[dispatch] ${message}`);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// src/client.ts
|
|
289
|
+
var Client = class {
|
|
290
|
+
config;
|
|
291
|
+
transport;
|
|
292
|
+
platform;
|
|
293
|
+
parseStack;
|
|
294
|
+
rng;
|
|
295
|
+
constructor(options) {
|
|
296
|
+
this.config = resolveConfig(options);
|
|
297
|
+
this.transport = options.transport ?? new FetchTransport(this.config);
|
|
298
|
+
this.platform = options.platform ?? "javascript";
|
|
299
|
+
this.parseStack = options.parseStack;
|
|
300
|
+
this.rng = options.rng ?? Math.random;
|
|
301
|
+
}
|
|
302
|
+
captureException(error, context = {}) {
|
|
303
|
+
try {
|
|
304
|
+
const c = this.config;
|
|
305
|
+
if (!errorTrackingEnabled(c)) return;
|
|
306
|
+
if (!environmentEnabled(c)) return;
|
|
307
|
+
if (alreadyCaptured(error)) return;
|
|
308
|
+
if (sampledOut(c.errorSampleRate, this.rng)) return;
|
|
309
|
+
markCaptured(error);
|
|
310
|
+
let event = buildEvent(error, {
|
|
311
|
+
config: c,
|
|
312
|
+
platform: this.platform,
|
|
313
|
+
level: context.level ?? "error",
|
|
314
|
+
handled: context.handled ?? true,
|
|
315
|
+
user: context.user,
|
|
316
|
+
tags: context.tags,
|
|
317
|
+
request: context.request,
|
|
318
|
+
transaction: context.transaction,
|
|
319
|
+
serverName: context.serverName,
|
|
320
|
+
parseStack: this.parseStack
|
|
321
|
+
});
|
|
322
|
+
if (c.beforeSend) {
|
|
323
|
+
const result = c.beforeSend(event);
|
|
324
|
+
if (!result) return;
|
|
325
|
+
event = result;
|
|
326
|
+
}
|
|
327
|
+
this.transport.sendEvent(event);
|
|
328
|
+
} catch (err) {
|
|
329
|
+
if (this.config.debug) console.warn(`[dispatch] capture failed: ${String(err)}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async report(input) {
|
|
333
|
+
if (!configured(this.config)) return null;
|
|
334
|
+
try {
|
|
335
|
+
return await this.transport.postTicket(buildTicketPayload(input));
|
|
336
|
+
} catch {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
flush(timeoutMs) {
|
|
341
|
+
return this.transport.flush(timeoutMs);
|
|
342
|
+
}
|
|
343
|
+
close(timeoutMs) {
|
|
344
|
+
return this.transport.flush(timeoutMs);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// src/index.ts
|
|
349
|
+
var defaultClient = null;
|
|
350
|
+
function init(options) {
|
|
351
|
+
defaultClient = new Client(options);
|
|
352
|
+
return defaultClient;
|
|
353
|
+
}
|
|
354
|
+
function getClient() {
|
|
355
|
+
return defaultClient;
|
|
356
|
+
}
|
|
357
|
+
function captureException(error, context) {
|
|
358
|
+
defaultClient?.captureException(error, context);
|
|
359
|
+
}
|
|
360
|
+
function report(input) {
|
|
361
|
+
return defaultClient ? defaultClient.report(input) : Promise.resolve(null);
|
|
362
|
+
}
|
|
363
|
+
function flush(timeoutMs) {
|
|
364
|
+
return defaultClient ? defaultClient.flush(timeoutMs) : Promise.resolve(true);
|
|
365
|
+
}
|
|
366
|
+
function close(timeoutMs) {
|
|
367
|
+
return defaultClient ? defaultClient.close(timeoutMs) : Promise.resolve(true);
|
|
368
|
+
}
|
|
369
|
+
export {
|
|
370
|
+
CONTRACT_VERSION,
|
|
371
|
+
Client,
|
|
372
|
+
DEFAULT_ENABLED_ENVIRONMENTS,
|
|
373
|
+
DEFAULT_ENDPOINT,
|
|
374
|
+
FetchTransport,
|
|
375
|
+
MAX_CAUSES,
|
|
376
|
+
MAX_FRAMES,
|
|
377
|
+
QUEUE_LIMIT,
|
|
378
|
+
SDK_NAME,
|
|
379
|
+
SDK_VERSION,
|
|
380
|
+
VALUE_MAX_LENGTH,
|
|
381
|
+
alreadyCaptured,
|
|
382
|
+
buildEvent,
|
|
383
|
+
buildTicketPayload,
|
|
384
|
+
captureException,
|
|
385
|
+
close,
|
|
386
|
+
configured,
|
|
387
|
+
deriveErrorEndpoint,
|
|
388
|
+
deriveReportBaseUrl,
|
|
389
|
+
environmentEnabled,
|
|
390
|
+
errorTrackingEnabled,
|
|
391
|
+
flush,
|
|
392
|
+
getClient,
|
|
393
|
+
init,
|
|
394
|
+
markCaptured,
|
|
395
|
+
parseStack,
|
|
396
|
+
report,
|
|
397
|
+
resolveConfig,
|
|
398
|
+
sampledOut,
|
|
399
|
+
sdkHeader
|
|
400
|
+
};
|
|
401
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/version.ts","../src/config.ts","../src/dedup.ts","../src/stacktrace.ts","../src/util.ts","../src/event.ts","../src/sampling.ts","../src/ticket.ts","../src/transport.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["// The SDK package version and the WIRE CONTRACT major it speaks. The contract version is\n// surfaced in the X-Dispatch-Sdk header so the backend can observe which contract a client\n// uses (e.g. \"dispatch-node/1.2.0 (contract/1)\"). A breaking wire change bumps CONTRACT_VERSION\n// and the whole SDK family's major together.\nexport const SDK_NAME = \"dispatch-js\";\nexport const SDK_VERSION = \"1.0.0\";\nexport const CONTRACT_VERSION = \"1\";\n","import type { DispatchEvent, DispatchUser, Tags } from \"./types\";\nimport { SDK_NAME, SDK_VERSION } from \"./version\";\n\nexport const DEFAULT_ENDPOINT = \"https://dispatchit.app/api/v1/tickets\";\nexport const DEFAULT_ENABLED_ENVIRONMENTS = [\"production\", \"staging\"];\n\nexport interface DispatchOptions {\n /** Project API token (prefix dsp_live_). Required. */\n apiKey: string;\n /** Tickets endpoint. Default https://dispatchit.app/api/v1/tickets. */\n endpoint?: string;\n /** Error-ingest endpoint. Default: `endpoint` with the last path segment swapped to /store. */\n errorEndpoint?: string;\n /** Deploy environment. Default process.env.NODE_ENV, else \"production\". */\n environment?: string;\n /** Release identifier, e.g. a git SHA. */\n release?: string | null;\n /** Environments in which capture is active. Default [\"production\", \"staging\"]; [] means all. */\n enabledEnvironments?: string[];\n /** Master switch for exception capture. Default true. */\n captureExceptions?: boolean;\n /** Fraction of errors to report, 0..1. Default 1.0. */\n errorSampleRate?: number;\n /** Last chance to mutate or drop an event. Return null to drop. */\n beforeSend?: ((event: DispatchEvent) => DispatchEvent | null) | null;\n /** Static affected-user (server adapters resolve a per-request user instead). */\n user?: DispatchUser | null;\n /** Static tags attached to every event. */\n tags?: Tags;\n /** Identifies the producing SDK. Server adapters override the name (e.g. \"dispatch-node\"). */\n sdk?: { name: string; version: string };\n /** Log internal failures to console. Default false. */\n debug?: boolean;\n /** Base URL for human-facing report links. Default: the origin of `endpoint`. */\n reportBaseUrl?: string | null;\n /** Budget (ms) for draining the event queue at process exit; 0 skips the exit flush.\n * Default 3000. Mirrors the gem's shutdown_timeout (seconds there, ms here). */\n shutdownTimeout?: number;\n}\n\nexport interface DispatchConfig {\n apiKey: string;\n endpoint: string;\n errorEndpoint: string;\n reportBaseUrl: string | null;\n environment: string;\n release: string | null;\n enabledEnvironments: string[];\n captureExceptions: boolean;\n errorSampleRate: number;\n beforeSend: ((event: DispatchEvent) => DispatchEvent | null) | null;\n user: DispatchUser | null;\n tags: Tags;\n sdk: { name: string; version: string };\n debug: boolean;\n shutdownTimeout: number;\n}\n\n// Default error endpoint: same host, last path segment swapped to /store\n// (\"/api/v1/tickets\" -> \"/api/v1/store\"). Mirrors Configuration#effective_error_endpoint.\nexport function deriveErrorEndpoint(endpoint: string): string {\n return endpoint.replace(/\\/[^/]+$/, \"/store\");\n}\n\n// Origin (scheme + host[:port]) of the endpoint, or null if unparseable.\n// Mirrors Configuration#effective_report_base_url.\nexport function deriveReportBaseUrl(endpoint: string): string | null {\n try {\n return new URL(endpoint).origin;\n } catch {\n return null;\n }\n}\n\nfunction defaultEnvironment(): string {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process\n ?.env?.NODE_ENV;\n return env && env.length > 0 ? env : \"production\";\n}\n\nexport function resolveConfig(options: DispatchOptions): DispatchConfig {\n const endpoint = options.endpoint ?? DEFAULT_ENDPOINT;\n return {\n apiKey: options.apiKey,\n endpoint,\n errorEndpoint: options.errorEndpoint ?? deriveErrorEndpoint(endpoint),\n reportBaseUrl: options.reportBaseUrl ?? deriveReportBaseUrl(endpoint),\n environment: options.environment ?? defaultEnvironment(),\n release: options.release ?? null,\n enabledEnvironments: options.enabledEnvironments ?? DEFAULT_ENABLED_ENVIRONMENTS,\n captureExceptions: options.captureExceptions ?? true,\n errorSampleRate: options.errorSampleRate ?? 1.0,\n beforeSend: options.beforeSend ?? null,\n user: options.user ?? null,\n tags: options.tags ?? {},\n sdk: options.sdk ?? { name: SDK_NAME, version: SDK_VERSION },\n debug: options.debug ?? false,\n shutdownTimeout: options.shutdownTimeout ?? 3000,\n };\n}\n\nexport function configured(c: DispatchConfig): boolean {\n return Boolean(c.apiKey) && Boolean(c.endpoint);\n}\n\nexport function environmentEnabled(c: DispatchConfig): boolean {\n return c.enabledEnvironments.length === 0 || c.enabledEnvironments.includes(c.environment);\n}\n\nexport function errorTrackingEnabled(c: DispatchConfig): boolean {\n return configured(c) && c.captureExceptions;\n}\n","// Prevents the same error object from being reported twice (e.g. once by a framework error\n// handler and again by a global handler after re-raise). The gem sets an instance variable on\n// the exception; JS can't add hidden props safely across realms, so we track identity in a\n// WeakSet — entries are GC'd with the error, so this never leaks.\nconst captured = new WeakSet<object>();\n\nfunction isObject(value: unknown): value is object {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function alreadyCaptured(error: unknown): boolean {\n return isObject(error) && captured.has(error);\n}\n\nexport function markCaptured(error: unknown): void {\n if (isObject(error)) captured.add(error);\n}\n","import type { DispatchFrame } from \"./types\";\n\nexport const MAX_FRAMES = 100;\n\n// Frames the parser should treat as the app's own code. Excludes dependencies and runtime\n// internals; mirrors the gem's in_app heuristic, adapted to JS runtimes.\nfunction isInApp(file: string): boolean {\n if (!file) return false;\n if (file.includes(\"node_modules\")) return false;\n if (file.startsWith(\"node:\") || file.startsWith(\"internal/\")) return false;\n return true;\n}\n\n// Portable best-effort stack parser. Handles the two dominant formats:\n// V8 (Chrome/Node): \" at fn (file:line:col)\" / \" at file:line:col\"\n// SpiderMonkey/JSC: \"fn@file:line:col\" / \"@file:line:col\"\n// Returns frames OLDEST FIRST (the failing frame last), matching the contract. Lines that\n// don't look like frames (e.g. the leading \"TypeError: ...\" message) are skipped.\n//\n// This is the minimal core parser used by manual capture. The browser SDK ships a more\n// thorough parser (source maps, eval frames); server SDKs add source context on top.\nexport function parseStack(stack?: string | null): DispatchFrame[] {\n if (!stack) return [];\n const frames: DispatchFrame[] = [];\n\n for (const raw of stack.split(\"\\n\")) {\n const line = raw.trim();\n if (!line) continue;\n\n const v8WithFn = /^at\\s+(.+?)\\s+\\((.+?):(\\d+):(\\d+)\\)$/.exec(line);\n const v8NoFn = v8WithFn ? null : /^at\\s+(.+?):(\\d+):(\\d+)$/.exec(line);\n const mozilla = v8WithFn || v8NoFn ? null : /^(.*?)@(.+?):(\\d+):(\\d+)$/.exec(line);\n\n let fn: string;\n let file: string;\n let lineno: number;\n let colno: number;\n\n if (v8WithFn) {\n fn = v8WithFn[1]!;\n file = v8WithFn[2]!;\n lineno = Number(v8WithFn[3]);\n colno = Number(v8WithFn[4]);\n } else if (v8NoFn) {\n fn = \"?\";\n file = v8NoFn[1]!;\n lineno = Number(v8NoFn[2]);\n colno = Number(v8NoFn[3]);\n } else if (mozilla) {\n fn = mozilla[1] || \"?\";\n file = mozilla[2]!;\n lineno = Number(mozilla[3]);\n colno = Number(mozilla[4]);\n } else {\n continue;\n }\n\n frames.push({\n function: fn,\n filename: file,\n abs_path: file,\n lineno,\n colno,\n in_app: isInApp(file),\n });\n }\n\n // Stack is newest-first; cap then reverse to oldest-first (failing frame last).\n return frames.slice(0, MAX_FRAMES).reverse();\n}\n","// Drop keys whose value is null/undefined — the JS analogue of Ruby's Hash#compact, which\n// the gem's EventBuilder uses so absent fields are omitted from the wire payload rather than\n// sent as null.\nexport function compact<T extends Record<string, unknown>>(obj: T): Partial<T> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n if (v !== null && v !== undefined) out[k] = v;\n }\n return out as Partial<T>;\n}\n\n// UUID v4 with hyphens removed — the contract's event_id shape (32 lowercase hex chars).\nexport function uuid32(): string {\n return globalThis.crypto.randomUUID().replace(/-/g, \"\");\n}\n\n// Seconds since the Unix epoch, as a float (matches Ruby's Time.now.to_f).\nexport function epochSeconds(): number {\n return Date.now() / 1000;\n}\n\nexport function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type {\n DispatchConfig,\n} from \"./config\";\nimport type {\n DispatchEvent,\n DispatchExceptionValue,\n DispatchFrame,\n DispatchRequest,\n DispatchUser,\n Level,\n Tags,\n} from \"./types\";\nimport { parseStack } from \"./stacktrace\";\nimport { epochSeconds, uuid32 } from \"./util\";\n\nexport const MAX_CAUSES = 5;\nexport const VALUE_MAX_LENGTH = 2000;\n\nexport interface BuildEventInput {\n config: DispatchConfig;\n handled: boolean;\n platform?: string;\n level?: Level;\n user?: DispatchUser | null;\n tags?: Tags;\n request?: DispatchRequest;\n transaction?: string | null;\n serverName?: string | null;\n /** Injectable for runtime-specific parsing (e.g. the Node V8 parser). Defaults to core's. */\n parseStack?: (stack?: string | null) => DispatchFrame[];\n /** Injectable for deterministic tests. */\n now?: () => number;\n uuid?: () => string;\n}\n\ninterface ErrorLike {\n name?: unknown;\n message?: unknown;\n stack?: unknown;\n cause?: unknown;\n}\n\nfunction asError(value: unknown): ErrorLike | null {\n return typeof value === \"object\" && value !== null ? (value as ErrorLike) : null;\n}\n\nfunction exceptionValue(\n error: unknown,\n handled: boolean,\n parse: (stack?: string | null) => DispatchFrame[],\n): DispatchExceptionValue {\n const err = asError(error);\n const type = (err && typeof err.name === \"string\" && err.name) || \"Error\";\n const rawMessage =\n err && typeof err.message === \"string\" ? err.message : String(error ?? \"\");\n const stack = err && typeof err.stack === \"string\" ? err.stack : undefined;\n return {\n type,\n value: rawMessage.slice(0, VALUE_MAX_LENGTH),\n mechanism: { type: \"generic\", handled },\n stacktrace: { frames: parse(stack) },\n };\n}\n\n// Walk the `cause` chain up to MAX_CAUSES and emit Sentry-ordered values: OLDEST CAUSE FIRST,\n// the raised error LAST. Mirrors EventBuilder#exception_values.\nfunction exceptionValues(\n error: unknown,\n handled: boolean,\n parse: (stack?: string | null) => DispatchFrame[],\n): DispatchExceptionValue[] {\n const chain: unknown[] = [];\n let current: unknown = error;\n for (let depth = 0; depth < MAX_CAUSES && current != null; depth++) {\n chain.push(current);\n current = asError(current)?.cause;\n }\n chain.reverse();\n return chain.map((e) => exceptionValue(e, handled, parse));\n}\n\n// Build the Sentry-shaped event from an error. The pure assembly lives here; runtime-specific\n// concerns (source context, request extraction) are layered on by injecting parseStack and\n// passing request/user/transaction.\nexport function buildEvent(error: unknown, input: BuildEventInput): DispatchEvent {\n const parse = input.parseStack ?? parseStack;\n const now = input.now ?? epochSeconds;\n const id = input.uuid ?? uuid32;\n const c = input.config;\n\n const derivedTags: Tags = {};\n if (input.transaction) derivedTags[\"transaction\"] = input.transaction;\n const tags: Tags = { ...derivedTags, ...c.tags, ...(input.tags ?? {}) };\n\n const event: DispatchEvent = {\n event_id: id(),\n timestamp: now(),\n platform: input.platform ?? \"javascript\",\n level: input.level ?? \"error\",\n environment: c.environment,\n exception: { values: exceptionValues(error, input.handled, parse) },\n };\n\n // Optional fields are set only when present, so they're omitted (not null) on the wire.\n if (c.release != null) event.release = c.release;\n if (input.serverName != null) event.server_name = input.serverName;\n if (input.transaction != null) event.transaction = input.transaction;\n if (input.request) event.request = input.request;\n const user = input.user ?? c.user;\n if (user != null) event.user = user;\n if (Object.keys(tags).length > 0) event.tags = tags;\n event.sdk = c.sdk;\n\n return event;\n}\n","// Client-side error sampling. Mirrors Reporter#sampled_out?: a rate >= 1 keeps everything,\n// <= 0 drops everything, otherwise keep with probability `rate`. The rng is injectable so\n// tests are deterministic.\nexport function sampledOut(rate: number, rng: () => number = Math.random): boolean {\n if (rate >= 1) return false;\n if (rate <= 0) return true;\n return rng() > rate;\n}\n","import type { TicketAttachment, TicketPayload, TicketReporter } from \"./types\";\nimport { compact } from \"./util\";\n\nexport interface ReportInput {\n /** Required. The human-readable description of the issue. */\n description: string;\n title?: string;\n /** One of low/medium/high/critical. Unknown values are dropped server-side. */\n severity?: string | null;\n /** Origin of the report. Default \"api\". */\n source?: string;\n metadata?: Record<string, unknown>;\n reporter?: TicketReporter | null;\n /** Links the ticket to an already-captured error group (e.g. a request id or event_id). */\n correlationId?: string | null;\n attachments?: TicketAttachment[];\n}\n\n// Build the { ticket: {...} } body for the tickets endpoint. Mirrors Dispatch::Rails.report:\n// correlation_id is folded into metadata, and absent fields are omitted.\nexport function buildTicketPayload(input: ReportInput): TicketPayload {\n const metadata: Record<string, unknown> = { ...(input.metadata ?? {}) };\n if (input.correlationId) metadata[\"correlation_id\"] = input.correlationId;\n\n const ticket = compact({\n description: input.description,\n title: input.title,\n source: input.source ?? \"api\",\n severity: input.severity ?? undefined,\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n reporter: input.reporter ?? undefined,\n attachments: input.attachments,\n });\n\n return { ticket } as TicketPayload;\n}\n","import type { DispatchConfig } from \"./config\";\nimport type { DispatchEvent, TicketPayload, TicketResponse } from \"./types\";\nimport { CONTRACT_VERSION } from \"./version\";\nimport { delay } from \"./util\";\n\nexport const QUEUE_LIMIT = 100;\nexport const DEFAULT_FLUSH_TIMEOUT = 2000;\n\nexport interface Transport {\n /** Enqueue an error event for asynchronous delivery (off the hot path). */\n sendEvent(event: DispatchEvent): void;\n /** Synchronously POST a ticket and return the parsed response (or null on failure). */\n postTicket(payload: TicketPayload): Promise<TicketResponse | null>;\n /** Resolve once the queue has drained (or the timeout elapses). */\n flush(timeoutMs?: number): Promise<boolean>;\n}\n\nexport type FetchLike = (\n input: string,\n init: { method: string; headers: Record<string, string>; body: string; keepalive?: boolean },\n) => Promise<{ ok: boolean; status: number; json(): Promise<unknown> }>;\n\n// \"dispatch-node/1.2.0 (contract/1)\" — lets the backend observe the SDK + contract version.\nexport function sdkHeader(config: DispatchConfig): string {\n return `${config.sdk.name}/${config.sdk.version} (contract/${CONTRACT_VERSION})`;\n}\n\n// A bounded, fire-and-forget transport built on the global fetch (present in Node 18+ and all\n// browsers). Mirrors the gem's Transport: a bounded queue (drop-on-overflow, never blocks the\n// caller) drained sequentially; failures are swallowed so telemetry never breaks the app.\n// Runtime packages can subclass/replace this (Node adds flush-on-exit; browser adds beacons).\nexport class FetchTransport implements Transport {\n private queue: DispatchEvent[] = [];\n private draining: Promise<void> | null = null;\n private readonly fetchImpl: FetchLike | undefined;\n\n constructor(\n protected readonly config: DispatchConfig,\n fetchImpl?: FetchLike,\n ) {\n this.fetchImpl =\n fetchImpl ?? (globalThis.fetch as unknown as FetchLike | undefined);\n }\n\n sendEvent(event: DispatchEvent): void {\n if (this.queue.length >= QUEUE_LIMIT) {\n this.warn(`queue full (${QUEUE_LIMIT}), dropping event ${event.event_id}`);\n return;\n }\n this.queue.push(event);\n this.kick();\n }\n\n async postTicket(payload: TicketPayload): Promise<TicketResponse | null> {\n const res = await this.post(this.config.endpoint, payload);\n if (!res || !res.ok) return null;\n try {\n return (await res.json()) as TicketResponse;\n } catch {\n return null;\n }\n }\n\n async flush(timeoutMs: number = DEFAULT_FLUSH_TIMEOUT): Promise<boolean> {\n if (this.draining) {\n await Promise.race([this.draining, delay(timeoutMs)]);\n }\n return this.queue.length === 0;\n }\n\n private kick(): void {\n if (this.draining) return;\n this.draining = this.drain().finally(() => {\n this.draining = null;\n });\n }\n\n private async drain(): Promise<void> {\n while (this.queue.length > 0) {\n const event = this.queue.shift()!;\n await this.post(this.config.errorEndpoint, event);\n }\n }\n\n protected async post(\n url: string,\n body: unknown,\n ): Promise<{ ok: boolean; status: number; json(): Promise<unknown> } | null> {\n if (!this.fetchImpl) {\n this.warn(\"no fetch implementation available\");\n return null;\n }\n try {\n return await this.fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n \"X-Dispatch-Sdk\": sdkHeader(this.config),\n },\n body: JSON.stringify(body),\n keepalive: true,\n });\n } catch (err) {\n this.warn(`delivery failed: ${String(err)}`);\n return null;\n }\n }\n\n protected warn(message: string): void {\n if (this.config.debug) console.warn(`[dispatch] ${message}`);\n }\n}\n","import {\n type DispatchConfig,\n type DispatchOptions,\n configured,\n environmentEnabled,\n errorTrackingEnabled,\n resolveConfig,\n} from \"./config\";\nimport { alreadyCaptured, markCaptured } from \"./dedup\";\nimport { buildEvent } from \"./event\";\nimport { sampledOut } from \"./sampling\";\nimport { type ReportInput, buildTicketPayload } from \"./ticket\";\nimport { FetchTransport, type Transport } from \"./transport\";\nimport type {\n DispatchFrame,\n DispatchRequest,\n DispatchUser,\n Level,\n Tags,\n TicketResponse,\n} from \"./types\";\n\nexport interface CaptureContext {\n level?: Level;\n /** Defaults to true for manual capture; framework handlers pass false for unhandled errors. */\n handled?: boolean;\n user?: DispatchUser | null;\n tags?: Tags;\n request?: DispatchRequest;\n transaction?: string | null;\n serverName?: string | null;\n}\n\nexport interface ClientOptions extends DispatchOptions {\n /** Override the transport (tests, or a runtime-specific transport). */\n transport?: Transport;\n /** The originating runtime written into event.platform. Default \"javascript\". */\n platform?: string;\n /** Injectable stack parser (e.g. the Node V8 parser, or a browser parser). */\n parseStack?: (stack?: string | null) => DispatchFrame[];\n /** Injectable RNG for deterministic sampling in tests. */\n rng?: () => number;\n}\n\n// The capture pipeline, mirroring the gem's Reporter + the top-level Dispatch::Rails API:\n// gate on config/environment, dedup, sample, build, before_send, deliver — and NEVER throw.\nexport class Client {\n readonly config: DispatchConfig;\n readonly transport: Transport;\n private readonly platform: string;\n private readonly parseStack: ((stack?: string | null) => DispatchFrame[]) | undefined;\n private readonly rng: () => number;\n\n constructor(options: ClientOptions) {\n this.config = resolveConfig(options);\n this.transport = options.transport ?? new FetchTransport(this.config);\n this.platform = options.platform ?? \"javascript\";\n this.parseStack = options.parseStack;\n this.rng = options.rng ?? Math.random;\n }\n\n captureException(error: unknown, context: CaptureContext = {}): void {\n try {\n const c = this.config;\n if (!errorTrackingEnabled(c)) return;\n if (!environmentEnabled(c)) return;\n if (alreadyCaptured(error)) return;\n if (sampledOut(c.errorSampleRate, this.rng)) return;\n markCaptured(error);\n\n let event = buildEvent(error, {\n config: c,\n platform: this.platform,\n level: context.level ?? \"error\",\n handled: context.handled ?? true,\n user: context.user,\n tags: context.tags,\n request: context.request,\n transaction: context.transaction,\n serverName: context.serverName,\n parseStack: this.parseStack,\n });\n\n if (c.beforeSend) {\n const result = c.beforeSend(event);\n if (!result) return;\n event = result;\n }\n\n this.transport.sendEvent(event);\n } catch (err) {\n if (this.config.debug) console.warn(`[dispatch] capture failed: ${String(err)}`);\n }\n }\n\n async report(input: ReportInput): Promise<TicketResponse | null> {\n if (!configured(this.config)) return null;\n try {\n return await this.transport.postTicket(buildTicketPayload(input));\n } catch {\n return null;\n }\n }\n\n flush(timeoutMs?: number): Promise<boolean> {\n return this.transport.flush(timeoutMs);\n }\n\n close(timeoutMs?: number): Promise<boolean> {\n return this.transport.flush(timeoutMs);\n }\n}\n","// @dispatchitapp/core — the framework-agnostic core of the Dispatch SDKs.\n//\n// On its own this is a usable minimal SDK (manual capture + report()) anywhere a global\n// `fetch` exists (Node 18+, browsers). Runtime packages layer on top: @dispatchitapp/node adds\n// source context, global handlers and flush-on-exit; @dispatchitapp/browser adds the error tracker\n// and the feedback widget; framework adapters add middleware.\n\nimport { Client, type ClientOptions, type CaptureContext } from \"./client\";\nimport type { ReportInput } from \"./ticket\";\nimport type { TicketResponse } from \"./types\";\n\nexport { Client } from \"./client\";\nexport type { CaptureContext, ClientOptions } from \"./client\";\nexport {\n type DispatchOptions,\n type DispatchConfig,\n DEFAULT_ENDPOINT,\n DEFAULT_ENABLED_ENVIRONMENTS,\n deriveErrorEndpoint,\n deriveReportBaseUrl,\n resolveConfig,\n configured,\n environmentEnabled,\n errorTrackingEnabled,\n} from \"./config\";\nexport { buildEvent, MAX_CAUSES, VALUE_MAX_LENGTH } from \"./event\";\nexport { parseStack, MAX_FRAMES } from \"./stacktrace\";\nexport { sampledOut } from \"./sampling\";\nexport { alreadyCaptured, markCaptured } from \"./dedup\";\nexport { buildTicketPayload, type ReportInput } from \"./ticket\";\nexport {\n FetchTransport,\n type Transport,\n type FetchLike,\n sdkHeader,\n QUEUE_LIMIT,\n} from \"./transport\";\nexport { SDK_NAME, SDK_VERSION, CONTRACT_VERSION } from \"./version\";\nexport * from \"./types\";\n\n// ---- Module-level default client (Sentry-style ergonomics) -------------------------------\n\nlet defaultClient: Client | null = null;\n\n/** Initialise the default client. Call once at startup. Returns it for direct use. */\nexport function init(options: ClientOptions): Client {\n defaultClient = new Client(options);\n return defaultClient;\n}\n\n/** The default client, or null if init() hasn't been called. */\nexport function getClient(): Client | null {\n return defaultClient;\n}\n\n/** Report a handled (or, from adapters, unhandled) exception via the default client. */\nexport function captureException(error: unknown, context?: CaptureContext): void {\n defaultClient?.captureException(error, context);\n}\n\n/** File a curated ticket via the default client. Resolves null if uninitialised. */\nexport function report(input: ReportInput): Promise<TicketResponse | null> {\n return defaultClient ? defaultClient.report(input) : Promise.resolve(null);\n}\n\n/** Wait for queued events to flush. Resolves true if the queue drained in time. */\nexport function flush(timeoutMs?: number): Promise<boolean> {\n return defaultClient ? defaultClient.flush(timeoutMs) : Promise.resolve(true);\n}\n\n/** Flush and stop using the default client. */\nexport function close(timeoutMs?: number): Promise<boolean> {\n return defaultClient ? defaultClient.close(timeoutMs) : Promise.resolve(true);\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dispatchitapp/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Framework-agnostic core for the Dispatch SDKs: config, event builder, sampling, dedup, before_send, ticket client, bounded transport.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Dispatch Team <hello@dispatchit.app>",
|
|
7
|
+
"homepage": "https://dispatchit.app",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Recursivity-LLC/dispatch-sdks.git",
|
|
11
|
+
"directory": "packages/core"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/Recursivity-LLC/dispatch-sdks/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"error-tracking",
|
|
16
|
+
"bug-report",
|
|
17
|
+
"monitoring",
|
|
18
|
+
"dispatch",
|
|
19
|
+
"sentry"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public",
|
|
23
|
+
"provenance": true
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"require": "./dist/index.cjs"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"sideEffects": false,
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^20.14.0",
|
|
42
|
+
"ajv": "^8.17.0",
|
|
43
|
+
"ajv-formats": "^3.0.1",
|
|
44
|
+
"tsup": "^8.0.0",
|
|
45
|
+
"typescript": "^5.5.0",
|
|
46
|
+
"vitest": "^2.0.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsup",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"lint": "tsc --noEmit"
|
|
53
|
+
}
|
|
54
|
+
}
|