@lastshotlabs/snapshot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1598 -0
- package/dist/cli.js +4529 -0
- package/dist/index.cjs +1135 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +396 -0
- package/dist/index.d.ts +396 -0
- package/dist/index.js +1106 -0
- package/dist/index.js.map +1 -0
- package/dist/vite.cjs +1186 -0
- package/dist/vite.d.cts +18 -0
- package/dist/vite.d.ts +18 -0
- package/dist/vite.js +1174 -0
- package/package.json +67 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { UseMutationResult, QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
interface TokenStorage {
|
|
5
|
+
get: () => string | null;
|
|
6
|
+
set: (token: string) => void;
|
|
7
|
+
clear: () => void;
|
|
8
|
+
getRefreshToken: () => string | null;
|
|
9
|
+
setRefreshToken: (token: string) => void;
|
|
10
|
+
clearRefreshToken: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare class ApiClient {
|
|
14
|
+
private readonly baseUrl;
|
|
15
|
+
private readonly authMode;
|
|
16
|
+
private readonly bearerToken;
|
|
17
|
+
private storage;
|
|
18
|
+
private onUnauthenticated;
|
|
19
|
+
private onForbidden;
|
|
20
|
+
private onMfaSetupRequired;
|
|
21
|
+
constructor(config: Pick<SnapshotConfig, 'apiUrl' | 'auth' | 'bearerToken' | 'onUnauthenticated' | 'onForbidden'> & {
|
|
22
|
+
onMfaSetupRequired?: () => void;
|
|
23
|
+
});
|
|
24
|
+
setStorage(storage: TokenStorage): void;
|
|
25
|
+
private buildHeaders;
|
|
26
|
+
private rawFetch;
|
|
27
|
+
private handleResponse;
|
|
28
|
+
private request;
|
|
29
|
+
get<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
30
|
+
post<T>(path: string, body: unknown, options?: RequestOptions): Promise<T>;
|
|
31
|
+
put<T>(path: string, body: unknown, options?: RequestOptions): Promise<T>;
|
|
32
|
+
patch<T>(path: string, body: unknown, options?: RequestOptions): Promise<T>;
|
|
33
|
+
delete<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
declare class ApiError extends Error {
|
|
37
|
+
readonly status: number;
|
|
38
|
+
readonly body: unknown;
|
|
39
|
+
constructor(status: number, body: unknown, message?: string);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type WsConfig = NonNullable<SnapshotConfig['ws']>;
|
|
43
|
+
declare class WebSocketManager<TEvents extends Record<string, unknown> = Record<string, unknown>> {
|
|
44
|
+
private ws;
|
|
45
|
+
private readonly rooms;
|
|
46
|
+
private readonly listeners;
|
|
47
|
+
private reconnectAttempts;
|
|
48
|
+
private reconnectTimer;
|
|
49
|
+
private destroyed;
|
|
50
|
+
private readonly url;
|
|
51
|
+
private readonly autoReconnect;
|
|
52
|
+
private readonly reconnectOnFocus;
|
|
53
|
+
private readonly maxReconnectAttempts;
|
|
54
|
+
private readonly reconnectBaseDelay;
|
|
55
|
+
private readonly reconnectMaxDelay;
|
|
56
|
+
private readonly onConnected;
|
|
57
|
+
private readonly onDisconnected;
|
|
58
|
+
private readonly onReconnecting;
|
|
59
|
+
private readonly onReconnectFailed;
|
|
60
|
+
constructor(config: WsConfig);
|
|
61
|
+
get isConnected(): boolean;
|
|
62
|
+
private handleVisibilityChange;
|
|
63
|
+
private connect;
|
|
64
|
+
private sendMessage;
|
|
65
|
+
private scheduleReconnect;
|
|
66
|
+
private clearReconnectTimer;
|
|
67
|
+
subscribe(room: string): void;
|
|
68
|
+
unsubscribe(room: string): void;
|
|
69
|
+
getRooms(): string[];
|
|
70
|
+
send(type: string, payload: unknown): void;
|
|
71
|
+
on<K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void): void;
|
|
72
|
+
off<K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void): void;
|
|
73
|
+
reconnect(): void;
|
|
74
|
+
disconnect(): void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface AuthUser {
|
|
78
|
+
id: string;
|
|
79
|
+
email: string;
|
|
80
|
+
[key: string]: unknown;
|
|
81
|
+
}
|
|
82
|
+
interface LoginBody {
|
|
83
|
+
email: string;
|
|
84
|
+
password: string;
|
|
85
|
+
}
|
|
86
|
+
interface RegisterBody {
|
|
87
|
+
email: string;
|
|
88
|
+
password: string;
|
|
89
|
+
[key: string]: unknown;
|
|
90
|
+
}
|
|
91
|
+
interface ForgotPasswordBody {
|
|
92
|
+
email: string;
|
|
93
|
+
}
|
|
94
|
+
type LoginVars = LoginBody & {
|
|
95
|
+
redirectTo?: string;
|
|
96
|
+
};
|
|
97
|
+
type RegisterVars = RegisterBody & {
|
|
98
|
+
redirectTo?: string;
|
|
99
|
+
};
|
|
100
|
+
interface LogoutVars {
|
|
101
|
+
redirectTo?: string;
|
|
102
|
+
}
|
|
103
|
+
type MfaMethod = 'totp' | 'emailOtp' | 'webauthn';
|
|
104
|
+
/** Raw login response shape from bunshot (includes MFA fields) */
|
|
105
|
+
interface LoginResponse {
|
|
106
|
+
token: string;
|
|
107
|
+
userId: string;
|
|
108
|
+
refreshToken?: string;
|
|
109
|
+
mfaRequired?: boolean;
|
|
110
|
+
mfaToken?: string;
|
|
111
|
+
mfaMethods?: MfaMethod[];
|
|
112
|
+
}
|
|
113
|
+
/** Returned by useLogin when mfaRequired is true */
|
|
114
|
+
interface MfaChallenge {
|
|
115
|
+
mfaToken: string;
|
|
116
|
+
mfaMethods: MfaMethod[];
|
|
117
|
+
}
|
|
118
|
+
/** useLogin resolves to either a user or an MFA challenge */
|
|
119
|
+
type LoginResult = AuthUser | MfaChallenge;
|
|
120
|
+
declare function isMfaChallenge(result: LoginResult): result is MfaChallenge;
|
|
121
|
+
interface MfaVerifyBody {
|
|
122
|
+
mfaToken: string;
|
|
123
|
+
code?: string;
|
|
124
|
+
method?: MfaMethod;
|
|
125
|
+
webauthnResponse?: unknown;
|
|
126
|
+
}
|
|
127
|
+
interface MfaSetupResponse {
|
|
128
|
+
secret: string;
|
|
129
|
+
uri: string;
|
|
130
|
+
}
|
|
131
|
+
interface MfaVerifySetupBody {
|
|
132
|
+
code: string;
|
|
133
|
+
}
|
|
134
|
+
interface MfaVerifySetupResponse {
|
|
135
|
+
message: string;
|
|
136
|
+
recoveryCodes: string[];
|
|
137
|
+
}
|
|
138
|
+
interface MfaDisableBody {
|
|
139
|
+
code: string;
|
|
140
|
+
}
|
|
141
|
+
interface MfaRecoveryCodesBody {
|
|
142
|
+
code: string;
|
|
143
|
+
}
|
|
144
|
+
interface MfaRecoveryCodesResponse {
|
|
145
|
+
recoveryCodes: string[];
|
|
146
|
+
}
|
|
147
|
+
interface MfaEmailOtpEnableResponse {
|
|
148
|
+
message: string;
|
|
149
|
+
setupToken: string;
|
|
150
|
+
}
|
|
151
|
+
interface MfaEmailOtpVerifySetupBody {
|
|
152
|
+
setupToken: string;
|
|
153
|
+
code: string;
|
|
154
|
+
}
|
|
155
|
+
interface MfaEmailOtpDisableBody {
|
|
156
|
+
code?: string;
|
|
157
|
+
password?: string;
|
|
158
|
+
}
|
|
159
|
+
interface MfaResendBody {
|
|
160
|
+
mfaToken: string;
|
|
161
|
+
}
|
|
162
|
+
interface MfaMethodsResponse {
|
|
163
|
+
methods: MfaMethod[];
|
|
164
|
+
}
|
|
165
|
+
interface ResetPasswordBody {
|
|
166
|
+
token: string;
|
|
167
|
+
password: string;
|
|
168
|
+
}
|
|
169
|
+
interface VerifyEmailBody {
|
|
170
|
+
token: string;
|
|
171
|
+
}
|
|
172
|
+
interface ResendVerificationBody {
|
|
173
|
+
email: string;
|
|
174
|
+
}
|
|
175
|
+
interface SetPasswordBody {
|
|
176
|
+
password: string;
|
|
177
|
+
currentPassword?: string;
|
|
178
|
+
}
|
|
179
|
+
interface DeleteAccountBody {
|
|
180
|
+
password?: string;
|
|
181
|
+
}
|
|
182
|
+
interface RefreshTokenBody {
|
|
183
|
+
refreshToken?: string;
|
|
184
|
+
}
|
|
185
|
+
interface RefreshTokenResponse {
|
|
186
|
+
token: string;
|
|
187
|
+
refreshToken?: string;
|
|
188
|
+
userId: string;
|
|
189
|
+
}
|
|
190
|
+
interface Session {
|
|
191
|
+
sessionId: string;
|
|
192
|
+
ipAddress?: string;
|
|
193
|
+
userAgent?: string;
|
|
194
|
+
createdAt: number;
|
|
195
|
+
lastActiveAt: number;
|
|
196
|
+
expiresAt: number;
|
|
197
|
+
isActive: boolean;
|
|
198
|
+
}
|
|
199
|
+
type OAuthProvider = 'google' | 'apple' | 'microsoft' | 'github';
|
|
200
|
+
interface OAuthExchangeBody {
|
|
201
|
+
code: string;
|
|
202
|
+
}
|
|
203
|
+
interface OAuthExchangeResponse {
|
|
204
|
+
token: string;
|
|
205
|
+
userId: string;
|
|
206
|
+
email?: string;
|
|
207
|
+
refreshToken?: string;
|
|
208
|
+
}
|
|
209
|
+
interface WebAuthnRegisterOptionsResponse {
|
|
210
|
+
options: unknown;
|
|
211
|
+
registrationToken: string;
|
|
212
|
+
}
|
|
213
|
+
interface WebAuthnRegisterBody {
|
|
214
|
+
registrationToken: string;
|
|
215
|
+
attestationResponse: unknown;
|
|
216
|
+
name?: string;
|
|
217
|
+
}
|
|
218
|
+
interface WebAuthnCredential {
|
|
219
|
+
credentialId: string;
|
|
220
|
+
name?: string;
|
|
221
|
+
createdAt: number;
|
|
222
|
+
transports?: string[];
|
|
223
|
+
}
|
|
224
|
+
interface PasskeyLoginOptionsBody {
|
|
225
|
+
email?: string;
|
|
226
|
+
}
|
|
227
|
+
interface PasskeyLoginOptionsResponse {
|
|
228
|
+
options: unknown;
|
|
229
|
+
passkeyToken: string;
|
|
230
|
+
}
|
|
231
|
+
interface PasskeyLoginBody {
|
|
232
|
+
passkeyToken: string;
|
|
233
|
+
assertionResponse: unknown;
|
|
234
|
+
}
|
|
235
|
+
interface RequestOptions {
|
|
236
|
+
headers?: Record<string, string>;
|
|
237
|
+
signal?: AbortSignal;
|
|
238
|
+
}
|
|
239
|
+
interface SocketHook<TEvents = Record<string, unknown>> {
|
|
240
|
+
isConnected: boolean;
|
|
241
|
+
send: (type: string, payload: unknown) => void;
|
|
242
|
+
subscribe: (room: string) => void;
|
|
243
|
+
unsubscribe: (room: string) => void;
|
|
244
|
+
getRooms: () => string[];
|
|
245
|
+
on: <K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) => void;
|
|
246
|
+
off: <K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) => void;
|
|
247
|
+
reconnect: () => void;
|
|
248
|
+
}
|
|
249
|
+
interface SnapshotConfig {
|
|
250
|
+
apiUrl: string;
|
|
251
|
+
/** `'cookie'` is the default and is the recommended mode for browser apps. */
|
|
252
|
+
auth?: 'cookie' | 'token';
|
|
253
|
+
/**
|
|
254
|
+
* Static API credential. Not a user session token. Do not use in browser
|
|
255
|
+
* deployments — emits a runtime warning in browser contexts.
|
|
256
|
+
*/
|
|
257
|
+
bearerToken?: string;
|
|
258
|
+
loginPath?: string;
|
|
259
|
+
homePath?: string;
|
|
260
|
+
forbiddenPath?: string;
|
|
261
|
+
mfaPath?: string;
|
|
262
|
+
mfaSetupPath?: string;
|
|
263
|
+
onUnauthenticated?: () => void;
|
|
264
|
+
onForbidden?: () => void;
|
|
265
|
+
/**
|
|
266
|
+
* When `auth: 'token'` is used, `'sessionStorage'` is the default (tab-scoped, survives
|
|
267
|
+
* refresh). `'memory'` is a stricter opt-in (loses state on page reload, does not share
|
|
268
|
+
* across tabs). `'localStorage'` is not recommended for auth tokens.
|
|
269
|
+
*/
|
|
270
|
+
tokenStorage?: 'localStorage' | 'sessionStorage' | 'memory';
|
|
271
|
+
tokenKey?: string;
|
|
272
|
+
staleTime?: number;
|
|
273
|
+
gcTime?: number;
|
|
274
|
+
retry?: number;
|
|
275
|
+
ws?: {
|
|
276
|
+
url: string;
|
|
277
|
+
autoReconnect?: boolean;
|
|
278
|
+
reconnectOnLogin?: boolean;
|
|
279
|
+
reconnectOnFocus?: boolean;
|
|
280
|
+
maxReconnectAttempts?: number;
|
|
281
|
+
reconnectBaseDelay?: number;
|
|
282
|
+
reconnectMaxDelay?: number;
|
|
283
|
+
onConnected?: () => void;
|
|
284
|
+
onDisconnected?: () => void;
|
|
285
|
+
onReconnecting?: (attempt: number) => void;
|
|
286
|
+
onReconnectFailed?: () => void;
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
interface SnapshotInstance<TWSEvents extends Record<string, unknown> = Record<string, unknown>> {
|
|
290
|
+
useUser: () => {
|
|
291
|
+
user: AuthUser | null;
|
|
292
|
+
isLoading: boolean;
|
|
293
|
+
isError: boolean;
|
|
294
|
+
};
|
|
295
|
+
useLogin: () => UseMutationResult<LoginResult, ApiError, LoginVars>;
|
|
296
|
+
useLogout: () => UseMutationResult<void, ApiError, LogoutVars | void>;
|
|
297
|
+
useRegister: () => UseMutationResult<AuthUser, ApiError, RegisterVars>;
|
|
298
|
+
useForgotPassword: () => UseMutationResult<void, ApiError, ForgotPasswordBody>;
|
|
299
|
+
useSocket: () => SocketHook<TWSEvents>;
|
|
300
|
+
useRoom: (room: string) => {
|
|
301
|
+
isSubscribed: boolean;
|
|
302
|
+
};
|
|
303
|
+
useRoomEvent: <T>(room: string, event: string, handler: (data: T) => void) => void;
|
|
304
|
+
useTheme: () => {
|
|
305
|
+
theme: 'light' | 'dark';
|
|
306
|
+
toggle: () => void;
|
|
307
|
+
set: (t: 'light' | 'dark') => void;
|
|
308
|
+
};
|
|
309
|
+
usePendingMfaChallenge: () => MfaChallenge | null;
|
|
310
|
+
useMfaVerify: () => UseMutationResult<AuthUser, ApiError, Omit<MfaVerifyBody, 'mfaToken'>>;
|
|
311
|
+
useMfaSetup: () => UseMutationResult<MfaSetupResponse, ApiError, void>;
|
|
312
|
+
useMfaVerifySetup: () => UseMutationResult<MfaVerifySetupResponse, ApiError, MfaVerifySetupBody>;
|
|
313
|
+
useMfaDisable: () => UseMutationResult<{
|
|
314
|
+
message: string;
|
|
315
|
+
}, ApiError, MfaDisableBody>;
|
|
316
|
+
useMfaRecoveryCodes: () => UseMutationResult<MfaRecoveryCodesResponse, ApiError, MfaRecoveryCodesBody>;
|
|
317
|
+
useMfaEmailOtpEnable: () => UseMutationResult<MfaEmailOtpEnableResponse, ApiError, void>;
|
|
318
|
+
useMfaEmailOtpVerifySetup: () => UseMutationResult<MfaVerifySetupResponse, ApiError, MfaEmailOtpVerifySetupBody>;
|
|
319
|
+
useMfaEmailOtpDisable: () => UseMutationResult<{
|
|
320
|
+
message: string;
|
|
321
|
+
}, ApiError, MfaEmailOtpDisableBody>;
|
|
322
|
+
useMfaResend: () => UseMutationResult<{
|
|
323
|
+
message: string;
|
|
324
|
+
}, ApiError, MfaResendBody>;
|
|
325
|
+
useMfaMethods: () => {
|
|
326
|
+
methods: MfaMethod[] | null;
|
|
327
|
+
isLoading: boolean;
|
|
328
|
+
isError: boolean;
|
|
329
|
+
};
|
|
330
|
+
isMfaChallenge: typeof isMfaChallenge;
|
|
331
|
+
useResetPassword: () => UseMutationResult<{
|
|
332
|
+
message: string;
|
|
333
|
+
}, ApiError, ResetPasswordBody>;
|
|
334
|
+
useVerifyEmail: () => UseMutationResult<{
|
|
335
|
+
message: string;
|
|
336
|
+
}, ApiError, VerifyEmailBody>;
|
|
337
|
+
useResendVerification: () => UseMutationResult<{
|
|
338
|
+
message: string;
|
|
339
|
+
}, ApiError, ResendVerificationBody>;
|
|
340
|
+
useSetPassword: () => UseMutationResult<{
|
|
341
|
+
message: string;
|
|
342
|
+
}, ApiError, SetPasswordBody>;
|
|
343
|
+
useDeleteAccount: () => UseMutationResult<void, ApiError, DeleteAccountBody | void>;
|
|
344
|
+
useCancelDeletion: () => UseMutationResult<{
|
|
345
|
+
message: string;
|
|
346
|
+
}, ApiError, void>;
|
|
347
|
+
useRefreshToken: () => UseMutationResult<RefreshTokenResponse, ApiError, RefreshTokenBody | void>;
|
|
348
|
+
useSessions: () => {
|
|
349
|
+
sessions: Session[];
|
|
350
|
+
isLoading: boolean;
|
|
351
|
+
isError: boolean;
|
|
352
|
+
};
|
|
353
|
+
useRevokeSession: () => UseMutationResult<void, ApiError, string>;
|
|
354
|
+
useOAuthExchange: () => UseMutationResult<OAuthExchangeResponse, ApiError, OAuthExchangeBody>;
|
|
355
|
+
useOAuthUnlink: () => UseMutationResult<void, ApiError, OAuthProvider>;
|
|
356
|
+
getOAuthUrl: (provider: OAuthProvider) => string;
|
|
357
|
+
getLinkUrl: (provider: OAuthProvider) => string;
|
|
358
|
+
useWebAuthnRegisterOptions: () => UseMutationResult<WebAuthnRegisterOptionsResponse, ApiError, void>;
|
|
359
|
+
useWebAuthnRegister: () => UseMutationResult<{
|
|
360
|
+
message: string;
|
|
361
|
+
}, ApiError, WebAuthnRegisterBody>;
|
|
362
|
+
useWebAuthnCredentials: () => {
|
|
363
|
+
credentials: WebAuthnCredential[];
|
|
364
|
+
isLoading: boolean;
|
|
365
|
+
isError: boolean;
|
|
366
|
+
};
|
|
367
|
+
useWebAuthnRemoveCredential: () => UseMutationResult<{
|
|
368
|
+
message: string;
|
|
369
|
+
}, ApiError, string>;
|
|
370
|
+
useWebAuthnDisable: () => UseMutationResult<{
|
|
371
|
+
message: string;
|
|
372
|
+
}, ApiError, void>;
|
|
373
|
+
usePasskeyLoginOptions: () => UseMutationResult<PasskeyLoginOptionsResponse, ApiError, PasskeyLoginOptionsBody>;
|
|
374
|
+
usePasskeyLogin: () => UseMutationResult<LoginResult, ApiError, PasskeyLoginBody>;
|
|
375
|
+
api: ApiClient;
|
|
376
|
+
tokenStorage: TokenStorage;
|
|
377
|
+
queryClient: QueryClient;
|
|
378
|
+
useWebSocketManager: () => WebSocketManager<TWSEvents> | null;
|
|
379
|
+
protectedBeforeLoad: (ctx: {
|
|
380
|
+
context: {
|
|
381
|
+
queryClient: QueryClient;
|
|
382
|
+
};
|
|
383
|
+
}) => Promise<void>;
|
|
384
|
+
guestBeforeLoad: (ctx: {
|
|
385
|
+
context: {
|
|
386
|
+
queryClient: QueryClient;
|
|
387
|
+
};
|
|
388
|
+
}) => Promise<void>;
|
|
389
|
+
QueryProvider: React.FC<{
|
|
390
|
+
children: React.ReactNode;
|
|
391
|
+
}>;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
declare function createSnapshot<TWSEvents extends Record<string, unknown> = Record<string, unknown>>(config: SnapshotConfig): SnapshotInstance<TWSEvents>;
|
|
395
|
+
|
|
396
|
+
export { ApiError, type AuthUser, type DeleteAccountBody, type ForgotPasswordBody, type LoginBody, type LoginResponse, type LoginResult, type LoginVars, type LogoutVars, type MfaChallenge, type MfaDisableBody, type MfaEmailOtpDisableBody, type MfaEmailOtpEnableResponse, type MfaEmailOtpVerifySetupBody, type MfaMethod, type MfaMethodsResponse, type MfaRecoveryCodesBody, type MfaRecoveryCodesResponse, type MfaResendBody, type MfaSetupResponse, type MfaVerifyBody, type MfaVerifySetupBody, type MfaVerifySetupResponse, type OAuthExchangeBody, type OAuthExchangeResponse, type OAuthProvider, type PasskeyLoginBody, type PasskeyLoginOptionsBody, type PasskeyLoginOptionsResponse, type RefreshTokenBody, type RefreshTokenResponse, type RegisterBody, type RegisterVars, type RequestOptions, type ResendVerificationBody, type ResetPasswordBody, type Session, type SetPasswordBody, type SnapshotConfig, type SnapshotInstance, type SocketHook, type TokenStorage, type VerifyEmailBody, type WebAuthnCredential, type WebAuthnRegisterBody, type WebAuthnRegisterOptionsResponse, WebSocketManager, createSnapshot, isMfaChallenge };
|