kaafil-js 0.1.0 → 0.3.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/dist/client-entry.cjs +134 -7
- package/dist/client-entry.cjs.map +1 -1
- package/dist/client-entry.d.cts +164 -33
- package/dist/client-entry.d.ts +164 -33
- package/dist/client-entry.js +134 -8
- package/dist/client-entry.js.map +1 -1
- package/package.json +1 -1
package/dist/client-entry.cjs
CHANGED
|
@@ -2585,6 +2585,11 @@ function createDrainer(options) {
|
|
|
2585
2585
|
row: outcome.entity,
|
|
2586
2586
|
...outcome.serverTime !== void 0 ? { syncedAt: outcome.serverTime } : {}
|
|
2587
2587
|
});
|
|
2588
|
+
const temporaryId = entity.temporaryId;
|
|
2589
|
+
if (temporaryId !== void 0 && temporaryId !== outcome.entity.id) {
|
|
2590
|
+
await snapshot.purgeEntity(op.tripRef, entity.listName, temporaryId);
|
|
2591
|
+
changed = true;
|
|
2592
|
+
}
|
|
2588
2593
|
}
|
|
2589
2594
|
if (changed && outcome.serverTime !== void 0) {
|
|
2590
2595
|
events.emit("snapshot.updated", {
|
|
@@ -2684,6 +2689,16 @@ function createDrainer(options) {
|
|
|
2684
2689
|
switch (result.action) {
|
|
2685
2690
|
case "drop":
|
|
2686
2691
|
await outbox.drop(op.id);
|
|
2692
|
+
if (op.entity?.temporaryId !== void 0) {
|
|
2693
|
+
await snapshot.purgeEntity(op.tripRef, op.entity.listName, op.entity.temporaryId);
|
|
2694
|
+
if (outcome.serverTime !== void 0) {
|
|
2695
|
+
events.emit("snapshot.updated", {
|
|
2696
|
+
tripRef: op.tripRef,
|
|
2697
|
+
lists: [op.entity.listName],
|
|
2698
|
+
serverTime: outcome.serverTime
|
|
2699
|
+
});
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2687
2702
|
return "terminal";
|
|
2688
2703
|
case "reissue":
|
|
2689
2704
|
await outbox.reissue(op.id, {
|
|
@@ -2964,7 +2979,35 @@ var SYNC_PULL_SECTIONS = [
|
|
|
2964
2979
|
"itinerary",
|
|
2965
2980
|
"closeout"
|
|
2966
2981
|
];
|
|
2967
|
-
|
|
2982
|
+
var SECTION_ROW_KEY = {
|
|
2983
|
+
// Delta-shaped `rooms[]`; `windows[]`/`unassigned[]` are derived
|
|
2984
|
+
// projections — the long note above is still exactly right about this one.
|
|
2985
|
+
rooming: "rooms",
|
|
2986
|
+
// The same decision in the same shape: `vehicles[]` is the feed,
|
|
2987
|
+
// `unassignedPool[]` the projection that must never be cached as rows.
|
|
2988
|
+
seating: "vehicles",
|
|
2989
|
+
expenses: "items",
|
|
2990
|
+
float: "data",
|
|
2991
|
+
// The one that was silently dead. `sections[]` is a grouping projection and
|
|
2992
|
+
// `availableTemplates[]` is agency-level catalogue; `items[]` is the trip's
|
|
2993
|
+
// own entity list and the only one of the three carrying tombstones.
|
|
2994
|
+
checklist: "items",
|
|
2995
|
+
// `days[]` is the day-by-day projection the engine recomputes per read;
|
|
2996
|
+
// `items[]` is the entity list.
|
|
2997
|
+
itinerary: "items",
|
|
2998
|
+
closeout: null
|
|
2999
|
+
// `stayWindows`, `pickups`, `bookings` and `collections` send a top-level
|
|
3000
|
+
// array and never reach this table.
|
|
3001
|
+
};
|
|
3002
|
+
function extractSectionRows(data, section) {
|
|
3003
|
+
if (section !== void 0 && section in SECTION_ROW_KEY) {
|
|
3004
|
+
const key = SECTION_ROW_KEY[section];
|
|
3005
|
+
if (key === null || key === void 0 || typeof data !== "object" || data === null) {
|
|
3006
|
+
return void 0;
|
|
3007
|
+
}
|
|
3008
|
+
const value = data[key];
|
|
3009
|
+
return Array.isArray(value) && isRowArray(value) ? value : void 0;
|
|
3010
|
+
}
|
|
2968
3011
|
if (Array.isArray(data)) {
|
|
2969
3012
|
return isRowArray(data) ? data : void 0;
|
|
2970
3013
|
}
|
|
@@ -3034,7 +3077,7 @@ function createPullCoordinator(options) {
|
|
|
3034
3077
|
absent.push(name);
|
|
3035
3078
|
continue;
|
|
3036
3079
|
}
|
|
3037
|
-
const rows = extractSectionRows(section.data);
|
|
3080
|
+
const rows = extractSectionRows(section.data, name);
|
|
3038
3081
|
if (rows === void 0) {
|
|
3039
3082
|
unmapped.push(name);
|
|
3040
3083
|
continue;
|
|
@@ -3071,6 +3114,49 @@ function createPullCoordinator(options) {
|
|
|
3071
3114
|
};
|
|
3072
3115
|
}
|
|
3073
3116
|
|
|
3117
|
+
// src/offline/reads.ts
|
|
3118
|
+
function createReadCacheStore(options) {
|
|
3119
|
+
const key = `${options.keyPrefix}:reads`;
|
|
3120
|
+
let reads = /* @__PURE__ */ new Map();
|
|
3121
|
+
async function persist() {
|
|
3122
|
+
const shape = { reads: Object.fromEntries(reads) };
|
|
3123
|
+
await options.storage.set(key, JSON.stringify(shape));
|
|
3124
|
+
}
|
|
3125
|
+
return {
|
|
3126
|
+
get(readKey) {
|
|
3127
|
+
return reads.get(readKey);
|
|
3128
|
+
},
|
|
3129
|
+
async set(readKey, value, serverTime) {
|
|
3130
|
+
reads.set(readKey, { value, syncedAt: serverTime });
|
|
3131
|
+
await persist();
|
|
3132
|
+
},
|
|
3133
|
+
async purge(readKey) {
|
|
3134
|
+
if (!reads.delete(readKey)) {
|
|
3135
|
+
return;
|
|
3136
|
+
}
|
|
3137
|
+
await persist();
|
|
3138
|
+
},
|
|
3139
|
+
async load() {
|
|
3140
|
+
reads = /* @__PURE__ */ new Map();
|
|
3141
|
+
const raw = await options.storage.get(key);
|
|
3142
|
+
if (raw === void 0) {
|
|
3143
|
+
return;
|
|
3144
|
+
}
|
|
3145
|
+
let parsed;
|
|
3146
|
+
try {
|
|
3147
|
+
parsed = JSON.parse(raw);
|
|
3148
|
+
} catch {
|
|
3149
|
+
return;
|
|
3150
|
+
}
|
|
3151
|
+
for (const [readKey, entry] of Object.entries(parsed.reads ?? {})) {
|
|
3152
|
+
if (entry !== null && typeof entry === "object" && typeof entry.syncedAt === "string") {
|
|
3153
|
+
reads.set(readKey, entry);
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
};
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3074
3160
|
// src/offline/share.ts
|
|
3075
3161
|
var SHARE_WRITE_GRACE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3076
3162
|
var KaafilShareLinkExpiredError = class _KaafilShareLinkExpiredError extends Error {
|
|
@@ -3445,6 +3531,8 @@ function createOfflineEngine(options) {
|
|
|
3445
3531
|
...options.onEventHandlerError !== void 0 ? { onHandlerError: (error) => options.onEventHandlerError?.(error) } : {}
|
|
3446
3532
|
});
|
|
3447
3533
|
const snapshot = createSnapshotStore({ storage: options.storage, keyPrefix });
|
|
3534
|
+
const reads = createReadCacheStore({ storage: options.storage, keyPrefix });
|
|
3535
|
+
const mintEntityId = () => `tmp_${options.newId?.() ?? newIdempotencyKey()}`;
|
|
3448
3536
|
const outbox = createOutbox({
|
|
3449
3537
|
storage: options.storage,
|
|
3450
3538
|
keyPrefix,
|
|
@@ -3493,6 +3581,13 @@ function createOfflineEngine(options) {
|
|
|
3493
3581
|
let unbind;
|
|
3494
3582
|
async function enqueue(input) {
|
|
3495
3583
|
share?.assertWritable();
|
|
3584
|
+
let entity = input.entity;
|
|
3585
|
+
let temporaryId;
|
|
3586
|
+
if (input.creates === true && input.entity !== void 0) {
|
|
3587
|
+
const { temporaryId: _ignored, ...ref } = input.entity;
|
|
3588
|
+
temporaryId = mintEntityId();
|
|
3589
|
+
entity = { ...ref, id: temporaryId, temporaryId };
|
|
3590
|
+
}
|
|
3496
3591
|
const op = await outbox.enqueue({
|
|
3497
3592
|
tripRef: input.tripRef,
|
|
3498
3593
|
method: input.method,
|
|
@@ -3500,16 +3595,25 @@ function createOfflineEngine(options) {
|
|
|
3500
3595
|
operationId: input.operationId,
|
|
3501
3596
|
...input.body !== void 0 ? { body: input.body } : {},
|
|
3502
3597
|
...input.ifMatch !== void 0 ? { ifMatch: input.ifMatch } : {},
|
|
3503
|
-
...
|
|
3598
|
+
...entity !== void 0 ? { entity } : {},
|
|
3504
3599
|
...input.idempotencyKey !== void 0 ? { idempotencyKey: input.idempotencyKey } : {},
|
|
3505
3600
|
...input.enqueuedAt !== void 0 ? { enqueuedAt: input.enqueuedAt } : {}
|
|
3506
3601
|
});
|
|
3507
|
-
if (input.optimistic !== void 0 &&
|
|
3602
|
+
if (input.optimistic !== void 0 && entity !== void 0) {
|
|
3508
3603
|
await snapshot.upsert({
|
|
3509
3604
|
tripRef: input.tripRef,
|
|
3510
|
-
listName:
|
|
3511
|
-
row
|
|
3605
|
+
listName: entity.listName,
|
|
3606
|
+
// A create's row is keyed on the minted id rather than on whatever
|
|
3607
|
+
// `id` the caller happened to put in the optimistic row — those two
|
|
3608
|
+
// disagreeing is what would leave an orphan the drainer cannot find.
|
|
3609
|
+
row: temporaryId === void 0 ? input.optimistic : { ...input.optimistic, id: temporaryId }
|
|
3512
3610
|
});
|
|
3611
|
+
if (temporaryId !== void 0) {
|
|
3612
|
+
events.emit("snapshot.updated", {
|
|
3613
|
+
tripRef: input.tripRef,
|
|
3614
|
+
lists: [entity.listName]
|
|
3615
|
+
});
|
|
3616
|
+
}
|
|
3513
3617
|
}
|
|
3514
3618
|
drainer.kick();
|
|
3515
3619
|
return op;
|
|
@@ -3517,17 +3621,39 @@ function createOfflineEngine(options) {
|
|
|
3517
3621
|
return {
|
|
3518
3622
|
events,
|
|
3519
3623
|
snapshot,
|
|
3624
|
+
reads,
|
|
3520
3625
|
outbox,
|
|
3521
3626
|
drainer,
|
|
3522
3627
|
pull,
|
|
3523
3628
|
blobs,
|
|
3524
3629
|
share,
|
|
3525
3630
|
async open() {
|
|
3526
|
-
await Promise.all([
|
|
3631
|
+
await Promise.all([
|
|
3632
|
+
snapshot.load(),
|
|
3633
|
+
reads.load(),
|
|
3634
|
+
outbox.load(),
|
|
3635
|
+
blobs?.load() ?? Promise.resolve()
|
|
3636
|
+
]);
|
|
3527
3637
|
unbind = drainer.bindOpportunisticTriggers();
|
|
3528
3638
|
drainer.kick();
|
|
3529
3639
|
},
|
|
3530
3640
|
enqueue,
|
|
3641
|
+
async discard(opId) {
|
|
3642
|
+
const op = outbox.get(opId);
|
|
3643
|
+
if (op === void 0) {
|
|
3644
|
+
return;
|
|
3645
|
+
}
|
|
3646
|
+
await outbox.drop(opId);
|
|
3647
|
+
const temporaryId = op.entity?.temporaryId;
|
|
3648
|
+
if (op.entity === void 0 || temporaryId === void 0) {
|
|
3649
|
+
return;
|
|
3650
|
+
}
|
|
3651
|
+
await snapshot.purgeEntity(op.tripRef, op.entity.listName, temporaryId);
|
|
3652
|
+
events.emit("snapshot.updated", {
|
|
3653
|
+
tripRef: op.tripRef,
|
|
3654
|
+
lists: [op.entity.listName]
|
|
3655
|
+
});
|
|
3656
|
+
},
|
|
3531
3657
|
async enqueueWithBlob(input) {
|
|
3532
3658
|
const { blob, ...rest } = input;
|
|
3533
3659
|
share?.assertWritable();
|
|
@@ -7511,6 +7637,7 @@ exports.createOfflineEngine = createOfflineEngine;
|
|
|
7511
7637
|
exports.createOfflineEvents = createOfflineEvents;
|
|
7512
7638
|
exports.createOutbox = createOutbox;
|
|
7513
7639
|
exports.createPullCoordinator = createPullCoordinator;
|
|
7640
|
+
exports.createReadCacheStore = createReadCacheStore;
|
|
7514
7641
|
exports.createShareGuard = createShareGuard;
|
|
7515
7642
|
exports.createSnapshotStore = createSnapshotStore;
|
|
7516
7643
|
exports.createSyncResource = createSyncResource;
|