{"_id":"@disregardfiat/spk-js","_rev":"4-fe4a6755795ce49a4413b5bdc0a950d1","name":"@disregardfiat/spk-js","dist-tags":{"next":"1.0.0-alpha.1","latest":"1.0.4"},"versions":{"1.0.0-alpha":{"name":"@disregardfiat/spk-js","version":"1.0.0-alpha","keywords":["spk","spknetwork","ipfs","decentralized","storage","hive","blockchain","web3"],"author":{"name":"SPK Network"},"license":"MIT","_id":"@disregardfiat/spk-js@1.0.0-alpha","maintainers":[{"name":"disregardfiat","email":"disregardfiat@gmail.com"}],"homepage":"https://github.com/disregardfiat/spk-js#readme","bugs":{"url":"https://github.com/disregardfiat/spk-js/issues"},"dist":{"shasum":"dafb87986f8d05383c3551ef42e3711140beb837","tarball":"https://registry.npmjs.org/@disregardfiat/spk-js/-/spk-js-1.0.0-alpha.tgz","fileCount":57,"integrity":"sha512-RBqoy+HyGk1NL4PELRTokfTf4GFQ1+LAYPmB5dB1Bm0vHcee+NweKgz8H08l8N0ZBx6QFZZ1Hi4G99r5IAu9JA==","signatures":[{"sig":"MEUCIBD1Eqj837qtKI1sd0HWY4+zBBi7GRb6EPPT5yrvlKMSAiEAvOsNRxAe2WxDCFN2iXz+Ku5ArZiGPs9hyUnHQR1CNw0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3516162},"main":"dist/spk-js.cjs.js","types":"dist/index.d.ts","module":"dist/spk-js.esm.js","browser":"dist/spk-js.umd.js","engines":{"node":">=16.0.0"},"gitHead":"0906dd379c664299b1a375be05693de9bbc96b0d","scripts":{"dev":"npm run build:watch & npm run test:watch","docs":"typedoc --out docs/api src/index.ts","lint":"eslint src tests --ext .js,.ts","test":"jest","build":"rollup -c","format":"prettier --write \"src/**/*.{js,ts}\" \"tests/**/*.{js,ts}\"","prepare":"npm run build || echo 'Build failed, but continuing...'","version":"npm run format && git add -A src","lint:fix":"eslint src tests --ext .js,.ts --fix","test:e2e":"jest --config jest.e2e.config.js --runInBand","test:watch":"jest --watch","build:watch":"rollup -c -w","postversion":"git push && git push --tags","test:coverage":"jest --coverage","prepublishOnly":"npm test && npm run lint","test:integration":"jest --testPathPattern=tests/integration"},"_npmUser":{"name":"disregardfiat","email":"disregardfiat@gmail.com"},"repository":{"url":"git+https://github.com/disregardfiat/spk-js.git","type":"git"},"_npmVersion":"10.8.2","description":"JavaScript library for interacting with SPK Network decentralized storage","directories":{},"_nodeVersion":"18.20.8","dependencies":{"axios":"^1.10.0","buffer":"^6.0.3","ipfs-only-hash":"^4.0.0","@hiveio/hive-js":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"cors":"^2.8.5","jest":"^29.7.0","busboy":"^1.6.0","eslint":"^8.55.0","rollup":"^3.29.4","express":"^4.21.2","ts-jest":"^29.1.1","ts-node":"^10.9.2","typedoc":"^0.25.4","fs-extra":"^11.3.0","prettier":"^3.1.0","form-data":"^4.0.3","typescript":"^5.3.0","@babel/core":"^7.23.0","@types/jest":"^29.5.11","@types/node":"^20.10.0","@playwright/test":"^1.32.0","@types/form-data":"^2.2.1","@babel/preset-env":"^7.23.0","rollup-plugin-dts":"^6.1.0","eslint-plugin-jest":"^27.6.0","@rollup/plugin-json":"^6.1.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-terser":"^0.4.4","eslint-config-prettier":"^9.1.0","jest-environment-jsdom":"^29.7.0","@rollup/plugin-commonjs":"^25.0.7","@babel/preset-typescript":"^7.23.0","@rollup/plugin-typescript":"^11.1.5","@typescript-eslint/parser":"^6.13.0","@rollup/plugin-node-resolve":"^15.2.3","rollup-plugin-node-polyfills":"^0.2.1","@typescript-eslint/eslint-plugin":"^6.13.0"},"_npmOperationalInternal":{"tmp":"tmp/spk-js_1.0.0-alpha_1753991988559_0.4140070618855871","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-alpha.1":{"name":"@disregardfiat/spk-js","version":"1.0.0-alpha.1","keywords":["spk","spknetwork","ipfs","decentralized","storage","hive","blockchain","web3"],"author":{"name":"SPK Network"},"license":"MIT","_id":"@disregardfiat/spk-js@1.0.0-alpha.1","maintainers":[{"name":"disregardfiat","email":"disregardfiat@gmail.com"}],"homepage":"https://github.com/disregardfiat/spk-js#readme","bugs":{"url":"https://github.com/disregardfiat/spk-js/issues"},"dist":{"shasum":"b8b206ca15ff4003af55f09ed87ba6ffe34114c3","tarball":"https://registry.npmjs.org/@disregardfiat/spk-js/-/spk-js-1.0.0-alpha.1.tgz","fileCount":57,"integrity":"sha512-2QMwmKchbgylKJV49ZVW5w5lOG27LEb3CFcY9jp5HAdWcvb3I1Or8GX+2+tA+ArBCPb/HfXLc7ICCjMYgwoJ/Q==","signatures":[{"sig":"MEUCIQCuuThO7HJbMqDkjW0OJU5uoICZU6RZhIH0nUGGhuUljQIgdIHf4KkNT6bciDXAGHOhFfN0UM6a+h6aQZ6/l7Uo/qw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3521887},"main":"dist/spk-js.cjs.js","types":"dist/index.d.ts","module":"dist/spk-js.esm.js","browser":"dist/spk-js.umd.js","engines":{"node":">=16.0.0"},"gitHead":"01342129c4a2ce8e993dbb334cf78d1153300e7a","scripts":{"dev":"npm run build:watch & npm run test:watch","docs":"typedoc --out docs/api src/index.ts","lint":"eslint src tests --ext .js,.ts","test":"jest","build":"rollup -c","format":"prettier --write \"src/**/*.{js,ts}\" \"tests/**/*.{js,ts}\"","prepare":"npm run build || echo 'Build failed, but continuing...'","version":"npm run format && git add -A src","lint:fix":"eslint src tests --ext .js,.ts --fix","test:e2e":"jest --config jest.e2e.config.js --runInBand","test:watch":"jest --watch","build:watch":"rollup -c -w","postversion":"git push && git push --tags","test:coverage":"jest --coverage","prepublishOnly":"npm test && npm run lint","test:integration":"jest --testPathPattern=tests/integration"},"_npmUser":{"name":"disregardfiat","email":"disregardfiat@gmail.com"},"repository":{"url":"git+https://github.com/disregardfiat/spk-js.git","type":"git"},"_npmVersion":"10.8.2","description":"JavaScript library for interacting with SPK Network decentralized storage","directories":{},"_nodeVersion":"18.20.8","dependencies":{"axios":"^1.10.0","buffer":"^6.0.3","ipfs-only-hash":"^4.0.0","@hiveio/hive-js":"^2.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"cors":"^2.8.5","jest":"^29.7.0","busboy":"^1.6.0","eslint":"^8.55.0","rollup":"^3.29.4","express":"^4.21.2","ts-jest":"^29.1.1","ts-node":"^10.9.2","typedoc":"^0.25.4","fs-extra":"^11.3.0","prettier":"^3.1.0","form-data":"^4.0.3","typescript":"^5.3.0","@babel/core":"^7.23.0","@types/jest":"^29.5.11","@types/node":"^20.10.0","@playwright/test":"^1.32.0","@types/form-data":"^2.2.1","@babel/preset-env":"^7.23.0","rollup-plugin-dts":"^6.1.0","eslint-plugin-jest":"^27.6.0","@rollup/plugin-json":"^6.1.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-terser":"^0.4.4","eslint-config-prettier":"^9.1.0","jest-environment-jsdom":"^29.7.0","@rollup/plugin-commonjs":"^25.0.7","@babel/preset-typescript":"^7.23.0","@rollup/plugin-typescript":"^11.1.5","@typescript-eslint/parser":"^6.13.0","@rollup/plugin-node-resolve":"^15.2.3","rollup-plugin-node-polyfills":"^0.2.1","@typescript-eslint/eslint-plugin":"^6.13.0"},"_npmOperationalInternal":{"tmp":"tmp/spk-js_1.0.0-alpha.1_1754164422440_0.43443998590684796","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@disregardfiat/spk-js","version":"1.0.0","keywords":["spk","spknetwork","ipfs","decentralized","storage","hive","blockchain","web3"],"author":{"name":"SPK Network"},"license":"MIT","_id":"@disregardfiat/spk-js@1.0.0","maintainers":[{"name":"disregardfiat","email":"disregardfiat@gmail.com"}],"homepage":"https://github.com/disregardfiat/spk-js#readme","bugs":{"url":"https://github.com/disregardfiat/spk-js/issues"},"dist":{"shasum":"21a1c13fe171763cab62f87f015bd6682ff12420","tarball":"https://registry.npmjs.org/@disregardfiat/spk-js/-/spk-js-1.0.0.tgz","fileCount":57,"integrity":"sha512-UhpKWn35wQqTTsNzPhgLyiJSsjndG5iZaacD2LxmSQl8daUx5vBCAK5lprrBGee8tKuL020Kg4evfsJORe+MQg==","signatures":[{"sig":"MEUCIQCD6kXIC+YG9oDSc3SWBh4Qn8n3HV9XeQJ4ft4F2OsYIAIgJuTP3ROcTbbRoZjP/GR8GcBj6gCTxwpX4UHg6K3nFaQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3550121},"main":"dist/spk-js.cjs.js","types":"dist/index.d.ts","module":"dist/spk-js.esm.js","browser":"dist/spk-js.umd.js","engines":{"node":">=16.0.0"},"gitHead":"c13a21ecded51e0c367756c610670bba1ae7d1ed","scripts":{"dev":"npm run build:watch & npm run test:watch","docs":"typedoc --out docs/api src/index.ts","lint":"eslint src tests --ext .js,.ts","test":"jest","build":"rollup -c","format":"prettier --write \"src/**/*.{js,ts}\" \"tests/**/*.{js,ts}\"","prepare":"npm run build || echo 'Build failed, but continuing...'","version":"npm run format && git add -A src","lint:fix":"eslint src tests --ext .js,.ts --fix","test:e2e":"jest --config jest.e2e.config.js --runInBand","test:watch":"jest --watch","build:watch":"rollup -c -w","postversion":"git push && git push --tags","test:coverage":"jest --coverage","prepublishOnly":"npm run lint","test:integration":"jest --testPathPattern=tests/integration"},"_npmUser":{"name":"disregardfiat","email":"disregardfiat@gmail.com"},"repository":{"url":"git+https://github.com/disregardfiat/spk-js.git","type":"git"},"_npmVersion":"10.8.2","description":"JavaScript library for interacting with SPK Network decentralized storage","directories":{},"_nodeVersion":"18.20.8","dependencies":{"axios":"^1.10.0","buffer":"^6.0.3","ipfs-only-hash":"^4.0.0","@hiveio/hive-js":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"cors":"^2.8.5","jest":"^29.7.0","busboy":"^1.6.0","eslint":"^8.55.0","rollup":"^3.29.4","express":"^4.21.2","ts-jest":"^29.1.1","ts-node":"^10.9.2","typedoc":"^0.25.4","fs-extra":"^11.3.0","prettier":"^3.1.0","form-data":"^4.0.3","typescript":"^5.3.0","@babel/core":"^7.23.0","@types/jest":"^29.5.11","@types/node":"^20.10.0","@playwright/test":"^1.32.0","@types/form-data":"^2.2.1","@babel/preset-env":"^7.23.0","rollup-plugin-dts":"^6.1.0","eslint-plugin-jest":"^27.6.0","@rollup/plugin-json":"^6.1.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-terser":"^0.4.4","eslint-config-prettier":"^9.1.0","jest-environment-jsdom":"^29.7.0","@rollup/plugin-commonjs":"^25.0.7","@babel/preset-typescript":"^7.23.0","@rollup/plugin-typescript":"^11.1.5","@typescript-eslint/parser":"^6.13.0","@rollup/plugin-node-resolve":"^15.2.3","rollup-plugin-node-polyfills":"^0.2.1","@typescript-eslint/eslint-plugin":"^6.13.0"},"_npmOperationalInternal":{"tmp":"tmp/spk-js_1.0.0_1754252382729_0.023384164718930345","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@disregardfiat/spk-js","version":"1.0.4","description":"JavaScript library for interacting with SPK Network decentralized storage","main":"dist/spk-js.cjs.js","module":"dist/spk-js.esm.js","browser":"dist/spk-js.umd.js","types":"dist/index.d.ts","scripts":{"test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","test:integration":"jest --testPathPattern=tests/integration","test:e2e":"jest --config jest.e2e.config.js --runInBand","build":"rollup -c","build:watch":"rollup -c -w","dev":"npm run build:watch & npm run test:watch","lint":"eslint src tests --ext .js,.ts","lint:fix":"eslint src tests --ext .js,.ts --fix","format":"prettier --write \"src/**/*.{js,ts}\" \"tests/**/*.{js,ts}\"","docs":"typedoc --out docs/api src/index.ts","prepare":"npm run build || echo 'Build failed, but continuing...'","prepublishOnly":"npm run lint","version":"npm run format && git add -A src","postversion":"git push && git push --tags"},"repository":{"type":"git","url":"git+https://github.com/disregardfiat/spk-js.git"},"keywords":["spk","spknetwork","ipfs","decentralized","storage","hive","blockchain","web3"],"author":{"name":"SPK Network"},"license":"MIT","bugs":{"url":"https://github.com/disregardfiat/spk-js/issues"},"homepage":"https://github.com/disregardfiat/spk-js#readme","dependencies":{"@hiveio/hive-js":"^2.0.0","axios":"^1.10.0","buffer":"^6.0.3","ipfs-only-hash":"^4.0.0"},"devDependencies":{"@babel/core":"^7.23.0","@babel/preset-env":"^7.23.0","@babel/preset-typescript":"^7.23.0","@playwright/test":"^1.32.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-commonjs":"^25.0.7","@rollup/plugin-json":"^6.1.0","@rollup/plugin-node-resolve":"^15.2.3","@rollup/plugin-terser":"^0.4.4","@rollup/plugin-typescript":"^11.1.5","@types/form-data":"^2.2.1","@types/jest":"^29.5.11","@types/node":"^20.10.0","@typescript-eslint/eslint-plugin":"^6.13.0","@typescript-eslint/parser":"^6.13.0","busboy":"^1.6.0","cors":"^2.8.5","eslint":"^8.55.0","eslint-config-prettier":"^9.1.0","eslint-plugin-jest":"^27.6.0","express":"^4.21.2","form-data":"^4.0.3","fs-extra":"^11.3.0","jest":"^29.7.0","jest-environment-jsdom":"^29.7.0","prettier":"^3.1.0","rollup":"^3.29.4","rollup-plugin-dts":"^6.1.0","rollup-plugin-node-polyfills":"^0.2.1","ts-jest":"^29.1.1","ts-node":"^10.9.2","typedoc":"^0.25.4","typescript":"^5.3.0"},"engines":{"node":">=16.0.0"},"_id":"@disregardfiat/spk-js@1.0.4","gitHead":"2ded92e2df36ec5d2b188750993efcbac034efb7","_nodeVersion":"18.20.8","_npmVersion":"10.8.2","dist":{"integrity":"sha512-uHggduSG7cp7FsokqYTlPMTZj6D73Q7a9m7jWpel+GCmAV+efo0c2BJmnrJR05eA65toz/vobz+TX+tRZgC5Iw==","shasum":"946c2c4e40e8ea0728e5db0c8eb9d9651968cd40","tarball":"https://registry.npmjs.org/@disregardfiat/spk-js/-/spk-js-1.0.4.tgz","fileCount":57,"unpackedSize":3564297,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHeB/VsL8D4jy+c2BMNvH9DkQ67eR1rdaS+AWhEYdFDDAiEA01x8kIIhnrEpsKL1nFImwZiQyrAIy1T/IPFV8RarePw="}]},"_npmUser":{"name":"disregardfiat","email":"disregardfiat@gmail.com"},"directories":{},"maintainers":[{"name":"disregardfiat","email":"disregardfiat@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/spk-js_1.0.4_1754286497740_0.2044165274162666"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-31T19:59:48.496Z","modified":"2025-08-04T05:48:18.133Z","1.0.0-alpha":"2025-07-31T19:59:48.811Z","1.0.0-alpha.1":"2025-08-02T19:53:42.673Z","1.0.0":"2025-08-03T20:19:42.965Z","1.0.4":"2025-08-04T05:48:17.958Z"},"bugs":{"url":"https://github.com/disregardfiat/spk-js/issues"},"author":{"name":"SPK Network"},"license":"MIT","homepage":"https://github.com/disregardfiat/spk-js#readme","keywords":["spk","spknetwork","ipfs","decentralized","storage","hive","blockchain","web3"],"repository":{"type":"git","url":"git+https://github.com/disregardfiat/spk-js.git"},"description":"JavaScript library for interacting with SPK Network decentralized storage","maintainers":[{"name":"disregardfiat","email":"disregardfiat@gmail.com"}],"readme":"# SPK-JS\n\nJavaScript library for interacting with SPK Network decentralized storage.\n\n## Features\n\n- 🚀 Simple API for decentralized file storage\n- 🔐 Hive blockchain authentication\n- 📦 Automatic IPFS content addressing\n- 💰 Token management (LARYNX, SPK, BROCA)\n- 🔄 Chunked uploads with resume support\n- 🔒 Client-side encryption\n- 📁 Virtual file system\n- ⚡ TypeScript support\n\n## Installation\n\n### NPM\n\n```bash\nnpm install @disregardfiat/spk-js\n```\n\n### CDN\n\n```html\n<script src=\"https://unpkg.com/@disregardfiat/spk-js@latest/dist/spk-js.min.js\"></script>\n```\n\n### Specific Version\n\n```bash\nnpm install @disregardfiat/spk-js@1.0.0-alpha.1\n```\n\n## Quick Start\n\n```javascript\nimport SPK from '@disregardfiat/spk-js';\n\n// Initialize with Hive account\nconst spk = new SPK('username');\nawait spk.init();\n\n// Upload a file\nconst file = document.getElementById('fileInput').files[0];\nconst result = await spk.upload(file);\n\nconsole.log(`File uploaded: ${result.cid}`);\n```\n\n## Usage\n\n### Authentication\n\nSPK-JS supports two authentication methods:\n\n#### 1. Hive Keychain (Auto-detected)\n\nIf Hive Keychain is available in the browser, it will be used automatically:\n\n```javascript\nconst spk = new SPK('username');\nawait spk.init(); // Auto-detects window.hive_keychain\n```\n\n#### 2. Custom Signer\n\nYou can provide a custom signer object with the following interface:\n\n```javascript\nconst customSigner = {\n  requestSignature: (account, challenge, keyType, callback) => {\n    // Your signing implementation\n    // callback({ signature: '...', publicKey: '...' }) on success\n    // callback({ error: 'error message' }) on failure\n  },\n  requestBroadcast: (account, operations, keyType, callback) => {\n    // Your broadcast implementation for raw Hive operations\n    // operations is an array of Hive transaction operations\n    // callback({ result: { id: 'txid' } }) on success\n    // callback({ error: 'error message' }) on failure\n  },\n  requestEncryptMemo: (account, recipient, memo, callback) => {\n    // Your memo encryption implementation\n    // recipient can be a string (single) or array (multi-sig)\n    // callback({ success: true, result: '#encrypted-memo' }) on success\n    // callback({ success: false, error: 'error message' }) on failure\n  }\n};\n\nconst spk = new SPK('username', {\n  keychain: customSigner\n});\n```\n\n**Note**: The library automatically detects whether you're using a custom signer or Hive Keychain and adapts accordingly.\n\nFor synchronous implementations, you can also provide:\n- `requestSignatureSynchronous(account, challenge, keyType)` - Returns `{ signature, publicKey }` or throws\n- `requestBroadcastSynchronous(account, operations, keyType)` - Returns `{ result: { id } }` or throws\n- `encryptMemoSync(privateKey, recipientPublicKey, message)` - Returns encrypted memo string starting with '#'\n- `decryptMemoSync(privateKey, encryptedMemo)` - Returns decrypted message\n\n### File Upload\n\nBasic upload:\n\n```javascript\nconst result = await spk.upload(file);\n// Returns: { cid, contract, size, url }\n```\n\nAdvanced upload with options:\n\n```javascript\nconst result = await spk.upload(files,{\n  // contract options {} defaults to autoRenew\n  encrypt: ['alice', 'bob'],  // Encrypt for specific users\n  autoRenew: true, \n  metaData: [{\n      name: 'Different',\n      FileIndex: 0,\n      ext: 'jpg',\n      path: '/Documents',        // See Virtual File System\n      thumbnail: `CID`, // custom thumbnail CID or address\n      tags: ['important'],        // See Tags\n      license: 'CC0', // See License\n      labels: '', // See Labels\n      autoRenew: true,           // Auto-renew contract\n      onProgress: (percent) => {\n        console.log(`Upload progress: ${percent}%`);\n  }\n}]);\n```\n\nThe user will be prompted for signatures and brodcasts as appropriate. It is better to batch file uploads where possible to minimize interactions.\n\n### Token Operations\n\n```javascript\n// Get balances\nconst balances = await spk.getBalances();\n// { ClaimableLARYNX: 1, LARYNX: 1000, ClaimableSPK: 2, SPK: 500, BROCA: 250, LP: 100, SP: 10, BP: 1000, BRC: '35Mb' }\n\n// Send tokens\nawait spk.sendLarynx(100, 'recipient', 'Optional memo'); //in millitokens\nawait spk.sendSpk(50, 'recipient');\nawait spk.send('50.000 BROCA', 'charlie') // will parse floats and token names\n\n// Power up/down\nawait spk.brocaPowerUp(100);    // Stake LARYNX\nawait spk.spkPowerDown(100);  // Unstake LARYNX\n```\n\n### File Management\n\n```javascript\n// List files\nconst files = await spk.listFiles({\n  folder: 'Documents',\n  tags: ['important']\n});\n\n// Get file info\nconst file = await spk.getFile('QmXxx...');\n\n// Delete file (stops renewal, places in \"Trash\")\nawait spk.deleteFile('QmXxx...');\n```\n\n### Encryption\n\nSPK-JS provides client-side file encryption using AES-256-GCM with Hive memo key wrapping:\n\n```javascript\n// Upload encrypted file\nconst result = await spk.upload(file, {\n  encrypt: ['alice', 'bob', 'charlie'] // Recipients who can decrypt\n});\n\n// The file is encrypted with a random AES key\n// The AES key is wrapped for each recipient using their Hive memo key\n// The signer account is automatically included as a recipient\n// Only specified recipients (plus the signer) can decrypt the file\n```\n\n#### How It Works\n\n1. **AES Key Generation**: A random 256-bit AES key is generated for each batch of files\n2. **File Encryption**: All files in the batch are encrypted using the same AES-256-GCM key\n3. **Auto-Signer Inclusion**: The signer account is automatically added to recipients (no need to track keys)\n4. **Key Wrapping**: The AES key is encrypted for each recipient using their Hive memo key\n5. **Multi-Sig Support**: When available, uses Hive Keychain multi-sig to encrypt for all recipients at once\n6. **Upload**: The encrypted files and wrapped keys are uploaded to IPFS\n\n#### Manual Encryption (Advanced)\n\n```javascript\nimport { Encryption, KeyManager } from '@disregardfiat/spk-js';\n\n// Initialize encryption\nconst keyManager = new KeyManager();\nconst encryption = new Encryption(keyManager);\n\n// Generate AES key\nconst aesKey = await encryption.generateAESKey();\n\n// Encrypt file\nconst encrypted = await encryption.encryptFile(file, aesKey);\n\n// Fetch recipient memo keys\nconst recipients = await keyManager.fetchMemoKeys(['alice', 'bob']);\n\n// Wrap AES key for recipients\nconst wrappedKeys = await encryption.wrapKeyForRecipients(aesKey, recipients);\n```\n\n#### Wallet Integration\n\nSPK-JS integrates with Hive Keychain for memo encryption:\n\n```javascript\nimport { walletEncryption } from '@disregardfiat/spk-js';\n\n// Check if Hive Keychain is available\nif (walletEncryption.isKeychainAvailable()) {\n  // Single recipient encryption\n  const encrypted = await walletEncryption.encryptMemoKeychain(\n    'sender',\n    'recipient',\n    'aes-key-data'\n  );\n  \n  // Multi-signature encryption (encrypt for multiple recipients at once)\n  const encryptedKeys = await walletEncryption.encryptMemoKeychainMultiSig(\n    'sender',\n    ['alice', 'bob', 'charlie'], // Array of recipients\n    'aes-key-data'\n  );\n  // Returns: [\n  //   { account: 'alice', encryptedKey: '#encrypted-for-alice' },\n  //   { account: 'bob', encryptedKey: '#encrypted-for-bob' },\n  //   { account: 'charlie', encryptedKey: '#encrypted-for-charlie' }\n  // ]\n  \n  // Batch encryption with automatic fallback\n  const results = await walletEncryption.encryptForMultipleRecipients(\n    'sender',\n    ['alice', 'bob', 'charlie'],\n    'aes-key-data'\n  );\n  // Tries multi-sig first, falls back to individual encryption if needed\n} else {\n  // Use custom wallet with synchronous encryption\n  const encrypted = walletEncryption.encryptMemoSync(\n    privateKey,\n    recipientPublicKey,\n    'aes-key-data'\n  );\n  \n  // Multi-recipient with custom wallet\n  const recipients = [\n    { account: 'alice', publicKey: 'STM8PublicKey1...' },\n    { account: 'bob', publicKey: 'STM8PublicKey2...' }\n  ];\n  const encryptedKeys = walletEncryption.encryptMemoSyncMultiSig(\n    privateKey,\n    recipients,\n    'aes-key-data'\n  );\n}\n```\n\n##### Hive Keychain Methods\n\nWhen Hive Keychain is available (`window.hive_keychain`), it provides:\n\n- `requestEncryptMemo(account, recipient, memo, callback)`\n  - `recipient`: Can be a string (single recipient) or array (multi-sig)\n  - Multi-sig response formats:\n    - Array: `['#encrypted-for-alice', '#encrypted-for-bob']`\n    - Object: `{ alice: '#encrypted-for-alice', bob: '#encrypted-for-bob' }`\n\n##### Metadata Storage\n\nEncrypted file metadata can be stored on-chain in a compact format:\n\n```javascript\nimport { Encryption } from '@disregardfiat/spk-js';\n\n// Generate compact metadata string\nconst metadataString = Encryption.generateMetadataString(metadata);\n// Returns base64 encoded string with minimal keys\n\n// Parse metadata string back to object\nconst metadata = Encryption.parseMetadataString(metadataString);\n```\n\n## Virtual File System\n\nThe SPK Network provides a virtual file system for organizing uploaded files. Files can be organized into folders and tagged with metadata for better organization and discovery.\n\n### File System API\n\nSPK-JS includes a FileSystem module that provides easy access to the Honeygraph file system API:\n\n```javascript\n// Browse user's files\nconst listing = await spk.filesystem.browse('username');\nconsole.log(`Found ${listing.contents.length} items`);\n\n// Browse specific folder\nconst docs = await spk.filesystem.browse('username', '/Documents');\n\n// Get file URL\nconst fileUrl = await spk.filesystem.getFileUrl('username', '/Images/photo.jpg');\n\n// Search for files\nconst videos = await spk.filesystem.searchFiles('username', '*.mp4', '/Videos');\n\n// Check if path exists\nconst exists = await spk.filesystem.exists('username', '/Music');\n\n// Get preset folders\nconst folders = await spk.filesystem.getPresetFolders('username');\n// Returns: Documents, Images, Videos, Music, Archives, Code, Trash, Misc\n\n// Calculate directory size\nconst size = await spk.filesystem.getDirectorySize('username', '/Documents');\nconsole.log(`Total size: ${(size / 1024 / 1024).toFixed(2)} MB`);\n\n// Build file tree\nconst tree = await spk.filesystem.buildFileTree('username', '/', 2);\n\n// Access shared files\nconst sharedWithMe = await spk.filesystem.getSharedWithMe('username');\nconst sharedByMe = await spk.filesystem.getSharedByMe('username');\n```\n\n### File System Entry Structure\n\nEach file or directory entry contains:\n- `name`: File/folder name\n- `type`: 'file' or 'directory'\n- `path`: Full path\n- `cid`: IPFS content identifier (files only)\n- `size`: File size in bytes\n- `mimeType`: File MIME type\n- `itemCount`: Number of items (directories only)\n- `contract`: Storage contract details\n- `metadata`: Additional metadata (encryption, tags, etc.)\n\n## Metadata\n\nSPK Network supports rich metadata for uploaded files including tags, labels, and licenses. This metadata helps with file organization, discovery, and rights management.\n\n### Tags\n\nTags are content warnings and file type indicators stored as bitwise flags:\n\n```javascript\nimport { SPKFileMetadata, TAGS } from '@disregardfiat/spk-js';\n\n// Create metadata with tags\nconst metadata = new SPKFileMetadata({\n  tags: [4, 8] // NSFW + Executable\n});\n\n// Or add tags individually\nmetadata.addTag(4); // Add NSFW tag\nmetadata.removeTag(8); // Remove Executable tag\n\n// Check if tag is present\nif (metadata.hasTag(4)) {\n  console.log('Content is NSFW');\n}\n\n// Available tags:\n// 4 - NSFW (Not Safe For Work)\n// 8 - Executable (Is an executable file)\n```\n\n### Labels\n\nLabels are visual organization markers stored as a string of characters:\n\n```javascript\n// Add labels to files\nmetadata.addLabel('1'); // Important\nmetadata.addLabel('2'); // Favorite\nmetadata.addLabel('5'); // Orange\n\n// Check labels\nif (metadata.hasLabel('1')) {\n  console.log('File is marked as important');\n}\n\n// Available labels:\n// 0 - Miscellaneous\n// 1 - Important\n// 2 - Favorite (default)\n// 3 - Random\n// 4 - Red\n// 5 - Orange\n// 6 - Yellow\n// 7 - Green\n// 8 - Blue\n// 9 - Purple\n```\n\n### Licenses\n\nLicenses define usage rights using Creative Commons standards:\n\n```javascript\n// Set a license\nmetadata.setLicense('7'); // CC0 Public Domain\n\n// Get license details\nconst license = metadata.getLicenseDetails();\nconsole.log(license.description); // \"CC0: Public Domain Grant\"\nconsole.log(license.link); // \"https://creativecommons.org/...\"\n\n// Available licenses:\n// 1 - CC BY (Attribution)\n// 2 - CC BY-SA (Attribution Share-Alike)\n// 3 - CC BY-ND (Attribution No-Derivatives)\n// 4 - CC BY-NC-ND (Attribution Non-Commercial No-Derivatives)\n// 5 - CC BY-NC (Attribution Non-Commercial)\n// 6 - CC BY-NC-SA (Attribution Non-Commercial Share-Alike)\n// 7 - CC0 (Public Domain)\n```\n\n### Using Metadata with Uploads\n\n```javascript\n// Upload with metadata\nconst result = await spk.upload(files, {\n  metaData: [{\n    name: 'vacation-photo',\n    FileIndex: 0,\n    ext: 'jpg',\n    thumb: 'https://example.com/thumb.jpg',\n    path: '/Photos/Vacation',\n    tags: [4], // NSFW\n    labels: '125', // Important, Favorite, Orange\n    license: '1' // CC BY\n  }]\n});\n\n// Or use the SPKFileMetadata class\nconst metadata = new SPKFileMetadata({\n  name: 'document',\n  ext: 'pdf',\n  tags: [8], // Executable\n  labels: '1', // Important\n  license: '2' // CC BY-SA\n});\n\nconst result = await spk.upload(file, {\n  metaData: [metadata.toSPKFormat()]\n});\n```\n\n## API Reference\n\n### Constructor\n\n```typescript\nnew SPK(username: string, options?: SPKOptions)\n```\n\nOptions:\n- `node`: SPK Network API node URL\n- `ipfsGateway`: IPFS gateway URL\n- `keychain`: Hive Keychain instance\n\n### Methods\n\n#### Account Methods\n- `init()`: Initialize account data\n- `getAccount()`: Get full account details\n- `getBalances()`: Get token balances\n- `refresh()`: Refresh account data\n\n#### File Methods\n- `upload(file, options)`: Upload file to IPFS\n- `listFiles(filters)`: List user's files\n- `getFile(cid)`: Get file metadata\n- `deleteFile(cid)`: Stop file renewal\n\n#### Token Methods\n- `sendLarynx(amount, to, memo)`: Send LARYNX tokens\n- `sendSpk(amount, to, memo)`: Send SPK tokens\n- `powerUp(amount)`: Stake LARYNX tokens\n- `powerDown(amount)`: Unstake LARYNX tokens\n\n#### Storage Node Operations\n- `registerNode(ipfsId, domain, bidRate)`: Register as a storage node\n- `getNodeStatus()`: Check node registration status\n- `storeFiles(contractIds)`: Store files on the network (become a storage provider)\n- `removeFiles(contractIds)`: Remove files from storage (stop being a provider)\n- `getStoredContracts()`: Get contracts being stored by this node\n- `getAvailableContracts(limit)`: Find under-replicated contracts to store\n- `extendContract(contractId, fileOwner, brocaAmount, power)`: Extend a storage contract\n- `calculateStorageEarnings(contract, bidRate)`: Calculate potential earnings\n- `batchStore(contractIds, chunkSize)`: Batch store multiple contracts efficiently\n- `registerAuthority(pubKey)`: Register a public key authority\n\n### Storage Node Example\n\n```javascript\n// Register as a storage node\nconst nodeReg = await spk.registerNode(\n  'QmYourIPFSNodeId',        // From `ipfs id`\n  'https://your-node.com',   // Your public URL\n  500                        // Bid rate\n);\n\n// Find and store available contracts\nconst available = await spk.getAvailableContracts(10);\nconst contractIds = available.slice(0, 3).map(c => c.id);\nconst storeResult = await spk.storeFiles(contractIds);\n\n// Check what you're storing\nconst stored = await spk.getStoredContracts();\nconsole.log(`Storing ${stored.length} contracts`);\n\n// Calculate earnings\nconst earnings = spk.calculateStorageEarnings({\n  size: 1024 * 1024,     // 1MB\n  providers: 3,          // 3 storage nodes\n  duration: 28800 * 30   // 30 days in blocks\n});\n```\n\n## Development\n\n### Setup\n\n```bash\ngit clone https://github.com/spknetwork/spk-js.git\ncd spk-js\nnpm install\n```\n\n### Testing\n\n```bash\nnpm test              # Run all tests\nnpm run test:watch    # Watch mode\nnpm run test:coverage # Coverage report\n```\n\n### Building\n\n```bash\nnpm run build         # Build library\nnpm run build:watch   # Watch mode\nnpm run docs          # Generate documentation\n```\n\n## Examples\n\nSee the [examples](./examples) directory for complete examples:\n\n- [Basic Upload](./examples/basic-upload.html)\n- [React Integration](./examples/react-example)\n- [Vue 3 Integration](./examples/vue-example)\n- [Node.js Usage](./examples/node-example)\n- [Storage Node Operations](./examples/storage-node-operations.js)\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Write tests for your changes\n4. Ensure all tests pass (`npm test`)\n5. Commit your changes (`git commit -m 'Add amazing feature'`)\n6. Push to the branch (`git push origin feature/amazing-feature`)\n7. Open a Pull Request\n\n## License\n\nMIT License - see [LICENSE](./LICENSE) for details\n\n## Links\n\n- [SPK Network](https://spk.network/)\n- [Documentation](https://dlux.io/docs)\n- [Discord](https://discord.gg/YEHvWEvvey)\n- [GitHub](https://github.com/disregardfiat/spk-js)","readmeFilename":"README.md"}