@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.
@@ -340,7 +340,9 @@ var init_files_model = __esm({
340
340
  linkKey: fileRaw.linkKey,
341
341
  linkKeyNonce: fileRaw.linkKeyNonce,
342
342
  commentKey: fileRaw.commentKey,
343
- link: fileRaw.link
343
+ link: fileRaw.link,
344
+ derivedKey: fileRaw.derivedKey,
345
+ secretKey: fileRaw.secretKey
344
346
  };
345
347
  }
346
348
  static async findAll(portalAddress, limit, skip) {
@@ -424,10 +426,20 @@ var init_files_model = __esm({
424
426
  const _id = uuidv7();
425
427
  const sql = `
426
428
  INSERT INTO ${this.TABLE}
427
- (_id, title, content, ddocId, portalAddress)
428
- VALUES (?, ?, ?, ?, ?)
429
+ (_id, title, content, ddocId, portalAddress, linkKey, linkKeyNonce, derivedKey, secretKey)
430
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
429
431
  `;
430
- await QueryBuilder.execute(sql, [_id, input.title, input.content, input.ddocId, input.portalAddress]);
432
+ await QueryBuilder.execute(sql, [
433
+ _id,
434
+ input.title,
435
+ input.content,
436
+ input.ddocId,
437
+ input.portalAddress,
438
+ input.linkKey ?? null,
439
+ input.linkKeyNonce ?? null,
440
+ input.derivedKey ?? null,
441
+ input.secretKey ?? null
442
+ ]);
431
443
  const created = await this.findById(_id, input.portalAddress);
432
444
  if (!created) {
433
445
  throw new Error("Failed to create file");
@@ -651,6 +663,29 @@ var init_events_model = __esm({
651
663
  `;
652
664
  await QueryBuilder.execute(sql, [Date.now(), _id]);
653
665
  }
666
+ static async markSubmitted(_id) {
667
+ const sql = `
668
+ UPDATE ${this.TABLE}
669
+ SET status = 'submitted',
670
+ lockedAt = NULL
671
+ WHERE _id = ?
672
+ `;
673
+ await QueryBuilder.execute(sql, [_id]);
674
+ }
675
+ static async findNextSubmitted(lockedFileIds) {
676
+ const exclusionClause = lockedFileIds.length > 0 ? `AND fileId NOT IN (${lockedFileIds.map(() => "?").join(", ")})` : "";
677
+ const sql = `
678
+ SELECT * FROM ${this.TABLE}
679
+ WHERE status = 'submitted'
680
+ AND userOpHash IS NOT NULL
681
+ ${exclusionClause}
682
+ ORDER BY timestamp ASC
683
+ LIMIT 1
684
+ `;
685
+ const params = [...lockedFileIds];
686
+ const row = await QueryBuilder.selectOne(sql, params);
687
+ return row ? this.parseEvent(row) : void 0;
688
+ }
654
689
  static async markProcessed(_id) {
655
690
  const sql = `
656
691
  UPDATE ${this.TABLE}
@@ -915,12 +950,52 @@ import { fromUint8Array, toUint8Array } from "js-base64";
915
950
  import { toAESKey, aesEncrypt } from "@fileverse/crypto/webcrypto";
916
951
  import axios from "axios";
917
952
  import { encodeFunctionData, parseEventLogs } from "viem";
953
+ var deriveKeyFromAg2Hash, getExistingEncryptionMaterial, getNaclSecretKey, generateLinkKeyMaterial;
918
954
  var init_file_utils = __esm({
919
955
  "src/sdk/file-utils.ts"() {
920
956
  "use strict";
921
957
  init_esm_shims();
922
958
  init_file_encryption();
923
959
  init_constants3();
960
+ deriveKeyFromAg2Hash = async (pass, salt) => {
961
+ const key = await getArgon2idHash(pass, salt);
962
+ return hkdf(Buffer.from(key), tweetnacl.secretbox.keyLength, {
963
+ info: Buffer.from("encryptionKey")
964
+ });
965
+ };
966
+ getExistingEncryptionMaterial = async (existingEncryptedSecretKey, existingNonce, docId) => {
967
+ const derivedKey = await deriveKeyFromAg2Hash(docId, toUint8Array(existingNonce));
968
+ const secretKey = tweetnacl.secretbox.open(
969
+ toUint8Array(existingEncryptedSecretKey),
970
+ toUint8Array(existingNonce),
971
+ derivedKey
972
+ );
973
+ return {
974
+ encryptedSecretKey: existingEncryptedSecretKey,
975
+ nonce: toUint8Array(existingNonce),
976
+ secretKey,
977
+ derivedKey: new Uint8Array(derivedKey)
978
+ };
979
+ };
980
+ getNaclSecretKey = async (ddocId) => {
981
+ const { secretKey } = tweetnacl.box.keyPair();
982
+ const nonce = tweetnacl.randomBytes(tweetnacl.secretbox.nonceLength);
983
+ const derivedKey = await deriveKeyFromAg2Hash(ddocId, nonce);
984
+ const encryptedSecretKey = fromUint8Array(tweetnacl.secretbox(secretKey, nonce, derivedKey), true);
985
+ return { nonce, encryptedSecretKey, secretKey, derivedKey: new Uint8Array(derivedKey) };
986
+ };
987
+ generateLinkKeyMaterial = async (params) => {
988
+ if (params.linkKeyNonce && params.linkKey) {
989
+ const { encryptedSecretKey: encryptedSecretKey2, nonce: nonce2, secretKey: secretKey2, derivedKey: derivedKey2 } = await getExistingEncryptionMaterial(
990
+ params.linkKey,
991
+ params.linkKeyNonce,
992
+ params.ddocId
993
+ );
994
+ if (secretKey2) return { encryptedSecretKey: encryptedSecretKey2, nonce: nonce2, secretKey: secretKey2, derivedKey: derivedKey2 };
995
+ }
996
+ const { secretKey, nonce, encryptedSecretKey, derivedKey } = await getNaclSecretKey(params.ddocId);
997
+ return { secretKey, nonce, encryptedSecretKey, derivedKey };
998
+ };
924
999
  }
925
1000
  });
926
1001
 
@@ -956,6 +1031,7 @@ var init_publish = __esm({
956
1031
  init_smart_agent();
957
1032
  init_file_manager();
958
1033
  init_config();
1034
+ init_pimlico_utils();
959
1035
  }
960
1036
  });
961
1037
 
@@ -1425,7 +1501,9 @@ CREATE TABLE IF NOT EXISTS files (
1425
1501
  commentKey TEXT,
1426
1502
  linkKey TEXT,
1427
1503
  linkKeyNonce TEXT,
1428
- link TEXT
1504
+ link TEXT,
1505
+ derivedKey TEXT,
1506
+ secretKey TEXT
1429
1507
  );
1430
1508
  CREATE INDEX IF NOT EXISTS idx_files_createdAt ON files(createdAt);
1431
1509
  CREATE INDEX IF NOT EXISTS idx_files_syncStatus ON files(syncStatus);
@@ -1456,7 +1534,7 @@ CREATE TABLE IF NOT EXISTS events (
1456
1534
  type TEXT NOT NULL CHECK (type IN ('create', 'update', 'delete')),
1457
1535
  timestamp BIGINT NOT NULL,
1458
1536
  fileId TEXT NOT NULL,
1459
- status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'processed', 'failed')),
1537
+ status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'submitted', 'processed', 'failed')),
1460
1538
  retryCount INTEGER NOT NULL DEFAULT 0,
1461
1539
  lastError TEXT,
1462
1540
  lockedAt BIGINT,
@@ -1505,7 +1583,9 @@ import Table from "cli-table3";
1505
1583
  init_esm_shims();
1506
1584
  init_models();
1507
1585
  init_constants2();
1586
+ init_file_utils();
1508
1587
  import { generate } from "short-uuid";
1588
+ import { fromUint8Array as fromUint8Array4 } from "js-base64";
1509
1589
  async function listFiles(params) {
1510
1590
  const { limit, skip, portalAddress } = params;
1511
1591
  const effectiveLimit = limit || DEFAULT_LIST_LIMIT;
@@ -1558,11 +1638,20 @@ var createFile = async (input) => {
1558
1638
  throw new Error("title, content, and portalAddress are required");
1559
1639
  }
1560
1640
  const ddocId = generate();
1641
+ const { encryptedSecretKey, nonce, secretKey, derivedKey } = await generateLinkKeyMaterial({
1642
+ ddocId,
1643
+ linkKey: void 0,
1644
+ linkKeyNonce: void 0
1645
+ });
1561
1646
  const file = await FilesModel.create({
1562
1647
  title: input.title,
1563
1648
  content: input.content,
1564
1649
  ddocId,
1565
- portalAddress: input.portalAddress
1650
+ portalAddress: input.portalAddress,
1651
+ linkKey: encryptedSecretKey,
1652
+ linkKeyNonce: fromUint8Array4(nonce),
1653
+ derivedKey: fromUint8Array4(derivedKey),
1654
+ secretKey: fromUint8Array4(secretKey)
1566
1655
  });
1567
1656
  await EventsModel.create({ type: "create", fileId: file._id, portalAddress: file.portalAddress });
1568
1657
  return file;