@koda-sl/baker-cli 0.99.0 → 0.99.1-dev.5b1957cc
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 +3 -1
- package/dist/{chunk-3JVYU72O.js → chunk-26K7V346.js} +4 -4
- package/dist/chunk-26K7V346.js.map +1 -0
- package/dist/cli.js +217 -46
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3JVYU72O.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
defaultRegistry,
|
|
10
10
|
generateCatalog,
|
|
11
11
|
validateCanvasDeep
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-26K7V346.js";
|
|
13
13
|
|
|
14
14
|
// src/cli.ts
|
|
15
15
|
import { defineCommand as defineCommand152, runMain } from "citty";
|
|
@@ -11969,6 +11969,7 @@ Subcommands:
|
|
|
11969
11969
|
import { defineCommand as defineCommand88 } from "citty";
|
|
11970
11970
|
|
|
11971
11971
|
// src/commands/creatives/publish.ts
|
|
11972
|
+
import { extname as extname2 } from "path";
|
|
11972
11973
|
import { defineCommand as defineCommand87 } from "citty";
|
|
11973
11974
|
|
|
11974
11975
|
// src/commands/images/api.ts
|
|
@@ -12015,9 +12016,6 @@ async function uploadLocalImage(args, deps = defaultImageApiDeps) {
|
|
|
12015
12016
|
function getImage(deps, imageId) {
|
|
12016
12017
|
return deps.get("/api/images/get", { id: imageId });
|
|
12017
12018
|
}
|
|
12018
|
-
function updateImageTags(deps, args) {
|
|
12019
|
-
return deps.post("/api/images/tag", args);
|
|
12020
|
-
}
|
|
12021
12019
|
async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
12022
12020
|
const timeoutMs = opts.timeoutMs ?? imageProcessingTimeoutMs;
|
|
12023
12021
|
const pollIntervalMs = opts.pollIntervalMs ?? imageReadyPollIntervalMs;
|
|
@@ -12039,31 +12037,68 @@ async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
|
12039
12037
|
|
|
12040
12038
|
// src/commands/creatives/publish.ts
|
|
12041
12039
|
var creativeTag = "creative";
|
|
12042
|
-
var
|
|
12040
|
+
var winningAdsTag = "winning-ads";
|
|
12041
|
+
var creativeTags = [creativeTag, winningAdsTag];
|
|
12042
|
+
var creativeImageContentTypes = ["image/png", "image/jpeg", "image/webp"];
|
|
12043
|
+
var creativeVideoContentTypesByExtension = {
|
|
12044
|
+
".mp4": "video/mp4",
|
|
12045
|
+
".mov": "video/quicktime",
|
|
12046
|
+
".webm": "video/webm"
|
|
12047
|
+
};
|
|
12048
|
+
var videoProcessingTimeoutMs = 5 * 60 * 1e3;
|
|
12049
|
+
var videoReadyPollIntervalMs = 5e3;
|
|
12050
|
+
var defaultCreativePublishDeps = {
|
|
12051
|
+
...defaultImageApiDeps,
|
|
12052
|
+
fetch
|
|
12053
|
+
};
|
|
12043
12054
|
registerSchema({
|
|
12044
12055
|
command: "creatives.publish",
|
|
12045
|
-
description: "Publish a final
|
|
12056
|
+
description: "Publish a final creative image or video, apply creative and winning-ads tags, and return an asset reference.",
|
|
12046
12057
|
args: {
|
|
12047
|
-
file: { type: "string", description: "Local PNG/JPG/WebP creative
|
|
12058
|
+
file: { type: "string", description: "Local PNG/JPG/WebP/MP4/MOV/WebM creative path", required: true },
|
|
12048
12059
|
title: { type: "string", description: "Human title for the creative output", required: true },
|
|
12049
|
-
|
|
12060
|
+
body: { type: "string", description: "Reference traceability body for the creative output", required: true }
|
|
12050
12061
|
}
|
|
12051
12062
|
});
|
|
12063
|
+
function uniqueTags(tags) {
|
|
12064
|
+
return [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];
|
|
12065
|
+
}
|
|
12066
|
+
function requiredMetadata(args) {
|
|
12067
|
+
const title = args.title.trim();
|
|
12068
|
+
const body = args.body.trim();
|
|
12069
|
+
if (!title) {
|
|
12070
|
+
throw new ApiError("VALIDATION_ERROR", "--title is required");
|
|
12071
|
+
}
|
|
12072
|
+
if (!body) {
|
|
12073
|
+
throw new ApiError("VALIDATION_ERROR", "--body is required");
|
|
12074
|
+
}
|
|
12075
|
+
return { title, body };
|
|
12076
|
+
}
|
|
12052
12077
|
function detectCreativeContentType(filePath) {
|
|
12078
|
+
const ext = extname2(filePath).toLowerCase();
|
|
12079
|
+
const videoContentType = creativeVideoContentTypesByExtension[ext];
|
|
12080
|
+
if (videoContentType) {
|
|
12081
|
+
return videoContentType;
|
|
12082
|
+
}
|
|
12053
12083
|
return detectImageContentType(filePath, {
|
|
12054
|
-
allowedContentTypes:
|
|
12055
|
-
unsupportedMessage: "Unsupported creative
|
|
12084
|
+
allowedContentTypes: creativeImageContentTypes,
|
|
12085
|
+
unsupportedMessage: "Unsupported creative extension. Use PNG, JPG, WebP, MP4, MOV, or WebM."
|
|
12056
12086
|
});
|
|
12057
12087
|
}
|
|
12088
|
+
function isVideoContentType(contentType) {
|
|
12089
|
+
return contentType.startsWith("video/");
|
|
12090
|
+
}
|
|
12058
12091
|
function imageToCreativeReference(image, title) {
|
|
12059
12092
|
if (!image.imageUrl) {
|
|
12060
12093
|
throw new ApiError("IMAGE_PROCESSING_ERROR", "Published image is missing imageUrl");
|
|
12061
12094
|
}
|
|
12095
|
+
const tags = uniqueTags([...image.tags ?? [], ...creativeTags]);
|
|
12062
12096
|
return {
|
|
12063
12097
|
type: "image",
|
|
12064
12098
|
slug: image._id,
|
|
12065
12099
|
title,
|
|
12066
|
-
|
|
12100
|
+
body: image.description,
|
|
12101
|
+
tags,
|
|
12067
12102
|
imageUrl: image.imageUrl,
|
|
12068
12103
|
thumbnailUrl: image.thumbnailUrl ?? image.imageUrl,
|
|
12069
12104
|
storageKey: image.storageKey,
|
|
@@ -12073,53 +12108,150 @@ function imageToCreativeReference(image, title) {
|
|
|
12073
12108
|
source: image.source
|
|
12074
12109
|
};
|
|
12075
12110
|
}
|
|
12076
|
-
|
|
12077
|
-
const
|
|
12078
|
-
|
|
12079
|
-
|
|
12111
|
+
function videoToCreativeReference(video, title) {
|
|
12112
|
+
const tags = uniqueTags([...video.tags, ...creativeTags]);
|
|
12113
|
+
return {
|
|
12114
|
+
type: "video",
|
|
12115
|
+
slug: video._id,
|
|
12116
|
+
title,
|
|
12117
|
+
body: video.description,
|
|
12118
|
+
tags,
|
|
12119
|
+
thumbnailUrl: video.thumbnailUrl,
|
|
12120
|
+
muxPlaybackId: video.muxPlaybackId,
|
|
12121
|
+
playbackUrl: video.muxPlaybackId ? `https://stream.mux.com/${video.muxPlaybackId}.m3u8` : void 0,
|
|
12122
|
+
duration: video.duration,
|
|
12123
|
+
width: video.width,
|
|
12124
|
+
height: video.height,
|
|
12125
|
+
aspectRatio: video.aspectRatio,
|
|
12126
|
+
source: video.source
|
|
12127
|
+
};
|
|
12128
|
+
}
|
|
12129
|
+
async function updateImageMetadata(deps, args) {
|
|
12130
|
+
await deps.post("/api/images/update-description", {
|
|
12131
|
+
imageId: args.imageId,
|
|
12132
|
+
name: args.title,
|
|
12133
|
+
description: args.body,
|
|
12134
|
+
tags: args.tags
|
|
12135
|
+
});
|
|
12136
|
+
}
|
|
12137
|
+
function createVideoUpload(deps) {
|
|
12138
|
+
return deps.post("/api/videos/upload", {});
|
|
12139
|
+
}
|
|
12140
|
+
function getVideo(deps, videoId) {
|
|
12141
|
+
return deps.get("/api/videos/get", { id: videoId });
|
|
12142
|
+
}
|
|
12143
|
+
async function updateVideoMetadata(deps, args) {
|
|
12144
|
+
await deps.post("/api/videos/update-description", {
|
|
12145
|
+
videoId: args.videoId,
|
|
12146
|
+
name: args.title,
|
|
12147
|
+
description: args.body,
|
|
12148
|
+
tags: args.tags
|
|
12149
|
+
});
|
|
12150
|
+
}
|
|
12151
|
+
async function waitForReadyVideo(deps, videoId, opts = {}) {
|
|
12152
|
+
const timeoutMs = opts.timeoutMs ?? videoProcessingTimeoutMs;
|
|
12153
|
+
const pollIntervalMs = opts.pollIntervalMs ?? videoReadyPollIntervalMs;
|
|
12154
|
+
const deadline = Date.now() + timeoutMs;
|
|
12155
|
+
let lastStatus = "unknown";
|
|
12156
|
+
while (Date.now() <= deadline) {
|
|
12157
|
+
const video = await getVideo(deps, videoId);
|
|
12158
|
+
lastStatus = video.status ?? "unknown";
|
|
12159
|
+
if (video.status === "ready") {
|
|
12160
|
+
return video;
|
|
12161
|
+
}
|
|
12162
|
+
if (video.status === "error") {
|
|
12163
|
+
throw new ApiError(
|
|
12164
|
+
"INTERNAL_ERROR",
|
|
12165
|
+
`Video processing failed for videoId ${videoId}: ${video.errorMessage ?? "unknown error"}`
|
|
12166
|
+
);
|
|
12167
|
+
}
|
|
12168
|
+
await deps.sleep(pollIntervalMs);
|
|
12169
|
+
}
|
|
12170
|
+
throw new ApiError("TIMEOUT", `Video was not ready before timeout; videoId: ${videoId}; last status: ${lastStatus}`);
|
|
12171
|
+
}
|
|
12172
|
+
async function uploadLocalVideo(args, deps) {
|
|
12173
|
+
const { uploadUrl, videoId } = await createVideoUpload(deps);
|
|
12174
|
+
const fileBuffer = await deps.readFile(args.file);
|
|
12175
|
+
const uploadResponse = await deps.fetch(uploadUrl, {
|
|
12176
|
+
method: "PUT",
|
|
12177
|
+
headers: { "Content-Type": args.contentType },
|
|
12178
|
+
body: fileBuffer
|
|
12179
|
+
});
|
|
12180
|
+
if (!uploadResponse.ok) {
|
|
12181
|
+
throw new ApiError(
|
|
12182
|
+
"INTERNAL_ERROR",
|
|
12183
|
+
`Mux upload failed: HTTP ${uploadResponse.status} ${uploadResponse.statusText}`
|
|
12184
|
+
);
|
|
12080
12185
|
}
|
|
12081
|
-
|
|
12186
|
+
return { videoId };
|
|
12187
|
+
}
|
|
12188
|
+
async function publishCreativeImage(args, deps) {
|
|
12082
12189
|
const upload = await uploadLocalImage(
|
|
12083
12190
|
{
|
|
12084
12191
|
file: args.file,
|
|
12085
|
-
contentType,
|
|
12192
|
+
contentType: args.contentType,
|
|
12086
12193
|
source: "ai_generated",
|
|
12087
|
-
descriptionContext: args.
|
|
12194
|
+
descriptionContext: args.body
|
|
12088
12195
|
},
|
|
12089
12196
|
deps
|
|
12090
12197
|
);
|
|
12091
12198
|
const readyImage = await waitForReadyImage(deps, upload.imageId, { timeoutMs: imageProcessingTimeoutMs });
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
addTags: [creativeTag],
|
|
12095
|
-
removeTags: []
|
|
12096
|
-
});
|
|
12199
|
+
const tags = uniqueTags([...readyImage.tags ?? [], ...creativeTags]);
|
|
12200
|
+
await updateImageMetadata(deps, { imageId: upload.imageId, title: args.title, body: args.body, tags });
|
|
12097
12201
|
const taggedImage = await getImage(deps, upload.imageId);
|
|
12098
|
-
return {
|
|
12202
|
+
return {
|
|
12203
|
+
imageId: upload.imageId,
|
|
12204
|
+
reference: imageToCreativeReference({ ...readyImage, ...taggedImage }, args.title)
|
|
12205
|
+
};
|
|
12206
|
+
}
|
|
12207
|
+
async function publishCreativeVideo(args, deps) {
|
|
12208
|
+
const { videoId } = await uploadLocalVideo({ file: args.file, contentType: args.contentType }, deps);
|
|
12209
|
+
const readyVideo = await waitForReadyVideo(deps, videoId);
|
|
12210
|
+
const tags = uniqueTags([...readyVideo.tags, ...creativeTags]);
|
|
12211
|
+
await updateVideoMetadata(deps, { videoId, title: args.title, body: args.body, tags });
|
|
12212
|
+
const taggedVideo = await getVideo(deps, videoId);
|
|
12213
|
+
return { videoId, reference: videoToCreativeReference(taggedVideo, args.title) };
|
|
12214
|
+
}
|
|
12215
|
+
function publishCreative(args, deps = defaultCreativePublishDeps) {
|
|
12216
|
+
try {
|
|
12217
|
+
const metadata = requiredMetadata(args);
|
|
12218
|
+
const contentType = detectCreativeContentType(args.file);
|
|
12219
|
+
if (isVideoContentType(contentType)) {
|
|
12220
|
+
return publishCreativeVideo({ file: args.file, ...metadata, contentType }, deps);
|
|
12221
|
+
}
|
|
12222
|
+
return publishCreativeImage({ file: args.file, ...metadata, contentType }, deps);
|
|
12223
|
+
} catch (error) {
|
|
12224
|
+
return Promise.reject(error);
|
|
12225
|
+
}
|
|
12099
12226
|
}
|
|
12100
12227
|
var publishCommand = defineCommand87({
|
|
12101
12228
|
meta: {
|
|
12102
12229
|
name: "publish",
|
|
12103
|
-
description: "Publish a final
|
|
12230
|
+
description: "Publish a final creative image or video, tag it as creative and winning-ads, and print the asset reference JSON."
|
|
12104
12231
|
},
|
|
12105
12232
|
args: {
|
|
12106
|
-
file: { type: "positional", description: "Local PNG/JPG/WebP creative
|
|
12233
|
+
file: { type: "positional", description: "Local PNG/JPG/WebP/MP4/MOV/WebM creative path", required: false },
|
|
12107
12234
|
title: { type: "string", description: "Human title for the creative output", required: false },
|
|
12108
|
-
|
|
12235
|
+
body: { type: "string", description: "Reference traceability body for the creative output", required: false }
|
|
12109
12236
|
},
|
|
12110
12237
|
run: async ({ args }) => {
|
|
12111
12238
|
try {
|
|
12112
12239
|
const file = args.file;
|
|
12113
12240
|
const title = args.title;
|
|
12241
|
+
const body = args.body;
|
|
12114
12242
|
if (!file) {
|
|
12115
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "
|
|
12243
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "File path is required" } });
|
|
12116
12244
|
process.exit(1);
|
|
12117
12245
|
}
|
|
12118
12246
|
if (!title) {
|
|
12119
12247
|
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "--title is required" } });
|
|
12120
12248
|
process.exit(1);
|
|
12121
12249
|
}
|
|
12122
|
-
|
|
12250
|
+
if (!body) {
|
|
12251
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "--body is required" } });
|
|
12252
|
+
process.exit(1);
|
|
12253
|
+
}
|
|
12254
|
+
const data = await publishCreative({ file, title, body });
|
|
12123
12255
|
writeJson({ ok: true, data });
|
|
12124
12256
|
} catch (err) {
|
|
12125
12257
|
if (err instanceof ApiError) {
|
|
@@ -12136,12 +12268,13 @@ var publishCommand = defineCommand87({
|
|
|
12136
12268
|
var creativesCommand3 = defineCommand88({
|
|
12137
12269
|
meta: {
|
|
12138
12270
|
name: "creatives",
|
|
12139
|
-
description: `Publish
|
|
12271
|
+
description: `Publish ad creatives as first-class Baker outputs.
|
|
12140
12272
|
|
|
12141
|
-
|
|
12142
|
-
baker creatives publish ./canvas/run/final.png --title "
|
|
12273
|
+
Creative handoff:
|
|
12274
|
+
baker creatives publish ./canvas/run/final.png --title "Winning Ads: Offer + Meta 4:5 + Angle" --body "Reference: Advertiser[ad_id]: https://example.com/ad.mp4
|
|
12275
|
+
Angle adapted: Client-safe angle"
|
|
12143
12276
|
|
|
12144
|
-
Publishing
|
|
12277
|
+
Publishing routes images to Images and videos to the video library, applies creative + winning-ads tags, and returns an asset reference for chat previews.`
|
|
12145
12278
|
},
|
|
12146
12279
|
subCommands: {
|
|
12147
12280
|
publish: publishCommand
|
|
@@ -12979,7 +13112,7 @@ function cropSprite(input, region) {
|
|
|
12979
13112
|
// src/lib/image/io.ts
|
|
12980
13113
|
import { randomBytes } from "crypto";
|
|
12981
13114
|
import { glob as fsGlob, readFile as readFile10, rename, stat as stat2, writeFile as writeFile4 } from "fs/promises";
|
|
12982
|
-
import { dirname, extname as
|
|
13115
|
+
import { dirname, extname as extname3, join as join3, resolve as resolve4 } from "path";
|
|
12983
13116
|
var REMOTE_RE = /^https?:\/\//i;
|
|
12984
13117
|
var GLOB_RE = /[*?[\]{}]/;
|
|
12985
13118
|
function isRemoteUrl(value) {
|
|
@@ -13025,7 +13158,7 @@ async function isDirectory(path11) {
|
|
|
13025
13158
|
}
|
|
13026
13159
|
}
|
|
13027
13160
|
async function resolveOutputPath(inputPath, outputArg, options) {
|
|
13028
|
-
const base = options.newExtension ? inputPath.slice(0, -
|
|
13161
|
+
const base = options.newExtension ? inputPath.slice(0, -extname3(inputPath).length) + options.newExtension : inputPath;
|
|
13029
13162
|
if (!outputArg) return base;
|
|
13030
13163
|
if (options.multipleInputs || await isDirectory(outputArg)) {
|
|
13031
13164
|
const filename = base.split("/").pop() ?? "out.png";
|
|
@@ -16485,6 +16618,16 @@ function validateScheduledActionRef(ref) {
|
|
|
16485
16618
|
function isNoSpawnAgentFlagSet(args) {
|
|
16486
16619
|
return args["no-spawn-agent"] === true || args.noSpawnAgent === true || args.spawnAgent === false;
|
|
16487
16620
|
}
|
|
16621
|
+
function isPromptWithoutAgent(args, agentDisabled) {
|
|
16622
|
+
return agentDisabled && typeof args.prompt === "string";
|
|
16623
|
+
}
|
|
16624
|
+
function failIfPromptWithoutAgent(args, agentDisabled) {
|
|
16625
|
+
if (isPromptWithoutAgent(args, agentDisabled)) {
|
|
16626
|
+
failValidation2(
|
|
16627
|
+
"--prompt only applies when an agent is spawned; it has no effect with --no-spawn-agent or --spawn-agent false."
|
|
16628
|
+
);
|
|
16629
|
+
}
|
|
16630
|
+
}
|
|
16488
16631
|
function parseBooleanFlag(raw, flagName) {
|
|
16489
16632
|
if (raw === void 0) {
|
|
16490
16633
|
return void 0;
|
|
@@ -16577,6 +16720,7 @@ var createCommand2 = defineCommand132({
|
|
|
16577
16720
|
const schedule = buildScheduleBody(args, { required: true });
|
|
16578
16721
|
const chatId = requireChatId();
|
|
16579
16722
|
const noSpawnAgent = isNoSpawnAgentFlagSet(args);
|
|
16723
|
+
failIfPromptWithoutAgent(args, noSpawnAgent);
|
|
16580
16724
|
const body = {
|
|
16581
16725
|
chatId,
|
|
16582
16726
|
name,
|
|
@@ -16827,6 +16971,7 @@ var updateCommand2 = defineCommand137({
|
|
|
16827
16971
|
body.spawnAgent = spawnAgent;
|
|
16828
16972
|
hasPatch = true;
|
|
16829
16973
|
}
|
|
16974
|
+
failIfPromptWithoutAgent(args, spawnAgent === false);
|
|
16830
16975
|
if (typeof args.prompt === "string") {
|
|
16831
16976
|
body.agentPrompt = args.prompt;
|
|
16832
16977
|
hasPatch = true;
|
|
@@ -17326,7 +17471,7 @@ var tagsCommand4 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
|
17326
17471
|
|
|
17327
17472
|
// src/commands/videos/upload.ts
|
|
17328
17473
|
import { readFile as readFile12, stat as stat3 } from "fs/promises";
|
|
17329
|
-
import { extname as
|
|
17474
|
+
import { extname as extname4 } from "path";
|
|
17330
17475
|
import { defineCommand as defineCommand147 } from "citty";
|
|
17331
17476
|
var MIME_MAP = {
|
|
17332
17477
|
".mp4": "video/mp4",
|
|
@@ -17354,7 +17499,7 @@ registerSchema({
|
|
|
17354
17499
|
}
|
|
17355
17500
|
});
|
|
17356
17501
|
function detectContentType(filePath) {
|
|
17357
|
-
const ext =
|
|
17502
|
+
const ext = extname4(filePath).toLowerCase();
|
|
17358
17503
|
const mime = MIME_MAP[ext];
|
|
17359
17504
|
if (!mime) {
|
|
17360
17505
|
throw new ApiError("VALIDATION_ERROR", `Cannot detect content type for extension "${ext}". Use --content-type.`);
|
|
@@ -17506,6 +17651,7 @@ var advertisersCommand2 = defineCommand149({
|
|
|
17506
17651
|
|
|
17507
17652
|
// src/commands/winning-ads/search.ts
|
|
17508
17653
|
import { defineCommand as defineCommand150 } from "citty";
|
|
17654
|
+
import { z as z4 } from "zod";
|
|
17509
17655
|
registerSchema({
|
|
17510
17656
|
command: "winning-ads.search",
|
|
17511
17657
|
description: "Search the ad-dna corpus of scored winning ads. Returns a lean shortlist (advertiser, summary, scores, media_url) to pick a reference to reproduce.",
|
|
@@ -17613,6 +17759,38 @@ function buildSearchBody(args) {
|
|
|
17613
17759
|
}
|
|
17614
17760
|
return body;
|
|
17615
17761
|
}
|
|
17762
|
+
function toOutputRecord(value) {
|
|
17763
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
17764
|
+
return {};
|
|
17765
|
+
}
|
|
17766
|
+
return Object.fromEntries(Object.entries(value));
|
|
17767
|
+
}
|
|
17768
|
+
var winningAdsSearchResponseSchema = z4.object({
|
|
17769
|
+
results: z4.array(z4.unknown()).optional(),
|
|
17770
|
+
pool_size: z4.number().nullable().optional(),
|
|
17771
|
+
match_confidence: z4.string().nullable().optional(),
|
|
17772
|
+
ownAdvertiserExclusion: z4.object({
|
|
17773
|
+
status: z4.enum(["applied", "unresolved", "skipped"]),
|
|
17774
|
+
excludedIds: z4.array(z4.string())
|
|
17775
|
+
}).nullable().optional()
|
|
17776
|
+
});
|
|
17777
|
+
function parseWinningAdsSearchResponse(data) {
|
|
17778
|
+
const parsed = winningAdsSearchResponseSchema.safeParse(data);
|
|
17779
|
+
if (!parsed.success) {
|
|
17780
|
+
throw new ApiError("INTERNAL_ERROR", "Invalid winning ads search response");
|
|
17781
|
+
}
|
|
17782
|
+
return parsed.data;
|
|
17783
|
+
}
|
|
17784
|
+
function buildSearchOutputData(data, options) {
|
|
17785
|
+
const rawResults = Array.isArray(data?.results) ? data.results : [];
|
|
17786
|
+
const results = rawResults.map((r) => winningAdNormalizer(toOutputRecord(r), options.full));
|
|
17787
|
+
return {
|
|
17788
|
+
results,
|
|
17789
|
+
pool_size: data?.pool_size ?? null,
|
|
17790
|
+
match_confidence: data?.match_confidence ?? null,
|
|
17791
|
+
ownAdvertiserExclusion: data?.ownAdvertiserExclusion ?? null
|
|
17792
|
+
};
|
|
17793
|
+
}
|
|
17616
17794
|
var searchCommand4 = defineCommand150({
|
|
17617
17795
|
meta: {
|
|
17618
17796
|
name: "search",
|
|
@@ -17691,19 +17869,12 @@ var searchCommand4 = defineCommand150({
|
|
|
17691
17869
|
});
|
|
17692
17870
|
process.exit(1);
|
|
17693
17871
|
}
|
|
17694
|
-
const data = await apiPost(
|
|
17695
|
-
"/api/winning-ads/search",
|
|
17696
|
-
body
|
|
17697
|
-
);
|
|
17872
|
+
const data = parseWinningAdsSearchResponse(await apiPost("/api/winning-ads/search", body));
|
|
17698
17873
|
const output = args.output || "json";
|
|
17699
17874
|
const full = args.full;
|
|
17700
17875
|
const rawResults = Array.isArray(data?.results) ? data.results : [];
|
|
17701
17876
|
if (output === "json") {
|
|
17702
|
-
|
|
17703
|
-
writeJson({
|
|
17704
|
-
ok: true,
|
|
17705
|
-
data: { results, pool_size: data?.pool_size ?? null, match_confidence: data?.match_confidence ?? null }
|
|
17706
|
-
});
|
|
17877
|
+
writeJson({ ok: true, data: buildSearchOutputData(data, { full }) });
|
|
17707
17878
|
return;
|
|
17708
17879
|
}
|
|
17709
17880
|
writeOutput(
|