makefx 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/makefx.mjs +263 -40
- package/package.json +1 -1
package/README.md
CHANGED
package/makefx.mjs
CHANGED
|
@@ -621,9 +621,85 @@ function isProviderAuthMessage(message, providerErrorCode, provider) {
|
|
|
621
621
|
return providerErrorCode?.toLowerCase() === "api_key_invalid" || message.includes("api_key_invalid") || message.includes("api key not valid") || message.includes("invalid api key") || message.includes("api key is required") || message.includes("not configured") || message.includes("unauthenticated");
|
|
622
622
|
}
|
|
623
623
|
//#endregion
|
|
624
|
+
//#region src/shared/generation-blockers.ts
|
|
625
|
+
var GENERATION_BLOCKER_CODES = [
|
|
626
|
+
"SUBSCRIPTION_REQUIRED",
|
|
627
|
+
"PROVIDER_KEY_REQUIRED",
|
|
628
|
+
"BYOK_CREDENTIAL_FAILED",
|
|
629
|
+
"MANAGED_AI_UNAVAILABLE"
|
|
630
|
+
];
|
|
631
|
+
var PROVIDER_LABELS = {
|
|
632
|
+
google_ai: "Google AI",
|
|
633
|
+
elevenlabs: "ElevenLabs",
|
|
634
|
+
lyria: "Lyria",
|
|
635
|
+
kling: "Kling",
|
|
636
|
+
fal: "fal.ai",
|
|
637
|
+
replicate: "Replicate"
|
|
638
|
+
};
|
|
639
|
+
function isGenerationBlockerCode(code) {
|
|
640
|
+
return GENERATION_BLOCKER_CODES.includes(code);
|
|
641
|
+
}
|
|
642
|
+
function inferGenerationBlockerProvider(message) {
|
|
643
|
+
const normalized = message?.toLowerCase() ?? "";
|
|
644
|
+
if (normalized.includes("google ai") || normalized.includes("gemini") || normalized.includes("veo")) return "google_ai";
|
|
645
|
+
if (normalized.includes("elevenlabs")) return "elevenlabs";
|
|
646
|
+
if (normalized.includes("lyria")) return "lyria";
|
|
647
|
+
if (normalized.includes("kling")) return "kling";
|
|
648
|
+
if (normalized.includes("fal.ai") || normalized.includes("fal provider")) return "fal";
|
|
649
|
+
if (normalized.includes("replicate")) return "replicate";
|
|
650
|
+
}
|
|
651
|
+
function generationBlockerProviderFromService(provider) {
|
|
652
|
+
if (provider === "google_ai" || provider === "veo") return "google_ai";
|
|
653
|
+
if (provider === "elevenlabs" || provider === "lyria" || provider === "kling" || provider === "fal" || provider === "replicate") return provider;
|
|
654
|
+
}
|
|
655
|
+
function getGenerationBlockerPresentation(code, serverMessage, provider) {
|
|
656
|
+
if (!isGenerationBlockerCode(code)) return null;
|
|
657
|
+
if (code === "SUBSCRIPTION_REQUIRED") return {
|
|
658
|
+
code,
|
|
659
|
+
message: "A BYOK Platform subscription is required before generation can start.",
|
|
660
|
+
retryable: false,
|
|
661
|
+
actionLabel: "View billing",
|
|
662
|
+
actionPath: "/profile#billing",
|
|
663
|
+
remediation: "Start or restore the BYOK Platform subscription at https://makefx.app/profile#billing, then try again."
|
|
664
|
+
};
|
|
665
|
+
if (code === "MANAGED_AI_UNAVAILABLE") return {
|
|
666
|
+
code,
|
|
667
|
+
message: "Managed AI is coming soon and cannot be selected for customer generation.",
|
|
668
|
+
retryable: false,
|
|
669
|
+
remediation: "Choose a BYOK model after connecting its provider key. Managed AI is not available yet."
|
|
670
|
+
};
|
|
671
|
+
const resolvedProvider = provider ?? inferGenerationBlockerProvider(serverMessage);
|
|
672
|
+
const providerLabel = resolvedProvider ? PROVIDER_LABELS[resolvedProvider] : "provider";
|
|
673
|
+
const actionPath = resolvedProvider ? `/profile#provider-key-${resolvedProvider}` : "/profile#provider-keys";
|
|
674
|
+
const setupUrl = `https://makefx.app${actionPath}`;
|
|
675
|
+
if (code === "PROVIDER_KEY_REQUIRED") return {
|
|
676
|
+
code,
|
|
677
|
+
message: `A ${providerLabel} account key is required before generation can start.`,
|
|
678
|
+
retryable: false,
|
|
679
|
+
actionLabel: "Configure key",
|
|
680
|
+
actionPath,
|
|
681
|
+
remediation: `Configure the ${providerLabel} account key at ${setupUrl}, then try again.`,
|
|
682
|
+
...resolvedProvider ? { provider: resolvedProvider } : {}
|
|
683
|
+
};
|
|
684
|
+
return {
|
|
685
|
+
code,
|
|
686
|
+
message: `The ${providerLabel} account key could not be used. Replace or reconnect it before trying again.`,
|
|
687
|
+
retryable: false,
|
|
688
|
+
actionLabel: "Reconnect key",
|
|
689
|
+
actionPath,
|
|
690
|
+
remediation: `Replace or reconnect the ${providerLabel} account key at ${setupUrl}, then try again.`,
|
|
691
|
+
...resolvedProvider ? { provider: resolvedProvider } : {}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function formatGenerationBlockerForTerminal(code, message) {
|
|
695
|
+
const blocker = getGenerationBlockerPresentation(code, message);
|
|
696
|
+
if (!blocker) return `${code}: ${message}`;
|
|
697
|
+
return `${blocker.code}: ${blocker.message}\n${blocker.remediation}`;
|
|
698
|
+
}
|
|
699
|
+
//#endregion
|
|
624
700
|
//#region src/cli/lib/error-format.ts
|
|
625
701
|
function formatServerErrorMessage(code, message) {
|
|
626
|
-
return
|
|
702
|
+
return formatGenerationBlockerForTerminal(code, formatGenerationFailureMessage(message));
|
|
627
703
|
}
|
|
628
704
|
function formatGenerationFailureMessage(message, providerMetadata) {
|
|
629
705
|
return sanitizeGenerationFailureMessage(message, providerMetadata);
|
|
@@ -631,6 +707,9 @@ function formatGenerationFailureMessage(message, providerMetadata) {
|
|
|
631
707
|
function getGenerationFailureCode(providerMetadata) {
|
|
632
708
|
return extractGenerationDiagnostic(providerMetadata)?.code ?? "GENERATION_FAILED";
|
|
633
709
|
}
|
|
710
|
+
function getGenerationFailureProvider(providerMetadata) {
|
|
711
|
+
return extractGenerationDiagnostic(providerMetadata)?.provider;
|
|
712
|
+
}
|
|
634
713
|
//#endregion
|
|
635
714
|
//#region src/shared/compact-references.ts
|
|
636
715
|
var COMPACT_ID_LENGTH = 8;
|
|
@@ -4722,7 +4801,8 @@ var WebSocketClient = class WebSocketClient {
|
|
|
4722
4801
|
success: variant.status === "completed",
|
|
4723
4802
|
variant: variant.status === "completed" ? variant : void 0,
|
|
4724
4803
|
error: variant.status === "failed" ? formatGenerationFailureMessage(variant.error_message, variant.provider_metadata) : void 0,
|
|
4725
|
-
errorCode: variant.status === "failed" ? getGenerationFailureCode(variant.provider_metadata) : void 0
|
|
4804
|
+
errorCode: variant.status === "failed" ? getGenerationFailureCode(variant.provider_metadata) : void 0,
|
|
4805
|
+
errorProvider: variant.status === "failed" ? getGenerationFailureProvider(variant.provider_metadata) : void 0
|
|
4726
4806
|
});
|
|
4727
4807
|
}
|
|
4728
4808
|
return handled;
|
|
@@ -5017,7 +5097,9 @@ var WebSocketClient = class WebSocketClient {
|
|
|
5017
5097
|
videoDurationSeconds: params.videoDurationSeconds,
|
|
5018
5098
|
videoTier: params.videoTier,
|
|
5019
5099
|
seedanceDuration: params.seedanceDuration,
|
|
5020
|
-
seedanceBitrateMode: params.seedanceBitrateMode
|
|
5100
|
+
seedanceBitrateMode: params.seedanceBitrateMode,
|
|
5101
|
+
avatarResolution: params.avatarResolution,
|
|
5102
|
+
avatarMode: params.avatarMode
|
|
5021
5103
|
};
|
|
5022
5104
|
try {
|
|
5023
5105
|
this.send(message);
|
|
@@ -5870,6 +5952,16 @@ function readIsoBmffVideoMetadata(bytes) {
|
|
|
5870
5952
|
return durationMs ? { durationMs } : {};
|
|
5871
5953
|
}
|
|
5872
5954
|
//#endregion
|
|
5955
|
+
//#region src/shared/avatarGenerationOptions.ts
|
|
5956
|
+
var AVATAR_MODEL_IDS = ["kling-avatar-v2"];
|
|
5957
|
+
var AVATAR_MODES = ["standard", "pro"];
|
|
5958
|
+
function isAvatarModelId(value) {
|
|
5959
|
+
return typeof value === "string" && AVATAR_MODEL_IDS.includes(value);
|
|
5960
|
+
}
|
|
5961
|
+
function isAvatarMode(value) {
|
|
5962
|
+
return typeof value === "string" && AVATAR_MODES.includes(value);
|
|
5963
|
+
}
|
|
5964
|
+
//#endregion
|
|
5873
5965
|
//#region src/shared/seedance2Capabilities.ts
|
|
5874
5966
|
var SEEDANCE_2_ASPECT_RATIOS = [
|
|
5875
5967
|
"auto",
|
|
@@ -6381,6 +6473,20 @@ var MEDIA_OPERATION_MATRIX = [
|
|
|
6381
6473
|
cliCommands: ["generate"],
|
|
6382
6474
|
cliSupportsRefs: true
|
|
6383
6475
|
},
|
|
6476
|
+
{
|
|
6477
|
+
mode: "avatar",
|
|
6478
|
+
label: "Avatar",
|
|
6479
|
+
shortLabel: "Avatar",
|
|
6480
|
+
mediaKind: "video",
|
|
6481
|
+
assetType: "avatar",
|
|
6482
|
+
promptNoun: "avatar video",
|
|
6483
|
+
inheritsReferenceAssetType: false,
|
|
6484
|
+
compatibleSlotMediaKinds: ["image", "audio"],
|
|
6485
|
+
supportsBatch: false,
|
|
6486
|
+
cliNamespace: null,
|
|
6487
|
+
cliCommands: [],
|
|
6488
|
+
cliSupportsRefs: false
|
|
6489
|
+
},
|
|
6384
6490
|
{
|
|
6385
6491
|
mode: "speech",
|
|
6386
6492
|
label: "Speech",
|
|
@@ -6621,7 +6727,8 @@ var CLI_GENERATION_MEDIA_OPTIONS = {
|
|
|
6621
6727
|
"last-frame",
|
|
6622
6728
|
"image-refs",
|
|
6623
6729
|
"video-refs",
|
|
6624
|
-
"audio-refs"
|
|
6730
|
+
"audio-refs",
|
|
6731
|
+
"mode"
|
|
6625
6732
|
]
|
|
6626
6733
|
};
|
|
6627
6734
|
function rejectUnknownGenerationOptions(options, mediaKind) {
|
|
@@ -6669,12 +6776,12 @@ function validateAudioModeRequiredVoiceOptions(options, mode) {
|
|
|
6669
6776
|
if (mode === "dialogue" && !normalizeCliOption(options["dialogue-voices"] ?? options.dialogueVoices)) throw new Error("Dialogue generation requires --dialogue-voices <voice_id,voice_id>. Run: makefx audio voices");
|
|
6670
6777
|
}
|
|
6671
6778
|
async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptions = {}) {
|
|
6672
|
-
const
|
|
6779
|
+
const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
|
|
6780
|
+
const prompt = isAvatarModelId(videoOptions.model) ? parsed.positionals.join(" ").trim() : getPrompt(parsed, "generate");
|
|
6673
6781
|
const outputPath = getOutputPath(parsed);
|
|
6674
6782
|
const name = requireOption(parsed, "name");
|
|
6675
6783
|
const assetType = requireOption(parsed, "type");
|
|
6676
6784
|
const musicProvider = parseMusicProviderOption(parsed, mediaKind, assetType);
|
|
6677
|
-
const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
|
|
6678
6785
|
const effectiveVideoModel = videoOptions.model ?? getVideoGenerationModelForSelection();
|
|
6679
6786
|
const seedanceCapability = mediaKind === "video" ? getSeedance2CapabilityByEndpoint(effectiveVideoModel) : void 0;
|
|
6680
6787
|
const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
|
|
@@ -6693,7 +6800,7 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
|
|
|
6693
6800
|
...deps,
|
|
6694
6801
|
waitForReferenceVariant: (variant) => waitForReferenceVariant(client, variant)
|
|
6695
6802
|
};
|
|
6696
|
-
const resolvedSeedanceRefs = state && seedanceReferenceCount > 0 ? await resolveSeedanceReferenceIds(seedanceRefs, ctx, referenceDeps, state) : {
|
|
6803
|
+
const resolvedSeedanceRefs = state && seedanceReferenceCount > 0 ? isAvatarModelId(effectiveVideoModel) ? await resolveAvatarReferenceIds(seedanceRefs, ctx, referenceDeps, state) : await resolveSeedanceReferenceIds(seedanceRefs, ctx, referenceDeps, state) : {
|
|
6697
6804
|
refs: [],
|
|
6698
6805
|
ids: []
|
|
6699
6806
|
};
|
|
@@ -6847,6 +6954,10 @@ function parseSeedanceReferenceOptions(parsed) {
|
|
|
6847
6954
|
};
|
|
6848
6955
|
}
|
|
6849
6956
|
function validateSeedanceReferenceOptions(options, model, command) {
|
|
6957
|
+
if (isAvatarModelId(model)) {
|
|
6958
|
+
if (options.imageRefs.length !== 1 || options.audioRefs.length !== 1 || options.videoRefs.length !== 0) throw new Error("Avatar generation requires exactly one --image-refs portrait and one --audio-refs input");
|
|
6959
|
+
return;
|
|
6960
|
+
}
|
|
6850
6961
|
const capability = getSeedance2CapabilityByEndpoint(model);
|
|
6851
6962
|
const total = options.imageRefs.length + options.videoRefs.length + options.audioRefs.length;
|
|
6852
6963
|
if (!capability) {
|
|
@@ -6864,6 +6975,15 @@ function validateSeedanceReferenceOptions(options, model, command) {
|
|
|
6864
6975
|
});
|
|
6865
6976
|
if (error) throw new Error(error.message);
|
|
6866
6977
|
}
|
|
6978
|
+
async function resolveAvatarReferenceIds(options, ctx, deps, state) {
|
|
6979
|
+
const resolve = (refs, kind) => resolveReferenceVariantIds(refs, ctx, deps, state.variants, "video", state.assets, kind);
|
|
6980
|
+
const imageIds = await resolve(options.imageRefs, "image");
|
|
6981
|
+
const audioIds = await resolve(options.audioRefs, "audio");
|
|
6982
|
+
return {
|
|
6983
|
+
refs: [...options.imageRefs, ...options.audioRefs],
|
|
6984
|
+
ids: [...imageIds, ...audioIds]
|
|
6985
|
+
};
|
|
6986
|
+
}
|
|
6867
6987
|
async function resolveSeedanceReferenceIds(options, ctx, deps, state, implicitVideoReferenceIds = []) {
|
|
6868
6988
|
await preflightLocalSeedanceReferences({
|
|
6869
6989
|
...options,
|
|
@@ -7141,7 +7261,9 @@ function compactStartedVariantRef(started) {
|
|
|
7141
7261
|
}
|
|
7142
7262
|
function formatTerminalGenerationError(result) {
|
|
7143
7263
|
const message = result.error || "Generation failed without a completed variant";
|
|
7144
|
-
|
|
7264
|
+
if (!result.errorCode) return message;
|
|
7265
|
+
const blocker = getGenerationBlockerPresentation(result.errorCode, message, generationBlockerProviderFromService(result.errorProvider));
|
|
7266
|
+
return blocker ? `${blocker.code}: ${blocker.message}\n${blocker.remediation}` : formatGenerationBlockerForTerminal(result.errorCode, message);
|
|
7145
7267
|
}
|
|
7146
7268
|
function throwGenerationWaitErrorIfNeeded(input, params) {
|
|
7147
7269
|
if (!isGenerationWaitTimeout(input)) throw input;
|
|
@@ -7196,7 +7318,7 @@ function validateVideoAudioOptions(parsed, mediaKind) {
|
|
|
7196
7318
|
const model = parseVideoModelOption(modelValue, videoTier, parsed);
|
|
7197
7319
|
if (parsed.options.audio !== void 0 && (isGeminiOmniVideoGenerationModel(model) || isFalSeedanceV1VideoGenerationModel(model))) throw new Error("--audio is only supported with --model veo-3.1, kling, or Seedance 2");
|
|
7198
7320
|
if (parsed.options["no-audio"] !== void 0) {
|
|
7199
|
-
if (!doesVideoGenerationModelSupportAudioToggle(model) && !isFalSeedance2VideoGenerationModel(model)) throw new Error(`${model} does not support --no-audio. Use the default audio-enabled output or omit the flag.`);
|
|
7321
|
+
if (isAvatarModelId(model) || !doesVideoGenerationModelSupportAudioToggle(model) && !isFalSeedance2VideoGenerationModel(model)) throw new Error(`${model} does not support --no-audio. Use the default audio-enabled output or omit the flag.`);
|
|
7200
7322
|
}
|
|
7201
7323
|
}
|
|
7202
7324
|
function parseVideoAudioOptions(parsed, mediaKind) {
|
|
@@ -7211,6 +7333,7 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
|
|
|
7211
7333
|
const durationValue = readOptionalOption(parsed, "duration");
|
|
7212
7334
|
const tierValue = readOptionalOption(parsed, "tier");
|
|
7213
7335
|
const bitrateValue = readOptionalOption(parsed, "bitrate");
|
|
7336
|
+
const modeValue = readOptionalOption(parsed, "mode");
|
|
7214
7337
|
const modelValue = mediaKind === "video" ? readOptionalOption(parsed, "model") : void 0;
|
|
7215
7338
|
const aspectValue = mediaKind === "video" ? readOptionalOption(parsed, "aspect") : void 0;
|
|
7216
7339
|
if (mediaKind !== "video" && resolutionValue === void 0 && durationValue === void 0 && tierValue === void 0 && aspectValue === void 0 && bitrateValue === void 0) return {};
|
|
@@ -7220,6 +7343,17 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
|
|
|
7220
7343
|
const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
|
|
7221
7344
|
if (tierValue !== void 0 && !videoTier) throw new Error("--tier must be generate, fast, or lite");
|
|
7222
7345
|
const model = parseVideoModelOption(modelValue, videoTier, parsed);
|
|
7346
|
+
if (isAvatarModelId(model)) {
|
|
7347
|
+
if (parsed.options.refs !== void 0 || parsed.options["first-frame"] !== void 0 || parsed.options["last-frame"] !== void 0) throw new Error("Avatar models accept only --image-refs and --audio-refs");
|
|
7348
|
+
if (aspectValue !== void 0 || durationValue !== void 0 || tierValue !== void 0 || bitrateValue !== void 0 || parsed.options.audio !== void 0 || parsed.options["no-audio"] !== void 0) throw new Error("Avatar models do not accept --aspect, --duration, --tier, --bitrate, --audio, or --no-audio");
|
|
7349
|
+
if (resolutionValue !== void 0) throw new Error("--resolution is not supported by Avatar models");
|
|
7350
|
+
if (modeValue !== void 0 && !isAvatarMode(modeValue)) throw new Error(`--mode must be ${AVATAR_MODES.join(" or ")}`);
|
|
7351
|
+
return {
|
|
7352
|
+
model,
|
|
7353
|
+
...modeValue ? { avatarMode: modeValue } : {}
|
|
7354
|
+
};
|
|
7355
|
+
}
|
|
7356
|
+
if (modeValue !== void 0) throw new Error("--mode is only supported by --model kling-avatar-v2");
|
|
7223
7357
|
const seedanceCapability = getSeedance2CapabilityByEndpoint(model);
|
|
7224
7358
|
const seedanceDuration = durationValue === void 0 ? void 0 : durationValue === "auto" ? "auto" : normalizeVideoGenerationDurationSeconds(durationValue);
|
|
7225
7359
|
const videoDurationSeconds = durationValue === void 0 || durationValue === "auto" ? void 0 : normalizeVideoGenerationDurationSeconds(durationValue);
|
|
@@ -7315,6 +7449,7 @@ function parseVideoModelOption(value, tier, parsed) {
|
|
|
7315
7449
|
const normalized = normalizeCliOption(value);
|
|
7316
7450
|
const effectiveTier = tier ?? "generate";
|
|
7317
7451
|
if (!normalized) return getVideoGenerationModelForSelection(DEFAULT_VIDEO_MODEL_SELECTION, effectiveTier);
|
|
7452
|
+
if (isAvatarModelId(normalized)) return normalized;
|
|
7318
7453
|
if (normalized === "seedance-2" || normalized === "seedance-2-fast") {
|
|
7319
7454
|
const hasFrames = Boolean(parsed?.options["first-frame"] || parsed?.options["last-frame"]);
|
|
7320
7455
|
const hasReferences = Boolean(parsed?.options.refs || parsed?.options["image-refs"] || parsed?.options["video-refs"] || parsed?.options["audio-refs"]);
|
|
@@ -7322,7 +7457,7 @@ function parseVideoModelOption(value, tier, parsed) {
|
|
|
7322
7457
|
}
|
|
7323
7458
|
const selection = normalizeVideoModelSelection(normalized === "seedance-1" ? "fal-seedance" : normalized);
|
|
7324
7459
|
if (selection) return getVideoGenerationModelForSelection(selection, effectiveTier);
|
|
7325
|
-
throw new Error("--model must be veo-3.1, omni-flash, kling, seedance-1, seedance-2,
|
|
7460
|
+
throw new Error("--model must be veo-3.1, omni-flash, kling, seedance-1, seedance-2, seedance-2-fast, or kling-avatar-v2");
|
|
7326
7461
|
}
|
|
7327
7462
|
function parseImageModelOption(value) {
|
|
7328
7463
|
if (!value) return void 0;
|
|
@@ -7360,6 +7495,10 @@ function validateImageModelOperation(command, mediaKind, model) {
|
|
|
7360
7495
|
function validateVideoModelOperation(command, mediaKind, model) {
|
|
7361
7496
|
if (mediaKind !== "video") return;
|
|
7362
7497
|
const effectiveModel = model ?? getVideoGenerationModelForSelection();
|
|
7498
|
+
if (isAvatarModelId(effectiveModel)) {
|
|
7499
|
+
if (command === "generate") return;
|
|
7500
|
+
throw new Error(`--model ${effectiveModel} does not support video ${command}`);
|
|
7501
|
+
}
|
|
7363
7502
|
if (isVideoOperationSupportedByModel(effectiveModel, command)) return;
|
|
7364
7503
|
throw new Error(`--model ${getVideoModelSelectionForModel(effectiveModel) ?? effectiveModel} does not support video ${command}`);
|
|
7365
7504
|
}
|
|
@@ -7799,14 +7938,14 @@ async function handleBilling(parsed) {
|
|
|
7799
7938
|
}
|
|
7800
7939
|
function printBillingHelp() {
|
|
7801
7940
|
console.log(`
|
|
7802
|
-
Billing Commands -
|
|
7941
|
+
Billing Commands - Platform Subscription Operations
|
|
7803
7942
|
|
|
7804
7943
|
Usage:
|
|
7805
7944
|
makefx billing <subcommand> [--env <environment>]
|
|
7806
7945
|
|
|
7807
7946
|
Subcommands:
|
|
7808
7947
|
status Show sync status (pending, failed, synced events)
|
|
7809
|
-
check Run operational checks for workers, Polar
|
|
7948
|
+
check Run operational checks for workers, Polar product, and sync health
|
|
7810
7949
|
reconcile Compare local billable usage with Polar usage for one user
|
|
7811
7950
|
retry-failed Reset failed events for retry (next cron will sync them)
|
|
7812
7951
|
|
|
@@ -7953,6 +8092,16 @@ function secondsSummary(seconds) {
|
|
|
7953
8092
|
const remainingSeconds = seconds % 60;
|
|
7954
8093
|
return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
|
|
7955
8094
|
}
|
|
8095
|
+
function resolveBillingOpsResult(options) {
|
|
8096
|
+
const statuses = [
|
|
8097
|
+
...options.workerStatuses,
|
|
8098
|
+
options.billingStatus,
|
|
8099
|
+
options.webhookStatus
|
|
8100
|
+
];
|
|
8101
|
+
if (statuses.includes("critical")) return "critical";
|
|
8102
|
+
if (statuses.includes("warning")) return "warning";
|
|
8103
|
+
return "ok";
|
|
8104
|
+
}
|
|
7956
8105
|
async function handleBillingOpsCheck(env) {
|
|
7957
8106
|
console.log(`Running billing operational checks for ${env}...\n`);
|
|
7958
8107
|
const workerChecks = await checkWorkerHealth(env);
|
|
@@ -7969,22 +8118,22 @@ async function handleBillingOpsCheck(env) {
|
|
|
7969
8118
|
process$1.exitCode = 1;
|
|
7970
8119
|
return;
|
|
7971
8120
|
}
|
|
7972
|
-
const
|
|
7973
|
-
console.log("\
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
if (
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
}
|
|
8121
|
+
const productCheck = billingChecks.checks.platformSubscriptionProduct;
|
|
8122
|
+
console.log("\nPlatform subscription product:");
|
|
8123
|
+
const product = productCheck.product;
|
|
8124
|
+
console.log(` ${statusLabel(productCheck.status)} configured=${product?.configured ?? false} recurring=${product?.isRecurring ?? "n/a"} archived=${product?.isArchived ?? "n/a"}`);
|
|
8125
|
+
console.log(` Environment: ${productCheck.actualEnvironment} (expected ${productCheck.expectedEnvironment})`);
|
|
8126
|
+
if (product?.productId) console.log(` Product: ${product.productId}${product.name ? ` (${product.name})` : ""}`);
|
|
8127
|
+
if (product?.fixedPrices.length) console.log(` Fixed price: ${product.fixedPrices.map((price) => `${price.amount} ${price.currency}/${price.interval ?? "one-time"}`).join(", ")}`);
|
|
8128
|
+
for (const error of productCheck.errors) console.log(` Error: ${error}`);
|
|
8129
|
+
const webhookCheck = billingChecks.checks.webhook ?? {
|
|
8130
|
+
status: "critical",
|
|
8131
|
+
configured: false,
|
|
8132
|
+
error: "Webhook readiness was not reported by the application Worker"
|
|
8133
|
+
};
|
|
8134
|
+
console.log("\nWebhook verifier:");
|
|
8135
|
+
console.log(` ${statusLabel(webhookCheck.status)} configured=${webhookCheck.configured}`);
|
|
8136
|
+
if (webhookCheck.error) console.log(` Error: ${webhookCheck.error}`);
|
|
7988
8137
|
const syncCheck = billingChecks.checks.syncHealth;
|
|
7989
8138
|
console.log("\nSync health:");
|
|
7990
8139
|
console.log(` ${statusLabel(syncCheck.status)} pending=${syncCheck.events.pending} failed=${syncCheck.events.failed} synced=${syncCheck.events.synced}`);
|
|
@@ -7993,13 +8142,15 @@ async function handleBillingOpsCheck(env) {
|
|
|
7993
8142
|
const internalCheck = billingChecks.checks.internalUsers;
|
|
7994
8143
|
console.log("\nInternal users:");
|
|
7995
8144
|
console.log(` ${statusLabel(internalCheck.status)} users=${internalCheck.internalUsers} nonBillableEvents=${internalCheck.nonBillableEvents} billableEvents=${internalCheck.billableEvents}`);
|
|
7996
|
-
const
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8145
|
+
const resultStatus = resolveBillingOpsResult({
|
|
8146
|
+
workerStatuses: workerChecks.map((check) => check.status),
|
|
8147
|
+
billingStatus: billingChecks.status,
|
|
8148
|
+
webhookStatus: webhookCheck.status
|
|
8149
|
+
});
|
|
8150
|
+
if (resultStatus === "critical") {
|
|
8000
8151
|
console.log("\nResult: CRITICAL - billing operations need attention.");
|
|
8001
8152
|
process$1.exitCode = 1;
|
|
8002
|
-
} else if (
|
|
8153
|
+
} else if (resultStatus === "warning") console.log("\nResult: WARNING - billing is operational but has lag or cleanup work.");
|
|
8003
8154
|
else console.log("\nResult: OK - billing workers, meters, and sync health are ready.");
|
|
8004
8155
|
}
|
|
8005
8156
|
async function handleBillingReconcile(env, parsed) {
|
|
@@ -8537,7 +8688,6 @@ function imageGenerator(capability) {
|
|
|
8537
8688
|
id: `image/${capability.selection}`,
|
|
8538
8689
|
label: capability.label,
|
|
8539
8690
|
mediaKind: "image",
|
|
8540
|
-
provider: capability.provider === "gemini" ? "google_ai" : "fal",
|
|
8541
8691
|
modelIds: [capability.modelId],
|
|
8542
8692
|
defaultModelId: capability.modelId,
|
|
8543
8693
|
operations,
|
|
@@ -8617,7 +8767,6 @@ function videoGenerator(selection) {
|
|
|
8617
8767
|
id: `video/${selection}`,
|
|
8618
8768
|
label: VIDEO_MODEL_LABELS[selection],
|
|
8619
8769
|
mediaKind: "video",
|
|
8620
|
-
provider: selection === "kling" ? "kling" : selection === "fal-seedance" ? "fal" : "google_ai",
|
|
8621
8770
|
modelIds,
|
|
8622
8771
|
defaultModelId: defaultModel,
|
|
8623
8772
|
operations,
|
|
@@ -8714,7 +8863,6 @@ function seedanceVideoGenerator(capability) {
|
|
|
8714
8863
|
id: capability.generatorId,
|
|
8715
8864
|
label: capability.label,
|
|
8716
8865
|
mediaKind: "video",
|
|
8717
|
-
provider: "fal",
|
|
8718
8866
|
modelIds: [capability.endpointId],
|
|
8719
8867
|
defaultModelId: capability.endpointId,
|
|
8720
8868
|
operations,
|
|
@@ -8743,6 +8891,72 @@ function seedanceVideoGenerator(capability) {
|
|
|
8743
8891
|
]
|
|
8744
8892
|
};
|
|
8745
8893
|
}
|
|
8894
|
+
function avatarVideoGenerator(model) {
|
|
8895
|
+
const parameters = [input("mode", "string", false, "Generation quality.", {
|
|
8896
|
+
allowedValues: AVATAR_MODES,
|
|
8897
|
+
defaultValue: "standard"
|
|
8898
|
+
})];
|
|
8899
|
+
return {
|
|
8900
|
+
id: `video/${model}`,
|
|
8901
|
+
label: "Kling Avatar V2",
|
|
8902
|
+
mediaKind: "video",
|
|
8903
|
+
modelIds: [model],
|
|
8904
|
+
defaultModelId: model,
|
|
8905
|
+
operations: [{
|
|
8906
|
+
operation: "derive",
|
|
8907
|
+
tool: "generate_video",
|
|
8908
|
+
description: "Create an Avatar video from one portrait image and one audio Variant.",
|
|
8909
|
+
inputs: [
|
|
8910
|
+
SPACE_INPUT,
|
|
8911
|
+
fixedInput("generator_id", `video/${model}`, "Selects this Avatar generator."),
|
|
8912
|
+
NAME_INPUT,
|
|
8913
|
+
input("asset_type", "string", true, "Asset classification stored in the Space."),
|
|
8914
|
+
input("prompt", "string", false, "Optional motion and expression guidance."),
|
|
8915
|
+
...parameters,
|
|
8916
|
+
input("image_reference_variant_refs", "string_array", true, "Exactly one completed portrait image Variant.", {
|
|
8917
|
+
minItems: 1,
|
|
8918
|
+
maxItems: 1
|
|
8919
|
+
}),
|
|
8920
|
+
input("audio_reference_variant_refs", "string_array", true, "Exactly one completed audio Variant.", {
|
|
8921
|
+
minItems: 1,
|
|
8922
|
+
maxItems: 1
|
|
8923
|
+
})
|
|
8924
|
+
]
|
|
8925
|
+
}],
|
|
8926
|
+
referenceRules: {
|
|
8927
|
+
mediaKind: null,
|
|
8928
|
+
completedOnly: true,
|
|
8929
|
+
maxCount: 2,
|
|
8930
|
+
maxTotalCount: 2,
|
|
8931
|
+
modalities: [{
|
|
8932
|
+
mediaKind: "image",
|
|
8933
|
+
minCount: 1,
|
|
8934
|
+
maxCount: 1,
|
|
8935
|
+
promptLabel: "Portrait",
|
|
8936
|
+
acceptedMimeTypes: [
|
|
8937
|
+
"image/jpeg",
|
|
8938
|
+
"image/png",
|
|
8939
|
+
"image/webp"
|
|
8940
|
+
],
|
|
8941
|
+
maxBytesPerFile: 10 * 1024 * 1024
|
|
8942
|
+
}, {
|
|
8943
|
+
mediaKind: "audio",
|
|
8944
|
+
minCount: 1,
|
|
8945
|
+
maxCount: 1,
|
|
8946
|
+
promptLabel: "Audio",
|
|
8947
|
+
acceptedMimeTypes: [
|
|
8948
|
+
"audio/mpeg",
|
|
8949
|
+
"audio/wav",
|
|
8950
|
+
"audio/x-wav",
|
|
8951
|
+
"audio/mp4",
|
|
8952
|
+
"audio/aac"
|
|
8953
|
+
],
|
|
8954
|
+
maxBytesPerFile: 5 * 1024 * 1024
|
|
8955
|
+
}]
|
|
8956
|
+
},
|
|
8957
|
+
notes: ["Outputs an ordinary video Variant. Provider routing remains internal."]
|
|
8958
|
+
};
|
|
8959
|
+
}
|
|
8746
8960
|
function audioGenerator(input_) {
|
|
8747
8961
|
const inputs = [
|
|
8748
8962
|
SPACE_INPUT,
|
|
@@ -8758,7 +8972,6 @@ function audioGenerator(input_) {
|
|
|
8758
8972
|
id: input_.id,
|
|
8759
8973
|
label: input_.label,
|
|
8760
8974
|
mediaKind: "audio",
|
|
8761
|
-
provider: input_.provider,
|
|
8762
8975
|
modelIds: [input_.modelId],
|
|
8763
8976
|
defaultModelId: input_.modelId,
|
|
8764
8977
|
operations: [{
|
|
@@ -8784,6 +8997,7 @@ function getGeneratorCatalog(overrides = {}) {
|
|
|
8784
8997
|
...Object.values(IMAGE_MODEL_CAPABILITIES).map(imageGenerator),
|
|
8785
8998
|
...VIDEO_MODEL_SELECTIONS.map(videoGenerator),
|
|
8786
8999
|
...SEEDANCE_2_SELECTIONS.map((selection) => seedanceVideoGenerator(SEEDANCE_2_CAPABILITIES[selection])),
|
|
9000
|
+
...AVATAR_MODEL_IDS.map(avatarVideoGenerator),
|
|
8787
9001
|
audioGenerator({
|
|
8788
9002
|
id: "audio/elevenlabs-speech",
|
|
8789
9003
|
label: "ElevenLabs Speech",
|
|
@@ -8863,6 +9077,11 @@ var DRAFT_RECIPE_INPUT_KEYS = {
|
|
|
8863
9077
|
duration: "seedanceDuration",
|
|
8864
9078
|
bitrate_mode: "seedanceBitrateMode"
|
|
8865
9079
|
};
|
|
9080
|
+
function draftRecipeInputKey(inputName, generatorId) {
|
|
9081
|
+
if (generatorId === "video/p-video-avatar" && inputName === "resolution") return "avatarResolution";
|
|
9082
|
+
if (generatorId === "video/kling-avatar-v2" && inputName === "mode") return "avatarMode";
|
|
9083
|
+
return DRAFT_RECIPE_INPUT_KEYS[inputName];
|
|
9084
|
+
}
|
|
8866
9085
|
var DRAFT_REFERENCE_FIELD = /(?:_variant_refs?|VariantRefs?)$/;
|
|
8867
9086
|
/**
|
|
8868
9087
|
* The one slot-naming convention used while authoring and resolving Bindings.
|
|
@@ -8883,6 +9102,7 @@ function generatorIdForDraftRecipe(mediaMode, recipe) {
|
|
|
8883
9102
|
}
|
|
8884
9103
|
if (mediaMode === "video") {
|
|
8885
9104
|
const model = typeof recipe.model === "string" ? recipe.model : "veo-3.1";
|
|
9105
|
+
if (isAvatarModelId(model)) return `video/${model}`;
|
|
8886
9106
|
const seedance = getSeedance2CapabilityByEndpoint(model);
|
|
8887
9107
|
if (seedance) return seedance.generatorId;
|
|
8888
9108
|
const selection = getVideoModelSelectionForModel(model);
|
|
@@ -8905,7 +9125,7 @@ function buildDraftMapping(args) {
|
|
|
8905
9125
|
if (!operationDefinition) throw new Error(`${generatorId} does not support ${operation} drafts`);
|
|
8906
9126
|
const recipeTemplate = { operation };
|
|
8907
9127
|
for (const input of operationDefinition.inputs) {
|
|
8908
|
-
const key =
|
|
9128
|
+
const key = draftRecipeInputKey(input.name, generatorId);
|
|
8909
9129
|
if (!key) continue;
|
|
8910
9130
|
const value = recipe[key];
|
|
8911
9131
|
if (value !== void 0) recipeTemplate[key] = value;
|
|
@@ -10094,7 +10314,7 @@ async function executeModels(parsed, deps = defaultDeps$5) {
|
|
|
10094
10314
|
const { models } = await response.json();
|
|
10095
10315
|
if (parsed.options.json === "true") deps.print(JSON.stringify(models, null, 2));
|
|
10096
10316
|
else for (const model of models) {
|
|
10097
|
-
const readiness = model.availability.available ? "ready" : model.availability.reason
|
|
10317
|
+
const readiness = model.availability.available ? "ready" : [model.availability.code, model.availability.reason].filter(Boolean).join(": ") || "unavailable";
|
|
10098
10318
|
deps.print(`${model.id.padEnd(20)} ${model.media_kind.padEnd(6)} ${readiness}`);
|
|
10099
10319
|
}
|
|
10100
10320
|
return models;
|
|
@@ -10117,6 +10337,7 @@ function formatModelDetail(model) {
|
|
|
10117
10337
|
`Availability: ${model.availability.available ? "ready" : model.availability.reason ?? "unavailable"}`,
|
|
10118
10338
|
"Operations:"
|
|
10119
10339
|
];
|
|
10340
|
+
if (!model.availability.available && model.availability.guidance) lines.splice(3, 0, `Next step: ${model.availability.guidance}`);
|
|
10120
10341
|
for (const operation of model.operations) {
|
|
10121
10342
|
if (typeof operation === "string") {
|
|
10122
10343
|
lines.push(` - ${operation}`);
|
|
@@ -11253,6 +11474,8 @@ var HELP = {
|
|
|
11253
11474
|
[--refs <variant-ref-or-file,...>] [--first-frame <ref>] [--last-frame <ref>] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>]
|
|
11254
11475
|
[--aspect <ratio>] [--resolution 480p|720p|1080p|4k] [--duration <seconds|auto>] [--tier generate|fast|lite] [--bitrate standard|high]
|
|
11255
11476
|
[--audio | --no-audio] [--collection <id>] [--space <id>]
|
|
11477
|
+
makefx video generate ["prompt"] --model kling-avatar-v2 --image-refs <portrait-ref> --audio-refs <audio-ref>
|
|
11478
|
+
--name <name> --type <type> -o <file> [--mode standard|pro] [--collection <id>] [--space <id>]
|
|
11256
11479
|
makefx video regenerate <variant-ref> ["prompt"] [--model <model>] [--aspect <ratio>] [--resolution <value>] [--duration <seconds>] [--tier <tier>] [--bitrate standard|high] [--audio | --no-audio] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>] [--no-activate] [--wait]
|
|
11257
11480
|
|
|
11258
11481
|
Seedance mode is inferred: first/last frame selects frame mode, image/video/audio refs select reference mode, and no references selects text mode.`,
|
|
@@ -11333,7 +11556,7 @@ compact variant refs, each optionally suffixed :derived, :refined, or :forked
|
|
|
11333
11556
|
};
|
|
11334
11557
|
//#endregion
|
|
11335
11558
|
//#region src/cli/index.ts
|
|
11336
|
-
var CLI_VERSION = "1.
|
|
11559
|
+
var CLI_VERSION = "1.6.0+e2eab203b853";
|
|
11337
11560
|
function printHelp() {
|
|
11338
11561
|
console.log(TOP_LEVEL_HELP);
|
|
11339
11562
|
}
|