@audiotool/nexus - v0.0.17
    Preparing search index...

    Type Alias SamplesAPI

    High-level API for working with samples. Handles the complexity of uploads, downloads, and metadata management.

    const upload = await at.samples.upload({
    file: audioFile,
    displayName: "My Kick Drum",
    }, signal)

    // Metadata available immediately
    console.log("Created:", upload.name)

    // Wait until the sample is ready to play with download URLs
    const sample = await upload.ready
    if (!(sample instanceof Error)) {
    console.log("Download URL:", sample.wavUrl)
    }
    const file = await at.samples.download("samples/abc-123", { format: "wav" })
    if (!(file instanceof Error)) {
    // Use the audio file
    }
    const result = await at.samples.list({
    textSearch: "kick drum",
    pageSize: 10,
    })
    for (const sample of result.samples) {
    console.log(sample.displayName)
    }
    type SamplesAPI = {
        delete: (
            sample: string | SampleMeta,
            signal?: AbortSignal,
        ) => Promise<void | Error>;
        download: (
            sample: string | SampleMeta,
            options?: { format?: SampleFormat },
            signal?: AbortSignal,
        ) => Promise<Blob | Error>;
        get: (
            sample: string | SampleMeta | NexusEntity<"sample">,
            signal?: AbortSignal,
        ) => Promise<SampleMeta | Error>;
        list: (
            options?: SampleListOptions,
            signal?: AbortSignal,
        ) => Promise<SampleListResult | Error>;
        upload: (
            options: SampleUploadOptions,
            signal?: AbortSignal,
        ) => Promise<SampleUpload | Error>;
    }
    Index

    Properties

    delete: (
        sample: string | SampleMeta,
        signal?: AbortSignal,
    ) => Promise<void | Error>

    Delete a sample.

    A sample can only be deleted if:

    • The user owns the sample
    • The sample is not currently used in any project

    Type declaration

    download: (
        sample: string | SampleMeta,
        options?: { format?: SampleFormat },
        signal?: AbortSignal,
    ) => Promise<Blob | Error>

    Download a sample's audio file.

    If the sample is still processing, this will wait until it's ready.

    Type declaration

    const blob = await at.samples.download(sample, { format: "wav" })
    if (!(blob instanceof Error)) {
    const url = URL.createObjectURL(blob)
    audio.src = url
    }
    get: (
        sample: string | SampleMeta | NexusEntity<"sample">,
        signal?: AbortSignal,
    ) => Promise<SampleMeta | Error>

    Get metadata for a single sample.

    Type declaration

    list: (
        options?: SampleListOptions,
        signal?: AbortSignal,
    ) => Promise<SampleListResult | Error>

    List samples with optional filtering and pagination.

    Type declaration

    let result = await at.samples.list({ pageSize: 20 })
    while (result.samples.length > 0) {
    for (const sample of result.samples) {
    console.log(sample.displayName)
    }
    if (!result.nextPageToken) break
    result = await at.samples.list({ pageToken: result.nextPageToken })
    }
    upload: (
        options: SampleUploadOptions,
        signal?: AbortSignal,
    ) => Promise<SampleUpload | Error>

    Upload a new sample. Returns immediately with pending metadata and a promise that resolves when processing completes.

    The upload flow:

    1. Creates sample metadata on the server
    2. Uploads the audio file to cloud storage
    3. Signals the server to begin processing
    4. Waits for transcoding to complete

    Important: If you stop uploading a file without proper cleanup, your user will have their rate limit reduced by 1 slot until the upload is cancelled automatically, which happens only within 24 hours.

    Make sure that you either wait for an upload to complete, or cancel the upload.

    In browsers: Pass preventTabClose: true to prompt the user with a confirmation dialog if they try to close the tab while the upload is in progress.

    In Node.js/Bun/Deno: There's no automatic cleanup mechanism. You should handle process signals yourself:

    const controller = new AbortController()
    process.on("SIGINT", () => controller.abort())
    process.on("SIGTERM", () => controller.abort())

    const upload = await at.samples.upload({
    file: audioBuffer,
    displayName: "My Sample",
    }, controller.signal)

    Type declaration

    const upload = await at.samples.upload({
    file: audioFile,
    displayName: "My Sample",
    })
    if (upload instanceof Error) throw upload

    // Wait until bytes are safely on the server.
    const err = await upload.uploaded
    if (err instanceof Error) throw err

    You can insert a sample into a document before upload.ready resolves by decoding local audio duration and passing a plain object to document.TransactionBuilder.insertSample. If that object omits bpm, the project BPM from config is used (fallback 120 if no config exists).

    async function readLocalDurationSeconds(file: Blob): Promise<number> {
    const context = new AudioContext()
    try {
    const decoded = await context.decodeAudioData(await file.arrayBuffer())
    return decoded.duration
    } finally {
    await context.close()
    }
    }

    const upload = await at.samples.upload({ file, displayName: "My Sample", bpm: 120 })
    if (upload instanceof Error) throw upload

    const durationSeconds = await readLocalDurationSeconds(file)
    await nexus.modify(t => {
    t.insertSample({
    name: upload.name,
    durationSeconds,
    // bpm optional
    })
    })
    const upload = await at.samples.upload({
    file: audioFile,
    displayName: "My Sample",
    preventTabClose: true, // User will be prompted before leaving
    })
    await upload.uploaded