@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
package/dist/diff.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Result diffs (docs/PROTOCOL.md, "Result diffs"): the server sends what changed in a query result instead of the
3
+ * whole result, relative to the result this client already has. The format, applied to the previous result:
4
+ *
5
+ * - `{"$r": value}`: replace with `value`.
6
+ * - `{"$a": [op, …]}`: edit an array. The ops walk the old array from the start: a positive integer `n` keeps the next
7
+ * `n` elements, a negative integer `-n` deletes them, an array inserts its elements, and `{"$p": diff}` patches the
8
+ * next element. Elements after the last op are kept.
9
+ * - `{"$o": {"s": {…}, "d": […], "p": {…}}}`: edit an object: set, delete and patch keys.
10
+ *
11
+ * Unchanged elements and objects are reused, not copied, so React and Svelte can skip re-rendering them.
12
+ */
13
+ /** A diff didn't fit the result it was applied to: the client's copy is not what the server diffed against. */
14
+ export declare class DiffMismatch extends Error {
15
+ constructor(message: string);
16
+ }
17
+ type Json = unknown;
18
+ export declare function applyDiff(old: Json, diff: Json): Json;
19
+ export {};
20
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+GAA+G;AAC/G,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAG5B;AAED,KAAK,IAAI,GAAG,OAAO,CAAC;AAYpB,wBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAsDrD"}
package/dist/diff.js ADDED
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Result diffs (docs/PROTOCOL.md, "Result diffs"): the server sends what changed in a query result instead of the
3
+ * whole result, relative to the result this client already has. The format, applied to the previous result:
4
+ *
5
+ * - `{"$r": value}`: replace with `value`.
6
+ * - `{"$a": [op, …]}`: edit an array. The ops walk the old array from the start: a positive integer `n` keeps the next
7
+ * `n` elements, a negative integer `-n` deletes them, an array inserts its elements, and `{"$p": diff}` patches the
8
+ * next element. Elements after the last op are kept.
9
+ * - `{"$o": {"s": {…}, "d": […], "p": {…}}}`: edit an object: set, delete and patch keys.
10
+ *
11
+ * Unchanged elements and objects are reused, not copied, so React and Svelte can skip re-rendering them.
12
+ */
13
+ /** A diff didn't fit the result it was applied to: the client's copy is not what the server diffed against. */
14
+ export class DiffMismatch extends Error {
15
+ constructor(message) {
16
+ super(`result diff doesn't apply: ${message}`);
17
+ }
18
+ }
19
+ function isObject(v) {
20
+ return typeof v === "object" && v !== null && !Array.isArray(v);
21
+ }
22
+ /** Sets `key` as a plain own property: `out[key] = value` would set the prototype for `"__proto__"` (a key data can
23
+ * have, e.g. in a map keyed by user input). */
24
+ function setOwn(out, key, value) {
25
+ Object.defineProperty(out, key, { value, enumerable: true, writable: true, configurable: true });
26
+ }
27
+ export function applyDiff(old, diff) {
28
+ if (!isObject(diff))
29
+ throw new DiffMismatch("a diff must be an object");
30
+ if ("$r" in diff)
31
+ return diff.$r;
32
+ if ("$a" in diff) {
33
+ const ops = diff.$a;
34
+ if (!Array.isArray(old) || !Array.isArray(ops))
35
+ throw new DiffMismatch("array diff applied to a non-array");
36
+ const out = [];
37
+ let i = 0;
38
+ for (const op of ops) {
39
+ if (typeof op === "number") {
40
+ const count = Math.abs(op);
41
+ if (op === 0 || !Number.isInteger(op) || i + count > old.length) {
42
+ throw new DiffMismatch(`op ${op} at ${i} runs past ${old.length} elements`);
43
+ }
44
+ if (op > 0)
45
+ for (let k = i; k < i + count; k++)
46
+ out.push(old[k]);
47
+ i += count;
48
+ }
49
+ else if (Array.isArray(op)) {
50
+ for (const item of op)
51
+ out.push(item);
52
+ }
53
+ else if (isObject(op) && "$p" in op) {
54
+ if (i >= old.length)
55
+ throw new DiffMismatch("patch past the end");
56
+ out.push(applyDiff(old[i], op.$p));
57
+ i += 1;
58
+ }
59
+ else {
60
+ throw new DiffMismatch(`bad array op ${JSON.stringify(op)}`);
61
+ }
62
+ }
63
+ for (let k = i; k < old.length; k++)
64
+ out.push(old[k]);
65
+ return out;
66
+ }
67
+ if ("$o" in diff) {
68
+ const o = diff.$o;
69
+ if (!isObject(old) || !isObject(o))
70
+ throw new DiffMismatch("object diff applied to a non-object");
71
+ const out = { ...old };
72
+ if (o.d !== undefined) {
73
+ if (!Array.isArray(o.d))
74
+ throw new DiffMismatch("bad deleted keys");
75
+ for (const key of o.d) {
76
+ if (typeof key !== "string" || !Object.hasOwn(out, key))
77
+ throw new DiffMismatch(`deleting missing key ${String(key)}`);
78
+ delete out[key];
79
+ }
80
+ }
81
+ if (o.s !== undefined) {
82
+ if (!isObject(o.s))
83
+ throw new DiffMismatch("bad set keys");
84
+ for (const [key, value] of Object.entries(o.s))
85
+ setOwn(out, key, value);
86
+ }
87
+ if (o.p !== undefined) {
88
+ if (!isObject(o.p))
89
+ throw new DiffMismatch("bad patched keys");
90
+ for (const [key, sub] of Object.entries(o.p)) {
91
+ if (!Object.hasOwn(old, key))
92
+ throw new DiffMismatch(`patching missing key ${key}`);
93
+ setOwn(out, key, applyDiff(old[key], sub));
94
+ }
95
+ }
96
+ return out;
97
+ }
98
+ throw new DiffMismatch(`unknown diff ${JSON.stringify(diff)}`);
99
+ }
100
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { ErrorData } from "./protocol.js";
2
+ /**
3
+ * An error raised by a RxFerrix function or by the client itself.
4
+ *
5
+ * For a server `UserError`, `code` and `data` carry the error's `errorData` (`{ code, data }`). For any other server
6
+ * error, `code` and `data` are undefined and `message` is the server's `errorMessage` (`"Server Error"` outside
7
+ * `--dev`).
8
+ */
9
+ export declare class RxFerrixError extends Error {
10
+ name: string;
11
+ readonly code?: string;
12
+ readonly data?: unknown;
13
+ constructor(message: string, options?: {
14
+ code?: string;
15
+ data?: unknown;
16
+ cause?: unknown;
17
+ });
18
+ /** Builds an error from a server failure payload (`errorMessage` + optional `errorData`). */
19
+ static fromServer(errorMessage: string | undefined, errorData: ErrorData | null | undefined): RxFerrixError;
20
+ }
21
+ /** Code used for client-side failures (lost connection, client closed). */
22
+ export declare const CONNECTION_LOST = "ConnectionLost";
23
+ export declare const CLIENT_CLOSED = "ClientClosed";
24
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAC7B,IAAI,SAAmB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;gBAEZ,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;IAMzF,6FAA6F;IAC7F,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,aAAa;CAU5G;AAED,2EAA2E;AAC3E,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAChD,eAAO,MAAM,aAAa,iBAAiB,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * An error raised by a RxFerrix function or by the client itself.
3
+ *
4
+ * For a server `UserError`, `code` and `data` carry the error's `errorData` (`{ code, data }`). For any other server
5
+ * error, `code` and `data` are undefined and `message` is the server's `errorMessage` (`"Server Error"` outside
6
+ * `--dev`).
7
+ */
8
+ export class RxFerrixError extends Error {
9
+ name = "RxFerrixError";
10
+ code;
11
+ data;
12
+ constructor(message, options) {
13
+ super(message, options?.cause !== undefined ? { cause: options.cause } : undefined);
14
+ if (options?.code !== undefined)
15
+ this.code = options.code;
16
+ if (options?.data !== undefined)
17
+ this.data = options.data;
18
+ }
19
+ /** Builds an error from a server failure payload (`errorMessage` + optional `errorData`). */
20
+ static fromServer(errorMessage, errorData) {
21
+ const message = typeof errorMessage === "string" && errorMessage.length > 0 ? errorMessage : "Server Error";
22
+ if (errorData && typeof errorData === "object") {
23
+ return new RxFerrixError(message, {
24
+ code: typeof errorData.code === "string" ? errorData.code : undefined,
25
+ data: errorData.data,
26
+ });
27
+ }
28
+ return new RxFerrixError(message);
29
+ }
30
+ }
31
+ /** Code used for client-side failures (lost connection, client closed). */
32
+ export const CONNECTION_LOST = "ConnectionLost";
33
+ export const CLIENT_CLOSED = "ClientClosed";
34
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,GAAG,eAAe,CAAC;IACvB,IAAI,CAAU;IACd,IAAI,CAAW;IAExB,YAAY,OAAe,EAAE,OAA4D;QACvF,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACpF,IAAI,OAAO,EAAE,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAC1D,IAAI,OAAO,EAAE,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5D,CAAC;IAED,6FAA6F;IAC7F,MAAM,CAAC,UAAU,CAAC,YAAgC,EAAE,SAAuC;QACzF,MAAM,OAAO,GAAG,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC;QAC5G,IAAI,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC/C,OAAO,IAAI,aAAa,CAAC,OAAO,EAAE;gBAChC,IAAI,EAAE,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;gBACrE,IAAI,EAAE,SAAS,CAAC,IAAI;aACrB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;CACF;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAChD,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAC"}
@@ -0,0 +1,14 @@
1
+ export { makeFunctionReference, getFunctionName, type FunctionKind, type FunctionReference, type AnyQueryReference, type AnyMutationReference, type AnyActionReference, type ArgsOf, type OutputOf, type OptionalArgs, type OptionalArgsOrSkip, type ArgsAndOptions, type HasNoRequiredArgs, type Id, } from "./api.js";
2
+ export { RxFerrixClient, type RxFerrixClientOptions, type MutationOptions, type AuthTokenFetcher, type ConnectionState, type QueryWatch, } from "./client.js";
3
+ export { RxFerrixError, CONNECTION_LOST, CLIENT_CLOSED } from "./errors.js";
4
+ export { applyDiff, DiffMismatch } from "./diff.js";
5
+ export { RxFerrixAuth, getAuth, systemApi, MemoryAuthStorage, type AuthStorage, type AuthState, type AuthTokens, type AuthProviders, type CodeProof, type RxFerrixAuthOptions, type RedirectResult, type User, } from "./auth.js";
6
+ export type { OptimisticLocalStore, OptimisticUpdate } from "./optimistic_updates.js";
7
+ export { insertAtTop, getAllPages, type PaginationOpts, type PaginationResult, type PaginationStatus, type PaginatedQuery, type PaginatedQueryResult, type PaginatedQueryOptions, type PaginatedQueryReference, type PaginatedQueryItem, type PaginatedQueryArgs, } from "./paginated_query.js";
8
+ export { LOADING, type QueryState } from "./query_state.js";
9
+ export { uploadFile, type UploadFileOptions, type UploadProgress } from "./storage.js";
10
+ export { bytesToJson, bytesFromJson, isBytes, type Bytes } from "./bytes.js";
11
+ export { canonicalJSON, queryToken, jsonEqual, type QueryToken } from "./canonical.js";
12
+ export { CLIENT_VERSION, type StateVersion, type ClientMessage, type ServerMessage, type ErrorData } from "./protocol.js";
13
+ export type * as protocol from "./protocol.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,EAAE,GACR,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EACL,YAAY,EACZ,OAAO,EACP,SAAS,EACT,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,IAAI,GACV,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACtF,OAAO,EACL,WAAW,EACX,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1H,YAAY,KAAK,QAAQ,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export { makeFunctionReference, getFunctionName, } from "./api.js";
2
+ export { RxFerrixClient, } from "./client.js";
3
+ export { RxFerrixError, CONNECTION_LOST, CLIENT_CLOSED } from "./errors.js";
4
+ export { applyDiff, DiffMismatch } from "./diff.js";
5
+ export { RxFerrixAuth, getAuth, systemApi, MemoryAuthStorage, } from "./auth.js";
6
+ export { insertAtTop, getAllPages, } from "./paginated_query.js";
7
+ export { LOADING } from "./query_state.js";
8
+ export { uploadFile } from "./storage.js";
9
+ export { bytesToJson, bytesFromJson, isBytes } from "./bytes.js";
10
+ export { canonicalJSON, queryToken, jsonEqual } from "./canonical.js";
11
+ export { CLIENT_VERSION } from "./protocol.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,eAAe,GAahB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,cAAc,GAMf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EACL,YAAY,EACZ,OAAO,EACP,SAAS,EACT,iBAAiB,GASlB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,WAAW,EACX,WAAW,GAUZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAmB,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAA+C,MAAM,cAAc,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAc,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAmB,MAAM,gBAAgB,CAAC;AACvF,OAAO,EAAE,cAAc,EAA6E,MAAM,eAAe,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { type QueryToken } from "./canonical.js";
2
+ import type { ModifyQuerySetMessage, QueryId } from "./protocol.js";
3
+ export interface LocalQuery {
4
+ readonly token: QueryToken;
5
+ readonly queryId: QueryId;
6
+ readonly udfPath: string;
7
+ readonly args: Record<string, unknown>;
8
+ refCount: number;
9
+ /** Whether an `Add` for this query is part of the server's query set on the current socket. */
10
+ onServer: boolean;
11
+ }
12
+ export interface FlushResult {
13
+ /** The message to send, or null when nothing changed (or nothing can be sent right now). */
14
+ message: ModifyQuerySetMessage | null;
15
+ /** Queries dropped locally by this flush (their last watcher left). Their results should be discarded. */
16
+ removed: QueryId[];
17
+ }
18
+ /**
19
+ * The set of queries this client wants to be subscribed to.
20
+ *
21
+ * Queries are keyed by `udfPath + canonicalJSON(args)`. Watchers of the same query share one queryId and one server
22
+ * subscription; the subscription is dropped when the last watcher leaves. Changes are not sent eagerly: they are
23
+ * diffed against what the server knows on flush, so an add and a remove of the same query in the same tick cancel
24
+ * out and several changes produce a single `ModifyQuerySet`.
25
+ */
26
+ export declare class LocalQuerySet {
27
+ private nextQueryId;
28
+ private readonly byToken;
29
+ private readonly byId;
30
+ /** Queries dropped locally whose `Remove` still has to reach the server on this socket. */
31
+ private readonly pendingRemoves;
32
+ /** The `newVersion` of the last ModifyQuerySet sent on this socket. */
33
+ private querySetVersion;
34
+ /** Adds a watcher; returns the query (created if needed) and whether a flush is needed. */
35
+ addRef(udfPath: string, args: Record<string, unknown>): {
36
+ query: LocalQuery;
37
+ needsFlush: boolean;
38
+ };
39
+ /** Removes a watcher; returns true when the query has no watchers left (a flush should be scheduled). */
40
+ removeRef(token: QueryToken): boolean;
41
+ get(token: QueryToken): LocalQuery | undefined;
42
+ getById(queryId: QueryId): LocalQuery | undefined;
43
+ /** All queries currently tracked (including ones whose last watcher left but that are not yet flushed). */
44
+ queries(): IterableIterator<LocalQuery>;
45
+ get size(): number;
46
+ /**
47
+ * Drops queries without watchers and, if `canSend`, builds the ModifyQuerySet that brings the server's query set
48
+ * in line with the local one (bumping the query set version).
49
+ */
50
+ flush(canSend: boolean): FlushResult;
51
+ /** The server state is fresh on a new socket: nothing is subscribed and the query set version is 0. */
52
+ resetForNewSocket(): void;
53
+ /** The `newVersion` of the last ModifyQuerySet sent on this socket. */
54
+ get sentQuerySetVersion(): number;
55
+ }
56
+ //# sourceMappingURL=local_query_set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local_query_set.d.ts","sourceRoot":"","sources":["../src/local_query_set.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,OAAO,EAAwB,MAAM,eAAe,CAAC;AAE1F,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,4FAA4F;IAC5F,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACtC,0GAA0G;IAC1G,OAAO,EAAE,OAAO,EAAE,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkC;IACvD,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAsB;IACrD,uEAAuE;IACvE,OAAO,CAAC,eAAe,CAAK;IAE5B,2FAA2F;IAC3F,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE;IAqBlG,yGAAyG;IACzG,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAOrC,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS;IAI9C,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS;IAIjD,2GAA2G;IAC3G,OAAO,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAIvC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW;IA8BpC,uGAAuG;IACvG,iBAAiB,IAAI,IAAI;IAMzB,uEAAuE;IACvE,IAAI,mBAAmB,IAAI,MAAM,CAEhC;CACF"}
@@ -0,0 +1,108 @@
1
+ import { queryToken } from "./canonical.js";
2
+ /**
3
+ * The set of queries this client wants to be subscribed to.
4
+ *
5
+ * Queries are keyed by `udfPath + canonicalJSON(args)`. Watchers of the same query share one queryId and one server
6
+ * subscription; the subscription is dropped when the last watcher leaves. Changes are not sent eagerly: they are
7
+ * diffed against what the server knows on flush, so an add and a remove of the same query in the same tick cancel
8
+ * out and several changes produce a single `ModifyQuerySet`.
9
+ */
10
+ export class LocalQuerySet {
11
+ nextQueryId = 0;
12
+ byToken = new Map();
13
+ byId = new Map();
14
+ /** Queries dropped locally whose `Remove` still has to reach the server on this socket. */
15
+ pendingRemoves = new Set();
16
+ /** The `newVersion` of the last ModifyQuerySet sent on this socket. */
17
+ querySetVersion = 0;
18
+ /** Adds a watcher; returns the query (created if needed) and whether a flush is needed. */
19
+ addRef(udfPath, args) {
20
+ const token = queryToken(udfPath, args);
21
+ const existing = this.byToken.get(token);
22
+ if (existing) {
23
+ existing.refCount += 1;
24
+ // refCount went 0 -> 1 before the flush: the query is revived without any server traffic.
25
+ return { query: existing, needsFlush: false };
26
+ }
27
+ const query = {
28
+ token,
29
+ queryId: this.nextQueryId++,
30
+ udfPath,
31
+ args,
32
+ refCount: 1,
33
+ onServer: false,
34
+ };
35
+ this.byToken.set(token, query);
36
+ this.byId.set(query.queryId, query);
37
+ return { query, needsFlush: true };
38
+ }
39
+ /** Removes a watcher; returns true when the query has no watchers left (a flush should be scheduled). */
40
+ removeRef(token) {
41
+ const query = this.byToken.get(token);
42
+ if (!query)
43
+ return false;
44
+ query.refCount = Math.max(0, query.refCount - 1);
45
+ return query.refCount === 0;
46
+ }
47
+ get(token) {
48
+ return this.byToken.get(token);
49
+ }
50
+ getById(queryId) {
51
+ return this.byId.get(queryId);
52
+ }
53
+ /** All queries currently tracked (including ones whose last watcher left but that are not yet flushed). */
54
+ queries() {
55
+ return this.byToken.values();
56
+ }
57
+ get size() {
58
+ return this.byToken.size;
59
+ }
60
+ /**
61
+ * Drops queries without watchers and, if `canSend`, builds the ModifyQuerySet that brings the server's query set
62
+ * in line with the local one (bumping the query set version).
63
+ */
64
+ flush(canSend) {
65
+ const removed = [];
66
+ for (const query of [...this.byToken.values()]) {
67
+ if (query.refCount > 0)
68
+ continue;
69
+ this.byToken.delete(query.token);
70
+ this.byId.delete(query.queryId);
71
+ removed.push(query.queryId);
72
+ if (query.onServer)
73
+ this.pendingRemoves.add(query.queryId);
74
+ }
75
+ if (!canSend)
76
+ return { message: null, removed };
77
+ const modifications = [];
78
+ for (const query of this.byToken.values()) {
79
+ if (!query.onServer) {
80
+ modifications.push({ type: "Add", queryId: query.queryId, udfPath: query.udfPath, args: query.args });
81
+ query.onServer = true;
82
+ }
83
+ }
84
+ for (const queryId of this.pendingRemoves)
85
+ modifications.push({ type: "Remove", queryId });
86
+ this.pendingRemoves.clear();
87
+ if (modifications.length === 0)
88
+ return { message: null, removed };
89
+ const baseVersion = this.querySetVersion;
90
+ this.querySetVersion += 1;
91
+ return {
92
+ message: { type: "ModifyQuerySet", baseVersion, newVersion: this.querySetVersion, modifications },
93
+ removed,
94
+ };
95
+ }
96
+ /** The server state is fresh on a new socket: nothing is subscribed and the query set version is 0. */
97
+ resetForNewSocket() {
98
+ this.querySetVersion = 0;
99
+ this.pendingRemoves.clear();
100
+ for (const query of this.byToken.values())
101
+ query.onServer = false;
102
+ }
103
+ /** The `newVersion` of the last ModifyQuerySet sent on this socket. */
104
+ get sentQuerySetVersion() {
105
+ return this.querySetVersion;
106
+ }
107
+ }
108
+ //# sourceMappingURL=local_query_set.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local_query_set.js","sourceRoot":"","sources":["../src/local_query_set.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface Logger {
2
+ /** Protocol-level tracing (enabled by `verbose`). */
3
+ debug(...args: unknown[]): void;
4
+ /** Connection diagnostics (enabled by `reportDebugInfoToConsole` or `verbose`). */
5
+ info(...args: unknown[]): void;
6
+ warn(...args: unknown[]): void;
7
+ error(...args: unknown[]): void;
8
+ /** Server-side `logLines` forwarded from a function execution. */
9
+ logLines(kind: string, udfPath: string, lines: string[] | undefined): void;
10
+ }
11
+ export declare function createLogger(options: {
12
+ verbose: boolean;
13
+ reportDebugInfoToConsole: boolean;
14
+ }): Logger;
15
+ //# sourceMappingURL=logging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,qDAAqD;IACrD,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,mFAAmF;IACnF,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC;CAC5E;AAID,wBAAgB,YAAY,CAAC,OAAO,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,wBAAwB,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAYrG"}
@@ -0,0 +1,17 @@
1
+ const PREFIX = "[rxferrix]";
2
+ export function createLogger(options) {
3
+ const noop = () => { };
4
+ return {
5
+ debug: options.verbose ? (...args) => console.debug(PREFIX, ...args) : noop,
6
+ info: options.verbose || options.reportDebugInfoToConsole ? (...args) => console.info(PREFIX, ...args) : noop,
7
+ warn: (...args) => console.warn(PREFIX, ...args),
8
+ error: (...args) => console.error(PREFIX, ...args),
9
+ logLines: (kind, udfPath, lines) => {
10
+ if (!lines || lines.length === 0)
11
+ return;
12
+ for (const line of lines)
13
+ console.log(`${PREFIX} [${kind} ${udfPath}]`, line);
14
+ },
15
+ };
16
+ }
17
+ //# sourceMappingURL=logging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.js","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,GAAG,YAAY,CAAC;AAE5B,MAAM,UAAU,YAAY,CAAC,OAAgE;IAC3F,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IACtB,OAAO;QACL,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;QAC3E,IAAI,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;QAC7G,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;QAChD,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;QAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;YACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YACzC,KAAK,MAAM,IAAI,IAAI,KAAK;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,IAAI,IAAI,OAAO,GAAG,EAAE,IAAI,CAAC,CAAC;QAChF,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { ArgsOf, FunctionReference, OutputOf } from "./api.js";
2
+ import { type QueryToken } from "./canonical.js";
3
+ import type { Logger } from "./logging.js";
4
+ import type { RequestId } from "./protocol.js";
5
+ import { type QueryState } from "./query_state.js";
6
+ /**
7
+ * A view of the client's query results that optimistic updates can read and write.
8
+ */
9
+ export interface OptimisticLocalStore {
10
+ /** The current value of a query, or undefined if it is loading, failed, or not subscribed. */
11
+ getQuery<Q extends FunctionReference<"query">>(ref: Q, args?: ArgsOf<Q>): OutputOf<Q> | undefined;
12
+ /** Overrides a query's value; `undefined` makes it look like it is loading. */
13
+ setQuery<Q extends FunctionReference<"query">>(ref: Q, args: ArgsOf<Q>, value: OutputOf<Q> | undefined): void;
14
+ /** Every query of this function the client knows about, with its args and current value. */
15
+ getAllQueries<Q extends FunctionReference<"query">>(ref: Q): {
16
+ args: ArgsOf<Q>;
17
+ value: OutputOf<Q> | undefined;
18
+ }[];
19
+ }
20
+ /** A function that optimistically applies a mutation's effect to the local store. */
21
+ export type OptimisticUpdate<Args> = (localStore: OptimisticLocalStore, args: Args) => void;
22
+ export interface ViewEntry {
23
+ readonly udfPath: string;
24
+ readonly args: Record<string, unknown>;
25
+ readonly state: QueryState;
26
+ }
27
+ export type ViewMap = Map<QueryToken, ViewEntry>;
28
+ /**
29
+ * Server query results with a stack of optimistic updates layered on top.
30
+ *
31
+ * Whenever the server state changes, the view is rebuilt from the server results and every pending update is
32
+ * replayed in the order the mutations were issued. An update is dropped when its mutation completes (its ts was
33
+ * observed) or fails. The view keeps the previous state object for a query when its visible value did not change, so
34
+ * watchers are only notified (and snapshots only change) on real changes.
35
+ */
36
+ export declare class OptimisticQueryResults {
37
+ private readonly logger;
38
+ private view;
39
+ private updates;
40
+ constructor(logger: Logger);
41
+ get(token: QueryToken): QueryState;
42
+ addUpdate(requestId: RequestId, apply: (store: OptimisticLocalStore) => void): void;
43
+ dropUpdates(requestIds: Iterable<RequestId>): boolean;
44
+ hasUpdates(): boolean;
45
+ /** Rebuilds the view from `server` plus all optimistic updates; returns the tokens whose visible state changed. */
46
+ recompute(server: ViewMap): QueryToken[];
47
+ }
48
+ //# sourceMappingURL=optimistic_updates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimistic_updates.d.ts","sourceRoot":"","sources":["../src/optimistic_updates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,8FAA8F;IAC9F,QAAQ,CAAC,CAAC,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAClG,+EAA+E;IAC/E,QAAQ,CAAC,CAAC,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAC9G,4FAA4F;IAC5F,aAAa,CAAC,CAAC,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;QAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;KAAE,EAAE,CAAC;CACpH;AAED,qFAAqF;AACrF,MAAM,MAAM,gBAAgB,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,oBAAoB,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;AAE5F,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;AAgCjD;;;;;;;GAOG;AACH,qBAAa,sBAAsB;IAIrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,OAAO,CAAgF;gBAElE,MAAM,EAAE,MAAM;IAE3C,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU;IAIlC,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,IAAI;IAInF,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,OAAO;IAQrD,UAAU,IAAI,OAAO;IAIrB,mHAAmH;IACnH,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,UAAU,EAAE;CAwBzC"}
@@ -0,0 +1,113 @@
1
+ import { jsonEqual, normalizeArgs, queryToken } from "./canonical.js";
2
+ import { LOADING } from "./query_state.js";
3
+ class LocalStoreImpl {
4
+ view;
5
+ constructor(view) {
6
+ this.view = view;
7
+ }
8
+ getQuery(ref, args) {
9
+ const entry = this.view.get(queryToken(ref._path, normalizeArgs(args)));
10
+ return entry?.state.status === "success" ? entry.state.value : undefined;
11
+ }
12
+ setQuery(ref, args, value) {
13
+ const normalized = normalizeArgs(args);
14
+ this.view.set(queryToken(ref._path, normalized), {
15
+ udfPath: ref._path,
16
+ args: normalized,
17
+ state: value === undefined ? LOADING : { status: "success", value },
18
+ });
19
+ }
20
+ getAllQueries(ref) {
21
+ const out = [];
22
+ for (const entry of this.view.values()) {
23
+ if (entry.udfPath !== ref._path)
24
+ continue;
25
+ out.push({
26
+ args: entry.args,
27
+ value: entry.state.status === "success" ? entry.state.value : undefined,
28
+ });
29
+ }
30
+ return out;
31
+ }
32
+ }
33
+ /**
34
+ * Server query results with a stack of optimistic updates layered on top.
35
+ *
36
+ * Whenever the server state changes, the view is rebuilt from the server results and every pending update is
37
+ * replayed in the order the mutations were issued. An update is dropped when its mutation completes (its ts was
38
+ * observed) or fails. The view keeps the previous state object for a query when its visible value did not change, so
39
+ * watchers are only notified (and snapshots only change) on real changes.
40
+ */
41
+ export class OptimisticQueryResults {
42
+ logger;
43
+ view = new Map();
44
+ updates = [];
45
+ constructor(logger) {
46
+ this.logger = logger;
47
+ }
48
+ get(token) {
49
+ return this.view.get(token)?.state ?? LOADING;
50
+ }
51
+ addUpdate(requestId, apply) {
52
+ this.updates.push({ requestId, apply });
53
+ }
54
+ dropUpdates(requestIds) {
55
+ const drop = new Set(requestIds);
56
+ if (drop.size === 0)
57
+ return false;
58
+ const before = this.updates.length;
59
+ this.updates = this.updates.filter((u) => !drop.has(u.requestId));
60
+ return this.updates.length !== before;
61
+ }
62
+ hasUpdates() {
63
+ return this.updates.length > 0;
64
+ }
65
+ /** Rebuilds the view from `server` plus all optimistic updates; returns the tokens whose visible state changed. */
66
+ recompute(server) {
67
+ const next = new Map(server);
68
+ const store = new LocalStoreImpl(next);
69
+ for (const update of this.updates) {
70
+ try {
71
+ update.apply(store);
72
+ }
73
+ catch (e) {
74
+ this.logger.error("optimistic update threw; ignoring it", e);
75
+ }
76
+ }
77
+ const changed = [];
78
+ for (const [token, entry] of next) {
79
+ const previous = this.view.get(token)?.state ?? LOADING;
80
+ const stable = stableState(previous, entry.state);
81
+ if (stable !== entry.state)
82
+ next.set(token, { ...entry, state: stable });
83
+ if (stable !== previous)
84
+ changed.push(token);
85
+ }
86
+ for (const [token, entry] of this.view) {
87
+ if (!next.has(token) && entry.state !== LOADING)
88
+ changed.push(token);
89
+ }
90
+ this.view = next;
91
+ return changed;
92
+ }
93
+ }
94
+ /** Returns `previous` if `next` shows the same thing, otherwise `next`. */
95
+ function stableState(previous, next) {
96
+ if (previous === next)
97
+ return previous;
98
+ if (previous.status !== next.status)
99
+ return next;
100
+ switch (next.status) {
101
+ case "loading":
102
+ return previous;
103
+ case "success":
104
+ return jsonEqual(previous.value, next.value) ? previous : next;
105
+ case "error": {
106
+ const p = previous.error;
107
+ return p.message === next.error.message && p.code === next.error.code && jsonEqual(p.data, next.error.data)
108
+ ? previous
109
+ : next;
110
+ }
111
+ }
112
+ }
113
+ //# sourceMappingURL=optimistic_updates.js.map