@productmaker/mcp 8.7.0 → 8.7.1

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.
Files changed (3) hide show
  1. package/dist/http.js +120 -64
  2. package/dist/stdio.js +120 -64
  3. package/package.json +1 -1
package/dist/http.js CHANGED
@@ -5189,8 +5189,10 @@ var VideoGenerator = z27.object({
5189
5189
  // `result.ts`. Write-side caps (angle.ts, wizard.ts, task-creative-variants.ts)
5190
5190
  // intentionally stay at 360.
5191
5191
  buyerPersona: z27.string().min(1).max(1200).optional(),
5192
- script: z27.string().min(1),
5193
- prompt: z27.string().min(1),
5192
+ // Read contract: pending/pre-plan failed rows have no authored text yet.
5193
+ // Preserve their empty fields and outcome; successful rows are checked below.
5194
+ script: z27.string(),
5195
+ prompt: z27.string(),
5194
5196
  // Empty string allowed: Pro pipeline pauses for script review BEFORE the grid
5195
5197
  // extraction that produces the Frame A URL; imageUrl stays '' until then.
5196
5198
  imageUrl: z27.string().url().or(z27.literal("")),
@@ -5216,11 +5218,29 @@ var VideoGenerator = z27.object({
5216
5218
  execution: VideoExecutionContract.optional(),
5217
5219
  adCopy: z27.string().optional(),
5218
5220
  /** TRUE when the seller APPROVED a script for this angle that the plan path
5219
- * could not honor, so a fresh script was re-authored and rendered instead
5220
- * (PR #1470). The angle still delivered — nothing was lost and nothing is
5221
- * refundable — but the video is NOT the script they signed off on, and the
5222
- * UI must say so. Absent (never `false`) on every honest delivery. */
5221
+ * could not honor, so a fresh script was re-authored and rendered instead
5222
+ * (PR #1470). The angle still delivered — nothing was lost and nothing is
5223
+ * refundable — but the video is NOT the script they signed off on, and the
5224
+ * UI must say so. Absent (never `false`) on every honest delivery. */
5223
5225
  scriptRewritten: z27.boolean().optional()
5226
+ }).superRefine((record, ctx) => {
5227
+ if (record.status !== "success") return;
5228
+ for (const field of [
5229
+ "script",
5230
+ "prompt"
5231
+ ]) {
5232
+ if (record[field].length > 0) continue;
5233
+ ctx.addIssue({
5234
+ code: z27.ZodIssueCode.too_small,
5235
+ minimum: 1,
5236
+ type: "string",
5237
+ inclusive: true,
5238
+ path: [
5239
+ field
5240
+ ],
5241
+ message: "Successful video results require authored text"
5242
+ });
5243
+ }
5224
5244
  });
5225
5245
  var VideoScriptSceneForReview = z27.object({
5226
5246
  index: z27.number().int().nonnegative(),
@@ -10946,71 +10966,106 @@ var MixAxes = z51.object({
10946
10966
  person: z51.boolean(),
10947
10967
  setting: z51.boolean()
10948
10968
  });
10949
- var MixReferences = z51.object({
10950
- product: z51.array(PublicHttpsUrl).max(3, "at most 3 product references"),
10951
- person: z51.array(PublicHttpsUrl).max(3, "at most 3 person references"),
10952
- setting: z51.array(PublicHttpsUrl).max(3, "at most 3 setting references")
10953
- });
10969
+ function createMixReferences(url) {
10970
+ return z51.object({
10971
+ product: z51.array(url).max(3, "at most 3 product references"),
10972
+ person: z51.array(url).max(3, "at most 3 person references"),
10973
+ setting: z51.array(url).max(3, "at most 3 setting references")
10974
+ });
10975
+ }
10976
+ __name(createMixReferences, "createMixReferences");
10977
+ var MixReferences = createMixReferences(PublicHttpsUrl);
10978
+ var MAX_VIDEO_MIX_REFERENCE_IMAGES = 5;
10979
+ function countGeneratedVideoMixReferences(axes, references) {
10980
+ return Number(axes.person && references.person.length === 0) + Number(axes.setting && references.setting.length === 0);
10981
+ }
10982
+ __name(countGeneratedVideoMixReferences, "countGeneratedVideoMixReferences");
10983
+ function countVideoMixReferenceImages(axes, references) {
10984
+ return (axes.product ? references.product.length : 0) + (axes.person ? references.person.length : 0) + (axes.setting ? references.setting.length : 0) + countGeneratedVideoMixReferences(axes, references);
10985
+ }
10986
+ __name(countVideoMixReferenceImages, "countVideoMixReferenceImages");
10954
10987
  var MixImageEdit = z51.object({
10955
10988
  instruction: z51.string().min(1).max(600),
10956
10989
  imageUrls: z51.array(MixImageUrl).min(1).max(3)
10957
10990
  });
10958
- var MixRequest = z51.object({
10959
- mediaType: z51.enum(MEDIA_TYPES),
10960
- originalUrl: z51.union([
10961
- PublicHttpsUrl,
10962
- InternalAssetPath
10963
- ]),
10964
- axes: MixAxes,
10965
- references: MixReferences,
10966
- personText: z51.string().max(500).optional(),
10967
- settingText: z51.string().max(500).optional(),
10968
- /**
10969
- * Optional public URL of a user-uploaded audio file (mp3/wav). Wan Video
10970
- * Edit has no audio input and the mix never lipsyncs: the Wan output is
10971
- * muted and, when this is set, the assemble worker mux'es THIS audio
10972
- * (instead of the original video's track) into the final concatenated mp4
10973
- * (mute + overlay). No per-scene slicing, no `reference_audio_urls`.
10974
- */
10975
- audioUrl: PublicHttpsUrl.optional(),
10976
- resolution: z51.enum(RESOLUTIONS).default("720p"),
10977
- originalDurationSec: z51.number().positive().max(600).optional(),
10978
- image: MixImageEdit.optional(),
10979
- sourceTaskId: z51.string().max(64).optional(),
10980
- sourceCreativeId: z51.string().max(64).optional()
10981
- }).superRefine((req, ctx) => {
10982
- if (req.mediaType === "image") {
10983
- if (!req.image) {
10991
+ function createMixRequestSchema(allowAdditionalUrl) {
10992
+ const acceptsUrl = /* @__PURE__ */ __name((url) => isPublicHttpsUrl(url) || Boolean(allowAdditionalUrl?.(url)), "acceptsUrl");
10993
+ const acceptedUrl = z51.string().url().refine(acceptsUrl, {
10994
+ message: "must be a public HTTPS URL"
10995
+ });
10996
+ return z51.object({
10997
+ mediaType: z51.enum(MEDIA_TYPES),
10998
+ originalUrl: z51.union([
10999
+ acceptedUrl,
11000
+ InternalAssetPath
11001
+ ]),
11002
+ axes: MixAxes,
11003
+ references: createMixReferences(acceptedUrl),
11004
+ personText: z51.string().max(500).optional(),
11005
+ settingText: z51.string().max(500).optional(),
11006
+ /**
11007
+ * Optional public URL of a user-uploaded audio file (mp3/wav). Wan Video
11008
+ * Edit has no audio input and the mix never lipsyncs: the Wan output is
11009
+ * muted and, when this is set, the assemble worker mux'es THIS audio
11010
+ * (instead of the original video's track) into the final concatenated mp4
11011
+ * (mute + overlay). No per-scene slicing, no `reference_audio_urls`.
11012
+ */
11013
+ audioUrl: acceptedUrl.optional(),
11014
+ resolution: z51.enum(RESOLUTIONS).default("720p"),
11015
+ originalDurationSec: z51.number().positive().max(600).optional(),
11016
+ image: MixImageEdit.extend({
11017
+ imageUrls: z51.array(z51.union([
11018
+ acceptedUrl,
11019
+ InternalAssetPath
11020
+ ])).min(1).max(3)
11021
+ }).optional(),
11022
+ sourceTaskId: z51.string().max(64).optional(),
11023
+ sourceCreativeId: z51.string().max(64).optional()
11024
+ }).superRefine((req, ctx) => {
11025
+ if (req.mediaType === "image") {
11026
+ if (!req.image) {
11027
+ ctx.addIssue({
11028
+ code: "custom",
11029
+ message: "image mix requires an image edit (instruction + 1-3 images)"
11030
+ });
11031
+ }
11032
+ return;
11033
+ }
11034
+ if (!acceptsUrl(req.originalUrl)) {
10984
11035
  ctx.addIssue({
10985
11036
  code: "custom",
10986
- message: "image mix requires an image edit (instruction + 1-3 images)"
11037
+ path: [
11038
+ "originalUrl"
11039
+ ],
11040
+ message: "must be a public HTTPS URL"
10987
11041
  });
10988
11042
  }
10989
- return;
10990
- }
10991
- if (!isPublicHttpsUrl(req.originalUrl)) {
10992
- ctx.addIssue({
10993
- code: "custom",
10994
- path: [
10995
- "originalUrl"
10996
- ],
10997
- message: "must be a public HTTPS URL"
10998
- });
10999
- }
11000
- if (req.axes.product && req.references.product.length === 0) {
11001
- ctx.addIssue({
11002
- code: "custom",
11003
- message: "product references required when product axis active"
11004
- });
11005
- }
11006
- const anyAxis = req.axes.product || req.axes.person || req.axes.setting;
11007
- if (!anyAxis && !req.audioUrl) {
11008
- ctx.addIssue({
11009
- code: "custom",
11010
- message: "mix requires at least one axis to swap or a user audio"
11011
- });
11012
- }
11013
- });
11043
+ if (req.axes.product && req.references.product.length === 0) {
11044
+ ctx.addIssue({
11045
+ code: "custom",
11046
+ message: "product references required when product axis active"
11047
+ });
11048
+ }
11049
+ if (countVideoMixReferenceImages(req.axes, req.references) > MAX_VIDEO_MIX_REFERENCE_IMAGES) {
11050
+ ctx.addIssue({
11051
+ code: "custom",
11052
+ path: [
11053
+ "references"
11054
+ ],
11055
+ message: `video mix accepts at most ${MAX_VIDEO_MIX_REFERENCE_IMAGES} reference images, including generated axes`
11056
+ });
11057
+ }
11058
+ const anyAxis = req.axes.product || req.axes.person || req.axes.setting;
11059
+ if (!anyAxis && !req.audioUrl) {
11060
+ ctx.addIssue({
11061
+ code: "custom",
11062
+ message: "mix requires at least one axis to swap or a user audio"
11063
+ });
11064
+ }
11065
+ });
11066
+ }
11067
+ __name(createMixRequestSchema, "createMixRequestSchema");
11068
+ var MixRequest = createMixRequestSchema();
11014
11069
  var ReferenceMap = z51.object({
11015
11070
  product: z51.object({
11016
11071
  start: z51.number().int(),
@@ -11110,6 +11165,7 @@ var MixResult = z51.object({
11110
11165
  });
11111
11166
 
11112
11167
  // ../../packages/types/src/mix-cost.ts
11168
+ var IMAGE_GEN_USER_PRICE_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2-5-sunburst-text-to-image"].userPriceCents;
11113
11169
  var MAX_QA_RETRIES_PER_SCENE_UPPER_BOUND = 1;
11114
11170
  var MAX_BILLABLE_GENERATIONS_PER_BLOCK = 1 + MAX_QA_RETRIES_PER_SCENE_UPPER_BOUND;
11115
11171
 
@@ -18628,7 +18684,7 @@ var ApiClient = class {
18628
18684
  };
18629
18685
 
18630
18686
  // src/index.ts
18631
- var MCP_VERSION = "8.7.0";
18687
+ var MCP_VERSION = "8.7.1";
18632
18688
 
18633
18689
  // src/meta-upload-app.ts
18634
18690
  import { readFileSync } from "fs";
package/dist/stdio.js CHANGED
@@ -5211,8 +5211,10 @@ var VideoGenerator = z27.object({
5211
5211
  // `result.ts`. Write-side caps (angle.ts, wizard.ts, task-creative-variants.ts)
5212
5212
  // intentionally stay at 360.
5213
5213
  buyerPersona: z27.string().min(1).max(1200).optional(),
5214
- script: z27.string().min(1),
5215
- prompt: z27.string().min(1),
5214
+ // Read contract: pending/pre-plan failed rows have no authored text yet.
5215
+ // Preserve their empty fields and outcome; successful rows are checked below.
5216
+ script: z27.string(),
5217
+ prompt: z27.string(),
5216
5218
  // Empty string allowed: Pro pipeline pauses for script review BEFORE the grid
5217
5219
  // extraction that produces the Frame A URL; imageUrl stays '' until then.
5218
5220
  imageUrl: z27.string().url().or(z27.literal("")),
@@ -5238,11 +5240,29 @@ var VideoGenerator = z27.object({
5238
5240
  execution: VideoExecutionContract.optional(),
5239
5241
  adCopy: z27.string().optional(),
5240
5242
  /** TRUE when the seller APPROVED a script for this angle that the plan path
5241
- * could not honor, so a fresh script was re-authored and rendered instead
5242
- * (PR #1470). The angle still delivered — nothing was lost and nothing is
5243
- * refundable — but the video is NOT the script they signed off on, and the
5244
- * UI must say so. Absent (never `false`) on every honest delivery. */
5243
+ * could not honor, so a fresh script was re-authored and rendered instead
5244
+ * (PR #1470). The angle still delivered — nothing was lost and nothing is
5245
+ * refundable — but the video is NOT the script they signed off on, and the
5246
+ * UI must say so. Absent (never `false`) on every honest delivery. */
5245
5247
  scriptRewritten: z27.boolean().optional()
5248
+ }).superRefine((record, ctx) => {
5249
+ if (record.status !== "success") return;
5250
+ for (const field of [
5251
+ "script",
5252
+ "prompt"
5253
+ ]) {
5254
+ if (record[field].length > 0) continue;
5255
+ ctx.addIssue({
5256
+ code: z27.ZodIssueCode.too_small,
5257
+ minimum: 1,
5258
+ type: "string",
5259
+ inclusive: true,
5260
+ path: [
5261
+ field
5262
+ ],
5263
+ message: "Successful video results require authored text"
5264
+ });
5265
+ }
5246
5266
  });
5247
5267
  var VideoScriptSceneForReview = z27.object({
5248
5268
  index: z27.number().int().nonnegative(),
@@ -10968,71 +10988,106 @@ var MixAxes = z51.object({
10968
10988
  person: z51.boolean(),
10969
10989
  setting: z51.boolean()
10970
10990
  });
10971
- var MixReferences = z51.object({
10972
- product: z51.array(PublicHttpsUrl).max(3, "at most 3 product references"),
10973
- person: z51.array(PublicHttpsUrl).max(3, "at most 3 person references"),
10974
- setting: z51.array(PublicHttpsUrl).max(3, "at most 3 setting references")
10975
- });
10991
+ function createMixReferences(url) {
10992
+ return z51.object({
10993
+ product: z51.array(url).max(3, "at most 3 product references"),
10994
+ person: z51.array(url).max(3, "at most 3 person references"),
10995
+ setting: z51.array(url).max(3, "at most 3 setting references")
10996
+ });
10997
+ }
10998
+ __name(createMixReferences, "createMixReferences");
10999
+ var MixReferences = createMixReferences(PublicHttpsUrl);
11000
+ var MAX_VIDEO_MIX_REFERENCE_IMAGES = 5;
11001
+ function countGeneratedVideoMixReferences(axes, references) {
11002
+ return Number(axes.person && references.person.length === 0) + Number(axes.setting && references.setting.length === 0);
11003
+ }
11004
+ __name(countGeneratedVideoMixReferences, "countGeneratedVideoMixReferences");
11005
+ function countVideoMixReferenceImages(axes, references) {
11006
+ return (axes.product ? references.product.length : 0) + (axes.person ? references.person.length : 0) + (axes.setting ? references.setting.length : 0) + countGeneratedVideoMixReferences(axes, references);
11007
+ }
11008
+ __name(countVideoMixReferenceImages, "countVideoMixReferenceImages");
10976
11009
  var MixImageEdit = z51.object({
10977
11010
  instruction: z51.string().min(1).max(600),
10978
11011
  imageUrls: z51.array(MixImageUrl).min(1).max(3)
10979
11012
  });
10980
- var MixRequest = z51.object({
10981
- mediaType: z51.enum(MEDIA_TYPES),
10982
- originalUrl: z51.union([
10983
- PublicHttpsUrl,
10984
- InternalAssetPath
10985
- ]),
10986
- axes: MixAxes,
10987
- references: MixReferences,
10988
- personText: z51.string().max(500).optional(),
10989
- settingText: z51.string().max(500).optional(),
10990
- /**
10991
- * Optional public URL of a user-uploaded audio file (mp3/wav). Wan Video
10992
- * Edit has no audio input and the mix never lipsyncs: the Wan output is
10993
- * muted and, when this is set, the assemble worker mux'es THIS audio
10994
- * (instead of the original video's track) into the final concatenated mp4
10995
- * (mute + overlay). No per-scene slicing, no `reference_audio_urls`.
10996
- */
10997
- audioUrl: PublicHttpsUrl.optional(),
10998
- resolution: z51.enum(RESOLUTIONS).default("720p"),
10999
- originalDurationSec: z51.number().positive().max(600).optional(),
11000
- image: MixImageEdit.optional(),
11001
- sourceTaskId: z51.string().max(64).optional(),
11002
- sourceCreativeId: z51.string().max(64).optional()
11003
- }).superRefine((req, ctx) => {
11004
- if (req.mediaType === "image") {
11005
- if (!req.image) {
11013
+ function createMixRequestSchema(allowAdditionalUrl) {
11014
+ const acceptsUrl = /* @__PURE__ */ __name((url) => isPublicHttpsUrl(url) || Boolean(allowAdditionalUrl?.(url)), "acceptsUrl");
11015
+ const acceptedUrl = z51.string().url().refine(acceptsUrl, {
11016
+ message: "must be a public HTTPS URL"
11017
+ });
11018
+ return z51.object({
11019
+ mediaType: z51.enum(MEDIA_TYPES),
11020
+ originalUrl: z51.union([
11021
+ acceptedUrl,
11022
+ InternalAssetPath
11023
+ ]),
11024
+ axes: MixAxes,
11025
+ references: createMixReferences(acceptedUrl),
11026
+ personText: z51.string().max(500).optional(),
11027
+ settingText: z51.string().max(500).optional(),
11028
+ /**
11029
+ * Optional public URL of a user-uploaded audio file (mp3/wav). Wan Video
11030
+ * Edit has no audio input and the mix never lipsyncs: the Wan output is
11031
+ * muted and, when this is set, the assemble worker mux'es THIS audio
11032
+ * (instead of the original video's track) into the final concatenated mp4
11033
+ * (mute + overlay). No per-scene slicing, no `reference_audio_urls`.
11034
+ */
11035
+ audioUrl: acceptedUrl.optional(),
11036
+ resolution: z51.enum(RESOLUTIONS).default("720p"),
11037
+ originalDurationSec: z51.number().positive().max(600).optional(),
11038
+ image: MixImageEdit.extend({
11039
+ imageUrls: z51.array(z51.union([
11040
+ acceptedUrl,
11041
+ InternalAssetPath
11042
+ ])).min(1).max(3)
11043
+ }).optional(),
11044
+ sourceTaskId: z51.string().max(64).optional(),
11045
+ sourceCreativeId: z51.string().max(64).optional()
11046
+ }).superRefine((req, ctx) => {
11047
+ if (req.mediaType === "image") {
11048
+ if (!req.image) {
11049
+ ctx.addIssue({
11050
+ code: "custom",
11051
+ message: "image mix requires an image edit (instruction + 1-3 images)"
11052
+ });
11053
+ }
11054
+ return;
11055
+ }
11056
+ if (!acceptsUrl(req.originalUrl)) {
11006
11057
  ctx.addIssue({
11007
11058
  code: "custom",
11008
- message: "image mix requires an image edit (instruction + 1-3 images)"
11059
+ path: [
11060
+ "originalUrl"
11061
+ ],
11062
+ message: "must be a public HTTPS URL"
11009
11063
  });
11010
11064
  }
11011
- return;
11012
- }
11013
- if (!isPublicHttpsUrl(req.originalUrl)) {
11014
- ctx.addIssue({
11015
- code: "custom",
11016
- path: [
11017
- "originalUrl"
11018
- ],
11019
- message: "must be a public HTTPS URL"
11020
- });
11021
- }
11022
- if (req.axes.product && req.references.product.length === 0) {
11023
- ctx.addIssue({
11024
- code: "custom",
11025
- message: "product references required when product axis active"
11026
- });
11027
- }
11028
- const anyAxis = req.axes.product || req.axes.person || req.axes.setting;
11029
- if (!anyAxis && !req.audioUrl) {
11030
- ctx.addIssue({
11031
- code: "custom",
11032
- message: "mix requires at least one axis to swap or a user audio"
11033
- });
11034
- }
11035
- });
11065
+ if (req.axes.product && req.references.product.length === 0) {
11066
+ ctx.addIssue({
11067
+ code: "custom",
11068
+ message: "product references required when product axis active"
11069
+ });
11070
+ }
11071
+ if (countVideoMixReferenceImages(req.axes, req.references) > MAX_VIDEO_MIX_REFERENCE_IMAGES) {
11072
+ ctx.addIssue({
11073
+ code: "custom",
11074
+ path: [
11075
+ "references"
11076
+ ],
11077
+ message: `video mix accepts at most ${MAX_VIDEO_MIX_REFERENCE_IMAGES} reference images, including generated axes`
11078
+ });
11079
+ }
11080
+ const anyAxis = req.axes.product || req.axes.person || req.axes.setting;
11081
+ if (!anyAxis && !req.audioUrl) {
11082
+ ctx.addIssue({
11083
+ code: "custom",
11084
+ message: "mix requires at least one axis to swap or a user audio"
11085
+ });
11086
+ }
11087
+ });
11088
+ }
11089
+ __name(createMixRequestSchema, "createMixRequestSchema");
11090
+ var MixRequest = createMixRequestSchema();
11036
11091
  var ReferenceMap = z51.object({
11037
11092
  product: z51.object({
11038
11093
  start: z51.number().int(),
@@ -11132,6 +11187,7 @@ var MixResult = z51.object({
11132
11187
  });
11133
11188
 
11134
11189
  // ../../packages/types/src/mix-cost.ts
11190
+ var IMAGE_GEN_USER_PRICE_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2-5-sunburst-text-to-image"].userPriceCents;
11135
11191
  var MAX_QA_RETRIES_PER_SCENE_UPPER_BOUND = 1;
11136
11192
  var MAX_BILLABLE_GENERATIONS_PER_BLOCK = 1 + MAX_QA_RETRIES_PER_SCENE_UPPER_BOUND;
11137
11193
 
@@ -16960,7 +17016,7 @@ var ApiClient = class {
16960
17016
  };
16961
17017
 
16962
17018
  // src/index.ts
16963
- var MCP_VERSION = "8.7.0";
17019
+ var MCP_VERSION = "8.7.1";
16964
17020
 
16965
17021
  // src/meta-upload-app.ts
16966
17022
  import { readFileSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "8.7.0",
3
+ "version": "8.7.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "ProductMaker MCP server — cost products, generate landing pages, UGC videos, and ad creatives, and publish to Shopify, Meta Ads, and TikTok Ads.",