@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
@@ -0,0 +1,39 @@
1
+ import type { FetchLike, MobileFileDownloader, MobileFileReader, SparkVaultLogger, TokenStorageAdapter } from './types.js';
2
+ export interface SparkVaultMobileConfig {
3
+ tokenStorage: TokenStorageAdapter;
4
+ apiBaseUrl?: string;
5
+ identityBaseUrl?: string;
6
+ identityAccountId: string;
7
+ preloadIdentityConfig?: boolean;
8
+ userAgent?: string;
9
+ timeoutMs?: number;
10
+ fileTransferTimeoutMs?: number;
11
+ tusPostTimeoutMs?: number;
12
+ tusChunkTimeoutMs?: number;
13
+ tusChunkSizeBytes?: number;
14
+ fetch?: FetchLike;
15
+ fileReader?: MobileFileReader;
16
+ fileDownloader?: MobileFileDownloader;
17
+ logger?: Partial<SparkVaultLogger>;
18
+ allowedDownloadHostPatterns?: RegExp[];
19
+ }
20
+ export interface ResolvedMobileConfig {
21
+ tokenStorage: TokenStorageAdapter;
22
+ apiBaseUrl: string;
23
+ identityBaseUrl: string;
24
+ identityAccountId: string;
25
+ preloadIdentityConfig: boolean;
26
+ userAgent: string;
27
+ timeoutMs: number;
28
+ fileTransferTimeoutMs: number;
29
+ tusPostTimeoutMs: number;
30
+ tusChunkTimeoutMs: number;
31
+ tusChunkSizeBytes: number;
32
+ fetch: FetchLike;
33
+ fileReader?: MobileFileReader;
34
+ fileDownloader?: MobileFileDownloader;
35
+ logger: SparkVaultLogger;
36
+ allowedDownloadHostPatterns: RegExp[];
37
+ }
38
+ export declare function resolveMobileConfig(config: SparkVaultMobileConfig): ResolvedMobileConfig;
39
+ export declare function identityUrl(config: ResolvedMobileConfig, path: string): string;
package/dist/config.js ADDED
@@ -0,0 +1,69 @@
1
+ import { SparkVaultValidationError } from './errors.js';
2
+ const DEFAULT_API_BASE_URL = 'https://api.sparkvault.com/v1';
3
+ const DEFAULT_IDENTITY_BASE_URL = 'https://api.sparkvault.com/v1/apps/identity';
4
+ // Hosts that are allowed to serve backend-issued ingot download URLs.
5
+ // Keep in sync with the sdk-js default in packages/sdk-js/src/config.ts.
6
+ const DEFAULT_ALLOWED_DOWNLOAD_HOST_PATTERNS = [
7
+ /(^|\.)sparkvault\.com$/i,
8
+ /(^|\.)(x|files|file|send|spark|by|at|db|auth)\.sv$/i,
9
+ /\.amazonaws\.com$/i,
10
+ /\.cloudfront\.net$/i,
11
+ ];
12
+ const noopLogger = {
13
+ debug: () => undefined,
14
+ info: () => undefined,
15
+ warn: () => undefined,
16
+ error: () => undefined,
17
+ };
18
+ function normalizeBaseUrl(url, field) {
19
+ if (!url || typeof url !== 'string') {
20
+ throw new SparkVaultValidationError(`${field} must be a non-empty string`, { field });
21
+ }
22
+ return url.replace(/\/+$/, '');
23
+ }
24
+ function defaultFetch(url, options) {
25
+ if (typeof fetch !== 'function') {
26
+ throw new SparkVaultValidationError('A fetch implementation is required in this runtime');
27
+ }
28
+ return fetch(url, options);
29
+ }
30
+ export function resolveMobileConfig(config) {
31
+ if (!config.tokenStorage) {
32
+ throw new SparkVaultValidationError('tokenStorage is required', { field: 'tokenStorage' });
33
+ }
34
+ const identityAccountId = config.identityAccountId;
35
+ if (!identityAccountId || typeof identityAccountId !== 'string') {
36
+ throw new SparkVaultValidationError('identityAccountId is required', {
37
+ field: 'identityAccountId',
38
+ received: identityAccountId,
39
+ });
40
+ }
41
+ if (!identityAccountId.startsWith('acc_')) {
42
+ throw new SparkVaultValidationError('identityAccountId must start with "acc_"', {
43
+ field: 'identityAccountId',
44
+ received: identityAccountId,
45
+ });
46
+ }
47
+ return {
48
+ tokenStorage: config.tokenStorage,
49
+ apiBaseUrl: normalizeBaseUrl(config.apiBaseUrl ?? DEFAULT_API_BASE_URL, 'apiBaseUrl'),
50
+ identityBaseUrl: normalizeBaseUrl(config.identityBaseUrl ?? DEFAULT_IDENTITY_BASE_URL, 'identityBaseUrl'),
51
+ identityAccountId,
52
+ preloadIdentityConfig: config.preloadIdentityConfig ?? true,
53
+ userAgent: config.userAgent ?? 'SparkVaultMobileSDK/0.1.0',
54
+ timeoutMs: config.timeoutMs ?? 30000,
55
+ fileTransferTimeoutMs: config.fileTransferTimeoutMs ?? 300000,
56
+ tusPostTimeoutMs: config.tusPostTimeoutMs ?? 30000,
57
+ tusChunkTimeoutMs: config.tusChunkTimeoutMs ?? 120000,
58
+ tusChunkSizeBytes: config.tusChunkSizeBytes ?? 5 * 1024 * 1024,
59
+ fetch: config.fetch ?? defaultFetch,
60
+ fileReader: config.fileReader,
61
+ fileDownloader: config.fileDownloader,
62
+ logger: { ...noopLogger, ...config.logger },
63
+ allowedDownloadHostPatterns: config.allowedDownloadHostPatterns ?? DEFAULT_ALLOWED_DOWNLOAD_HOST_PATTERNS,
64
+ };
65
+ }
66
+ export function identityUrl(config, path) {
67
+ return `${config.identityBaseUrl}/${config.identityAccountId}${path}`;
68
+ }
69
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function utf8ToBytes(value: string): Uint8Array;
2
+ export declare function base64EncodeUtf8(value: string): string;
3
+ export declare function bytesToUtf8(bytes: Uint8Array): string;
4
+ export declare function base64UrlToBytes(value: string): Uint8Array;
5
+ export declare function base64UrlToUtf8(value: string): string;
6
+ export declare function bytesToBase64(bytes: Uint8Array): string;
7
+ export declare function base64ToBytes(value: string): Uint8Array;
@@ -0,0 +1,113 @@
1
+ const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
2
+ const BASE64_LOOKUP = new Map(Array.from(BASE64_ALPHABET).map((char, index) => [char, index]));
3
+ export function utf8ToBytes(value) {
4
+ const bytes = [];
5
+ for (let i = 0; i < value.length; i++) {
6
+ let codePoint = value.charCodeAt(i);
7
+ if (codePoint >= 0xd800 && codePoint <= 0xdbff && i + 1 < value.length) {
8
+ const next = value.charCodeAt(i + 1);
9
+ if (next >= 0xdc00 && next <= 0xdfff) {
10
+ codePoint = 0x10000 + ((codePoint - 0xd800) << 10) + (next - 0xdc00);
11
+ i++;
12
+ }
13
+ }
14
+ if (codePoint <= 0x7f) {
15
+ bytes.push(codePoint);
16
+ }
17
+ else if (codePoint <= 0x7ff) {
18
+ bytes.push(0xc0 | (codePoint >> 6), 0x80 | (codePoint & 0x3f));
19
+ }
20
+ else if (codePoint <= 0xffff) {
21
+ bytes.push(0xe0 | (codePoint >> 12), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
22
+ }
23
+ else {
24
+ bytes.push(0xf0 | (codePoint >> 18), 0x80 | ((codePoint >> 12) & 0x3f), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
25
+ }
26
+ }
27
+ return new Uint8Array(bytes);
28
+ }
29
+ export function base64EncodeUtf8(value) {
30
+ return bytesToBase64(utf8ToBytes(value));
31
+ }
32
+ export function bytesToUtf8(bytes) {
33
+ let output = '';
34
+ let i = 0;
35
+ while (i < bytes.length) {
36
+ const byte1 = bytes[i++];
37
+ if (byte1 < 0x80) {
38
+ output += String.fromCharCode(byte1);
39
+ continue;
40
+ }
41
+ if (byte1 >= 0xc0 && byte1 < 0xe0) {
42
+ const byte2 = bytes[i++];
43
+ output += String.fromCharCode(((byte1 & 0x1f) << 6) | (byte2 & 0x3f));
44
+ continue;
45
+ }
46
+ if (byte1 >= 0xe0 && byte1 < 0xf0) {
47
+ const byte2 = bytes[i++];
48
+ const byte3 = bytes[i++];
49
+ output += String.fromCharCode(((byte1 & 0x0f) << 12) |
50
+ ((byte2 & 0x3f) << 6) |
51
+ (byte3 & 0x3f));
52
+ continue;
53
+ }
54
+ const byte2 = bytes[i++];
55
+ const byte3 = bytes[i++];
56
+ const byte4 = bytes[i++];
57
+ const codePoint = (((byte1 & 0x07) << 18) |
58
+ ((byte2 & 0x3f) << 12) |
59
+ ((byte3 & 0x3f) << 6) |
60
+ (byte4 & 0x3f)) - 0x10000;
61
+ output += String.fromCharCode(0xd800 + (codePoint >> 10), 0xdc00 + (codePoint & 0x3ff));
62
+ }
63
+ return output;
64
+ }
65
+ export function base64UrlToBytes(value) {
66
+ return base64ToBytes(value);
67
+ }
68
+ export function base64UrlToUtf8(value) {
69
+ return bytesToUtf8(base64UrlToBytes(value));
70
+ }
71
+ export function bytesToBase64(bytes) {
72
+ let output = '';
73
+ for (let i = 0; i < bytes.length; i += 3) {
74
+ const byte1 = bytes[i];
75
+ const byte2 = bytes[i + 1] ?? 0;
76
+ const byte3 = bytes[i + 2] ?? 0;
77
+ const triplet = (byte1 << 16) | (byte2 << 8) | byte3;
78
+ output += BASE64_ALPHABET[(triplet >> 18) & 0x3f];
79
+ output += BASE64_ALPHABET[(triplet >> 12) & 0x3f];
80
+ output += i + 1 < bytes.length ? BASE64_ALPHABET[(triplet >> 6) & 0x3f] : '=';
81
+ output += i + 2 < bytes.length ? BASE64_ALPHABET[triplet & 0x3f] : '=';
82
+ }
83
+ return output;
84
+ }
85
+ export function base64ToBytes(value) {
86
+ const sanitized = value.replace(/\s/g, '').replace(/-/g, '+').replace(/_/g, '/');
87
+ if (sanitized.length % 4 === 1) {
88
+ throw new Error('Invalid base64 input');
89
+ }
90
+ const padded = sanitized.padEnd(Math.ceil(sanitized.length / 4) * 4, '=');
91
+ const bytes = [];
92
+ for (let i = 0; i < padded.length; i += 4) {
93
+ const c1 = padded[i];
94
+ const c2 = padded[i + 1];
95
+ const c3 = padded[i + 2];
96
+ const c4 = padded[i + 3];
97
+ const v1 = BASE64_LOOKUP.get(c1);
98
+ const v2 = BASE64_LOOKUP.get(c2);
99
+ const v3 = c3 === '=' ? 0 : BASE64_LOOKUP.get(c3);
100
+ const v4 = c4 === '=' ? 0 : BASE64_LOOKUP.get(c4);
101
+ if (v1 === undefined || v2 === undefined || v3 === undefined || v4 === undefined) {
102
+ throw new Error('Invalid base64 input');
103
+ }
104
+ const triplet = (v1 << 18) | (v2 << 12) | (v3 << 6) | v4;
105
+ bytes.push((triplet >> 16) & 0xff);
106
+ if (c3 !== '=')
107
+ bytes.push((triplet >> 8) & 0xff);
108
+ if (c4 !== '=')
109
+ bytes.push(triplet & 0xff);
110
+ }
111
+ return new Uint8Array(bytes);
112
+ }
113
+ //# sourceMappingURL=encoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.js","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { MobileHttpClient } from './http.js';
2
+ export type EntropyFormat = 'hex' | 'base64' | 'bytes' | 'uuid';
3
+ export interface GenerateEntropyOptions {
4
+ bytes: number;
5
+ format?: EntropyFormat;
6
+ }
7
+ export interface EntropyResponse {
8
+ value: string;
9
+ num_bytes: number;
10
+ format?: EntropyFormat;
11
+ }
12
+ export declare class MobileEntropyClient {
13
+ private readonly http;
14
+ constructor(http: MobileHttpClient);
15
+ generate(options: GenerateEntropyOptions): Promise<EntropyResponse>;
16
+ generateBytes(bytes: number): Promise<Uint8Array>;
17
+ private validateByteCount;
18
+ }
@@ -0,0 +1,35 @@
1
+ import { base64ToBytes } from './encoding.js';
2
+ import { SparkVaultMobileError, SparkVaultValidationError } from './errors.js';
3
+ export class MobileEntropyClient {
4
+ constructor(http) {
5
+ this.http = http;
6
+ }
7
+ async generate(options) {
8
+ this.validateByteCount(options.bytes);
9
+ const response = await this.http.post('/entropy/generate', {
10
+ num_bytes: options.bytes,
11
+ format: options.format ?? 'base64',
12
+ });
13
+ return response.data;
14
+ }
15
+ async generateBytes(bytes) {
16
+ const response = await this.generate({ bytes, format: 'base64' });
17
+ if (typeof response.value !== 'string' || response.value.length === 0) {
18
+ throw new SparkVaultMobileError('Entropy endpoint returned no value');
19
+ }
20
+ const entropy = base64ToBytes(response.value);
21
+ if (entropy.length !== bytes) {
22
+ throw new SparkVaultMobileError(`Entropy length mismatch: expected ${bytes}, got ${entropy.length}`);
23
+ }
24
+ return entropy;
25
+ }
26
+ validateByteCount(bytes) {
27
+ if (!Number.isInteger(bytes) || bytes < 1 || bytes > 1024) {
28
+ throw new SparkVaultValidationError('Entropy byte count must be an integer from 1 to 1024', {
29
+ field: 'bytes',
30
+ received: bytes,
31
+ });
32
+ }
33
+ }
34
+ }
35
+ //# sourceMappingURL=entropy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy.js","sourceRoot":"","sources":["../src/entropy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAgB/E,MAAM,OAAO,mBAAmB;IAG9B,YAAY,IAAsB;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAA+B;QAC5C,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAkB,mBAAmB,EAAE;YAC1E,SAAS,EAAE,OAAO,CAAC,KAAK;YACxB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,QAAQ;SACnC,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAa;QAC/B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClE,IAAI,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,qBAAqB,CAAC,oCAAoC,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YAC7B,MAAM,IAAI,qBAAqB,CAAC,qCAAqC,KAAK,SAAS,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACvG,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,iBAAiB,CAAC,KAAa;QACrC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,IAAI,EAAE,CAAC;YAC1D,MAAM,IAAI,yBAAyB,CAAC,sDAAsD,EAAE;gBAC1F,KAAK,EAAE,OAAO;gBACd,QAAQ,EAAE,KAAK;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,46 @@
1
+ import type { ApiMeta } from './types.js';
2
+ export declare class SparkVaultMobileError extends Error {
3
+ readonly code: string | number;
4
+ readonly statusCode?: number;
5
+ readonly details?: Record<string, unknown>;
6
+ readonly meta?: ApiMeta;
7
+ constructor(message: string, options?: {
8
+ code?: string | number;
9
+ statusCode?: number;
10
+ details?: Record<string, unknown>;
11
+ meta?: ApiMeta;
12
+ });
13
+ }
14
+ export declare class SparkVaultValidationError extends SparkVaultMobileError {
15
+ constructor(message: string, details?: Record<string, unknown>);
16
+ }
17
+ export declare class SparkVaultAuthenticationError extends SparkVaultMobileError {
18
+ constructor(message?: string, details?: Record<string, unknown>);
19
+ }
20
+ export declare class SparkVaultAuthorizationError extends SparkVaultMobileError {
21
+ constructor(message?: string, details?: Record<string, unknown>);
22
+ }
23
+ export declare class SparkVaultNetworkError extends SparkVaultMobileError {
24
+ constructor(message?: string, details?: Record<string, unknown>);
25
+ }
26
+ export declare class SparkVaultTimeoutError extends SparkVaultMobileError {
27
+ constructor(message?: string);
28
+ }
29
+ export declare class TusUploadError extends SparkVaultMobileError {
30
+ readonly cause: Error | null;
31
+ readonly filename: string | null;
32
+ readonly fileSize: number | null;
33
+ readonly phase: 'create' | 'upload' | 'network' | 'timeout' | 'cancelled' | 'stalled' | 'unknown';
34
+ constructor(message: string, options?: {
35
+ cause?: Error | null;
36
+ httpStatus?: number | null;
37
+ filename?: string | null;
38
+ fileSize?: number | null;
39
+ phase?: TusUploadError['phase'];
40
+ });
41
+ static fromError(error: Error, context: {
42
+ filename?: string;
43
+ fileSize?: number;
44
+ phase?: TusUploadError['phase'];
45
+ }): TusUploadError;
46
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,72 @@
1
+ export class SparkVaultMobileError extends Error {
2
+ constructor(message, options = {}) {
3
+ super(message);
4
+ this.name = 'SparkVaultMobileError';
5
+ this.code = options.code ?? 'sparkvault_error';
6
+ this.statusCode = options.statusCode;
7
+ this.details = options.details;
8
+ this.meta = options.meta;
9
+ Object.setPrototypeOf(this, SparkVaultMobileError.prototype);
10
+ }
11
+ }
12
+ export class SparkVaultValidationError extends SparkVaultMobileError {
13
+ constructor(message, details) {
14
+ super(message, { code: 'validation_error', statusCode: 400, details });
15
+ this.name = 'SparkVaultValidationError';
16
+ Object.setPrototypeOf(this, SparkVaultValidationError.prototype);
17
+ }
18
+ }
19
+ export class SparkVaultAuthenticationError extends SparkVaultMobileError {
20
+ constructor(message = 'Authentication required', details) {
21
+ super(message, { code: 'authentication_error', statusCode: 401, details });
22
+ this.name = 'SparkVaultAuthenticationError';
23
+ Object.setPrototypeOf(this, SparkVaultAuthenticationError.prototype);
24
+ }
25
+ }
26
+ export class SparkVaultAuthorizationError extends SparkVaultMobileError {
27
+ constructor(message = 'Forbidden', details) {
28
+ super(message, { code: 'authorization_error', statusCode: 403, details });
29
+ this.name = 'SparkVaultAuthorizationError';
30
+ Object.setPrototypeOf(this, SparkVaultAuthorizationError.prototype);
31
+ }
32
+ }
33
+ export class SparkVaultNetworkError extends SparkVaultMobileError {
34
+ constructor(message = 'Network request failed', details) {
35
+ super(message, { code: 'network_error', details });
36
+ this.name = 'SparkVaultNetworkError';
37
+ Object.setPrototypeOf(this, SparkVaultNetworkError.prototype);
38
+ }
39
+ }
40
+ export class SparkVaultTimeoutError extends SparkVaultMobileError {
41
+ constructor(message = 'Request timed out') {
42
+ super(message, { code: 'timeout_error', statusCode: 408 });
43
+ this.name = 'SparkVaultTimeoutError';
44
+ Object.setPrototypeOf(this, SparkVaultTimeoutError.prototype);
45
+ }
46
+ }
47
+ export class TusUploadError extends SparkVaultMobileError {
48
+ constructor(message, options = {}) {
49
+ super(message, {
50
+ code: options.httpStatus ?? 'tus_upload_error',
51
+ statusCode: options.httpStatus ?? undefined,
52
+ });
53
+ this.name = 'TusUploadError';
54
+ this.cause = options.cause ?? null;
55
+ this.filename = options.filename ?? null;
56
+ this.fileSize = options.fileSize ?? null;
57
+ this.phase = options.phase ?? 'unknown';
58
+ Object.setPrototypeOf(this, TusUploadError.prototype);
59
+ }
60
+ static fromError(error, context) {
61
+ const statusMatch = error.message.match(/(\d{3})/);
62
+ const httpStatus = statusMatch ? parseInt(statusMatch[1], 10) : null;
63
+ return new TusUploadError(error.message, {
64
+ cause: error,
65
+ httpStatus,
66
+ filename: context.filename,
67
+ fileSize: context.fileSize,
68
+ phase: context.phase ?? 'unknown',
69
+ });
70
+ }
71
+ }
72
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { MobileHttpClient } from './http.js';
2
+ import type { CreateFolderRequest, Folder, FolderBreadcrumbItem, ListFoldersResponse, UpdateFolderRequest } from './types.js';
3
+ export declare class MobileFoldersClient {
4
+ private readonly http;
5
+ constructor(http: MobileHttpClient);
6
+ list(vaultId: string, vat: string): Promise<ListFoldersResponse>;
7
+ get(vaultId: string, folderId: string, vat: string): Promise<Folder>;
8
+ getBreadcrumb(vaultId: string, folderId: string, vat: string): Promise<FolderBreadcrumbItem[]>;
9
+ create(vaultId: string, vat: string, data: CreateFolderRequest): Promise<Folder>;
10
+ update(vaultId: string, folderId: string, vat: string, data: UpdateFolderRequest): Promise<Folder>;
11
+ move(vaultId: string, folderId: string, vat: string, newParentId: string | null): Promise<Folder>;
12
+ togglePin(vaultId: string, folderId: string, vat: string, pinned: boolean): Promise<Folder>;
13
+ delete(vaultId: string, folderId: string, vat: string): Promise<void>;
14
+ moveIngot(vaultId: string, ingotId: string, vat: string, folderId: string | null): Promise<void>;
15
+ }
@@ -0,0 +1,54 @@
1
+ import { validateFolderId, validateIngotId, validateVaultId } from './validation.js';
2
+ export class MobileFoldersClient {
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ async list(vaultId, vat) {
7
+ validateVaultId(vaultId);
8
+ const response = await this.http.get(`/vaults/${vaultId}/folders`, { vat });
9
+ return response.data;
10
+ }
11
+ async get(vaultId, folderId, vat) {
12
+ validateVaultId(vaultId);
13
+ validateFolderId(folderId);
14
+ const response = await this.http.get(`/vaults/${vaultId}/folders/${folderId}`, { vat });
15
+ return response.data;
16
+ }
17
+ async getBreadcrumb(vaultId, folderId, vat) {
18
+ validateVaultId(vaultId);
19
+ validateFolderId(folderId);
20
+ const response = await this.http.get(`/vaults/${vaultId}/folders/${folderId}/breadcrumb`, { vat });
21
+ return response.data.breadcrumb;
22
+ }
23
+ async create(vaultId, vat, data) {
24
+ validateVaultId(vaultId);
25
+ const response = await this.http.post(`/vaults/${vaultId}/folders`, data, { vat });
26
+ return response.data;
27
+ }
28
+ async update(vaultId, folderId, vat, data) {
29
+ validateVaultId(vaultId);
30
+ validateFolderId(folderId);
31
+ const response = await this.http.patch(`/vaults/${vaultId}/folders/${folderId}`, data, { vat });
32
+ return response.data;
33
+ }
34
+ async move(vaultId, folderId, vat, newParentId) {
35
+ return this.update(vaultId, folderId, vat, { parent_id: newParentId });
36
+ }
37
+ async togglePin(vaultId, folderId, vat, pinned) {
38
+ return this.update(vaultId, folderId, vat, { pinned });
39
+ }
40
+ async delete(vaultId, folderId, vat) {
41
+ validateVaultId(vaultId);
42
+ validateFolderId(folderId);
43
+ await this.http.delete(`/vaults/${vaultId}/folders/${folderId}`, { vat });
44
+ }
45
+ async moveIngot(vaultId, ingotId, vat, folderId) {
46
+ validateVaultId(vaultId);
47
+ validateIngotId(ingotId);
48
+ if (folderId !== null) {
49
+ validateFolderId(folderId);
50
+ }
51
+ await this.http.patch(`/vaults/${vaultId}/ingots/${ingotId}`, { folder_id: folderId }, { vat });
52
+ }
53
+ }
54
+ //# sourceMappingURL=folders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"folders.js","sourceRoot":"","sources":["../src/folders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { ResolvedMobileConfig } from './config.js';
2
+ export interface HealthCheckOptions {
3
+ timeoutMs?: number;
4
+ }
5
+ export interface HealthCheckResult {
6
+ online: boolean;
7
+ status: string;
8
+ httpStatus?: number;
9
+ checkedAt: number;
10
+ error?: string;
11
+ }
12
+ export declare class MobileHealthClient {
13
+ private readonly config;
14
+ constructor(config: ResolvedMobileConfig);
15
+ check(options?: HealthCheckOptions): Promise<HealthCheckResult>;
16
+ isOnline(options?: HealthCheckOptions): Promise<boolean>;
17
+ private healthUrl;
18
+ private readStatus;
19
+ }
package/dist/health.js ADDED
@@ -0,0 +1,60 @@
1
+ export class MobileHealthClient {
2
+ constructor(config) {
3
+ this.config = config;
4
+ }
5
+ async check(options = {}) {
6
+ const checkedAt = Math.floor(Date.now() / 1000);
7
+ try {
8
+ const response = await this.config.fetch(this.healthUrl(), {
9
+ method: 'GET',
10
+ headers: {
11
+ Accept: 'application/json',
12
+ 'User-Agent': this.config.userAgent,
13
+ },
14
+ timeoutMs: options.timeoutMs ?? this.config.timeoutMs,
15
+ });
16
+ return {
17
+ online: response.ok,
18
+ status: response.ok ? await this.readStatus(response) : 'unhealthy',
19
+ httpStatus: response.status,
20
+ checkedAt,
21
+ };
22
+ }
23
+ catch (err) {
24
+ const message = err instanceof Error ? err.message : String(err);
25
+ this.config.logger.debug('Health check failed', { error: message });
26
+ return {
27
+ online: false,
28
+ status: 'unreachable',
29
+ checkedAt,
30
+ error: message,
31
+ };
32
+ }
33
+ }
34
+ async isOnline(options = {}) {
35
+ const result = await this.check(options);
36
+ return result.online;
37
+ }
38
+ healthUrl() {
39
+ return `${this.config.apiBaseUrl.replace(/\/v1$/, '')}/health`;
40
+ }
41
+ async readStatus(response) {
42
+ try {
43
+ const body = await response.json();
44
+ const data = typeof body === 'object' && body !== null && 'data' in body
45
+ ? body.data
46
+ : body;
47
+ if (typeof data === 'object' && data !== null) {
48
+ const status = data.status;
49
+ if (typeof status === 'string' && status) {
50
+ return status;
51
+ }
52
+ }
53
+ }
54
+ catch {
55
+ return response.ok ? 'healthy' : 'unhealthy';
56
+ }
57
+ return response.ok ? 'healthy' : 'unhealthy';
58
+ }
59
+ }
60
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAcA,MAAM,OAAO,kBAAkB;IAG7B,YAAY,MAA4B;QACtC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAA8B,EAAE;QAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAEhD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE;gBACzD,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE;oBACP,MAAM,EAAE,kBAAkB;oBAC1B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;iBACpC;gBACD,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS;aACtD,CAAC,CAAC;YAEH,OAAO;gBACL,MAAM,EAAE,QAAQ,CAAC,EAAE;gBACnB,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW;gBACnE,UAAU,EAAE,QAAQ,CAAC,MAAM;gBAC3B,SAAS;aACV,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACpE,OAAO;gBACL,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,aAAa;gBACrB,SAAS;gBACT,KAAK,EAAE,OAAO;aACf,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,UAA8B,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;IAEO,SAAS;QACf,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC;IACjE,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,QAAkB;QACzC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI;gBACtE,CAAC,CAAE,IAA2B,CAAC,IAAI;gBACnC,CAAC,CAAC,IAAI,CAAC;YAET,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC9C,MAAM,MAAM,GAAI,IAA6B,CAAC,MAAM,CAAC;gBACrD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,EAAE,CAAC;oBACzC,OAAO,MAAM,CAAC;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;QAC/C,CAAC;QAED,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;IAC/C,CAAC;CACF"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import type { ResolvedMobileConfig } from './config.js';
2
+ import type { ApiMeta, ApiResponse, RateLimitInfo } from './types.js';
3
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
4
+ export interface RequestOptions {
5
+ body?: unknown;
6
+ headers?: Record<string, string>;
7
+ skipAuth?: boolean;
8
+ vat?: string;
9
+ timeoutMs?: number;
10
+ }
11
+ export type AuthEvent = 'logout' | 'token_refreshed';
12
+ export type AuthEventListener = (event: AuthEvent) => void;
13
+ export declare class MobileHttpClient {
14
+ private readonly config;
15
+ private readonly authListeners;
16
+ private readonly refreshMutex;
17
+ private lastMeta;
18
+ private rateLimitInfo;
19
+ constructor(config: ResolvedMobileConfig);
20
+ get baseUrl(): string;
21
+ get meta(): ApiMeta | null;
22
+ get rateLimit(): RateLimitInfo | null;
23
+ onAuthEvent(listener: AuthEventListener): () => void;
24
+ private emitAuthEvent;
25
+ private getHeaders;
26
+ private parseRateLimitHeaders;
27
+ private normalizeError;
28
+ private makeUrl;
29
+ private serializeBody;
30
+ refreshAccessToken(): Promise<boolean>;
31
+ private doRefreshOnce;
32
+ private doRefresh;
33
+ request<T>(method: HttpMethod, endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>>;
34
+ requestRaw(endpoint: string, options?: RequestOptions & {
35
+ method?: HttpMethod;
36
+ responseType?: XMLHttpRequestResponseType;
37
+ }): Promise<Response>;
38
+ get<T>(endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>>;
39
+ post<T>(endpoint: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
40
+ put<T>(endpoint: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
41
+ patch<T>(endpoint: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
42
+ delete<T>(endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>>;
43
+ uploadFile<T>(endpoint: string, formData: FormData, options?: Omit<RequestOptions, 'body'>): Promise<ApiResponse<T>>;
44
+ private defaultErrorMessage;
45
+ }