Docs do Nodaro
DocumentaçãoReferência de nósModelosAgentes de IA (MCP)DesenvolvedoresSelf-hostingPesquisa
SDK para TypeScript

Produções do Studio

Em TypeScript, crie produções do Studio com um plano, edite-as com operações, gere imagens e clipes, revise quadros planejados, compartilhe-as ou copie-as.

Disponível em Nodaro Cloud

Uma produção do Studio é um workflow do Nodaro cujas configurações guardam as tomadas de um filme. Cada tomada tem uma imagem fixa enquadrada, um clipe animado opcional e o plano, os visuais, os vínculos de elenco e a voz que os geraram. client.studio lê e grava produções, então um script, um assistente de IA e o app Studio trabalham em uma mesma produção. client.shots armazena os registros compartilhados de tomadas por trás dos links de compartilhamento. Os métodos chamam a API REST de produções do Studio. Veja Produções do Studio pelo MCP para o guia de criação.

As produções do Studio são executadas no Nodaro Cloud. Onde as rotas não são servidas, todos os métodos lançam NotFoundError. Para verificar uma vez, chame client.studio.productions.list(): uma implantação com produções responde com uma página vazia, e uma sem elas lança NotFoundError.

Dois conjuntos de métodos

client.studio tem duas camadas. As duas trabalham nas mesmas produções.

CamadaUse paraRetorna
client.studio.productions.*O documento da produção: criar a partir de um plano, editar com operações, gerar imagens fixas e clipes, adicionar voz e música, compartilhar e copiarO próprio payload
client.studio.*Quadros planejados: recursos disponíveis, geração e revisão de quadros-chave, pacotes, salvamentos do editor e compartilhamento por link com verificação de revisãoO envelope { data } da API

Os envelopes são tipados; o documento da produção não é. Uma produção, uma tomada e uma operação são JSON aberto, Record<string, unknown>. Tudo o que você usa para decidir o fluxo é tipado: version, rebased, receipts, warnings, os credits de uma cotação e os jobIds de uma execução. O vocabulário de operações vem do servidor: leia-o em skill().

Métodos de client.studio.productions

MétodoO que faz
skill()Lê o guia de criação, o catálogo, o esquema do plano e o guia de operação
validatePlan(plan)Verifica um plano, de graça
list(opts?)Lista as suas produções
get(productionId, opts?)Lê uma produção
exportPlan(productionId, opts?)Planeja os passos de exportação e calcula o preço deles
create(input?)Cria uma produção, opcionalmente a partir de um plano
ops(productionId, input)Aplica, ou pré-visualiza, um lote de operações
reconcile(productionId)Incorpora as gerações concluídas
importPlan(productionId, plan, opts?)Adiciona as cenas de um plano a uma produção
describe(productionId, input)Transforma um briefing em cenas
generate(), generateStill(), generateClip()Enquadra ou anima uma tomada
frame(productionId, input)Extrai uma imagem fixa do clipe de uma tomada
voice(productionId, input)Gera a fala de uma tomada
revoice(productionId, input)Troca as vozes do clipe de uma tomada
music(productionId, input)Cria a trilha sonora do filme
share(), unshare(), clone()Abre ou fecha o link de compartilhamento, ou copia a produção

client.studio.productions

productions.skill()

Retorna o guia de criação, o catálogo completo, o JSON Schema do plano e o guia de operação, gerados a partir da versão que roda no servidor. É gratuito.

skill(): Promise<{ skill: string; catalog: string; schema: Record<string, unknown>; operating: string; generatedFrom: object }>
const { skill, schema, operating } = await client.studio.productions.skill()

operating lista as operações que ops() aceita. Leia-o em tempo de execução em vez de fixar o vocabulário no código.

productions.validatePlan(plan)

Verifica um plano antes que ele vire uma produção. É gratuito, não armazena nada e resolve os nomes do elenco com base na sua biblioteca. Corrija os errors e valide de novo até valid ser true; depois, chame create({ plan }).

validatePlan(plan: Record<string, unknown>): Promise<{
  valid: boolean
  errors: Array<{ path: string; message: string; hint?: string }>
  warnings: Array<{ path: string; message: string; hint?: string }>
  summary?: { name?: string; scenes: number; shots: number; cast: number; bound: number }
}>

Prop

Type

const check = await client.studio.productions.validatePlan(plan)
if (!check.valid) console.log(check.errors)

summary.bound conta as entradas do elenco que corresponderam a um personagem da sua biblioteca.

productions.list(opts?)

Lista as suas produções, das mais recentes para as mais antigas.

list(opts?: { limit?: number; cursor?: string; includeArchived?: boolean }): Promise<{ data: StudioProduction[]; nextCursor?: string }>

Prop

Type

const { data: productions } = await client.studio.productions.list({ limit: 20 })

productions.get(productionId, opts?)

Lê uma produção. É uma leitura pura e nunca incorpora um job concluído, então chame reconcile() antes quando estiver esperando por um.

get(productionId: string, opts?: { detail?: "summary" | "full"; shotId?: string }): Promise<StudioProduction>

Prop

Type

const production = await client.studio.productions.get(productionId, { detail: "full" })

productions.exportPlan(productionId, opts?)

Retorna os passos ordenados que montam o filme, com os preços deles. Não executa nada e não gasta nada: execute os passos você mesmo com os métodos comuns de nós.

exportPlan(productionId: string, opts?: { upscale?: boolean }): Promise<{
  canExport: boolean
  steps: Array<{ id: string; label: string; node: string; creditModel: string; credits: number | null; params: Record<string, unknown> }>
  resultStepId: string | null
  estimate: number | null
  unpriced: string[]
}>

Prop

Type

const plan = await client.studio.productions.exportPlan(productionId)
console.log(plan.canExport, plan.estimate)
for (const step of plan.steps) console.log(step.id, step.label, step.node, step.credits)

canExport é false quando a produção tem menos de dois clipes. estimate é null quando algum passo não tem preço, porque uma soma parcial subestimaria o custo, e unpriced indica os modelos desses passos. O node de cada passo é um tipo de nó, como merge-video-audio, combine-videos ou video-upscale.

productions.create(input?)

Cria uma produção e, opcionalmente, incorpora um plano na mesma chamada.

create(input?: { name?: string; plan?: Record<string, unknown> }): Promise<{
  production: StudioProduction
  warnings?: Array<{ path: string; message: string; hint?: string }>
  summary?: { shotsAdded: number; castEnrolled: number; castBound: number }
}>

Prop

Type

const { production, summary } = await client.studio.productions.create({ name: "Rome chase", plan })

productions.ops(productionId, input)

Aplica um lote de operações a uma produção. Toda alteração é uma operação, endereçada por uma chave estável, como o ID de uma tomada, o slug de um papel ou o ID do job de um resultado, nunca pela posição.

ops(productionId: string, input: StudioOpsRequest): Promise<StudioOpsResponse>
ops(productionId: string, input: StudioOpsRequest & { dryRun: true }): Promise<StudioOpsDryRunResponse>

Prop

Type

const result = await client.studio.productions.ops(productionId, {
  ops: [/* operations from the operating guide */],
  baseVersion: version,
  clientRequestId: crypto.randomUUID(),
})
version = result.version // carry it forward as the next baseVersion
for (const r of result.receipts) console.log(r.summary)
  • Atômico. Uma operação inválida recusa o lote inteiro com um StudioOpError cujo opIndex a identifica, e nada é gravado.
  • Rebase automático. Duas pessoas podem editar uma produção ao mesmo tempo. Um lote montado sobre uma versão mais antiga continua sendo aplicado à mais recente, e rebased é true.
  • Recibos. receipts tem uma linha no pretérito por operação, como “Deleted take 2 of Shot 1 (in the bin)”. Quando o efeito de uma operação vai além do que ela nomeia, o impact dela lista os keyframeIds e os shotIds a atualizar.
  • Adote a resposta. Substitua a sua cópia por production e leve version adiante. Não mescle a resposta com a sua cópia antiga.

Pré-visualize um lote. Com dryRun: true, a resposta diz o que o lote faria, para que uma pessoa possa aprovar antes as edições de um assistente. Ela tem dryRun, version, receipts e warnings, e nenhuma production. Cada recibo adiciona class: S seguro, D exclui, P muda quem pode acessar o trabalho, $ gasta créditos. Ele também adiciona restorable, que só está presente quando a operação colocou algo na lixeira. Leia-o como restorable ?? false.

Escreva dryRun: true como um literal no próprio objeto da chamada. Passado por uma variável, ele se amplia para boolean, e a chamada é tipada como uma aplicação, embora continue sendo uma prévia.

Uma prévia envia duas requisições: primeiro um lote vazio que comprova que a implantação consegue pré-visualizar, depois o seu lote. Caso contrário, uma implantação que não consegue pré-visualizar aplicaria o seu lote sem avisar. Dois erros podem ocorrer:

import { StudioPreviewAppliedError, StudioPreviewUnavailable } from "@nodaro/sdk"

try {
  const preview = await client.studio.productions.ops(productionId, { ops, baseVersion, dryRun: true })
  for (const r of preview.receipts) console.log(r.class, r.summary, r.restorable ?? false)
} catch (err) {
  if (err instanceof StudioPreviewUnavailable) {
    // Nothing was sent. Say that no preview is available; do not apply the batch instead.
  } else if (err instanceof StudioPreviewAppliedError) {
    // The batch was applied. Adopt err.applied.production and err.applied.version.
    // Do not send it again. When err.applied is undefined, read the production first.
  } else {
    throw err
  }
}

productions.reconcile(productionId)

Incorpora todas as gerações que terminaram desde a última vez que você verificou e informa o que ainda está em execução. É a única chamada que transforma jobs concluídos em resultados sem o app aberto, e ela só grava quando algo foi incorporado.

reconcile(productionId: string): Promise<{
  landed: string[]
  pending: string[]
  failed: string[]
  warnings: string[]
  production: StudioProduction
  version: number
}>

Prop

Type

const { landed, pending } = await client.studio.productions.reconcile(productionId)

landed lista os jobs cuja mídia já está na produção, pending os jobs ainda em execução e failed os jobs que falharam ou foram cancelados.

productions.importPlan(productionId, plan, opts?)

Adiciona as cenas de um plano a uma produção existente.

importPlan(productionId: string, plan: Record<string, unknown>, opts?: { mode?: "append" }): Promise<{
  production: StudioProduction
  warnings?: Array<{ path: string; message: string; hint?: string }>
  summary?: { shotsAdded: number; castEnrolled: number; castBound: number }
}>

Prop

Type

await client.studio.productions.importPlan(productionId, extraScenesPlan)

productions.describe(productionId, input)

Transforma um briefing em cenas com o Diretor. Inicia um job e retorna imediatamente; as cenas são incorporadas por reconcile(). A produção volta com a execução registrada como um rascunho pendente.

describe(productionId: string, input: {
  brief: string
  llmModel: string
  mode?: "append" | "replace"
  label?: string
  clientRequestId?: string
}): Promise<{ production: StudioProduction; jobId: string }>

Prop

Type

const { jobId } = await client.studio.productions.describe(productionId, {
  brief: "A courier races across Rome in the rain to deliver a violin.",
  llmModel,
})

Gerar imagens fixas e clipes

generateStill() enquadra uma tomada, generateClip() a anima e generate() faz uma coisa ou outra conforme kind. Uma execução envia os jobs, registra um marcador pendente na produção e retorna: nada fica esperando por minutos. A requisição é montada no servidor a partir do próprio plano, dos visuais e das referências da tomada, então um script e um clique no app produzem a mesma mídia.

generate(productionId: string, input: StudioGenerateRequest): Promise<StudioGenerateResult>
generateStill(productionId: string, shotId: string, opts?: StudioGenerateOptions): Promise<StudioGenerateResult>
generateClip(productionId: string, shotId: string, opts?: StudioGenerateOptions): Promise<StudioGenerateResult>

Prop

Type

import { isStudioGenerateEstimate } from "@nodaro/sdk"

const quote = await client.studio.productions.generateStill(productionId, "shot-2", { count: 2, dryRun: true })
if (isStudioGenerateEstimate(quote)) console.log(quote.credits) // null means unpriced, not free

const run = await client.studio.productions.generateStill(productionId, "shot-2", {
  count: 2,
  clientRequestId: crypto.randomUUID(),
})
  • Faça a cotação antes. dryRun: true calcula o preço da execução e não grava nada. Restrinja o tipo da resposta com isStudioGenerateEstimate().
  • Repita com segurança. Com o mesmo clientRequestId, uma nova tentativa responde com os jobs que a primeira chamada iniciou, marcados com deduped: true, e não envia nem cobra nada. Nunca repita uma chamada paga sem ele. Todas as chamadas pagas desta página o aceitam, incluindo frame() e voice().
  • A via é escolhida para você. Para um clipe, a rota de vídeo é escolhida a partir das entradas da tomada e retornada como lane: generate-video ou text-to-video.

productions.frame(productionId, input)

Extrai uma imagem fixa do clipe ativo de uma tomada e a coloca onde target indica. Espera pelo job, que leva segundos, e retorna a produção alterada e a url da imagem.

frame(productionId: string, input: {
  shotId: string
  mode?: "first" | "last" | "timestamp"
  timestamp?: number
  target?: "new-shot" | "start-frame" | "end-frame" | "still"
  clientRequestId?: string
}): Promise<StudioMediaResponse>

Prop

Type

const { url } = await client.studio.productions.frame(productionId, { shotId: "shot-2", mode: "last" })

productions.voice(productionId, input)

Gera a fala de uma tomada e a registra na tomada. Espera pelo job.

voice(productionId: string, input: {
  shotId: string
  text: string
  voiceId?: string
  voiceType?: "premade" | "custom" | "library"
  ttsProvider?: string
  delivery?: Record<string, number>
  clientRequestId?: string
}): Promise<StudioMediaResponse>

Prop

Type

await client.studio.productions.voice(productionId, { shotId: "shot-3", text: "We're out of time." })

productions.revoice(productionId, input)

Troca as vozes do clipe ativo de uma tomada. Leva minutos, então retorna um jobId, e o novo clipe é incorporado pelo marcador dele.

revoice(productionId: string, input: { shotId: string; plan: Record<string, unknown>; clientRequestId?: string }): Promise<{ production: StudioProduction; jobId: string }>

Prop

Type

const { jobId } = await client.studio.productions.revoice(productionId, {
  shotId: "shot-3",
  plan: recastPlan, // the speaker-ordered plan the voice recast route takes
})

productions.music(productionId, input)

Cria a trilha sonora do filme. A faixa pronta é incorporada pelo marcador pendente dela.

music(productionId: string, input: {
  prompt: string
  duration?: number
  instrumental?: boolean
  vocalGender?: string
  model?: string
  clientRequestId?: string
}): Promise<{ production: StudioProduction; jobId: string }>

Prop

Type

const { jobId } = await client.studio.productions.music(productionId, {
  prompt: "Tense strings building to a chase",
  instrumental: true,
})

Compartilhar e copiar

share() abre a visualização por link e unshare() a fecha de novo. Compartilhar é uma chamada própria, nunca uma operação, então quem pode ver o trabalho nunca muda como efeito colateral de uma edição. clone() copia uma produção que é sua ou que você pode ver para o seu próprio projeto do Studio.

share(productionId: string): Promise<StudioProduction>
unshare(productionId: string): Promise<StudioProduction>
clone(productionId: string, input?: { name?: string }): Promise<StudioProduction>

Prop

Type

await client.studio.productions.share(productionId)
const copy = await client.studio.productions.clone(productionId, { name: "Rome chase, take 2" })

Uma cópia começa privada e não arquivada: o compartilhamento e o arquivamento nunca são copiados. Ela é copiada pela sua visão da origem, então a lixeira de outra pessoa não vem junto.

client.studio: quadros planejados

Estes métodos cobrem os quadros-chave planejados e a revisão deles. Verifique capabilities() antes de oferecer um controle, e chame reconcile() uma vez ao reabrir uma produção, porque a resposta de um envio pode ter se perdido. Nada aqui inicia uma geração ou aceita um candidato, a menos que você chame o método que faz isso.

MétodoO que faz
capabilities()Lê as versões do plano e as operações que esta implantação aceita
skill(), list(), validatePlan(), create()As mesmas leituras e a mesma criação da camada de produções, no envelope
get(id, options?)Lê uma produção com os recursos dela
edit(id, input)Aplica operações com condições de revisão
saveEditorState(id, input)Salva campos comuns do editor com base na revisão carregada
generateKeyframe(id, input)Gera um quadro planejado, sem aceitá-lo
generateShot(id, input)Faz a cotação ou envia uma imagem fixa ou um clipe
acceptKeyframe(id, review, concurrency?)Aceita um candidato revisado
reconcile(id)Registra jobs concluídos, sem aceitar nada
setShared(id, input)Compartilha ou deixa de compartilhar, vinculado à revisão que você conferiu
clone(id, input?)Copia uma produção salva
importBundle(input)Importa uma produção portátil
appendBundle(id, input)Anexa um pacote a uma produção

studio.capabilities()

Retorna as versões do plano e quais operações de quadros planejados esta implantação aceita.

capabilities(): Promise<{ data: StudioProductionCapabilities }>
const { data: caps } = await client.studio.capabilities()
if (caps.operations.generateKeyframes) showGenerateFrameButton()

operations tem uma flag por operação, como readKeyframes, editKeyframes, generateKeyframes, acceptKeyframes, rejectKeyframes, editSequencePlans, generateLinkedClips, retakeLinkedClips, saveEditorState, revisionedSharing, editableSharedCopies, cloneLinkedProductions, importPlannedBundles, importLinkedBundles, appendPlannedBundles e appendLinkedBundles. automaticAcceptance e unattendedGeneration são sempre false.

studio.skill(), list(), validatePlan() e create()

As mesmas chamadas que productions.skill(), list(), validatePlan() e create(), retornadas no envelope { data }. Em list(), as linhas ficam em response.data.data.

skill(): Promise<{ data: Record<string, unknown> }>
list(options?: { limit?: number; cursor?: string; includeArchived?: boolean }): Promise<{ data: {
  data: Array<{ id: string; name: string; version: number; updatedAt: string; thumbnailUrl: string | null; shared: boolean; archived: boolean; shotCount: number }>
  nextCursor?: string
} }>
validatePlan(plan: Record<string, unknown>): Promise<{ data: { valid: boolean; errors: object[]; warnings: object[]; summary?: object } }>
create(input: { name?: string; plan?: Record<string, unknown> }): Promise<{ data: StudioProductionReply }>

Prop

Type

const { data: page } = await client.studio.list({ limit: 20 })
for (const row of page.data) console.log(row.name, row.shotCount)

studio.get(id, options?)

Lê uma produção com os recursos dela. Nunca incorpora jobs.

get(id: string, options?: { detail?: "summary" | "full"; shotId?: string }): Promise<{ data: StudioProductionReply }>

Prop

Type

const { data: { production } } = await client.studio.get(productionId, { detail: "full" })
const frame = production.keyframes?.[0] // { id, label, revision, previewUrl, acceptedUrl, pending, ... }

studio.edit(id, input)

Aplica operações com condições de revisão (POST .../:id/ops), no envelope. Use uma baseVersion estrita para remove_shot, restore_trashed e purge_trashed, e desvincule um segmento de sequência vinculado antes de remover a cena dele.

edit(id: string, input: { ops: Array<{ op: string; [field: string]: unknown }>; baseVersion?: number; strict?: boolean; clientRequestId?: string }): Promise<{ data: StudioProductionReply & { version: number; rebased: boolean; receipts: object[] } }>

Prop

Type

await client.studio.edit(productionId, {
  ops: [{ op: "reject_keyframe_result", keyframeId, expectedRevision, resultKey, expectedAcceptedResultKey, reason: "Face drifted" }],
  baseVersion: version,
  strict: true,
})

Algumas operações de quadros planejados enviadas por edit():

  • reject_keyframe_result registra Needs revision sem gerar nada. Exige operations.rejectKeyframes.
  • update_sequence_plan edita os segmentos ordenados de uma sequência, cada um { shotId, startKeyframeId, endKeyframeId }, e mantém os IDs das cenas. Exige operations.editSequencePlans.
  • detach_sequence_segment torna um segmento independente, com mode definido como clear ou keep-accepted. Exige operations.editSequencePlans.
  • purge_trashed esvazia as entradas da lixeira que você mostra, e clear_trash esvazia todas as lixeiras, incluindo as dos quadros planejados.

studio.saveEditorState(id, input)

Salva campos comuns do editor com base na revisão que você carregou. Verifique operations.saveEditorState antes. O salvamento é sempre estrito: um conflito falha com um 409, então mantenha o rascunho local e recarregue antes de resolver o conflito.

saveEditorState(id: string, input: { expectedVersion: number; graph: object; clientRequestId?: string })

Prop

Type

await client.studio.saveEditorState(productionId, { expectedVersion: version, graph })

O salvamento não pode alterar planos de quadros, aceitação, vínculos de extremidade, histórico de jobs, entradas protegidas da lixeira nem compartilhamento. Use as ações próprias de cada um.

studio.generateKeyframe(id, input)

Gera um quadro planejado sem aceitá-lo. Não há simulação (dry run) para quadros.

generateKeyframe(id: string, input: { keyframeId: string; expectedRevision: number; clientRequestId?: string; overrides?: Record<string, unknown> }): Promise<{ data: { jobIds: string[]; deduped?: true; lane?: string } }>

Prop

Type

const { data: caps } = await client.studio.capabilities()
const { data: { production } } = await client.studio.get(productionId, { detail: "full" })
const frame = production.keyframes?.[0]

if (frame && caps.operations.generateKeyframes) {
  const { data: generation } = await client.studio.generateKeyframe(productionId, {
    keyframeId: frame.id,
    expectedRevision: frame.revision,
    clientRequestId: crypto.randomUUID(),
  })
  // follow generation.jobIds with client.jobs, then call reconcile()
}

Gerar não aceita um candidato e não cria um retrato de personagem. Uma referência de elenco que tem só uma descrição não precisa de retrato.

studio.generateShot(id, input)

Faz a cotação ou envia uma imagem fixa ou um clipe para uma tomada.

generateShot(id: string, input: StudioShotGenerationInput): Promise<{ data: StudioGenerationReply }>

Prop

Type

const { data: quote } = await client.studio.generateShot(productionId, { kind: "clip", shotId, dryRun: true })
if ("inputHash" in quote) {
  await client.studio.generateShot(productionId, {
    kind: "clip",
    shotId,
    expectedInputHash: quote.inputHash,
    clientRequestId: crypto.randomUUID(),
  })
}

Clipes vinculados. A cotação de um clipe entre quadros planejados inclui inputHash, os endpointPins aceitos, as configurações normalizadas de duração, resolução, proporção e som, e o creditIdentifier usado no preço. Passe o inputHash conferido como expectedInputHash. Se as configurações ou os quadros aceitos mudaram desde a cotação, a chamada falha com 409 sequence_quote_changed antes de enviar qualquer coisa; peça uma nova cotação. Os créditos de uma cotação são uma estimativa: a geração reserva o preço atual.

Refações. Quando operations.retakeLinkedClips é true, passe retakeResultKey com kind: "clip" e shotId, e faça a cotação com dryRun: true. Envie com o expectedInputHash conferido e um novo clientRequestId, e deixe de fora mode, overrides e count. Uma refação reutiliza a requisição original e as imagens de quadro guardadas, mesmo depois que o plano ou a aceitação mudaram. Os takes anteriores continuam no histórico. Um take sem uma requisição original verificável ou sem imagens guardadas é recusado, e uma refação não reproduz os mesmos bytes de vídeo.

studio.acceptKeyframe(id, review, concurrency?)

Aceita um candidato revisado para um quadro planejado. É um passo separado e explícito: a geração nunca o chama.

acceptKeyframe(id: string, review: StudioKeyframeAcceptanceInput, concurrency?: { baseVersion?: number; strict?: boolean; clientRequestId?: string })

Prop

Type

await client.studio.acceptKeyframe(productionId, {
  keyframeId: frame.id,
  expectedRevision: frame.revision,
  resultKey,
  expectedAcceptedResultKey: frame.acceptedResultKey,
  requirementChecks, // one { requirementId, outcome } per requirement of the frame
})

Um conflito lança o erro de sempre. O SDK nunca escolhe outro resultado nem tenta de novo com uma revisão mais recente por conta própria.

studio.reconcile(id)

Registra jobs concluídos, sem aceitar nenhum candidato e sem iniciar uma geração. Também verifica jobs de cenas na lixeira: um clipe concluído fica no grafo armazenado dessa cena, e você o recupera com restore_trashed.

reconcile(id: string): Promise<{ data: StudioProductionReply & { landed: string[]; pending: string[]; failed: string[]; version: number } }>

Prop

Type

const { data } = await client.studio.reconcile(productionId)
console.log(data.landed, data.pending)

studio.setShared(id, input)

Compartilha uma produção ou deixa de compartilhá-la, vinculado à revisão que você conferiu. Verifique operations.revisionedSharing e passe expectedVersion: uma edição simultânea então falha com 409 workflow_conflict, e o SDK não tenta de novo. Só quem pode alterar a visibilidade pode usar este método.

setShared(id: string, input: { shared: boolean; allowEditableCopy?: boolean; expectedVersion?: number }): Promise<{ data: StudioProductionReply }>

Prop

Type

await client.studio.setShared(productionId, { shared: true, allowEditableCopy: true, expectedVersion: version })

Com allowEditableCopy, um proprietário ou administrador do espaço de trabalho permite que quem vê o link copie o plano salvo, os prompts, as descrições do elenco, as entradas de referência guardadas e o histórico de takes. A lixeira e as notas de revisão privadas nunca vêm junto. As cópias começam privadas, sem nenhum quadro aceito. Desativar a cópia, ou deixar de compartilhar, bloqueia novas cópias; as cópias já feitas continuam independentes.

studio.clone(id, input?)

Copia uma produção salva. Verifique operations.cloneLinkedProductions antes de copiar uma produção com quadros vinculados, e passe a expectedVersion dela que você carregou: uma origem alterada falha com um 409.

clone(id: string, input?: { name?: string; projectId?: string; expectedVersion?: number }): Promise<{ data: StudioProductionReply }>

Prop

Type

const { data: { production: copy } } = await client.studio.clone(productionId, {
  name: "Rome chase copy",
  expectedVersion: version,
})

A cópia começa privada. Ela mantém as entradas dos quadros, que contam no seu armazenamento, recebe novos IDs de quadros, cenas e sequências e não traz jobs em execução nem quadros aceitos. Revise e aceite os quadros dela antes de gerar mídia que dependa deles. Copiar não envia nenhuma geração.

studio.importBundle(input)

Importa uma produção portátil como uma nova produção privada, com novos IDs de cenas, quadros e sequências (POST .../import-bundle). Verifique operations.importPlannedBundles para receitas e planos sem mídia, e importLinkedBundles para pacotes com mídia de quadros guardada.

importBundle(input: { bundle: Record<string, unknown>; projectId?: string }): Promise<{ data: StudioProductionReply }>

Prop

Type

const { data: { production } } = await client.studio.importBundle({ bundle })

Um pacote vinculado indica a produção de origem dele; o servidor verifica se ela é sua e confere cada imagem guardada antes de copiar qualquer coisa. Falta de acesso ou procedência forjada recusam a importação antes de a nova produção ser criada. Nenhum dos dois tipos de importação traz aceitação ou jobs em execução, e nenhum deles gera mídia.

studio.appendBundle(id, input)

Anexa um pacote completo a uma produção editável, com novos IDs e uma verificação exata de revisão (POST .../:id/import-bundle). Um token OAuth precisa de workflows:write, e você precisa de acesso de edição à produção. Verifique appendPlannedBundles ou appendLinkedBundles antes.

appendBundle(id: string, input: { bundle: Record<string, unknown>; expectedVersion: number; afterShotId?: string; applyFilm?: boolean }): Promise<{
  data: { production: StudioProductionRecord; importedShotIds: string[]; importedKeyframeIds: string[] }
}>

Prop

Type

const { data } = await client.studio.appendBundle(productionId, { bundle, expectedVersion: version })
console.log(data.importedShotIds)

As cenas, os quadros, os jobs, o compartilhamento e as outras configurações existentes continuam como estão; os papéis de elenco importados são mesclados. Os quadros importados precisam ser aceitos de novo. Um afterShotId desconhecido ou uma expectedVersion desatualizada fazem a chamada falhar.

client.shots

Registros de tomadas por trás dos links de compartilhamento /s/:id, para o Share and Remix. Uma tomada guarda o estado de um construtor: as escolhas dos seletores, os prompts, os modelos de destino, as referências de menções @ e as URLs dos resultados. Esse estado fica sob um ID de 12 caracteres impossível de adivinhar, que também é a chave de compartilhamento. As tomadas são privadas por padrão; compartilhar é uma mudança de visibilidade que você faz.

create(input?: CreateShotInput): Promise<{ id: string }>
get(id: string): Promise<{ shot: Shot }>
update(id: string, input: UpdateShotInput): Promise<{ shot: Shot }>
delete(id: string): Promise<void>

Prop

Type

const { id } = await client.shots.create({ mode: "single", freeText: "A lighthouse in a storm", models: ["nano-banana-2"] })
await client.shots.update(id, { visibility: "public" }) // anyone with the id can now read it
const { shot } = await client.shots.get(id)

Uma tomada pública pode ser lida por qualquer pessoa que tenha o ID dela. Uma tomada privada só pode ser lida pelo proprietário, e as outras pessoas recebem NotFoundError. Só o proprietário pode atualizar ou excluir uma tomada.

Perguntas frequentes

Última atualização

Nesta página