@crispy-streaming/crispy-addon-client
v2.0.1
Published
Modern TypeScript client for the Stremio add-on protocol (v3) for Web, React Native, and Node 18+
Maintainers
Readme
@crispy-streaming/crispy-addon-client
Modern, TypeScript-first client for the Stremio add-on protocol (v3).
Based on (and API-inspired by) the upstream stremio-addon-client.
- Works in Web apps, React Native, and Node 18+.
- Promise-first API with optional callback adapter.
- Strong typed errors and transport-level cache metadata.
- ESM-first package with CJS compatibility and tree-shakable transport entrypoints.
Compatibility notes
- Errors are real
Errorinstances (AddonClientError) with string codes (for example,ERR_NOT_FOUND). detectFromURL()does not runstremio-addon-linterby default. Linting is an optional hook.stremio://andcrispy://URLs are accepted as input and normalized tohttps://.http://add-on URLs are kept as-is (no forced upgrade tohttps://).- IPFS support is provided through an HTTP gateway shim (
ipfs:///ipns://URLs are preserved astransportUrl). - Legacy transport behavior is preserved for
/stremio/v1and/stremio/v1/stremiogetendpoints.
Install
npm install @crispy-streaming/crispy-addon-clientQuick start (Web / Node)
import { detectFromURL } from "@crispy-streaming/crispy-addon-client";
const detected = await detectFromURL("https://v3-cinemeta.strem.io/manifest.json");
if (detected.addon) {
const addon = detected.addon;
const catalog = await addon.get("catalog", "movie", "top", { skip: 0 });
console.log(catalog);
}React Native usage
import { fromDescriptor } from "@crispy-streaming/crispy-addon-client";
const addon = await fromDescriptor({
manifest: {
id: "org.example.addon",
resources: ["meta"],
types: ["movie"],
},
transportUrl: "https://example.com/manifest.json",
});
const meta = await addon.get("meta", "movie", "tt0111161");Core API
AddonClient
manifest(readonly/frozen)transportUrlflags(readonly/frozen)isSupported(resource, type, id): booleanget(resource, type, id, extra?): Promise<unknown>get(resource, type, id, extra?, callback)optional callback adaptergetWithMeta(resource, type, id, extra?)to access cache metadatadestroy(): Promise<void>toDescriptor(): AddonDescriptor
Top-level functions
fromDescriptor(descriptor): Promise<AddonClient>detectFromURL(url, options?): Promise<{ addon?: AddonClient; collection?: AddonCollectionLike }>mapURL(url): stringstringifyRequest(args): string
AddonCollection
load(descriptors): Promise<void>save(): AddonDescriptor[]getAddons(): AddonClient[]add(addon): voidremove(addon): voidincludes(addon): booleanclone(): AddonCollection
Error handling
import { ERR_NOT_FOUND, isAddonClientError } from "@crispy-streaming/crispy-addon-client";
try {
await addon.get("meta", "movie", "tt123");
} catch (error) {
if (isAddonClientError(error) && error.code === ERR_NOT_FOUND) {
console.log("Resource not found");
}
}Optional lint hook for detectFromURL
import { detectFromURL } from "@crispy-streaming/crispy-addon-client";
const result = await detectFromURL("https://example.com/manifest.json", {
lint: async ({ kind, value }) => {
// Plug in stremio-addon-linter (or your own validator) here.
// Return shape: { valid: boolean, ...extraMetadata }
return { valid: true, kind, valueType: typeof value };
},
});Tree-shakable transport entrypoints
import { HttpTransport } from "@crispy-streaming/crispy-addon-client/transports/http";
import { IpfsShimTransport } from "@crispy-streaming/crispy-addon-client/transports/ipfsShim";
import { LegacyTransport } from "@crispy-streaming/crispy-addon-client/transports/legacy";Development
npm run typecheck
npm test
npm run buildLegacy code
The previous JavaScript/CommonJS implementation is kept in legacy/ for reference and parity checks.
