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,
|
createCloudAgentConnection,
|
||||||
createConnectorStack,
|
createConnectorStack,
|
||||||
createJobReconciler,
|
createJobReconciler,
|
||||||
createMessagingContextLoader,
|
|
||||||
createMessagingTeamChatSender,
|
|
||||||
createMediaJobHandlers,
|
createMediaJobHandlers,
|
||||||
createMediaServices,
|
createMediaServices,
|
||||||
|
createMessagingContextLoader,
|
||||||
|
createMessagingTeamChatSender,
|
||||||
createProfileConsolidationScheduler,
|
createProfileConsolidationScheduler,
|
||||||
createRunExecutor,
|
createRunExecutor,
|
||||||
createRunSandbox,
|
createRunSandbox,
|
||||||
@ -94,6 +94,7 @@ import { cors } from "hono/cors";
|
|||||||
import type { AppEnv } from "./env.js";
|
import type { AppEnv } from "./env.js";
|
||||||
import { loadEnv } from "./env.js";
|
import { loadEnv } from "./env.js";
|
||||||
import { mountLocalSettings } from "./local-settings.js";
|
import { mountLocalSettings } from "./local-settings.js";
|
||||||
|
import { mountMediaHttpRoutes } from "./media-http.js";
|
||||||
import {
|
import {
|
||||||
createMessagingInboundHandler,
|
createMessagingInboundHandler,
|
||||||
teamChatSenderCanWakeMessageRoutines,
|
teamChatSenderCanWakeMessageRoutines,
|
||||||
@ -112,7 +113,6 @@ import {
|
|||||||
TEAM_CHAT_STARTUP_SHUTDOWN_MS,
|
TEAM_CHAT_STARTUP_SHUTDOWN_MS,
|
||||||
} from "./team-chat-startup.js";
|
} from "./team-chat-startup.js";
|
||||||
import { mountTradingBotStatus } from "./trading-bot-proxy.js";
|
import { mountTradingBotStatus } from "./trading-bot-proxy.js";
|
||||||
import { mountMediaHttpRoutes } from "./media-http.js";
|
|
||||||
import { mountVoiceHttpRoutes } from "./voice.js";
|
import { mountVoiceHttpRoutes } from "./voice.js";
|
||||||
import { mountWebhookHttpRoutes } from "./webhook.js";
|
import { mountWebhookHttpRoutes } from "./webhook.js";
|
||||||
|
|
||||||
@ -455,7 +455,9 @@ export async function createApp(
|
|||||||
await graphileWorkerHost.start(jobHandlers);
|
await graphileWorkerHost.start(jobHandlers);
|
||||||
}
|
}
|
||||||
if (mediaJobs) {
|
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
|
const reconciler = inMemoryJobs
|
||||||
? createJobReconciler({
|
? createJobReconciler({
|
||||||
|
|||||||
@ -10,10 +10,10 @@ import {
|
|||||||
createCloudAgentConnection,
|
createCloudAgentConnection,
|
||||||
createConnectorStack,
|
createConnectorStack,
|
||||||
createJobReconciler,
|
createJobReconciler,
|
||||||
createMessagingContextLoader,
|
|
||||||
createPostgresReconciliationLeadership,
|
|
||||||
createMediaJobHandlers,
|
createMediaJobHandlers,
|
||||||
createMediaServices,
|
createMediaServices,
|
||||||
|
createMessagingContextLoader,
|
||||||
|
createPostgresReconciliationLeadership,
|
||||||
createProfileConsolidationScheduler,
|
createProfileConsolidationScheduler,
|
||||||
createRunExecutor,
|
createRunExecutor,
|
||||||
createRunSandbox,
|
createRunSandbox,
|
||||||
@ -31,9 +31,9 @@ import {
|
|||||||
isPipedreamEnabled,
|
isPipedreamEnabled,
|
||||||
LocalAgentHomeStore,
|
LocalAgentHomeStore,
|
||||||
LocalArtifactStore,
|
LocalArtifactStore,
|
||||||
mediaConfigFromEnv,
|
|
||||||
McpConnector,
|
McpConnector,
|
||||||
McpOAuthBroker,
|
McpOAuthBroker,
|
||||||
|
mediaConfigFromEnv,
|
||||||
messagingEnvFromProcess,
|
messagingEnvFromProcess,
|
||||||
messagingPlatformsFromEnv,
|
messagingPlatformsFromEnv,
|
||||||
PiAgentRuntime,
|
PiAgentRuntime,
|
||||||
|
|||||||
@ -77,6 +77,7 @@ export * from "./mcp-oauth.js";
|
|||||||
export * from "./mcp-server-tool.js";
|
export * from "./mcp-server-tool.js";
|
||||||
export * from "./mcp-transport.js";
|
export * from "./mcp-transport.js";
|
||||||
export * from "./media-brand.js";
|
export * from "./media-brand.js";
|
||||||
|
export * from "./media-consent.js";
|
||||||
export * from "./media-context.js";
|
export * from "./media-context.js";
|
||||||
export * from "./media-emulator.js";
|
export * from "./media-emulator.js";
|
||||||
export * from "./media-emulator-clips.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-ffmpeg-renderer.js";
|
||||||
export * from "./media-folder-source.js";
|
export * from "./media-folder-source.js";
|
||||||
export * from "./media-folder-source-probe.js";
|
export * from "./media-folder-source-probe.js";
|
||||||
|
export * from "./media-gate-autofix.js";
|
||||||
export * from "./media-ingest.js";
|
export * from "./media-ingest.js";
|
||||||
export { defaultMediaJobLimits, MediaJobLimiter, type MediaJobLimits } from "./media-jobs.js";
|
export { defaultMediaJobLimits, MediaJobLimiter, type MediaJobLimits } from "./media-jobs.js";
|
||||||
export * from "./media-marketing.js";
|
export * from "./media-marketing.js";
|
||||||
@ -103,9 +105,10 @@ export {
|
|||||||
MotionTemplateError,
|
MotionTemplateError,
|
||||||
ResvgMotionGraphicsRenderer,
|
ResvgMotionGraphicsRenderer,
|
||||||
} from "./media-motion-renderer.js";
|
} 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-publish.js";
|
||||||
export * from "./media-publisher-bundle.js";
|
export * from "./media-publisher-bundle.js";
|
||||||
export * from "./media-services.js";
|
|
||||||
export {
|
export {
|
||||||
createMediaRenderHandler,
|
createMediaRenderHandler,
|
||||||
createMediaRenderService,
|
createMediaRenderService,
|
||||||
@ -113,6 +116,7 @@ export {
|
|||||||
pickEncoder,
|
pickEncoder,
|
||||||
softwareEncoder,
|
softwareEncoder,
|
||||||
} from "./media-render.js";
|
} from "./media-render.js";
|
||||||
|
export * from "./media-services.js";
|
||||||
export * from "./media-sidecar.js";
|
export * from "./media-sidecar.js";
|
||||||
export * from "./media-zip.js";
|
export * from "./media-zip.js";
|
||||||
export * from "./memory-provider-factory.js";
|
export * from "./memory-provider-factory.js";
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { InvalidMediaInputError, MediaStateConflictError } from "@rakazo/db";
|
|||||||
import { getLogger } from "@rakazo/logging";
|
import { getLogger } from "@rakazo/logging";
|
||||||
import { buildTrackingUrl, normalizeHashtags, uploadChecklist } from "@rakazo/media";
|
import { buildTrackingUrl, normalizeHashtags, uploadChecklist } from "@rakazo/media";
|
||||||
import { resolveInside } from "@rakazo/media/node";
|
import { resolveInside } from "@rakazo/media/node";
|
||||||
|
import { assertExportConsent } from "./media-consent.js";
|
||||||
import type { MediaActor, MediaMarketingService, MediaServiceDeps } from "./media-context.js";
|
import type { MediaActor, MediaMarketingService, MediaServiceDeps } from "./media-context.js";
|
||||||
import type { MediaToolPaths } from "./media-folder-source-probe.js";
|
import type { MediaToolPaths } from "./media-folder-source-probe.js";
|
||||||
import { runMediaTool } 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;
|
const profile = profileSet.profiles.get(pub.profileId)?.profile;
|
||||||
if (!profile) throw new MediaStateConflictError(`Profile ${pub.profileId} is not available`);
|
if (!profile) throw new MediaStateConflictError(`Profile ${pub.profileId} is not available`);
|
||||||
const edl = plan.edl;
|
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 outputs = storedRenderOutputs(row.outputs);
|
||||||
const video = outputs.find((output) => output.kind === "video");
|
const video = outputs.find((output) => output.kind === "video");
|
||||||
if (!video) throw new MediaStateConflictError("Render has no video output");
|
if (!video) throw new MediaStateConflictError("Render has no video output");
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import type {
|
|||||||
MediaServiceDeps,
|
MediaServiceDeps,
|
||||||
} from "./media-context.js";
|
} from "./media-context.js";
|
||||||
import { MediaToolMissingError } from "./media-folder-source-probe.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).
|
* Render service (API side) and render job (worker side).
|
||||||
@ -573,10 +574,12 @@ async function runRender(input: RunInput): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fix =
|
const planned =
|
||||||
round < MAX_AUTO_FIX_ROUNDS
|
round < MAX_AUTO_FIX_ROUNDS
|
||||||
? planAutoFix(edl, { ...report, autoFixRound: round }, alternatives)
|
? planAutoFix(edl, { ...report, autoFixRound: round }, alternatives)
|
||||||
: null;
|
: 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) {
|
if (!fix) {
|
||||||
await rm(renderDir, { recursive: true, force: true });
|
await rm(renderDir, { recursive: true, force: true });
|
||||||
const blocked = await update({ status: "blocked", progress: 1, gateReport: report });
|
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);
|
const set = mergeProfiles(builtin.profiles, own.profiles);
|
||||||
set.errors = [...builtin.errors, ...own.errors];
|
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 };
|
cached = { at: Date.now(), set };
|
||||||
return set;
|
return set;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user