@absolutejs/sync 1.20.0 → 1.20.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/devtools.d.ts +8 -0
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/index.js +131 -72
- package/dist/engine/index.js.map +3 -3
- package/dist/engine/syncEngine.d.ts +36 -0
- package/dist/index.js +130 -72
- package/dist/index.js.map +3 -3
- package/dist/testing.js +130 -72
- package/dist/testing.js.map +3 -3
- package/package.json +1 -1
package/dist/testing.js
CHANGED
|
@@ -634,6 +634,19 @@ class MutationQueueOverflowError extends Error {
|
|
|
634
634
|
this.queueLimit = queueLimit;
|
|
635
635
|
}
|
|
636
636
|
}
|
|
637
|
+
|
|
638
|
+
class SubscriptionLimitError extends Error {
|
|
639
|
+
tenantKey;
|
|
640
|
+
limit;
|
|
641
|
+
active;
|
|
642
|
+
constructor(tenantKey, limit, active) {
|
|
643
|
+
super(`Tenant "${tenantKey}" is at the subscription cap ` + `(${active}/${limit}). Close an existing subscription before opening another.`);
|
|
644
|
+
this.name = "SubscriptionLimitError";
|
|
645
|
+
this.tenantKey = tenantKey;
|
|
646
|
+
this.limit = limit;
|
|
647
|
+
this.active = active;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
637
650
|
var defaultKey = (row) => row.id;
|
|
638
651
|
var shallowEqual3 = (a, b) => {
|
|
639
652
|
if (a === b) {
|
|
@@ -784,6 +797,31 @@ var createSyncEngine = (options = {}) => {
|
|
|
784
797
|
if (next !== undefined)
|
|
785
798
|
next();
|
|
786
799
|
};
|
|
800
|
+
const subscriptionsByTenant = new Map;
|
|
801
|
+
const acquireSubscriptionSlot = (ctx, args) => {
|
|
802
|
+
const cap = options.subscriptionLimit;
|
|
803
|
+
if (cap === undefined)
|
|
804
|
+
return;
|
|
805
|
+
const tenantKey = cap.key(ctx, args);
|
|
806
|
+
if (tenantKey === undefined)
|
|
807
|
+
return;
|
|
808
|
+
const active2 = subscriptionsByTenant.get(tenantKey) ?? 0;
|
|
809
|
+
if (active2 >= cap.max) {
|
|
810
|
+
throw new SubscriptionLimitError(tenantKey, cap.max, active2);
|
|
811
|
+
}
|
|
812
|
+
subscriptionsByTenant.set(tenantKey, active2 + 1);
|
|
813
|
+
return tenantKey;
|
|
814
|
+
};
|
|
815
|
+
const releaseSubscriptionSlot = (tenantKey) => {
|
|
816
|
+
if (tenantKey === undefined)
|
|
817
|
+
return;
|
|
818
|
+
const active2 = subscriptionsByTenant.get(tenantKey);
|
|
819
|
+
if (active2 === undefined || active2 <= 1) {
|
|
820
|
+
subscriptionsByTenant.delete(tenantKey);
|
|
821
|
+
} else {
|
|
822
|
+
subscriptionsByTenant.set(tenantKey, active2 - 1);
|
|
823
|
+
}
|
|
824
|
+
};
|
|
787
825
|
const reactiveCacheMax = options.reactiveCache?.max ?? 256;
|
|
788
826
|
const reactiveCacheTtlMs = options.reactiveCache?.ttlMs ?? 60000;
|
|
789
827
|
const cachedReruns = new Map;
|
|
@@ -1621,84 +1659,103 @@ var createSyncEngine = (options = {}) => {
|
|
|
1621
1659
|
if (registered === undefined) {
|
|
1622
1660
|
throw new Error(`Unknown collection "${collection}"`);
|
|
1623
1661
|
}
|
|
1624
|
-
const
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
const
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1662
|
+
const tenantSlot = acquireSubscriptionSlot(ctx, { collection });
|
|
1663
|
+
let slotHandedOff = false;
|
|
1664
|
+
try {
|
|
1665
|
+
const typedOnDiff = onDiff;
|
|
1666
|
+
const subscribeSet = subsFor(collection);
|
|
1667
|
+
const wrapReturn = (sub) => {
|
|
1668
|
+
checkAborted(signal);
|
|
1669
|
+
const innerUnsubscribe = sub.unsubscribe;
|
|
1670
|
+
let released = false;
|
|
1671
|
+
const wrappedUnsubscribe = () => {
|
|
1672
|
+
if (released)
|
|
1673
|
+
return;
|
|
1674
|
+
released = true;
|
|
1675
|
+
releaseSubscriptionSlot(tenantSlot);
|
|
1676
|
+
innerUnsubscribe();
|
|
1677
|
+
};
|
|
1678
|
+
const wrapped = { ...sub, unsubscribe: wrappedUnsubscribe };
|
|
1679
|
+
linkAbortToUnsubscribe(signal, wrappedUnsubscribe);
|
|
1680
|
+
slotHandedOff = true;
|
|
1681
|
+
return wrapped;
|
|
1682
|
+
};
|
|
1683
|
+
const registeredKind = registered.kind;
|
|
1684
|
+
if (registeredKind === "join") {
|
|
1685
|
+
const joined = await subscribeJoin(collection, registered, params, ctx, typedOnDiff, subscribeSet);
|
|
1686
|
+
return wrapReturn(joined);
|
|
1687
|
+
}
|
|
1688
|
+
if (registeredKind === "graph") {
|
|
1689
|
+
const graphed = await subscribeGraph(collection, registered, params, ctx, typedOnDiff, subscribeSet);
|
|
1690
|
+
return wrapReturn(graphed);
|
|
1691
|
+
}
|
|
1692
|
+
if (registeredKind === "reactive") {
|
|
1693
|
+
const reactived = await subscribeReactive(collection, registered, params, ctx, typedOnDiff, subscribeSet);
|
|
1694
|
+
return wrapReturn(reactived);
|
|
1695
|
+
}
|
|
1696
|
+
if (registeredKind === "search") {
|
|
1697
|
+
const searched = await subscribeSearch(collection, registered, params, ctx, typedOnDiff, subscribeSet);
|
|
1698
|
+
return wrapReturn(searched);
|
|
1699
|
+
}
|
|
1700
|
+
const definition = registered;
|
|
1701
|
+
if (definition.authorize !== undefined) {
|
|
1702
|
+
const allowed = await definition.authorize(params, ctx);
|
|
1703
|
+
if (!allowed) {
|
|
1704
|
+
throw new UnauthorizedError(`subscribe to collection "${collection}"`);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
const key = definition.key ?? defaultKey;
|
|
1708
|
+
const match = definition.match;
|
|
1709
|
+
const tables = definition.tables ?? [collection];
|
|
1710
|
+
const scopedTable = tables.length === 1 ? tables[0] : undefined;
|
|
1711
|
+
const readRule = scopedTable !== undefined ? readRuleFor(scopedTable) : undefined;
|
|
1712
|
+
const rehydrate = async () => {
|
|
1713
|
+
const raw = [...await definition.hydrate(params, ctx)];
|
|
1714
|
+
const rows = scopedTable !== undefined ? raw.map((row) => migrateRow(scopedTable, row)) : raw;
|
|
1715
|
+
return readRule ? rows.filter((row) => readRule(ctx, row)) : rows;
|
|
1716
|
+
};
|
|
1717
|
+
const incremental = match !== undefined && tables.length === 1;
|
|
1718
|
+
const boundMatch = incremental ? (row) => match(row, params, ctx) && (readRule ? readRule(ctx, row) : true) : () => true;
|
|
1719
|
+
const view = createMaterializedView({
|
|
1720
|
+
key,
|
|
1721
|
+
match: boundMatch
|
|
1722
|
+
});
|
|
1723
|
+
const resuming = since !== undefined && canResume(since, incremental);
|
|
1724
|
+
view.hydrate([...await rehydrate()]);
|
|
1725
|
+
const atVersion = version;
|
|
1726
|
+
const subscription = {
|
|
1727
|
+
kind: "view",
|
|
1728
|
+
collection,
|
|
1729
|
+
view,
|
|
1730
|
+
incremental,
|
|
1731
|
+
rehydrate,
|
|
1732
|
+
key,
|
|
1733
|
+
onDiff: typedOnDiff
|
|
1734
|
+
};
|
|
1735
|
+
subscribeSet.add(subscription);
|
|
1736
|
+
const unsubscribe = () => {
|
|
1737
|
+
subscribeSet.delete(subscription);
|
|
1738
|
+
};
|
|
1739
|
+
if (resuming) {
|
|
1740
|
+
return wrapReturn({
|
|
1741
|
+
initial: [],
|
|
1742
|
+
catchup: buildCatchup(since, tables, key, boundMatch),
|
|
1743
|
+
cursor: currentCursor(),
|
|
1744
|
+
version: atVersion,
|
|
1745
|
+
unsubscribe
|
|
1746
|
+
});
|
|
1653
1747
|
}
|
|
1654
|
-
}
|
|
1655
|
-
const key = definition.key ?? defaultKey;
|
|
1656
|
-
const match = definition.match;
|
|
1657
|
-
const tables = definition.tables ?? [collection];
|
|
1658
|
-
const scopedTable = tables.length === 1 ? tables[0] : undefined;
|
|
1659
|
-
const readRule = scopedTable !== undefined ? readRuleFor(scopedTable) : undefined;
|
|
1660
|
-
const rehydrate = async () => {
|
|
1661
|
-
const raw = [...await definition.hydrate(params, ctx)];
|
|
1662
|
-
const rows = scopedTable !== undefined ? raw.map((row) => migrateRow(scopedTable, row)) : raw;
|
|
1663
|
-
return readRule ? rows.filter((row) => readRule(ctx, row)) : rows;
|
|
1664
|
-
};
|
|
1665
|
-
const incremental = match !== undefined && tables.length === 1;
|
|
1666
|
-
const boundMatch = incremental ? (row) => match(row, params, ctx) && (readRule ? readRule(ctx, row) : true) : () => true;
|
|
1667
|
-
const view = createMaterializedView({
|
|
1668
|
-
key,
|
|
1669
|
-
match: boundMatch
|
|
1670
|
-
});
|
|
1671
|
-
const resuming = since !== undefined && canResume(since, incremental);
|
|
1672
|
-
view.hydrate([...await rehydrate()]);
|
|
1673
|
-
const atVersion = version;
|
|
1674
|
-
const subscription = {
|
|
1675
|
-
kind: "view",
|
|
1676
|
-
collection,
|
|
1677
|
-
view,
|
|
1678
|
-
incremental,
|
|
1679
|
-
rehydrate,
|
|
1680
|
-
key,
|
|
1681
|
-
onDiff: typedOnDiff
|
|
1682
|
-
};
|
|
1683
|
-
subscribeSet.add(subscription);
|
|
1684
|
-
const unsubscribe = () => {
|
|
1685
|
-
subscribeSet.delete(subscription);
|
|
1686
|
-
};
|
|
1687
|
-
if (resuming) {
|
|
1688
1748
|
return wrapReturn({
|
|
1689
|
-
initial:
|
|
1690
|
-
catchup: buildCatchup(since, tables, key, boundMatch),
|
|
1749
|
+
initial: view.rows(),
|
|
1691
1750
|
cursor: currentCursor(),
|
|
1692
1751
|
version: atVersion,
|
|
1693
1752
|
unsubscribe
|
|
1694
1753
|
});
|
|
1754
|
+
} catch (error) {
|
|
1755
|
+
if (!slotHandedOff)
|
|
1756
|
+
releaseSubscriptionSlot(tenantSlot);
|
|
1757
|
+
throw error;
|
|
1695
1758
|
}
|
|
1696
|
-
return wrapReturn({
|
|
1697
|
-
initial: view.rows(),
|
|
1698
|
-
cursor: currentCursor(),
|
|
1699
|
-
version: atVersion,
|
|
1700
|
-
unsubscribe
|
|
1701
|
-
});
|
|
1702
1759
|
},
|
|
1703
1760
|
hydrate: async (collection, params, ctx, options2) => {
|
|
1704
1761
|
const signal = options2?.signal;
|
|
@@ -2163,6 +2220,7 @@ var createSyncEngine = (options = {}) => {
|
|
|
2163
2220
|
},
|
|
2164
2221
|
subscriptions: {
|
|
2165
2222
|
byCollection,
|
|
2223
|
+
byTenant: Object.fromEntries(subscriptionsByTenant),
|
|
2166
2224
|
total: totalSubscriptions
|
|
2167
2225
|
},
|
|
2168
2226
|
uptimeMs: now - engineStartedAt,
|
|
@@ -2272,5 +2330,5 @@ export {
|
|
|
2272
2330
|
createTestEngine
|
|
2273
2331
|
};
|
|
2274
2332
|
|
|
2275
|
-
//# debugId=
|
|
2333
|
+
//# debugId=5456F0E468513B7264756E2164756E21
|
|
2276
2334
|
//# sourceMappingURL=testing.js.map
|