{"_id":"@curiostorage/market-client","_rev":"3-b0a75f38ada36fca4730fb155a78a494","name":"@curiostorage/market-client","dist-tags":{"latest":"0.4.2"},"versions":{"0.4.0":{"name":"@curiostorage/market-client","version":"0.4.0","keywords":["curio","filecoin","storage","market","api","typescript"],"author":{"name":"Curio Team"},"license":"MIT","_id":"@curiostorage/market-client@0.4.0","maintainers":[{"name":"snadrus","email":"snadrus@gmail.com"}],"dist":{"shasum":"93cd1e3a878cf8773e62ea5bf80441d5f1fc466e","tarball":"https://registry.npmjs.org/@curiostorage/market-client/-/market-client-0.4.0.tgz","fileCount":35,"integrity":"sha512-N44KjqnHgPyfiAqvXeyema0OCJdXNkwLge2tbJIcwi/ScleEl3IB3O/AyoxNnmYGkRM7DNMHwBOnalXv31O9hg==","signatures":[{"sig":"MEQCIDGHzUcp0nwKeeYJ4Pq0owYJTy+Ie9ZaT17n9tnIImC3AiBZ4PHjR3apYsg0nqjWAeRoXDBKkSPXJrwQ8yfm1B6j4Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":194480},"main":"dist/src/index.js","types":"dist/src/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"3523a02ce21ea1b144ba0b73c49213955a10e17d","scripts":{"test":"jest","build":"npm run generate && npm run compile","clean":"rm -rf dist generated","compile":"tsc","generate":"openapi-generator-cli generate -i ../http/swagger.json -g typescript-fetch -o ./generated --additional-properties=supportsES6=true,typescriptThreePlus=true --skip-validate-spec","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"snadrus","email":"snadrus@gmail.com"},"_npmVersion":"10.9.2","description":"TypeScript API client for Curio storage market. You probably want the Synapse SDK instead.","directories":{},"_nodeVersion":"23.11.0","dependencies":{"ulid":"^3.0.1","tweetnacl":"^1.0.3","multiformats":"^13.4.0","@noble/secp256k1":"^2.1.0","isomorphic-fetch":"^3.0.0","@glif/filecoin-address":"^4.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.0.0","ts-jest":"^29.0.0","typescript":"^5.0.0","@types/jest":"^29.0.0","@types/node":"^20.0.0","@openapitools/openapi-generator-cli":"^2.7.0"},"_npmOperationalInternal":{"tmp":"tmp/market-client_0.4.0_1757555307945_0.7242965263878081","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@curiostorage/market-client","version":"0.4.1","keywords":["curio","filecoin","storage","market","api","typescript"],"author":{"name":"Curio Team"},"license":"MIT","_id":"@curiostorage/market-client@0.4.1","maintainers":[{"name":"snadrus","email":"snadrus@gmail.com"}],"dist":{"shasum":"3e8d58180612ea01249ff6e121d9c30749ea2a0e","tarball":"https://registry.npmjs.org/@curiostorage/market-client/-/market-client-0.4.1.tgz","fileCount":35,"integrity":"sha512-gtr2i0QO9xffoMurFqaeA7rb9P1djhwBI0l4bo3gQqTCkJvLeAdTiWucdx3PuhlOoNuOAkoqPrcnkU+iikpHHQ==","signatures":[{"sig":"MEUCIQDJjxX4CJo/nssYAP8xxAWDi9xYMvHz0jPAHDzRwovjNAIgNO6s8/HATwTnJzz4NB3l5eZWaA9ReujadAVL+3467eo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":201907},"main":"dist/src/index.js","types":"dist/src/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"80d989647891a4390f9913b726a5f38d4ec741c3","scripts":{"test":"jest","build":"npm run generate && npm run compile","clean":"rm -rf dist generated","compile":"tsc","generate":"openapi-generator-cli generate -i ../http/swagger.json -g typescript-fetch -o ./generated --additional-properties=supportsES6=true,typescriptThreePlus=true --skip-validate-spec","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"snadrus","email":"snadrus@gmail.com"},"_npmVersion":"10.9.2","description":"TypeScript API client for Curio storage market. You probably want the Synapse SDK instead.","directories":{},"_nodeVersion":"23.11.0","dependencies":{"ulid":"^3.0.1","tweetnacl":"^1.0.3","multiformats":"^13.4.0","@noble/secp256k1":"^2.1.0","isomorphic-fetch":"^3.0.0","@glif/filecoin-address":"^4.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.0.0","ts-jest":"^29.0.0","typescript":"^5.0.0","@types/jest":"^29.0.0","@types/node":"^20.0.0","@openapitools/openapi-generator-cli":"^2.7.0"},"_npmOperationalInternal":{"tmp":"tmp/market-client_0.4.1_1757556305106_0.106221055473676","host":"s3://npm-registry-packages-npm-production"}},"0.4.2":{"name":"@curiostorage/market-client","version":"0.4.2","description":"TypeScript API client for Curio storage market. You probably want the Synapse SDK instead.","main":"dist/src/index.js","types":"dist/src/index.d.ts","scripts":{"build":"npm run generate && npm run compile","generate":"openapi-generator-cli generate -i ../http/swagger.json -g typescript-fetch -o ./generated --additional-properties=supportsES6=true,typescriptThreePlus=true --skip-validate-spec","compile":"tsc","clean":"rm -rf dist generated","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"keywords":["curio","filecoin","storage","market","api","typescript"],"author":{"name":"Curio Team"},"license":"MIT","devDependencies":{"@openapitools/openapi-generator-cli":"^2.7.0","@types/jest":"^29.0.0","@types/node":"^20.0.0","jest":"^29.0.0","ts-jest":"^29.0.0","typescript":"^5.0.0"},"dependencies":{"@glif/filecoin-address":"^4.0.0","@noble/secp256k1":"^2.1.0","@web3-storage/data-segment":"^5.3.0","isomorphic-fetch":"^3.0.0","multiformats":"^13.4.0","tweetnacl":"^1.0.3","ulid":"^3.0.1"},"engines":{"node":">=18.0.0"},"_id":"@curiostorage/market-client@0.4.2","gitHead":"c3f52bfeadd843f012a235738c5adf9cb470d7cc","_nodeVersion":"23.11.0","_npmVersion":"11.6.0","dist":{"integrity":"sha512-+y+ILW9KdkNHi0e3Kc2Pe5ICaZwpXlBwKHIESsHYbFALjzU66mfaH0fs/tt7a9QqD16rKfhW4TyYeTlfm6uFYg==","shasum":"5968e983d0216b6f9ea8c69e2066016bf888ce89","tarball":"https://registry.npmjs.org/@curiostorage/market-client/-/market-client-0.4.2.tgz","fileCount":38,"unpackedSize":184074,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBVhJpDhQj3igEqIpUc0PcivnkoEKK2W3WBQ4/jYNJi3AiEAkWyBZE9uJZiTbvuPIDjCszgHO/ASABnc0uGJ2e0YSYU="}]},"_npmUser":{"name":"snadrus","email":"snadrus@gmail.com"},"directories":{},"maintainers":[{"name":"snadrus","email":"snadrus@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/market-client_0.4.2_1758213091095_0.8515397060563983"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-11T01:48:27.864Z","modified":"2025-09-18T16:31:31.488Z","0.4.0":"2025-09-11T01:48:28.127Z","0.4.1":"2025-09-11T02:05:05.282Z","0.4.2":"2025-09-18T16:31:31.305Z"},"author":{"name":"Curio Team"},"license":"MIT","keywords":["curio","filecoin","storage","market","api","typescript"],"description":"TypeScript API client for Curio storage market. You probably want the Synapse SDK instead.","maintainers":[{"name":"snadrus","email":"snadrus@gmail.com"}],"readme":"# Curio TypeScript Market Client\n\nThis is a TypeScript API client for the Curio storage market API. It provides a strongly-typed interface for interacting with Curio storage providers.\n\n## Installation\n\n```bash\nnpm install @curiostorage/market-client\n```\n\n## Prerequisites\n\n**Authentication is required** for all API operations. You must configure authentication before using the client.\n\n### Authentication Methods\n\nThe client supports two authentication methods:\n\n1. **Ed25519** (default) - Uses Ed25519 key pairs\n2. **Secp256k1** - Uses Secp256k1 key pairs (compatible with Ethereum wallets)\n\n### Authentication Configuration\n\nAuthentication can be configured programmatically or via environment variables (used in examples):\n\n**Programmatic Configuration:**\n```typescript\nconst authConfig = {\n  serverUrl: 'https://your-server.com',\n  clientAddr: 'f1client...',\n  recordKeeper: 't1000',  // Required for PDPv1 deals\n  contractAddress: '0x4A6867D8537f83c1cEae02dF9Df2E31a6c5A1bb6',\n  keyType: 'ed25519' as 'ed25519' | 'secp256k1',\n  publicKeyB64: 'your_base64_public_key',\n  privateKeyB64: 'your_base64_private_key',\n  // OR for secp256k1:\n  // secpPrivateKeyHex: 'your_hex_private_key',\n  // secpPrivateKeyB64: 'your_base64_private_key',\n};\n```\n\n**Environment Variables (for examples):**\n```bash\n# Used in the example scripts\nexport PDP_URL=https://your-server.com\nexport PDP_CLIENT=f1client...\nexport PDP_RECORD_KEEPER=t1000\nexport PDP_CONTRACT=0x4A6867D8537f83c1cEae02dF9Df2E31a6c5A1bb6\nexport PDP_KEY_TYPE=ed25519\nexport PDP_PUBLIC_KEY_B64=your_base64_public_key\nexport PDP_PRIVATE_KEY_B64=your_base64_private_key\n```\n\n**Running Example Scripts:**\n```bash\n# Example: Running step 1 with all environment variables inline\nPDP_INSECURE_TLS=1 \\\nPDP_URL=\"https://your-server.com\" \\\nPDP_CLIENT=f1client... \\\nPDP_KEY_TYPE=secp256k1 \\\nPDP_SECP_PRIVATE_KEY_B64=\"your_base64_private_key\" \\\nPDP_CONTRACT=\"0x4A6867D8537f83c1cEae02dF9Df2E31a6c5A1bb6\" \\\nPDP_RECORD_KEEPER=\"0x158c8f05A616403589b99BE5d82d756860363A92\" \\\nDATASET_ID=\"01K4TKYS9302Y42BRBT0V0S389\" \\\nnpx ts-node 1.ts\n```\n\nYou'll need a wallet:\n lotus wallet new delegated\n\nYou can get your private key (for demo only) from:\n   lotus wallet export <your-delegated-wallet-address> | xxd -r -p | jq -r ‘.PrivateKey’ | base64 -d | xxd -p -c 32\n\nBe sure to setup Curio with:\n- ui —> pdp —> ownerAddress —> (hex key)\n- Your curio also needs storage attached:\n  -- ./curio cli storage attach -snap -seal /home/ubuntu/curiofolder\n  -- And a market enabled, such as taking the following with ./curio config set market.yaml\nmarket.yaml:\n[Batching]\n  [Batching.Commit]\n    Timeout = \"0h0m5s\"\n  [Batching.PreCommit]\n    Slack = \"6h0m0s\"\n    Timeout = \"0h0m5s\"\n\n[HTTP]\n  DelegateTLS = false\n  DomainName = \"yourserver.yourdomain.com\"\n  Enable = true\n  ListenAddress = \"0.0.0.0:443\"\n\n[Ingest]\n  MaxDealWaitTime = \"0h0m30s\"\n\n[Market]\n  [Market.StorageMarketConfig]\n    [Market.StorageMarketConfig.MK12]\n      ExpectedPoRepSealDuration = \"0h1m0s\"\n      ExpectedSnapSealDuration = \"0h1m0s\"\n      PublishMsgPeriod = \"0h0m10s\"\n\n[Subsystems]\n  EnableCommP = true\n  EnableDealMarket = true\n  EnablePDP = true\n  EnableParkPiece = true\n\n\n## Building from Source\n\n1. Install dependencies:\n```bash\nnpm install\n```\n\n2. Generate the client from swagger files:\n```bash\nnpm run generate\n```\n\n3. Compile TypeScript:\n```bash\nnpm run compile\n```\n\n4. Or build everything at once:\n```bash\nnpm run build\n```\n\n## Usage\n\n```typescript\nimport { MarketClient, PieceCidUtils, AuthUtils } from '@curiostorage/market-client';\n\n// Configure authentication programmatically\nconst authConfig = {\n  serverUrl: 'https://your-server.com',\n  clientAddr: 'f1client...',\n  recordKeeper: 't1000',  // Required for PDPv1 deals\n  contractAddress: '0x4A6867D8537f83c1cEae02dF9Df2E31a6c5A1bb6',\n  keyType: 'ed25519' as 'ed25519' | 'secp256k1',\n  publicKeyB64: 'your_base64_public_key',\n  privateKeyB64: 'your_base64_private_key',\n};\n\n// Build authentication header\nconst authHeader = await AuthUtils.buildAuthHeader(authConfig);\n\n// Create authenticated client\nconst client = new MarketClient({ \n  serverUrl: authConfig.serverUrl,\n  authHeader \n});\n\n// Get supported contracts\nconst contracts = await client.getContracts();\n\n// Get supported products\nconst products = await client.getProducts();\n\n// Get supported data sources\nconst sources = await client.getSources();\n\n// Get deal status\nconst status = await client.getStatus('deal-id-here');\n\n// Submit a deal\nconst deal = {\n  // ... deal configuration\n};\nconst result = await client.submitDeal(deal);\n\n// Upload data (single request - suitable for small deals)\nawait client.uploadData('deal-id', [1, 2, 3, 4]);\n\n// Chunked upload (suitable for large deals)\nawait client.initializeChunkedUpload('deal-id', startUploadData);\nawait client.uploadChunk('deal-id', '0', chunkData);\nawait client.uploadChunk('deal-id', '1', chunkData);\nawait client.finalizeChunkedUpload('deal-id');\n\n// Check upload status\nconst uploadStatus = await client.getUploadStatus('deal-id');\n\n// Compute piece CID v2 from blobs\nconst blobs = [new Blob(['file content'])];\nconst pieceCid = await PieceCidUtils.computePieceCidV2(blobs);\n\n// Convenience wrappers for common workflows (includes automatic chunked upload)\nconst result = await client.submitPDPv1DealWithUpload({\n  blobs: [new Blob(['file content'])],\n  client: 'f1client...',\n  provider: 'f1provider...',\n  contractAddress: '0x...'\n});\n\n// DDO deals with custom duration (includes automatic chunked upload)\nconst ddoResult = await client.submitDDOV1DealWithUpload({\n  blobs: [new Blob(['file content'])],\n  client: 'f1client...',\n  provider: 'f1provider...',\n  contractAddress: '0x...',\n  // Optional lifespan (epochs); defaults to 518400 if omitted\n  lifespan: 600000\n});\n\n// Results include upload statistics\nconsole.log('Uploaded chunks:', result.uploadedChunks);\nconsole.log('Uploaded bytes:', result.uploadedBytes);\n```\n\n## Streaming PDP (no upfront data section)\n\nCreate a deal without a `data` section, stream data using `uploadChunk`, compute the piece CID while streaming, then finalize with the computed `data`:\n\n```typescript\nimport { Client, MarketClientConfig, AuthUtils } from '@curiostorage/market-client';\n\n// Configure authentication programmatically\nconst authConfig = {\n  serverUrl: 'https://your-server.com',\n  clientAddr: 'f1client...',\n  recordKeeper: 't1000',  // Required for PDPv1 deals\n  contractAddress: '0x4A6867D8537f83c1cEae02dF9Df2E31a6c5A1bb6',\n  keyType: 'ed25519' as 'ed25519' | 'secp256k1',\n  publicKeyB64: 'your_base64_public_key',\n  privateKeyB64: 'your_base64_private_key',\n};\n\nconst authHeader = await AuthUtils.buildAuthHeader(authConfig);\n\nconst config: MarketClientConfig = { \n  serverUrl: authConfig.serverUrl,\n  authHeader \n};\nconst client = new Client(config);\n\n// Create the streaming helper (defaults to 1MB chunks)\nconst spdp = client.streamingPDP({\n  client: 'f1client...',\n  provider: 'f1provider...',\n  contractAddress: '0x...',\n  // chunkSize: 2 * 1024 * 1024, // optional\n});\n\n// Begin: submits deal without data and initializes chunked upload\nawait spdp.begin();\n\n// Stream bytes (these are uploaded as chunks and hashed for CID)\nspdp.write(new TextEncoder().encode('hello '));\nspdp.write(new TextEncoder().encode('world'));\n\n// Commit: flushes remaining chunk, computes piece CID, and finalizes with data\nconst { id, pieceCid, totalSize } = await spdp.commit();\nconsole.log({ id, pieceCid, totalSize });\n```\n\n## Product Types\n\nThe client supports three main product types for different use cases:\n\n### PDPv1 (Proof of Data Possession)\nUsed for creating datasets and proving data possession:\n```typescript\nproducts: {\n  pdpV1: {\n    createDataSet: true,        // Create new dataset\n    recordKeeper: 'provider-address',\n    pieceIds: [123, 456, 789]  // Piece IDs for each individual blob\n  },\n  retrievalV1: {\n    announcePayload: true,     // Announce to IPNI\n    announcePiece: true,       // Announce piece info\n    indexing: true             // Enable retrieval\n  }\n}\n```\nthen without createDataSet & with:\n    addPiece: true,            // Add piece to dataset\n\n### DDOv1 (Direct Data Onboarding)\nUsed for direct data onboarding with contract verification:\n```typescript\nproducts: {\n  ddoV1: {\n    duration: 518400,          // Typically chosen per-deal (lifespan)\n    provider: { address: 'provider-address' },\n    contractAddress: '0x...',\n    contractVerifyMethod: 'verifyDeal'\n  },\n  retrievalV1: {\n    announcePayload: true,\n    announcePiece: true,\n    indexing: true\n  }\n}\n```\n\n### RetrievalV1\nConfigures retrieval behavior and indexing:\n```typescript\nretrievalV1: {\n  announcePayload: true,       // Announce payload to IPNI\n  announcePiece: true,         // Announce piece information\n  indexing: true               // Index for CID-based retrieval\n}\n```\n\n## API Endpoints\n\n- `GET /contracts` - List supported DDO contracts\n- `GET /products` - List supported products  \n- `GET /sources` - List supported data sources\n- `GET /status/{id}` - Get deal status\n- `POST /store` - Submit a new deal\n- `PUT /upload/{id}` - Upload deal data (single request)\n- `POST /upload/{id}` - Initialize chunked upload\n- `PUT /uploads/{id}/{chunkNum}` - Upload a chunk\n- `POST /uploads/finalize/{id}` - Finalize chunked upload\n- `GET /uploads/{id}` - Get upload status\n\n## Automatic Chunked Upload\n\nThe convenience wrappers automatically handle chunked uploads after deal submission:\n\n- **Automatic Processing**: After submitting a deal, all blobs are automatically uploaded in chunks\n- **Configurable Chunk Size**: Uses 1MB chunks by default for optimal performance\n- **Progress Tracking**: Provides detailed logging of upload progress\n- **Complete Workflow**: Handles initialization, chunking, upload, and finalization\n- **Upload Statistics**: Returns total chunks and bytes uploaded\n- **Simple & Reliable**: Sequential uploads ensure data integrity and predictable behavior\n\n```typescript\nconst result = await client.submitPDPv1DealWithUpload({\n  blobs: [blob1, blob2, blob3],\n  client: 'f1client...',\n  provider: 'f1provider...',\n  contractAddress: '0x...'\n});\n\n// The result includes upload statistics\nconsole.log('Uploaded chunks:', result.uploadedChunks); // Total number of chunks\nconsole.log('Uploaded bytes:', result.uploadedBytes);   // Total bytes uploaded\n```\n\n## Piece ID Calculation\n\nThe client automatically calculates unique piece IDs for each blob in a deal:\n\n- **Individual Blob Piece IDs**: Each blob gets a unique piece ID based on its content hash and size\n- **Deterministic**: The same blob content will always generate the same piece ID\n- **Consistent**: Both PDPv1 and DDOv1 deals use the same piece ID calculation method\n- **Returned**: Piece IDs are included in the deal creation and returned by convenience wrappers\n\n```typescript\n// Each blob gets its own piece ID\nconst result = await client.submitPDPv1DealWithUpload({\n  blobs: [blob1, blob2, blob3],\n  client: 'f1client...',\n  provider: 'f1provider...',\n  contractAddress: '0x...'\n});\n\nconsole.log('Piece IDs:', result.pieceIds); // [123, 456, 789]\nconsole.log('Blob 1 → Piece ID:', result.pieceIds[0]); // 123\nconsole.log('Blob 2 → Piece ID:', result.pieceIds[1]); // 456\nconsole.log('Blob 3 → Piece ID:', result.pieceIds[2]); // 789\n```\n\n## Piece CID Computation\n\nThe client includes utilities for computing Filecoin piece CIDs using the [js-multiformats library](https://github.com/multiformats/js-multiformats):\n\n### `PieceCidUtils.computePieceCidV2(blobs: Blob[])`\nComputes a piece CID v2 from an array of blobs by:\n1. Concatenating all blob data\n2. Computing SHA2-256 hash\n3. Creating a CID v1 with raw codec\n4. Converting to piece CID v2 format\n\n### `PieceCidUtils.pieceCidV2FromV1(cid: CID, payloadSize: number)`\nConverts an existing CID v1 to piece CID v2 format, supporting:\n- Filecoin unsealed commitments (SHA2-256)\n- Filecoin sealed commitments (Poseidon)\n- Raw data codecs\n\n## Troubleshooting\n\n### Common Authentication Issues\n\n**Error: \"REQUIRED ENVIRONMENT VARIABLE MISSING: PDP_RECORD_KEEPER\"**\n- This error only appears when running the example scripts\n- The `PDP_RECORD_KEEPER` environment variable is required for the examples\n- Set it with: `export PDP_RECORD_KEEPER=your-record-keeper-address`\n- For programmatic usage, include `recordKeeper` in your auth config\n\n**Error: \"Authentication failed\" or \"Invalid signature\"**\n- Verify your private key is correctly formatted (base64 or hex)\n- Ensure the key type matches your key format (`ed25519` or `secp256k1`)\n- Check that the public key corresponds to the private key\n\n**Error: \"TLS verification failed\"**\n- For debugging only, you can disable TLS verification with `export PDP_INSECURE_TLS=1`\n- **Warning**: Never use this in production\n\n**Error: \"Connection refused\" or \"Network error\"**\n- Verify the `PDP_URL` is correct and accessible\n- Check that the server is running and accepting connections\n- Ensure firewall settings allow the connection\n\n### Key Generation\n\n**Ed25519 Key Generation:**\n```bash\n# Generate Ed25519 key pair\nnode -e \"\nconst crypto = require('crypto');\nconst keyPair = crypto.generateKeyPairSync('ed25519');\nconsole.log('Public key (base64):', keyPair.publicKey.export({ type: 'spki', format: 'der' }).toString('base64'));\nconsole.log('Private key (base64):', keyPair.privateKey.export({ type: 'pkcs8', format: 'der' }).toString('base64'));\n\"\n```\n\n**Secp256k1 Key Generation:**\n```bash\n# Generate Secp256k1 key pair\nnode -e \"\nconst crypto = require('crypto');\nconst keyPair = crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' });\nconsole.log('Private key (hex):', keyPair.privateKey.export({ type: 'sec1', format: 'der' }).toString('hex'));\nconsole.log('Private key (base64):', keyPair.privateKey.export({ type: 'sec1', format: 'der' }).toString('base64'));\n\"\n```\n\n### Environment Variable Validation\n\nThe example client validates your configuration:\n\n```typescript\nimport { AuthUtils } from '@curiostorage/market-client';\n\nconst authConfig = {\n  // ... your config\n};\n\ntry {\n  const authHeader = await AuthUtils.buildAuthHeader(authConfig);\n  console.log('✅ Authentication configuration is valid');\n} catch (error) {\n  console.error('❌ Authentication configuration error:', error.message);\n}\n```\n\n## Examples\n\nSee the `examples/unpkg-end-to-end/` directory for a complete step-by-step workflow that demonstrates:\n\n- Authentication setup and configuration (using environment variables)\n- Creating PDPv1 datasets\n- Adding pieces to datasets\n- Uploading data with chunked uploads\n- Downloading pieces\n- Deleting datasets and pieces\n\nEach step is documented and can be run independently, making it easy to understand the complete workflow. The examples use environment variables for configuration, but you can adapt the code to use programmatic configuration instead.\n\n**Quick Start with Examples:**\n```bash\n# Set your configuration\nexport PDP_URL=\"https://your-server.com\"\nexport PDP_CLIENT=\"f1client...\"\nexport PDP_RECORD_KEEPER=\"0x158c8f05A616403589b99BE5d82d756860363A92\"\nexport PDP_CONTRACT=\"0x4A6867D8537f83c1cEae02dF9Df2E31a6c5A1bb6\"\nexport PDP_KEY_TYPE=\"secp256k1\"\nexport PDP_SECP_PRIVATE_KEY_B64=\"your_base64_private_key\"\n\n# Run the complete workflow\ncd examples/unpkg-end-to-end/\nnpx ts-node 1.ts  # Create dataset\nnpx ts-node 2.ts  # Add piece and upload\nnpx ts-node 3.ts  # Download piece\nnpx ts-node 4.ts  # Delete\n```\n\n## Development\n\nThe client is generated from the OpenAPI/Swagger specification in `../http/swagger.json`. To regenerate after API changes:\n\n```bash\nnpm run generate\nnpm run compile\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}