@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.
Files changed (105) hide show
  1. package/dist/client/Auth.d.ts.map +1 -1
  2. package/dist/client/Auth.js +3 -0
  3. package/dist/client/QueryBuilder.d.ts.map +1 -1
  4. package/dist/client/QueryBuilder.js +4 -0
  5. package/dist/client/RealtimeClient.d.ts +19 -1
  6. package/dist/client/RealtimeClient.d.ts.map +1 -1
  7. package/dist/client/RealtimeClient.js +65 -12
  8. package/dist/client/ZveltioClient.d.ts.map +1 -1
  9. package/dist/client/ZveltioClient.js +12 -1
  10. package/dist/client.d.ts +28 -2
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +41 -14
  13. package/dist/core.d.ts.map +1 -1
  14. package/dist/core.js +21 -3
  15. package/dist/crdt.d.ts.map +1 -1
  16. package/dist/crdt.js +11 -2
  17. package/dist/ddl/index.d.ts.map +1 -1
  18. package/dist/errors.d.ts +58 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +124 -0
  21. package/dist/extension/index.d.ts +459 -29
  22. package/dist/extension/index.d.ts.map +1 -1
  23. package/dist/extension/index.js +3 -0
  24. package/dist/extension/jsonb.d.ts +62 -0
  25. package/dist/extension/jsonb.d.ts.map +1 -0
  26. package/dist/extension/jsonb.js +64 -0
  27. package/dist/extension/multipart.d.ts +58 -0
  28. package/dist/extension/multipart.d.ts.map +1 -0
  29. package/dist/extension/multipart.js +61 -0
  30. package/dist/extension/numeric.d.ts +94 -0
  31. package/dist/extension/numeric.d.ts.map +1 -0
  32. package/dist/extension/numeric.js +162 -0
  33. package/dist/extension/permission-gate.d.ts +15 -0
  34. package/dist/extension/permission-gate.d.ts.map +1 -1
  35. package/dist/extension/permission-gate.js +33 -1
  36. package/dist/index.d.ts +3 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -0
  39. package/dist/local-store.d.ts +5 -0
  40. package/dist/local-store.d.ts.map +1 -1
  41. package/dist/local-store.js +62 -10
  42. package/dist/offline/index.d.ts +3 -3
  43. package/dist/offline/index.js +51 -15
  44. package/dist/publish/index.d.ts.map +1 -1
  45. package/dist/publish/index.js +6 -1
  46. package/dist/realtime.d.ts +18 -1
  47. package/dist/realtime.d.ts.map +1 -1
  48. package/dist/realtime.js +34 -3
  49. package/dist/rpc/index.d.ts.map +1 -1
  50. package/dist/rpc/index.js +2 -0
  51. package/dist/schema-codegen.d.ts +3 -1
  52. package/dist/schema-codegen.d.ts.map +1 -1
  53. package/dist/schema-codegen.js +41 -7
  54. package/dist/schema-watcher.d.ts +10 -2
  55. package/dist/schema-watcher.d.ts.map +1 -1
  56. package/dist/schema-watcher.js +30 -10
  57. package/dist/studio/index.d.ts +1 -0
  58. package/dist/studio/index.d.ts.map +1 -1
  59. package/dist/studio/index.js +3 -0
  60. package/dist/studio/slot-owner-registry.d.ts +13 -0
  61. package/dist/studio/slot-owner-registry.d.ts.map +1 -0
  62. package/dist/studio/slot-owner-registry.js +21 -0
  63. package/dist/svelte.d.ts +1 -1
  64. package/dist/svelte.d.ts.map +1 -1
  65. package/dist/svelte.js +4 -2
  66. package/dist/sync-manager.d.ts +30 -4
  67. package/dist/sync-manager.d.ts.map +1 -1
  68. package/dist/sync-manager.js +101 -15
  69. package/dist/testing/index.d.ts.map +1 -1
  70. package/dist/testing/index.js +23 -1
  71. package/dist/testing/with-test-db.d.ts.map +1 -1
  72. package/dist/testing/with-test-db.js +21 -14
  73. package/dist/tests/client.test.d.ts +2 -0
  74. package/dist/tests/client.test.d.ts.map +1 -0
  75. package/dist/tests/client.test.js +61 -0
  76. package/dist/tests/crdt-orset.test.d.ts +2 -0
  77. package/dist/tests/crdt-orset.test.d.ts.map +1 -0
  78. package/dist/tests/crdt-orset.test.js +23 -0
  79. package/dist/tests/local-store.test.js +44 -0
  80. package/dist/tests/multipart.test.d.ts +2 -0
  81. package/dist/tests/multipart.test.d.ts.map +1 -0
  82. package/dist/tests/multipart.test.js +37 -0
  83. package/dist/tests/offline-provider-crdt.test.d.ts +2 -0
  84. package/dist/tests/offline-provider-crdt.test.d.ts.map +1 -0
  85. package/dist/tests/offline-provider-crdt.test.js +119 -0
  86. package/dist/tests/realtime.test.d.ts +2 -0
  87. package/dist/tests/realtime.test.d.ts.map +1 -0
  88. package/dist/tests/realtime.test.js +284 -0
  89. package/dist/tests/sync-manager.test.d.ts +2 -0
  90. package/dist/tests/sync-manager.test.d.ts.map +1 -0
  91. package/dist/tests/sync-manager.test.js +65 -0
  92. package/dist/tests/with-test-db.test.d.ts +2 -0
  93. package/dist/tests/with-test-db.test.d.ts.map +1 -0
  94. package/dist/tests/with-test-db.test.js +57 -0
  95. package/dist/types/index.d.ts.map +1 -1
  96. package/dist/validate/index.d.ts +49 -0
  97. package/dist/validate/index.d.ts.map +1 -1
  98. package/dist/validate/index.js +503 -7
  99. package/dist/validate/shared-message-keys.d.ts +16 -0
  100. package/dist/validate/shared-message-keys.d.ts.map +1 -0
  101. package/dist/validate/shared-message-keys.js +227 -0
  102. package/package.json +7 -7
  103. package/dist/generate-types.d.ts +0 -37
  104. package/dist/generate-types.d.ts.map +0 -1
  105. 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;IAI3B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC;IAW7E,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;IAOxB,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"}
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"}
@@ -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;IAC/B,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,QAAQ,CAAoB;gBAExB,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa;IAMrD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IACtC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAWlD,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;IAMjB,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,eAAe,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAiCxE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,cAAc,CAAC,CAAC,EAAE,CAAC;CAY9D"}
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
- constructor(baseUrl: string);
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":"AAAA,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,aAAa,CAAyC;IAC9D,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,eAAe,CAAQ;gBAEnB,OAAO,EAAE,MAAM;IAI3B,OAAO,IAAI,IAAI;IA8Cf,UAAU,IAAI,IAAI;IAQlB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IAwBvF,cAAc,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI;IAKpD,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,YAAY;CAGrB"}
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
- constructor(baseUrl) {
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
- if (this.ws?.readyState === WebSocket.OPEN)
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
- this.ws = new WebSocket(wsUrl);
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
- this.ws.onopen = () => {
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
- this.ws.onmessage = (event) => {
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
- this.ws.onclose = () => {
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 (this.shouldReconnect) {
45
- setTimeout(() => this.connect(), this.reconnectDelay);
46
- this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);
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
- this.ws.onerror = () => {
50
- this.ws?.close();
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;IAOjC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY;IAKhC,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAIpF,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAKxD,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAQjE,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;IAQ7E,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"}
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
- this.realtime = new RealtimeClient(config.baseUrl);
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
- /** Storage helpers */
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>;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
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
- constructor(name, client) {
5
- this.name = name;
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', `/api/data/${this.name}${q ? `?${q}` : ''}`);
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', `/api/data/${this.name}/${id}`);
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', `/api/data/${this.name}`, data);
44
+ return this.client['request']('POST', this.path, data);
38
45
  }
39
46
  update(id, data) {
40
- return this.client['request']('PATCH', `/api/data/${this.name}/${id}`, data);
47
+ return this.client['request']('PATCH', `${this.path}/${encodeURIComponent(id)}`, data);
41
48
  }
42
49
  delete(id) {
43
- return this.client['request']('DELETE', `/api/data/${this.name}/${id}`);
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
- const text = await res.text().catch(() => '');
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 new Error(`Upload ${path} failed: ${res.status}`);
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
- /** Storage helpers */
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('folder', folder);
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 ? `?folder=${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
  }
@@ -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;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3E;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,GAAG,GAAG,IAAI,CAAC;IACjB,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAID,wBAAsB,eAAe,CAAC,CAAC,GAAG,GAAG,EAC3C,MAAM,EAAE,aAAa,EACrB,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,CAAC,EAAE,CAAC,CAGd;AAED,wBAAsB,WAAW,CAAC,CAAC,GAAG,GAAG,EACvC,MAAM,EAAE,aAAa,EACrB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAGnB;AAED,wBAAsB,YAAY,CAAC,CAAC,GAAG,GAAG,EACxC,MAAM,EAAE,aAAa,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GACf,OAAO,CAAC,CAAC,CAAC,CAGZ;AAED,wBAAsB,YAAY,CAAC,CAAC,GAAG,GAAG,EACxC,MAAM,EAAE,aAAa,EACrB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GACf,OAAO,CAAC,CAAC,CAAC,CAGZ;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,aAAa,EACrB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CAEf;AAID,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAO5E;AAED,wBAAsB,SAAS,CAC7B,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,SAAS,CAAC,CAGpB;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAG1E;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,SAAS,CAAC,CAGpB;AAID,wBAAsB,UAAU,CAC9B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,CAAC,CAGtB;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAG9F;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErF;AAID,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,KAAK,IAAI,GACrD,MAAM,IAAI,CAEZ"}
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
- const session = await client.auth.session();
32
- return { user: session?.user ?? null, session };
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, callback) {
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"crdt.d.ts","sourceRoot":"","sources":["../src/crdt.ts"],"names":[],"mappings":"AAOA,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,CACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,WAAW,CAMb;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAMlE;AAID,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,GAAG;IACnC,KAAK,EAAE,CAAC,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,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,CAUzE;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"}
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"}