better-auth-audit-logs 0.1.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.
Files changed (46) hide show
  1. package/README.md +366 -0
  2. package/dist/adapters/index.d.ts +2 -0
  3. package/dist/adapters/index.d.ts.map +1 -0
  4. package/dist/adapters/memory.d.ts +9 -0
  5. package/dist/adapters/memory.d.ts.map +1 -0
  6. package/dist/client.cjs +53 -0
  7. package/dist/client.d.ts +11 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +13 -0
  10. package/dist/endpoints/get-log.d.ts +28 -0
  11. package/dist/endpoints/get-log.d.ts.map +1 -0
  12. package/dist/endpoints/index.d.ts +4 -0
  13. package/dist/endpoints/index.d.ts.map +1 -0
  14. package/dist/endpoints/insert-log.d.ts +45 -0
  15. package/dist/endpoints/insert-log.d.ts.map +1 -0
  16. package/dist/endpoints/list-logs.d.ts +41 -0
  17. package/dist/endpoints/list-logs.d.ts.map +1 -0
  18. package/dist/hooks/after.d.ts +7 -0
  19. package/dist/hooks/after.d.ts.map +1 -0
  20. package/dist/hooks/before.d.ts +8 -0
  21. package/dist/hooks/before.d.ts.map +1 -0
  22. package/dist/hooks/index.d.ts +3 -0
  23. package/dist/hooks/index.d.ts.map +1 -0
  24. package/dist/index.cjs +564 -0
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +522 -0
  28. package/dist/internal.d.ts +16 -0
  29. package/dist/internal.d.ts.map +1 -0
  30. package/dist/plugin.d.ts +181 -0
  31. package/dist/plugin.d.ts.map +1 -0
  32. package/dist/schema.d.ts +109 -0
  33. package/dist/schema.d.ts.map +1 -0
  34. package/dist/types.d.ts +88 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/utils/index.d.ts +5 -0
  37. package/dist/utils/index.d.ts.map +1 -0
  38. package/dist/utils/normalize-path.d.ts +2 -0
  39. package/dist/utils/normalize-path.d.ts.map +1 -0
  40. package/dist/utils/request-meta.d.ts +6 -0
  41. package/dist/utils/request-meta.d.ts.map +1 -0
  42. package/dist/utils/sanitize.d.ts +4 -0
  43. package/dist/utils/sanitize.d.ts.map +1 -0
  44. package/dist/utils/severity.d.ts +3 -0
  45. package/dist/utils/severity.d.ts.map +1 -0
  46. package/package.json +43 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,564 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/index.ts
40
+ var exports_src = {};
41
+ __export(exports_src, {
42
+ auditLog: () => auditLog,
43
+ MemoryStorage: () => MemoryStorage
44
+ });
45
+ module.exports = __toCommonJS(exports_src);
46
+
47
+ // src/schema.ts
48
+ var import_db = require("better-auth/db");
49
+ var baseSchema = {
50
+ auditLog: {
51
+ modelName: "audit_log",
52
+ fields: {
53
+ userId: {
54
+ type: "string",
55
+ required: false,
56
+ references: {
57
+ model: "user",
58
+ field: "id",
59
+ onDelete: "set null"
60
+ },
61
+ index: true
62
+ },
63
+ action: {
64
+ type: "string",
65
+ required: true,
66
+ sortable: true,
67
+ index: true
68
+ },
69
+ status: {
70
+ type: "string",
71
+ required: true,
72
+ sortable: true
73
+ },
74
+ severity: {
75
+ type: "string",
76
+ required: true,
77
+ sortable: true
78
+ },
79
+ ipAddress: {
80
+ type: "string",
81
+ required: false
82
+ },
83
+ userAgent: {
84
+ type: "string",
85
+ required: false,
86
+ returned: false
87
+ },
88
+ metadata: {
89
+ type: "string",
90
+ required: false
91
+ },
92
+ createdAt: {
93
+ type: "date",
94
+ required: true,
95
+ sortable: true,
96
+ index: true,
97
+ defaultValue: () => new Date
98
+ }
99
+ }
100
+ }
101
+ };
102
+ function buildSchema(options) {
103
+ return import_db.mergeSchema(baseSchema, options?.schema);
104
+ }
105
+ function getModelName(options) {
106
+ return options?.schema?.auditLog?.modelName ?? "audit_log";
107
+ }
108
+
109
+ // src/hooks/before.ts
110
+ var import_api2 = require("better-auth/api");
111
+
112
+ // src/utils/normalize-path.ts
113
+ function normalizePath(path) {
114
+ return path.replace(/^\//, "").replace(/\//g, ":");
115
+ }
116
+ // src/utils/severity.ts
117
+ var CRITICAL = ["ban-user", "impersonate-user"];
118
+ var HIGH = [
119
+ "delete-user",
120
+ "delete-account",
121
+ "revoke-sessions",
122
+ "revoke-other-sessions"
123
+ ];
124
+ var MEDIUM = [
125
+ "sign-in",
126
+ "sign-out",
127
+ "revoke-session",
128
+ "two-factor",
129
+ "change-password",
130
+ "reset-password"
131
+ ];
132
+ function inferSeverity(action, status) {
133
+ if (CRITICAL.some((p) => action.includes(p)))
134
+ return "critical";
135
+ if (HIGH.some((p) => action.includes(p)))
136
+ return "high";
137
+ if (MEDIUM.some((p) => action.includes(p)))
138
+ return status === "failed" ? "high" : "medium";
139
+ return "low";
140
+ }
141
+ // src/utils/request-meta.ts
142
+ var import_api = require("better-auth/api");
143
+ function extractRequestMeta(request, headers, options) {
144
+ return {
145
+ ipAddress: request ? import_api.getIp(request, options) ?? null : null,
146
+ userAgent: headers?.get("user-agent") ?? null
147
+ };
148
+ }
149
+ // src/utils/sanitize.ts
150
+ var DEFAULT_PII_FIELDS = [
151
+ "password",
152
+ "newPassword",
153
+ "currentPassword",
154
+ "token",
155
+ "secret",
156
+ "apiKey",
157
+ "refreshToken",
158
+ "accessToken",
159
+ "code",
160
+ "backupCode",
161
+ "otp"
162
+ ];
163
+ async function sha256(value) {
164
+ const encoded = new TextEncoder().encode(value);
165
+ const buffer = await crypto.subtle.digest("SHA-256", encoded);
166
+ return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
167
+ }
168
+ async function redactPII(data, config) {
169
+ if (!config.enabled)
170
+ return data;
171
+ const fields = config.fields ?? DEFAULT_PII_FIELDS;
172
+ const strategy = config.strategy ?? "mask";
173
+ const result = { ...data };
174
+ for (const field of fields) {
175
+ if (!(field in result) || result[field] == null)
176
+ continue;
177
+ if (strategy === "remove") {
178
+ delete result[field];
179
+ } else if (strategy === "hash") {
180
+ result[field] = await sha256(String(result[field]));
181
+ } else {
182
+ result[field] = "[REDACTED]";
183
+ }
184
+ }
185
+ return result;
186
+ }
187
+ // src/internal.ts
188
+ async function buildLogEntry(path, status, params) {
189
+ const action = normalizePath(path);
190
+ const severity = params.pathConfig?.severity ?? inferSeverity(action, status);
191
+ const captureOpts = {
192
+ ...params.options.capture,
193
+ ...params.pathConfig?.capture
194
+ };
195
+ const { ipAddress, userAgent } = extractRequestMeta(captureOpts.ipAddress !== false ? params.request : undefined, captureOpts.userAgent !== false ? params.headers : undefined, params.authOptions);
196
+ let metadata = params.metadata ?? {};
197
+ if (params.options.piiRedaction.enabled) {
198
+ metadata = await redactPII(metadata, params.options.piiRedaction);
199
+ }
200
+ return {
201
+ userId: params.userId,
202
+ action,
203
+ status,
204
+ severity,
205
+ ipAddress,
206
+ userAgent,
207
+ metadata,
208
+ createdAt: new Date
209
+ };
210
+ }
211
+ async function buildLogEntryFromAction(action, status, params) {
212
+ const severity = inferSeverity(action, status);
213
+ const { ipAddress, userAgent } = extractRequestMeta(params.options.capture.ipAddress !== false ? params.request : undefined, params.options.capture.userAgent !== false ? params.headers : undefined, params.authOptions);
214
+ let metadata = params.metadata ?? {};
215
+ if (params.options.piiRedaction.enabled) {
216
+ metadata = await redactPII(metadata, params.options.piiRedaction);
217
+ }
218
+ return {
219
+ userId: params.userId,
220
+ action,
221
+ status,
222
+ severity,
223
+ ipAddress,
224
+ userAgent,
225
+ metadata,
226
+ createdAt: new Date
227
+ };
228
+ }
229
+ async function writeEntry(ctx, entry, opts, modelName) {
230
+ let finalEntry = entry;
231
+ if (opts.beforeLog) {
232
+ const modified = await opts.beforeLog(finalEntry);
233
+ if (modified === null)
234
+ return;
235
+ finalEntry = modified;
236
+ }
237
+ const doWrite = async () => {
238
+ let written;
239
+ if (opts.storage) {
240
+ written = { id: crypto.randomUUID(), ...finalEntry };
241
+ await opts.storage.write(written);
242
+ } else {
243
+ const record = await ctx.context.adapter.create({
244
+ model: modelName,
245
+ data: {
246
+ ...finalEntry,
247
+ metadata: JSON.stringify(finalEntry.metadata)
248
+ }
249
+ });
250
+ written = { ...record, metadata: finalEntry.metadata };
251
+ }
252
+ if (opts.afterLog)
253
+ await opts.afterLog(written);
254
+ };
255
+ if (opts.nonBlocking) {
256
+ ctx.context.runInBackground(doWrite().catch((err) => ctx.context.logger?.error("[audit-log] write failed", err)));
257
+ } else {
258
+ await doWrite();
259
+ }
260
+ }
261
+
262
+ // src/hooks/before.ts
263
+ var BEFORE_PATHS = [
264
+ "/sign-out",
265
+ "/delete-user",
266
+ "/revoke-session",
267
+ "/revoke-sessions",
268
+ "/revoke-other-sessions"
269
+ ];
270
+ function createBeforeHooks(opts, modelName) {
271
+ return [
272
+ {
273
+ matcher: (context) => !!context.path && BEFORE_PATHS.some((p) => context.path.startsWith(p)) && opts.shouldCapture(context.path),
274
+ handler: import_api2.createAuthMiddleware(async (ctx) => {
275
+ try {
276
+ const session = await import_api2.getSessionFromCtx(ctx);
277
+ const path = ctx.path;
278
+ const pathConfig = opts.getPathConfig(path);
279
+ const entry = await buildLogEntry(path, "success", {
280
+ userId: session?.user?.id ?? null,
281
+ request: ctx.request,
282
+ headers: ctx.headers,
283
+ pathConfig,
284
+ options: opts,
285
+ authOptions: ctx.context.options
286
+ });
287
+ await writeEntry(ctx, entry, opts, modelName);
288
+ } catch (err) {
289
+ ctx.context.logger?.error("[audit-log] before hook failed", err);
290
+ }
291
+ })
292
+ }
293
+ ];
294
+ }
295
+ // src/hooks/after.ts
296
+ var import_api3 = require("better-auth/api");
297
+ function createAfterHooks(opts, modelName) {
298
+ return [
299
+ {
300
+ matcher: (context) => !!context.path && !BEFORE_PATHS.some((p) => context.path.startsWith(p)) && opts.shouldCapture(context.path),
301
+ handler: import_api3.createAuthMiddleware(async (ctx) => {
302
+ try {
303
+ const path = ctx.path;
304
+ const isError = ctx.context.returned instanceof Error;
305
+ const status = isError ? "failed" : "success";
306
+ const user = ctx.context.newSession?.user ?? ctx.context.session?.user;
307
+ const pathConfig = opts.getPathConfig(path);
308
+ const metadata = {};
309
+ if (opts.capture.requestBody && ctx.body) {
310
+ metadata.requestBody = ctx.body;
311
+ }
312
+ if (isError) {
313
+ const err = ctx.context.returned;
314
+ metadata.error = {
315
+ message: err.message,
316
+ ...err.status !== undefined && { status: err.status },
317
+ ...err.code !== undefined && { code: err.code }
318
+ };
319
+ }
320
+ const entry = await buildLogEntry(path, status, {
321
+ userId: user?.id ?? null,
322
+ request: ctx.request,
323
+ headers: ctx.headers,
324
+ metadata,
325
+ pathConfig,
326
+ options: opts,
327
+ authOptions: ctx.context.options
328
+ });
329
+ await writeEntry(ctx, entry, opts, modelName);
330
+ } catch (err) {
331
+ ctx.context.logger?.error("[audit-log] after hook failed", err);
332
+ }
333
+ })
334
+ }
335
+ ];
336
+ }
337
+ // src/endpoints/list-logs.ts
338
+ var import_api4 = require("better-auth/api");
339
+ var import_zod = require("zod");
340
+ function createListLogsEndpoint(opts, modelName) {
341
+ return import_api4.createAuthEndpoint("/audit-log/list", {
342
+ method: "GET",
343
+ use: [import_api4.sessionMiddleware],
344
+ query: import_zod.z.object({
345
+ userId: import_zod.z.string().optional(),
346
+ action: import_zod.z.string().optional(),
347
+ status: import_zod.z.enum(["success", "failed"]).optional(),
348
+ from: import_zod.z.string().optional(),
349
+ to: import_zod.z.string().optional(),
350
+ limit: import_zod.z.coerce.number().min(1).max(500).optional().default(50),
351
+ offset: import_zod.z.coerce.number().min(0).optional().default(0)
352
+ })
353
+ }, async (ctx) => {
354
+ const session = ctx.context.session;
355
+ const targetUserId = ctx.query.userId ?? session.user.id;
356
+ if (targetUserId !== session.user.id) {
357
+ throw new import_api4.APIError("FORBIDDEN", {
358
+ message: "Cannot query other users' audit logs"
359
+ });
360
+ }
361
+ const fromDate = ctx.query.from ? new Date(ctx.query.from) : undefined;
362
+ const toDate = ctx.query.to ? new Date(ctx.query.to) : undefined;
363
+ if (opts.storage?.read) {
364
+ const readOpts = {
365
+ userId: targetUserId,
366
+ action: ctx.query.action,
367
+ status: ctx.query.status,
368
+ from: fromDate,
369
+ to: toDate,
370
+ limit: ctx.query.limit,
371
+ offset: ctx.query.offset
372
+ };
373
+ const result = await opts.storage.read(readOpts);
374
+ return ctx.json(result);
375
+ }
376
+ const where = [{ field: "userId", value: targetUserId }];
377
+ if (ctx.query.action) {
378
+ where.push({ field: "action", value: ctx.query.action });
379
+ }
380
+ if (ctx.query.status) {
381
+ where.push({ field: "status", value: ctx.query.status });
382
+ }
383
+ if (fromDate) {
384
+ where.push({ field: "createdAt", operator: "gte", value: fromDate });
385
+ }
386
+ if (toDate) {
387
+ where.push({ field: "createdAt", operator: "lte", value: toDate });
388
+ }
389
+ const [entries, total] = await Promise.all([
390
+ ctx.context.adapter.findMany({
391
+ model: modelName,
392
+ where,
393
+ sortBy: { field: "createdAt", direction: "desc" },
394
+ limit: ctx.query.limit,
395
+ offset: ctx.query.offset
396
+ }),
397
+ ctx.context.adapter.count({ model: modelName, where })
398
+ ]);
399
+ const parsed = entries.map((e) => ({
400
+ ...e,
401
+ metadata: typeof e["metadata"] === "string" ? JSON.parse(e["metadata"]) : e["metadata"] ?? {}
402
+ }));
403
+ return ctx.json({ entries: parsed, total });
404
+ });
405
+ }
406
+ // src/endpoints/get-log.ts
407
+ var import_api5 = require("better-auth/api");
408
+ function createGetLogEndpoint(opts, modelName) {
409
+ return import_api5.createAuthEndpoint("/audit-log/:id", { method: "GET", use: [import_api5.sessionMiddleware] }, async (ctx) => {
410
+ const { id } = ctx.params;
411
+ const session = ctx.context.session;
412
+ if (opts.storage?.readById) {
413
+ const entry2 = await opts.storage.readById(id);
414
+ if (!entry2 || entry2.userId !== session.user.id) {
415
+ throw new import_api5.APIError("NOT_FOUND", {
416
+ message: "Audit log entry not found"
417
+ });
418
+ }
419
+ return ctx.json(entry2);
420
+ }
421
+ const record = await ctx.context.adapter.findOne({
422
+ model: modelName,
423
+ where: [
424
+ { field: "id", value: id },
425
+ { field: "userId", value: session.user.id }
426
+ ]
427
+ });
428
+ if (!record) {
429
+ throw new import_api5.APIError("NOT_FOUND", {
430
+ message: "Audit log entry not found"
431
+ });
432
+ }
433
+ const entry = {
434
+ ...record,
435
+ metadata: typeof record["metadata"] === "string" ? JSON.parse(record["metadata"]) : record["metadata"] ?? {}
436
+ };
437
+ return ctx.json(entry);
438
+ });
439
+ }
440
+ // src/endpoints/insert-log.ts
441
+ var import_api6 = require("better-auth/api");
442
+ var import_zod2 = require("zod");
443
+ function createInsertLogEndpoint(opts, modelName) {
444
+ return import_api6.createAuthEndpoint("/audit-log/insert", {
445
+ method: "POST",
446
+ use: [import_api6.sessionMiddleware],
447
+ body: import_zod2.z.object({
448
+ action: import_zod2.z.string().min(1),
449
+ status: import_zod2.z.enum(["success", "failed"]).optional().default("success"),
450
+ severity: import_zod2.z.enum(["low", "medium", "high", "critical"]).optional(),
451
+ metadata: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()).optional().default({})
452
+ })
453
+ }, async (ctx) => {
454
+ const session = ctx.context.session;
455
+ const { action, status, severity, metadata } = ctx.body;
456
+ const entry = await buildLogEntryFromAction(action, status, {
457
+ userId: session.user.id,
458
+ request: ctx.request,
459
+ headers: ctx.headers,
460
+ metadata,
461
+ options: opts,
462
+ authOptions: ctx.context.options
463
+ });
464
+ if (severity) {
465
+ entry.severity = severity;
466
+ }
467
+ await writeEntry(ctx, entry, opts, modelName);
468
+ return ctx.json({ success: true });
469
+ });
470
+ }
471
+ // src/plugin.ts
472
+ function resolveOptions(options) {
473
+ const pathsMap = new Map;
474
+ const hasPaths = (options?.paths?.length ?? 0) > 0;
475
+ for (const p of options?.paths ?? []) {
476
+ if (typeof p === "string") {
477
+ pathsMap.set(p, undefined);
478
+ } else {
479
+ pathsMap.set(p.path, p.config);
480
+ }
481
+ }
482
+ return {
483
+ enabled: options?.enabled ?? true,
484
+ nonBlocking: options?.nonBlocking ?? false,
485
+ storage: options?.storage,
486
+ capture: {
487
+ ipAddress: options?.capture?.ipAddress ?? true,
488
+ userAgent: options?.capture?.userAgent ?? true,
489
+ requestBody: options?.capture?.requestBody ?? false
490
+ },
491
+ piiRedaction: {
492
+ enabled: options?.piiRedaction?.enabled ?? false,
493
+ fields: options?.piiRedaction?.fields,
494
+ strategy: options?.piiRedaction?.strategy ?? "mask"
495
+ },
496
+ retention: options?.retention,
497
+ beforeLog: options?.beforeLog,
498
+ afterLog: options?.afterLog,
499
+ shouldCapture: (path) => !hasPaths || pathsMap.has(path),
500
+ getPathConfig: (path) => pathsMap.get(path)
501
+ };
502
+ }
503
+ function auditLog(options) {
504
+ const schema = buildSchema(options);
505
+ const modelName = getModelName(options);
506
+ const resolved = resolveOptions(options);
507
+ const beforeHooks = resolved.enabled ? createBeforeHooks(resolved, modelName) : [];
508
+ const afterHooks = resolved.enabled ? createAfterHooks(resolved, modelName) : [];
509
+ return {
510
+ id: "audit-log",
511
+ schema,
512
+ hooks: {
513
+ before: beforeHooks,
514
+ after: afterHooks
515
+ },
516
+ endpoints: {
517
+ listAuditLogs: createListLogsEndpoint(resolved, modelName),
518
+ getAuditLog: createGetLogEndpoint(resolved, modelName),
519
+ insertAuditLog: createInsertLogEndpoint(resolved, modelName)
520
+ },
521
+ rateLimit: [
522
+ {
523
+ pathMatcher: (path) => path.startsWith("/audit-log/"),
524
+ window: 60,
525
+ max: 60
526
+ }
527
+ ]
528
+ };
529
+ }
530
+ // src/adapters/memory.ts
531
+ class MemoryStorage {
532
+ entries = [];
533
+ async write(entry) {
534
+ this.entries.push(entry);
535
+ }
536
+ async read(opts) {
537
+ let filtered = this.entries.filter((e) => {
538
+ if (opts.userId !== undefined && e.userId !== opts.userId)
539
+ return false;
540
+ if (opts.action !== undefined && e.action !== opts.action)
541
+ return false;
542
+ if (opts.status !== undefined && e.status !== opts.status)
543
+ return false;
544
+ if (opts.from !== undefined && e.createdAt < opts.from)
545
+ return false;
546
+ if (opts.to !== undefined && e.createdAt > opts.to)
547
+ return false;
548
+ return true;
549
+ });
550
+ const total = filtered.length;
551
+ filtered = filtered.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()).slice(opts.offset, opts.offset + opts.limit);
552
+ return { entries: filtered, total };
553
+ }
554
+ async readById(id) {
555
+ return this.entries.find((e) => e.id === id) ?? null;
556
+ }
557
+ async deleteOlderThan(date) {
558
+ const before = this.entries.length;
559
+ const retained = this.entries.filter((e) => e.createdAt >= date);
560
+ this.entries.length = 0;
561
+ this.entries.push(...retained);
562
+ return before - this.entries.length;
563
+ }
564
+ }
@@ -0,0 +1,4 @@
1
+ export { auditLog } from "./plugin";
2
+ export { MemoryStorage } from "./adapters/memory";
3
+ export type { AuditLogEntry, AuditLogOptions, AuditLogStorage, AuditLogStatus, AuditLogSeverity, StorageReadOptions, StorageReadResult, PIIRedactionOptions, CaptureOptions, PathConfig, RetentionConfig, } from "./types";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,YAAY,EACV,aAAa,EACb,eAAe,EACf,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,eAAe,GAChB,MAAM,SAAS,CAAC"}