@absolutejs/sync 1.8.1 → 1.9.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.
@@ -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
  };
@@ -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';
@@ -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
- return {
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: buffered2 } = makeActions(tx, {}, false);
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 buffered2;
2444
+ return buffered;
2418
2445
  };
2419
- const buffered = runInTransaction !== undefined ? await runInTransaction((tx) => runHandler(tx)) : await runHandler(undefined);
2420
- await applyChangeBatch(buffered);
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,6 +2699,7 @@ var createSyncEngine = (options = {}) => {
2543
2699
  };
2544
2700
  }
2545
2701
  };
2702
+ return engine;
2546
2703
  };
2547
2704
  // src/engine/cdc.ts
2548
2705
  import { Elysia } from "elysia";
@@ -2892,6 +3049,7 @@ export {
2892
3049
  filterOp,
2893
3050
  field,
2894
3051
  exponentialBackoff,
3052
+ defineSyncPack,
2895
3053
  defineSearchCollection,
2896
3054
  defineSchema,
2897
3055
  defineSchedule,
@@ -2917,9 +3075,11 @@ export {
2917
3075
  SchemaError,
2918
3076
  SEARCH_SCORE_FIELD,
2919
3077
  RetriesExhaustedError,
3078
+ PackTableConflictError,
3079
+ PackMissingDependencyError,
2920
3080
  MissedChangesError,
2921
3081
  CdcConsumerSlowError
2922
3082
  };
2923
3083
 
2924
- //# debugId=2984A33F7845F42C64756E2164756E21
3084
+ //# debugId=3D4E309EDB79002E64756E2164756E21
2925
3085
  //# sourceMappingURL=index.js.map