@sparkvault/sdk-mobile 0.1.3

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 (82) hide show
  1. package/README.md +186 -0
  2. package/dist/auth.d.ts +74 -0
  3. package/dist/auth.js +515 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/billing.d.ts +21 -0
  6. package/dist/billing.js +10 -0
  7. package/dist/billing.js.map +1 -0
  8. package/dist/client.d.ts +27 -0
  9. package/dist/client.js +36 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/config.d.ts +39 -0
  12. package/dist/config.js +69 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/encoding.d.ts +7 -0
  15. package/dist/encoding.js +113 -0
  16. package/dist/encoding.js.map +1 -0
  17. package/dist/entropy.d.ts +18 -0
  18. package/dist/entropy.js +35 -0
  19. package/dist/entropy.js.map +1 -0
  20. package/dist/errors.d.ts +46 -0
  21. package/dist/errors.js +72 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/folders.d.ts +15 -0
  24. package/dist/folders.js +54 -0
  25. package/dist/folders.js.map +1 -0
  26. package/dist/health.d.ts +19 -0
  27. package/dist/health.js +60 -0
  28. package/dist/health.js.map +1 -0
  29. package/dist/http.d.ts +45 -0
  30. package/dist/http.js +351 -0
  31. package/dist/http.js.map +1 -0
  32. package/dist/identity-dialog.d.ts +19 -0
  33. package/dist/identity-dialog.js +656 -0
  34. package/dist/identity-dialog.js.map +1 -0
  35. package/dist/index.d.ts +24 -0
  36. package/dist/index.js +15 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/ingots.d.ts +99 -0
  39. package/dist/ingots.js +365 -0
  40. package/dist/ingots.js.map +1 -0
  41. package/dist/mutex.d.ts +6 -0
  42. package/dist/mutex.js +20 -0
  43. package/dist/mutex.js.map +1 -0
  44. package/dist/push-tokens.d.ts +12 -0
  45. package/dist/push-tokens.js +15 -0
  46. package/dist/push-tokens.js.map +1 -0
  47. package/dist/sparks.d.ts +39 -0
  48. package/dist/sparks.js +32 -0
  49. package/dist/sparks.js.map +1 -0
  50. package/dist/tus.d.ts +24 -0
  51. package/dist/tus.js +202 -0
  52. package/dist/tus.js.map +1 -0
  53. package/dist/types.d.ts +406 -0
  54. package/dist/types.js +2 -0
  55. package/dist/types.js.map +1 -0
  56. package/dist/validation.d.ts +5 -0
  57. package/dist/validation.js +45 -0
  58. package/dist/validation.js.map +1 -0
  59. package/dist/vaults.d.ts +94 -0
  60. package/dist/vaults.js +106 -0
  61. package/dist/vaults.js.map +1 -0
  62. package/package.json +58 -0
  63. package/src/auth.ts +707 -0
  64. package/src/billing.ts +30 -0
  65. package/src/client.ts +51 -0
  66. package/src/config.ts +123 -0
  67. package/src/encoding.ts +150 -0
  68. package/src/entropy.ts +56 -0
  69. package/src/errors.ts +110 -0
  70. package/src/folders.ts +76 -0
  71. package/src/health.ts +81 -0
  72. package/src/http.ts +429 -0
  73. package/src/identity-dialog.tsx +955 -0
  74. package/src/index.ts +103 -0
  75. package/src/ingots.ts +593 -0
  76. package/src/mutex.ts +26 -0
  77. package/src/push-tokens.ts +26 -0
  78. package/src/sparks.ts +73 -0
  79. package/src/tus.ts +280 -0
  80. package/src/types.ts +487 -0
  81. package/src/validation.ts +49 -0
  82. package/src/vaults.ts +271 -0
package/src/types.ts ADDED
@@ -0,0 +1,487 @@
1
+ export interface ApiMeta {
2
+ request_id: string;
3
+ response_ms: number;
4
+ timestamp: number;
5
+ api_version: string;
6
+ balance?: string;
7
+ quota?: {
8
+ limit: number;
9
+ used: number;
10
+ remaining: number;
11
+ resets_at: number;
12
+ };
13
+ }
14
+
15
+ export interface ApiResponse<T> {
16
+ data: T;
17
+ meta: ApiMeta;
18
+ }
19
+
20
+ export interface ApiErrorBody {
21
+ error?: {
22
+ code?: number | string;
23
+ message?: string;
24
+ details?: Record<string, unknown>;
25
+ };
26
+ message?: string;
27
+ data?: unknown;
28
+ meta?: ApiMeta;
29
+ }
30
+
31
+ export interface RateLimitInfo {
32
+ limit: number;
33
+ remaining: number;
34
+ reset: number;
35
+ }
36
+
37
+ export interface SparkVaultUser {
38
+ user_id: string;
39
+ email: string;
40
+ name?: string;
41
+ role: 'admin' | 'engineer' | 'viewer';
42
+ has_passkey?: boolean;
43
+ created_at: number;
44
+ }
45
+
46
+ export interface SparkVaultAccount {
47
+ account_id: string;
48
+ organization_name: string;
49
+ email: string;
50
+ status: 'active' | 'suspended';
51
+ balance: string;
52
+ logo_url?: string;
53
+ logo_dark_url?: string;
54
+ created_at: number;
55
+ }
56
+
57
+ export type IdentityType = 'email' | 'phone';
58
+
59
+ export type IdentityMethodId =
60
+ | 'totp_email'
61
+ | 'totp_sms'
62
+ | 'totp_voice'
63
+ | 'passkey'
64
+ | 'sparklink'
65
+ | 'social_google'
66
+ | 'social_apple'
67
+ | 'social_microsoft'
68
+ | 'social_github'
69
+ | 'social_facebook'
70
+ | 'social_linkedin'
71
+ | 'enterprise_okta'
72
+ | 'enterprise_entra'
73
+ | 'enterprise_onelogin'
74
+ | 'enterprise_ping'
75
+ | 'enterprise_jumpcloud';
76
+
77
+ export interface IdentityBranding {
78
+ companyName: string | null;
79
+ logoLight: string | null;
80
+ logoDark: string | null;
81
+ backdrop_blur?: boolean;
82
+ themeMode?: 'light' | 'dark';
83
+ }
84
+
85
+ export interface IdentityConfig {
86
+ accountId: string;
87
+ branding?: IdentityBranding;
88
+ allowedIdentityTypes?: IdentityType[];
89
+ methods: IdentityMethodId[];
90
+ wsDomain?: string;
91
+ }
92
+
93
+ export interface IdentityJwk {
94
+ kty: 'OKP';
95
+ crv: 'Ed25519';
96
+ x: string;
97
+ kid?: string;
98
+ alg?: 'EdDSA' | string;
99
+ use?: string;
100
+ }
101
+
102
+ export interface IdentityJwks {
103
+ keys: IdentityJwk[];
104
+ }
105
+
106
+ export interface IdentityTokenClaims {
107
+ iss: string;
108
+ sub: string;
109
+ aud: string;
110
+ exp: number;
111
+ iat: number;
112
+ nbf?: number;
113
+ jti?: string;
114
+ identity: string;
115
+ identity_type: IdentityType;
116
+ verified_at: number;
117
+ method: string;
118
+ }
119
+
120
+ export interface IdentityVerifyResult {
121
+ token: string;
122
+ identity: string;
123
+ identityType: IdentityType;
124
+ method?: string;
125
+ redirect?: string;
126
+ jwksUri: string;
127
+ jwks?: IdentityJwks;
128
+ }
129
+
130
+ export interface SendTotpRequest {
131
+ identity: string;
132
+ identityType: IdentityType;
133
+ method: 'email' | 'sms' | 'voice';
134
+ }
135
+
136
+ export interface VerifyTotpRequest {
137
+ kindling: string;
138
+ pin: string;
139
+ recipient: string;
140
+ }
141
+
142
+ export interface RequestPinRequest {
143
+ email: string;
144
+ organization_name?: string;
145
+ }
146
+
147
+ export interface RequestPinResponse {
148
+ kindling: string;
149
+ expires_at: number;
150
+ retry_after?: number;
151
+ is_signup: boolean;
152
+ }
153
+
154
+ export interface PinVerifyRequest {
155
+ kindling: string;
156
+ pin: string;
157
+ recipient: string;
158
+ organization_name?: string;
159
+ }
160
+
161
+ export interface PinVerifyLoginResponse {
162
+ access_token: string;
163
+ refresh_token: string;
164
+ token_type: 'Bearer';
165
+ expires_in: number;
166
+ user: SparkVaultUser;
167
+ }
168
+
169
+ export interface PinVerifySignupPendingResponse {
170
+ verified: true;
171
+ needs_signup_info: true;
172
+ signup_token: string;
173
+ expires_at: number;
174
+ }
175
+
176
+ export type PinVerifyResponse = PinVerifyLoginResponse | PinVerifySignupPendingResponse;
177
+
178
+ export interface CompleteSignupRequest {
179
+ organization_name: string;
180
+ full_name?: string;
181
+ }
182
+
183
+ export interface CompleteSignupResponse {
184
+ access_token: string;
185
+ refresh_token: string;
186
+ token_type?: 'Bearer';
187
+ expires_in?: number;
188
+ user: SparkVaultUser;
189
+ account: SparkVaultAccount;
190
+ }
191
+
192
+ export type PasskeySession = Record<string, unknown>;
193
+
194
+ export interface PasskeyAuthOptions {
195
+ challenge: string;
196
+ timeout: number;
197
+ rpId: string;
198
+ allowCredentials?: {
199
+ id: string;
200
+ type: 'public-key';
201
+ }[];
202
+ userVerification: 'required' | 'preferred' | 'discouraged';
203
+ }
204
+
205
+ export interface PasskeyAuthChallenge {
206
+ options: PasskeyAuthOptions;
207
+ session: PasskeySession;
208
+ }
209
+
210
+ export interface PasskeyRegisterOptions {
211
+ challenge: string;
212
+ rp: {
213
+ name: string;
214
+ id: string;
215
+ };
216
+ user: {
217
+ id: string;
218
+ name: string;
219
+ displayName: string;
220
+ };
221
+ pubKeyCredParams: {
222
+ type: 'public-key';
223
+ alg: number;
224
+ }[];
225
+ timeout: number;
226
+ authenticatorSelection: {
227
+ userVerification: 'required' | 'preferred' | 'discouraged';
228
+ residentKey: 'required' | 'preferred' | 'discouraged';
229
+ };
230
+ }
231
+
232
+ export interface PasskeyRegisterChallenge {
233
+ options: PasskeyRegisterOptions;
234
+ session: PasskeySession;
235
+ }
236
+
237
+ export interface PasskeyCredential {
238
+ id: string;
239
+ rawId: string;
240
+ response: {
241
+ clientDataJSON: string;
242
+ authenticatorData?: string;
243
+ signature?: string;
244
+ attestationObject?: string;
245
+ };
246
+ type: 'public-key';
247
+ }
248
+
249
+ export interface PasskeyStatus {
250
+ has_passkey: boolean;
251
+ registered_at?: number;
252
+ last_used_at?: number;
253
+ }
254
+
255
+ export interface IdentitySessionResponse {
256
+ access_token: string;
257
+ refresh_token: string;
258
+ token_type?: 'Bearer';
259
+ expires_in?: number;
260
+ user: SparkVaultUser | null;
261
+ account: SparkVaultAccount | null;
262
+ }
263
+
264
+ export interface Vault {
265
+ vault_id: string;
266
+ name: string;
267
+ description?: string;
268
+ status: 'sealed' | 'unsealed';
269
+ ingot_count: number;
270
+ storage_bytes: number;
271
+ created_at: number;
272
+ created_by_user_id?: string;
273
+ last_unsealed_at?: number;
274
+ unseal_count?: number;
275
+ }
276
+
277
+ export interface CreateVaultRequest {
278
+ name: string;
279
+ description?: string;
280
+ }
281
+
282
+ export interface CreateVaultResponse {
283
+ vault_id: string;
284
+ name: string;
285
+ description?: string;
286
+ vmk: string;
287
+ vmk_warning: string;
288
+ status: 'sealed';
289
+ created_at: number;
290
+ }
291
+
292
+ export interface UpdateVaultRequest {
293
+ name?: string;
294
+ description?: string;
295
+ }
296
+
297
+ export interface UpdateVaultResponse {
298
+ vault_id: string;
299
+ name: string;
300
+ description?: string;
301
+ updated_at: number;
302
+ }
303
+
304
+ export interface UnsealVaultRequest {
305
+ vmk: string;
306
+ ttl_seconds?: number;
307
+ }
308
+
309
+ export interface UnsealVaultResponse {
310
+ vat: string;
311
+ vault_id: string;
312
+ issued_at: number;
313
+ expires_at: number;
314
+ ttl_seconds: number;
315
+ }
316
+
317
+ export interface ListVaultsResponse {
318
+ vaults: Vault[];
319
+ total: number;
320
+ }
321
+
322
+ export interface Ingot {
323
+ ingot_id: string;
324
+ name: string;
325
+ content_type: string;
326
+ size_bytes: number;
327
+ storage_location: 'dynamodb' | 's3';
328
+ status?: 'uploading' | 'encrypting' | 'active' | 'failed';
329
+ folder_id?: string | null;
330
+ created_at: number;
331
+ accessed_at?: number;
332
+ access_count?: number;
333
+ expires_at?: number;
334
+ }
335
+
336
+ export interface ListIngotsResponse {
337
+ ingots: Ingot[];
338
+ total: number;
339
+ next_cursor?: string;
340
+ }
341
+
342
+ export interface UploadResult {
343
+ ingot_id: string;
344
+ name: string;
345
+ size_bytes: number;
346
+ storage_location: 's3';
347
+ }
348
+
349
+ export interface IngotSharingConfig {
350
+ shared: boolean;
351
+ visibility?: 'invite_only' | 'authenticated' | 'public';
352
+ share_code?: string;
353
+ share_url?: string;
354
+ invites?: IngotInvite[];
355
+ }
356
+
357
+ export interface IngotInvite {
358
+ invite_id: string;
359
+ identity: string;
360
+ identity_type: 'email';
361
+ created_at: number;
362
+ }
363
+
364
+ export interface IngotAccessLog {
365
+ log_id: string;
366
+ action: 'download' | 'view';
367
+ identity: string;
368
+ ip_address: string;
369
+ user_agent: string;
370
+ timestamp: number;
371
+ }
372
+
373
+ export interface IngotAccessStats {
374
+ total_downloads: number;
375
+ unique_visitors: number;
376
+ last_accessed_at?: number;
377
+ }
378
+
379
+ export interface Folder {
380
+ folder_id: string;
381
+ vault_id: string;
382
+ name: string;
383
+ parent_id: string | null;
384
+ is_system: boolean;
385
+ pinned: boolean;
386
+ created_at: number;
387
+ updated_at?: number;
388
+ path?: string;
389
+ depth?: number;
390
+ ingot_count?: number;
391
+ }
392
+
393
+ export interface CreateFolderRequest {
394
+ name: string;
395
+ parent_id?: string | null;
396
+ }
397
+
398
+ export interface UpdateFolderRequest {
399
+ name?: string;
400
+ parent_id?: string | null;
401
+ pinned?: boolean;
402
+ }
403
+
404
+ export interface ListFoldersResponse {
405
+ folders: Folder[];
406
+ total: number;
407
+ }
408
+
409
+ export interface FolderBreadcrumbItem {
410
+ folder_id: string | null;
411
+ name: string;
412
+ }
413
+
414
+ export interface TokenStorageAdapter {
415
+ getAccessToken(): Promise<string | null>;
416
+ setAccessToken(token: string): Promise<void>;
417
+ getRefreshToken(): Promise<string | null>;
418
+ setRefreshToken(token: string): Promise<void>;
419
+ setTokens?(accessToken: string, refreshToken: string): Promise<void>;
420
+ clearTokens(): Promise<void>;
421
+ getUser?<T = SparkVaultUser>(): Promise<T | null>;
422
+ setUser?<T = SparkVaultUser>(user: T): Promise<void>;
423
+ getAccount?<T = SparkVaultAccount>(): Promise<T | null>;
424
+ setAccount?<T = SparkVaultAccount>(account: T): Promise<void>;
425
+ clearAll?(): Promise<void>;
426
+ }
427
+
428
+ export type FetchLike = (
429
+ url: string,
430
+ options?: RequestInit & {
431
+ timeoutMs?: number;
432
+ responseType?: XMLHttpRequestResponseType;
433
+ }
434
+ ) => Promise<Response>;
435
+
436
+ export interface SparkVaultLogger {
437
+ debug(message: string, context?: Record<string, unknown>): void;
438
+ info(message: string, context?: Record<string, unknown>): void;
439
+ warn(message: string, context?: Record<string, unknown>): void;
440
+ error(message: string, context?: Record<string, unknown>): void;
441
+ }
442
+
443
+ export interface MobileFileReader {
444
+ readAsBase64(fileUri: string, options: { position: number; length: number }): Promise<string>;
445
+ }
446
+
447
+ export interface MobileDownloadProgress {
448
+ bytesWritten: number;
449
+ bytesTotal?: number;
450
+ }
451
+
452
+ export interface MobileDownloadedFile {
453
+ uri: string;
454
+ status?: number;
455
+ headers?: Record<string, string>;
456
+ sizeBytes?: number;
457
+ }
458
+
459
+ export interface MobileFileInfo {
460
+ exists: boolean;
461
+ sizeBytes?: number;
462
+ }
463
+
464
+ export interface MobileFileDownloader {
465
+ download(
466
+ url: string,
467
+ fileUri: string,
468
+ options?: {
469
+ timeoutMs?: number;
470
+ abortSignal?: AbortSignal;
471
+ onProgress?: (progress: MobileDownloadProgress) => void;
472
+ }
473
+ ): Promise<MobileDownloadedFile | null>;
474
+ getInfo(fileUri: string): Promise<MobileFileInfo>;
475
+ delete(fileUri: string): Promise<void>;
476
+ }
477
+
478
+ export interface DebugLogger {
479
+ log(message: string): void;
480
+ warn(message: string): void;
481
+ error(message: string): void;
482
+ success(message: string): void;
483
+ }
484
+
485
+ export interface UploadProgressCallback {
486
+ (bytesUploaded: number, bytesTotal: number): void;
487
+ }
@@ -0,0 +1,49 @@
1
+ import { SparkVaultValidationError } from './errors.js';
2
+
3
+ export function isSafeId(id: string): boolean {
4
+ if (!id || typeof id !== 'string') return false;
5
+ if (id.includes('/') || id.includes('\\') || id.includes('..') || id.includes('\0')) return false;
6
+ if (id.length < 8 || id.length > 128) return false;
7
+ return /^[a-zA-Z0-9_-]+$/.test(id);
8
+ }
9
+
10
+ export function validateVaultId(vaultId: string): void {
11
+ if (!isSafeId(vaultId)) {
12
+ throw new SparkVaultValidationError('Invalid vault ID format', { vaultId });
13
+ }
14
+ }
15
+
16
+ export function validateIngotId(ingotId: string): void {
17
+ if (!isSafeId(ingotId)) {
18
+ throw new SparkVaultValidationError('Invalid ingot ID format', { ingotId });
19
+ }
20
+ }
21
+
22
+ export function validateFolderId(folderId: string): void {
23
+ if (!folderId || typeof folderId !== 'string' || !folderId.startsWith('fld_') || !isSafeId(folderId)) {
24
+ throw new SparkVaultValidationError('Invalid folder ID format', { folderId });
25
+ }
26
+ }
27
+
28
+ export function sanitizeFilename(filename: string): string {
29
+ const reservedNames = new Set([
30
+ 'CON', 'PRN', 'AUX', 'NUL',
31
+ 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
32
+ 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9',
33
+ ]);
34
+
35
+ let sanitized = filename
36
+ .replace(/\0/g, '')
37
+ .replace(/[\x00-\x1f\x7f]/g, '')
38
+ .replace(/\.\./g, '')
39
+ .replace(/[\/\\]/g, '_')
40
+ .replace(/^\.+/, '')
41
+ .trim();
42
+
43
+ const baseName = sanitized.split('.')[0].toUpperCase();
44
+ if (reservedNames.has(baseName)) {
45
+ sanitized = `_${sanitized}`;
46
+ }
47
+
48
+ return sanitized || 'file';
49
+ }