@zveltio/sdk 3.0.0-beta.5 → 3.0.0-beta.70
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/client/Auth.d.ts.map +1 -1
- package/dist/client/Auth.js +3 -0
- package/dist/client/QueryBuilder.d.ts.map +1 -1
- package/dist/client/QueryBuilder.js +4 -0
- package/dist/client/RealtimeClient.d.ts +19 -1
- package/dist/client/RealtimeClient.d.ts.map +1 -1
- package/dist/client/RealtimeClient.js +65 -12
- package/dist/client/ZveltioClient.d.ts.map +1 -1
- package/dist/client/ZveltioClient.js +12 -1
- package/dist/client.d.ts +28 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +41 -14
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +21 -3
- package/dist/crdt.d.ts.map +1 -1
- package/dist/crdt.js +11 -2
- package/dist/ddl/index.d.ts.map +1 -1
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +124 -0
- package/dist/extension/index.d.ts +459 -29
- package/dist/extension/index.d.ts.map +1 -1
- package/dist/extension/index.js +3 -0
- package/dist/extension/jsonb.d.ts +62 -0
- package/dist/extension/jsonb.d.ts.map +1 -0
- package/dist/extension/jsonb.js +64 -0
- package/dist/extension/multipart.d.ts +58 -0
- package/dist/extension/multipart.d.ts.map +1 -0
- package/dist/extension/multipart.js +61 -0
- package/dist/extension/numeric.d.ts +94 -0
- package/dist/extension/numeric.d.ts.map +1 -0
- package/dist/extension/numeric.js +162 -0
- package/dist/extension/permission-gate.d.ts +15 -0
- package/dist/extension/permission-gate.d.ts.map +1 -1
- package/dist/extension/permission-gate.js +33 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/local-store.d.ts +5 -0
- package/dist/local-store.d.ts.map +1 -1
- package/dist/local-store.js +62 -10
- package/dist/offline/index.d.ts +3 -3
- package/dist/offline/index.js +51 -15
- package/dist/publish/index.d.ts.map +1 -1
- package/dist/publish/index.js +6 -1
- package/dist/realtime.d.ts +18 -1
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +34 -3
- package/dist/rpc/index.d.ts.map +1 -1
- package/dist/rpc/index.js +2 -0
- package/dist/schema-codegen.d.ts +3 -1
- package/dist/schema-codegen.d.ts.map +1 -1
- package/dist/schema-codegen.js +41 -7
- package/dist/schema-watcher.d.ts +10 -2
- package/dist/schema-watcher.d.ts.map +1 -1
- package/dist/schema-watcher.js +30 -10
- package/dist/studio/index.d.ts +1 -0
- package/dist/studio/index.d.ts.map +1 -1
- package/dist/studio/index.js +3 -0
- package/dist/studio/slot-owner-registry.d.ts +13 -0
- package/dist/studio/slot-owner-registry.d.ts.map +1 -0
- package/dist/studio/slot-owner-registry.js +21 -0
- package/dist/svelte.d.ts +1 -1
- package/dist/svelte.d.ts.map +1 -1
- package/dist/svelte.js +4 -2
- package/dist/sync-manager.d.ts +30 -4
- package/dist/sync-manager.d.ts.map +1 -1
- package/dist/sync-manager.js +101 -15
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +23 -1
- package/dist/testing/with-test-db.d.ts.map +1 -1
- package/dist/testing/with-test-db.js +21 -14
- package/dist/tests/client.test.d.ts +2 -0
- package/dist/tests/client.test.d.ts.map +1 -0
- package/dist/tests/client.test.js +61 -0
- package/dist/tests/crdt-orset.test.d.ts +2 -0
- package/dist/tests/crdt-orset.test.d.ts.map +1 -0
- package/dist/tests/crdt-orset.test.js +23 -0
- package/dist/tests/local-store.test.js +44 -0
- package/dist/tests/multipart.test.d.ts +2 -0
- package/dist/tests/multipart.test.d.ts.map +1 -0
- package/dist/tests/multipart.test.js +37 -0
- package/dist/tests/offline-provider-crdt.test.d.ts +2 -0
- package/dist/tests/offline-provider-crdt.test.d.ts.map +1 -0
- package/dist/tests/offline-provider-crdt.test.js +119 -0
- package/dist/tests/realtime.test.d.ts +2 -0
- package/dist/tests/realtime.test.d.ts.map +1 -0
- package/dist/tests/realtime.test.js +284 -0
- package/dist/tests/sync-manager.test.d.ts +2 -0
- package/dist/tests/sync-manager.test.d.ts.map +1 -0
- package/dist/tests/sync-manager.test.js +65 -0
- package/dist/tests/with-test-db.test.d.ts +2 -0
- package/dist/tests/with-test-db.test.d.ts.map +1 -0
- package/dist/tests/with-test-db.test.js +57 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/validate/index.d.ts +49 -0
- package/dist/validate/index.d.ts.map +1 -1
- package/dist/validate/index.js +503 -7
- package/dist/validate/shared-message-keys.d.ts +16 -0
- package/dist/validate/shared-message-keys.d.ts.map +1 -0
- package/dist/validate/shared-message-keys.js +227 -0
- package/package.json +7 -7
- package/dist/generate-types.d.ts +0 -37
- package/dist/generate-types.d.ts.map +0 -1
- package/dist/generate-types.js +0 -157
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Auth.d.ts","sourceRoot":"","sources":["../../src/client/Auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,qBAAa,IAAI;IACf,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,aAAa;
|
|
1
|
+
{"version":3,"file":"Auth.d.ts","sourceRoot":"","sources":["../../src/client/Auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,qBAAa,IAAI;IACf,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,aAAa;IAK3B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC;IAY7E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC;IAW7E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQxB,UAAU,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,GAAG,IAAI,CAAC;IAQ/D,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,IAAI;CAGnE"}
|
package/dist/client/Auth.js
CHANGED
|
@@ -3,6 +3,7 @@ export class Auth {
|
|
|
3
3
|
constructor(config) {
|
|
4
4
|
this.config = config;
|
|
5
5
|
}
|
|
6
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
6
7
|
async signIn(email, password) {
|
|
7
8
|
const res = await fetch(`${this.config.baseUrl}/api/auth/sign-in/email`, {
|
|
8
9
|
method: 'POST',
|
|
@@ -14,6 +15,7 @@ export class Auth {
|
|
|
14
15
|
throw new Error((await res.json()).message || 'Sign in failed');
|
|
15
16
|
return res.json();
|
|
16
17
|
}
|
|
18
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
17
19
|
async signUp(name, email, password) {
|
|
18
20
|
const res = await fetch(`${this.config.baseUrl}/api/auth/sign-up/email`, {
|
|
19
21
|
method: 'POST',
|
|
@@ -31,6 +33,7 @@ export class Auth {
|
|
|
31
33
|
credentials: 'include',
|
|
32
34
|
});
|
|
33
35
|
}
|
|
36
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
34
37
|
async getSession() {
|
|
35
38
|
const res = await fetch(`${this.config.baseUrl}/api/me`, { credentials: 'include' });
|
|
36
39
|
if (!res.ok)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryBuilder.d.ts","sourceRoot":"","sources":["../../src/client/QueryBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEpF,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAgB;
|
|
1
|
+
{"version":3,"file":"QueryBuilder.d.ts","sourceRoot":"","sources":["../../src/client/QueryBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEpF,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAgB;IAE/B,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,QAAQ,CAAoB;gBAExB,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa;IAOrD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAEtC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAYlD,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAIrB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAMtB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,KAAK,GAAG,MAAc,GAAG,IAAI;IAO1D,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAOjB,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,eAAe,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAkCxE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,cAAc,CAAC,CAAC,EAAE,CAAC;CAY9D"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export class QueryBuilder {
|
|
2
2
|
_collection;
|
|
3
3
|
_config;
|
|
4
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
4
5
|
_filters = {};
|
|
5
6
|
_options = {};
|
|
6
7
|
constructor(collection, config) {
|
|
7
8
|
this._collection = collection;
|
|
8
9
|
this._config = config;
|
|
9
10
|
}
|
|
11
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
10
12
|
where(field, opOrValue, value) {
|
|
11
13
|
if (value === undefined) {
|
|
12
14
|
this._filters[field] = opOrValue;
|
|
@@ -37,6 +39,7 @@ export class QueryBuilder {
|
|
|
37
39
|
return this;
|
|
38
40
|
}
|
|
39
41
|
// Execute
|
|
42
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
40
43
|
async query(overrideOptions) {
|
|
41
44
|
const opts = { ...this._options, ...overrideOptions };
|
|
42
45
|
const params = new URLSearchParams();
|
|
@@ -69,6 +72,7 @@ export class QueryBuilder {
|
|
|
69
72
|
return res.json();
|
|
70
73
|
}
|
|
71
74
|
// Async iterable — allows `for await (const page of query)`
|
|
75
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
72
76
|
async *[Symbol.asyncIterator]() {
|
|
73
77
|
let currentPage = this._options.page || 1;
|
|
74
78
|
const pageSize = this._options.limit || 20;
|
|
@@ -4,16 +4,34 @@ type StatusCallback = (status: 'connecting' | 'connected' | 'disconnected') => v
|
|
|
4
4
|
export declare class RealtimeClient {
|
|
5
5
|
private ws;
|
|
6
6
|
private baseUrl;
|
|
7
|
+
private headers;
|
|
7
8
|
private subscriptions;
|
|
8
9
|
private statusCallbacks;
|
|
10
|
+
private unauthorizedCallbacks;
|
|
9
11
|
private reconnectDelay;
|
|
10
12
|
private maxReconnectDelay;
|
|
13
|
+
private reconnectAttempts;
|
|
14
|
+
private maxReconnectAttempts;
|
|
15
|
+
private reconnectTimer;
|
|
11
16
|
private shouldReconnect;
|
|
12
|
-
|
|
17
|
+
/** Set by a 4001 close; only an explicit `connect()` clears it. */
|
|
18
|
+
private unauthorized;
|
|
19
|
+
/**
|
|
20
|
+
* @param options.headers Sent with the upgrade — e.g. `{ 'X-API-Key': key }`
|
|
21
|
+
* for a server-side client (Bun, Node). A browser cannot set headers on a
|
|
22
|
+
* WebSocket and authenticates by session cookie.
|
|
23
|
+
*/
|
|
24
|
+
constructor(baseUrl: string, options?: {
|
|
25
|
+
headers?: Record<string, string>;
|
|
26
|
+
});
|
|
27
|
+
/** Open the socket — also after a 4001, once the app has re-authenticated. */
|
|
13
28
|
connect(): void;
|
|
29
|
+
private open;
|
|
14
30
|
disconnect(): void;
|
|
15
31
|
subscribe(collection: string, event: string | '*', callback: EventCallback): () => void;
|
|
16
32
|
onStatusChange(callback: StatusCallback): () => void;
|
|
33
|
+
/** Called when the engine ends the socket because its credentials were revoked. */
|
|
34
|
+
onUnauthorized(callback: () => void): () => void;
|
|
17
35
|
private sendSubscribe;
|
|
18
36
|
private sendUnsubscribe;
|
|
19
37
|
private notifyStatus;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RealtimeClient.d.ts","sourceRoot":"","sources":["../../src/client/RealtimeClient.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RealtimeClient.d.ts","sourceRoot":"","sources":["../../src/client/RealtimeClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,KAAK,aAAa,GAAG,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;AACxD,KAAK,cAAc,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,cAAc,KAAK,IAAI,CAAC;AAEpF,qBAAa,cAAc;IACzB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,qBAAqB,CAAyB;IACtD,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,oBAAoB,CAAM;IAClC,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,eAAe,CAAQ;IAC/B,mEAAmE;IACnE,OAAO,CAAC,YAAY,CAAS;IAE7B;;;;OAIG;gBACS,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAO;IAK/E,8EAA8E;IAC9E,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,IAAI;IAkEZ,UAAU,IAAI,IAAI;IAUlB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IA0BvF,cAAc,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI;IAKpD,mFAAmF;IACnF,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAKhD,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,YAAY;CAGrB"}
|
|
@@ -1,29 +1,57 @@
|
|
|
1
|
+
import { WS_UNAUTHORIZED } from '../realtime.js';
|
|
1
2
|
export class RealtimeClient {
|
|
2
3
|
ws = null;
|
|
3
4
|
baseUrl;
|
|
5
|
+
headers;
|
|
4
6
|
subscriptions = new Map();
|
|
5
7
|
statusCallbacks = new Set();
|
|
8
|
+
unauthorizedCallbacks = new Set();
|
|
6
9
|
reconnectDelay = 1000;
|
|
7
10
|
maxReconnectDelay = 30000;
|
|
11
|
+
reconnectAttempts = 0;
|
|
12
|
+
maxReconnectAttempts = 10;
|
|
13
|
+
reconnectTimer = null;
|
|
8
14
|
shouldReconnect = true;
|
|
9
|
-
|
|
15
|
+
/** Set by a 4001 close; only an explicit `connect()` clears it. */
|
|
16
|
+
unauthorized = false;
|
|
17
|
+
/**
|
|
18
|
+
* @param options.headers Sent with the upgrade — e.g. `{ 'X-API-Key': key }`
|
|
19
|
+
* for a server-side client (Bun, Node). A browser cannot set headers on a
|
|
20
|
+
* WebSocket and authenticates by session cookie.
|
|
21
|
+
*/
|
|
22
|
+
constructor(baseUrl, options = {}) {
|
|
10
23
|
this.baseUrl = baseUrl;
|
|
24
|
+
this.headers = options.headers;
|
|
11
25
|
}
|
|
26
|
+
/** Open the socket — also after a 4001, once the app has re-authenticated. */
|
|
12
27
|
connect() {
|
|
13
|
-
|
|
28
|
+
this.unauthorized = false;
|
|
29
|
+
this.shouldReconnect = true;
|
|
30
|
+
this.reconnectAttempts = 0;
|
|
31
|
+
this.reconnectDelay = 1000;
|
|
32
|
+
this.open();
|
|
33
|
+
}
|
|
34
|
+
open() {
|
|
35
|
+
if (this.ws?.readyState === WebSocket.OPEN || this.ws?.readyState === WebSocket.CONNECTING) {
|
|
14
36
|
return;
|
|
37
|
+
}
|
|
15
38
|
const wsUrl = this.baseUrl.replace(/^http/, 'ws') + '/api/ws';
|
|
16
|
-
|
|
39
|
+
// The two-argument form with `{ headers }` is the Bun/undici extension.
|
|
40
|
+
const ws = this.headers
|
|
41
|
+
? new WebSocket(wsUrl, { headers: this.headers })
|
|
42
|
+
: new WebSocket(wsUrl);
|
|
43
|
+
this.ws = ws;
|
|
17
44
|
this.notifyStatus('connecting');
|
|
18
|
-
|
|
45
|
+
ws.onopen = () => {
|
|
19
46
|
this.reconnectDelay = 1000;
|
|
47
|
+
this.reconnectAttempts = 0;
|
|
20
48
|
this.notifyStatus('connected');
|
|
21
49
|
// Re-subscribe all active subscriptions
|
|
22
50
|
for (const channel of this.subscriptions.keys()) {
|
|
23
51
|
this.sendSubscribe(channel);
|
|
24
52
|
}
|
|
25
53
|
};
|
|
26
|
-
|
|
54
|
+
ws.onmessage = (event) => {
|
|
27
55
|
try {
|
|
28
56
|
const message = JSON.parse(event.data);
|
|
29
57
|
const key = `${message.collection}:${message.event}`;
|
|
@@ -39,19 +67,37 @@ export class RealtimeClient {
|
|
|
39
67
|
/* ignore invalid messages */
|
|
40
68
|
}
|
|
41
69
|
};
|
|
42
|
-
|
|
70
|
+
ws.onclose = (event) => {
|
|
71
|
+
// A socket `disconnect()` dropped still reports; one already replaced does not.
|
|
72
|
+
if (this.ws !== ws) {
|
|
73
|
+
if (this.ws === null)
|
|
74
|
+
this.notifyStatus('disconnected');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
43
77
|
this.notifyStatus('disconnected');
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
this.
|
|
78
|
+
if (event?.code === WS_UNAUTHORIZED) {
|
|
79
|
+
// Credentials revoked: every retry would be refused with 401.
|
|
80
|
+
this.unauthorized = true;
|
|
81
|
+
this.unauthorizedCallbacks.forEach((cb) => cb());
|
|
82
|
+
return;
|
|
47
83
|
}
|
|
84
|
+
// Bounded: a refused handshake (401) is not visible to a WebSocket in any
|
|
85
|
+
// runtime — it closes as 1002/1006 — so it must not be retried forever.
|
|
86
|
+
if (!this.shouldReconnect || this.reconnectAttempts >= this.maxReconnectAttempts)
|
|
87
|
+
return;
|
|
88
|
+
this.reconnectAttempts++;
|
|
89
|
+
this.reconnectTimer = setTimeout(() => this.open(), this.reconnectDelay);
|
|
90
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);
|
|
48
91
|
};
|
|
49
|
-
|
|
50
|
-
|
|
92
|
+
ws.onerror = () => {
|
|
93
|
+
ws.close();
|
|
51
94
|
};
|
|
52
95
|
}
|
|
53
96
|
disconnect() {
|
|
54
97
|
this.shouldReconnect = false;
|
|
98
|
+
if (this.reconnectTimer)
|
|
99
|
+
clearTimeout(this.reconnectTimer);
|
|
100
|
+
this.reconnectTimer = null;
|
|
55
101
|
this.ws?.close();
|
|
56
102
|
this.ws = null;
|
|
57
103
|
}
|
|
@@ -66,9 +112,11 @@ export class RealtimeClient {
|
|
|
66
112
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
67
113
|
this.sendSubscribe(key);
|
|
68
114
|
}
|
|
69
|
-
else {
|
|
115
|
+
else if (!this.unauthorized) {
|
|
70
116
|
this.connect();
|
|
71
117
|
}
|
|
118
|
+
// After a 4001 the subscription is only recorded: the next explicit
|
|
119
|
+
// `connect()` sends it. Dialling again would only be refused.
|
|
72
120
|
// Return unsubscribe function
|
|
73
121
|
return () => {
|
|
74
122
|
this.subscriptions.get(key)?.delete(callback);
|
|
@@ -82,6 +130,11 @@ export class RealtimeClient {
|
|
|
82
130
|
this.statusCallbacks.add(callback);
|
|
83
131
|
return () => this.statusCallbacks.delete(callback);
|
|
84
132
|
}
|
|
133
|
+
/** Called when the engine ends the socket because its credentials were revoked. */
|
|
134
|
+
onUnauthorized(callback) {
|
|
135
|
+
this.unauthorizedCallbacks.add(callback);
|
|
136
|
+
return () => this.unauthorizedCallbacks.delete(callback);
|
|
137
|
+
}
|
|
85
138
|
sendSubscribe(channel) {
|
|
86
139
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
87
140
|
this.ws.send(JSON.stringify({ type: 'subscribe', channel }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZveltioClient.d.ts","sourceRoot":"","sources":["../../src/client/ZveltioClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EAGb,cAAc,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,qBAAa,aAAa;IACxB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,aAAa;
|
|
1
|
+
{"version":3,"file":"ZveltioClient.d.ts","sourceRoot":"","sources":["../../src/client/ZveltioClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EAGb,cAAc,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,qBAAa,aAAa;IACxB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,aAAa;IAajC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY;IAMhC,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAKpF,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAMxD,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IASjE,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAS7E,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAQrE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAO/D,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;CA4B/D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAEjE"}
|
|
@@ -8,20 +8,29 @@ export class ZveltioClient {
|
|
|
8
8
|
constructor(config) {
|
|
9
9
|
this.config = config;
|
|
10
10
|
this.auth = new Auth(config);
|
|
11
|
-
|
|
11
|
+
// The key the HTTP calls send, sent with the upgrade too (server-side
|
|
12
|
+
// clients; a browser authenticates the socket by its session cookie).
|
|
13
|
+
this.realtime = new RealtimeClient(config.baseUrl, {
|
|
14
|
+
headers: config.apiKey ? { 'X-API-Key': config.apiKey } : undefined,
|
|
15
|
+
});
|
|
16
|
+
// A socket closed for revoked credentials is the same event as a 401.
|
|
17
|
+
this.realtime.onUnauthorized(() => config.onUnauthorized?.());
|
|
12
18
|
}
|
|
13
19
|
// Fluent query builder
|
|
14
20
|
from(collection) {
|
|
15
21
|
return new QueryBuilder(collection, this.config);
|
|
16
22
|
}
|
|
17
23
|
// Direct CRUD methods
|
|
24
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
18
25
|
async list(collection, options) {
|
|
19
26
|
return this.from(collection).query(options);
|
|
20
27
|
}
|
|
28
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
21
29
|
async get(collection, id) {
|
|
22
30
|
const res = await this.request(`/api/data/${collection}/${id}`);
|
|
23
31
|
return res.record;
|
|
24
32
|
}
|
|
33
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
25
34
|
async create(collection, data) {
|
|
26
35
|
const res = await this.request(`/api/data/${collection}`, {
|
|
27
36
|
method: 'POST',
|
|
@@ -29,6 +38,7 @@ export class ZveltioClient {
|
|
|
29
38
|
});
|
|
30
39
|
return res.record;
|
|
31
40
|
}
|
|
41
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
32
42
|
async update(collection, id, data) {
|
|
33
43
|
const res = await this.request(`/api/data/${collection}/${id}`, {
|
|
34
44
|
method: 'PATCH',
|
|
@@ -36,6 +46,7 @@ export class ZveltioClient {
|
|
|
36
46
|
});
|
|
37
47
|
return res.record;
|
|
38
48
|
}
|
|
49
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
39
50
|
async replace(collection, id, data) {
|
|
40
51
|
const res = await this.request(`/api/data/${collection}/${id}`, {
|
|
41
52
|
method: 'PUT',
|
package/dist/client.d.ts
CHANGED
|
@@ -3,6 +3,19 @@ export interface ZveltioClientConfig {
|
|
|
3
3
|
apiKey?: string;
|
|
4
4
|
headers?: Record<string, string>;
|
|
5
5
|
}
|
|
6
|
+
/** `GET /api/api-keys/self` — the key a client authenticates with, as the engine holds it. */
|
|
7
|
+
export interface ApiKeySelf {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
key_prefix: string;
|
|
11
|
+
scopes: Array<{
|
|
12
|
+
collection: string;
|
|
13
|
+
actions: string[];
|
|
14
|
+
}>;
|
|
15
|
+
tenant_id: string | null;
|
|
16
|
+
expires_at: string | null;
|
|
17
|
+
rls_bypass: boolean;
|
|
18
|
+
}
|
|
6
19
|
export interface ListParams {
|
|
7
20
|
page?: number;
|
|
8
21
|
limit?: number;
|
|
@@ -20,8 +33,11 @@ export interface ListResult<T> {
|
|
|
20
33
|
next_cursor?: string;
|
|
21
34
|
}
|
|
22
35
|
declare class CollectionRef<T extends Record<string, any>> {
|
|
23
|
-
private readonly name;
|
|
24
36
|
private readonly client;
|
|
37
|
+
/** URL-encoded once, here: a record id is caller data (a slug, an email, a
|
|
38
|
+
* composite key), and an unencoded `/`, `?` or `#` in one silently routes
|
|
39
|
+
* the request somewhere else. */
|
|
40
|
+
private readonly path;
|
|
25
41
|
constructor(name: string, client: ZveltioClient<any>);
|
|
26
42
|
list(params?: ListParams): Promise<ListResult<T>>;
|
|
27
43
|
getMany(params?: ListParams): Promise<ListResult<T>>;
|
|
@@ -69,8 +85,18 @@ export declare class ZveltioClient<Schema extends Record<string, any> = Record<s
|
|
|
69
85
|
readonly signup: (email: string, password: string, name: string) => Promise<any>;
|
|
70
86
|
readonly logout: () => Promise<any>;
|
|
71
87
|
readonly session: () => Promise<any>;
|
|
88
|
+
/**
|
|
89
|
+
* The API key this client was made with: its scopes, tenant, expiry and RLS
|
|
90
|
+
* exemption — never the hash. 403 for a session, 401 for a key that no
|
|
91
|
+
* longer authenticates.
|
|
92
|
+
*/
|
|
93
|
+
readonly apiKey: () => Promise<ApiKeySelf>;
|
|
72
94
|
};
|
|
73
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* Storage helpers. A client made with `apiKey` needs a key holding the `$storage`
|
|
97
|
+
* scope — `{ collection: '$storage', actions: ['read', 'create', 'delete'] }`; a
|
|
98
|
+
* `*` collection does not include it, and the engine answers 403 without it.
|
|
99
|
+
*/
|
|
74
100
|
readonly storage: {
|
|
75
101
|
readonly upload: (file: File, folder?: string) => Promise<any>;
|
|
76
102
|
readonly list: (folder?: string) => Promise<any>;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import { ZveltioApiError } from './errors.js';
|
|
2
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
1
3
|
class CollectionRef {
|
|
2
|
-
name;
|
|
3
4
|
client;
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/** URL-encoded once, here: a record id is caller data (a slug, an email, a
|
|
6
|
+
* composite key), and an unencoded `/`, `?` or `#` in one silently routes
|
|
7
|
+
* the request somewhere else. */
|
|
8
|
+
path;
|
|
9
|
+
constructor(name,
|
|
10
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
11
|
+
client) {
|
|
6
12
|
this.client = client;
|
|
13
|
+
this.path = `/api/data/${encodeURIComponent(name)}`;
|
|
7
14
|
}
|
|
8
15
|
list(params) {
|
|
9
16
|
const qs = new URLSearchParams();
|
|
@@ -22,25 +29,25 @@ class CollectionRef {
|
|
|
22
29
|
if (params?.cursor)
|
|
23
30
|
qs.set('cursor', params.cursor);
|
|
24
31
|
const q = qs.toString();
|
|
25
|
-
return this.client['request']('GET',
|
|
32
|
+
return this.client['request']('GET', `${this.path}${q ? `?${q}` : ''}`);
|
|
26
33
|
}
|
|
27
34
|
getMany(params) {
|
|
28
35
|
return this.list(params);
|
|
29
36
|
}
|
|
30
37
|
get(id) {
|
|
31
|
-
return this.client['request']('GET',
|
|
38
|
+
return this.client['request']('GET', `${this.path}/${encodeURIComponent(id)}`);
|
|
32
39
|
}
|
|
33
40
|
getOne(id) {
|
|
34
41
|
return this.get(id);
|
|
35
42
|
}
|
|
36
43
|
create(data) {
|
|
37
|
-
return this.client['request']('POST',
|
|
44
|
+
return this.client['request']('POST', this.path, data);
|
|
38
45
|
}
|
|
39
46
|
update(id, data) {
|
|
40
|
-
return this.client['request']('PATCH',
|
|
47
|
+
return this.client['request']('PATCH', `${this.path}/${encodeURIComponent(id)}`, data);
|
|
41
48
|
}
|
|
42
49
|
delete(id) {
|
|
43
|
-
return this.client['request']('DELETE',
|
|
50
|
+
return this.client['request']('DELETE', `${this.path}/${encodeURIComponent(id)}`);
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
/**
|
|
@@ -56,6 +63,7 @@ class CollectionRef {
|
|
|
56
63
|
* Usage without types (untyped, same as before):
|
|
57
64
|
* const client = createZveltioClient({ baseUrl: '...' });
|
|
58
65
|
*/
|
|
66
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
59
67
|
export class ZveltioClient {
|
|
60
68
|
baseUrl;
|
|
61
69
|
headers;
|
|
@@ -67,6 +75,7 @@ export class ZveltioClient {
|
|
|
67
75
|
...config.headers,
|
|
68
76
|
};
|
|
69
77
|
}
|
|
78
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
70
79
|
async request(method, path, body) {
|
|
71
80
|
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
72
81
|
method,
|
|
@@ -75,23 +84,27 @@ export class ZveltioClient {
|
|
|
75
84
|
body: body ? JSON.stringify(body) : undefined,
|
|
76
85
|
});
|
|
77
86
|
if (!res.ok) {
|
|
78
|
-
|
|
79
|
-
throw new Error(`${method} ${path} failed: ${res.status} ${text}`);
|
|
87
|
+
throw await ZveltioApiError.fromResponse(res);
|
|
80
88
|
}
|
|
81
89
|
return res.json();
|
|
82
90
|
}
|
|
91
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
83
92
|
get(path) {
|
|
84
93
|
return this.request('GET', path);
|
|
85
94
|
}
|
|
95
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
86
96
|
post(path, body) {
|
|
87
97
|
return this.request('POST', path, body);
|
|
88
98
|
}
|
|
99
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
89
100
|
patch(path, body) {
|
|
90
101
|
return this.request('PATCH', path, body);
|
|
91
102
|
}
|
|
103
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
92
104
|
delete(path) {
|
|
93
105
|
return this.request('DELETE', path);
|
|
94
106
|
}
|
|
107
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
95
108
|
async upload(path, formData) {
|
|
96
109
|
const headers = { ...this.headers };
|
|
97
110
|
delete headers['Content-Type'];
|
|
@@ -102,9 +115,10 @@ export class ZveltioClient {
|
|
|
102
115
|
body: formData,
|
|
103
116
|
});
|
|
104
117
|
if (!res.ok)
|
|
105
|
-
throw
|
|
118
|
+
throw await ZveltioApiError.fromResponse(res);
|
|
106
119
|
return res.json();
|
|
107
120
|
}
|
|
121
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
108
122
|
collection(name) {
|
|
109
123
|
return new CollectionRef(name, this);
|
|
110
124
|
}
|
|
@@ -114,20 +128,33 @@ export class ZveltioClient {
|
|
|
114
128
|
signup: (email, password, name) => this.request('POST', '/api/auth/sign-up/email', { email, password, name }),
|
|
115
129
|
logout: () => this.request('POST', '/api/auth/sign-out'),
|
|
116
130
|
session: () => this.request('GET', '/api/auth/get-session'),
|
|
131
|
+
/**
|
|
132
|
+
* The API key this client was made with: its scopes, tenant, expiry and RLS
|
|
133
|
+
* exemption — never the hash. 403 for a session, 401 for a key that no
|
|
134
|
+
* longer authenticates.
|
|
135
|
+
*/
|
|
136
|
+
apiKey: () => this.request('GET', '/api/api-keys/self'),
|
|
117
137
|
};
|
|
118
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Storage helpers. A client made with `apiKey` needs a key holding the `$storage`
|
|
140
|
+
* scope — `{ collection: '$storage', actions: ['read', 'create', 'delete'] }`; a
|
|
141
|
+
* `*` collection does not include it, and the engine answers 403 without it.
|
|
142
|
+
*/
|
|
119
143
|
storage = {
|
|
120
144
|
upload: (file, folder) => {
|
|
121
145
|
const fd = new FormData();
|
|
122
146
|
fd.append('file', file);
|
|
147
|
+
// The engine reads `folder_id`; a `folder` field is ignored and the file
|
|
148
|
+
// lands in the root.
|
|
123
149
|
if (folder)
|
|
124
|
-
fd.append('
|
|
150
|
+
fd.append('folder_id', folder);
|
|
125
151
|
return this.upload('/api/storage/upload', fd);
|
|
126
152
|
},
|
|
127
|
-
list: (folder) => this.get(`/api/storage${folder ? `?
|
|
153
|
+
list: (folder) => this.get(`/api/storage${folder ? `?folder_id=${encodeURIComponent(folder)}` : ''}`),
|
|
128
154
|
delete: (key) => this.delete(`/api/storage/${encodeURIComponent(key)}`),
|
|
129
155
|
};
|
|
130
156
|
}
|
|
157
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
131
158
|
export function createZveltioClient(config) {
|
|
132
159
|
return new ZveltioClient(config);
|
|
133
160
|
}
|
package/dist/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIrD,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
|
package/dist/core.js
CHANGED
|
@@ -6,20 +6,31 @@
|
|
|
6
6
|
* state primitives (useState/ref) and lifecycle hooks (useEffect/onMounted).
|
|
7
7
|
*/
|
|
8
8
|
// ── Collection ────────────────────────────────────────────────────────────────
|
|
9
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
9
10
|
export async function fetchCollection(client, collectionName, options) {
|
|
11
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
10
12
|
const result = await client.collection(collectionName).list(options);
|
|
13
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
11
14
|
return result?.data ?? result?.records ?? result ?? [];
|
|
12
15
|
}
|
|
16
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
13
17
|
export async function fetchRecord(client, collectionName, id) {
|
|
14
18
|
const result = await client.collection(collectionName).get(id);
|
|
19
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
15
20
|
return result?.data ?? result?.record ?? result ?? null;
|
|
16
21
|
}
|
|
22
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
17
23
|
export async function createRecord(client, collectionName, data) {
|
|
24
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
18
25
|
const result = await client.collection(collectionName).create(data);
|
|
26
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
19
27
|
return result?.data ?? result?.record ?? result;
|
|
20
28
|
}
|
|
29
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
21
30
|
export async function updateRecord(client, collectionName, id, data) {
|
|
31
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
22
32
|
const result = await client.collection(collectionName).update(id, data);
|
|
33
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
23
34
|
return result?.data ?? result?.record ?? result;
|
|
24
35
|
}
|
|
25
36
|
export async function deleteRecord(client, collectionName, id) {
|
|
@@ -28,8 +39,10 @@ export async function deleteRecord(client, collectionName, id) {
|
|
|
28
39
|
// ── Auth ──────────────────────────────────────────────────────────────────────
|
|
29
40
|
export async function fetchSession(client) {
|
|
30
41
|
try {
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
// `/api/auth/get-session` answers `{ session, user }` (or null): `session`
|
|
43
|
+
// is the envelope's own member, not the envelope.
|
|
44
|
+
const res = await client.auth.session();
|
|
45
|
+
return { user: res?.user ?? null, session: res?.session ?? null };
|
|
33
46
|
}
|
|
34
47
|
catch {
|
|
35
48
|
return { user: null, session: null };
|
|
@@ -50,16 +63,21 @@ export async function signupUser(client, email, password, name) {
|
|
|
50
63
|
// ── Storage ───────────────────────────────────────────────────────────────────
|
|
51
64
|
export async function uploadFile(client, file, folder) {
|
|
52
65
|
const result = await client.storage.upload(file, folder);
|
|
66
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
53
67
|
return result?.data ?? result?.file ?? result;
|
|
54
68
|
}
|
|
55
69
|
export async function listFiles(client, folder) {
|
|
56
70
|
const result = await client.storage.list(folder);
|
|
71
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
57
72
|
return result?.data ?? result?.files ?? result ?? [];
|
|
58
73
|
}
|
|
59
74
|
export async function removeFile(client, fileId) {
|
|
60
75
|
await client.storage.delete(fileId);
|
|
61
76
|
}
|
|
62
77
|
// ── Realtime ──────────────────────────────────────────────────────────────────
|
|
63
|
-
export function subscribeToCollection(realtime, collection,
|
|
78
|
+
export function subscribeToCollection(realtime, collection,
|
|
79
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
80
|
+
callback) {
|
|
81
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
64
82
|
return realtime.subscribe(collection, callback);
|
|
65
83
|
}
|
package/dist/crdt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crdt.d.ts","sourceRoot":"","sources":["../src/crdt.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"crdt.d.ts","sourceRoot":"","sources":["../src/crdt.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,GAAG;IAC/B,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,WAAW,CAkB7E;AAED,gDAAgD;AAChD,wBAAgB,UAAU,CAExB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,WAAW,CAMb;AAED,8CAA8C;AAE9C,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOlE;AAKD,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,GAAG;IACnC,KAAK,EAAE,CAAC,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;CAClB;AAGD,MAAM,MAAM,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;AAE/C,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAE7D;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAEnE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAezE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAEjD;AAID,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,EAAE,MAAM,EAAE,OAAO,SAAI;IAKzC,yCAAyC;IACzC,IAAI,IAAI,MAAM;IAId,uDAAuD;IACvD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAKhC,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,EAAE,IAAI,MAAM,CAEf;CACF"}
|