@arcote.tech/arc 0.7.15 → 0.7.17

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.
@@ -14,7 +14,7 @@
14
14
  import type { ArcEventAny } from "../context-element/event";
15
15
  import type { ArcEventInstance } from "../context-element/event/instance";
16
16
  import type { ArcViewAny } from "../context-element/view/view";
17
- import type { CommittedChange, DataStorage } from "../data-storage";
17
+ import type { DataStorage } from "../data-storage";
18
18
  /** Shared table names for all events */
19
19
  export declare const EVENT_TABLES: {
20
20
  readonly events: "events";
@@ -99,19 +99,12 @@ export declare class LocalEventPublisher implements EventPublisher {
99
99
  private views;
100
100
  private syncCallback?;
101
101
  private subscribers;
102
- private viewChangesCallbacks;
103
102
  constructor(dataStorage: DataStorage);
104
103
  /**
105
104
  * Set a callback to be called after each event is published
106
105
  * Used for syncing events to the host
107
106
  */
108
107
  onPublish(callback: (event: ArcEventInstance<ArcEventAny>) => void): void;
109
- /**
110
- * Register a callback fired after each publish commit with the committed
111
- * VIEW store changes (old/new rows). Used by the host to broadcast
112
- * incremental view deltas to subscribed streaming clients.
113
- */
114
- onViewChanges(callback: (changes: CommittedChange[]) => void): () => void;
115
108
  /**
116
109
  * Register views that should be updated when events are published
117
110
  */
@@ -24,16 +24,19 @@ export interface ReceivedEvent {
24
24
  clientId: string;
25
25
  authContext: EventAuthContext | null;
26
26
  }
27
- import type { ListenerEvent } from "../data-storage/data-storage.abstract";
27
+ import type { ContextDescriptor } from "../model/context-accessor";
28
+ import type { QueryResultChange } from "../model/live-query/diff";
28
29
  type EventWireState = "disconnected" | "connecting" | "connected";
29
30
  /**
30
- * Callbacks for a view replica subscription. The server answers
31
- * `subscribe-view` with a full `view-snapshot`, then pushes incremental
32
- * `view-changes` deltas (already filtered by the scope's token).
31
+ * Callbacks for a live query subscription. The server answers
32
+ * `subscribe-query` with a full `query-snapshot` (the query's result),
33
+ * then pushes positional `query-changes` deltas computed by the server-side
34
+ * LiveQuery (re-execute + diff). Non-list results always arrive as
35
+ * snapshots.
33
36
  */
34
- export interface ViewSubscriptionCallbacks {
35
- onSnapshot: (items: any[]) => void;
36
- onChanges: (changes: ListenerEvent<any>[]) => void;
37
+ export interface QuerySubscriptionCallbacks {
38
+ onSnapshot: (result: any) => void;
39
+ onChanges: (changes: QueryResultChange[]) => void;
37
40
  }
38
41
  export declare class EventWire {
39
42
  private readonly baseUrl;
@@ -47,13 +50,15 @@ export declare class EventWire {
47
50
  private onSyncedCallback?;
48
51
  private reconnectTimeout?;
49
52
  private syncRequested;
50
- /** Active view subscriptions keyed by `${scope}:${element}`. Re-sent in
51
- * full on every (re)connect — the server drops its registry on
52
- * disconnect, and a fresh snapshot follows each re-subscribe. */
53
- private viewSubscriptions;
53
+ /** Active query subscriptions keyed by subscriptionId. Re-sent in full
54
+ * on every (re)connect — the server drops its registry on disconnect,
55
+ * and a fresh snapshot follows each re-subscribe. */
56
+ private querySubscriptions;
57
+ private querySubCounter;
54
58
  /** When false (streaming mode), the client neither requests the event
55
- * log (`request-sync`) nor consumes domain events — view replicas are
56
- * the only data channel. Local mode keeps full event sync. */
59
+ * log (`request-sync`) nor consumes domain events — live query
60
+ * subscriptions are the only data channel. Local mode keeps full
61
+ * event sync. */
57
62
  private readonly enableEventSync;
58
63
  constructor(baseUrl: string, options?: {
59
64
  enableEventSync?: boolean;
@@ -97,16 +102,16 @@ export declare class EventWire {
97
102
  */
98
103
  onSynced(callback: (localIds: string[]) => void): void;
99
104
  /**
100
- * Subscribe to a view replica. The server responds with a full
101
- * `view-snapshot` of the token's slice, then pushes `view-changes`
102
- * deltas. One subscription per `${scope}:${element}` callers dedupe
103
- * (StreamingQueryCache.registerStream).
105
+ * Subscribe to a live query. The server executes the descriptor with
106
+ * tracking, responds with a full `query-snapshot`, then pushes positional
107
+ * `query-changes` deltas whenever the result changes. Callers dedupe
108
+ * identical descriptors (StreamingQueryCache).
104
109
  */
105
- subscribeView(element: string, scope: string, callbacks: ViewSubscriptionCallbacks): void;
110
+ subscribeQuery(descriptor: ContextDescriptor, scope: string, callbacks: QuerySubscriptionCallbacks): string;
106
111
  /**
107
- * Unsubscribe from a view replica.
112
+ * Unsubscribe from a live query.
108
113
  */
109
- unsubscribeView(element: string, scope: string): void;
114
+ unsubscribeQuery(subscriptionId: string): void;
110
115
  /**
111
116
  * Get current connection state
112
117
  */
@@ -120,11 +125,12 @@ export declare class EventWire {
120
125
  private requestSync;
121
126
  private flushPendingEvents;
122
127
  /**
123
- * (Re)send every active view subscription. Called on each (re)connect —
128
+ * (Re)send every active query subscription. Called on each (re)connect —
124
129
  * covers both subscriptions made while offline and re-establishing the
125
130
  * server-side registry after a reconnect (server cleans it on disconnect).
131
+ * Each re-subscribe yields a fresh snapshot.
126
132
  */
127
- private sendAllViewSubscriptions;
133
+ private sendAllQuerySubscriptions;
128
134
  private scheduleReconnect;
129
135
  }
130
136
  export {};
@@ -10,9 +10,11 @@
10
10
  */
11
11
  export { AuthAdapter } from "./auth-adapter";
12
12
  export type { DecodedToken } from "./auth-adapter";
13
+ export { awaitModuleSync, hasModuleSyncProvider, registerModuleSyncProvider, triggerModuleSync, } from "./module-sync-coordinator";
14
+ export type { ModuleSyncProvider } from "./module-sync-coordinator";
13
15
  export { CommandWire } from "./command-wire";
14
16
  export { EventWire } from "./event-wire";
15
- export type { ReceivedEvent, SyncableEvent, ViewSubscriptionCallbacks, } from "./event-wire";
17
+ export type { QuerySubscriptionCallbacks, ReceivedEvent, SyncableEvent, } from "./event-wire";
16
18
  export { QueryWire } from "./query-wire";
17
19
  export { Wire } from "./wire";
18
20
  export type { WireAuth } from "./wire";
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Module-sync coordinator — neutral seam letting token-setters (core/react)
3
+ * await the platform module loader WITHOUT core/react depending on platform.
4
+ *
5
+ * Token-gated code-splitting: setting a scope token must dynamically import
6
+ * that token's module chunks before routes inside them exist. The loader
7
+ * lives in the platform layer; setToken lives in core/react. This singleton
8
+ * is the bridge: platform's useModuleLoader registers a provider (runs
9
+ * syncModules), and setToken triggers a sync + returns a promise that
10
+ * resolves when the LATEST sync finishes.
11
+ *
12
+ * With no provider registered (server, SSR, tests, app-without-platform)
13
+ * every call resolves immediately — preserving the historical synchronous
14
+ * semantics. It NEVER rejects: a hung/failed sync resolves after a bounded
15
+ * timeout so navigation always proceeds.
16
+ */
17
+ export type ModuleSyncProvider = (scope?: string) => Promise<void>;
18
+ /**
19
+ * Register the function that performs a module sync. Returns an unregister fn.
20
+ * Last registration wins (only one platform loader is ever mounted).
21
+ */
22
+ export declare function registerModuleSyncProvider(fn: ModuleSyncProvider): () => void;
23
+ export declare function hasModuleSyncProvider(): boolean;
24
+ /**
25
+ * Trigger a sync through the registered provider; resolve when it finishes
26
+ * (or after `timeoutMs`). Coalesces concurrent calls — the published
27
+ * `latestSync` tracks the newest invocation.
28
+ *
29
+ * - No provider → resolves immediately (sync semantics preserved).
30
+ * - Provider hangs → resolves (never rejects) after `timeoutMs` + a warning.
31
+ * - Provider throws → resolves (never rejects) + a warning; the loader
32
+ * surfaces its own error state. setToken must not throw on module-load fail.
33
+ */
34
+ export declare function triggerModuleSync(scope?: string, timeoutMs?: number): Promise<void>;
35
+ /**
36
+ * Await the most recent sync without triggering a new one. Resolves
37
+ * immediately when nothing is in flight.
38
+ */
39
+ export declare function awaitModuleSync(): Promise<void>;
40
+ //# sourceMappingURL=module-sync-coordinator.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=module-sync-coordinator.test.d.ts.map
@@ -5,8 +5,8 @@
5
5
  * - One-shot queries via HTTP POST
6
6
  * - Per-request auth via scope + token
7
7
  *
8
- * Live updates go through EventWire view subscriptions
9
- * (view-snapshot + view-changes), not through this adapter.
8
+ * Live updates go through EventWire query subscriptions
9
+ * (query-snapshot + query-changes), not through this adapter.
10
10
  */
11
11
  import { Wire, type WireAuth } from "./wire";
12
12
  export declare class QueryWire extends Wire {
@@ -196,16 +196,6 @@ export declare class ArcAggregateElement<Name extends string = string, Id extend
196
196
  get cronMethods(): AggregateCronMethodEntry[];
197
197
  queryContext(adapters: ModelAdapters): AggregateQueryContext<QueryMethods>;
198
198
  private buildPrivateQuery;
199
- /**
200
- * Resolve this aggregate's protection for the current auth context.
201
- * Public entry point for the host's view-subscription handler — used to
202
- * compute the subscriber's restrictions once at subscribe time (snapshot
203
- * filtering + per-delta filtering).
204
- */
205
- getRestrictionsFor(adapters: ModelAdapters): {
206
- restrictions: Record<string, unknown> | null;
207
- denied: boolean;
208
- };
209
199
  private isScopeDenied;
210
200
  private getAuth;
211
201
  private getScopeRestrictions;
@@ -104,16 +104,6 @@ export declare class ArcView<const Data extends ArcViewData> extends ArcContextE
104
104
  * @returns Context object with find/findOne methods
105
105
  */
106
106
  queryContext(adapters: any): ArcViewQueryContext<Data["id"], Data["schema"]>;
107
- /**
108
- * Resolve this view's protection for the current auth context.
109
- * Public entry point for the host's view-subscription handler — used to
110
- * compute the subscriber's restrictions once at subscribe time (snapshot
111
- * filtering + per-delta filtering).
112
- */
113
- getRestrictionsFor(adapters: any): {
114
- restrictions: Record<string, unknown> | null;
115
- denied: boolean;
116
- };
117
107
  private resolveProtection;
118
108
  /**
119
109
  * Get event handlers for this view
@@ -1,5 +1,5 @@
1
1
  import { ForkedDataStorage } from "./data-storage-forked";
2
- import { DataStorage, type CommittedChange, type DataStorageChanges } from "./data-storage.abstract";
2
+ import { DataStorage, type DataStorageChanges } from "./data-storage.abstract";
3
3
  import type { DatabaseAdapter, ReadTransaction, ReadWriteTransaction } from "./database-adapter";
4
4
  import type { StoreState } from "./store-state.abstract";
5
5
  export declare class MasterDataStorage extends DataStorage {
@@ -22,9 +22,7 @@ export declare class MasterDataStorage extends DataStorage {
22
22
  _id: string;
23
23
  } | null;
24
24
  }[][]>;
25
- commitChanges(changes: DataStorageChanges[], options?: {
26
- captureRowsFor?: Set<string>;
27
- }): Promise<CommittedChange[]>;
25
+ commitChanges(changes: DataStorageChanges[]): Promise<void>;
28
26
  fork(): ForkedDataStorage;
29
27
  /**
30
28
  * Destroy the data storage - clears all stores and destroys the database
@@ -1,5 +1,5 @@
1
1
  import type { ForkedDataStorage } from "./data-storage-forked";
2
- import type { CommittedChange, DataStorage, DataStorageChanges, ListenerEvent, QueryListenerCallback } from "./data-storage.abstract";
2
+ import type { DataStorage, DataStorageChanges, ListenerEvent, QueryListenerCallback } from "./data-storage.abstract";
3
3
  import type { ReadTransaction, ReadWriteTransaction } from "./database-adapter";
4
4
  import type { FindOptions } from "./find-options";
5
5
  import type { StoreState } from "./store-state.abstract";
@@ -25,9 +25,7 @@ export declare class ObservableDataStorage {
25
25
  fork(): ForkedDataStorage;
26
26
  getReadTransaction(): Promise<ReadTransaction>;
27
27
  getReadWriteTransaction(): Promise<ReadWriteTransaction>;
28
- commitChanges(changes: DataStorageChanges[], options?: {
29
- captureRowsFor?: Set<string>;
30
- }): Promise<CommittedChange[]>;
28
+ commitChanges(changes: DataStorageChanges[]): Promise<void>;
31
29
  /**
32
30
  * Register a tracked query
33
31
  */
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data-storage-observable.test.d.ts.map
@@ -9,21 +9,8 @@ export declare abstract class DataStorage {
9
9
  abstract fork(): ForkedDataStorage;
10
10
  abstract getReadTransaction(): Promise<ReadTransaction>;
11
11
  abstract getReadWriteTransaction(): Promise<ReadWriteTransaction>;
12
- commitChanges(changes: DataStorageChanges[], _options?: {
13
- captureRowsFor?: Set<string>;
14
- }): Promise<CommittedChange[]>;
12
+ commitChanges(changes: DataStorageChanges[]): Promise<void>;
15
13
  }
16
- /**
17
- * A change applied and committed to a store, with the row state before and
18
- * after the write (store/DB form). Returned by `commitChanges` for stores
19
- * requested via `captureRowsFor` — consumed by view-change broadcasting.
20
- */
21
- export type CommittedChange = {
22
- store: string;
23
- id: string;
24
- oldRow: any | null;
25
- newRow: any | null;
26
- };
27
14
  export type StoreStateChange<Item> = {
28
15
  type: "set";
29
16
  data: Item;
@@ -13,20 +13,10 @@ export declare class MasterStoreState<Item extends {
13
13
  * the same aggregate id) and must not shadow each other.
14
14
  */
15
15
  private readExisting;
16
- applyChangeAndReturnEvent(transaction: ReadWriteTransaction, change: StoreStateChange<Item>, transactionCache?: Map<string, Item>, options?: {
17
- captureRows?: boolean;
18
- }): Promise<{
16
+ applyChangeAndReturnEvent(transaction: ReadWriteTransaction, change: StoreStateChange<Item>, transactionCache?: Map<string, Item>): Promise<{
19
17
  from: Item | null;
20
18
  to: Item | null;
21
19
  event: ListenerEvent<Item>;
22
- /**
23
- * Rows in store form (as written to the DB) for change broadcasting:
24
- * state before the write and after. Captured for modify/mutate always
25
- * (existing is read for the merge anyway); for set/delete only when
26
- * `options.captureRows` — avoids extra PK lookups on event tables.
27
- */
28
- oldRow: Item | null;
29
- newRow: Item | null;
30
20
  }>;
31
21
  applyChange(change: StoreStateChange<Item>): Promise<{
32
22
  from: Item | null;