@estra/client 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +53 -2
- package/dist/_schema/index.d.ts +2 -0
- package/dist/_schema/index.js +2 -0
- package/dist/_schema/local.d.ts +14 -0
- package/dist/_schema/local.js +186 -0
- package/dist/_schema/query.d.ts +132 -0
- package/dist/_schema/query.js +34 -0
- package/dist/auth.d.ts +108 -0
- package/dist/auth.js +245 -0
- package/dist/channels.d.ts +42 -0
- package/dist/channels.js +176 -0
- package/dist/compat/app.d.ts +33 -0
- package/dist/compat/app.js +37 -0
- package/dist/compat/auth.d.ts +141 -0
- package/dist/compat/auth.js +221 -0
- package/dist/compat/firestore.d.ts +18 -0
- package/dist/compat/firestore.js +43 -0
- package/dist/compat/storage.d.ts +5 -0
- package/dist/compat/storage.js +5 -0
- package/dist/firestore.d.ts +256 -0
- package/dist/firestore.js +576 -0
- package/dist/functions.d.ts +20 -0
- package/dist/functions.js +43 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/local.d.ts +1 -0
- package/dist/local.js +2 -0
- package/dist/offline.d.ts +15 -0
- package/dist/offline.js +309 -0
- package/dist/realtime.d.ts +44 -0
- package/dist/realtime.js +112 -0
- package/dist/storage.d.ts +57 -0
- package/dist/storage.js +111 -0
- package/dist/store.d.ts +37 -0
- package/dist/store.js +44 -0
- package/dist/transport.d.ts +46 -0
- package/dist/transport.js +45 -0
- package/package.json +78 -3
package/dist/store.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export function memoryStore() {
|
|
2
|
+
const m = new Map();
|
|
3
|
+
const copy = (v) => (v === undefined ? undefined : structuredClone(v));
|
|
4
|
+
return {
|
|
5
|
+
get: async (k) => copy(m.get(k)),
|
|
6
|
+
set: async (k, v) => void m.set(k, structuredClone(v)),
|
|
7
|
+
delete: async (k) => void m.delete(k),
|
|
8
|
+
list: async (p) => [...m].filter(([k]) => k.startsWith(p)).map(([k, v]) => [k, copy(v)]),
|
|
9
|
+
clear: async () => m.clear(),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const g = globalThis;
|
|
13
|
+
/** One IndexedDB database with one object store; values are structured-cloned. */
|
|
14
|
+
export function indexedDbStore(name, idb = g.indexedDB) {
|
|
15
|
+
if (!idb || !g.IDBKeyRange)
|
|
16
|
+
throw new Error("IndexedDB isn't available here");
|
|
17
|
+
const keyRange = g.IDBKeyRange;
|
|
18
|
+
let dbp = null;
|
|
19
|
+
const db = () => (dbp ??= new Promise((resolve, reject) => {
|
|
20
|
+
const r = idb.open(name, 1);
|
|
21
|
+
r.onupgradeneeded = () => r.result.createObjectStore("kv");
|
|
22
|
+
r.onsuccess = () => resolve(r.result);
|
|
23
|
+
r.onerror = () => reject(r.error);
|
|
24
|
+
}));
|
|
25
|
+
const tx = async (mode, fn) => {
|
|
26
|
+
const d = await db();
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
const req = fn(d.transaction("kv", mode).objectStore("kv"));
|
|
29
|
+
req.onsuccess = () => resolve(req.result);
|
|
30
|
+
req.onerror = () => reject(req.error);
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
get: (k) => tx("readonly", (s) => s.get(k)),
|
|
35
|
+
set: async (k, v) => void (await tx("readwrite", (s) => s.put(v, k))),
|
|
36
|
+
delete: async (k) => void (await tx("readwrite", (s) => s.delete(k))),
|
|
37
|
+
list: async (p) => {
|
|
38
|
+
const range = keyRange.bound(p, p + "\uffff");
|
|
39
|
+
const [keys, vals] = await Promise.all([tx("readonly", (s) => s.getAllKeys(range)), tx("readonly", (s) => s.getAll(range))]);
|
|
40
|
+
return keys.map((k, i) => [String(k), vals[i]]);
|
|
41
|
+
},
|
|
42
|
+
clear: async () => void (await tx("readwrite", (s) => s.clear())),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CommitRequest, DocOut, Query } from "./_schema/index.js";
|
|
2
|
+
import { type Listen } from "./realtime.js";
|
|
3
|
+
export interface CommitOut {
|
|
4
|
+
writes: {
|
|
5
|
+
path: string;
|
|
6
|
+
v: number | null;
|
|
7
|
+
seq: number;
|
|
8
|
+
}[];
|
|
9
|
+
seq: number;
|
|
10
|
+
duplicate?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface QueryOut {
|
|
13
|
+
docs: DocOut[];
|
|
14
|
+
hasMore: boolean;
|
|
15
|
+
truncated?: boolean;
|
|
16
|
+
fromCache?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface Transport {
|
|
19
|
+
/** Live listeners (onSnapshot); absent = not supported by this transport. */
|
|
20
|
+
listen?: Listen;
|
|
21
|
+
getAll(paths: string[]): Promise<(DocOut | null)[]>;
|
|
22
|
+
query(query: Query): Promise<QueryOut>;
|
|
23
|
+
aggregate(query: Query): Promise<Record<string, number | null>>;
|
|
24
|
+
commit(req: CommitRequest): Promise<CommitOut>;
|
|
25
|
+
/** Hot counters (POST /v1/counters/inc): buffered server-side, flushed about once a second. */
|
|
26
|
+
counterInc?(path: string, field: string, by: number): Promise<{
|
|
27
|
+
value: number | null;
|
|
28
|
+
}>;
|
|
29
|
+
/** Re-send the auth token on the live connection now (after sign-in / sign-out). */
|
|
30
|
+
refreshAuth?(): void;
|
|
31
|
+
}
|
|
32
|
+
/** Errors carry Firestore's code names ("permission-denied", "not-found" …). */
|
|
33
|
+
export declare class EstraClientError extends Error {
|
|
34
|
+
readonly code: string;
|
|
35
|
+
constructor(code: string, message: string);
|
|
36
|
+
}
|
|
37
|
+
export interface HttpOptions {
|
|
38
|
+
/** Base URL of the app's Estra Worker, e.g. https://api.example.com */
|
|
39
|
+
url: string;
|
|
40
|
+
/** Current access token, or null when signed out. */
|
|
41
|
+
getToken?: () => Promise<string | null> | string | null;
|
|
42
|
+
fetch?: typeof fetch;
|
|
43
|
+
/** WebSocket implementation for onSnapshot (defaults to the global one; false = no listeners). */
|
|
44
|
+
WebSocket?: typeof WebSocket | false;
|
|
45
|
+
}
|
|
46
|
+
export declare function httpTransport(o: HttpOptions): Transport;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { realtimeConnection } from "./realtime.js";
|
|
2
|
+
/** Errors carry Firestore's code names ("permission-denied", "not-found" …). */
|
|
3
|
+
export class EstraClientError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
constructor(code, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.name = "EstraError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function httpTransport(o) {
|
|
12
|
+
const f = o.fetch ?? fetch;
|
|
13
|
+
const call = async (route, body) => {
|
|
14
|
+
const token = o.getToken ? await o.getToken() : null;
|
|
15
|
+
const headers = { "content-type": "application/json" };
|
|
16
|
+
if (token)
|
|
17
|
+
headers.authorization = `Bearer ${token}`;
|
|
18
|
+
let r;
|
|
19
|
+
try {
|
|
20
|
+
r = await f(`${o.url.replace(/\/$/, "")}/v1/${route}`, { method: "POST", headers, body: JSON.stringify(body) });
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new EstraClientError("unavailable", "network request failed");
|
|
24
|
+
}
|
|
25
|
+
if (r.status === 502 || r.status === 503 || r.status === 504)
|
|
26
|
+
throw new EstraClientError("unavailable", `HTTP ${r.status}`);
|
|
27
|
+
const j = (await r.json().catch(() => ({})));
|
|
28
|
+
if (!r.ok)
|
|
29
|
+
throw new EstraClientError(j.error?.code ?? "unavailable", j.error?.message ?? `HTTP ${r.status}`);
|
|
30
|
+
return j;
|
|
31
|
+
};
|
|
32
|
+
let rt = null;
|
|
33
|
+
const listen = o.WebSocket === false
|
|
34
|
+
? undefined
|
|
35
|
+
: (target, h) => (rt ??= realtimeConnection({ url: o.url, ...(o.getToken ? { getToken: o.getToken } : {}), ...(o.WebSocket ? { WebSocket: o.WebSocket } : {}) })).listen(target, h);
|
|
36
|
+
return {
|
|
37
|
+
...(listen ? { listen } : {}),
|
|
38
|
+
refreshAuth: () => rt?.refreshAuth(),
|
|
39
|
+
getAll: async (paths) => (await call("get", { paths })).docs,
|
|
40
|
+
query: (query) => call("query", { query }),
|
|
41
|
+
aggregate: async (query) => (await call("query", { query })).aggregate,
|
|
42
|
+
commit: (req) => call("commit", req),
|
|
43
|
+
counterInc: (path, field, by) => call("counters/inc", { path, field, by }),
|
|
44
|
+
};
|
|
45
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,81 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estra/client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Web and server client for Estra: documents, queries, realtime listeners, auth and callable functions, with a Firebase-compatible API.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://estra.cloud",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Realm-8/estra.git",
|
|
10
|
+
"directory": "packages/client"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/Realm-8/estra/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"estra",
|
|
15
|
+
"database",
|
|
16
|
+
"realtime",
|
|
17
|
+
"auth",
|
|
18
|
+
"firebase",
|
|
19
|
+
"firestore"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.js",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./firestore": {
|
|
29
|
+
"types": "./dist/firestore.d.ts",
|
|
30
|
+
"default": "./dist/firestore.js"
|
|
31
|
+
},
|
|
32
|
+
"./auth": {
|
|
33
|
+
"types": "./dist/auth.d.ts",
|
|
34
|
+
"default": "./dist/auth.js"
|
|
35
|
+
},
|
|
36
|
+
"./storage": {
|
|
37
|
+
"types": "./dist/storage.d.ts",
|
|
38
|
+
"default": "./dist/storage.js"
|
|
39
|
+
},
|
|
40
|
+
"./functions": {
|
|
41
|
+
"types": "./dist/functions.d.ts",
|
|
42
|
+
"default": "./dist/functions.js"
|
|
43
|
+
},
|
|
44
|
+
"./channels": {
|
|
45
|
+
"types": "./dist/channels.d.ts",
|
|
46
|
+
"default": "./dist/channels.js"
|
|
47
|
+
},
|
|
48
|
+
"./compat/app": {
|
|
49
|
+
"types": "./dist/compat/app.d.ts",
|
|
50
|
+
"default": "./dist/compat/app.js"
|
|
51
|
+
},
|
|
52
|
+
"./compat/auth": {
|
|
53
|
+
"types": "./dist/compat/auth.d.ts",
|
|
54
|
+
"default": "./dist/compat/auth.js"
|
|
55
|
+
},
|
|
56
|
+
"./compat/firestore": {
|
|
57
|
+
"types": "./dist/compat/firestore.d.ts",
|
|
58
|
+
"default": "./dist/compat/firestore.js"
|
|
59
|
+
},
|
|
60
|
+
"./compat/storage": {
|
|
61
|
+
"types": "./dist/compat/storage.d.ts",
|
|
62
|
+
"default": "./dist/compat/storage.js"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"files": [
|
|
66
|
+
"dist"
|
|
67
|
+
],
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"typescript": "^5.9.2",
|
|
73
|
+
"@estra/schema": "0.1.1"
|
|
74
|
+
},
|
|
75
|
+
"scripts": {
|
|
76
|
+
"typecheck": "tsc -p .",
|
|
77
|
+
"build": "node ../../scripts/build-package.ts client",
|
|
78
|
+
"test": "echo 'client is tested through @estra/testing'"
|
|
79
|
+
},
|
|
80
|
+
"types": "./dist/index.d.ts"
|
|
6
81
|
}
|