@rxferrix/client 0.0.0-stage → 0.2.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.
- package/dist/api.d.ts +60 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +22 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +256 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +541 -0
- package/dist/auth.js.map +1 -0
- package/dist/bytes.d.ts +21 -0
- package/dist/bytes.d.ts.map +1 -0
- package/dist/bytes.js +51 -0
- package/dist/bytes.js.map +1 -0
- package/dist/canonical.d.ts +13 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +66 -0
- package/dist/canonical.js.map +1 -0
- package/dist/client.d.ts +170 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +638 -0
- package/dist/client.js.map +1 -0
- package/dist/diff.d.ts +20 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +100 -0
- package/dist/diff.js.map +1 -0
- package/dist/errors.d.ts +24 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +34 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/local_query_set.d.ts +56 -0
- package/dist/local_query_set.d.ts.map +1 -0
- package/dist/local_query_set.js +108 -0
- package/dist/local_query_set.js.map +1 -0
- package/dist/logging.d.ts +15 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +17 -0
- package/dist/logging.js.map +1 -0
- package/dist/optimistic_updates.d.ts +48 -0
- package/dist/optimistic_updates.d.ts.map +1 -0
- package/dist/optimistic_updates.js +113 -0
- package/dist/optimistic_updates.js.map +1 -0
- package/dist/paginated_query.d.ts +118 -0
- package/dist/paginated_query.d.ts.map +1 -0
- package/dist/paginated_query.js +199 -0
- package/dist/paginated_query.js.map +1 -0
- package/dist/protocol.d.ts +136 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +11 -0
- package/dist/protocol.js.map +1 -0
- package/dist/query_state.d.ts +16 -0
- package/dist/query_state.d.ts.map +1 -0
- package/dist/query_state.js +2 -0
- package/dist/query_state.js.map +1 -0
- package/dist/remote_query_set.d.ts +37 -0
- package/dist/remote_query_set.d.ts.map +1 -0
- package/dist/remote_query_set.js +87 -0
- package/dist/remote_query_set.js.map +1 -0
- package/dist/request_manager.d.ts +57 -0
- package/dist/request_manager.d.ts.map +1 -0
- package/dist/request_manager.js +163 -0
- package/dist/request_manager.js.map +1 -0
- package/dist/storage.d.ts +45 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +120 -0
- package/dist/storage.js.map +1 -0
- package/dist/testing.d.ts +68 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +97 -0
- package/dist/testing.js.map +1 -0
- package/dist/web_socket_manager.d.ts +88 -0
- package/dist/web_socket_manager.d.ts.map +1 -0
- package/dist/web_socket_manager.js +291 -0
- package/dist/web_socket_manager.js.map +1 -0
- package/package.json +50 -4
- package/src/api.ts +86 -0
- package/src/auth.ts +646 -0
- package/src/bytes.ts +57 -0
- package/src/canonical.ts +61 -0
- package/src/client.ts +740 -0
- package/src/diff.ts +87 -0
- package/src/errors.ts +36 -0
- package/src/index.ts +60 -0
- package/src/local_query_set.ts +130 -0
- package/src/logging.ts +26 -0
- package/src/optimistic_updates.ts +137 -0
- package/src/paginated_query.ts +299 -0
- package/src/protocol.ts +152 -0
- package/src/query_state.ts +12 -0
- package/src/remote_query_set.ts +105 -0
- package/src/request_manager.ts +199 -0
- package/src/storage.ts +171 -0
- package/src/testing.ts +120 -0
- package/src/web_socket_manager.ts +322 -0
- package/README.md +0 -3
package/src/bytes.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary values: `rxferrix::Bytes` travels (and is stored) as `{ $bytes: "<base64>" }`, which is also its generated
|
|
3
|
+
* TypeScript type. These helpers convert between that form and `Uint8Array`.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* await client.mutation(api.files.save_thumbnail, { id, thumb: bytesToJson(new Uint8Array(png)) });
|
|
7
|
+
* const doc = await client.query(api.files.get, { id });
|
|
8
|
+
* const png: Uint8Array = bytesFromJson(doc.thumb);
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** The JSON form of `rxferrix::Bytes`: standard, padded base64. */
|
|
13
|
+
export type Bytes = { $bytes: string };
|
|
14
|
+
|
|
15
|
+
const CHUNK = 0x8000;
|
|
16
|
+
|
|
17
|
+
/** Wrap binary data as `{ $bytes: "<base64>" }` (for args and documents). */
|
|
18
|
+
export function bytesToJson(data: Uint8Array | ArrayBuffer | ArrayBufferView): Bytes {
|
|
19
|
+
const bytes =
|
|
20
|
+
data instanceof Uint8Array
|
|
21
|
+
? data
|
|
22
|
+
: ArrayBuffer.isView(data)
|
|
23
|
+
? new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
|
|
24
|
+
: new Uint8Array(data);
|
|
25
|
+
let binary = "";
|
|
26
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
27
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
28
|
+
}
|
|
29
|
+
return { $bytes: btoa(binary) };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The bytes of a `{ $bytes: "<base64>" }` value (from a query result or document). Throws a `TypeError` otherwise. */
|
|
33
|
+
export function bytesFromJson(value: Bytes): Uint8Array {
|
|
34
|
+
if (!isBytes(value)) {
|
|
35
|
+
throw new TypeError("expected bytes as { $bytes: string }");
|
|
36
|
+
}
|
|
37
|
+
let binary: string;
|
|
38
|
+
try {
|
|
39
|
+
binary = atob(value.$bytes);
|
|
40
|
+
} catch {
|
|
41
|
+
throw new TypeError("`$bytes` is not valid base64");
|
|
42
|
+
}
|
|
43
|
+
const out = new Uint8Array(binary.length);
|
|
44
|
+
for (let i = 0; i < binary.length; i++) {
|
|
45
|
+
out[i] = binary.charCodeAt(i);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** True for a value in the `{ $bytes: string }` form (an object with exactly that key). */
|
|
51
|
+
export function isBytes(value: unknown): value is Bytes {
|
|
52
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const keys = Object.keys(value);
|
|
56
|
+
return keys.length === 1 && keys[0] === "$bytes" && typeof (value as Bytes).$bytes === "string";
|
|
57
|
+
}
|
package/src/canonical.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical JSON: `JSON.stringify` with object keys sorted recursively. Two arg objects that are structurally equal
|
|
3
|
+
* produce the same string, regardless of key insertion order. `undefined` object values are dropped, as in JSON.
|
|
4
|
+
*/
|
|
5
|
+
export function canonicalJSON(value: unknown): string {
|
|
6
|
+
return JSON.stringify(sortKeys(value)) ?? "null";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function sortKeys(value: unknown): unknown {
|
|
10
|
+
if (value === null || typeof value !== "object") return value;
|
|
11
|
+
if (typeof (value as { toJSON?: unknown }).toJSON === "function") {
|
|
12
|
+
return sortKeys((value as { toJSON: () => unknown }).toJSON());
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(value)) return value.map(sortKeys);
|
|
15
|
+
const out: Record<string, unknown> = {};
|
|
16
|
+
for (const key of Object.keys(value).sort()) {
|
|
17
|
+
const v = (value as Record<string, unknown>)[key];
|
|
18
|
+
if (v === undefined || typeof v === "function" || typeof v === "symbol") continue;
|
|
19
|
+
out[key] = sortKeys(v);
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** The client-side identity of a query: `udfPath + canonicalJSON(args)`. */
|
|
25
|
+
export type QueryToken = string;
|
|
26
|
+
|
|
27
|
+
export function queryToken(udfPath: string, args: Record<string, unknown>): QueryToken {
|
|
28
|
+
return udfPath + canonicalJSON(args);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Structural equality for JSON values (as produced by `JSON.parse`). */
|
|
32
|
+
export function jsonEqual(a: unknown, b: unknown): boolean {
|
|
33
|
+
if (a === b) return true;
|
|
34
|
+
if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") {
|
|
35
|
+
// NaN never appears in JSON; plain === suffices for primitives.
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(a)) {
|
|
39
|
+
if (!Array.isArray(b) || a.length !== b.length) return false;
|
|
40
|
+
for (let i = 0; i < a.length; i++) if (!jsonEqual(a[i], b[i])) return false;
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (Array.isArray(b)) return false;
|
|
44
|
+
const ao = a as Record<string, unknown>;
|
|
45
|
+
const bo = b as Record<string, unknown>;
|
|
46
|
+
const aKeys = Object.keys(ao);
|
|
47
|
+
if (aKeys.length !== Object.keys(bo).length) return false;
|
|
48
|
+
for (const k of aKeys) {
|
|
49
|
+
if (!Object.prototype.hasOwnProperty.call(bo, k) || !jsonEqual(ao[k], bo[k])) return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Normalizes user-supplied args: `undefined` becomes `{}`; anything else must be a plain object. */
|
|
55
|
+
export function normalizeArgs(args: unknown): Record<string, unknown> {
|
|
56
|
+
if (args === undefined || args === null) return {};
|
|
57
|
+
if (typeof args !== "object" || Array.isArray(args)) {
|
|
58
|
+
throw new TypeError(`RxFerrix function args must be an object, got ${Array.isArray(args) ? "array" : typeof args}`);
|
|
59
|
+
}
|
|
60
|
+
return args as Record<string, unknown>;
|
|
61
|
+
}
|