{"id":14971465,"url":"https://github.com/radio4000/sdk","last_synced_at":"2026-02-17T21:04:08.375Z","repository":{"id":61489965,"uuid":"551873186","full_name":"radio4000/sdk","owner":"radio4000","description":"javascript SDK to interact with radio4000 (browser \u0026 node) [supabase wrapper]","archived":false,"fork":false,"pushed_at":"2026-02-03T17:21:35.000Z","size":618,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-04T07:22:56.750Z","etag":null,"topics":["javascript","jsdocs","radio4000","supababe","supabase","typescript"],"latest_commit_sha":null,"homepage":"https://sdk.radio4000.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/radio4000.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-10-15T09:29:18.000Z","updated_at":"2026-02-03T17:21:23.000Z","dependencies_parsed_at":"2024-05-13T13:46:23.948Z","dependency_job_id":"412c3da0-5042-4d9f-8875-bfca45aac2ba","html_url":"https://github.com/radio4000/sdk","commit_stats":{"total_commits":112,"total_committers":3,"mean_commits":"37.333333333333336","dds":0.2678571428571429,"last_synced_commit":"a904d0ae1db822a1e2c63bc3569cb7c1ace022a7"},"previous_names":[],"tags_count":64,"template":false,"template_full_name":null,"purl":"pkg:github/radio4000/sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radio4000%2Fsdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radio4000%2Fsdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radio4000%2Fsdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radio4000%2Fsdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/radio4000","download_url":"https://codeload.github.com/radio4000/sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radio4000%2Fsdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29558101,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T20:52:40.164Z","status":"ssl_error","status_checked_at":"2026-02-17T20:48:10.325Z","response_time":100,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","jsdocs","radio4000","supababe","supabase","typescript"],"created_at":"2024-09-24T13:45:14.729Z","updated_at":"2026-02-17T21:04:08.336Z","avatar_url":"https://github.com/radio4000.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Publish Package to npmjs](https://github.com/radio4000/sdk/actions/workflows/publish-to-npm-registry.yml/badge.svg)](https://github.com/radio4000/sdk/actions/workflows/publish-to-npm-registry.yml)\n\n# @radio4000/sdk\n\nA JavaScript SDK to interact with [Radio4000](https://radio4000.com) via a browser or node.js.  \n\nIt offers authentication as well as full create, read, update and delete of users, channels and tracks. While the SDK has many methods, remember you can always use `sdk.supabase` directly.\n\n## Usage with a build system\n\n```js\nimport {sdk} from '@radio4000/sdk'\n\nconst {data: channels, error} = await sdk.channels.readChannels()\nif (error) throw new Error(error)\nconsole.log(channels)\n```\n\n## Browser usage via CDN\n\nThis example can be copy pasted into any HTML page. We read the latest five channels created.\n\n```html\n\u003cscript type=\"module\"\u003e\n  import {sdk} from 'https://cdn.jsdelivr.net/npm/@radio4000/sdk/+esm'\n\n  const {data: channels, error} = await sdk.channels.readChannels(5)\n  if (error) throw new Error(error.message)\n  console.log(channels.map(c =\u003e c.name))\n  // [object Array] (5) [\"Radio Oskar\",\"ko002\",\"Radio Maretto\",\"Samro\",\"Good Time Radio\"]\n\u003c/script\u003e\n```\n\nHere's another, where we sign in (use your own credentials), create a channel and a track.\n\n```html\n\u003cscript type=\"module\"\u003e\n  import {sdk} from 'https://cdn.jsdelivr.net/npm/@radio4000/sdk/+esm'\n\n  await sdk.auth.signIn({email: '', password: ''})\n\n  const {data: channel, error} = await sdk.channels.createChannel({\n    name: 'My radio',\n    slug: 'my-radio',\n    description: '...'\n  })\n\n  if (error) throw new Error(error.message)\n\n  const {data: track} = await sdk.tracks.createTrack(channel.id, {\n    url: 'http://...',\n    title: 'Artist - Title',\n    description: '...'\n  })\n\u003c/script\u003e\n```\n\n### Using your own Supabase instance\n\nThe SDK by default connects to the main PostgreSQL maintained by Radio4000 (see `.env`). You can however use whichever you like. Note that the Supabase URL + (anon) Key are public, because we have postgres row policies in place.\n\n```js\nimport {createClient} from '@supabase/supabase-js'\nimport {createSdk} from '@radio4000/sdk'\n\nconst supabase = createClient(url, key)\nconst sdk = createSdk(supabase)\n```\n\n## Contributing and development\n\nIf you'd like to help out, clone the repository, install dependencies and start the local server. The SDK itself is in the `./src` folder and the playground is in `./examples`.\n\n```shell\ngit clone git@github.com:radio4000/sdk.git radio4000-sdk\ncd radio4000-sdk\nnpm install\nnpm start\n```\n\n## Overview\n\n```\n Radio4000 SDK\n  │\n  ├── createSdk(supabaseClient) → SDK\n  │\n  ├── auth/\n  │   ├── signUp({email, password, options?}) → Promise\n  │   ├── signIn({email, password, options?}) → Promise\n  │   ├── signOut() → Promise\n  │   └── via sdk.supabase.auth:\n  │       ├── signInWithOtp({email}) → Promise (magic link)\n  │       └── signInWithOAuth({provider}) → Promise (google or facebook)\n  │\n  ├── users/\n  │   ├── readUser() → Promise\u003c{data?, error?}\u003e\n  │   └── deleteUser() → Promise\n  │\n  ├── channels/\n  │   ├── createChannel({id?, name, slug, userId?}) → Promise\u003cSupabaseResponse\u003e\n  │   ├── updateChannel(id, changes) → Promise\u003cSupabaseResponse\u003e\n  │   ├── deleteChannel(id) → Promise\n  │   ├── readChannel(slug) → Promise\u003cSupabaseResponse\u003e\n  │   ├── readChannels(limit?) → Promise\u003cSupabaseResponse\u003e\n  │   ├── readChannelTracks(slug, limit?) → Promise\u003cSupabaseResponse\u003e\n  │   ├── readUserChannels() → Promise\n  │   ├── canEditChannel(slug) → Promise\u003cBoolean\u003e\n  │   ├── createImage(file, tags?) → Promise\n  │   ├── followChannel(followerId, channelId) → Promise\u003cSupabaseResponse\u003e\n  │   ├── unfollowChannel(followerId, channelId) → Promise\u003cSupabaseResponse\u003e\n  │   ├── readFollowers(channelId) → Promise\u003cSupabaseResponse\u003e\n  │   └── readFollowings(channelId) → Promise\u003cSupabaseResponse\u003e\n  │\n  ├── tracks/\n  │   ├── createTrack(channelId, fields) → Promise\u003cSupabaseResponse\u003e\n  │   ├── updateTrack(id, changes) → Promise\u003cSupabaseResponse\u003e\n  │   ├── deleteTrack(id) → Promise\n  │   ├── readTrack(id) → Promise\u003cSupabaseResponse\u003e\n  │   └── canEditTrack(track_id) → Promise\u003cBoolean\u003e\n  │\n  ├── firebase/\n  │   ├── readChannel(slug) → Promise\u003c{data?, error?}\u003e\n  │   ├── readChannels({limit?}) → Promise\u003c{data?, error?}\u003e\n  │   ├── readTracks({channelId?, slug?}) → Promise\u003c{data?, error?}\u003e\n  │   ├── parseChannel(rawChannel) → v2Channel\n  │   └── parseTrack(rawTrack, channelId, channelSlug) → v2Track\n  │\n  ├── search/\n  │   ├── searchChannels(query, {limit?}) → Promise\u003c{data?, error?}\u003e\n  │   ├── searchTracks(query, {limit?}) → Promise\u003c{data?, error?}\u003e\n  │   └── searchAll(query, {limit?}) → Promise\u003c{data: {channels, tracks}, error?}\u003e\n  │\n  ├── browse/\n  │   ├── query({page?, limit?, table?, select?, orderBy?, orderConfig?, filters?}) → Promise\n  │   ├── supabaseOperators: Array\u003cstring\u003e\n  │   └── supabaseOperatorsTable: Object\n  │\n  ├── utils/\n  │   └── extractTokens(str) → {mentions: string[], tags: string[]}\n  │\n  └── supabase (Supabase client instance)\n\n  Almost every method returns the {data, error} format\n```\n\n### Generate types from database schema\n\n```shell\nnpx supabase login\nnpx supabase gen types typescript --project-id SUPABASE_PROJECT_ID \u003e src/database.types.ts\n```\n\n### Build system\n\nWe use [vite](https://vitejs.dev/) in library mode to bundle the project. The only reason we bundle is for usage directly in a browser environment without a bundler.\n\n- dist/sdk.js (esm, good for browsers and newer node.js after cjs legacy)\n\nOur package.json defines the `main`, `module` and `exports` fields to specify which file should be loaded in which environment. \n\n## How to release a new version\n\nCreate a new, tagged release via the github.com website UI. This will trigger our GitHub workflow and publish to npm.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fradio4000%2Fsdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fradio4000%2Fsdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fradio4000%2Fsdk/lists"}