@arcote.tech/arc-host 0.7.15 → 0.7.16

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/index.js CHANGED
@@ -4782,66 +4782,14 @@ function arcHttpHandlers(ch, cm) {
4782
4782
  ];
4783
4783
  }
4784
4784
  // src/middleware/ws.ts
4785
- import {
4786
- ScopedModel as ScopedModel3,
4787
- ScopedStore,
4788
- checkItemMatchesWhere
4789
- } from "@arcote.tech/arc";
4790
- var viewSubscribers = new Map;
4785
+ import { LiveQuery } from "@arcote.tech/arc";
4786
+ var clientQuerySubs = new Map;
4791
4787
  function cleanupClientSubs(clientId) {
4792
- const prefix = `${clientId}:`;
4793
- for (const subs of viewSubscribers.values()) {
4794
- for (const key of subs.keys()) {
4795
- if (key.startsWith(prefix))
4796
- subs.delete(key);
4797
- }
4798
- }
4799
- }
4800
- function filterChangeForSubscriber(change, restrictions) {
4801
- const newMatches = change.newRow !== null && (restrictions === null || checkItemMatchesWhere(change.newRow, restrictions));
4802
- if (newMatches) {
4803
- return { type: "set", id: change.id, item: change.newRow };
4804
- }
4805
- const oldMatches = change.oldRow !== null && (restrictions === null || checkItemMatchesWhere(change.oldRow, restrictions));
4806
- if (oldMatches) {
4807
- return { type: "delete", id: change.id, item: null };
4808
- }
4809
- return null;
4810
- }
4811
- function broadcastViewChanges(committed, connectionManager) {
4812
- const byStore = new Map;
4813
- for (const change of committed) {
4814
- let list = byStore.get(change.store);
4815
- if (!list) {
4816
- list = [];
4817
- byStore.set(change.store, list);
4818
- }
4819
- list.push(change);
4820
- }
4821
- for (const [viewName, changes] of byStore) {
4822
- const subs = viewSubscribers.get(viewName);
4823
- if (!subs || subs.size === 0)
4824
- continue;
4825
- for (const sub of subs.values()) {
4826
- const filtered = [];
4827
- for (const change of changes) {
4828
- const wireChange = filterChangeForSubscriber(change, sub.restrictions);
4829
- if (wireChange)
4830
- filtered.push(wireChange);
4831
- }
4832
- if (filtered.length === 0)
4833
- continue;
4834
- if (sub.buffer) {
4835
- sub.buffer.push(...filtered);
4836
- continue;
4837
- }
4838
- connectionManager.sendToClient(sub.clientId, {
4839
- type: "view-changes",
4840
- element: viewName,
4841
- scope: sub.scope,
4842
- changes: filtered
4843
- });
4844
- }
4788
+ const subs = clientQuerySubs.get(clientId);
4789
+ if (subs) {
4790
+ for (const live of subs.values())
4791
+ live.stop();
4792
+ clientQuerySubs.delete(clientId);
4845
4793
  }
4846
4794
  }
4847
4795
  function scopeAuthHandler() {
@@ -4940,82 +4888,62 @@ function executeCommandHandler() {
4940
4888
  return true;
4941
4889
  };
4942
4890
  }
4943
- function viewSubscriptionHandler() {
4891
+ function querySubscriptionHandler() {
4944
4892
  return async (client, message, ctx) => {
4945
- if (message.type === "subscribe-view") {
4946
- const { element: elementName } = message;
4893
+ if (message.type === "subscribe-query") {
4894
+ const { subscriptionId, descriptor } = message;
4947
4895
  const scope = message.scope ?? "default";
4948
4896
  const scopeToken = client.scopeTokens.get(scope) ?? null;
4949
4897
  let rawToken = scopeToken?.raw ?? null;
4950
4898
  if (!rawToken && client.scopeTokens.size > 0) {
4951
4899
  rawToken = client.scopeTokens.values().next().value.raw;
4952
4900
  }
4953
- const scoped = new ScopedModel3(ctx.contextHandler.getModel(), scope);
4954
- if (rawToken)
4955
- scoped.setToken(rawToken);
4956
- const element = ctx.contextHandler.getModel().context.get(elementName);
4957
- if (!element || typeof element.getRestrictionsFor !== "function") {
4958
- ctx.connectionManager.sendToClient(client.id, {
4959
- type: "error",
4960
- message: `Cannot subscribe to view "${elementName}": unknown element`
4961
- });
4962
- return true;
4963
- }
4964
- const { restrictions, denied } = element.getRestrictionsFor(scoped.getAdapters());
4965
- const subKey = `${client.id}:${scope}`;
4966
- if (denied) {
4967
- viewSubscribers.get(elementName)?.delete(subKey);
4968
- ctx.connectionManager.sendToClient(client.id, {
4969
- type: "view-snapshot",
4970
- element: elementName,
4971
- scope,
4972
- items: []
4973
- });
4974
- return true;
4975
- }
4976
- const subscriber = {
4977
- clientId: client.id,
4978
- scope,
4979
- restrictions,
4980
- buffer: []
4981
- };
4982
- if (!viewSubscribers.has(elementName)) {
4983
- viewSubscribers.set(elementName, new Map);
4901
+ clientQuerySubs.get(client.id)?.get(subscriptionId)?.stop();
4902
+ const live = new LiveQuery(ctx.contextHandler.getModel(), descriptor, scope, rawToken, (update) => {
4903
+ if (update.type === "changes") {
4904
+ ctx.connectionManager.sendToClient(client.id, {
4905
+ type: "query-changes",
4906
+ subscriptionId,
4907
+ changes: update.changes
4908
+ });
4909
+ } else {
4910
+ ctx.connectionManager.sendToClient(client.id, {
4911
+ type: "query-snapshot",
4912
+ subscriptionId,
4913
+ result: update.result ?? null
4914
+ });
4915
+ }
4916
+ });
4917
+ if (!clientQuerySubs.has(client.id)) {
4918
+ clientQuerySubs.set(client.id, new Map);
4984
4919
  }
4985
- viewSubscribers.get(elementName).set(subKey, subscriber);
4920
+ clientQuerySubs.get(client.id).set(subscriptionId, live);
4986
4921
  try {
4987
- const store = ctx.contextHandler.getDataStorage().getStore(elementName);
4988
- const items = restrictions ? await new ScopedStore(store, restrictions, false).find({}) : await store.find({});
4922
+ const result = await live.start();
4989
4923
  ctx.connectionManager.sendToClient(client.id, {
4990
- type: "view-snapshot",
4991
- element: elementName,
4992
- scope,
4993
- items
4924
+ type: "query-snapshot",
4925
+ subscriptionId,
4926
+ result: result ?? null
4994
4927
  });
4928
+ live.flush();
4995
4929
  } catch (err) {
4996
- viewSubscribers.get(elementName)?.delete(subKey);
4997
- console.error(`[Arc] View subscription error (${elementName}):`, err);
4930
+ live.stop();
4931
+ clientQuerySubs.get(client.id)?.delete(subscriptionId);
4932
+ console.error(`[Arc] Query subscription error (${descriptor?.element}.${descriptor?.method}):`, err);
4998
4933
  ctx.connectionManager.sendToClient(client.id, {
4999
4934
  type: "error",
5000
- message: `Failed to subscribe to view "${elementName}"`
5001
- });
5002
- return true;
5003
- }
5004
- const buffered = subscriber.buffer;
5005
- subscriber.buffer = null;
5006
- if (buffered.length > 0) {
5007
- ctx.connectionManager.sendToClient(client.id, {
5008
- type: "view-changes",
5009
- element: elementName,
5010
- scope,
5011
- changes: buffered
4935
+ message: `Failed to subscribe to query "${descriptor?.element}.${descriptor?.method}"`
5012
4936
  });
5013
4937
  }
5014
4938
  return true;
5015
4939
  }
5016
- if (message.type === "unsubscribe-view") {
5017
- const scope = message.scope ?? "default";
5018
- viewSubscribers.get(message.element)?.delete(`${client.id}:${scope}`);
4940
+ if (message.type === "unsubscribe-query") {
4941
+ const subs = clientQuerySubs.get(client.id);
4942
+ const live = subs?.get(message.subscriptionId);
4943
+ if (live) {
4944
+ live.stop();
4945
+ subs.delete(message.subscriptionId);
4946
+ }
5019
4947
  return true;
5020
4948
  }
5021
4949
  return false;
@@ -5027,7 +4955,7 @@ function arcWsHandlers() {
5027
4955
  syncEventsHandler(),
5028
4956
  requestSyncHandler(),
5029
4957
  executeCommandHandler(),
5030
- viewSubscriptionHandler()
4958
+ querySubscriptionHandler()
5031
4959
  ];
5032
4960
  }
5033
4961
  // src/create-server.ts
@@ -5040,7 +4968,6 @@ async function createArcServer(config) {
5040
4968
  const cronScheduler = new CronScheduler(contextHandler);
5041
4969
  cronScheduler.start();
5042
4970
  const connectionManager = new ConnectionManager;
5043
- contextHandler.getEventPublisher().onViewChanges((changes) => broadcastViewChanges(changes, connectionManager));
5044
4971
  function buildCorsHeaders(req) {
5045
4972
  const origin = req?.headers.get("Origin") || "*";
5046
4973
  return {
@@ -5223,11 +5150,11 @@ function hostLiveModel(context, dbAdapterFactory) {
5223
5150
  });
5224
5151
  }
5225
5152
  export {
5226
- viewSubscriptionHandler,
5227
5153
  syncEventsHandler,
5228
5154
  scopeAuthHandler,
5229
5155
  routeHandler,
5230
5156
  requestSyncHandler,
5157
+ querySubscriptionHandler,
5231
5158
  queryHandler,
5232
5159
  hostLiveModel,
5233
5160
  healthHandler,
@@ -5240,7 +5167,6 @@ export {
5240
5167
  cleanupClientSubs,
5241
5168
  canTokenReceiveEvent,
5242
5169
  canTokenEmitEvent,
5243
- broadcastViewChanges,
5244
5170
  arcWsHandlers,
5245
5171
  arcHttpHandlers,
5246
5172
  CronScheduler,
@@ -5248,5 +5174,5 @@ export {
5248
5174
  ConnectionManager
5249
5175
  };
5250
5176
 
5251
- //# debugId=094B6B350E52DB8A64756E2164756E21
5177
+ //# debugId=5FB48DB48B7AE0DA64756E2164756E21
5252
5178
  //# sourceMappingURL=index.js.map