@arke-institute/sdk 2.0.0 → 2.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 CHANGED
@@ -151,6 +151,111 @@ const arke = new ArkeClient({
151
151
  });
152
152
  ```
153
153
 
154
+ ## Folder Upload
155
+
156
+ Upload entire folder structures with automatic CID computation and relationship linking:
157
+
158
+ ### Node.js
159
+
160
+ ```typescript
161
+ import { ArkeClient } from '@arke-institute/sdk';
162
+ import { uploadTree, scanDirectory } from '@arke-institute/sdk/operations';
163
+
164
+ const arke = new ArkeClient({ authToken: 'your-token' });
165
+
166
+ // Scan a local directory
167
+ const tree = await scanDirectory('/path/to/my-folder');
168
+
169
+ // Upload to a new collection
170
+ const result = await uploadTree(arke, tree, {
171
+ target: {
172
+ createCollection: {
173
+ label: 'My Upload',
174
+ description: 'Uploaded folder contents',
175
+ },
176
+ },
177
+ onProgress: (p) => {
178
+ console.log(`${p.phase}: ${p.completedFiles}/${p.totalFiles} files`);
179
+ },
180
+ });
181
+
182
+ console.log('Collection:', result.collection.id);
183
+ console.log('Files:', result.files.length);
184
+ console.log('Folders:', result.folders.length);
185
+ ```
186
+
187
+ ### Browser (Drag & Drop)
188
+
189
+ ```typescript
190
+ import { uploadTree, scanFileSystemEntries } from '@arke-institute/sdk/operations';
191
+
192
+ dropzone.ondrop = async (e) => {
193
+ e.preventDefault();
194
+ const entries = Array.from(e.dataTransfer.items)
195
+ .map(item => item.webkitGetAsEntry())
196
+ .filter(Boolean);
197
+
198
+ const tree = await scanFileSystemEntries(entries);
199
+ const result = await uploadTree(client, tree, {
200
+ target: { collectionId: 'existing-collection-id' },
201
+ });
202
+ };
203
+ ```
204
+
205
+ ### Browser (File Input)
206
+
207
+ ```typescript
208
+ import { uploadTree, scanFileList } from '@arke-institute/sdk/operations';
209
+
210
+ // <input type="file" webkitdirectory multiple />
211
+ input.onchange = async (e) => {
212
+ const tree = await scanFileList(e.target.files);
213
+ const result = await uploadTree(client, tree, {
214
+ target: { parentId: 'existing-folder-id', collectionId: 'collection-id' },
215
+ });
216
+ };
217
+ ```
218
+
219
+ ### Upload Options
220
+
221
+ ```typescript
222
+ const result = await uploadTree(client, tree, {
223
+ target: {
224
+ // Option 1: Create new collection
225
+ createCollection: { label: 'New Collection' },
226
+
227
+ // Option 2: Upload to existing collection root
228
+ collectionId: '01ABC...',
229
+
230
+ // Option 3: Upload to existing folder
231
+ collectionId: '01ABC...',
232
+ parentId: '01XYZ...',
233
+ },
234
+
235
+ // Progress tracking
236
+ onProgress: (p) => console.log(p.phase, p.completedFiles),
237
+
238
+ // Parallel uploads (default: 5)
239
+ concurrency: 10,
240
+
241
+ // Continue if some files fail
242
+ continueOnError: true,
243
+ });
244
+ ```
245
+
246
+ ### CID Utilities
247
+
248
+ ```typescript
249
+ import { computeCid, verifyCid } from '@arke-institute/sdk/operations';
250
+
251
+ // Compute CIDv1 for any content
252
+ const cid = await computeCid(new TextEncoder().encode('hello'));
253
+ // => "bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e"
254
+
255
+ // Verify content matches CID
256
+ const isValid = await verifyCid(content, expectedCid);
257
+ ```
258
+
154
259
  ## Development
155
260
 
156
261
  ### Regenerate Types
@@ -187,13 +292,12 @@ npm run publish-all:dry
187
292
  npm run publish-all
188
293
  ```
189
294
 
190
- ## Future Operations (TODO)
295
+ ## Future Operations
191
296
 
192
- The SDK includes placeholder modules for high-level operations:
297
+ The SDK includes placeholder modules for additional high-level operations:
193
298
 
194
- - **FolderOperations**: Recursive directory upload
195
299
  - **BatchOperations**: Bulk entity/relationship creation
196
- - **CryptoOperations**: Ed25519 key generation, CID computation
300
+ - **CryptoOperations**: Ed25519 key generation
197
301
 
198
302
  ## License
199
303
 
@@ -99,16 +99,170 @@ declare class ArkeClient {
99
99
  declare function createArkeClient(config?: ArkeClientConfig): ArkeClient;
100
100
 
101
101
  /**
102
- * Folder Operations
102
+ * Upload Types
103
103
  *
104
- * High-level operations for working with folders and directory structures.
104
+ * Type definitions for the folder/file upload system.
105
+ */
106
+ /**
107
+ * Represents a file to be uploaded.
108
+ * Platform-agnostic - works with browser File API or Node.js buffers.
109
+ */
110
+ interface UploadFile {
111
+ /** Filename (e.g., "document.pdf") */
112
+ name: string;
113
+ /** Relative path from upload root (e.g., "docs/reports/document.pdf") */
114
+ relativePath: string;
115
+ /** File size in bytes */
116
+ size: number;
117
+ /** MIME type (e.g., "application/pdf") */
118
+ mimeType: string;
119
+ /**
120
+ * Function to retrieve the file data.
121
+ * Called during upload phase.
122
+ */
123
+ getData: () => Promise<ArrayBuffer | Blob | Uint8Array>;
124
+ }
125
+ /**
126
+ * Represents a folder in the upload tree.
127
+ */
128
+ interface UploadFolder {
129
+ /** Folder name (e.g., "reports") */
130
+ name: string;
131
+ /** Relative path from upload root (e.g., "docs/reports") */
132
+ relativePath: string;
133
+ }
134
+ /**
135
+ * Complete tree structure to upload.
136
+ * Built by platform-specific scanners.
137
+ */
138
+ interface UploadTree {
139
+ /** All files to upload */
140
+ files: UploadFile[];
141
+ /** All folders to create (sorted by depth for correct ordering) */
142
+ folders: UploadFolder[];
143
+ }
144
+ /**
145
+ * Target specification for upload.
146
+ * Determines where items will be placed.
147
+ */
148
+ interface UploadTarget {
149
+ /**
150
+ * Collection ID - required for permissions.
151
+ * If not provided and createCollection is not set, upload will fail.
152
+ */
153
+ collectionId?: string;
154
+ /**
155
+ * Parent folder/collection ID where items will be added.
156
+ * If not provided, items go to collection root.
157
+ * Can be the same as collectionId (collection acts as folder).
158
+ */
159
+ parentId?: string;
160
+ /**
161
+ * Create a new collection for this upload.
162
+ * If set, collectionId is ignored.
163
+ */
164
+ createCollection?: {
165
+ /** Collection display name (required) */
166
+ label: string;
167
+ /** Collection description */
168
+ description?: string;
169
+ /** Custom roles (uses defaults if not provided) */
170
+ roles?: Record<string, string[]>;
171
+ };
172
+ }
173
+ /**
174
+ * Upload progress tracking.
175
+ */
176
+ interface UploadProgress$1 {
177
+ /** Current phase of the upload */
178
+ phase: 'scanning' | 'computing-cids' | 'creating-folders' | 'creating-files' | 'uploading-content' | 'linking' | 'complete' | 'error';
179
+ /** Total number of files to upload */
180
+ totalFiles: number;
181
+ /** Number of files completed */
182
+ completedFiles: number;
183
+ /** Total number of folders to create */
184
+ totalFolders: number;
185
+ /** Number of folders completed */
186
+ completedFolders: number;
187
+ /** Current file being processed */
188
+ currentFile?: string;
189
+ /** Current folder being processed */
190
+ currentFolder?: string;
191
+ /** Error message if phase is 'error' */
192
+ error?: string;
193
+ /** Bytes uploaded so far (for content upload phase) */
194
+ bytesUploaded?: number;
195
+ /** Total bytes to upload */
196
+ totalBytes?: number;
197
+ }
198
+ /**
199
+ * Configuration options for upload.
200
+ */
201
+ interface UploadOptions {
202
+ /** Where to upload */
203
+ target: UploadTarget;
204
+ /** Progress callback */
205
+ onProgress?: (progress: UploadProgress$1) => void;
206
+ /** Maximum concurrent operations (default: 5) */
207
+ concurrency?: number;
208
+ /** Continue uploading even if some files fail (default: false) */
209
+ continueOnError?: boolean;
210
+ /** Custom note to add to created entities */
211
+ note?: string;
212
+ }
213
+ /**
214
+ * Information about a created entity.
215
+ */
216
+ interface CreatedEntity {
217
+ /** Entity ID (ULID) */
218
+ id: string;
219
+ /** Entity CID */
220
+ cid: string;
221
+ /** Entity type */
222
+ type: 'file' | 'folder' | 'collection';
223
+ /** Original path in upload tree */
224
+ relativePath: string;
225
+ }
226
+ /**
227
+ * Result of an upload operation.
228
+ */
229
+ interface UploadResult {
230
+ /** Whether upload completed successfully */
231
+ success: boolean;
232
+ /** Collection used or created */
233
+ collection: {
234
+ id: string;
235
+ cid: string;
236
+ created: boolean;
237
+ };
238
+ /** Created folder entities */
239
+ folders: CreatedEntity[];
240
+ /** Created file entities */
241
+ files: CreatedEntity[];
242
+ /** Errors encountered (if continueOnError was true) */
243
+ errors: Array<{
244
+ path: string;
245
+ error: string;
246
+ }>;
247
+ }
248
+
249
+ /**
250
+ * Folder Operations (Legacy)
251
+ *
252
+ * @deprecated Use the new upload module instead:
253
+ * ```typescript
254
+ * import { uploadTree, scanDirectory } from '@arke-institute/sdk/operations';
105
255
  *
106
- * TODO: Implement folder operations
107
- * - uploadDirectory: Recursively upload a local directory
108
- * - createFolderHierarchy: Create folder structure from paths
109
- * - moveFolderContents: Move files between folders
256
+ * const tree = await scanDirectory('/path/to/folder');
257
+ * const result = await uploadTree(client, tree, {
258
+ * target: { collectionId: '...' },
259
+ * });
260
+ * ```
110
261
  */
111
262
 
263
+ /**
264
+ * @deprecated Use UploadProgress from upload module
265
+ */
112
266
  interface UploadProgress {
113
267
  phase: 'scanning' | 'creating-folders' | 'uploading-files' | 'linking' | 'complete';
114
268
  totalFiles: number;
@@ -117,6 +271,9 @@ interface UploadProgress {
117
271
  completedFolders: number;
118
272
  currentFile?: string;
119
273
  }
274
+ /**
275
+ * @deprecated Use UploadOptions from upload module
276
+ */
120
277
  interface UploadDirectoryOptions {
121
278
  /** Collection to upload into */
122
279
  collectionId: string;
@@ -127,6 +284,9 @@ interface UploadDirectoryOptions {
127
284
  /** Max concurrent uploads */
128
285
  concurrency?: number;
129
286
  }
287
+ /**
288
+ * @deprecated Use UploadResult from upload module
289
+ */
130
290
  interface UploadDirectoryResult {
131
291
  /** Root folder entity */
132
292
  rootFolder: unknown;
@@ -138,11 +298,13 @@ interface UploadDirectoryResult {
138
298
  /**
139
299
  * Folder operations helper
140
300
  *
141
- * @example
301
+ * @deprecated Use uploadTree and scanDirectory functions instead:
142
302
  * ```typescript
143
- * const folders = new FolderOperations(arkeClient);
144
- * const result = await folders.uploadDirectory('/path/to/local/folder', {
145
- * collectionId: '01ABC...',
303
+ * import { uploadTree, scanDirectory } from '@arke-institute/sdk/operations';
304
+ *
305
+ * const tree = await scanDirectory('/path/to/folder');
306
+ * const result = await uploadTree(client, tree, {
307
+ * target: { collectionId: '...' },
146
308
  * onProgress: (p) => console.log(`${p.completedFiles}/${p.totalFiles} files`),
147
309
  * });
148
310
  * ```
@@ -153,14 +315,9 @@ declare class FolderOperations {
153
315
  /**
154
316
  * Upload a local directory to Arke
155
317
  *
156
- * TODO: Implement this method
157
- * Steps:
158
- * 1. Scan directory structure
159
- * 2. Create folder hierarchy (depth-first)
160
- * 3. Upload files in parallel (with concurrency limit)
161
- * 4. Create bidirectional relationships (folder contains file)
318
+ * @deprecated Use uploadTree and scanDirectory instead
162
319
  */
163
- uploadDirectory(_localPath: string, _options: UploadDirectoryOptions): Promise<UploadDirectoryResult>;
320
+ uploadDirectory(localPath: string, options: UploadDirectoryOptions): Promise<UploadDirectoryResult>;
164
321
  }
165
322
 
166
323
  /**
@@ -299,4 +456,4 @@ declare class CryptoOperations {
299
456
  static computeCID(_content: Uint8Array): Promise<string>;
300
457
  }
301
458
 
302
- export { ArkeClient as A, BatchOperations as B, CryptoOperations as C, DEFAULT_CONFIG as D, FolderOperations as F, type KeyPair as K, type SignedPayload as S, type UploadProgress as U, type ArkeApiClient as a, type ArkeClientConfig as b, createArkeClient as c, type UploadDirectoryOptions as d, type UploadDirectoryResult as e, type BatchCreateOptions as f, type BatchResult as g };
459
+ export { ArkeClient as A, BatchOperations as B, CryptoOperations as C, DEFAULT_CONFIG as D, FolderOperations as F, type KeyPair as K, type SignedPayload as S, type UploadProgress$1 as U, type ArkeApiClient as a, type ArkeClientConfig as b, createArkeClient as c, type UploadDirectoryOptions as d, type UploadDirectoryResult as e, type BatchCreateOptions as f, type BatchResult as g, type UploadTree as h, type UploadOptions as i, type UploadResult as j, type UploadFile as k, type UploadFolder as l, type UploadTarget as m, type CreatedEntity as n };
@@ -99,16 +99,170 @@ declare class ArkeClient {
99
99
  declare function createArkeClient(config?: ArkeClientConfig): ArkeClient;
100
100
 
101
101
  /**
102
- * Folder Operations
102
+ * Upload Types
103
103
  *
104
- * High-level operations for working with folders and directory structures.
104
+ * Type definitions for the folder/file upload system.
105
+ */
106
+ /**
107
+ * Represents a file to be uploaded.
108
+ * Platform-agnostic - works with browser File API or Node.js buffers.
109
+ */
110
+ interface UploadFile {
111
+ /** Filename (e.g., "document.pdf") */
112
+ name: string;
113
+ /** Relative path from upload root (e.g., "docs/reports/document.pdf") */
114
+ relativePath: string;
115
+ /** File size in bytes */
116
+ size: number;
117
+ /** MIME type (e.g., "application/pdf") */
118
+ mimeType: string;
119
+ /**
120
+ * Function to retrieve the file data.
121
+ * Called during upload phase.
122
+ */
123
+ getData: () => Promise<ArrayBuffer | Blob | Uint8Array>;
124
+ }
125
+ /**
126
+ * Represents a folder in the upload tree.
127
+ */
128
+ interface UploadFolder {
129
+ /** Folder name (e.g., "reports") */
130
+ name: string;
131
+ /** Relative path from upload root (e.g., "docs/reports") */
132
+ relativePath: string;
133
+ }
134
+ /**
135
+ * Complete tree structure to upload.
136
+ * Built by platform-specific scanners.
137
+ */
138
+ interface UploadTree {
139
+ /** All files to upload */
140
+ files: UploadFile[];
141
+ /** All folders to create (sorted by depth for correct ordering) */
142
+ folders: UploadFolder[];
143
+ }
144
+ /**
145
+ * Target specification for upload.
146
+ * Determines where items will be placed.
147
+ */
148
+ interface UploadTarget {
149
+ /**
150
+ * Collection ID - required for permissions.
151
+ * If not provided and createCollection is not set, upload will fail.
152
+ */
153
+ collectionId?: string;
154
+ /**
155
+ * Parent folder/collection ID where items will be added.
156
+ * If not provided, items go to collection root.
157
+ * Can be the same as collectionId (collection acts as folder).
158
+ */
159
+ parentId?: string;
160
+ /**
161
+ * Create a new collection for this upload.
162
+ * If set, collectionId is ignored.
163
+ */
164
+ createCollection?: {
165
+ /** Collection display name (required) */
166
+ label: string;
167
+ /** Collection description */
168
+ description?: string;
169
+ /** Custom roles (uses defaults if not provided) */
170
+ roles?: Record<string, string[]>;
171
+ };
172
+ }
173
+ /**
174
+ * Upload progress tracking.
175
+ */
176
+ interface UploadProgress$1 {
177
+ /** Current phase of the upload */
178
+ phase: 'scanning' | 'computing-cids' | 'creating-folders' | 'creating-files' | 'uploading-content' | 'linking' | 'complete' | 'error';
179
+ /** Total number of files to upload */
180
+ totalFiles: number;
181
+ /** Number of files completed */
182
+ completedFiles: number;
183
+ /** Total number of folders to create */
184
+ totalFolders: number;
185
+ /** Number of folders completed */
186
+ completedFolders: number;
187
+ /** Current file being processed */
188
+ currentFile?: string;
189
+ /** Current folder being processed */
190
+ currentFolder?: string;
191
+ /** Error message if phase is 'error' */
192
+ error?: string;
193
+ /** Bytes uploaded so far (for content upload phase) */
194
+ bytesUploaded?: number;
195
+ /** Total bytes to upload */
196
+ totalBytes?: number;
197
+ }
198
+ /**
199
+ * Configuration options for upload.
200
+ */
201
+ interface UploadOptions {
202
+ /** Where to upload */
203
+ target: UploadTarget;
204
+ /** Progress callback */
205
+ onProgress?: (progress: UploadProgress$1) => void;
206
+ /** Maximum concurrent operations (default: 5) */
207
+ concurrency?: number;
208
+ /** Continue uploading even if some files fail (default: false) */
209
+ continueOnError?: boolean;
210
+ /** Custom note to add to created entities */
211
+ note?: string;
212
+ }
213
+ /**
214
+ * Information about a created entity.
215
+ */
216
+ interface CreatedEntity {
217
+ /** Entity ID (ULID) */
218
+ id: string;
219
+ /** Entity CID */
220
+ cid: string;
221
+ /** Entity type */
222
+ type: 'file' | 'folder' | 'collection';
223
+ /** Original path in upload tree */
224
+ relativePath: string;
225
+ }
226
+ /**
227
+ * Result of an upload operation.
228
+ */
229
+ interface UploadResult {
230
+ /** Whether upload completed successfully */
231
+ success: boolean;
232
+ /** Collection used or created */
233
+ collection: {
234
+ id: string;
235
+ cid: string;
236
+ created: boolean;
237
+ };
238
+ /** Created folder entities */
239
+ folders: CreatedEntity[];
240
+ /** Created file entities */
241
+ files: CreatedEntity[];
242
+ /** Errors encountered (if continueOnError was true) */
243
+ errors: Array<{
244
+ path: string;
245
+ error: string;
246
+ }>;
247
+ }
248
+
249
+ /**
250
+ * Folder Operations (Legacy)
251
+ *
252
+ * @deprecated Use the new upload module instead:
253
+ * ```typescript
254
+ * import { uploadTree, scanDirectory } from '@arke-institute/sdk/operations';
105
255
  *
106
- * TODO: Implement folder operations
107
- * - uploadDirectory: Recursively upload a local directory
108
- * - createFolderHierarchy: Create folder structure from paths
109
- * - moveFolderContents: Move files between folders
256
+ * const tree = await scanDirectory('/path/to/folder');
257
+ * const result = await uploadTree(client, tree, {
258
+ * target: { collectionId: '...' },
259
+ * });
260
+ * ```
110
261
  */
111
262
 
263
+ /**
264
+ * @deprecated Use UploadProgress from upload module
265
+ */
112
266
  interface UploadProgress {
113
267
  phase: 'scanning' | 'creating-folders' | 'uploading-files' | 'linking' | 'complete';
114
268
  totalFiles: number;
@@ -117,6 +271,9 @@ interface UploadProgress {
117
271
  completedFolders: number;
118
272
  currentFile?: string;
119
273
  }
274
+ /**
275
+ * @deprecated Use UploadOptions from upload module
276
+ */
120
277
  interface UploadDirectoryOptions {
121
278
  /** Collection to upload into */
122
279
  collectionId: string;
@@ -127,6 +284,9 @@ interface UploadDirectoryOptions {
127
284
  /** Max concurrent uploads */
128
285
  concurrency?: number;
129
286
  }
287
+ /**
288
+ * @deprecated Use UploadResult from upload module
289
+ */
130
290
  interface UploadDirectoryResult {
131
291
  /** Root folder entity */
132
292
  rootFolder: unknown;
@@ -138,11 +298,13 @@ interface UploadDirectoryResult {
138
298
  /**
139
299
  * Folder operations helper
140
300
  *
141
- * @example
301
+ * @deprecated Use uploadTree and scanDirectory functions instead:
142
302
  * ```typescript
143
- * const folders = new FolderOperations(arkeClient);
144
- * const result = await folders.uploadDirectory('/path/to/local/folder', {
145
- * collectionId: '01ABC...',
303
+ * import { uploadTree, scanDirectory } from '@arke-institute/sdk/operations';
304
+ *
305
+ * const tree = await scanDirectory('/path/to/folder');
306
+ * const result = await uploadTree(client, tree, {
307
+ * target: { collectionId: '...' },
146
308
  * onProgress: (p) => console.log(`${p.completedFiles}/${p.totalFiles} files`),
147
309
  * });
148
310
  * ```
@@ -153,14 +315,9 @@ declare class FolderOperations {
153
315
  /**
154
316
  * Upload a local directory to Arke
155
317
  *
156
- * TODO: Implement this method
157
- * Steps:
158
- * 1. Scan directory structure
159
- * 2. Create folder hierarchy (depth-first)
160
- * 3. Upload files in parallel (with concurrency limit)
161
- * 4. Create bidirectional relationships (folder contains file)
318
+ * @deprecated Use uploadTree and scanDirectory instead
162
319
  */
163
- uploadDirectory(_localPath: string, _options: UploadDirectoryOptions): Promise<UploadDirectoryResult>;
320
+ uploadDirectory(localPath: string, options: UploadDirectoryOptions): Promise<UploadDirectoryResult>;
164
321
  }
165
322
 
166
323
  /**
@@ -299,4 +456,4 @@ declare class CryptoOperations {
299
456
  static computeCID(_content: Uint8Array): Promise<string>;
300
457
  }
301
458
 
302
- export { ArkeClient as A, BatchOperations as B, CryptoOperations as C, DEFAULT_CONFIG as D, FolderOperations as F, type KeyPair as K, type SignedPayload as S, type UploadProgress as U, type ArkeApiClient as a, type ArkeClientConfig as b, createArkeClient as c, type UploadDirectoryOptions as d, type UploadDirectoryResult as e, type BatchCreateOptions as f, type BatchResult as g };
459
+ export { ArkeClient as A, BatchOperations as B, CryptoOperations as C, DEFAULT_CONFIG as D, FolderOperations as F, type KeyPair as K, type SignedPayload as S, type UploadProgress$1 as U, type ArkeApiClient as a, type ArkeClientConfig as b, createArkeClient as c, type UploadDirectoryOptions as d, type UploadDirectoryResult as e, type BatchCreateOptions as f, type BatchResult as g, type UploadTree as h, type UploadOptions as i, type UploadResult as j, type UploadFile as k, type UploadFolder as l, type UploadTarget as m, type CreatedEntity as n };