@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/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # SparkVault Mobile SDK
2
+
3
+ Mobile SDK for SparkVault Identity, vault, folder, and ingot workflows.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @sparkvault/sdk-mobile
9
+ ```
10
+
11
+ ## Create a Client
12
+
13
+ ```typescript
14
+ import * as FileSystem from 'expo-file-system/legacy';
15
+ import { createSparkVaultMobileClient } from '@sparkvault/sdk-mobile';
16
+
17
+ export const sparkVault = createSparkVaultMobileClient({
18
+ tokenStorage,
19
+ apiBaseUrl: 'https://api.sparkvault.com/v1',
20
+ identityBaseUrl: 'https://api.sparkvault.com/v1/apps/identity',
21
+ identityAccountId: 'acc_00000000000000000000000000000000',
22
+ userAgent: 'SparkVault/1.0.0 (Mobile)',
23
+ fetch: xhrFetch,
24
+ fileReader: {
25
+ readAsBase64: (fileUri, { position, length }) =>
26
+ FileSystem.readAsStringAsync(fileUri, {
27
+ encoding: 'base64',
28
+ position,
29
+ length,
30
+ }),
31
+ },
32
+ fileDownloader: {
33
+ download: async (url, fileUri, options) => {
34
+ const resumable = FileSystem.createDownloadResumable(
35
+ url,
36
+ fileUri,
37
+ {},
38
+ progress => options?.onProgress?.({
39
+ bytesWritten: progress.totalBytesWritten,
40
+ bytesTotal: progress.totalBytesExpectedToWrite || undefined,
41
+ })
42
+ );
43
+ const result = await resumable.downloadAsync();
44
+ return result ? { uri: result.uri, status: result.status, headers: result.headers } : null;
45
+ },
46
+ getInfo: async (fileUri) => {
47
+ const info = await FileSystem.getInfoAsync(fileUri);
48
+ return { exists: info.exists, sizeBytes: info.exists ? info.size : undefined };
49
+ },
50
+ delete: (fileUri) => FileSystem.deleteAsync(fileUri, { idempotent: true }),
51
+ },
52
+ });
53
+ ```
54
+
55
+ ### Dependency contract
56
+
57
+ The SDK depends on `tweetnacl` for Ed25519 Identity JWT verification and declares `react`/`react-native` as peer dependencies for the optional native Identity dialog. Platform behavior stays behind adapters so the SDK is portable across React Native runtimes.
58
+
59
+ | Adapter | Required | Default if omitted |
60
+ |---------|----------|--------------------|
61
+ | `tokenStorage` | Yes | Throws at client construction |
62
+ | `identityAccountId` | Yes (must start with `acc_`) | Throws at client construction |
63
+ | `fetch` | No | Falls back to `globalThis.fetch`; throws if neither exists |
64
+ | `fileReader` | Only for `ingots.uploadFromUri` | Throws on first upload-from-URI call |
65
+ | `fileDownloader` | Only for `ingots.downloadToFile` | Throws on first file-download call |
66
+ | `passkeyProvider` | Only for passkey sign-in UI | Passkey is hidden from the Identity dialog |
67
+ | `logger` | No | No-op logger |
68
+
69
+ ## Modules
70
+
71
+ - `auth`: Identity config, TOTP/passkey login, JWKS/JWT verification, Core exchange, signup completion, profile, and account APIs.
72
+ - `vaults`: Vault CRUD, unseal/seal, sharing, access retention, and public upload settings.
73
+ - `folders`: Folder CRUD, breadcrumbs, folder moves, and ingot moves.
74
+ - `ingots`: List/search/get, URI streaming upload/replace, rename/delete, sharing, access logs, and SDK-managed file downloads.
75
+ - `health`: Root API availability checks.
76
+ - `sparks`: SparkSync spark list/read/create operations.
77
+ - `entropy`: HSM-backed entropy generation.
78
+ - `pushTokens`: Expo push-token registration/removal.
79
+ - `billing`: Account balance.
80
+
81
+ ## Identity Dialog
82
+
83
+ `SparkVaultIdentityDialog` is the mobile equivalent of the web SDK Identity popup. It fetches Identity App config, renders email/phone input from `allowedIdentityTypes`, offers enabled mobile-supported methods (`passkey`, `totp_email`, `totp_sms`, `totp_voice`), applies configured branding and light/dark mode, and returns the raw signed Identity JWT plus JWKS metadata.
84
+
85
+ ```tsx
86
+ import * as Passkey from 'react-native-passkeys';
87
+ import {
88
+ SparkVaultIdentityDialog,
89
+ type MobilePasskeyProvider,
90
+ } from '@sparkvault/sdk-mobile/identity-dialog';
91
+
92
+ const passkeyProvider: MobilePasskeyProvider = {
93
+ isSupported: () => Passkey.isSupported(),
94
+ authenticate: async (options) => {
95
+ const credential = await Passkey.get({
96
+ challenge: options.challenge,
97
+ timeout: options.timeout,
98
+ rpId: options.rpId,
99
+ allowCredentials: options.allowCredentials,
100
+ userVerification: options.userVerification,
101
+ });
102
+
103
+ return credential
104
+ ? {
105
+ id: credential.id,
106
+ rawId: credential.rawId,
107
+ type: 'public-key',
108
+ response: {
109
+ clientDataJSON: credential.response.clientDataJSON,
110
+ authenticatorData: credential.response.authenticatorData,
111
+ signature: credential.response.signature,
112
+ },
113
+ }
114
+ : null;
115
+ },
116
+ };
117
+
118
+ <SparkVaultIdentityDialog
119
+ client={sparkVault}
120
+ visible={visible}
121
+ passkeyProvider={passkeyProvider}
122
+ onCancel={() => setVisible(false)}
123
+ onSuccess={async (result) => {
124
+ await sparkVault.auth.verifyIdentityToken(result.token, { jwks: result.jwks });
125
+ const session = await sparkVault.auth.exchangeIdentityToken(result.token);
126
+ // Continue only after local verification and Core exchange succeed.
127
+ }}
128
+ />;
129
+ ```
130
+
131
+ Client-side JWT verification is an app integrity gate. Third-party backends must still verify the token server-side with the JWKS endpoint before creating their own sessions.
132
+
133
+ ## Health Check
134
+
135
+ ```typescript
136
+ const status = await sparkVault.health.check();
137
+ const online = await sparkVault.health.isOnline();
138
+ ```
139
+
140
+ ## Ingot Upload
141
+
142
+ ```typescript
143
+ const session = await sparkVault.vaults.unseal(vaultId, { vmk });
144
+
145
+ await sparkVault.ingots.uploadFromUri({
146
+ vaultId,
147
+ vat: session.vat,
148
+ fileUri,
149
+ fileSize,
150
+ name: 'receipt.pdf',
151
+ contentType: 'application/pdf',
152
+ onProgress: (uploaded, total) => console.log(uploaded / total),
153
+ });
154
+
155
+ await sparkVault.ingots.replaceFromUri({
156
+ vaultId,
157
+ ingotId,
158
+ vat: session.vat,
159
+ fileUri,
160
+ fileSize,
161
+ name: 'receipt.pdf',
162
+ contentType: 'application/pdf',
163
+ });
164
+ ```
165
+
166
+ Uploads use Forge with tus v1.0.0 and read file chunks through the configured
167
+ `fileReader` adapter. Generated content should be staged to a file URI first so
168
+ all uploads use the same streaming path.
169
+
170
+ ## Ingot Download
171
+
172
+ ```typescript
173
+ const result = await sparkVault.ingots.downloadToFile({
174
+ vaultId,
175
+ ingotId,
176
+ vat: session.vat,
177
+ fileUri: cacheFileUri,
178
+ expectedSizeBytes,
179
+ onProgress: (downloaded, total) => console.log(downloaded / total),
180
+ });
181
+ ```
182
+
183
+ Downloads use the configured `fileDownloader` adapter for one canonical
184
+ streaming path across every supported file size. Production adapters should
185
+ honor `abortSignal` and `timeoutMs`, and should throw on transport failure
186
+ instead of writing an error response as a successful file.
package/dist/auth.d.ts ADDED
@@ -0,0 +1,74 @@
1
+ import { type ResolvedMobileConfig } from './config.js';
2
+ import type { MobileHttpClient } from './http.js';
3
+ import type { CompleteSignupRequest, CompleteSignupResponse, IdentityConfig, IdentityJwks, IdentityTokenClaims, IdentityType, IdentityVerifyResult, PasskeyAuthChallenge, PasskeyCredential, PasskeyRegisterChallenge, PasskeySession, PasskeyStatus, PinVerifyRequest, PinVerifyResponse, RequestPinRequest, RequestPinResponse, SendTotpRequest, SparkVaultAccount, SparkVaultUser, VerifyTotpRequest } from './types.js';
4
+ export declare class MobileAuthClient {
5
+ private readonly config;
6
+ private readonly http;
7
+ private configCache;
8
+ private jwksCache;
9
+ private jwksCachedAt;
10
+ constructor(config: ResolvedMobileConfig, http: MobileHttpClient);
11
+ getJwksUri(): string;
12
+ getConfig(): Promise<IdentityConfig>;
13
+ preloadConfig(): void;
14
+ isConfigPreloaded(): boolean;
15
+ getJwks(options?: {
16
+ forceRefresh?: boolean;
17
+ }): Promise<IdentityJwks>;
18
+ verifyIdentityToken(token: string, options?: {
19
+ jwks?: IdentityJwks;
20
+ audience?: string;
21
+ clockSkewSeconds?: number;
22
+ }): Promise<IdentityTokenClaims>;
23
+ private resolveJwk;
24
+ private tryFindJwk;
25
+ sendTotp(request: SendTotpRequest): Promise<RequestPinResponse>;
26
+ requestPin(request: RequestPinRequest): Promise<RequestPinResponse>;
27
+ verifyTotp(request: VerifyTotpRequest): Promise<IdentityVerifyResult>;
28
+ verifyPin(request: PinVerifyRequest): Promise<PinVerifyResponse>;
29
+ completeSignup(signupToken: string, request: CompleteSignupRequest): Promise<CompleteSignupResponse>;
30
+ signup(params: {
31
+ signup_token: string;
32
+ organization_name: string;
33
+ full_name?: string;
34
+ }): Promise<CompleteSignupResponse>;
35
+ checkPasskeyStatus(identity: string, identityType?: IdentityType): Promise<{
36
+ hasPasskey: boolean;
37
+ }>;
38
+ getPasskeyAuthOptions(identity: string, identityType?: IdentityType): Promise<PasskeyAuthChallenge>;
39
+ completePasskeyAuthentication(credential: PasskeyCredential, session: PasskeySession): Promise<IdentityVerifyResult>;
40
+ verifyPasskeyAuth(credential: PasskeyCredential, session: PasskeySession): Promise<PinVerifyResponse>;
41
+ getPasskeyRegisterOptions(params?: {
42
+ email?: string;
43
+ deviceName?: string;
44
+ }): Promise<PasskeyRegisterChallenge>;
45
+ registerPasskey(credential: PasskeyCredential, session: PasskeySession): Promise<{
46
+ success: boolean;
47
+ credential_id: string;
48
+ }>;
49
+ getMyPasskeyStatus(): Promise<PasskeyStatus>;
50
+ getProfile(): Promise<SparkVaultUser>;
51
+ updateProfile(updates: {
52
+ name?: string;
53
+ }): Promise<SparkVaultUser>;
54
+ getAccount(): Promise<SparkVaultAccount>;
55
+ revokeRefreshToken(refreshToken?: string): Promise<void>;
56
+ logout(options?: {
57
+ revoke?: boolean;
58
+ clearTokens?: boolean;
59
+ }): Promise<void>;
60
+ exchangeIdentityToken(identityToken: string): Promise<PinVerifyResponse>;
61
+ private storeSession;
62
+ private verifyTotpWithRetryErrors;
63
+ private startConfigLoad;
64
+ private toIdentityVerifyResult;
65
+ private decodeIdentityTokenClaims;
66
+ private getIdentity;
67
+ private postIdentity;
68
+ private identityHeaders;
69
+ private identityLookupBody;
70
+ private normalizeIdentity;
71
+ private selectJwk;
72
+ private isIdentityTokenClaims;
73
+ private getStoredUserEmail;
74
+ }