@rxferrix/client 0.0.0-stage → 0.1.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.
Files changed (97) hide show
  1. package/dist/api.d.ts +60 -0
  2. package/dist/api.d.ts.map +1 -0
  3. package/dist/api.js +22 -0
  4. package/dist/api.js.map +1 -0
  5. package/dist/auth.d.ts +251 -0
  6. package/dist/auth.d.ts.map +1 -0
  7. package/dist/auth.js +531 -0
  8. package/dist/auth.js.map +1 -0
  9. package/dist/bytes.d.ts +21 -0
  10. package/dist/bytes.d.ts.map +1 -0
  11. package/dist/bytes.js +51 -0
  12. package/dist/bytes.js.map +1 -0
  13. package/dist/canonical.d.ts +13 -0
  14. package/dist/canonical.d.ts.map +1 -0
  15. package/dist/canonical.js +66 -0
  16. package/dist/canonical.js.map +1 -0
  17. package/dist/client.d.ts +170 -0
  18. package/dist/client.d.ts.map +1 -0
  19. package/dist/client.js +638 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/diff.d.ts +20 -0
  22. package/dist/diff.d.ts.map +1 -0
  23. package/dist/diff.js +100 -0
  24. package/dist/diff.js.map +1 -0
  25. package/dist/errors.d.ts +24 -0
  26. package/dist/errors.d.ts.map +1 -0
  27. package/dist/errors.js +34 -0
  28. package/dist/errors.js.map +1 -0
  29. package/dist/index.d.ts +14 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +12 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/local_query_set.d.ts +56 -0
  34. package/dist/local_query_set.d.ts.map +1 -0
  35. package/dist/local_query_set.js +108 -0
  36. package/dist/local_query_set.js.map +1 -0
  37. package/dist/logging.d.ts +15 -0
  38. package/dist/logging.d.ts.map +1 -0
  39. package/dist/logging.js +17 -0
  40. package/dist/logging.js.map +1 -0
  41. package/dist/optimistic_updates.d.ts +48 -0
  42. package/dist/optimistic_updates.d.ts.map +1 -0
  43. package/dist/optimistic_updates.js +113 -0
  44. package/dist/optimistic_updates.js.map +1 -0
  45. package/dist/paginated_query.d.ts +118 -0
  46. package/dist/paginated_query.d.ts.map +1 -0
  47. package/dist/paginated_query.js +199 -0
  48. package/dist/paginated_query.js.map +1 -0
  49. package/dist/protocol.d.ts +136 -0
  50. package/dist/protocol.d.ts.map +1 -0
  51. package/dist/protocol.js +11 -0
  52. package/dist/protocol.js.map +1 -0
  53. package/dist/query_state.d.ts +16 -0
  54. package/dist/query_state.d.ts.map +1 -0
  55. package/dist/query_state.js +2 -0
  56. package/dist/query_state.js.map +1 -0
  57. package/dist/remote_query_set.d.ts +37 -0
  58. package/dist/remote_query_set.d.ts.map +1 -0
  59. package/dist/remote_query_set.js +87 -0
  60. package/dist/remote_query_set.js.map +1 -0
  61. package/dist/request_manager.d.ts +57 -0
  62. package/dist/request_manager.d.ts.map +1 -0
  63. package/dist/request_manager.js +163 -0
  64. package/dist/request_manager.js.map +1 -0
  65. package/dist/storage.d.ts +45 -0
  66. package/dist/storage.d.ts.map +1 -0
  67. package/dist/storage.js +120 -0
  68. package/dist/storage.js.map +1 -0
  69. package/dist/testing.d.ts +68 -0
  70. package/dist/testing.d.ts.map +1 -0
  71. package/dist/testing.js +97 -0
  72. package/dist/testing.js.map +1 -0
  73. package/dist/web_socket_manager.d.ts +88 -0
  74. package/dist/web_socket_manager.d.ts.map +1 -0
  75. package/dist/web_socket_manager.js +291 -0
  76. package/dist/web_socket_manager.js.map +1 -0
  77. package/package.json +50 -4
  78. package/src/api.ts +86 -0
  79. package/src/auth.ts +636 -0
  80. package/src/bytes.ts +57 -0
  81. package/src/canonical.ts +61 -0
  82. package/src/client.ts +740 -0
  83. package/src/diff.ts +87 -0
  84. package/src/errors.ts +36 -0
  85. package/src/index.ts +60 -0
  86. package/src/local_query_set.ts +130 -0
  87. package/src/logging.ts +26 -0
  88. package/src/optimistic_updates.ts +137 -0
  89. package/src/paginated_query.ts +299 -0
  90. package/src/protocol.ts +152 -0
  91. package/src/query_state.ts +12 -0
  92. package/src/remote_query_set.ts +105 -0
  93. package/src/request_manager.ts +199 -0
  94. package/src/storage.ts +171 -0
  95. package/src/testing.ts +120 -0
  96. package/src/web_socket_manager.ts +322 -0
  97. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimistic_updates.js","sourceRoot":"","sources":["../src/optimistic_updates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Reactive pagination on top of {@link RxFerrixClient.watchQuery}.
3
+ *
4
+ * A paginated query is a server query that takes `paginationOpts: PaginationOpts` and returns a
5
+ * `PaginationResult<Item>` (in Rust: `Query::paginate`). The client subscribes to it once per loaded page:
6
+ *
7
+ * - Page 0 is `{ ...args, paginationOpts: { numItems: initialNumItems, cursor: null } }`.
8
+ * - `loadMore(n)` subscribes to the next page, starting at the last page's `continueCursor`.
9
+ * - When a page gets a successor, it is re-subscribed with `endCursor` pinned to the cursor the successor starts at.
10
+ * A pinned page covers a fixed span of the index, so inserts and deletes make it grow or shrink instead of
11
+ * shifting documents into (or out of) its neighbours: no duplicates or gaps between pages. The unpinned
12
+ * subscription stays visible until the pinned one has a result, so the swap does not flash a loading state.
13
+ *
14
+ * Only the last page is unpinned; it grows up to its `numItems` when documents are added after it.
15
+ */
16
+ import type { ArgsOf, FunctionReference, OutputOf } from "./api.js";
17
+ import type { RxFerrixClient } from "./client.js";
18
+ import type { RxFerrixError } from "./errors.js";
19
+ import type { OptimisticLocalStore } from "./optimistic_updates.js";
20
+ /** Which page to read: the `paginationOpts` argument of a paginated query (Rust `rxferrix::PaginationOpts`). */
21
+ export interface PaginationOpts {
22
+ /** How many items to return (ignored when `endCursor` is set). */
23
+ numItems: number;
24
+ /** Where the page starts: `null` for the start, otherwise a previous page's `continueCursor`. */
25
+ cursor: string | null;
26
+ /** Where the page ends. When set, the page holds every item between `cursor` and `endCursor`. */
27
+ endCursor?: string | null;
28
+ }
29
+ /** One page of results (Rust `rxferrix::PaginationResult<T>`). */
30
+ export interface PaginationResult<T> {
31
+ page: T[];
32
+ /** True when there is nothing after this page. */
33
+ isDone: boolean;
34
+ /** Where the next page starts. */
35
+ continueCursor: string;
36
+ }
37
+ /** A reference to a query whose args include `paginationOpts` and whose output is a {@link PaginationResult}. */
38
+ export type PaginatedQueryReference<Item = any> = FunctionReference<"query", {
39
+ paginationOpts: PaginationOpts;
40
+ }, PaginationResult<Item>>;
41
+ /** The item type of a paginated query. */
42
+ export type PaginatedQueryItem<Q> = OutputOf<Q> extends PaginationResult<infer Item> ? Item : never;
43
+ /** The args of a paginated query without `paginationOpts` (the client manages those). */
44
+ export type PaginatedQueryArgs<Q> = Omit<ArgsOf<Q>, "paginationOpts">;
45
+ export type PaginationStatus = "LoadingFirstPage" | "CanLoadMore" | "LoadingMore" | "Exhausted";
46
+ export interface PaginatedQueryResult<Item> {
47
+ /** The items of every loaded page, in order. */
48
+ readonly results: Item[];
49
+ readonly status: PaginationStatus;
50
+ /** True while the first page or a further page is loading (and no page failed). */
51
+ readonly isLoading: boolean;
52
+ /** The error of the first failed page, if any. A failed page counts as not loaded for `status`. */
53
+ readonly error: RxFerrixError | undefined;
54
+ /**
55
+ * Loads `numItems` more items. Does nothing (and returns false) unless the last page is loaded and not done
56
+ * (status `"CanLoadMore"`).
57
+ */
58
+ loadMore(numItems: number): boolean;
59
+ }
60
+ export interface PaginatedQueryOptions {
61
+ /** The size of the first page. */
62
+ initialNumItems: number;
63
+ }
64
+ /** A framework-agnostic paginated query. Pages are subscribed while at least one `subscribe` callback is registered. */
65
+ export interface PaginatedQuery<Item> {
66
+ /** Registers `callback` to be called whenever {@link getCurrent} changes. Returns the unsubscribe function. */
67
+ subscribe(callback: () => void): () => void;
68
+ /** The current results. The object is referentially stable until something visible changes. */
69
+ getCurrent(): PaginatedQueryResult<Item>;
70
+ }
71
+ /** @internal Created by {@link RxFerrixClient.paginatedQuery}. */
72
+ export declare class PaginatedQueryImpl<Item> implements PaginatedQuery<Item> {
73
+ private readonly client;
74
+ private readonly ref;
75
+ private readonly pages;
76
+ private readonly listeners;
77
+ private readonly args;
78
+ private snapshot;
79
+ /** The page states `snapshot` was built from. */
80
+ private snapshotStates;
81
+ constructor(client: RxFerrixClient, ref: FunctionReference<"query">, args: Record<string, unknown>, options: PaginatedQueryOptions);
82
+ subscribe(callback: () => void): () => void;
83
+ getCurrent(): PaginatedQueryResult<Item>;
84
+ private loadMore;
85
+ /** The state a page shows: its pinned replacement once that has a result, otherwise the current subscription. */
86
+ private displayed;
87
+ private makeSub;
88
+ private activate;
89
+ private deactivate;
90
+ private onPageUpdate;
91
+ private notify;
92
+ }
93
+ /**
94
+ * Every loaded page of a paginated query in the optimistic store, with its args (including `paginationOpts`).
95
+ * Pass `argsToMatch` (args without `paginationOpts`, or a subset of them) to keep only one paginated query's pages.
96
+ */
97
+ export declare function getAllPages<Q extends PaginatedQueryReference>(localStore: OptimisticLocalStore, ref: Q, argsToMatch?: Partial<PaginatedQueryArgs<Q>>): {
98
+ args: ArgsOf<Q>;
99
+ value: PaginationResult<PaginatedQueryItem<Q>>;
100
+ }[];
101
+ /**
102
+ * Optimistically inserts `item` at the top of the first page of a paginated query (every paginated query of `ref`
103
+ * whose args match `argsToMatch`). Typical for "newest first" lists:
104
+ *
105
+ * ```ts
106
+ * const send = useMutation(api.messages.send).withOptimisticUpdate((store, args) => {
107
+ * insertAtTop({ paginatedQuery: api.messages.list, argsToMatch: { channel: args.channel }, localQueryStore: store,
108
+ * item: { _id: "optimistic" as Id<"messages">, _creationTime: Date.now(), ...args } });
109
+ * });
110
+ * ```
111
+ */
112
+ export declare function insertAtTop<Q extends PaginatedQueryReference>(options: {
113
+ paginatedQuery: Q;
114
+ argsToMatch?: Partial<PaginatedQueryArgs<Q>>;
115
+ localQueryStore: OptimisticLocalStore;
116
+ item: PaginatedQueryItem<Q>;
117
+ }): void;
118
+ //# sourceMappingURL=paginated_query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginated_query.d.ts","sourceRoot":"","sources":["../src/paginated_query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,199 @@
1
+ import { jsonEqual, normalizeArgs } from "./canonical.js";
2
+ function validateNumItems(numItems, what) {
3
+ if (!Number.isInteger(numItems) || numItems < 1) {
4
+ throw new Error(`${what} must be a positive integer, got ${numItems}`);
5
+ }
6
+ }
7
+ /** @internal Created by {@link RxFerrixClient.paginatedQuery}. */
8
+ export class PaginatedQueryImpl {
9
+ client;
10
+ ref;
11
+ pages = [];
12
+ listeners = new Set();
13
+ args;
14
+ snapshot = null;
15
+ /** The page states `snapshot` was built from. */
16
+ snapshotStates = [];
17
+ constructor(client, ref, args, options) {
18
+ this.client = client;
19
+ this.ref = ref;
20
+ validateNumItems(options?.initialNumItems, "initialNumItems");
21
+ const { paginationOpts: _ignored, ...rest } = normalizeArgs(args);
22
+ this.args = rest;
23
+ this.pages.push({ current: this.makeSub({ numItems: options.initialNumItems, cursor: null }), pending: null });
24
+ }
25
+ subscribe(callback) {
26
+ const entry = () => callback();
27
+ this.listeners.add(entry);
28
+ if (this.listeners.size === 1) {
29
+ for (const page of this.pages) {
30
+ this.activate(page.current);
31
+ if (page.pending)
32
+ this.activate(page.pending);
33
+ }
34
+ }
35
+ let active = true;
36
+ return () => {
37
+ if (!active)
38
+ return;
39
+ active = false;
40
+ this.listeners.delete(entry);
41
+ if (this.listeners.size === 0) {
42
+ for (const page of this.pages) {
43
+ this.deactivate(page.current);
44
+ if (page.pending)
45
+ this.deactivate(page.pending);
46
+ }
47
+ }
48
+ };
49
+ }
50
+ getCurrent() {
51
+ const states = this.pages.map((p) => this.displayed(p));
52
+ if (this.snapshot && states.length === this.snapshotStates.length && states.every((s, i) => s === this.snapshotStates[i])) {
53
+ return this.snapshot;
54
+ }
55
+ let results = [];
56
+ let loading = false;
57
+ let error;
58
+ for (const state of states) {
59
+ if (state.status === "success")
60
+ results = results.concat(state.value.page);
61
+ else if (state.status === "loading")
62
+ loading = true;
63
+ else
64
+ error ??= state.error;
65
+ }
66
+ const last = states[states.length - 1];
67
+ let status;
68
+ if (loading || error !== undefined) {
69
+ status = results.length === 0 && states[0]?.status !== "success" ? "LoadingFirstPage" : "LoadingMore";
70
+ }
71
+ else if (last?.status === "success" && last.value.isDone) {
72
+ status = "Exhausted";
73
+ }
74
+ else {
75
+ status = "CanLoadMore";
76
+ }
77
+ this.snapshotStates = states;
78
+ const previous = this.snapshot;
79
+ // E.g. a page swapped for its pinned copy: new state objects, same items. Keep the snapshot (no re-render).
80
+ if (previous && previous.status === status && previous.error === error && jsonEqual(previous.results, results)) {
81
+ return previous;
82
+ }
83
+ this.snapshot = {
84
+ results,
85
+ status,
86
+ isLoading: error === undefined && (status === "LoadingFirstPage" || status === "LoadingMore"),
87
+ error,
88
+ loadMore: (numItems) => this.loadMore(numItems),
89
+ };
90
+ return this.snapshot;
91
+ }
92
+ loadMore(numItems) {
93
+ validateNumItems(numItems, "loadMore(numItems)");
94
+ const last = this.pages[this.pages.length - 1];
95
+ if (!last)
96
+ return false;
97
+ const state = this.displayed(last);
98
+ if (state.status !== "success" || state.value.isDone)
99
+ return false;
100
+ const cursor = state.value.continueCursor;
101
+ // Pin the page to where its successor starts (it covers the same span, so it shows the same items).
102
+ const shown = last.pending && last.pending.watch.localQueryState().status !== "loading" ? last.pending : last.current;
103
+ if (shown.opts.endCursor == null) {
104
+ if (last.pending)
105
+ this.deactivate(last.pending);
106
+ last.pending = this.makeSub({ ...shown.opts, endCursor: cursor });
107
+ if (this.listeners.size > 0)
108
+ this.activate(last.pending);
109
+ }
110
+ const next = { current: this.makeSub({ numItems, cursor }), pending: null };
111
+ this.pages.push(next);
112
+ if (this.listeners.size > 0)
113
+ this.activate(next.current);
114
+ this.notify();
115
+ return true;
116
+ }
117
+ /** The state a page shows: its pinned replacement once that has a result, otherwise the current subscription. */
118
+ displayed(page) {
119
+ if (page.pending) {
120
+ const pending = page.pending.watch.localQueryState();
121
+ if (pending.status !== "loading")
122
+ return pending;
123
+ }
124
+ return page.current.watch.localQueryState();
125
+ }
126
+ makeSub(opts) {
127
+ const args = { ...this.args, paginationOpts: opts };
128
+ const watch = this.client.watchQuery(this.ref, args);
129
+ return { opts, watch, unsubscribe: null };
130
+ }
131
+ activate(sub) {
132
+ if (!sub.unsubscribe)
133
+ sub.unsubscribe = sub.watch.onUpdate(() => this.onPageUpdate());
134
+ }
135
+ deactivate(sub) {
136
+ sub.unsubscribe?.();
137
+ sub.unsubscribe = null;
138
+ }
139
+ onPageUpdate() {
140
+ // Complete the swaps whose pinned page has a result. Done here (not in getCurrent) to keep reads side-effect free.
141
+ for (const page of this.pages) {
142
+ if (page.pending && page.pending.watch.localQueryState().status !== "loading") {
143
+ this.deactivate(page.current);
144
+ page.current = page.pending;
145
+ page.pending = null;
146
+ }
147
+ }
148
+ this.notify();
149
+ }
150
+ notify() {
151
+ const before = this.snapshot;
152
+ if (this.getCurrent() === before)
153
+ return;
154
+ for (const listener of [...this.listeners])
155
+ listener();
156
+ }
157
+ }
158
+ // ---------------------------------------------------------------------------------------------------------------------
159
+ // Optimistic update helpers
160
+ /** Does every key of `argsToMatch` equal the corresponding arg of a page? */
161
+ function argsMatch(args, argsToMatch) {
162
+ if (!argsToMatch)
163
+ return true;
164
+ return Object.entries(argsToMatch).every(([k, v]) => v === undefined || jsonEqual(args[k], v));
165
+ }
166
+ /**
167
+ * Every loaded page of a paginated query in the optimistic store, with its args (including `paginationOpts`).
168
+ * Pass `argsToMatch` (args without `paginationOpts`, or a subset of them) to keep only one paginated query's pages.
169
+ */
170
+ export function getAllPages(localStore, ref, argsToMatch) {
171
+ const out = [];
172
+ for (const { args, value } of localStore.getAllQueries(ref)) {
173
+ if (value === undefined || !argsMatch(args, argsToMatch))
174
+ continue;
175
+ out.push({ args, value: value });
176
+ }
177
+ return out;
178
+ }
179
+ /**
180
+ * Optimistically inserts `item` at the top of the first page of a paginated query (every paginated query of `ref`
181
+ * whose args match `argsToMatch`). Typical for "newest first" lists:
182
+ *
183
+ * ```ts
184
+ * const send = useMutation(api.messages.send).withOptimisticUpdate((store, args) => {
185
+ * insertAtTop({ paginatedQuery: api.messages.list, argsToMatch: { channel: args.channel }, localQueryStore: store,
186
+ * item: { _id: "optimistic" as Id<"messages">, _creationTime: Date.now(), ...args } });
187
+ * });
188
+ * ```
189
+ */
190
+ export function insertAtTop(options) {
191
+ const { paginatedQuery, argsToMatch, localQueryStore, item } = options;
192
+ for (const { args, value } of getAllPages(localQueryStore, paginatedQuery, argsToMatch)) {
193
+ const opts = args.paginationOpts;
194
+ if (opts?.cursor !== null)
195
+ continue;
196
+ localQueryStore.setQuery(paginatedQuery, args, { ...value, page: [item, ...value.page] });
197
+ }
198
+ }
199
+ //# sourceMappingURL=paginated_query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginated_query.js","sourceRoot":"","sources":["../src/paginated_query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Wire types for the RxFerrix sync protocol (v1). See `docs/PROTOCOL.md` in the repository; that document is normative.
3
+ */
4
+ export type QueryId = number;
5
+ export type RequestId = number;
6
+ export type JSONValue = null | boolean | number | string | JSONValue[] | {
7
+ [key: string]: JSONValue;
8
+ };
9
+ export declare const CLIENT_VERSION = "0.1.0";
10
+ export interface StateVersion {
11
+ querySet: number;
12
+ identity: number;
13
+ ts: number;
14
+ }
15
+ /** `{ code, data }` attached to user errors. */
16
+ export interface ErrorData {
17
+ code: string;
18
+ data?: unknown;
19
+ }
20
+ export interface ConnectMessage {
21
+ type: "Connect";
22
+ sessionId: string;
23
+ connectionCount: number;
24
+ lastCloseReason: string | null;
25
+ clientVersion: string;
26
+ /** Optional protocol features this client supports: `"diffs"` (results may arrive as diffs, see `diff.ts`). */
27
+ features?: string[];
28
+ }
29
+ export type QuerySetModification = {
30
+ type: "Add";
31
+ queryId: QueryId;
32
+ udfPath: string;
33
+ args: Record<string, unknown>;
34
+ } | {
35
+ type: "Remove";
36
+ queryId: QueryId;
37
+ };
38
+ export interface ModifyQuerySetMessage {
39
+ type: "ModifyQuerySet";
40
+ baseVersion: number;
41
+ newVersion: number;
42
+ modifications: QuerySetModification[];
43
+ }
44
+ export interface MutationMessage {
45
+ type: "Mutation";
46
+ requestId: RequestId;
47
+ udfPath: string;
48
+ args: Record<string, unknown>;
49
+ }
50
+ export interface ActionMessage {
51
+ type: "Action";
52
+ requestId: RequestId;
53
+ udfPath: string;
54
+ args: Record<string, unknown>;
55
+ }
56
+ export interface AuthenticateMessage {
57
+ type: "Authenticate";
58
+ baseVersion: number;
59
+ token: string | null;
60
+ }
61
+ export interface PongMessage {
62
+ type: "Pong";
63
+ }
64
+ export type ClientMessage = ConnectMessage | ModifyQuerySetMessage | MutationMessage | ActionMessage | AuthenticateMessage | PongMessage;
65
+ export type StateModification = {
66
+ type: "QueryUpdated";
67
+ queryId: QueryId;
68
+ value: unknown;
69
+ logLines?: string[];
70
+ }
71
+ /** The new result as a diff from the result this connection last received for the query (`diff.ts`). */
72
+ | {
73
+ type: "QueryUpdated";
74
+ queryId: QueryId;
75
+ diff: unknown;
76
+ logLines?: string[];
77
+ } | {
78
+ type: "QueryFailed";
79
+ queryId: QueryId;
80
+ errorMessage: string;
81
+ errorData?: ErrorData | null;
82
+ logLines?: string[];
83
+ } | {
84
+ type: "QueryRemoved";
85
+ queryId: QueryId;
86
+ };
87
+ export interface TransitionMessage {
88
+ type: "Transition";
89
+ startVersion: StateVersion;
90
+ endVersion: StateVersion;
91
+ modifications: StateModification[];
92
+ }
93
+ export type MutationResponseMessage = {
94
+ type: "MutationResponse";
95
+ requestId: RequestId;
96
+ success: true;
97
+ result: unknown;
98
+ ts: number;
99
+ logLines?: string[];
100
+ } | {
101
+ type: "MutationResponse";
102
+ requestId: RequestId;
103
+ success: false;
104
+ errorMessage: string;
105
+ errorData?: ErrorData | null;
106
+ logLines?: string[];
107
+ };
108
+ export type ActionResponseMessage = {
109
+ type: "ActionResponse";
110
+ requestId: RequestId;
111
+ success: true;
112
+ result: unknown;
113
+ logLines?: string[];
114
+ } | {
115
+ type: "ActionResponse";
116
+ requestId: RequestId;
117
+ success: false;
118
+ errorMessage: string;
119
+ errorData?: ErrorData | null;
120
+ logLines?: string[];
121
+ };
122
+ export interface FatalErrorMessage {
123
+ type: "FatalError";
124
+ error: string;
125
+ }
126
+ export interface AuthErrorMessage {
127
+ type: "AuthError";
128
+ error: string;
129
+ }
130
+ export interface PingMessage {
131
+ type: "Ping";
132
+ }
133
+ export type ServerMessage = TransitionMessage | MutationResponseMessage | ActionResponseMessage | FatalErrorMessage | AuthErrorMessage | PingMessage;
134
+ export declare function versionsEqual(a: StateVersion, b: StateVersion): boolean;
135
+ export declare function formatVersion(v: StateVersion): string;
136
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAC7B,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAC/B,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtG,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,gDAAgD;AAChD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAKD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,+GAA+G;IAC/G,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACjF;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEzC,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,oBAAoB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,aAAa,GACrB,cAAc,GACd,qBAAqB,GACrB,eAAe,GACf,aAAa,GACb,mBAAmB,GACnB,WAAW,CAAC;AAKhB,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;AACjF,wGAAwG;GACtG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC9E;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,GACD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,YAAY,CAAC;IACzB,aAAa,EAAE,iBAAiB,EAAE,CAAC;CACpC;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACnH;IACE,IAAI,EAAE,kBAAkB,CAAC;IACzB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEN,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACrG;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEN,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,aAAa,GACrB,iBAAiB,GACjB,uBAAuB,GACvB,qBAAqB,GACrB,iBAAiB,GACjB,gBAAgB,GAChB,WAAW,CAAC;AAEhB,wBAAgB,aAAa,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CAEvE;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAErD"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Wire types for the RxFerrix sync protocol (v1). See `docs/PROTOCOL.md` in the repository; that document is normative.
3
+ */
4
+ export const CLIENT_VERSION = "0.1.0";
5
+ export function versionsEqual(a, b) {
6
+ return a.querySet === b.querySet && a.identity === b.identity && a.ts === b.ts;
7
+ }
8
+ export function formatVersion(v) {
9
+ return `{querySet:${v.querySet},identity:${v.identity},ts:${v.ts}}`;
10
+ }
11
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAyItC,MAAM,UAAU,aAAa,CAAC,CAAe,EAAE,CAAe;IAC5D,OAAO,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAe;IAC3C,OAAO,aAAa,CAAC,CAAC,QAAQ,aAAa,CAAC,CAAC,QAAQ,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC;AACtE,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { RxFerrixError } from "./errors.js";
2
+ /**
3
+ * The local state of a query. Objects are reused while the visible value does not change, so they can be compared
4
+ * by reference (e.g. as a `useSyncExternalStore` snapshot).
5
+ */
6
+ export type QueryState<T = unknown> = {
7
+ readonly status: "loading";
8
+ } | {
9
+ readonly status: "success";
10
+ readonly value: T;
11
+ } | {
12
+ readonly status: "error";
13
+ readonly error: RxFerrixError;
14
+ };
15
+ export declare const LOADING: QueryState<never>;
16
+ //# sourceMappingURL=query_state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query_state.d.ts","sourceRoot":"","sources":["../src/query_state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,GAAG,OAAO,IAC9B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC;AAEhE,eAAO,MAAM,OAAO,EAAE,UAAU,CAAC,KAAK,CAAiD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const LOADING = Object.freeze({ status: "loading" });
2
+ //# sourceMappingURL=query_state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query_state.js","sourceRoot":"","sources":["../src/query_state.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,OAAO,GAAsB,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAkB,EAAE,CAAC,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { type QueryId, type StateVersion, type TransitionMessage } from "./protocol.js";
2
+ import type { QueryState } from "./query_state.js";
3
+ export declare class TransitionVersionMismatch extends Error {
4
+ constructor(expected: StateVersion, got: StateVersion);
5
+ }
6
+ export interface TransitionResult {
7
+ /** Queries whose server result changed (updated, failed or removed). */
8
+ changed: QueryId[];
9
+ logLines: {
10
+ queryId: QueryId;
11
+ lines: string[];
12
+ }[];
13
+ }
14
+ /**
15
+ * The server's view of the world for the current socket: the StateVersion and the latest result for every query.
16
+ * Transitions are validated (`startVersion` must equal the current version) and then applied atomically.
17
+ */
18
+ export declare class RemoteQuerySet {
19
+ private _version;
20
+ private readonly results;
21
+ get version(): StateVersion;
22
+ result(queryId: QueryId): QueryState | undefined;
23
+ /**
24
+ * Applies a transition. Modifications for queries that `isKnown` rejects (removed locally while the transition was
25
+ * in flight) are ignored. Throws {@link TransitionVersionMismatch} without changing anything when the transition
26
+ * does not start at the current version, and {@link DiffMismatch} when a result diff doesn't fit the result held.
27
+ */
28
+ transition(message: TransitionMessage, isKnown: (queryId: QueryId) => boolean): TransitionResult;
29
+ /** Forgets a query's result (it was removed from the local query set). */
30
+ remove(queryId: QueryId): void;
31
+ /**
32
+ * A new socket starts from a fresh server state (all versions 0). Results are kept so the UI keeps showing the
33
+ * last known data until the re-subscribed queries report again.
34
+ */
35
+ resetVersion(): void;
36
+ }
37
+ //# sourceMappingURL=remote_query_set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote_query_set.d.ts","sourceRoot":"","sources":["../src/remote_query_set.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,OAAO,EAEZ,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY;CAGtD;AAED,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,QAAQ,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;CACnD;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAqD;IACrE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAE1D,IAAI,OAAO,IAAI,YAAY,CAE1B;IAED,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS;IAIhD;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAG,gBAAgB;IA+ChG,0EAA0E;IAC1E,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI9B;;;OAGG;IACH,YAAY,IAAI,IAAI;CAGrB"}