@arke-institute/sdk 3.6.0 → 3.6.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.
- package/dist/generated/index.d.cts +157 -1
- package/dist/generated/index.d.ts +157 -1
- package/dist/operations/index.cjs +181 -0
- package/dist/operations/index.cjs.map +1 -1
- package/dist/operations/index.d.cts +99 -1
- package/dist/operations/index.d.ts +99 -1
- package/dist/operations/index.js +180 -0
- package/dist/operations/index.js.map +1 -1
- package/openapi/spec.json +173 -0
- package/openapi/version.json +1 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Source: Arke v1 API
|
|
8
8
|
* Version: 1.0.0
|
|
9
|
-
* Generated: 2026-02-
|
|
9
|
+
* Generated: 2026-02-09T15:17:42.566Z
|
|
10
10
|
*/
|
|
11
11
|
type paths = {
|
|
12
12
|
"/ops-reference": {
|
|
@@ -160,6 +160,84 @@ type paths = {
|
|
|
160
160
|
patch?: never;
|
|
161
161
|
trace?: never;
|
|
162
162
|
};
|
|
163
|
+
"/auth/whoami": {
|
|
164
|
+
parameters: {
|
|
165
|
+
query?: never;
|
|
166
|
+
header?: never;
|
|
167
|
+
path?: never;
|
|
168
|
+
cookie?: never;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Get current identity
|
|
172
|
+
* @description Returns identity information for the authenticated caller.
|
|
173
|
+
*
|
|
174
|
+
* Accepts any valid credential type:
|
|
175
|
+
* - **JWT**: Returns user PI, email, name, and Supabase user ID
|
|
176
|
+
* - **User API Key (uk_)**: Returns user PI and key metadata
|
|
177
|
+
* - **Agent API Key (ak_)**: Returns agent PI, owner PI, and key metadata
|
|
178
|
+
*
|
|
179
|
+
* Use this endpoint to verify credentials are working or to retrieve the caller's entity PI.
|
|
180
|
+
*
|
|
181
|
+
* ---
|
|
182
|
+
* **Permission:** `auth:whoami`
|
|
183
|
+
* **Auth:** required
|
|
184
|
+
*/
|
|
185
|
+
get: {
|
|
186
|
+
parameters: {
|
|
187
|
+
query?: never;
|
|
188
|
+
header?: never;
|
|
189
|
+
path?: never;
|
|
190
|
+
cookie?: never;
|
|
191
|
+
};
|
|
192
|
+
requestBody?: never;
|
|
193
|
+
responses: {
|
|
194
|
+
/** @description Identity information */
|
|
195
|
+
200: {
|
|
196
|
+
headers: {
|
|
197
|
+
[name: string]: unknown;
|
|
198
|
+
};
|
|
199
|
+
content: {
|
|
200
|
+
"application/json": components["schemas"]["WhoamiResponse"];
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
/** @description Unauthorized - Missing or invalid authentication */
|
|
204
|
+
401: {
|
|
205
|
+
headers: {
|
|
206
|
+
[name: string]: unknown;
|
|
207
|
+
};
|
|
208
|
+
content: {
|
|
209
|
+
/**
|
|
210
|
+
* @example {
|
|
211
|
+
* "error": "Unauthorized: Missing or invalid authentication token"
|
|
212
|
+
* }
|
|
213
|
+
*/
|
|
214
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
/** @description Internal Server Error */
|
|
218
|
+
500: {
|
|
219
|
+
headers: {
|
|
220
|
+
[name: string]: unknown;
|
|
221
|
+
};
|
|
222
|
+
content: {
|
|
223
|
+
/**
|
|
224
|
+
* @example {
|
|
225
|
+
* "error": "Internal server error"
|
|
226
|
+
* }
|
|
227
|
+
*/
|
|
228
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
put?: never;
|
|
234
|
+
post?: never;
|
|
235
|
+
delete?: never;
|
|
236
|
+
options?: never;
|
|
237
|
+
head?: never;
|
|
238
|
+
patch?: never;
|
|
239
|
+
trace?: never;
|
|
240
|
+
};
|
|
163
241
|
"/alpha/invite": {
|
|
164
242
|
parameters: {
|
|
165
243
|
query?: never;
|
|
@@ -9177,6 +9255,84 @@ type components = {
|
|
|
9177
9255
|
[key: string]: unknown;
|
|
9178
9256
|
};
|
|
9179
9257
|
};
|
|
9258
|
+
WhoamiUserResponse: {
|
|
9259
|
+
/**
|
|
9260
|
+
* @description Identity type
|
|
9261
|
+
* @enum {string}
|
|
9262
|
+
*/
|
|
9263
|
+
type: "user";
|
|
9264
|
+
/**
|
|
9265
|
+
* @description User entity PI (persistent identifier)
|
|
9266
|
+
* @example 01J1SHMAE10000000000000000
|
|
9267
|
+
*/
|
|
9268
|
+
pi: string;
|
|
9269
|
+
/**
|
|
9270
|
+
* @description How this identity was authenticated
|
|
9271
|
+
* @example jwt
|
|
9272
|
+
* @enum {string}
|
|
9273
|
+
*/
|
|
9274
|
+
auth_method: "jwt" | "api_key";
|
|
9275
|
+
/**
|
|
9276
|
+
* Format: email
|
|
9277
|
+
* @description User email (JWT auth only)
|
|
9278
|
+
* @example ishmael@pequod.ship
|
|
9279
|
+
*/
|
|
9280
|
+
email?: string;
|
|
9281
|
+
/**
|
|
9282
|
+
* @description Display name (JWT auth only)
|
|
9283
|
+
* @example Ishmael
|
|
9284
|
+
*/
|
|
9285
|
+
name?: string;
|
|
9286
|
+
/**
|
|
9287
|
+
* Format: uuid
|
|
9288
|
+
* @description Supabase Auth user ID (JWT auth only)
|
|
9289
|
+
*/
|
|
9290
|
+
supabase_user_id?: string;
|
|
9291
|
+
/**
|
|
9292
|
+
* @description API key prefix (API key auth only)
|
|
9293
|
+
* @example uk_abc1
|
|
9294
|
+
*/
|
|
9295
|
+
key_prefix?: string;
|
|
9296
|
+
/**
|
|
9297
|
+
* Format: date-time
|
|
9298
|
+
* @description API key expiration (API key auth only)
|
|
9299
|
+
*/
|
|
9300
|
+
key_expires_at?: string;
|
|
9301
|
+
};
|
|
9302
|
+
WhoamiAgentResponse: {
|
|
9303
|
+
/**
|
|
9304
|
+
* @description Identity type
|
|
9305
|
+
* @enum {string}
|
|
9306
|
+
*/
|
|
9307
|
+
type: "agent";
|
|
9308
|
+
/**
|
|
9309
|
+
* @description Agent entity PI (persistent identifier)
|
|
9310
|
+
* @example 01J1AGENTID000000000000000
|
|
9311
|
+
*/
|
|
9312
|
+
pi: string;
|
|
9313
|
+
/**
|
|
9314
|
+
* @description How this identity was authenticated
|
|
9315
|
+
* @example api_key
|
|
9316
|
+
* @enum {string}
|
|
9317
|
+
*/
|
|
9318
|
+
auth_method: "api_key";
|
|
9319
|
+
/**
|
|
9320
|
+
* @description Entity PI of the agent owner
|
|
9321
|
+
* @example 01J1OWNERID0000000000000000
|
|
9322
|
+
*/
|
|
9323
|
+
owner_pi: string;
|
|
9324
|
+
/**
|
|
9325
|
+
* @description API key prefix
|
|
9326
|
+
* @example ak_xyz9
|
|
9327
|
+
*/
|
|
9328
|
+
key_prefix: string;
|
|
9329
|
+
/**
|
|
9330
|
+
* Format: date-time
|
|
9331
|
+
* @description API key expiration
|
|
9332
|
+
*/
|
|
9333
|
+
key_expires_at: string;
|
|
9334
|
+
};
|
|
9335
|
+
WhoamiResponse: components["schemas"]["WhoamiUserResponse"] | components["schemas"]["WhoamiAgentResponse"];
|
|
9180
9336
|
AlphaInvite: {
|
|
9181
9337
|
/**
|
|
9182
9338
|
* Format: uuid
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Source: Arke v1 API
|
|
8
8
|
* Version: 1.0.0
|
|
9
|
-
* Generated: 2026-02-
|
|
9
|
+
* Generated: 2026-02-09T15:17:42.566Z
|
|
10
10
|
*/
|
|
11
11
|
type paths = {
|
|
12
12
|
"/ops-reference": {
|
|
@@ -160,6 +160,84 @@ type paths = {
|
|
|
160
160
|
patch?: never;
|
|
161
161
|
trace?: never;
|
|
162
162
|
};
|
|
163
|
+
"/auth/whoami": {
|
|
164
|
+
parameters: {
|
|
165
|
+
query?: never;
|
|
166
|
+
header?: never;
|
|
167
|
+
path?: never;
|
|
168
|
+
cookie?: never;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Get current identity
|
|
172
|
+
* @description Returns identity information for the authenticated caller.
|
|
173
|
+
*
|
|
174
|
+
* Accepts any valid credential type:
|
|
175
|
+
* - **JWT**: Returns user PI, email, name, and Supabase user ID
|
|
176
|
+
* - **User API Key (uk_)**: Returns user PI and key metadata
|
|
177
|
+
* - **Agent API Key (ak_)**: Returns agent PI, owner PI, and key metadata
|
|
178
|
+
*
|
|
179
|
+
* Use this endpoint to verify credentials are working or to retrieve the caller's entity PI.
|
|
180
|
+
*
|
|
181
|
+
* ---
|
|
182
|
+
* **Permission:** `auth:whoami`
|
|
183
|
+
* **Auth:** required
|
|
184
|
+
*/
|
|
185
|
+
get: {
|
|
186
|
+
parameters: {
|
|
187
|
+
query?: never;
|
|
188
|
+
header?: never;
|
|
189
|
+
path?: never;
|
|
190
|
+
cookie?: never;
|
|
191
|
+
};
|
|
192
|
+
requestBody?: never;
|
|
193
|
+
responses: {
|
|
194
|
+
/** @description Identity information */
|
|
195
|
+
200: {
|
|
196
|
+
headers: {
|
|
197
|
+
[name: string]: unknown;
|
|
198
|
+
};
|
|
199
|
+
content: {
|
|
200
|
+
"application/json": components["schemas"]["WhoamiResponse"];
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
/** @description Unauthorized - Missing or invalid authentication */
|
|
204
|
+
401: {
|
|
205
|
+
headers: {
|
|
206
|
+
[name: string]: unknown;
|
|
207
|
+
};
|
|
208
|
+
content: {
|
|
209
|
+
/**
|
|
210
|
+
* @example {
|
|
211
|
+
* "error": "Unauthorized: Missing or invalid authentication token"
|
|
212
|
+
* }
|
|
213
|
+
*/
|
|
214
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
/** @description Internal Server Error */
|
|
218
|
+
500: {
|
|
219
|
+
headers: {
|
|
220
|
+
[name: string]: unknown;
|
|
221
|
+
};
|
|
222
|
+
content: {
|
|
223
|
+
/**
|
|
224
|
+
* @example {
|
|
225
|
+
* "error": "Internal server error"
|
|
226
|
+
* }
|
|
227
|
+
*/
|
|
228
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
put?: never;
|
|
234
|
+
post?: never;
|
|
235
|
+
delete?: never;
|
|
236
|
+
options?: never;
|
|
237
|
+
head?: never;
|
|
238
|
+
patch?: never;
|
|
239
|
+
trace?: never;
|
|
240
|
+
};
|
|
163
241
|
"/alpha/invite": {
|
|
164
242
|
parameters: {
|
|
165
243
|
query?: never;
|
|
@@ -9177,6 +9255,84 @@ type components = {
|
|
|
9177
9255
|
[key: string]: unknown;
|
|
9178
9256
|
};
|
|
9179
9257
|
};
|
|
9258
|
+
WhoamiUserResponse: {
|
|
9259
|
+
/**
|
|
9260
|
+
* @description Identity type
|
|
9261
|
+
* @enum {string}
|
|
9262
|
+
*/
|
|
9263
|
+
type: "user";
|
|
9264
|
+
/**
|
|
9265
|
+
* @description User entity PI (persistent identifier)
|
|
9266
|
+
* @example 01J1SHMAE10000000000000000
|
|
9267
|
+
*/
|
|
9268
|
+
pi: string;
|
|
9269
|
+
/**
|
|
9270
|
+
* @description How this identity was authenticated
|
|
9271
|
+
* @example jwt
|
|
9272
|
+
* @enum {string}
|
|
9273
|
+
*/
|
|
9274
|
+
auth_method: "jwt" | "api_key";
|
|
9275
|
+
/**
|
|
9276
|
+
* Format: email
|
|
9277
|
+
* @description User email (JWT auth only)
|
|
9278
|
+
* @example ishmael@pequod.ship
|
|
9279
|
+
*/
|
|
9280
|
+
email?: string;
|
|
9281
|
+
/**
|
|
9282
|
+
* @description Display name (JWT auth only)
|
|
9283
|
+
* @example Ishmael
|
|
9284
|
+
*/
|
|
9285
|
+
name?: string;
|
|
9286
|
+
/**
|
|
9287
|
+
* Format: uuid
|
|
9288
|
+
* @description Supabase Auth user ID (JWT auth only)
|
|
9289
|
+
*/
|
|
9290
|
+
supabase_user_id?: string;
|
|
9291
|
+
/**
|
|
9292
|
+
* @description API key prefix (API key auth only)
|
|
9293
|
+
* @example uk_abc1
|
|
9294
|
+
*/
|
|
9295
|
+
key_prefix?: string;
|
|
9296
|
+
/**
|
|
9297
|
+
* Format: date-time
|
|
9298
|
+
* @description API key expiration (API key auth only)
|
|
9299
|
+
*/
|
|
9300
|
+
key_expires_at?: string;
|
|
9301
|
+
};
|
|
9302
|
+
WhoamiAgentResponse: {
|
|
9303
|
+
/**
|
|
9304
|
+
* @description Identity type
|
|
9305
|
+
* @enum {string}
|
|
9306
|
+
*/
|
|
9307
|
+
type: "agent";
|
|
9308
|
+
/**
|
|
9309
|
+
* @description Agent entity PI (persistent identifier)
|
|
9310
|
+
* @example 01J1AGENTID000000000000000
|
|
9311
|
+
*/
|
|
9312
|
+
pi: string;
|
|
9313
|
+
/**
|
|
9314
|
+
* @description How this identity was authenticated
|
|
9315
|
+
* @example api_key
|
|
9316
|
+
* @enum {string}
|
|
9317
|
+
*/
|
|
9318
|
+
auth_method: "api_key";
|
|
9319
|
+
/**
|
|
9320
|
+
* @description Entity PI of the agent owner
|
|
9321
|
+
* @example 01J1OWNERID0000000000000000
|
|
9322
|
+
*/
|
|
9323
|
+
owner_pi: string;
|
|
9324
|
+
/**
|
|
9325
|
+
* @description API key prefix
|
|
9326
|
+
* @example ak_xyz9
|
|
9327
|
+
*/
|
|
9328
|
+
key_prefix: string;
|
|
9329
|
+
/**
|
|
9330
|
+
* Format: date-time
|
|
9331
|
+
* @description API key expiration
|
|
9332
|
+
*/
|
|
9333
|
+
key_expires_at: string;
|
|
9334
|
+
};
|
|
9335
|
+
WhoamiResponse: components["schemas"]["WhoamiUserResponse"] | components["schemas"]["WhoamiAgentResponse"];
|
|
9180
9336
|
AlphaInvite: {
|
|
9181
9337
|
/**
|
|
9182
9338
|
* Format: uuid
|
|
@@ -43,6 +43,7 @@ __export(operations_exports, {
|
|
|
43
43
|
isCasConflictError: () => isCasConflictError,
|
|
44
44
|
scanFileList: () => scanFileList,
|
|
45
45
|
scanFileSystemEntries: () => scanFileSystemEntries,
|
|
46
|
+
uploadToEntity: () => uploadToEntity,
|
|
46
47
|
uploadTree: () => uploadTree,
|
|
47
48
|
verifyCid: () => verifyCid,
|
|
48
49
|
withCasRetry: () => withCasRetry
|
|
@@ -859,6 +860,185 @@ function buildUploadTree(items) {
|
|
|
859
860
|
return { files, folders };
|
|
860
861
|
}
|
|
861
862
|
|
|
863
|
+
// src/operations/upload/single.ts
|
|
864
|
+
var MAX_CAS_RETRIES = 3;
|
|
865
|
+
async function uploadToEntity(client, entityId, items, options = {}) {
|
|
866
|
+
if (items.length === 0) {
|
|
867
|
+
throw new Error("At least one upload item is required");
|
|
868
|
+
}
|
|
869
|
+
const { onProgress } = options;
|
|
870
|
+
let progressState = {
|
|
871
|
+
phase: "preparing",
|
|
872
|
+
totalBytes: 0,
|
|
873
|
+
uploadedBytes: 0,
|
|
874
|
+
completedFiles: 0,
|
|
875
|
+
totalFiles: items.length
|
|
876
|
+
};
|
|
877
|
+
const reportProgress = (update) => {
|
|
878
|
+
progressState = { ...progressState, ...update };
|
|
879
|
+
onProgress?.(progressState);
|
|
880
|
+
};
|
|
881
|
+
reportProgress({ phase: "preparing" });
|
|
882
|
+
const prepared = await Promise.all(
|
|
883
|
+
items.map((item) => prepareItem(item))
|
|
884
|
+
);
|
|
885
|
+
const keys = prepared.map((p) => p.key);
|
|
886
|
+
const duplicates = keys.filter((key, i) => keys.indexOf(key) !== i);
|
|
887
|
+
if (duplicates.length > 0) {
|
|
888
|
+
const uniqueDupes = [...new Set(duplicates)];
|
|
889
|
+
throw new Error(
|
|
890
|
+
`Duplicate content keys detected: ${uniqueDupes.map((k) => `"${k}"`).join(", ")}. Each file must have a unique key. Provide explicit keys to resolve.`
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
const totalBytes = prepared.reduce((sum, p) => sum + p.size, 0);
|
|
894
|
+
reportProgress({ totalBytes });
|
|
895
|
+
const uploadInfos = await Promise.all(
|
|
896
|
+
prepared.map(async (item) => {
|
|
897
|
+
const { data: presigned, error } = await client.api.POST(
|
|
898
|
+
"/entities/{id}/content/upload-url",
|
|
899
|
+
{
|
|
900
|
+
params: { path: { id: entityId } },
|
|
901
|
+
body: {
|
|
902
|
+
cid: item.cid,
|
|
903
|
+
content_type: item.contentType,
|
|
904
|
+
size: item.size
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
);
|
|
908
|
+
if (error || !presigned) {
|
|
909
|
+
throw new Error(
|
|
910
|
+
`Failed to get upload URL for ${item.key}: ${JSON.stringify(error)}`
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
return {
|
|
914
|
+
...item,
|
|
915
|
+
uploadUrl: presigned.upload_url
|
|
916
|
+
};
|
|
917
|
+
})
|
|
918
|
+
);
|
|
919
|
+
reportProgress({ phase: "uploading", uploadedBytes: 0 });
|
|
920
|
+
let uploadedBytes = 0;
|
|
921
|
+
await Promise.all(
|
|
922
|
+
uploadInfos.map(async (item) => {
|
|
923
|
+
const response = await fetch(item.uploadUrl, {
|
|
924
|
+
method: "PUT",
|
|
925
|
+
headers: { "Content-Type": item.contentType },
|
|
926
|
+
body: item.bytes
|
|
927
|
+
});
|
|
928
|
+
if (!response.ok) {
|
|
929
|
+
throw new Error(
|
|
930
|
+
`Upload to R2 failed for ${item.key}: ${response.statusText}`
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
uploadedBytes += item.size;
|
|
934
|
+
reportProgress({ uploadedBytes });
|
|
935
|
+
})
|
|
936
|
+
);
|
|
937
|
+
const { data: tipData, error: tipError } = await client.api.GET(
|
|
938
|
+
"/entities/{id}/tip",
|
|
939
|
+
{ params: { path: { id: entityId } } }
|
|
940
|
+
);
|
|
941
|
+
if (tipError || !tipData) {
|
|
942
|
+
throw new Error(`Failed to get entity tip: ${JSON.stringify(tipError)}`);
|
|
943
|
+
}
|
|
944
|
+
const prevCid = tipData.cid;
|
|
945
|
+
let currentTip = prevCid;
|
|
946
|
+
reportProgress({ phase: "completing", completedFiles: 0 });
|
|
947
|
+
const contents = [];
|
|
948
|
+
let finalCid = currentTip;
|
|
949
|
+
for (let i = 0; i < uploadInfos.length; i++) {
|
|
950
|
+
const item = uploadInfos[i];
|
|
951
|
+
const result = await completeWithRetry(client, entityId, item, currentTip);
|
|
952
|
+
currentTip = result.cid;
|
|
953
|
+
finalCid = result.cid;
|
|
954
|
+
contents.push({
|
|
955
|
+
key: item.key,
|
|
956
|
+
cid: result.contentCid,
|
|
957
|
+
size: item.size,
|
|
958
|
+
contentType: item.contentType,
|
|
959
|
+
filename: item.filename
|
|
960
|
+
});
|
|
961
|
+
reportProgress({ completedFiles: i + 1 });
|
|
962
|
+
}
|
|
963
|
+
return {
|
|
964
|
+
id: entityId,
|
|
965
|
+
cid: finalCid,
|
|
966
|
+
prevCid,
|
|
967
|
+
contents
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
async function prepareItem(item) {
|
|
971
|
+
const { data } = item;
|
|
972
|
+
let bytes;
|
|
973
|
+
if (data instanceof Blob) {
|
|
974
|
+
bytes = await data.arrayBuffer();
|
|
975
|
+
} else if (data instanceof ArrayBuffer) {
|
|
976
|
+
bytes = data;
|
|
977
|
+
} else {
|
|
978
|
+
const buffer = new ArrayBuffer(data.byteLength);
|
|
979
|
+
new Uint8Array(buffer).set(data);
|
|
980
|
+
bytes = buffer;
|
|
981
|
+
}
|
|
982
|
+
const size = bytes.byteLength;
|
|
983
|
+
let filename = item.filename;
|
|
984
|
+
let contentType = item.contentType;
|
|
985
|
+
if (data instanceof File) {
|
|
986
|
+
filename = filename ?? data.name;
|
|
987
|
+
contentType = contentType ?? (data.type || getMimeType(data.name));
|
|
988
|
+
}
|
|
989
|
+
contentType = contentType ?? "application/octet-stream";
|
|
990
|
+
if (contentType === "application/octet-stream" && filename) {
|
|
991
|
+
contentType = getMimeType(filename);
|
|
992
|
+
}
|
|
993
|
+
const cid = await computeCid(new Uint8Array(bytes));
|
|
994
|
+
let key = item.key;
|
|
995
|
+
if (!key && filename) {
|
|
996
|
+
const lastDot = filename.lastIndexOf(".");
|
|
997
|
+
key = lastDot > 0 ? filename.substring(0, lastDot) : filename;
|
|
998
|
+
}
|
|
999
|
+
if (!key) {
|
|
1000
|
+
key = `file_${cid.slice(-8)}`;
|
|
1001
|
+
}
|
|
1002
|
+
return { key, bytes, size, contentType, filename, cid };
|
|
1003
|
+
}
|
|
1004
|
+
async function completeWithRetry(client, entityId, item, expectTip) {
|
|
1005
|
+
let tip = expectTip;
|
|
1006
|
+
for (let attempt = 0; attempt < MAX_CAS_RETRIES; attempt++) {
|
|
1007
|
+
const { data, error, response } = await client.api.POST(
|
|
1008
|
+
"/entities/{id}/content/complete",
|
|
1009
|
+
{
|
|
1010
|
+
params: { path: { id: entityId } },
|
|
1011
|
+
body: {
|
|
1012
|
+
key: item.key,
|
|
1013
|
+
cid: item.cid,
|
|
1014
|
+
size: item.size,
|
|
1015
|
+
content_type: item.contentType,
|
|
1016
|
+
filename: item.filename,
|
|
1017
|
+
expect_tip: tip
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
);
|
|
1021
|
+
if (data) {
|
|
1022
|
+
return { cid: data.cid, contentCid: data.content.cid };
|
|
1023
|
+
}
|
|
1024
|
+
if (response?.status === 409) {
|
|
1025
|
+
const { data: freshTip, error: tipError } = await client.api.GET(
|
|
1026
|
+
"/entities/{id}/tip",
|
|
1027
|
+
{ params: { path: { id: entityId } } }
|
|
1028
|
+
);
|
|
1029
|
+
if (tipError || !freshTip) {
|
|
1030
|
+
throw new Error(`Failed to refresh tip: ${JSON.stringify(tipError)}`);
|
|
1031
|
+
}
|
|
1032
|
+
tip = freshTip.cid;
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
throw new Error(
|
|
1036
|
+
`Failed to complete upload for ${item.key}: ${JSON.stringify(error)}`
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
throw new Error(`Max CAS retries exceeded for ${item.key}`);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
862
1042
|
// src/operations/folders.ts
|
|
863
1043
|
var FolderOperations = class {
|
|
864
1044
|
constructor(client) {
|
|
@@ -1056,6 +1236,7 @@ async function withCasRetry(callbacks, options) {
|
|
|
1056
1236
|
isCasConflictError,
|
|
1057
1237
|
scanFileList,
|
|
1058
1238
|
scanFileSystemEntries,
|
|
1239
|
+
uploadToEntity,
|
|
1059
1240
|
uploadTree,
|
|
1060
1241
|
verifyCid,
|
|
1061
1242
|
withCasRetry
|