feat(media): wave 2 integration
Composition root shared by API and worker, media job handlers on every job host, HTTP byte routes, consent re-check before bundling, and auto-fix limited to changes that keep protection. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NLSCTnhge4umMnemGXWr1w
This commit is contained in:
parent
90f18cea52
commit
b4083844ce
@ -25,10 +25,10 @@ import {
|
||||
createCloudAgentConnection,
|
||||
createConnectorStack,
|
||||
createJobReconciler,
|
||||
createMessagingContextLoader,
|
||||
createMessagingTeamChatSender,
|
||||
createMediaJobHandlers,
|
||||
createMediaServices,
|
||||
createMessagingContextLoader,
|
||||
createMessagingTeamChatSender,
|
||||
createProfileConsolidationScheduler,
|
||||
createRunExecutor,
|
||||
createRunSandbox,
|
||||
@ -94,6 +94,7 @@ import { cors } from "hono/cors";
|
||||
import type { AppEnv } from "./env.js";
|
||||
import { loadEnv } from "./env.js";
|
||||
import { mountLocalSettings } from "./local-settings.js";
|
||||
import { mountMediaHttpRoutes } from "./media-http.js";
|
||||
import {
|
||||
createMessagingInboundHandler,
|
||||
teamChatSenderCanWakeMessageRoutines,
|
||||
@ -112,7 +113,6 @@ import {
|
||||
TEAM_CHAT_STARTUP_SHUTDOWN_MS,
|
||||
} from "./team-chat-startup.js";
|
||||
import { mountTradingBotStatus } from "./trading-bot-proxy.js";
|
||||
import { mountMediaHttpRoutes } from "./media-http.js";
|
||||
import { mountVoiceHttpRoutes } from "./voice.js";
|
||||
import { mountWebhookHttpRoutes } from "./webhook.js";
|
||||
|
||||
@ -455,7 +455,9 @@ export async function createApp(
|
||||
await graphileWorkerHost.start(jobHandlers);
|
||||
}
|
||||
if (mediaJobs) {
|
||||
void mediaJobs.resume().catch((error) => getLogger().error("media ingest resume failed", error));
|
||||
void mediaJobs
|
||||
.resume()
|
||||
.catch((error) => getLogger().error("media ingest resume failed", error));
|
||||
}
|
||||
const reconciler = inMemoryJobs
|
||||
? createJobReconciler({
|
||||
|
||||
@ -10,10 +10,10 @@ import {
|
||||
createCloudAgentConnection,
|
||||
createConnectorStack,
|
||||
createJobReconciler,
|
||||
createMessagingContextLoader,
|
||||
createPostgresReconciliationLeadership,
|
||||
createMediaJobHandlers,
|
||||
createMediaServices,
|
||||
createMessagingContextLoader,
|
||||
createPostgresReconciliationLeadership,
|
||||
createProfileConsolidationScheduler,
|
||||
createRunExecutor,
|
||||
createRunSandbox,
|
||||
@ -31,9 +31,9 @@ import {
|
||||
isPipedreamEnabled,
|
||||
LocalAgentHomeStore,
|
||||
LocalArtifactStore,
|
||||
mediaConfigFromEnv,
|
||||
McpConnector,
|
||||
McpOAuthBroker,
|
||||
mediaConfigFromEnv,
|
||||
messagingEnvFromProcess,
|
||||
messagingPlatformsFromEnv,
|
||||
PiAgentRuntime,
|
||||
|
||||
@ -77,6 +77,7 @@ export * from "./mcp-oauth.js";
|
||||
export * from "./mcp-server-tool.js";
|
||||
export * from "./mcp-transport.js";
|
||||
export * from "./media-brand.js";
|
||||
export * from "./media-consent.js";
|
||||
export * from "./media-context.js";
|
||||
export * from "./media-emulator.js";
|
||||
export * from "./media-emulator-clips.js";
|
||||
@ -85,6 +86,7 @@ export * from "./media-factory.js";
|
||||
export * from "./media-ffmpeg-renderer.js";
|
||||
export * from "./media-folder-source.js";
|
||||
export * from "./media-folder-source-probe.js";
|
||||
export * from "./media-gate-autofix.js";
|
||||
export * from "./media-ingest.js";
|
||||
export { defaultMediaJobLimits, MediaJobLimiter, type MediaJobLimits } from "./media-jobs.js";
|
||||
export * from "./media-marketing.js";
|
||||
@ -103,9 +105,10 @@ export {
|
||||
MotionTemplateError,
|
||||
ResvgMotionGraphicsRenderer,
|
||||
} from "./media-motion-renderer.js";
|
||||
export * from "./media-privacy.js";
|
||||
export { PrivacyUnavailableError } from "./media-privacy-io.js";
|
||||
export * from "./media-publish.js";
|
||||
export * from "./media-publisher-bundle.js";
|
||||
export * from "./media-services.js";
|
||||
export {
|
||||
createMediaRenderHandler,
|
||||
createMediaRenderService,
|
||||
@ -113,6 +116,7 @@ export {
|
||||
pickEncoder,
|
||||
softwareEncoder,
|
||||
} from "./media-render.js";
|
||||
export * from "./media-services.js";
|
||||
export * from "./media-sidecar.js";
|
||||
export * from "./media-zip.js";
|
||||
export * from "./memory-provider-factory.js";
|
||||
|
||||
@ -8,6 +8,7 @@ import { InvalidMediaInputError, MediaStateConflictError } from "@rakazo/db";
|
||||
import { getLogger } from "@rakazo/logging";
|
||||
import { buildTrackingUrl, normalizeHashtags, uploadChecklist } from "@rakazo/media";
|
||||
import { resolveInside } from "@rakazo/media/node";
|
||||
import { assertExportConsent } from "./media-consent.js";
|
||||
import type { MediaActor, MediaMarketingService, MediaServiceDeps } from "./media-context.js";
|
||||
import type { MediaToolPaths } from "./media-folder-source-probe.js";
|
||||
import { runMediaTool } from "./media-folder-source-probe.js";
|
||||
@ -249,6 +250,8 @@ export async function buildBundle(
|
||||
const profile = profileSet.profiles.get(pub.profileId)?.profile;
|
||||
if (!profile) throw new MediaStateConflictError(`Profile ${pub.profileId} is not available`);
|
||||
const edl = plan.edl;
|
||||
// Consent is re-read here: a withdrawal after the gate passed still stops the export.
|
||||
await assertExportConsent(deps, actor, { edl, profile });
|
||||
const outputs = storedRenderOutputs(row.outputs);
|
||||
const video = outputs.find((output) => output.kind === "video");
|
||||
if (!video) throw new MediaStateConflictError("Render has no video output");
|
||||
|
||||
@ -29,6 +29,7 @@ import type {
|
||||
MediaServiceDeps,
|
||||
} from "./media-context.js";
|
||||
import { MediaToolMissingError } from "./media-folder-source-probe.js";
|
||||
import { nonCompliantChange } from "./media-gate-autofix.js";
|
||||
|
||||
/*
|
||||
* Render service (API side) and render job (worker side).
|
||||
@ -573,10 +574,12 @@ async function runRender(input: RunInput): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
const fix =
|
||||
const planned =
|
||||
round < MAX_AUTO_FIX_ROUNDS
|
||||
? planAutoFix(edl, { ...report, autoFixRound: round }, alternatives)
|
||||
: null;
|
||||
// An auto-fix may only add protection or cut content, never weaken a redaction.
|
||||
const fix = planned && nonCompliantChange(edl, planned.edl) === null ? planned : null;
|
||||
if (!fix) {
|
||||
await rm(renderDir, { recursive: true, force: true });
|
||||
const blocked = await update({ status: "blocked", progress: 1, gateReport: report });
|
||||
|
||||
@ -72,7 +72,9 @@ export function createMediaServices(input: {
|
||||
]);
|
||||
const set = mergeProfiles(builtin.profiles, own.profiles);
|
||||
set.errors = [...builtin.errors, ...own.errors];
|
||||
for (const error of set.errors) getLogger().warn("media profile ignored", error);
|
||||
for (const error of set.errors) {
|
||||
getLogger().warn("media profile ignored", { file: error.file, reason: error.message });
|
||||
}
|
||||
cached = { at: Date.now(), set };
|
||||
return set;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user