@arcote.tech/arc 0.3.1 → 0.3.2
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/adapters/event-publisher.d.ts +18 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/query-wire.d.ts +34 -0
- package/dist/adapters/wire.d.ts +9 -1
- package/dist/context/context.d.ts +104 -2
- package/dist/context/index.d.ts +1 -1
- package/dist/context-element/index.d.ts +3 -1
- package/dist/context-element/listener/index.d.ts +2 -0
- package/dist/context-element/listener/listener.d.ts +170 -0
- package/dist/context-element/route/index.d.ts +3 -0
- package/dist/context-element/route/route-data.d.ts +42 -0
- package/dist/context-element/route/route.d.ts +163 -0
- package/dist/context-element/view/view-data.d.ts +5 -6
- package/dist/context-element/view/view.d.ts +15 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.js +725 -69
- package/dist/model/live-query/live-query.d.ts +2 -1
- package/dist/model/model-adapters.d.ts +5 -0
- package/dist/streaming/index.d.ts +6 -0
- package/dist/streaming/streaming-event-publisher.d.ts +51 -0
- package/dist/streaming/streaming-live-query.d.ts +23 -0
- package/dist/streaming/streaming-query-cache.d.ts +57 -0
- package/dist/token/index.d.ts +2 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48,14 +48,20 @@ class AuthAdapter {
|
|
|
48
48
|
}
|
|
49
49
|
// src/adapters/wire.ts
|
|
50
50
|
class Wire {
|
|
51
|
-
baseUrl;
|
|
52
51
|
token = null;
|
|
52
|
+
baseUrl;
|
|
53
53
|
constructor(baseUrl) {
|
|
54
54
|
this.baseUrl = baseUrl;
|
|
55
55
|
}
|
|
56
56
|
setAuthToken(token) {
|
|
57
57
|
this.token = token;
|
|
58
58
|
}
|
|
59
|
+
getAuthToken() {
|
|
60
|
+
return this.token;
|
|
61
|
+
}
|
|
62
|
+
getBaseUrl() {
|
|
63
|
+
return this.baseUrl;
|
|
64
|
+
}
|
|
59
65
|
async fetch(endpoint, options = {}) {
|
|
60
66
|
const headers = new Headers(options.headers);
|
|
61
67
|
if (this.token) {
|
|
@@ -241,6 +247,62 @@ class EventWire {
|
|
|
241
247
|
}, 3000);
|
|
242
248
|
}
|
|
243
249
|
}
|
|
250
|
+
// src/adapters/query-wire.ts
|
|
251
|
+
class QueryWire extends Wire {
|
|
252
|
+
constructor(baseUrl) {
|
|
253
|
+
super(baseUrl);
|
|
254
|
+
}
|
|
255
|
+
async query(viewName, options = {}) {
|
|
256
|
+
const response = await this.fetch(`/query/${viewName}`, {
|
|
257
|
+
method: "POST",
|
|
258
|
+
body: JSON.stringify(options)
|
|
259
|
+
});
|
|
260
|
+
if (!response.ok) {
|
|
261
|
+
const errorText = await response.text();
|
|
262
|
+
throw new Error(`Query ${viewName} failed: ${response.status} ${errorText}`);
|
|
263
|
+
}
|
|
264
|
+
return await response.json();
|
|
265
|
+
}
|
|
266
|
+
stream(viewName, options, callback, token) {
|
|
267
|
+
const params = new URLSearchParams;
|
|
268
|
+
if (options?.where) {
|
|
269
|
+
params.set("where", JSON.stringify(options.where));
|
|
270
|
+
}
|
|
271
|
+
if (options?.orderBy) {
|
|
272
|
+
params.set("orderBy", JSON.stringify(options.orderBy));
|
|
273
|
+
}
|
|
274
|
+
if (options?.limit) {
|
|
275
|
+
params.set("limit", String(options.limit));
|
|
276
|
+
}
|
|
277
|
+
const authToken = token ?? this.getAuthToken();
|
|
278
|
+
if (authToken) {
|
|
279
|
+
params.set("token", authToken);
|
|
280
|
+
}
|
|
281
|
+
const queryString = params.toString();
|
|
282
|
+
const url = `${this.getBaseUrl()}/stream/${viewName}${queryString ? `?${queryString}` : ""}`;
|
|
283
|
+
const eventSource = new EventSource(url);
|
|
284
|
+
eventSource.onmessage = (event) => {
|
|
285
|
+
try {
|
|
286
|
+
const message = JSON.parse(event.data);
|
|
287
|
+
if (message.type === "data") {
|
|
288
|
+
callback(message.data);
|
|
289
|
+
}
|
|
290
|
+
} catch (err) {
|
|
291
|
+
console.error("QueryWire: Failed to parse SSE message", err);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
eventSource.onerror = (err) => {
|
|
295
|
+
console.error("QueryWire: SSE error", err);
|
|
296
|
+
};
|
|
297
|
+
const unsubscribe = () => {
|
|
298
|
+
eventSource.close();
|
|
299
|
+
};
|
|
300
|
+
return {
|
|
301
|
+
eventSource,
|
|
302
|
+
unsubscribe
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
244
306
|
// src/adapters/event-publisher.ts
|
|
245
307
|
var EVENT_TABLES = {
|
|
246
308
|
events: "events",
|
|
@@ -252,6 +314,7 @@ class LocalEventPublisher {
|
|
|
252
314
|
dataStorage;
|
|
253
315
|
views = [];
|
|
254
316
|
syncCallback;
|
|
317
|
+
subscribers = new Map;
|
|
255
318
|
constructor(dataStorage) {
|
|
256
319
|
this.dataStorage = dataStorage;
|
|
257
320
|
}
|
|
@@ -261,6 +324,21 @@ class LocalEventPublisher {
|
|
|
261
324
|
registerViews(views) {
|
|
262
325
|
this.views = views;
|
|
263
326
|
}
|
|
327
|
+
subscribe(eventType, callback) {
|
|
328
|
+
if (!this.subscribers.has(eventType)) {
|
|
329
|
+
this.subscribers.set(eventType, new Set);
|
|
330
|
+
}
|
|
331
|
+
this.subscribers.get(eventType).add(callback);
|
|
332
|
+
return () => {
|
|
333
|
+
const subs = this.subscribers.get(eventType);
|
|
334
|
+
if (subs) {
|
|
335
|
+
subs.delete(callback);
|
|
336
|
+
if (subs.size === 0) {
|
|
337
|
+
this.subscribers.delete(eventType);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
264
342
|
async publish(event) {
|
|
265
343
|
const allChanges = [];
|
|
266
344
|
const storedEvent = {
|
|
@@ -309,10 +387,30 @@ class LocalEventPublisher {
|
|
|
309
387
|
const viewChanges = await this.collectViewChanges(event);
|
|
310
388
|
allChanges.push(...viewChanges);
|
|
311
389
|
await this.dataStorage.commitChanges(allChanges);
|
|
390
|
+
await this.notifySubscribers(event);
|
|
312
391
|
if (this.syncCallback) {
|
|
313
392
|
this.syncCallback(event);
|
|
314
393
|
}
|
|
315
394
|
}
|
|
395
|
+
async notifySubscribers(event) {
|
|
396
|
+
const subs = this.subscribers.get(event.type);
|
|
397
|
+
if (!subs || subs.size === 0)
|
|
398
|
+
return;
|
|
399
|
+
const promises = [];
|
|
400
|
+
for (const callback of subs) {
|
|
401
|
+
try {
|
|
402
|
+
const result = callback(event);
|
|
403
|
+
if (result instanceof Promise) {
|
|
404
|
+
promises.push(result);
|
|
405
|
+
}
|
|
406
|
+
} catch (error) {
|
|
407
|
+
console.error(`Listener error for event "${event.type}":`, error);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (promises.length > 0) {
|
|
411
|
+
await Promise.all(promises.map((p) => p.catch((e) => console.error(e))));
|
|
412
|
+
}
|
|
413
|
+
}
|
|
316
414
|
async markSynced(eventIds) {
|
|
317
415
|
const syncStatusStore = this.dataStorage.getStore(EVENT_TABLES.syncStatus);
|
|
318
416
|
const changes = eventIds.map((eventId) => ({
|
|
@@ -423,13 +521,6 @@ function contextMerge(...contexts) {
|
|
|
423
521
|
const allElements = contexts.flatMap((ctx) => ctx.elements);
|
|
424
522
|
return new ArcContext(allElements);
|
|
425
523
|
}
|
|
426
|
-
// src/context-element/context-element.ts
|
|
427
|
-
class ArcContextElement {
|
|
428
|
-
name;
|
|
429
|
-
constructor(name) {
|
|
430
|
-
this.name = name;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
524
|
// src/elements/optional.ts
|
|
434
525
|
class ArcOptional {
|
|
435
526
|
parent;
|
|
@@ -958,6 +1049,14 @@ function object(element) {
|
|
|
958
1049
|
return new ArcObject(element);
|
|
959
1050
|
}
|
|
960
1051
|
|
|
1052
|
+
// src/context-element/context-element.ts
|
|
1053
|
+
class ArcContextElement {
|
|
1054
|
+
name;
|
|
1055
|
+
constructor(name) {
|
|
1056
|
+
this.name = name;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
961
1060
|
// src/context-element/command/command.ts
|
|
962
1061
|
class ArcCommand extends ArcContextElement {
|
|
963
1062
|
data;
|
|
@@ -1502,17 +1601,13 @@ class ArcEvent extends ArcContextElement {
|
|
|
1502
1601
|
});
|
|
1503
1602
|
const tagsSchema = new ArcObject({
|
|
1504
1603
|
_id: new ArcString().primaryKey(),
|
|
1505
|
-
eventId: new ArcString().
|
|
1506
|
-
onDelete: "CASCADE"
|
|
1507
|
-
}),
|
|
1604
|
+
eventId: new ArcString().index(),
|
|
1508
1605
|
tagKey: new ArcString().index(),
|
|
1509
1606
|
tagValue: new ArcString().index()
|
|
1510
1607
|
});
|
|
1511
1608
|
const syncStatusSchema = new ArcObject({
|
|
1512
1609
|
_id: new ArcString().primaryKey(),
|
|
1513
|
-
eventId: new ArcString().
|
|
1514
|
-
onDelete: "CASCADE"
|
|
1515
|
-
}),
|
|
1610
|
+
eventId: new ArcString().index(),
|
|
1516
1611
|
synced: new ArcBoolean().index(),
|
|
1517
1612
|
timestamp: new ArcNumber,
|
|
1518
1613
|
retryCount: new ArcNumber
|
|
@@ -1537,6 +1632,305 @@ function event(name, payload) {
|
|
|
1537
1632
|
protections: []
|
|
1538
1633
|
});
|
|
1539
1634
|
}
|
|
1635
|
+
// src/context-element/listener/listener.ts
|
|
1636
|
+
class ArcListener extends ArcContextElement {
|
|
1637
|
+
data;
|
|
1638
|
+
unsubscribers = [];
|
|
1639
|
+
constructor(data) {
|
|
1640
|
+
super(data.name);
|
|
1641
|
+
this.data = data;
|
|
1642
|
+
}
|
|
1643
|
+
description(description) {
|
|
1644
|
+
return new ArcListener({
|
|
1645
|
+
...this.data,
|
|
1646
|
+
description
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
listenTo(events) {
|
|
1650
|
+
return new ArcListener({
|
|
1651
|
+
...this.data,
|
|
1652
|
+
eventElements: events
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
query(elements) {
|
|
1656
|
+
return new ArcListener({
|
|
1657
|
+
...this.data,
|
|
1658
|
+
queryElements: elements
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
mutate(elements) {
|
|
1662
|
+
return new ArcListener({
|
|
1663
|
+
...this.data,
|
|
1664
|
+
mutationElements: elements
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
async() {
|
|
1668
|
+
return new ArcListener({
|
|
1669
|
+
...this.data,
|
|
1670
|
+
isAsync: true
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
handle(handler) {
|
|
1674
|
+
return new ArcListener({
|
|
1675
|
+
...this.data,
|
|
1676
|
+
handler
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
get eventElements() {
|
|
1680
|
+
return this.data.eventElements || [];
|
|
1681
|
+
}
|
|
1682
|
+
get isAsync() {
|
|
1683
|
+
return this.data.isAsync;
|
|
1684
|
+
}
|
|
1685
|
+
async init(environment, adapters) {
|
|
1686
|
+
if (environment !== "server") {
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
if (!this.data.handler) {
|
|
1690
|
+
console.warn(`Listener "${this.data.name}" has no handler`);
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
if (!adapters.eventPublisher) {
|
|
1694
|
+
console.warn(`Listener "${this.data.name}" cannot subscribe: no eventPublisher adapter`);
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
for (const eventElement of this.data.eventElements) {
|
|
1698
|
+
const unsubscribe = adapters.eventPublisher.subscribe(eventElement.name, async (event2) => {
|
|
1699
|
+
await this.handleEvent(event2, adapters);
|
|
1700
|
+
});
|
|
1701
|
+
this.unsubscribers.push(unsubscribe);
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
async handleEvent(event2, adapters) {
|
|
1705
|
+
if (!this.data.handler)
|
|
1706
|
+
return;
|
|
1707
|
+
const context2 = this.buildListenerContext(adapters);
|
|
1708
|
+
if (this.data.isAsync) {
|
|
1709
|
+
Promise.resolve(this.data.handler(context2, event2)).catch((error) => {
|
|
1710
|
+
console.error(`Async listener "${this.data.name}" error:`, error);
|
|
1711
|
+
});
|
|
1712
|
+
} else {
|
|
1713
|
+
await this.data.handler(context2, event2);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
buildListenerContext(adapters) {
|
|
1717
|
+
const context2 = {};
|
|
1718
|
+
const elementMap = new Map;
|
|
1719
|
+
for (const element of this.data.queryElements) {
|
|
1720
|
+
if (element.queryContext) {
|
|
1721
|
+
const elementContext = element.queryContext(adapters);
|
|
1722
|
+
context2[element.name] = elementContext;
|
|
1723
|
+
elementMap.set(element, elementContext);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
for (const element of this.data.mutationElements) {
|
|
1727
|
+
if (element.mutateContext) {
|
|
1728
|
+
const elementContext = element.mutateContext(adapters);
|
|
1729
|
+
context2[element.name] = elementContext;
|
|
1730
|
+
elementMap.set(element, elementContext);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
context2.get = (element) => {
|
|
1734
|
+
const cached = elementMap.get(element);
|
|
1735
|
+
if (cached)
|
|
1736
|
+
return cached;
|
|
1737
|
+
if (element.queryContext) {
|
|
1738
|
+
const ctx = element.queryContext(adapters);
|
|
1739
|
+
elementMap.set(element, ctx);
|
|
1740
|
+
return ctx;
|
|
1741
|
+
}
|
|
1742
|
+
if (element.mutateContext) {
|
|
1743
|
+
const ctx = element.mutateContext(adapters);
|
|
1744
|
+
elementMap.set(element, ctx);
|
|
1745
|
+
return ctx;
|
|
1746
|
+
}
|
|
1747
|
+
throw new Error(`Element "${element.name}" has no context available`);
|
|
1748
|
+
};
|
|
1749
|
+
if (adapters.authAdapter) {
|
|
1750
|
+
const decoded = adapters.authAdapter.getDecoded();
|
|
1751
|
+
if (decoded) {
|
|
1752
|
+
context2.$auth = {
|
|
1753
|
+
params: decoded.params,
|
|
1754
|
+
tokenName: decoded.tokenName
|
|
1755
|
+
};
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
return context2;
|
|
1759
|
+
}
|
|
1760
|
+
destroy() {
|
|
1761
|
+
for (const unsubscribe of this.unsubscribers) {
|
|
1762
|
+
unsubscribe();
|
|
1763
|
+
}
|
|
1764
|
+
this.unsubscribers = [];
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
function listener(name) {
|
|
1768
|
+
return new ArcListener({
|
|
1769
|
+
name,
|
|
1770
|
+
eventElements: [],
|
|
1771
|
+
queryElements: [],
|
|
1772
|
+
mutationElements: [],
|
|
1773
|
+
isAsync: false
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1776
|
+
// src/context-element/route/route.ts
|
|
1777
|
+
class ArcRoute extends ArcContextElement {
|
|
1778
|
+
data;
|
|
1779
|
+
constructor(data) {
|
|
1780
|
+
super(data.name);
|
|
1781
|
+
this.data = data;
|
|
1782
|
+
}
|
|
1783
|
+
description(description) {
|
|
1784
|
+
return new ArcRoute({
|
|
1785
|
+
...this.data,
|
|
1786
|
+
description
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
path(path) {
|
|
1790
|
+
return new ArcRoute({
|
|
1791
|
+
...this.data,
|
|
1792
|
+
path
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
public() {
|
|
1796
|
+
return new ArcRoute({
|
|
1797
|
+
...this.data,
|
|
1798
|
+
isPublic: true
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
query(elements) {
|
|
1802
|
+
return new ArcRoute({
|
|
1803
|
+
...this.data,
|
|
1804
|
+
queryElements: elements
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
mutate(elements) {
|
|
1808
|
+
return new ArcRoute({
|
|
1809
|
+
...this.data,
|
|
1810
|
+
mutationElements: elements
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1813
|
+
protectBy(token, check) {
|
|
1814
|
+
const existingProtections = this.data.protections || [];
|
|
1815
|
+
return new ArcRoute({
|
|
1816
|
+
...this.data,
|
|
1817
|
+
protections: [...existingProtections, { token, check }]
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
handle(handlers) {
|
|
1821
|
+
return new ArcRoute({
|
|
1822
|
+
...this.data,
|
|
1823
|
+
handlers
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
get routePath() {
|
|
1827
|
+
return this.data.path || `/${this.data.name}`;
|
|
1828
|
+
}
|
|
1829
|
+
get fullPath() {
|
|
1830
|
+
return `/route${this.routePath}`;
|
|
1831
|
+
}
|
|
1832
|
+
get isPublic() {
|
|
1833
|
+
return this.data.isPublic;
|
|
1834
|
+
}
|
|
1835
|
+
get hasProtections() {
|
|
1836
|
+
return (this.data.protections?.length ?? 0) > 0;
|
|
1837
|
+
}
|
|
1838
|
+
get protections() {
|
|
1839
|
+
return this.data.protections || [];
|
|
1840
|
+
}
|
|
1841
|
+
getHandler(method) {
|
|
1842
|
+
return this.data.handlers?.[method];
|
|
1843
|
+
}
|
|
1844
|
+
matchesPath(pathname) {
|
|
1845
|
+
const routePath = this.fullPath;
|
|
1846
|
+
const routeParts = routePath.split("/").filter(Boolean);
|
|
1847
|
+
const pathParts = pathname.split("/").filter(Boolean);
|
|
1848
|
+
if (routeParts.length !== pathParts.length) {
|
|
1849
|
+
return { matches: false, params: {} };
|
|
1850
|
+
}
|
|
1851
|
+
const params = {};
|
|
1852
|
+
for (let i = 0;i < routeParts.length; i++) {
|
|
1853
|
+
const routePart = routeParts[i];
|
|
1854
|
+
const pathPart = pathParts[i];
|
|
1855
|
+
if (routePart.startsWith(":")) {
|
|
1856
|
+
const paramName = routePart.slice(1);
|
|
1857
|
+
params[paramName] = pathPart;
|
|
1858
|
+
} else if (routePart !== pathPart) {
|
|
1859
|
+
return { matches: false, params: {} };
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
return { matches: true, params };
|
|
1863
|
+
}
|
|
1864
|
+
async verifyProtections(tokens) {
|
|
1865
|
+
if (this.data.isPublic) {
|
|
1866
|
+
return true;
|
|
1867
|
+
}
|
|
1868
|
+
if (!this.data.protections || this.data.protections.length === 0) {
|
|
1869
|
+
return true;
|
|
1870
|
+
}
|
|
1871
|
+
for (const protection of this.data.protections) {
|
|
1872
|
+
const tokenInstance = tokens.find((t) => t.getTokenDefinition() === protection.token);
|
|
1873
|
+
if (!tokenInstance) {
|
|
1874
|
+
return false;
|
|
1875
|
+
}
|
|
1876
|
+
const allowed = await protection.check(tokenInstance);
|
|
1877
|
+
if (!allowed) {
|
|
1878
|
+
return false;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
return true;
|
|
1882
|
+
}
|
|
1883
|
+
buildContext(adapters, authParams) {
|
|
1884
|
+
const context2 = {};
|
|
1885
|
+
const elementMap = new Map;
|
|
1886
|
+
for (const element of this.data.queryElements) {
|
|
1887
|
+
if (element.queryContext) {
|
|
1888
|
+
const elementContext = element.queryContext(adapters);
|
|
1889
|
+
context2[element.name] = elementContext;
|
|
1890
|
+
elementMap.set(element, elementContext);
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
for (const element of this.data.mutationElements) {
|
|
1894
|
+
if (element.mutateContext) {
|
|
1895
|
+
const elementContext = element.mutateContext(adapters);
|
|
1896
|
+
context2[element.name] = elementContext;
|
|
1897
|
+
elementMap.set(element, elementContext);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
context2.get = (element) => {
|
|
1901
|
+
const cached = elementMap.get(element);
|
|
1902
|
+
if (cached)
|
|
1903
|
+
return cached;
|
|
1904
|
+
if (element.queryContext) {
|
|
1905
|
+
const ctx = element.queryContext(adapters);
|
|
1906
|
+
elementMap.set(element, ctx);
|
|
1907
|
+
return ctx;
|
|
1908
|
+
}
|
|
1909
|
+
if (element.mutateContext) {
|
|
1910
|
+
const ctx = element.mutateContext(adapters);
|
|
1911
|
+
elementMap.set(element, ctx);
|
|
1912
|
+
return ctx;
|
|
1913
|
+
}
|
|
1914
|
+
throw new Error(`Element "${element.name}" has no context available`);
|
|
1915
|
+
};
|
|
1916
|
+
if (authParams) {
|
|
1917
|
+
context2.$auth = authParams;
|
|
1918
|
+
}
|
|
1919
|
+
return context2;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
function route(name) {
|
|
1923
|
+
return new ArcRoute({
|
|
1924
|
+
name,
|
|
1925
|
+
path: undefined,
|
|
1926
|
+
description: undefined,
|
|
1927
|
+
queryElements: [],
|
|
1928
|
+
mutationElements: [],
|
|
1929
|
+
handlers: {},
|
|
1930
|
+
protections: [],
|
|
1931
|
+
isPublic: false
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1540
1934
|
// src/context-element/view/view.ts
|
|
1541
1935
|
class ArcView extends ArcContextElement {
|
|
1542
1936
|
data;
|
|
@@ -1596,20 +1990,22 @@ class ArcView extends ArcContextElement {
|
|
|
1596
1990
|
const getReadRestrictions = () => {
|
|
1597
1991
|
if (protections.length === 0)
|
|
1598
1992
|
return null;
|
|
1599
|
-
if (!adapters.authAdapter)
|
|
1600
|
-
return
|
|
1993
|
+
if (!adapters.authAdapter) {
|
|
1994
|
+
return false;
|
|
1995
|
+
}
|
|
1601
1996
|
const decoded = adapters.authAdapter.getDecoded();
|
|
1602
|
-
if (!decoded)
|
|
1603
|
-
return
|
|
1997
|
+
if (!decoded) {
|
|
1998
|
+
return false;
|
|
1999
|
+
}
|
|
1604
2000
|
for (const protection of protections) {
|
|
1605
2001
|
if (protection.token.name === decoded.tokenName) {
|
|
1606
|
-
const
|
|
1607
|
-
if (
|
|
2002
|
+
const restrictions = protection.protectionFn(decoded.params);
|
|
2003
|
+
if (restrictions === false)
|
|
1608
2004
|
return false;
|
|
1609
|
-
return
|
|
2005
|
+
return restrictions ?? {};
|
|
1610
2006
|
}
|
|
1611
2007
|
}
|
|
1612
|
-
return
|
|
2008
|
+
return false;
|
|
1613
2009
|
};
|
|
1614
2010
|
const applyRestrictions = (options) => {
|
|
1615
2011
|
const restrictions = getReadRestrictions();
|
|
@@ -1623,30 +2019,39 @@ class ArcView extends ArcContextElement {
|
|
|
1623
2019
|
};
|
|
1624
2020
|
return {
|
|
1625
2021
|
find: async (options) => {
|
|
1626
|
-
if (!adapters.dataStorage) {
|
|
1627
|
-
console.warn(`View "${viewName}" query: no dataStorage available`);
|
|
1628
|
-
return [];
|
|
1629
|
-
}
|
|
1630
2022
|
const restrictedOptions = applyRestrictions(options);
|
|
1631
2023
|
if (restrictedOptions === false) {
|
|
1632
2024
|
return [];
|
|
1633
2025
|
}
|
|
1634
|
-
|
|
1635
|
-
|
|
2026
|
+
if (adapters.dataStorage) {
|
|
2027
|
+
const store = adapters.dataStorage.getStore(viewName);
|
|
2028
|
+
return store.find(restrictedOptions);
|
|
2029
|
+
}
|
|
2030
|
+
if (adapters.queryWire) {
|
|
2031
|
+
return adapters.queryWire.query(viewName, restrictedOptions);
|
|
2032
|
+
}
|
|
2033
|
+
console.warn(`View "${viewName}" query: no dataStorage or queryWire available`);
|
|
2034
|
+
return [];
|
|
1636
2035
|
},
|
|
1637
2036
|
findOne: async (where) => {
|
|
1638
|
-
if (!adapters.dataStorage) {
|
|
1639
|
-
console.warn(`View "${viewName}" query: no dataStorage available`);
|
|
1640
|
-
return;
|
|
1641
|
-
}
|
|
1642
2037
|
const restrictions = getReadRestrictions();
|
|
1643
2038
|
if (restrictions === false) {
|
|
1644
2039
|
return;
|
|
1645
2040
|
}
|
|
1646
|
-
const store = adapters.dataStorage.getStore(viewName);
|
|
1647
2041
|
const mergedWhere = restrictions && Object.keys(restrictions).length > 0 ? { ...where, ...restrictions } : where;
|
|
1648
|
-
|
|
1649
|
-
|
|
2042
|
+
if (adapters.dataStorage) {
|
|
2043
|
+
const store = adapters.dataStorage.getStore(viewName);
|
|
2044
|
+
const results = await store.find({ where: mergedWhere });
|
|
2045
|
+
return results[0];
|
|
2046
|
+
}
|
|
2047
|
+
if (adapters.queryWire) {
|
|
2048
|
+
const results = await adapters.queryWire.query(viewName, {
|
|
2049
|
+
where: mergedWhere
|
|
2050
|
+
});
|
|
2051
|
+
return results[0];
|
|
2052
|
+
}
|
|
2053
|
+
console.warn(`View "${viewName}" query: no dataStorage or queryWire available`);
|
|
2054
|
+
return;
|
|
1650
2055
|
}
|
|
1651
2056
|
};
|
|
1652
2057
|
}
|
|
@@ -1851,12 +2256,12 @@ class StoreState {
|
|
|
1851
2256
|
applySerializedChanges(changes) {
|
|
1852
2257
|
return Promise.all(changes.map((change) => this.applyChange(change)));
|
|
1853
2258
|
}
|
|
1854
|
-
unsubscribe(
|
|
1855
|
-
this.listeners.delete(
|
|
2259
|
+
unsubscribe(listener4) {
|
|
2260
|
+
this.listeners.delete(listener4);
|
|
1856
2261
|
}
|
|
1857
2262
|
notifyListeners(events) {
|
|
1858
|
-
for (const
|
|
1859
|
-
|
|
2263
|
+
for (const listener4 of this.listeners.values()) {
|
|
2264
|
+
listener4.callback(events);
|
|
1860
2265
|
}
|
|
1861
2266
|
}
|
|
1862
2267
|
}
|
|
@@ -1869,7 +2274,7 @@ function deepMerge(target, source) {
|
|
|
1869
2274
|
output[key] = undefined;
|
|
1870
2275
|
continue;
|
|
1871
2276
|
}
|
|
1872
|
-
if (
|
|
2277
|
+
if (isPlainObject(source[key]) && isPlainObject(target[key])) {
|
|
1873
2278
|
output[key] = deepMerge(target[key], source[key]);
|
|
1874
2279
|
} else {
|
|
1875
2280
|
output[key] = source[key];
|
|
@@ -1877,8 +2282,8 @@ function deepMerge(target, source) {
|
|
|
1877
2282
|
}
|
|
1878
2283
|
return output;
|
|
1879
2284
|
}
|
|
1880
|
-
function
|
|
1881
|
-
return item && typeof item === "object" && !Array.isArray(item);
|
|
2285
|
+
function isPlainObject(item) {
|
|
2286
|
+
return item && typeof item === "object" && !Array.isArray(item) && !(item instanceof Date) && Object.prototype.toString.call(item) === "[object Object]";
|
|
1882
2287
|
}
|
|
1883
2288
|
// src/utils/murmur-hash.ts
|
|
1884
2289
|
function murmurHash(key, seed = 0) {
|
|
@@ -2011,9 +2416,9 @@ class ForkedStoreState extends StoreState {
|
|
|
2011
2416
|
this.notifyListeners(events);
|
|
2012
2417
|
}
|
|
2013
2418
|
}
|
|
2014
|
-
async find(options,
|
|
2015
|
-
if (
|
|
2016
|
-
this.listeners.set(
|
|
2419
|
+
async find(options, listener4) {
|
|
2420
|
+
if (listener4) {
|
|
2421
|
+
this.listeners.set(listener4, { callback: listener4 });
|
|
2017
2422
|
}
|
|
2018
2423
|
const parentResults = await this.master.find(options);
|
|
2019
2424
|
const results = new Map;
|
|
@@ -2172,9 +2577,9 @@ class MasterStoreState extends StoreState {
|
|
|
2172
2577
|
this.notifyListeners(events);
|
|
2173
2578
|
}
|
|
2174
2579
|
}
|
|
2175
|
-
async find(options,
|
|
2176
|
-
if (
|
|
2177
|
-
this.listeners.set(
|
|
2580
|
+
async find(options, listener4) {
|
|
2581
|
+
if (listener4) {
|
|
2582
|
+
this.listeners.set(listener4, { callback: listener4 });
|
|
2178
2583
|
}
|
|
2179
2584
|
const transaction = await this.dataStorage.getReadTransaction();
|
|
2180
2585
|
const results = await transaction.find(this.storeName, options);
|
|
@@ -2364,13 +2769,13 @@ class ObservableDataStorage {
|
|
|
2364
2769
|
commitChanges(changes) {
|
|
2365
2770
|
return this.source.commitChanges(changes);
|
|
2366
2771
|
}
|
|
2367
|
-
trackQuery(storeName, options, result,
|
|
2772
|
+
trackQuery(storeName, options, result, listener4) {
|
|
2368
2773
|
const key = this.getQueryKey(storeName, options);
|
|
2369
2774
|
this.trackedQueries.set(key, {
|
|
2370
2775
|
storeName,
|
|
2371
2776
|
options,
|
|
2372
2777
|
result,
|
|
2373
|
-
listener
|
|
2778
|
+
listener: listener4
|
|
2374
2779
|
});
|
|
2375
2780
|
}
|
|
2376
2781
|
handleStoreChange(storeName, events) {
|
|
@@ -2427,15 +2832,15 @@ class ObservableStoreState {
|
|
|
2427
2832
|
if (cached !== undefined) {
|
|
2428
2833
|
return cached;
|
|
2429
2834
|
}
|
|
2430
|
-
const
|
|
2835
|
+
const listener4 = (events) => {
|
|
2431
2836
|
this.observable.handleStoreChange(this.storeName, events);
|
|
2432
2837
|
};
|
|
2433
|
-
const result = await this.source.find(options,
|
|
2434
|
-
this.observable.trackQuery(this.storeName, options, result,
|
|
2838
|
+
const result = await this.source.find(options, listener4);
|
|
2839
|
+
this.observable.trackQuery(this.storeName, options, result, listener4);
|
|
2435
2840
|
return result;
|
|
2436
2841
|
}
|
|
2437
|
-
unsubscribe(
|
|
2438
|
-
this.source.unsubscribe(
|
|
2842
|
+
unsubscribe(listener4) {
|
|
2843
|
+
this.source.unsubscribe(listener4);
|
|
2439
2844
|
}
|
|
2440
2845
|
async set(item) {
|
|
2441
2846
|
return this.source.set(item);
|
|
@@ -3127,33 +3532,276 @@ function mutationExecutor(model) {
|
|
|
3127
3532
|
}
|
|
3128
3533
|
});
|
|
3129
3534
|
}
|
|
3130
|
-
// src/
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3535
|
+
// src/streaming/streaming-query-cache.ts
|
|
3536
|
+
class StreamingQueryCache {
|
|
3537
|
+
stores = new Map;
|
|
3538
|
+
views = [];
|
|
3539
|
+
registerViews(views) {
|
|
3540
|
+
this.views = views;
|
|
3541
|
+
for (const view3 of views) {
|
|
3542
|
+
if (!this.stores.has(view3.name)) {
|
|
3543
|
+
this.stores.set(view3.name, new StreamingStore);
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
}
|
|
3547
|
+
getStore(viewName) {
|
|
3548
|
+
if (!this.stores.has(viewName)) {
|
|
3549
|
+
this.stores.set(viewName, new StreamingStore);
|
|
3550
|
+
}
|
|
3551
|
+
return this.stores.get(viewName);
|
|
3552
|
+
}
|
|
3553
|
+
setViewData(viewName, items) {
|
|
3554
|
+
const store = this.stores.get(viewName);
|
|
3555
|
+
if (store) {
|
|
3556
|
+
store.setAll(items);
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
async applyEvent(event3) {
|
|
3560
|
+
for (const view3 of this.views) {
|
|
3561
|
+
const handlers = view3.getHandlers();
|
|
3562
|
+
const handler = handlers[event3.type];
|
|
3563
|
+
if (!handler)
|
|
3564
|
+
continue;
|
|
3565
|
+
const store = this.stores.get(view3.name);
|
|
3566
|
+
if (!store)
|
|
3567
|
+
continue;
|
|
3568
|
+
const ctx = {
|
|
3569
|
+
set: async (id3, data) => {
|
|
3570
|
+
store.set(String(id3), { _id: String(id3), ...data });
|
|
3571
|
+
},
|
|
3572
|
+
modify: async (id3, data) => {
|
|
3573
|
+
store.modify(String(id3), data);
|
|
3574
|
+
},
|
|
3575
|
+
remove: async (id3) => {
|
|
3576
|
+
store.remove(String(id3));
|
|
3577
|
+
},
|
|
3578
|
+
find: async (options) => {
|
|
3579
|
+
return store.find(options);
|
|
3580
|
+
},
|
|
3581
|
+
findOne: async (where) => {
|
|
3582
|
+
return store.findOne(where);
|
|
3583
|
+
},
|
|
3584
|
+
$auth: {}
|
|
3585
|
+
};
|
|
3586
|
+
await handler(ctx, event3);
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
clear() {
|
|
3590
|
+
for (const store of this.stores.values()) {
|
|
3591
|
+
store.clear();
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3596
|
+
class StreamingStore {
|
|
3597
|
+
data = new Map;
|
|
3598
|
+
listeners = new Set;
|
|
3599
|
+
setAll(items) {
|
|
3600
|
+
this.data.clear();
|
|
3601
|
+
for (const item of items) {
|
|
3602
|
+
this.data.set(item._id, item);
|
|
3603
|
+
}
|
|
3604
|
+
this.notifyListeners();
|
|
3605
|
+
}
|
|
3606
|
+
set(id3, item) {
|
|
3607
|
+
this.data.set(id3, item);
|
|
3608
|
+
this.notifyListeners();
|
|
3609
|
+
}
|
|
3610
|
+
modify(id3, updates) {
|
|
3611
|
+
const existing = this.data.get(id3);
|
|
3612
|
+
if (existing) {
|
|
3613
|
+
this.data.set(id3, { ...existing, ...updates });
|
|
3614
|
+
this.notifyListeners();
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3617
|
+
remove(id3) {
|
|
3618
|
+
if (this.data.delete(id3)) {
|
|
3619
|
+
this.notifyListeners();
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
clear() {
|
|
3623
|
+
this.data.clear();
|
|
3624
|
+
this.notifyListeners();
|
|
3625
|
+
}
|
|
3626
|
+
find(options = {}) {
|
|
3627
|
+
let results = Array.from(this.data.values());
|
|
3628
|
+
if (options.where) {
|
|
3629
|
+
results = results.filter((item) => checkItemMatchesWhere(item, options.where));
|
|
3630
|
+
}
|
|
3631
|
+
return applyOrderByAndLimit(results, options);
|
|
3632
|
+
}
|
|
3633
|
+
findOne(where) {
|
|
3634
|
+
const results = this.find({ where });
|
|
3635
|
+
return results[0];
|
|
3636
|
+
}
|
|
3637
|
+
subscribe(listener4) {
|
|
3638
|
+
this.listeners.add(listener4);
|
|
3639
|
+
return () => {
|
|
3640
|
+
this.listeners.delete(listener4);
|
|
3641
|
+
};
|
|
3642
|
+
}
|
|
3643
|
+
notifyListeners() {
|
|
3644
|
+
for (const listener4 of this.listeners) {
|
|
3645
|
+
listener4();
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
// src/streaming/streaming-event-publisher.ts
|
|
3650
|
+
class StreamingEventPublisher {
|
|
3651
|
+
cache;
|
|
3652
|
+
eventWire;
|
|
3653
|
+
views = [];
|
|
3654
|
+
subscribers = new Map;
|
|
3655
|
+
constructor(cache, eventWire) {
|
|
3656
|
+
this.cache = cache;
|
|
3657
|
+
this.eventWire = eventWire;
|
|
3658
|
+
}
|
|
3659
|
+
registerViews(views) {
|
|
3660
|
+
this.views = views;
|
|
3661
|
+
this.cache.registerViews(views);
|
|
3662
|
+
}
|
|
3663
|
+
async publish(event3) {
|
|
3664
|
+
await this.cache.applyEvent(event3);
|
|
3665
|
+
await this.notifySubscribers(event3);
|
|
3666
|
+
this.eventWire.syncEvents([
|
|
3667
|
+
{
|
|
3668
|
+
localId: event3.id,
|
|
3669
|
+
type: event3.type,
|
|
3670
|
+
payload: event3.payload,
|
|
3671
|
+
createdAt: event3.createdAt.toISOString()
|
|
3672
|
+
}
|
|
3673
|
+
]);
|
|
3674
|
+
}
|
|
3675
|
+
subscribe(eventType, callback) {
|
|
3676
|
+
if (!this.subscribers.has(eventType)) {
|
|
3677
|
+
this.subscribers.set(eventType, new Set);
|
|
3678
|
+
}
|
|
3679
|
+
this.subscribers.get(eventType).add(callback);
|
|
3680
|
+
return () => {
|
|
3681
|
+
const subs = this.subscribers.get(eventType);
|
|
3682
|
+
if (subs) {
|
|
3683
|
+
subs.delete(callback);
|
|
3684
|
+
if (subs.size === 0) {
|
|
3685
|
+
this.subscribers.delete(eventType);
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
async markSynced(_eventIds) {}
|
|
3691
|
+
async getUnsyncedEvents(_eventType) {
|
|
3692
|
+
return [];
|
|
3693
|
+
}
|
|
3694
|
+
async notifySubscribers(event3) {
|
|
3695
|
+
const subs = this.subscribers.get(event3.type);
|
|
3696
|
+
if (!subs || subs.size === 0)
|
|
3697
|
+
return;
|
|
3698
|
+
const promises = [];
|
|
3699
|
+
for (const callback of subs) {
|
|
3700
|
+
try {
|
|
3701
|
+
const result = callback(event3);
|
|
3702
|
+
if (result instanceof Promise) {
|
|
3703
|
+
promises.push(result);
|
|
3704
|
+
}
|
|
3705
|
+
} catch (error) {
|
|
3706
|
+
console.error(`Listener error for event "${event3.type}":`, error);
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
if (promises.length > 0) {
|
|
3710
|
+
await Promise.all(promises.map((p) => p.catch((e) => console.error(e))));
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
// src/streaming/streaming-live-query.ts
|
|
3715
|
+
function streamingLiveQuery(model, queryFn, callback, options) {
|
|
3716
|
+
const { queryWire, cache, authToken } = options;
|
|
3717
|
+
let currentResult = undefined;
|
|
3718
|
+
const unsubscribers = [];
|
|
3719
|
+
const streamConnections = [];
|
|
3720
|
+
const queriedViews = new Set;
|
|
3721
|
+
const queryContext = new Proxy({}, {
|
|
3138
3722
|
get(_target, viewName) {
|
|
3139
3723
|
const element2 = model.context.get(viewName);
|
|
3140
3724
|
if (!element2) {
|
|
3141
3725
|
throw new Error(`View '${viewName}' not found in context`);
|
|
3142
3726
|
}
|
|
3143
|
-
|
|
3727
|
+
queriedViews.add(viewName);
|
|
3728
|
+
return {
|
|
3729
|
+
find: async (findOptions = {}) => {
|
|
3730
|
+
const store = cache.getStore(viewName);
|
|
3731
|
+
return store.find(findOptions);
|
|
3732
|
+
},
|
|
3733
|
+
findOne: async (where) => {
|
|
3734
|
+
const store = cache.getStore(viewName);
|
|
3735
|
+
return store.findOne(where);
|
|
3736
|
+
}
|
|
3737
|
+
};
|
|
3144
3738
|
}
|
|
3145
3739
|
});
|
|
3740
|
+
const executeQuery = async () => {
|
|
3741
|
+
const result = await queryFn(queryContext);
|
|
3742
|
+
currentResult = result;
|
|
3743
|
+
callback(result);
|
|
3744
|
+
};
|
|
3745
|
+
const setupStreams = async () => {
|
|
3746
|
+
queriedViews.clear();
|
|
3747
|
+
await queryFn(queryContext);
|
|
3748
|
+
for (const viewName of queriedViews) {
|
|
3749
|
+
const store = cache.getStore(viewName);
|
|
3750
|
+
const unsub = store.subscribe(() => {
|
|
3751
|
+
executeQuery();
|
|
3752
|
+
});
|
|
3753
|
+
unsubscribers.push(unsub);
|
|
3754
|
+
const streamConn = queryWire.stream(viewName, {}, (data) => {
|
|
3755
|
+
cache.setViewData(viewName, data);
|
|
3756
|
+
}, authToken);
|
|
3757
|
+
streamConnections.push(streamConn);
|
|
3758
|
+
}
|
|
3759
|
+
};
|
|
3760
|
+
setupStreams();
|
|
3761
|
+
return {
|
|
3762
|
+
get result() {
|
|
3763
|
+
return currentResult;
|
|
3764
|
+
},
|
|
3765
|
+
unsubscribe: () => {
|
|
3766
|
+
for (const unsub of unsubscribers) {
|
|
3767
|
+
unsub();
|
|
3768
|
+
}
|
|
3769
|
+
for (const conn of streamConnections) {
|
|
3770
|
+
conn.unsubscribe();
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
};
|
|
3146
3774
|
}
|
|
3775
|
+
// src/model/live-query/live-query.ts
|
|
3147
3776
|
function liveQuery(model, queryFn, callback) {
|
|
3148
3777
|
let currentResult = undefined;
|
|
3149
3778
|
const adapters = model.getAdapters();
|
|
3150
|
-
if (!adapters.dataStorage) {
|
|
3151
|
-
|
|
3779
|
+
if (!adapters.dataStorage && adapters.streamingCache && adapters.queryWire) {
|
|
3780
|
+
return streamingLiveQuery(model, queryFn, callback, {
|
|
3781
|
+
queryWire: adapters.queryWire,
|
|
3782
|
+
cache: adapters.streamingCache,
|
|
3783
|
+
authToken: adapters.authAdapter?.getToken?.() ?? null
|
|
3784
|
+
});
|
|
3785
|
+
}
|
|
3786
|
+
if (!adapters.dataStorage && !adapters.queryWire) {
|
|
3787
|
+
throw new Error("liveQuery requires dataStorage or queryWire adapter");
|
|
3152
3788
|
}
|
|
3153
|
-
const observableStorage = observeQueries(adapters.dataStorage, () => {
|
|
3789
|
+
const observableStorage = adapters.dataStorage ? observeQueries(adapters.dataStorage, () => {
|
|
3154
3790
|
executeQuery();
|
|
3791
|
+
}) : null;
|
|
3792
|
+
const observableAdapters = {
|
|
3793
|
+
...adapters,
|
|
3794
|
+
dataStorage: observableStorage ?? undefined
|
|
3795
|
+
};
|
|
3796
|
+
const queryContext = new Proxy({}, {
|
|
3797
|
+
get(_target, viewName) {
|
|
3798
|
+
const element2 = model.context.get(viewName);
|
|
3799
|
+
if (!element2) {
|
|
3800
|
+
throw new Error(`View '${viewName}' not found in context`);
|
|
3801
|
+
}
|
|
3802
|
+
return element2.queryContext(observableAdapters);
|
|
3803
|
+
}
|
|
3155
3804
|
});
|
|
3156
|
-
const queryContext = createQueryContext(model, observableStorage);
|
|
3157
3805
|
const executeQuery = async () => {
|
|
3158
3806
|
const result = await queryFn(queryContext);
|
|
3159
3807
|
currentResult = result;
|
|
@@ -3165,7 +3813,7 @@ function liveQuery(model, queryFn, callback) {
|
|
|
3165
3813
|
return currentResult;
|
|
3166
3814
|
},
|
|
3167
3815
|
unsubscribe: () => {
|
|
3168
|
-
observableStorage
|
|
3816
|
+
observableStorage?.clear();
|
|
3169
3817
|
}
|
|
3170
3818
|
};
|
|
3171
3819
|
}
|
|
@@ -3552,7 +4200,9 @@ export {
|
|
|
3552
4200
|
token,
|
|
3553
4201
|
stringEnum,
|
|
3554
4202
|
string,
|
|
4203
|
+
streamingLiveQuery,
|
|
3555
4204
|
secureDataStorage,
|
|
4205
|
+
route,
|
|
3556
4206
|
resolveQueryChange,
|
|
3557
4207
|
record,
|
|
3558
4208
|
or,
|
|
@@ -3562,6 +4212,7 @@ export {
|
|
|
3562
4212
|
mutationExecutor,
|
|
3563
4213
|
murmurHash,
|
|
3564
4214
|
liveQuery,
|
|
4215
|
+
listener,
|
|
3565
4216
|
id,
|
|
3566
4217
|
file,
|
|
3567
4218
|
extractDatabaseAgnosticSchema,
|
|
@@ -3581,9 +4232,12 @@ export {
|
|
|
3581
4232
|
Wire,
|
|
3582
4233
|
TokenInstance,
|
|
3583
4234
|
TokenCache,
|
|
4235
|
+
StreamingQueryCache,
|
|
4236
|
+
StreamingEventPublisher,
|
|
3584
4237
|
StoreState,
|
|
3585
4238
|
SecuredStoreState,
|
|
3586
4239
|
SecuredDataStorage,
|
|
4240
|
+
QueryWire,
|
|
3587
4241
|
ObservableDataStorage,
|
|
3588
4242
|
Model,
|
|
3589
4243
|
MasterStoreState,
|
|
@@ -3600,11 +4254,13 @@ export {
|
|
|
3600
4254
|
ArcToken,
|
|
3601
4255
|
ArcStringEnum,
|
|
3602
4256
|
ArcString,
|
|
4257
|
+
ArcRoute,
|
|
3603
4258
|
ArcRecord,
|
|
3604
4259
|
ArcOr,
|
|
3605
4260
|
ArcOptional,
|
|
3606
4261
|
ArcObject,
|
|
3607
4262
|
ArcNumber,
|
|
4263
|
+
ArcListener,
|
|
3608
4264
|
ArcId,
|
|
3609
4265
|
ArcFile,
|
|
3610
4266
|
ArcEvent,
|