feat(sdk,graphql): deprecate pinThing mutation in favor of direct Pinata uploads#1188
feat(sdk,graphql): deprecate pinThing mutation in favor of direct Pinata uploads#1188simonas-notcat wants to merge 3 commits intomainfrom
Conversation
…ata uploads Migrate from backend-mediated IPFS pinning to client-side Pinata uploads for better performance and reliability. This change removes the dependency on the GraphQL backend for IPFS operations. Breaking Changes: - createAtomFromThing now requires pinataApiJWT in config - batchCreateAtomsFromThings now requires pinataApiJWT in config Deprecations: - pinThing GraphQL mutation (use uploadJsonToPinata instead) - pinThing SDK function (use uploadJsonToPinata instead) Updates: - All documentation and examples updated with new Pinata JWT requirement - Added deprecation notices to GraphQL README and mutation files - Updated SDK CHANGELOG with breaking changes and migration guidance - Modified nextjs-template example to include pinataApiJWT configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
PR Review: Deprecate pinThing mutation in favor of direct Pinata uploadsSummaryThis PR successfully migrates from backend-mediated IPFS pinning to client-side Pinata uploads. The changes are well-documented with proper deprecation notices and migration guides. Overall, this is a solid refactoring that improves architecture by reducing backend dependencies. ✅ Strengths
🔍 Issues & RecommendationsHigh Priority1. Security: Exposed Pinata JWT in Client-Side Code Using NEXT_PUBLIC_* exposes the JWT to the browser, allowing users to extract and abuse your Pinata API key. This could lead to unauthorized IPFS uploads, quota abuse, and API key compromise. Recommendation: Use a backend API route to proxy Pinata uploads securely, or use Pinata key scoping. Update docs to warn about this. 2. Type Safety: Missing URI Format Validation No validation that dataIpfs.IpfsHash is valid. Add validation before constructing the URI. 3. Inconsistent URI Construction Medium Priority4. Test Coverage Missing - No tests for createAtomFromThing and batchCreateAtomsFromThings 5. Unused Variable - Line 22 in packages/sdk/src/api/pin-thing.ts is a no-op 6. Sequential Uploads - Batch operation uploads sequentially (slow). Consider Promise.all for parallelization. 7. Documentation Typo - Extra quote in description string at IntuitionCreateThingButton.tsx:36 📊 Overall Assessment
✅ RecommendationApprove with changes - Fix the NEXT_PUBLIC_PINATA_API_JWT exposure before merging, add input validation, consider parallelizing uploads, and add tests. Great work on the migration and documentation! 🤖 Review generated with Claude Code |
- Add security warning for exposed NEXT_PUBLIC_PINATA_API_JWT in example template - Add IPFS hash validation in all upload functions - Standardize URI construction pattern across SDK functions - Parallelize batch uploads for improved performance - Remove unused variable in pin-thing.ts - Fix typo in example description string 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
PR Review: Migration to Direct Pinata UploadsSummaryThis PR successfully migrates from backend-mediated IPFS pinning to client-side Pinata uploads. The implementation is clean, well-documented, and maintains backward compatibility through clear deprecation notices. ✅ Strengths1. Clear Breaking Change Communication
2. Security Awareness
3. Type Safety
4. Error Handling
5. Performance Improvement
🔍 Issues & Concerns1. Security: API Key Exposure (CRITICAL)Location: While the warning comment is excellent, the example code still demonstrates an insecure pattern. Consider: // Current (insecure for production):
const pinataApiJWT = process.env.NEXT_PUBLIC_PINATA_API_JWT
// Better approach - add a comment suggesting:
// TODO: Replace with: const response = await fetch('/api/upload-to-pinata', { ... })Recommendation: Either provide a secure implementation example or add a more prominent warning that this code should NOT be deployed to production as-is. 2. Missing Error Context in Batch OperationsLocation: When uploading multiple items in parallel, if one fails, the error doesn't indicate which item failed: const uploadPromises = data.map(async (item) => {
const dataIpfs = await uploadJsonToPinata(config.pinataApiJWT, item)
if (!dataIpfs.IpfsHash || dataIpfs.IpfsHash.trim() === '') {
throw new Error('Invalid IPFS hash received from Pinata') // Which item failed?
}
return \`ipfs://\${dataIpfs.IpfsHash}\`
})Recommendation: Add context to errors: throw new Error(\`Invalid IPFS hash received from Pinata for item: \${JSON.stringify(item).slice(0, 100)}\`)3. Inconsistent Error ParsingLocations:
Question: Why does 4. Test Coverage GapThe existing test in expect(data.IpfsHash).toEqual('QmYiJdC6KbkUuKVYeuQLm3DRbaok3h6yPyJjPqas8cotqx')Missing test cases:
5. Minor: Typo FixLocation: Good catch fixing the typo from 6. Documentation FormattingThe GraphQL README.md has significant formatting changes (many are just spacing/line breaks), but the core deprecation message at line 1029 is clear. 📋 RecommendationsHigh Priority
Medium Priority
Low Priority
🧪 Test Plan StatusFrom the PR description, ensure these are tested:
📊 Overall AssessmentCode Quality: ⭐⭐⭐⭐ (4/5) ✅ Approval RecommendationAPPROVE with minor changes requested This is a well-executed migration that improves performance and reduces backend dependencies. The breaking changes are clearly communicated, and the deprecation strategy is sound. Address the security warning prominence and add error handling tests before merging to production. Review generated with assistance from Claude Code |
- Enhanced security warning in IntuitionCreateThingButton with prominent banner and detailed secure implementation guide - Added error context to batch operations including item index and data preview for easier debugging - Fixed event parsing inconsistency: changed createAtomFromIpfsUpload to use eventParseAtomCreated instead of eventParseDeposited for consistency - Added comprehensive error handling tests for Pinata integration covering non-200 responses, network errors, and malformed JSON 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Code Review: Migration to Direct Pinata UploadsSummaryThis PR migrates from backend-mediated IPFS pinning to client-side Pinata uploads. Overall, the implementation is solid and well-documented, with proper deprecation notices and comprehensive tests. However, there are several areas that need attention before merging. 🔴 Critical Issues1. Security Exposure in Example App (apps/nextjs-template/src/components/intuition/IntuitionCreateThingButton.tsx:34)const pinataApiJWT = process.env.NEXT_PUBLIC_PINATA_API_JWTIssue: While there's a warning comment, the example code directly exposes the API key in the browser. This is dangerous because:
Recommendation:
// IMPORTANT: Do NOT use NEXT_PUBLIC_ environment variables for API keys
// Implement a server-side API route instead. See documentation for details.
throw new Error('This example requires implementing a secure server-side upload endpoint')2. Missing Validation in Tests (packages/sdk/tests/external.test.ts:20-23)expect(data.IpfsHash).toEqual(
'QmYiJdC6KbkUuKVYeuQLm3DRbaok3h6yPyJjPqas8cotqx',
)Issue: This test expects a hardcoded IPFS hash, which suggests it's hitting a real API. This will fail if:
Recommendation: Mock the vi.mock('../src/external/upload-json-to-pinata', () => ({
uploadJsonToPinata: vi.fn().mockResolvedValue({
IpfsHash: 'QmYiJdC6KbkUuKVYeuQLm3DRbaok3h6yPyJjPqas8cotqx',
// ... other fields
})
}))
|
Summary
Migrates from backend-mediated IPFS pinning (via GraphQL API) to client-side Pinata uploads for improved performance and reliability. This removes the dependency on the GraphQL backend for IPFS operations, allowing SDK users to interact directly with Pinata.
Breaking Changes
createAtomFromThingnow requirespinataApiJWTin the config parameterbatchCreateAtomsFromThingsnow requirespinataApiJWTin the config parameterCreateAtomConfigWithIpfstype instead ofWriteConfigDeprecations
pinThingmutation is deprecated (useuploadJsonToPinatafrom SDK instead)pinThingfunction is deprecated (useuploadJsonToPinatainstead)Changes
uploadJsonToPinataMigration Guide
Before:
After:
Test plan
createAtomFromThingworks with Pinata JWTbatchCreateAtomsFromThingsworks with Pinata JWT🤖 Generated with Claude Code