{"_id":"@bluebillywig/bb-sapi-node-sdk","_rev":"2-d8a34376c1864cab1d37d2d4ac380f8f","name":"@bluebillywig/bb-sapi-node-sdk","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@bluebillywig/bb-sapi-node-sdk","version":"1.0.0","_id":"@bluebillywig/bb-sapi-node-sdk@1.0.0","maintainers":[{"name":"jkoppen-bluebillywig","email":"j.koppen@bluebillywig.com"},{"name":"martijnbots_bb","email":"m.bots@bluebillywig.com"},{"name":"ghultink","email":"g.hultink@bluebillywig.com"},{"name":"vvanlaar","email":"v.vanlaar@bluebillywig.com"},{"name":"p.vanderspek","email":"p.vanderspek@bluebillywig.com"}],"dist":{"shasum":"e8a21b36893e45203c00c9d1466334b77919604a","tarball":"https://registry.npmjs.org/@bluebillywig/bb-sapi-node-sdk/-/bb-sapi-node-sdk-1.0.0.tgz","fileCount":171,"integrity":"sha512-SqScba6v8OFXUvaNLegQmrOpmr388lY2W61lrxWRzCCX7Dtj+hC9dAF5cai6wpMGJtUyd/mIM5xV9PudhGa3zQ==","signatures":[{"sig":"MEQCIF1LLRG765tUIU7Y+06IrMhfGnglI8oRUG0dYZ7jgIGCAiAjJ/crUzKksc1megm9kXAAF4s6dRFvdOXoPSLd9UZ0Ew==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":147164},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"7459ce161527bfad695e1250dadfe153ff01b54e","scripts":{"test":"vitest run","build":"tsc","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"martijnbots_bb","email":"m.bots@bluebillywig.com"},"_npmVersion":"10.9.3","description":"Blue Billywig Server API SDK for Node.js","directories":{},"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^1.6.0","typescript":"^5.4.0","@types/node":"^20.0.0","@vitest/coverage-v8":"^1.6.1"},"_npmOperationalInternal":{"tmp":"tmp/bb-sapi-node-sdk_1.0.0_1774004289989_0.9144180206096537","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@bluebillywig/bb-sapi-node-sdk","version":"1.0.1","description":"Blue Billywig Server API SDK for Node.js","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsc","typecheck":"tsc --noEmit","test":"vitest run","test:coverage":"vitest run --coverage","test:watch":"vitest"},"repository":{"type":"git","url":"git+https://github.com/bluebillywig/bb-sapi-node-sdk.git"},"homepage":"https://github.com/bluebillywig/bb-sapi-node-sdk#readme","bugs":{"url":"https://github.com/bluebillywig/bb-sapi-node-sdk/issues"},"engines":{"node":">=18"},"devDependencies":{"@types/node":"^20.0.0","@vitest/coverage-v8":"^1.6.1","typescript":"^5.4.0","vitest":"^1.6.0"},"_id":"@bluebillywig/bb-sapi-node-sdk@1.0.1","gitHead":"f130155ce8afb8864bd3cb0ad8ec156dfbed68f8","_nodeVersion":"22.20.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-KLsPnaro8IBM6BCQrdCBvqp8JsaP1+J4nm4F/GlhJr8jBpGsTEfuntWqwJ2IeTBh52IDi2yUDKNGSE/qP0PV5w==","shasum":"c6f728dd01a034a8e56afd63420088047184d00b","tarball":"https://registry.npmjs.org/@bluebillywig/bb-sapi-node-sdk/-/bb-sapi-node-sdk-1.0.1.tgz","fileCount":171,"unpackedSize":147998,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDRbpNWuVEle+yc6l4fPCKpI9g468ddnkmD2XVdS+M4ngIhAPdlQw0/QbcLipG+rG5eN9JkiePrh7BxWAoriwTnpxJL"}]},"_npmUser":{"name":"martijnbots_bb","email":"m.bots@bluebillywig.com"},"directories":{},"maintainers":[{"name":"jkoppen-bluebillywig","email":"j.koppen@bluebillywig.com"},{"name":"martijnbots_bb","email":"m.bots@bluebillywig.com"},{"name":"ghultink","email":"g.hultink@bluebillywig.com"},{"name":"vvanlaar","email":"v.vanlaar@bluebillywig.com"},{"name":"p.vanderspek","email":"p.vanderspek@bluebillywig.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/bb-sapi-node-sdk_1.0.1_1774014410229_0.7285197583492684"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-20T10:58:09.921Z","modified":"2026-03-20T13:46:50.570Z","1.0.0":"2026-03-20T10:58:10.152Z","1.0.1":"2026-03-20T13:46:50.373Z"},"description":"Blue Billywig Server API SDK for Node.js","maintainers":[{"name":"jkoppen-bluebillywig","email":"j.koppen@bluebillywig.com"},{"name":"martijnbots_bb","email":"m.bots@bluebillywig.com"},{"name":"ghultink","email":"g.hultink@bluebillywig.com"},{"name":"vvanlaar","email":"v.vanlaar@bluebillywig.com"},{"name":"p.vanderspek","email":"p.vanderspek@bluebillywig.com"}],"readme":"# Blue Billywig SAPI Node.js SDK\n\nThis Node.js SDK provides abstractions to interact with the Blue Billywig Server API.\n\n## Requirements\n\n- Node.js >= 18\n- Zero runtime dependencies\n\n## Installation\n\n```bash\nnpm install @bluebillywig/bb-sapi-node-sdk\n```\n\n## Quick Start\n\n```typescript\nimport { Sdk } from '@bluebillywig/bb-sapi-node-sdk';\n\nconst sdk = Sdk.withRPCTokenAuthentication(\n  'my-publication',\n  1,              // token ID\n  'shared-secret' // shared secret\n);\n\n// List media clips\nconst response = await sdk.mediaclip.list();\nconst data = response.json();\nconsole.log(data);\n```\n\n## Authentication\n\nThe SDK uses HOTP-based RPC token authentication. You need a **token ID** and **shared secret** from your Blue Billywig publication settings.\n\n```typescript\n// Recommended: use the convenience factory\nconst sdk = Sdk.withRPCTokenAuthentication('my-publication', tokenId, sharedSecret);\n\n// Or provide a custom authenticator\nimport { Sdk, RPCTokenAuthenticator } from '@bluebillywig/bb-sapi-node-sdk';\n\nconst authenticator = new RPCTokenAuthenticator(tokenId, sharedSecret);\nconst sdk = new Sdk('my-publication', authenticator);\n```\n\n**Clock synchronization**: The RPC token is time-based (HOTP). Both client and server clocks must be reasonably synchronized (within the token expiration window, default 120 seconds). Significant clock drift will cause authentication failures.\n\n## Entities\n\nAll entities support standard CRUD operations where applicable:\n\n| Entity | List | Get | Create | Update | Delete |\n|---|---|---|---|---|---|\n| `sdk.mediaclip` | Yes | Yes | Yes | Yes | Yes |\n| `sdk.playlist` | Yes | Yes | Yes | Yes | Yes |\n| `sdk.channel` | Yes | Yes | Yes | Yes | Yes |\n| `sdk.playout` | Yes | Yes | Yes | Yes | Yes |\n| `sdk.subtitle` | Yes | Yes | Yes | Yes | Yes |\n| `sdk.thumbnail` | - | - | - | - | - |\n\n### Media Clips\n\n```typescript\n// List\nconst response = await sdk.mediaclip.list(15, 0, 'createddate desc');\n\n// Get (with optional language and job inclusion)\nconst response = await sdk.mediaclip.get(123);\nconst response = await sdk.mediaclip.get(123, 'en', false);\n\n// Create\nconst response = await sdk.mediaclip.create({ title: 'My Video' });\n\n// Update\nconst response = await sdk.mediaclip.update(123, { title: 'Updated Title' });\n\n// Delete (with optional purge)\nconst response = await sdk.mediaclip.delete(123);\nconst response = await sdk.mediaclip.delete(123, true); // purge\n```\n\n### Playlists, Channels, Playouts, Subtitles\n\n```typescript\n// All follow the same pattern\nconst response = await sdk.playlist.list();\nconst response = await sdk.playlist.get(1);\nconst response = await sdk.playlist.create({ title: 'My Playlist' });\nconst response = await sdk.playlist.update(1, { title: 'Updated' });\nconst response = await sdk.playlist.delete(1);\n```\n\n## File Uploads\n\nThe SDK supports single-chunk and multi-part streaming uploads to S3 via presigned URLs.\n\n```typescript\n// 1. Initialize the upload\nconst initResponse = await sdk.mediaclip.initializeUpload('/path/to/video.mp4');\ninitResponse.assertOk();\nconst uploadData = initResponse.json();\n\n// 2. Execute the upload (streams file data, no full-file buffering)\nconst success = await sdk.mediaclip.executeUpload('/path/to/video.mp4', uploadData);\n\n// 3. (Optional) Track upload progress\nfor await (const progress of sdk.mediaclip.uploadProgressGenerator(\n  uploadData.listPartsUrl,\n  uploadData.headObjectUrl,\n  uploadData.chunks,\n)) {\n  console.log(`Upload progress: ${progress}%`);\n}\n```\n\n## Thumbnails\n\n```typescript\n// Generate an absolute thumbnail URL with dimensions\nconst url = sdk.thumbnail.getAbsoluteImagePath('/path/to/image.jpg', 640, 360);\n// => https://my-publication.bbvms.com/image/640/360/path/to/image.jpg\n```\n\n## Response Handling\n\nAll entity methods return a `SapiResponse` object:\n\n```typescript\nconst response = await sdk.mediaclip.get(123);\n\n// Check status\nif (response.ok) {\n  const data = response.json();\n}\n\n// Or assert (throws on non-2xx)\nresponse.assertOk();\nconst data = response.json();\n\n// Access response details\nresponse.statusCode;           // e.g. 200\nresponse.body;                 // raw body string\nresponse.header('Content-Type');\nresponse.queryParam('limit');  // query param from the request URL\nresponse.statusCategory;       // HTTPStatusCodeCategory enum\n\n// Batch response utilities\nSapiResponse.allOk(responses);         // true if all 2xx\nSapiResponse.assertAllOk(responses);   // throws on first non-2xx\nSapiResponse.failedResponses(responses); // generator yielding non-2xx responses\n```\n\n## Error Handling\n\nThe SDK throws typed exceptions for HTTP errors:\n\n```typescript\nimport {\n  HTTPRequestException,\n  HTTPClientErrorException,\n  HTTPServerErrorException,\n} from '@bluebillywig/bb-sapi-node-sdk';\n\ntry {\n  const response = await sdk.mediaclip.get(999);\n  response.assertOk();\n} catch (error) {\n  if (error instanceof HTTPClientErrorException) {\n    // 4xx error\n    console.error(`Client error ${error.statusCode}: ${error.message}`);\n    console.error('Response body:', error.responseBody);\n  } else if (error instanceof HTTPServerErrorException) {\n    // 5xx error\n    console.error(`Server error ${error.statusCode}: ${error.message}`);\n  }\n}\n```\n\n## Configuration\n\n```typescript\nconst sdk = Sdk.withRPCTokenAuthentication('my-publication', tokenId, sharedSecret, {\n  // Override the base URI (useful for testing or custom deployments)\n  baseUri: 'https://custom-host.example.com',\n\n  // Inject a custom fetch implementation (useful for testing)\n  fetch: customFetchFn,\n});\n```\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Type check\nnpm run typecheck\n\n# Run tests\nnpm test\n\n# Build\nnpm run build\n```\n","readmeFilename":"README.md","homepage":"https://github.com/bluebillywig/bb-sapi-node-sdk#readme","repository":{"type":"git","url":"git+https://github.com/bluebillywig/bb-sapi-node-sdk.git"},"bugs":{"url":"https://github.com/bluebillywig/bb-sapi-node-sdk/issues"}}