@fileverse/api 0.0.9 → 0.0.11

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/index.js CHANGED
@@ -669,7 +669,9 @@ var init_files_model = __esm({
669
669
  linkKey: fileRaw.linkKey,
670
670
  linkKeyNonce: fileRaw.linkKeyNonce,
671
671
  commentKey: fileRaw.commentKey,
672
- link: fileRaw.link
672
+ link: fileRaw.link,
673
+ derivedKey: fileRaw.derivedKey,
674
+ secretKey: fileRaw.secretKey
673
675
  };
674
676
  }
675
677
  static async findAll(portalAddress, limit, skip) {
@@ -753,10 +755,20 @@ var init_files_model = __esm({
753
755
  const _id = uuidv7();
754
756
  const sql = `
755
757
  INSERT INTO ${this.TABLE}
756
- (_id, title, content, ddocId, portalAddress)
757
- VALUES (?, ?, ?, ?, ?)
758
+ (_id, title, content, ddocId, portalAddress, linkKey, linkKeyNonce, derivedKey, secretKey)
759
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
758
760
  `;
759
- await QueryBuilder.execute(sql, [_id, input.title, input.content, input.ddocId, input.portalAddress]);
761
+ await QueryBuilder.execute(sql, [
762
+ _id,
763
+ input.title,
764
+ input.content,
765
+ input.ddocId,
766
+ input.portalAddress,
767
+ input.linkKey ?? null,
768
+ input.linkKeyNonce ?? null,
769
+ input.derivedKey ?? null,
770
+ input.secretKey ?? null
771
+ ]);
760
772
  const created = await this.findById(_id, input.portalAddress);
761
773
  if (!created) {
762
774
  throw new Error("Failed to create file");
@@ -1136,6 +1148,29 @@ var init_events_model = __esm({
1136
1148
  `;
1137
1149
  await QueryBuilder.execute(sql, [Date.now(), _id]);
1138
1150
  }
1151
+ static async markSubmitted(_id) {
1152
+ const sql = `
1153
+ UPDATE ${this.TABLE}
1154
+ SET status = 'submitted',
1155
+ lockedAt = NULL
1156
+ WHERE _id = ?
1157
+ `;
1158
+ await QueryBuilder.execute(sql, [_id]);
1159
+ }
1160
+ static async findNextSubmitted(lockedFileIds) {
1161
+ const exclusionClause = lockedFileIds.length > 0 ? `AND fileId NOT IN (${lockedFileIds.map(() => "?").join(", ")})` : "";
1162
+ const sql = `
1163
+ SELECT * FROM ${this.TABLE}
1164
+ WHERE status = 'submitted'
1165
+ AND userOpHash IS NOT NULL
1166
+ ${exclusionClause}
1167
+ ORDER BY timestamp ASC
1168
+ LIMIT 1
1169
+ `;
1170
+ const params = [...lockedFileIds];
1171
+ const row = await QueryBuilder.selectOne(sql, params);
1172
+ return row ? this.parseEvent(row) : void 0;
1173
+ }
1139
1174
  static async markProcessed(_id) {
1140
1175
  const sql = `
1141
1176
  UPDATE ${this.TABLE}
@@ -2550,7 +2585,7 @@ import { fromUint8Array, toUint8Array } from "js-base64";
2550
2585
  import { toAESKey, aesEncrypt } from "@fileverse/crypto/webcrypto";
2551
2586
  import axios from "axios";
2552
2587
  import { encodeFunctionData, parseEventLogs } from "viem";
2553
- var deriveKeyFromAg2Hash, decryptSecretKey, getExistingEncryptionMaterial, getNaclSecretKey, generateLinkKeyMaterial, jsonToFile, appendAuthTagIvToBlob, encryptFile, getNonceAppendedCipherText, jsonToBytes, buildLinklock, encryptTitleWithFileKey, uploadFileToIPFS, getEditFileTrxCalldata, getAddFileTrxCalldata, prepareCallData, prepareDeleteFileCallData, createEncryptedContentFile, buildFileMetadata, parseFileEventLog, uploadAllFilesToIPFS;
2588
+ var deriveKeyFromAg2Hash, getExistingEncryptionMaterial, getNaclSecretKey, generateLinkKeyMaterial, jsonToFile, appendAuthTagIvToBlob, encryptFile, getNonceAppendedCipherText, jsonToBytes, buildLinklock, encryptTitleWithFileKey, uploadFileToIPFS, getEditFileTrxCalldata, getAddFileTrxCalldata, prepareCallData, prepareDeleteFileCallData, createEncryptedContentFile, buildFileMetadata, parseFileEventLog, uploadAllFilesToIPFS;
2554
2589
  var init_file_utils = __esm({
2555
2590
  "src/sdk/file-utils.ts"() {
2556
2591
  "use strict";
@@ -2563,16 +2598,18 @@ var init_file_utils = __esm({
2563
2598
  info: Buffer.from("encryptionKey")
2564
2599
  });
2565
2600
  };
2566
- decryptSecretKey = async (docId, nonce, encryptedSecretKey) => {
2567
- const derivedKey = await deriveKeyFromAg2Hash(docId, toUint8Array(nonce));
2568
- return tweetnacl.secretbox.open(toUint8Array(encryptedSecretKey), toUint8Array(nonce), derivedKey);
2569
- };
2570
2601
  getExistingEncryptionMaterial = async (existingEncryptedSecretKey, existingNonce, docId) => {
2571
- const secretKey = await decryptSecretKey(docId, existingNonce, existingEncryptedSecretKey);
2602
+ const derivedKey = await deriveKeyFromAg2Hash(docId, toUint8Array(existingNonce));
2603
+ const secretKey = tweetnacl.secretbox.open(
2604
+ toUint8Array(existingEncryptedSecretKey),
2605
+ toUint8Array(existingNonce),
2606
+ derivedKey
2607
+ );
2572
2608
  return {
2573
2609
  encryptedSecretKey: existingEncryptedSecretKey,
2574
2610
  nonce: toUint8Array(existingNonce),
2575
- secretKey
2611
+ secretKey,
2612
+ derivedKey: new Uint8Array(derivedKey)
2576
2613
  };
2577
2614
  };
2578
2615
  getNaclSecretKey = async (ddocId) => {
@@ -2580,19 +2617,19 @@ var init_file_utils = __esm({
2580
2617
  const nonce = tweetnacl.randomBytes(tweetnacl.secretbox.nonceLength);
2581
2618
  const derivedKey = await deriveKeyFromAg2Hash(ddocId, nonce);
2582
2619
  const encryptedSecretKey = fromUint8Array(tweetnacl.secretbox(secretKey, nonce, derivedKey), true);
2583
- return { nonce, encryptedSecretKey, secretKey };
2620
+ return { nonce, encryptedSecretKey, secretKey, derivedKey: new Uint8Array(derivedKey) };
2584
2621
  };
2585
2622
  generateLinkKeyMaterial = async (params) => {
2586
2623
  if (params.linkKeyNonce && params.linkKey) {
2587
- const { encryptedSecretKey: encryptedSecretKey2, nonce: nonce2, secretKey: secretKey2 } = await getExistingEncryptionMaterial(
2624
+ const { encryptedSecretKey: encryptedSecretKey2, nonce: nonce2, secretKey: secretKey2, derivedKey: derivedKey2 } = await getExistingEncryptionMaterial(
2588
2625
  params.linkKey,
2589
2626
  params.linkKeyNonce,
2590
2627
  params.ddocId
2591
2628
  );
2592
- if (secretKey2) return { encryptedSecretKey: encryptedSecretKey2, nonce: nonce2, secretKey: secretKey2 };
2629
+ if (secretKey2) return { encryptedSecretKey: encryptedSecretKey2, nonce: nonce2, secretKey: secretKey2, derivedKey: derivedKey2 };
2593
2630
  }
2594
- const { secretKey, nonce, encryptedSecretKey } = await getNaclSecretKey(params.ddocId);
2595
- return { secretKey, nonce, encryptedSecretKey };
2631
+ const { secretKey, nonce, encryptedSecretKey, derivedKey } = await getNaclSecretKey(params.ddocId);
2632
+ return { secretKey, nonce, encryptedSecretKey, derivedKey };
2596
2633
  };
2597
2634
  jsonToFile = (json2, fileName) => {
2598
2635
  const blob = new Blob([JSON.stringify(json2)], {
@@ -2845,11 +2882,9 @@ var init_file_manager = __esm({
2845
2882
  }
2846
2883
  async submitAddFileTrx(file2) {
2847
2884
  logger.debug(`Preparing to add file ${file2.ddocId}`);
2848
- const { encryptedSecretKey, nonce, secretKey } = await generateLinkKeyMaterial({
2849
- ddocId: file2.ddocId,
2850
- linkKey: file2.linkKey,
2851
- linkKeyNonce: file2.linkKeyNonce
2852
- });
2885
+ const encryptedSecretKey = file2.linkKey;
2886
+ const nonce = toUint8Array2(file2.linkKeyNonce);
2887
+ const secretKey = toUint8Array2(file2.secretKey);
2853
2888
  const yJSContent = markdownToYjs(file2.content);
2854
2889
  const { encryptedFile, key } = await createEncryptedContentFile(yJSContent);
2855
2890
  logger.debug(`Generated encrypted content file for file ${file2.ddocId}`);
@@ -2893,13 +2928,59 @@ var init_file_manager = __esm({
2893
2928
  metadata
2894
2929
  };
2895
2930
  }
2896
- async updateFile(file2) {
2897
- logger.debug(`Updating file ${file2.ddocId} with onChainFileId ${file2.onChainFileId}`);
2898
- const { encryptedSecretKey, nonce, secretKey } = await generateLinkKeyMaterial({
2931
+ async submitUpdateFile(file2) {
2932
+ logger.debug(`Submitting update for file ${file2.ddocId} with onChainFileId ${file2.onChainFileId}`);
2933
+ const encryptedSecretKey = file2.linkKey;
2934
+ const nonce = toUint8Array2(file2.linkKeyNonce);
2935
+ const secretKey = toUint8Array2(file2.secretKey);
2936
+ const yjsContent = markdownToYjs(file2.content);
2937
+ const { encryptedFile, key } = await createEncryptedContentFile(yjsContent);
2938
+ const commentKey = toUint8Array2(file2.commentKey);
2939
+ const { appLock, ownerLock } = this.createLocks(key, encryptedSecretKey, commentKey);
2940
+ const linkLock = buildLinklock(secretKey, toUint8Array2(key), commentKey);
2941
+ const encryptedTitle = await encryptTitleWithFileKey({
2942
+ title: file2.title || "Untitled",
2943
+ key
2944
+ });
2945
+ const metadata = buildFileMetadata({
2946
+ encryptedTitle,
2947
+ encryptedFileSize: encryptedFile.size,
2948
+ appLock,
2949
+ ownerLock,
2899
2950
  ddocId: file2.ddocId,
2900
- linkKey: file2.linkKey,
2901
- linkKeyNonce: file2.linkKeyNonce
2951
+ nonce: fromUint8Array2(nonce),
2952
+ owner: this.agentClient.getAgentAddress()
2902
2953
  });
2954
+ const authParams = await this.getAuthParams();
2955
+ const { metadataHash, contentHash, gateHash } = await uploadAllFilesToIPFS(
2956
+ { metadata, encryptedFile, linkLock, ddocId: file2.ddocId },
2957
+ authParams
2958
+ );
2959
+ const callData = prepareCallData({
2960
+ metadataHash,
2961
+ contentHash,
2962
+ gateHash,
2963
+ appFileId: file2.ddocId,
2964
+ fileId: file2.onChainFileId
2965
+ });
2966
+ const userOpHash = await this.sendFileOperation(callData);
2967
+ logger.debug(`Submitted update user op for file ${file2.ddocId}`);
2968
+ return { userOpHash, metadata };
2969
+ }
2970
+ async submitDeleteFile(file2) {
2971
+ logger.debug(`Submitting delete for file ${file2.ddocId} with onChainFileId ${file2.onChainFileId}`);
2972
+ const callData = prepareDeleteFileCallData({
2973
+ onChainFileId: file2.onChainFileId
2974
+ });
2975
+ const userOpHash = await this.sendFileOperation(callData);
2976
+ logger.debug(`Submitted delete user op for file ${file2.ddocId}`);
2977
+ return { userOpHash };
2978
+ }
2979
+ async updateFile(file2) {
2980
+ logger.debug(`Updating file ${file2.ddocId} with onChainFileId ${file2.onChainFileId}`);
2981
+ const encryptedSecretKey = file2.linkKey;
2982
+ const nonce = toUint8Array2(file2.linkKeyNonce);
2983
+ const secretKey = toUint8Array2(file2.secretKey);
2903
2984
  logger.debug(`Generating encrypted content file for file ${file2.ddocId} with onChainFileId ${file2.onChainFileId}`);
2904
2985
  const yjsContent = markdownToYjs(file2.content);
2905
2986
  const { encryptedFile, key } = await createEncryptedContentFile(yjsContent);
@@ -2996,6 +3077,7 @@ var init_publish = __esm({
2996
3077
  init_smart_agent();
2997
3078
  init_file_manager();
2998
3079
  init_config();
3080
+ init_pimlico_utils();
2999
3081
  createFileManager = async (portalSeed, portalAddress, ucanSecret, privateAccountKey) => {
3000
3082
  const keyPair = ucans2.EdKeypair.fromSecretKey(fromUint8Array3(ucanSecret), {
3001
3083
  exportable: true
@@ -3570,7 +3652,9 @@ CREATE TABLE IF NOT EXISTS files (
3570
3652
  commentKey TEXT,
3571
3653
  linkKey TEXT,
3572
3654
  linkKeyNonce TEXT,
3573
- link TEXT
3655
+ link TEXT,
3656
+ derivedKey TEXT,
3657
+ secretKey TEXT
3574
3658
  );
3575
3659
  CREATE INDEX IF NOT EXISTS idx_files_createdAt ON files(createdAt);
3576
3660
  CREATE INDEX IF NOT EXISTS idx_files_syncStatus ON files(syncStatus);
@@ -3601,7 +3685,7 @@ CREATE TABLE IF NOT EXISTS events (
3601
3685
  type TEXT NOT NULL CHECK (type IN ('create', 'update', 'delete')),
3602
3686
  timestamp BIGINT NOT NULL,
3603
3687
  fileId TEXT NOT NULL,
3604
- status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'processed', 'failed')),
3688
+ status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'submitted', 'processed', 'failed')),
3605
3689
  retryCount INTEGER NOT NULL DEFAULT 0,
3606
3690
  lastError TEXT,
3607
3691
  lockedAt BIGINT,
@@ -3764,7 +3848,9 @@ init_esm_shims();
3764
3848
  init_esm_shims();
3765
3849
  init_models();
3766
3850
  init_constants2();
3851
+ init_file_utils();
3767
3852
  import { generate } from "short-uuid";
3853
+ import { fromUint8Array as fromUint8Array4 } from "js-base64";
3768
3854
  async function listFiles(params) {
3769
3855
  const { limit, skip, portalAddress } = params;
3770
3856
  const effectiveLimit = limit || DEFAULT_LIST_LIMIT;
@@ -3817,11 +3903,20 @@ var createFile = async (input) => {
3817
3903
  throw new Error("title, content, and portalAddress are required");
3818
3904
  }
3819
3905
  const ddocId = generate();
3906
+ const { encryptedSecretKey, nonce, secretKey, derivedKey } = await generateLinkKeyMaterial({
3907
+ ddocId,
3908
+ linkKey: void 0,
3909
+ linkKeyNonce: void 0
3910
+ });
3820
3911
  const file2 = await FilesModel.create({
3821
3912
  title: input.title,
3822
3913
  content: input.content,
3823
3914
  ddocId,
3824
- portalAddress: input.portalAddress
3915
+ portalAddress: input.portalAddress,
3916
+ linkKey: encryptedSecretKey,
3917
+ linkKeyNonce: fromUint8Array4(nonce),
3918
+ derivedKey: fromUint8Array4(derivedKey),
3919
+ secretKey: fromUint8Array4(secretKey)
3825
3920
  });
3826
3921
  await EventsModel.create({ type: "create", fileId: file2._id, portalAddress: file2.portalAddress });
3827
3922
  return file2;