@spacelr/sdk 0.1.4 → 0.1.6

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/index.d.mts CHANGED
@@ -250,21 +250,39 @@ interface UploadProgress {
250
250
  }
251
251
 
252
252
  type RefreshCallback = (refreshToken: string) => Promise<StoredTokens>;
253
+ type AuthLostReason = 'refresh-failed' | 'unauthorized';
254
+ type TokenRefreshedListener = (tokens: StoredTokens) => void;
255
+ type AuthLostListener = (reason: AuthLostReason) => void;
253
256
  declare class TokenManager {
254
257
  private storage;
255
258
  private refreshBufferSeconds;
256
259
  private refreshCallback;
257
260
  private refreshPromise;
261
+ private tokenRefreshedListeners;
262
+ private authLostListeners;
263
+ private authLostEmitted;
258
264
  constructor(storage?: TokenStorage, refreshBufferSeconds?: number);
259
265
  setRefreshCallback(callback: RefreshCallback): void;
260
266
  getAccessToken(): Promise<string | null>;
261
267
  setTokens(tokens: StoredTokens): Promise<void>;
262
268
  clearTokens(): Promise<void>;
263
269
  getStoredTokens(): Promise<StoredTokens | null>;
270
+ /**
271
+ * Force a refresh using the current stored refresh token.
272
+ * Returns the new access token, or null if refresh is not possible or fails.
273
+ * A rejecting custom `TokenStorage.getTokens()` is treated as "no tokens"
274
+ * so callers (notably `HttpClient`'s 401 retry path) see a clean `null`
275
+ * rather than an exception that would get wrapped as a network error.
276
+ */
277
+ forceRefresh(): Promise<string | null>;
278
+ onTokenRefreshed(listener: TokenRefreshedListener): () => void;
279
+ onAuthLost(listener: AuthLostListener): () => void;
280
+ emitAuthLost(reason: AuthLostReason): void;
264
281
  private isTokenExpired;
265
282
  private shouldRefresh;
266
283
  private tryRefresh;
267
284
  private executeRefresh;
285
+ private emitTokenRefreshed;
268
286
  }
269
287
 
270
288
  interface HttpRequestOptions {
@@ -282,10 +300,22 @@ declare class HttpClient {
282
300
  private tokenManager;
283
301
  constructor(config: SpacelrClientConfig, tokenManager: TokenManager);
284
302
  request<T>(options: HttpRequestOptions): Promise<T>;
303
+ private requestWithRetry;
285
304
  uploadForm<T>(path: string, formData: FormData, onProgress?: (event: {
286
305
  loaded: number;
287
306
  total: number;
288
307
  }) => void): Promise<T>;
308
+ private uploadFormWithRetry;
309
+ /**
310
+ * Shared handler for a 401 on an authenticated request. Returns true if the
311
+ * caller should retry with a refreshed token. 403 is never routed here —
312
+ * it means "forbidden for this action" and must not trigger logout.
313
+ *
314
+ * `emitAuthLost('unauthorized')` is deduped inside TokenManager, so it's a
315
+ * no-op if `executeRefresh` already emitted 'refresh-failed'.
316
+ */
317
+ private recoverFromAuthFailure;
318
+ private uploadFormOnce;
289
319
  private uploadFormWithProgress;
290
320
  private buildUrl;
291
321
  private buildHeaders;
@@ -335,6 +365,7 @@ declare class SpacelrEmailVerificationRequiredError extends SpacelrError {
335
365
  constructor(emailSent: boolean, details?: Record<string, unknown>);
336
366
  }
337
367
 
368
+ type ConnectionState = 'connected' | 'reconnecting' | 'disconnected';
338
369
  interface DatabaseChangeEvent {
339
370
  type: 'insert' | 'update' | 'delete';
340
371
  projectId: string;
@@ -346,6 +377,13 @@ interface DatabaseChangeEvent {
346
377
  interface RealtimeConfig {
347
378
  baseUrl: string;
348
379
  getToken: () => Promise<string | null>;
380
+ /**
381
+ * Optional subscription to token-refresh events. When wired, the realtime
382
+ * client will push the fresh access token to the server via a
383
+ * `reauthenticate` message so the open socket stays authenticated without
384
+ * dropping the connection.
385
+ */
386
+ onTokenRefreshed?: (listener: (accessToken: string) => void) => () => void;
349
387
  }
350
388
  declare class RealtimeClient {
351
389
  private socket;
@@ -353,13 +391,42 @@ declare class RealtimeClient {
353
391
  private subscriptions;
354
392
  private connecting;
355
393
  private roomWhereMap;
394
+ private unsubscribeFromTokenRefreshed;
395
+ private onVisibilityChange;
396
+ private onOnline;
397
+ private disposed;
398
+ private rebuildRetryTimer;
399
+ private connectionState;
400
+ private connectionStateListeners;
356
401
  constructor(config: RealtimeConfig);
357
402
  subscribe(projectId: string, collectionName: string, callback: (event: DatabaseChangeEvent) => void, onError?: (error: Error) => void, where?: Record<string, string | number | boolean>): Promise<() => void>;
403
+ /**
404
+ * Tear down the realtime client permanently. After this call the instance
405
+ * is disposed — subsequent `subscribe()` calls will not re-establish a
406
+ * connection. Create a new `RealtimeClient` (via `createClient`) if you
407
+ * need to reconnect after a logout.
408
+ */
358
409
  disconnect(): void;
410
+ getConnectionState(): ConnectionState;
411
+ onConnectionStateChanged(listener: (state: ConnectionState) => void): () => void;
412
+ private setConnectionState;
359
413
  private buildRoomKey;
360
414
  private ensureConnected;
361
415
  private connect;
362
416
  private eventMatchesRoom;
417
+ /**
418
+ * Tear down the current socket and create a fresh one. Used by both
419
+ * `reconnect_failed` (socket.io gave up) and the visibility/online wake-up
420
+ * listeners. Preserves the `subscriptions` map so existing rooms can be
421
+ * replayed to the server on the new connection. If the rebuild itself
422
+ * fails it schedules one retry after 5 s — beyond that we rely on the
423
+ * next wake-up event (visibility/online) to try again.
424
+ */
425
+ private rebuildSocket;
426
+ private handlePostRebuild;
427
+ private scheduleRebuildRetry;
428
+ private ensureWakeListeners;
429
+ private detachWakeListeners;
363
430
  private resubscribeAll;
364
431
  }
365
432
 
@@ -597,14 +664,81 @@ declare class NotificationsModule {
597
664
  private urlBase64ToUint8Array;
598
665
  }
599
666
 
667
+ interface FunctionInvokeOptions {
668
+ secret: string;
669
+ payload?: Record<string, unknown>;
670
+ }
671
+ interface FunctionInvokeResult {
672
+ success: boolean;
673
+ executionId?: string;
674
+ error?: string;
675
+ }
676
+ declare class FunctionsModule {
677
+ private http;
678
+ constructor(http: HttpClient);
679
+ /**
680
+ * Invoke a function via webhook trigger.
681
+ * Calls POST /api/v1/functions/:projectId/:functionId/invoke
682
+ * with X-Webhook-Secret header.
683
+ */
684
+ invoke(projectId: string, functionId: string, options: FunctionInvokeOptions): Promise<FunctionInvokeResult>;
685
+ }
686
+
600
687
  interface SpacelrClient {
601
688
  readonly auth: AuthModule;
602
689
  readonly storage: StorageModule;
603
690
  readonly db: DatabaseModule;
604
691
  readonly notifications: NotificationsModule;
692
+ readonly functions: FunctionsModule;
693
+ /**
694
+ * Store auth tokens externally (e.g. obtained via the auth-components
695
+ * library that bypasses the SDK). Makes the tokens available to HTTP +
696
+ * realtime clients. Refresh is on-demand: the SDK will refresh the
697
+ * access token when it next makes a request and the token is within the
698
+ * expiry buffer (or on a 401 retry).
699
+ */
700
+ setTokens(tokens: StoredTokens): Promise<void>;
701
+ /** Clear stored tokens and reset auth-loss state. */
702
+ clearTokens(): Promise<void>;
605
703
  /** Disconnect realtime WebSocket (if connected) */
606
704
  disconnect(): void;
705
+ /**
706
+ * Subscribe to auth loss. Fires in three situations:
707
+ * - `'refresh-failed'` — a refresh call was rejected by the server
708
+ * (refresh token revoked or expired). Note: this can also fire from a
709
+ * *background* refresh triggered inside the expiry buffer window, at
710
+ * which point the current access token may still be valid for up to
711
+ * `refreshBufferSeconds` (default 60). Treat the session as over anyway;
712
+ * the refresh token is dead.
713
+ * - `'unauthorized'` — an authenticated request came back 401 and no
714
+ * fresh token could be produced (no refresh token, or the retry after
715
+ * a successful refresh was itself 401).
716
+ *
717
+ * Typical consumer reaction: clear UI state and show the login screen.
718
+ * The event is deduped until `setTokens`/`clearTokens` is called again.
719
+ */
720
+ onAuthLost(listener: (reason: AuthLostReason) => void): () => void;
721
+ /** Subscribe to successful token refreshes. */
722
+ onTokenRefreshed(listener: (tokens: StoredTokens) => void): () => void;
723
+ /**
724
+ * Subscribe to realtime socket connection-state changes. Fires on every
725
+ * transition (dedup: identical consecutive states are skipped). Returns
726
+ * an unsubscribe function.
727
+ *
728
+ * States:
729
+ * - `'disconnected'` — initial state before the first subscribe, or after
730
+ * the SDK has torn the realtime socket down (e.g. on logout via the
731
+ * internal `realtime.disconnect()`). This is a terminal state for the
732
+ * current realtime client; reconnect happens on the next `subscribe()`.
733
+ * - `'reconnecting'` — connecting or rebuilding the socket (initial
734
+ * connect, socket drop, `reconnect_failed` rebuild, or a wake-up event
735
+ * after suspend).
736
+ * - `'connected'` — authenticated and actively listening for events.
737
+ */
738
+ onConnectionStateChanged(listener: (state: ConnectionState) => void): () => void;
739
+ /** Read the current realtime socket state without waiting for an event. */
740
+ getConnectionState(): ConnectionState;
607
741
  }
608
742
  declare function createClient(config: SpacelrClientConfig): SpacelrClient;
609
743
 
610
- export { type ApiResponse, type AuthorizationUrlParams, BrowserTokenStorage, CodeChallengeMethod, type DatabaseChangeEvent, type DownloadUrlResponse, type ExchangeCodeParams, type FileInfo, type FileListResponse, FileVisibility, GrantType, type InitMultipartUploadParams, type InitMultipartUploadResponse, type JWK, type JWKSResponse, type ListFilesParams, type LoginParams, type LoginResponse, MemoryTokenStorage, type OpenIDConfiguration, type PKCEChallenge, type PartEtag, type PushSubscriptionInfo, type QuotaInfo, type RegisterParams, type RegisterResponse, type ShareFileParams, SharePermission, SpacelrAuthError, type SpacelrClient, type SpacelrClientConfig, SpacelrEmailVerificationRequiredError, SpacelrError, SpacelrNetworkError, SpacelrTimeoutError, SpacelrTwoFactorRequiredError, type StoredTokens, type SubscribeHandlers, type TokenResponse, type TokenStorage, type TwoFactorResponse, type TwoFactorVerifyParams, type UnshareFileParams, type UploadFileParams, type UploadLargeFileParams, type UploadProgress, type UserInfo, type UserProfile, type VapidKeyResponse, createClient, generatePKCEChallenge };
744
+ export { type ApiResponse, type AuthLostReason, type AuthorizationUrlParams, BrowserTokenStorage, CodeChallengeMethod, type ConnectionState, type DatabaseChangeEvent, type DownloadUrlResponse, type ExchangeCodeParams, type FileInfo, type FileListResponse, FileVisibility, type FunctionInvokeOptions, type FunctionInvokeResult, GrantType, type InitMultipartUploadParams, type InitMultipartUploadResponse, type JWK, type JWKSResponse, type ListFilesParams, type LoginParams, type LoginResponse, MemoryTokenStorage, type OpenIDConfiguration, type PKCEChallenge, type PartEtag, type PushSubscriptionInfo, type QuotaInfo, type RegisterParams, type RegisterResponse, type ShareFileParams, SharePermission, SpacelrAuthError, type SpacelrClient, type SpacelrClientConfig, SpacelrEmailVerificationRequiredError, SpacelrError, SpacelrNetworkError, SpacelrTimeoutError, SpacelrTwoFactorRequiredError, type StoredTokens, type SubscribeHandlers, type TokenResponse, type TokenStorage, type TwoFactorResponse, type TwoFactorVerifyParams, type UnshareFileParams, type UploadFileParams, type UploadLargeFileParams, type UploadProgress, type UserInfo, type UserProfile, type VapidKeyResponse, createClient, generatePKCEChallenge };
package/dist/index.d.ts CHANGED
@@ -250,21 +250,39 @@ interface UploadProgress {
250
250
  }
251
251
 
252
252
  type RefreshCallback = (refreshToken: string) => Promise<StoredTokens>;
253
+ type AuthLostReason = 'refresh-failed' | 'unauthorized';
254
+ type TokenRefreshedListener = (tokens: StoredTokens) => void;
255
+ type AuthLostListener = (reason: AuthLostReason) => void;
253
256
  declare class TokenManager {
254
257
  private storage;
255
258
  private refreshBufferSeconds;
256
259
  private refreshCallback;
257
260
  private refreshPromise;
261
+ private tokenRefreshedListeners;
262
+ private authLostListeners;
263
+ private authLostEmitted;
258
264
  constructor(storage?: TokenStorage, refreshBufferSeconds?: number);
259
265
  setRefreshCallback(callback: RefreshCallback): void;
260
266
  getAccessToken(): Promise<string | null>;
261
267
  setTokens(tokens: StoredTokens): Promise<void>;
262
268
  clearTokens(): Promise<void>;
263
269
  getStoredTokens(): Promise<StoredTokens | null>;
270
+ /**
271
+ * Force a refresh using the current stored refresh token.
272
+ * Returns the new access token, or null if refresh is not possible or fails.
273
+ * A rejecting custom `TokenStorage.getTokens()` is treated as "no tokens"
274
+ * so callers (notably `HttpClient`'s 401 retry path) see a clean `null`
275
+ * rather than an exception that would get wrapped as a network error.
276
+ */
277
+ forceRefresh(): Promise<string | null>;
278
+ onTokenRefreshed(listener: TokenRefreshedListener): () => void;
279
+ onAuthLost(listener: AuthLostListener): () => void;
280
+ emitAuthLost(reason: AuthLostReason): void;
264
281
  private isTokenExpired;
265
282
  private shouldRefresh;
266
283
  private tryRefresh;
267
284
  private executeRefresh;
285
+ private emitTokenRefreshed;
268
286
  }
269
287
 
270
288
  interface HttpRequestOptions {
@@ -282,10 +300,22 @@ declare class HttpClient {
282
300
  private tokenManager;
283
301
  constructor(config: SpacelrClientConfig, tokenManager: TokenManager);
284
302
  request<T>(options: HttpRequestOptions): Promise<T>;
303
+ private requestWithRetry;
285
304
  uploadForm<T>(path: string, formData: FormData, onProgress?: (event: {
286
305
  loaded: number;
287
306
  total: number;
288
307
  }) => void): Promise<T>;
308
+ private uploadFormWithRetry;
309
+ /**
310
+ * Shared handler for a 401 on an authenticated request. Returns true if the
311
+ * caller should retry with a refreshed token. 403 is never routed here —
312
+ * it means "forbidden for this action" and must not trigger logout.
313
+ *
314
+ * `emitAuthLost('unauthorized')` is deduped inside TokenManager, so it's a
315
+ * no-op if `executeRefresh` already emitted 'refresh-failed'.
316
+ */
317
+ private recoverFromAuthFailure;
318
+ private uploadFormOnce;
289
319
  private uploadFormWithProgress;
290
320
  private buildUrl;
291
321
  private buildHeaders;
@@ -335,6 +365,7 @@ declare class SpacelrEmailVerificationRequiredError extends SpacelrError {
335
365
  constructor(emailSent: boolean, details?: Record<string, unknown>);
336
366
  }
337
367
 
368
+ type ConnectionState = 'connected' | 'reconnecting' | 'disconnected';
338
369
  interface DatabaseChangeEvent {
339
370
  type: 'insert' | 'update' | 'delete';
340
371
  projectId: string;
@@ -346,6 +377,13 @@ interface DatabaseChangeEvent {
346
377
  interface RealtimeConfig {
347
378
  baseUrl: string;
348
379
  getToken: () => Promise<string | null>;
380
+ /**
381
+ * Optional subscription to token-refresh events. When wired, the realtime
382
+ * client will push the fresh access token to the server via a
383
+ * `reauthenticate` message so the open socket stays authenticated without
384
+ * dropping the connection.
385
+ */
386
+ onTokenRefreshed?: (listener: (accessToken: string) => void) => () => void;
349
387
  }
350
388
  declare class RealtimeClient {
351
389
  private socket;
@@ -353,13 +391,42 @@ declare class RealtimeClient {
353
391
  private subscriptions;
354
392
  private connecting;
355
393
  private roomWhereMap;
394
+ private unsubscribeFromTokenRefreshed;
395
+ private onVisibilityChange;
396
+ private onOnline;
397
+ private disposed;
398
+ private rebuildRetryTimer;
399
+ private connectionState;
400
+ private connectionStateListeners;
356
401
  constructor(config: RealtimeConfig);
357
402
  subscribe(projectId: string, collectionName: string, callback: (event: DatabaseChangeEvent) => void, onError?: (error: Error) => void, where?: Record<string, string | number | boolean>): Promise<() => void>;
403
+ /**
404
+ * Tear down the realtime client permanently. After this call the instance
405
+ * is disposed — subsequent `subscribe()` calls will not re-establish a
406
+ * connection. Create a new `RealtimeClient` (via `createClient`) if you
407
+ * need to reconnect after a logout.
408
+ */
358
409
  disconnect(): void;
410
+ getConnectionState(): ConnectionState;
411
+ onConnectionStateChanged(listener: (state: ConnectionState) => void): () => void;
412
+ private setConnectionState;
359
413
  private buildRoomKey;
360
414
  private ensureConnected;
361
415
  private connect;
362
416
  private eventMatchesRoom;
417
+ /**
418
+ * Tear down the current socket and create a fresh one. Used by both
419
+ * `reconnect_failed` (socket.io gave up) and the visibility/online wake-up
420
+ * listeners. Preserves the `subscriptions` map so existing rooms can be
421
+ * replayed to the server on the new connection. If the rebuild itself
422
+ * fails it schedules one retry after 5 s — beyond that we rely on the
423
+ * next wake-up event (visibility/online) to try again.
424
+ */
425
+ private rebuildSocket;
426
+ private handlePostRebuild;
427
+ private scheduleRebuildRetry;
428
+ private ensureWakeListeners;
429
+ private detachWakeListeners;
363
430
  private resubscribeAll;
364
431
  }
365
432
 
@@ -597,14 +664,81 @@ declare class NotificationsModule {
597
664
  private urlBase64ToUint8Array;
598
665
  }
599
666
 
667
+ interface FunctionInvokeOptions {
668
+ secret: string;
669
+ payload?: Record<string, unknown>;
670
+ }
671
+ interface FunctionInvokeResult {
672
+ success: boolean;
673
+ executionId?: string;
674
+ error?: string;
675
+ }
676
+ declare class FunctionsModule {
677
+ private http;
678
+ constructor(http: HttpClient);
679
+ /**
680
+ * Invoke a function via webhook trigger.
681
+ * Calls POST /api/v1/functions/:projectId/:functionId/invoke
682
+ * with X-Webhook-Secret header.
683
+ */
684
+ invoke(projectId: string, functionId: string, options: FunctionInvokeOptions): Promise<FunctionInvokeResult>;
685
+ }
686
+
600
687
  interface SpacelrClient {
601
688
  readonly auth: AuthModule;
602
689
  readonly storage: StorageModule;
603
690
  readonly db: DatabaseModule;
604
691
  readonly notifications: NotificationsModule;
692
+ readonly functions: FunctionsModule;
693
+ /**
694
+ * Store auth tokens externally (e.g. obtained via the auth-components
695
+ * library that bypasses the SDK). Makes the tokens available to HTTP +
696
+ * realtime clients. Refresh is on-demand: the SDK will refresh the
697
+ * access token when it next makes a request and the token is within the
698
+ * expiry buffer (or on a 401 retry).
699
+ */
700
+ setTokens(tokens: StoredTokens): Promise<void>;
701
+ /** Clear stored tokens and reset auth-loss state. */
702
+ clearTokens(): Promise<void>;
605
703
  /** Disconnect realtime WebSocket (if connected) */
606
704
  disconnect(): void;
705
+ /**
706
+ * Subscribe to auth loss. Fires in three situations:
707
+ * - `'refresh-failed'` — a refresh call was rejected by the server
708
+ * (refresh token revoked or expired). Note: this can also fire from a
709
+ * *background* refresh triggered inside the expiry buffer window, at
710
+ * which point the current access token may still be valid for up to
711
+ * `refreshBufferSeconds` (default 60). Treat the session as over anyway;
712
+ * the refresh token is dead.
713
+ * - `'unauthorized'` — an authenticated request came back 401 and no
714
+ * fresh token could be produced (no refresh token, or the retry after
715
+ * a successful refresh was itself 401).
716
+ *
717
+ * Typical consumer reaction: clear UI state and show the login screen.
718
+ * The event is deduped until `setTokens`/`clearTokens` is called again.
719
+ */
720
+ onAuthLost(listener: (reason: AuthLostReason) => void): () => void;
721
+ /** Subscribe to successful token refreshes. */
722
+ onTokenRefreshed(listener: (tokens: StoredTokens) => void): () => void;
723
+ /**
724
+ * Subscribe to realtime socket connection-state changes. Fires on every
725
+ * transition (dedup: identical consecutive states are skipped). Returns
726
+ * an unsubscribe function.
727
+ *
728
+ * States:
729
+ * - `'disconnected'` — initial state before the first subscribe, or after
730
+ * the SDK has torn the realtime socket down (e.g. on logout via the
731
+ * internal `realtime.disconnect()`). This is a terminal state for the
732
+ * current realtime client; reconnect happens on the next `subscribe()`.
733
+ * - `'reconnecting'` — connecting or rebuilding the socket (initial
734
+ * connect, socket drop, `reconnect_failed` rebuild, or a wake-up event
735
+ * after suspend).
736
+ * - `'connected'` — authenticated and actively listening for events.
737
+ */
738
+ onConnectionStateChanged(listener: (state: ConnectionState) => void): () => void;
739
+ /** Read the current realtime socket state without waiting for an event. */
740
+ getConnectionState(): ConnectionState;
607
741
  }
608
742
  declare function createClient(config: SpacelrClientConfig): SpacelrClient;
609
743
 
610
- export { type ApiResponse, type AuthorizationUrlParams, BrowserTokenStorage, CodeChallengeMethod, type DatabaseChangeEvent, type DownloadUrlResponse, type ExchangeCodeParams, type FileInfo, type FileListResponse, FileVisibility, GrantType, type InitMultipartUploadParams, type InitMultipartUploadResponse, type JWK, type JWKSResponse, type ListFilesParams, type LoginParams, type LoginResponse, MemoryTokenStorage, type OpenIDConfiguration, type PKCEChallenge, type PartEtag, type PushSubscriptionInfo, type QuotaInfo, type RegisterParams, type RegisterResponse, type ShareFileParams, SharePermission, SpacelrAuthError, type SpacelrClient, type SpacelrClientConfig, SpacelrEmailVerificationRequiredError, SpacelrError, SpacelrNetworkError, SpacelrTimeoutError, SpacelrTwoFactorRequiredError, type StoredTokens, type SubscribeHandlers, type TokenResponse, type TokenStorage, type TwoFactorResponse, type TwoFactorVerifyParams, type UnshareFileParams, type UploadFileParams, type UploadLargeFileParams, type UploadProgress, type UserInfo, type UserProfile, type VapidKeyResponse, createClient, generatePKCEChallenge };
744
+ export { type ApiResponse, type AuthLostReason, type AuthorizationUrlParams, BrowserTokenStorage, CodeChallengeMethod, type ConnectionState, type DatabaseChangeEvent, type DownloadUrlResponse, type ExchangeCodeParams, type FileInfo, type FileListResponse, FileVisibility, type FunctionInvokeOptions, type FunctionInvokeResult, GrantType, type InitMultipartUploadParams, type InitMultipartUploadResponse, type JWK, type JWKSResponse, type ListFilesParams, type LoginParams, type LoginResponse, MemoryTokenStorage, type OpenIDConfiguration, type PKCEChallenge, type PartEtag, type PushSubscriptionInfo, type QuotaInfo, type RegisterParams, type RegisterResponse, type ShareFileParams, SharePermission, SpacelrAuthError, type SpacelrClient, type SpacelrClientConfig, SpacelrEmailVerificationRequiredError, SpacelrError, SpacelrNetworkError, SpacelrTimeoutError, SpacelrTwoFactorRequiredError, type StoredTokens, type SubscribeHandlers, type TokenResponse, type TokenStorage, type TwoFactorResponse, type TwoFactorVerifyParams, type UnshareFileParams, type UploadFileParams, type UploadLargeFileParams, type UploadProgress, type UserInfo, type UserProfile, type VapidKeyResponse, createClient, generatePKCEChallenge };