@absolutejs/sync 1.8.1 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine/cdc.d.ts +2 -2
- package/dist/engine/devtools.d.ts +27 -0
- package/dist/engine/index.d.ts +2 -0
- package/dist/engine/index.js +234 -64
- package/dist/engine/index.js.map +8 -7
- package/dist/engine/pack.d.ts +138 -0
- package/dist/engine/schedule.d.ts +14 -0
- package/dist/engine/syncEngine.d.ts +13 -0
- package/dist/index.js +234 -68
- package/dist/index.js.map +7 -6
- package/package.json +1 -1
package/dist/engine/cdc.d.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* `error` SSE event so the client knows to resubscribe (vs silently
|
|
21
21
|
* dropping commits).
|
|
22
22
|
*/
|
|
23
|
-
import { Elysia } from 'elysia';
|
|
23
|
+
import type { Elysia as ElysiaType } from 'elysia';
|
|
24
24
|
import { type SyncEngine } from './syncEngine';
|
|
25
25
|
export type SyncCdcOptions = {
|
|
26
26
|
/** The engine whose change log this route streams. */
|
|
@@ -32,7 +32,7 @@ export type SyncCdcOptions = {
|
|
|
32
32
|
/** Per-stream in-flight buffer cap. Passed to {@link SyncEngine.streamChanges}. Default 10000. */
|
|
33
33
|
maxBuffer?: number;
|
|
34
34
|
};
|
|
35
|
-
export declare const syncCdc: ({ engine, path, heartbeatMs, maxBuffer }: SyncCdcOptions) =>
|
|
35
|
+
export declare const syncCdc: ({ engine, path, heartbeatMs, maxBuffer }: SyncCdcOptions) => ElysiaType<"", {
|
|
36
36
|
decorator: {};
|
|
37
37
|
store: {};
|
|
38
38
|
derive: {};
|
|
@@ -35,6 +35,18 @@ export type EngineInspection = {
|
|
|
35
35
|
table: string;
|
|
36
36
|
op: RowOp;
|
|
37
37
|
}[];
|
|
38
|
+
/**
|
|
39
|
+
* Registered sync packs (see {@link SyncEngine.registerPack}). Each
|
|
40
|
+
* entry reports the pack's name, version, the tables it owns, and the
|
|
41
|
+
* tables it reads but does not own. Surfaced for devtools and for
|
|
42
|
+
* conflict diagnostics.
|
|
43
|
+
*/
|
|
44
|
+
packs: {
|
|
45
|
+
name: string;
|
|
46
|
+
version: string;
|
|
47
|
+
ownsTables: string[];
|
|
48
|
+
readsTables: string[];
|
|
49
|
+
}[];
|
|
38
50
|
};
|
|
39
51
|
/**
|
|
40
52
|
* A live engine event (see {@link SyncEngine.onActivity}): a committed change or
|
|
@@ -63,4 +75,19 @@ export type EngineActivity = {
|
|
|
63
75
|
delayMs: number;
|
|
64
76
|
errorName: string;
|
|
65
77
|
errorMessage: string;
|
|
78
|
+
} | {
|
|
79
|
+
type: 'schedule';
|
|
80
|
+
at: number;
|
|
81
|
+
name: string;
|
|
82
|
+
status: 'ok' | 'error';
|
|
83
|
+
} | {
|
|
84
|
+
/** Emitted between attempts of a retried schedule. Mirrors
|
|
85
|
+
* {@link mutationRetry}. */
|
|
86
|
+
type: 'scheduleRetry';
|
|
87
|
+
at: number;
|
|
88
|
+
name: string;
|
|
89
|
+
attempt: number;
|
|
90
|
+
delayMs: number;
|
|
91
|
+
errorName: string;
|
|
92
|
+
errorMessage: string;
|
|
66
93
|
};
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export { createVectorIndex } from './vectorIndex';
|
|
|
40
40
|
export type { VectorIndexOptions, VectorMetric } from './vectorIndex';
|
|
41
41
|
export { defineSchedule } from './schedule';
|
|
42
42
|
export type { ScheduleContext, ScheduleDefinition } from './schedule';
|
|
43
|
+
export { defineSyncPack, PackMissingDependencyError, PackTableConflictError } from './pack';
|
|
44
|
+
export type { CrdtFieldsMap, RegisteredPack, SyncPack } from './pack';
|
|
43
45
|
export { defineMutation } from './mutation';
|
|
44
46
|
export type { MutationActions, MutationDefinition, MutationHandler, TableWriter, TransactionRunner } from './mutation';
|
|
45
47
|
export type { BridgeFetchConfig, BridgeFetchEndpoint, BridgeFetchResponse, HandlerMetricsHook, HandlerMetricsRecord, SandboxConfig } from './sandbox';
|
package/dist/engine/index.js
CHANGED
|
@@ -1056,6 +1056,31 @@ var createVectorIndex = (options) => {
|
|
|
1056
1056
|
};
|
|
1057
1057
|
// src/engine/schedule.ts
|
|
1058
1058
|
var defineSchedule = (definition) => definition;
|
|
1059
|
+
// src/engine/pack.ts
|
|
1060
|
+
class PackTableConflictError extends Error {
|
|
1061
|
+
table;
|
|
1062
|
+
existingPack;
|
|
1063
|
+
newPack;
|
|
1064
|
+
constructor(table, existingPack, newPack) {
|
|
1065
|
+
super(`Pack "${newPack}" claims table "${table}", but "${existingPack}" already owns it. Use a tablePrefix on one of them.`);
|
|
1066
|
+
this.name = "PackTableConflictError";
|
|
1067
|
+
this.table = table;
|
|
1068
|
+
this.existingPack = existingPack;
|
|
1069
|
+
this.newPack = newPack;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
class PackMissingDependencyError extends Error {
|
|
1074
|
+
pack;
|
|
1075
|
+
missingTable;
|
|
1076
|
+
constructor(pack, missingTable) {
|
|
1077
|
+
super(`Pack "${pack}" requires a reader for table "${missingTable}" but none is registered. Call engine.registerReader("${missingTable}", ...) before engine.registerPack.`);
|
|
1078
|
+
this.name = "PackMissingDependencyError";
|
|
1079
|
+
this.pack = pack;
|
|
1080
|
+
this.missingTable = missingTable;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
var defineSyncPack = (pack) => pack;
|
|
1059
1084
|
// src/engine/mutation.ts
|
|
1060
1085
|
var defineMutation = (definition) => definition;
|
|
1061
1086
|
// src/engine/retry.ts
|
|
@@ -1405,6 +1430,8 @@ var createSyncEngine = (options = {}) => {
|
|
|
1405
1430
|
const writers = new Map;
|
|
1406
1431
|
const readers = new Map;
|
|
1407
1432
|
const schedules = new Map;
|
|
1433
|
+
const packTableOwners = new Map;
|
|
1434
|
+
const registeredPacks = [];
|
|
1408
1435
|
const permissions = new Map;
|
|
1409
1436
|
for (const [table, rules] of Object.entries(options.permissions ?? {})) {
|
|
1410
1437
|
permissions.set(table, rules);
|
|
@@ -2136,7 +2163,7 @@ var createSyncEngine = (options = {}) => {
|
|
|
2136
2163
|
}
|
|
2137
2164
|
};
|
|
2138
2165
|
};
|
|
2139
|
-
|
|
2166
|
+
const engine = {
|
|
2140
2167
|
register: (collection) => {
|
|
2141
2168
|
registry.set(collection.name, collection);
|
|
2142
2169
|
for (const table of collection.tables ?? [collection.name]) {
|
|
@@ -2411,13 +2438,136 @@ var createSyncEngine = (options = {}) => {
|
|
|
2411
2438
|
throw new Error(`Unknown schedule "${name}"`);
|
|
2412
2439
|
}
|
|
2413
2440
|
const runHandler = async (tx) => {
|
|
2414
|
-
const { actions, buffered
|
|
2441
|
+
const { actions, buffered } = makeActions(tx, {}, false);
|
|
2415
2442
|
const db = makeReadHandle({}, new Set, new Set, [], false);
|
|
2416
2443
|
await schedule.run({ actions, db });
|
|
2417
|
-
return
|
|
2444
|
+
return buffered;
|
|
2418
2445
|
};
|
|
2419
|
-
const
|
|
2420
|
-
|
|
2446
|
+
const retry = schedule.retry;
|
|
2447
|
+
const maxAttempts = retry === undefined ? 1 : retry.maxAttempts ?? 5;
|
|
2448
|
+
const isRetryable = retry?.isRetryable ?? isSerializationFailure;
|
|
2449
|
+
const computeDelay = retry?.backoff ?? exponentialBackoff();
|
|
2450
|
+
const maxElapsedMs = retry?.maxElapsedMs ?? 30000;
|
|
2451
|
+
const startedAt = Date.now();
|
|
2452
|
+
let lastError;
|
|
2453
|
+
let attemptsMade = 0;
|
|
2454
|
+
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
2455
|
+
attemptsMade = attempt;
|
|
2456
|
+
try {
|
|
2457
|
+
const buffered = runInTransaction !== undefined ? await runInTransaction((tx) => runHandler(tx)) : await runHandler(undefined);
|
|
2458
|
+
await applyChangeBatch(buffered);
|
|
2459
|
+
emitActivity({
|
|
2460
|
+
type: "schedule",
|
|
2461
|
+
at: Date.now(),
|
|
2462
|
+
name,
|
|
2463
|
+
status: "ok"
|
|
2464
|
+
});
|
|
2465
|
+
return;
|
|
2466
|
+
} catch (error) {
|
|
2467
|
+
lastError = error;
|
|
2468
|
+
const elapsedMs = Date.now() - startedAt;
|
|
2469
|
+
const canRetry = attempt < maxAttempts && isRetryable(error) && elapsedMs < maxElapsedMs;
|
|
2470
|
+
if (!canRetry)
|
|
2471
|
+
break;
|
|
2472
|
+
const rawDelay = computeDelay(attempt);
|
|
2473
|
+
const remaining = maxElapsedMs - elapsedMs;
|
|
2474
|
+
if (remaining <= 0)
|
|
2475
|
+
break;
|
|
2476
|
+
const delayMs = Math.max(0, Math.min(rawDelay, remaining));
|
|
2477
|
+
emitActivity({
|
|
2478
|
+
type: "scheduleRetry",
|
|
2479
|
+
at: Date.now(),
|
|
2480
|
+
name,
|
|
2481
|
+
attempt,
|
|
2482
|
+
delayMs,
|
|
2483
|
+
errorName: error instanceof Error ? error.name : "Error",
|
|
2484
|
+
errorMessage: error instanceof Error ? error.message : String(error)
|
|
2485
|
+
});
|
|
2486
|
+
if (delayMs > 0) {
|
|
2487
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
emitActivity({
|
|
2492
|
+
type: "schedule",
|
|
2493
|
+
at: Date.now(),
|
|
2494
|
+
name,
|
|
2495
|
+
status: "error"
|
|
2496
|
+
});
|
|
2497
|
+
if (attemptsMade > 1) {
|
|
2498
|
+
throw new RetriesExhaustedError(attemptsMade, Date.now() - startedAt, lastError);
|
|
2499
|
+
}
|
|
2500
|
+
throw lastError;
|
|
2501
|
+
},
|
|
2502
|
+
registerPack: (pack) => {
|
|
2503
|
+
for (const table of pack.ownsTables) {
|
|
2504
|
+
const existing = packTableOwners.get(table);
|
|
2505
|
+
if (existing !== undefined) {
|
|
2506
|
+
throw new PackTableConflictError(table, existing, pack.name);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
if (pack.requireDependencies === true) {
|
|
2510
|
+
for (const table of pack.readsTables ?? []) {
|
|
2511
|
+
if (!readers.has(table)) {
|
|
2512
|
+
throw new PackMissingDependencyError(pack.name, table);
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
if (pack.schemas !== undefined) {
|
|
2517
|
+
for (const [table, schema] of Object.entries(pack.schemas)) {
|
|
2518
|
+
engine.registerSchema(table, schema);
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
if (pack.permissions !== undefined) {
|
|
2522
|
+
for (const [table, rules] of Object.entries(pack.permissions)) {
|
|
2523
|
+
engine.registerPermissions(table, rules);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
if (pack.readers !== undefined) {
|
|
2527
|
+
for (const [table, reader] of Object.entries(pack.readers)) {
|
|
2528
|
+
engine.registerReader(table, reader);
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
if (pack.writers !== undefined) {
|
|
2532
|
+
for (const [table, writer] of Object.entries(pack.writers)) {
|
|
2533
|
+
engine.registerWriter(table, writer);
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
if (pack.crdt !== undefined) {
|
|
2537
|
+
for (const [table, fields] of Object.entries(pack.crdt)) {
|
|
2538
|
+
engine.registerCrdt(table, fields);
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
for (const collection of pack.collections ?? []) {
|
|
2542
|
+
engine.register(collection);
|
|
2543
|
+
}
|
|
2544
|
+
for (const collection of pack.joinCollections ?? []) {
|
|
2545
|
+
engine.registerJoin(collection);
|
|
2546
|
+
}
|
|
2547
|
+
for (const collection of pack.graphCollections ?? []) {
|
|
2548
|
+
engine.registerGraph(collection);
|
|
2549
|
+
}
|
|
2550
|
+
for (const collection of pack.searchCollections ?? []) {
|
|
2551
|
+
engine.registerSearch(collection);
|
|
2552
|
+
}
|
|
2553
|
+
for (const query2 of pack.reactiveQueries ?? []) {
|
|
2554
|
+
engine.registerReactive(query2);
|
|
2555
|
+
}
|
|
2556
|
+
for (const mutation of pack.mutations ?? []) {
|
|
2557
|
+
engine.registerMutation(mutation);
|
|
2558
|
+
}
|
|
2559
|
+
for (const schedule of pack.schedules ?? []) {
|
|
2560
|
+
engine.registerSchedule(schedule);
|
|
2561
|
+
}
|
|
2562
|
+
for (const table of pack.ownsTables) {
|
|
2563
|
+
packTableOwners.set(table, pack.name);
|
|
2564
|
+
}
|
|
2565
|
+
registeredPacks.push({
|
|
2566
|
+
name: pack.name,
|
|
2567
|
+
version: pack.version,
|
|
2568
|
+
ownsTables: [...pack.ownsTables],
|
|
2569
|
+
readsTables: [...pack.readsTables ?? []]
|
|
2570
|
+
});
|
|
2421
2571
|
},
|
|
2422
2572
|
inspect: () => {
|
|
2423
2573
|
const collections = [...registry.entries()].map(([name, def]) => {
|
|
@@ -2457,6 +2607,12 @@ var createSyncEngine = (options = {}) => {
|
|
|
2457
2607
|
version: entry.version,
|
|
2458
2608
|
table: entry.table,
|
|
2459
2609
|
op: entry.change.op
|
|
2610
|
+
})),
|
|
2611
|
+
packs: registeredPacks.map((pack) => ({
|
|
2612
|
+
name: pack.name,
|
|
2613
|
+
version: pack.version,
|
|
2614
|
+
ownsTables: [...pack.ownsTables],
|
|
2615
|
+
readsTables: [...pack.readsTables]
|
|
2460
2616
|
}))
|
|
2461
2617
|
};
|
|
2462
2618
|
},
|
|
@@ -2543,9 +2699,17 @@ var createSyncEngine = (options = {}) => {
|
|
|
2543
2699
|
};
|
|
2544
2700
|
}
|
|
2545
2701
|
};
|
|
2702
|
+
return engine;
|
|
2546
2703
|
};
|
|
2547
2704
|
// src/engine/cdc.ts
|
|
2548
|
-
|
|
2705
|
+
var cachedElysia;
|
|
2706
|
+
var loadElysia = () => {
|
|
2707
|
+
if (cachedElysia !== undefined)
|
|
2708
|
+
return cachedElysia;
|
|
2709
|
+
const mod = __require("elysia");
|
|
2710
|
+
cachedElysia = mod.Elysia;
|
|
2711
|
+
return cachedElysia;
|
|
2712
|
+
};
|
|
2549
2713
|
var parseSince = (query2, lastEventId) => {
|
|
2550
2714
|
const raw = query2.since ?? lastEventId ?? "0";
|
|
2551
2715
|
const parsed = Number(raw);
|
|
@@ -2567,68 +2731,71 @@ var syncCdc = ({
|
|
|
2567
2731
|
path = "/sync/cdc",
|
|
2568
2732
|
heartbeatMs = 25000,
|
|
2569
2733
|
maxBuffer = 1e4
|
|
2570
|
-
}) =>
|
|
2571
|
-
const
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2734
|
+
}) => {
|
|
2735
|
+
const Elysia = loadElysia();
|
|
2736
|
+
return new Elysia({ name: "@absolutejs/sync/cdc" }).get(path, (context) => {
|
|
2737
|
+
const lastEventId = context.request.headers.get("last-event-id");
|
|
2738
|
+
const since = parseSince(context.query, lastEventId);
|
|
2739
|
+
const encoder = new TextEncoder;
|
|
2740
|
+
const stream = new ReadableStream({
|
|
2741
|
+
async start(controller) {
|
|
2742
|
+
const write = (chunk) => {
|
|
2743
|
+
try {
|
|
2744
|
+
controller.enqueue(encoder.encode(chunk));
|
|
2745
|
+
} catch {}
|
|
2746
|
+
};
|
|
2747
|
+
write(encodeEvent("open", null, {
|
|
2748
|
+
since,
|
|
2749
|
+
at: Date.now()
|
|
2750
|
+
}));
|
|
2751
|
+
const heartbeat = setInterval(() => write(`: ping
|
|
2586
2752
|
|
|
2587
2753
|
`), heartbeatMs);
|
|
2588
|
-
try {
|
|
2589
|
-
for await (const entry of engine.streamChanges({
|
|
2590
|
-
since,
|
|
2591
|
-
signal: context.request.signal,
|
|
2592
|
-
maxBuffer
|
|
2593
|
-
})) {
|
|
2594
|
-
write(encodeEvent("change", entry.version, entry));
|
|
2595
|
-
}
|
|
2596
|
-
} catch (error) {
|
|
2597
|
-
if (error instanceof MissedChangesError) {
|
|
2598
|
-
write(encodeEvent("error", null, {
|
|
2599
|
-
name: "MissedChangesError",
|
|
2600
|
-
message: error.message,
|
|
2601
|
-
requestedSince: error.requestedSince,
|
|
2602
|
-
availableSince: error.availableSince
|
|
2603
|
-
}));
|
|
2604
|
-
} else if (error instanceof CdcConsumerSlowError) {
|
|
2605
|
-
write(encodeEvent("error", null, {
|
|
2606
|
-
name: "CdcConsumerSlowError",
|
|
2607
|
-
message: error.message,
|
|
2608
|
-
lastDeliveredVersion: error.lastDeliveredVersion
|
|
2609
|
-
}));
|
|
2610
|
-
} else {
|
|
2611
|
-
write(encodeEvent("error", null, {
|
|
2612
|
-
name: error instanceof Error ? error.name : "Error",
|
|
2613
|
-
message: error instanceof Error ? error.message : String(error)
|
|
2614
|
-
}));
|
|
2615
|
-
}
|
|
2616
|
-
} finally {
|
|
2617
|
-
clearInterval(heartbeat);
|
|
2618
2754
|
try {
|
|
2619
|
-
|
|
2620
|
-
|
|
2755
|
+
for await (const entry of engine.streamChanges({
|
|
2756
|
+
since,
|
|
2757
|
+
signal: context.request.signal,
|
|
2758
|
+
maxBuffer
|
|
2759
|
+
})) {
|
|
2760
|
+
write(encodeEvent("change", entry.version, entry));
|
|
2761
|
+
}
|
|
2762
|
+
} catch (error) {
|
|
2763
|
+
if (error instanceof MissedChangesError) {
|
|
2764
|
+
write(encodeEvent("error", null, {
|
|
2765
|
+
name: "MissedChangesError",
|
|
2766
|
+
message: error.message,
|
|
2767
|
+
requestedSince: error.requestedSince,
|
|
2768
|
+
availableSince: error.availableSince
|
|
2769
|
+
}));
|
|
2770
|
+
} else if (error instanceof CdcConsumerSlowError) {
|
|
2771
|
+
write(encodeEvent("error", null, {
|
|
2772
|
+
name: "CdcConsumerSlowError",
|
|
2773
|
+
message: error.message,
|
|
2774
|
+
lastDeliveredVersion: error.lastDeliveredVersion
|
|
2775
|
+
}));
|
|
2776
|
+
} else {
|
|
2777
|
+
write(encodeEvent("error", null, {
|
|
2778
|
+
name: error instanceof Error ? error.name : "Error",
|
|
2779
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2780
|
+
}));
|
|
2781
|
+
}
|
|
2782
|
+
} finally {
|
|
2783
|
+
clearInterval(heartbeat);
|
|
2784
|
+
try {
|
|
2785
|
+
controller.close();
|
|
2786
|
+
} catch {}
|
|
2787
|
+
}
|
|
2621
2788
|
}
|
|
2622
|
-
}
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
}
|
|
2789
|
+
});
|
|
2790
|
+
return new Response(stream, {
|
|
2791
|
+
headers: {
|
|
2792
|
+
"cache-control": "no-cache, no-transform",
|
|
2793
|
+
connection: "keep-alive",
|
|
2794
|
+
"content-type": "text/event-stream"
|
|
2795
|
+
}
|
|
2796
|
+
});
|
|
2630
2797
|
});
|
|
2631
|
-
}
|
|
2798
|
+
};
|
|
2632
2799
|
// src/engine/schema.ts
|
|
2633
2800
|
var defineSchema = (schemas) => schemas;
|
|
2634
2801
|
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
@@ -2892,6 +3059,7 @@ export {
|
|
|
2892
3059
|
filterOp,
|
|
2893
3060
|
field,
|
|
2894
3061
|
exponentialBackoff,
|
|
3062
|
+
defineSyncPack,
|
|
2895
3063
|
defineSearchCollection,
|
|
2896
3064
|
defineSchema,
|
|
2897
3065
|
defineSchedule,
|
|
@@ -2917,9 +3085,11 @@ export {
|
|
|
2917
3085
|
SchemaError,
|
|
2918
3086
|
SEARCH_SCORE_FIELD,
|
|
2919
3087
|
RetriesExhaustedError,
|
|
3088
|
+
PackTableConflictError,
|
|
3089
|
+
PackMissingDependencyError,
|
|
2920
3090
|
MissedChangesError,
|
|
2921
3091
|
CdcConsumerSlowError
|
|
2922
3092
|
};
|
|
2923
3093
|
|
|
2924
|
-
//# debugId=
|
|
3094
|
+
//# debugId=5962FD669C5BC3D964756E2164756E21
|
|
2925
3095
|
//# sourceMappingURL=index.js.map
|