@productmaker/mcp 11.5.4 → 11.5.6
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/dist/http.js +503 -302
- package/dist/stdio.js +253 -52
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -8403,7 +8403,9 @@ var CampaignCopyEstimationOptions = z40.object({
|
|
|
8403
8403
|
/** Number of image creatives that can each use one vision analysis (0-10). */
|
|
8404
8404
|
nImages: z40.number().int().min(0).max(10).default(0)
|
|
8405
8405
|
});
|
|
8406
|
-
var BrandExtractEstimationOptions = z40.object({
|
|
8406
|
+
var BrandExtractEstimationOptions = z40.object({
|
|
8407
|
+
sourceUrl: z40.string().url().optional()
|
|
8408
|
+
}).strict();
|
|
8407
8409
|
var PersonaSuggestEstimationOptions = z40.object({}).strict();
|
|
8408
8410
|
var ChatParseEstimationOptions = z40.object({}).strict();
|
|
8409
8411
|
var CodeLandingEditEstimationOptions = z40.object({}).strict();
|
|
@@ -9858,10 +9860,476 @@ var TikTokCreateCampaignResponseSchema = z52.object({
|
|
|
9858
9860
|
var GEMINI_OMNI_FLAT_OUR_COST_CENTS = 84;
|
|
9859
9861
|
var GEMINI_OMNI_FLAT_USER_PRICE_CENTS = 168;
|
|
9860
9862
|
|
|
9863
|
+
// ../../packages/types/src/public-host.ts
|
|
9864
|
+
function normalizeHostname(value) {
|
|
9865
|
+
const normalized = value.trim().toLowerCase().replace(/\.+$/, "");
|
|
9866
|
+
return normalized.startsWith("[") && normalized.endsWith("]") ? normalized.slice(1, -1) : normalized;
|
|
9867
|
+
}
|
|
9868
|
+
__name(normalizeHostname, "normalizeHostname");
|
|
9869
|
+
function parseIpv4(address) {
|
|
9870
|
+
const octets = address.split(".");
|
|
9871
|
+
if (octets.length !== 4 || !octets.every((octet) => /^(0|[1-9]\d{0,2})$/.test(octet))) {
|
|
9872
|
+
return null;
|
|
9873
|
+
}
|
|
9874
|
+
const parsedOctets = octets.map(Number);
|
|
9875
|
+
if (parsedOctets.some((octet) => octet > 255)) return null;
|
|
9876
|
+
const [first, second, third, fourth] = parsedOctets;
|
|
9877
|
+
if (first === void 0 || second === void 0 || third === void 0 || fourth === void 0) {
|
|
9878
|
+
return null;
|
|
9879
|
+
}
|
|
9880
|
+
return [
|
|
9881
|
+
first,
|
|
9882
|
+
second,
|
|
9883
|
+
third,
|
|
9884
|
+
fourth
|
|
9885
|
+
];
|
|
9886
|
+
}
|
|
9887
|
+
__name(parseIpv4, "parseIpv4");
|
|
9888
|
+
function isPublicIpv4Octets([first, second, third]) {
|
|
9889
|
+
if (first === 0 || first === 10 || first === 127 || first >= 224) return false;
|
|
9890
|
+
if (first === 100 && second >= 64 && second <= 127) return false;
|
|
9891
|
+
if (first === 169 && second === 254) return false;
|
|
9892
|
+
if (first === 172 && second >= 16 && second <= 31) return false;
|
|
9893
|
+
if (first === 192 && second === 0 && (third === 0 || third === 2)) return false;
|
|
9894
|
+
if (first === 192 && second === 88 && third === 99) return false;
|
|
9895
|
+
if (first === 192 && second === 168) return false;
|
|
9896
|
+
if (first === 198 && (second === 18 || second === 19)) return false;
|
|
9897
|
+
if (first === 198 && second === 51 && third === 100) return false;
|
|
9898
|
+
if (first === 203 && second === 0 && third === 113) return false;
|
|
9899
|
+
return true;
|
|
9900
|
+
}
|
|
9901
|
+
__name(isPublicIpv4Octets, "isPublicIpv4Octets");
|
|
9902
|
+
function parseIpv6Hextets(address) {
|
|
9903
|
+
let normalized = address;
|
|
9904
|
+
const lastColon = normalized.lastIndexOf(":");
|
|
9905
|
+
const finalPart = normalized.slice(lastColon + 1);
|
|
9906
|
+
if (finalPart.includes(".")) {
|
|
9907
|
+
const octets = parseIpv4(finalPart);
|
|
9908
|
+
if (octets === null) return null;
|
|
9909
|
+
const [first, second, third, fourth] = octets;
|
|
9910
|
+
normalized = `${normalized.slice(0, lastColon + 1)}${(first << 8 | second).toString(16)}:${(third << 8 | fourth).toString(16)}`;
|
|
9911
|
+
}
|
|
9912
|
+
const parts = normalized.split("::");
|
|
9913
|
+
if (parts.length > 2) return null;
|
|
9914
|
+
const left = parts[0] ? parts[0].split(":") : [];
|
|
9915
|
+
const right = parts[1] ? parts[1].split(":") : [];
|
|
9916
|
+
const explicit = [];
|
|
9917
|
+
for (const part of [
|
|
9918
|
+
...left,
|
|
9919
|
+
...right
|
|
9920
|
+
]) {
|
|
9921
|
+
if (!/^[\da-f]{1,4}$/i.test(part)) return null;
|
|
9922
|
+
explicit.push(Number.parseInt(part, 16));
|
|
9923
|
+
}
|
|
9924
|
+
if (parts.length === 1) return explicit.length === 8 ? explicit : null;
|
|
9925
|
+
if (explicit.length >= 8) return null;
|
|
9926
|
+
return [
|
|
9927
|
+
...explicit.slice(0, left.length),
|
|
9928
|
+
...Array(8 - explicit.length).fill(0),
|
|
9929
|
+
...explicit.slice(left.length)
|
|
9930
|
+
];
|
|
9931
|
+
}
|
|
9932
|
+
__name(parseIpv6Hextets, "parseIpv6Hextets");
|
|
9933
|
+
function matchesIpv6Prefix(hextets, prefix, prefixLength) {
|
|
9934
|
+
const completeHextets = Math.floor(prefixLength / 16);
|
|
9935
|
+
for (let index = 0; index < completeHextets; index += 1) {
|
|
9936
|
+
if (hextets[index] !== prefix[index]) return false;
|
|
9937
|
+
}
|
|
9938
|
+
const remainingBits = prefixLength % 16;
|
|
9939
|
+
if (remainingBits === 0) return true;
|
|
9940
|
+
const mask = 65535 << 16 - remainingBits & 65535;
|
|
9941
|
+
return ((hextets[completeHextets] ?? 0) & mask) === ((prefix[completeHextets] ?? 0) & mask);
|
|
9942
|
+
}
|
|
9943
|
+
__name(matchesIpv6Prefix, "matchesIpv6Prefix");
|
|
9944
|
+
function embeddedIpv4(hextets) {
|
|
9945
|
+
const seventh = hextets[6] ?? 0;
|
|
9946
|
+
const eighth = hextets[7] ?? 0;
|
|
9947
|
+
return [
|
|
9948
|
+
seventh >> 8,
|
|
9949
|
+
seventh & 255,
|
|
9950
|
+
eighth >> 8,
|
|
9951
|
+
eighth & 255
|
|
9952
|
+
];
|
|
9953
|
+
}
|
|
9954
|
+
__name(embeddedIpv4, "embeddedIpv4");
|
|
9955
|
+
function isPublicIpv6(address) {
|
|
9956
|
+
const hextets = parseIpv6Hextets(address);
|
|
9957
|
+
if (hextets === null) return false;
|
|
9958
|
+
const isIpv4Compatible = matchesIpv6Prefix(hextets, [
|
|
9959
|
+
0,
|
|
9960
|
+
0,
|
|
9961
|
+
0,
|
|
9962
|
+
0,
|
|
9963
|
+
0,
|
|
9964
|
+
0
|
|
9965
|
+
], 96);
|
|
9966
|
+
const isIpv4Mapped = matchesIpv6Prefix(hextets, [
|
|
9967
|
+
0,
|
|
9968
|
+
0,
|
|
9969
|
+
0,
|
|
9970
|
+
0,
|
|
9971
|
+
0,
|
|
9972
|
+
65535
|
|
9973
|
+
], 96);
|
|
9974
|
+
if (isIpv4Compatible || isIpv4Mapped) {
|
|
9975
|
+
return isPublicIpv4Octets(embeddedIpv4(hextets));
|
|
9976
|
+
}
|
|
9977
|
+
const first = hextets[0] ?? 0;
|
|
9978
|
+
if (first === 8194) {
|
|
9979
|
+
const second = hextets[1] ?? 0;
|
|
9980
|
+
const third = hextets[2] ?? 0;
|
|
9981
|
+
return isPublicIpv4Octets([
|
|
9982
|
+
second >> 8,
|
|
9983
|
+
second & 255,
|
|
9984
|
+
third >> 8,
|
|
9985
|
+
third & 255
|
|
9986
|
+
]);
|
|
9987
|
+
}
|
|
9988
|
+
const nonPublicPrefixes = [
|
|
9989
|
+
[
|
|
9990
|
+
[
|
|
9991
|
+
100,
|
|
9992
|
+
65435,
|
|
9993
|
+
1
|
|
9994
|
+
],
|
|
9995
|
+
48
|
|
9996
|
+
],
|
|
9997
|
+
[
|
|
9998
|
+
[
|
|
9999
|
+
256,
|
|
10000
|
+
0,
|
|
10001
|
+
0,
|
|
10002
|
+
0
|
|
10003
|
+
],
|
|
10004
|
+
64
|
|
10005
|
+
],
|
|
10006
|
+
[
|
|
10007
|
+
[
|
|
10008
|
+
8193,
|
|
10009
|
+
0
|
|
10010
|
+
],
|
|
10011
|
+
32
|
|
10012
|
+
],
|
|
10013
|
+
[
|
|
10014
|
+
[
|
|
10015
|
+
8193,
|
|
10016
|
+
2,
|
|
10017
|
+
0
|
|
10018
|
+
],
|
|
10019
|
+
48
|
|
10020
|
+
],
|
|
10021
|
+
[
|
|
10022
|
+
[
|
|
10023
|
+
8193,
|
|
10024
|
+
16
|
|
10025
|
+
],
|
|
10026
|
+
28
|
|
10027
|
+
],
|
|
10028
|
+
[
|
|
10029
|
+
[
|
|
10030
|
+
8193,
|
|
10031
|
+
32
|
|
10032
|
+
],
|
|
10033
|
+
28
|
|
10034
|
+
],
|
|
10035
|
+
[
|
|
10036
|
+
[
|
|
10037
|
+
8193,
|
|
10038
|
+
3512
|
|
10039
|
+
],
|
|
10040
|
+
32
|
|
10041
|
+
],
|
|
10042
|
+
[
|
|
10043
|
+
[
|
|
10044
|
+
16383
|
|
10045
|
+
],
|
|
10046
|
+
20
|
|
10047
|
+
],
|
|
10048
|
+
[
|
|
10049
|
+
[
|
|
10050
|
+
24320
|
|
10051
|
+
],
|
|
10052
|
+
16
|
|
10053
|
+
],
|
|
10054
|
+
[
|
|
10055
|
+
[
|
|
10056
|
+
64512
|
|
10057
|
+
],
|
|
10058
|
+
7
|
|
10059
|
+
],
|
|
10060
|
+
[
|
|
10061
|
+
[
|
|
10062
|
+
65152
|
|
10063
|
+
],
|
|
10064
|
+
10
|
|
10065
|
+
],
|
|
10066
|
+
[
|
|
10067
|
+
[
|
|
10068
|
+
65216
|
|
10069
|
+
],
|
|
10070
|
+
10
|
|
10071
|
+
],
|
|
10072
|
+
[
|
|
10073
|
+
[
|
|
10074
|
+
65280
|
|
10075
|
+
],
|
|
10076
|
+
8
|
|
10077
|
+
]
|
|
10078
|
+
];
|
|
10079
|
+
return matchesIpv6Prefix(hextets, [
|
|
10080
|
+
8192
|
|
10081
|
+
], 3) && !nonPublicPrefixes.some(([prefix, length]) => matchesIpv6Prefix(hextets, prefix, length));
|
|
10082
|
+
}
|
|
10083
|
+
__name(isPublicIpv6, "isPublicIpv6");
|
|
10084
|
+
function isPublicHost(value) {
|
|
10085
|
+
const hostname = normalizeHostname(value);
|
|
10086
|
+
if (hostname.length === 0 || hostname === "localhost" || hostname.endsWith(".localhost")) {
|
|
10087
|
+
return false;
|
|
10088
|
+
}
|
|
10089
|
+
const ipv4 = parseIpv4(hostname);
|
|
10090
|
+
if (ipv4 !== null) return isPublicIpv4Octets(ipv4);
|
|
10091
|
+
if (hostname.includes(":")) return isPublicIpv6(hostname);
|
|
10092
|
+
if (/^[\d.]+$/.test(hostname)) return false;
|
|
10093
|
+
return true;
|
|
10094
|
+
}
|
|
10095
|
+
__name(isPublicHost, "isPublicHost");
|
|
10096
|
+
function parsePublicHttpsOrigin(value) {
|
|
10097
|
+
let parsed;
|
|
10098
|
+
try {
|
|
10099
|
+
parsed = new URL(value);
|
|
10100
|
+
} catch {
|
|
10101
|
+
return null;
|
|
10102
|
+
}
|
|
10103
|
+
if (parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash || parsed.port !== "" || !isPublicHost(parsed.hostname)) {
|
|
10104
|
+
return null;
|
|
10105
|
+
}
|
|
10106
|
+
return parsed;
|
|
10107
|
+
}
|
|
10108
|
+
__name(parsePublicHttpsOrigin, "parsePublicHttpsOrigin");
|
|
10109
|
+
|
|
10110
|
+
// ../../packages/types/src/social-profile-source.ts
|
|
10111
|
+
var INSTAGRAM_HOSTS = /* @__PURE__ */ new Set([
|
|
10112
|
+
"instagram.com",
|
|
10113
|
+
"www.instagram.com",
|
|
10114
|
+
"m.instagram.com",
|
|
10115
|
+
"instagr.am",
|
|
10116
|
+
"www.instagr.am"
|
|
10117
|
+
]);
|
|
10118
|
+
var FACEBOOK_HOSTS = /* @__PURE__ */ new Set([
|
|
10119
|
+
"facebook.com",
|
|
10120
|
+
"www.facebook.com",
|
|
10121
|
+
"m.facebook.com",
|
|
10122
|
+
"mbasic.facebook.com",
|
|
10123
|
+
"web.facebook.com",
|
|
10124
|
+
"fb.com",
|
|
10125
|
+
"www.fb.com"
|
|
10126
|
+
]);
|
|
10127
|
+
var INSTAGRAM_RESERVED = /* @__PURE__ */ new Set([
|
|
10128
|
+
"accounts",
|
|
10129
|
+
"about",
|
|
10130
|
+
"api",
|
|
10131
|
+
"challenge",
|
|
10132
|
+
"developer",
|
|
10133
|
+
"developers",
|
|
10134
|
+
"direct",
|
|
10135
|
+
"directory",
|
|
10136
|
+
"emails",
|
|
10137
|
+
"explore",
|
|
10138
|
+
"legal",
|
|
10139
|
+
"p",
|
|
10140
|
+
"privacy",
|
|
10141
|
+
"reel",
|
|
10142
|
+
"reels",
|
|
10143
|
+
"stories",
|
|
10144
|
+
"tv",
|
|
10145
|
+
"web"
|
|
10146
|
+
]);
|
|
10147
|
+
var FACEBOOK_RESERVED = /* @__PURE__ */ new Set([
|
|
10148
|
+
"about",
|
|
10149
|
+
"ads",
|
|
10150
|
+
"business",
|
|
10151
|
+
"checkpoint",
|
|
10152
|
+
"dialog",
|
|
10153
|
+
"events",
|
|
10154
|
+
"friends",
|
|
10155
|
+
"gaming",
|
|
10156
|
+
"groups",
|
|
10157
|
+
"help",
|
|
10158
|
+
"home.php",
|
|
10159
|
+
"login",
|
|
10160
|
+
"login.php",
|
|
10161
|
+
"logout.php",
|
|
10162
|
+
"marketplace",
|
|
10163
|
+
"messages",
|
|
10164
|
+
"pages",
|
|
10165
|
+
"people",
|
|
10166
|
+
"p",
|
|
10167
|
+
"photo",
|
|
10168
|
+
"photo.php",
|
|
10169
|
+
"photos",
|
|
10170
|
+
"plugins",
|
|
10171
|
+
"policies",
|
|
10172
|
+
"privacy",
|
|
10173
|
+
"profile.php",
|
|
10174
|
+
"recover",
|
|
10175
|
+
"reel",
|
|
10176
|
+
"reels",
|
|
10177
|
+
"search",
|
|
10178
|
+
"settings",
|
|
10179
|
+
"share",
|
|
10180
|
+
"sharer",
|
|
10181
|
+
"sharer.php",
|
|
10182
|
+
"story.php",
|
|
10183
|
+
"video.php",
|
|
10184
|
+
"videos",
|
|
10185
|
+
"watch"
|
|
10186
|
+
]);
|
|
10187
|
+
function socialProfileRequest(input) {
|
|
10188
|
+
let parsed;
|
|
10189
|
+
try {
|
|
10190
|
+
parsed = new URL(input.trim());
|
|
10191
|
+
} catch {
|
|
10192
|
+
return null;
|
|
10193
|
+
}
|
|
10194
|
+
if (![
|
|
10195
|
+
"http:",
|
|
10196
|
+
"https:"
|
|
10197
|
+
].includes(parsed.protocol) || parsed.username || parsed.password || parsed.port || parsed.pathname.includes("%")) return null;
|
|
10198
|
+
const host = parsed.hostname.toLowerCase().replace(/\.$/, "");
|
|
10199
|
+
const segments = parsed.pathname.split("/").filter(Boolean);
|
|
10200
|
+
const first = segments[0]?.toLowerCase();
|
|
10201
|
+
if (INSTAGRAM_HOSTS.has(host)) {
|
|
10202
|
+
if (segments.length !== 1 || !first || !/^[a-z0-9._]{1,30}$/.test(first) || INSTAGRAM_RESERVED.has(first)) return null;
|
|
10203
|
+
return {
|
|
10204
|
+
platform: "instagram",
|
|
10205
|
+
handle: first,
|
|
10206
|
+
url: `https://www.instagram.com/${first}/`
|
|
10207
|
+
};
|
|
10208
|
+
}
|
|
10209
|
+
if (!FACEBOOK_HOSTS.has(host) || !first) return null;
|
|
10210
|
+
const numericId = first === "profile.php" && segments.length === 1 ? parsed.searchParams.get("id") : first === "people" && segments.length === 3 ? segments[2] : first === "p" && segments.length === 2 ? segments[1]?.match(/-(\d+)$/)?.[1] : void 0;
|
|
10211
|
+
if (numericId && /^[1-9]\d{0,29}$/.test(numericId)) {
|
|
10212
|
+
return {
|
|
10213
|
+
platform: "facebook",
|
|
10214
|
+
handle: numericId,
|
|
10215
|
+
url: `https://www.facebook.com/profile.php?id=${numericId}`
|
|
10216
|
+
};
|
|
10217
|
+
}
|
|
10218
|
+
if (segments.length !== 1 || !/^[a-z0-9._-]{1,100}$/.test(first) || FACEBOOK_RESERVED.has(first)) return null;
|
|
10219
|
+
return {
|
|
10220
|
+
platform: "facebook",
|
|
10221
|
+
handle: first,
|
|
10222
|
+
url: `https://www.facebook.com/${first}/`
|
|
10223
|
+
};
|
|
10224
|
+
}
|
|
10225
|
+
__name(socialProfileRequest, "socialProfileRequest");
|
|
10226
|
+
|
|
10227
|
+
// ../../packages/types/src/web-address.ts
|
|
10228
|
+
function normalizeWebAddress(input) {
|
|
10229
|
+
const trimmed = input.trim();
|
|
10230
|
+
if (!trimmed || /\s/.test(trimmed)) return null;
|
|
10231
|
+
const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed);
|
|
10232
|
+
const hasOpaqueScheme = !hasScheme && /^[a-z][a-z0-9+.-]*:(?!\d)/i.test(trimmed);
|
|
10233
|
+
if (hasOpaqueScheme) return null;
|
|
10234
|
+
const candidate = hasScheme ? trimmed : `https://${trimmed}`;
|
|
10235
|
+
let parsed;
|
|
10236
|
+
try {
|
|
10237
|
+
parsed = new URL(candidate);
|
|
10238
|
+
} catch {
|
|
10239
|
+
return null;
|
|
10240
|
+
}
|
|
10241
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
10242
|
+
if (parsed.username || parsed.password) return null;
|
|
10243
|
+
if (!isPublicHostname(parsed.hostname)) return null;
|
|
10244
|
+
return candidate;
|
|
10245
|
+
}
|
|
10246
|
+
__name(normalizeWebAddress, "normalizeWebAddress");
|
|
10247
|
+
var LOGIN_REDIRECTS = [
|
|
10248
|
+
{
|
|
10249
|
+
hosts: /* @__PURE__ */ new Set([
|
|
10250
|
+
"instagram.com",
|
|
10251
|
+
"m.instagram.com"
|
|
10252
|
+
]),
|
|
10253
|
+
loginPath: /^\/accounts\/login\/?$/i,
|
|
10254
|
+
canonicalOrigin: "https://www.instagram.com"
|
|
10255
|
+
},
|
|
10256
|
+
{
|
|
10257
|
+
hosts: /* @__PURE__ */ new Set([
|
|
10258
|
+
"facebook.com",
|
|
10259
|
+
"m.facebook.com"
|
|
10260
|
+
]),
|
|
10261
|
+
loginPath: /^\/login(?:\.php)?\/?$/i,
|
|
10262
|
+
canonicalOrigin: "https://www.facebook.com"
|
|
10263
|
+
}
|
|
10264
|
+
];
|
|
10265
|
+
function unwrapLoginRedirectUrl(input) {
|
|
10266
|
+
let parsed;
|
|
10267
|
+
try {
|
|
10268
|
+
parsed = new URL(input.trim());
|
|
10269
|
+
} catch {
|
|
10270
|
+
return input;
|
|
10271
|
+
}
|
|
10272
|
+
const host = parsed.hostname.toLowerCase().replace(/^www\./, "");
|
|
10273
|
+
const rule = LOGIN_REDIRECTS.find((candidate) => candidate.hosts.has(host) && candidate.loginPath.test(parsed.pathname));
|
|
10274
|
+
const next = rule ? parsed.searchParams.get("next") : null;
|
|
10275
|
+
if (!rule || !next) return input;
|
|
10276
|
+
let target;
|
|
10277
|
+
try {
|
|
10278
|
+
target = new URL(next, rule.canonicalOrigin);
|
|
10279
|
+
} catch {
|
|
10280
|
+
return input;
|
|
10281
|
+
}
|
|
10282
|
+
const targetHost = target.hostname.toLowerCase().replace(/^www\./, "");
|
|
10283
|
+
if (!rule.hosts.has(targetHost) || ![
|
|
10284
|
+
"http:",
|
|
10285
|
+
"https:"
|
|
10286
|
+
].includes(target.protocol) || rule.loginPath.test(target.pathname) || target.pathname === "/") return input;
|
|
10287
|
+
return `${rule.canonicalOrigin}${target.pathname}${target.search}`;
|
|
10288
|
+
}
|
|
10289
|
+
__name(unwrapLoginRedirectUrl, "unwrapLoginRedirectUrl");
|
|
10290
|
+
var LABEL = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
|
|
10291
|
+
var TLD = /^(?:[a-z]{2,}|xn--[a-z0-9-]+)$/i;
|
|
10292
|
+
function isPublicHostname(hostname) {
|
|
10293
|
+
const host = hostname.replace(/\.$/, "").toLowerCase();
|
|
10294
|
+
if (!host || host.startsWith("[")) return false;
|
|
10295
|
+
if (host === "localhost" || host.endsWith(".localhost")) return false;
|
|
10296
|
+
const labels = host.split(".");
|
|
10297
|
+
if (labels.length < 2) return false;
|
|
10298
|
+
if (!labels.every((label) => label.length <= 63 && LABEL.test(label))) return false;
|
|
10299
|
+
const tld = labels[labels.length - 1] ?? "";
|
|
10300
|
+
return TLD.test(tld);
|
|
10301
|
+
}
|
|
10302
|
+
__name(isPublicHostname, "isPublicHostname");
|
|
10303
|
+
|
|
9861
10304
|
// ../../packages/types/src/pricing.ts
|
|
9862
10305
|
var GEMINI_TTS_CREDIT_PRICING_ACTION = "tts-generation:gemini-3-1-flash-tts-percredit";
|
|
9863
10306
|
var CREDITS_PER_USD_CENT = 10;
|
|
9864
10307
|
var CREDITS_PER_DOLLAR = 100 * CREDITS_PER_USD_CENT;
|
|
10308
|
+
var APIFY_SOCIAL_PROFILE_MAX_RUN_COST_USD = 0.1;
|
|
10309
|
+
var APIFY_SOCIAL_PROFILE_EXPECTED_RUN_COST_CENTS = 0.23;
|
|
10310
|
+
function apifySocialProfileUserPriceCents(costCents) {
|
|
10311
|
+
if (!Number.isFinite(costCents * 2) || costCents < 0) {
|
|
10312
|
+
throw new RangeError("APIFY_SOCIAL_INVALID_COST");
|
|
10313
|
+
}
|
|
10314
|
+
return Number((costCents * 2).toFixed(10));
|
|
10315
|
+
}
|
|
10316
|
+
__name(apifySocialProfileUserPriceCents, "apifySocialProfileUserPriceCents");
|
|
10317
|
+
var APIFY_INSTAGRAM_PROFILE_PRICE_RANGE_CENTS = Object.freeze({
|
|
10318
|
+
min: apifySocialProfileUserPriceCents(APIFY_SOCIAL_PROFILE_EXPECTED_RUN_COST_CENTS),
|
|
10319
|
+
max: apifySocialProfileUserPriceCents(APIFY_SOCIAL_PROFILE_MAX_RUN_COST_USD * 100)
|
|
10320
|
+
});
|
|
10321
|
+
function estimateInstagramProfileAcquisitionCostCents(sourceUrl) {
|
|
10322
|
+
if (socialProfileRequest(unwrapLoginRedirectUrl(sourceUrl ?? ""))?.platform !== "instagram") {
|
|
10323
|
+
return {
|
|
10324
|
+
min: 0,
|
|
10325
|
+
max: 0
|
|
10326
|
+
};
|
|
10327
|
+
}
|
|
10328
|
+
return {
|
|
10329
|
+
...APIFY_INSTAGRAM_PROFILE_PRICE_RANGE_CENTS
|
|
10330
|
+
};
|
|
10331
|
+
}
|
|
10332
|
+
__name(estimateInstagramProfileAcquisitionCostCents, "estimateInstagramProfileAcquisitionCostCents");
|
|
9865
10333
|
var AD_CREATIVE_MODELS = {
|
|
9866
10334
|
STANDARD: IMAGE_WRITE_TOKENS["1k"],
|
|
9867
10335
|
PREMIUM: IMAGE_WRITE_TOKENS["2k"]
|
|
@@ -14359,9 +14827,17 @@ function motionGraphicsPriceCents(durationSec, options = {}) {
|
|
|
14359
14827
|
}
|
|
14360
14828
|
__name(motionGraphicsPriceCents, "motionGraphicsPriceCents");
|
|
14361
14829
|
function motionGraphicsPriceRangeCents(durationSec, options = {}) {
|
|
14830
|
+
const pending = options.socialAcquisitionPriceCents;
|
|
14831
|
+
if (pending !== void 0 && (!Number.isFinite(pending) || pending < 0)) {
|
|
14832
|
+
throw new RangeError("APIFY_SOCIAL_INVALID_PRICE");
|
|
14833
|
+
}
|
|
14834
|
+
const acquisition = pending !== void 0 ? {
|
|
14835
|
+
min: pending,
|
|
14836
|
+
max: pending
|
|
14837
|
+
} : estimateInstagramProfileAcquisitionCostCents(options.socialSourceUrl);
|
|
14362
14838
|
return {
|
|
14363
|
-
minCents: roundClipCents(motionGraphicsBasePriceCents(durationSec)),
|
|
14364
|
-
maxCents: motionGraphicsPriceCents(durationSec, options)
|
|
14839
|
+
minCents: roundClipCents(motionGraphicsBasePriceCents(durationSec) + acquisition.min),
|
|
14840
|
+
maxCents: roundClipCents(motionGraphicsPriceCents(durationSec, options) + acquisition.max)
|
|
14365
14841
|
};
|
|
14366
14842
|
}
|
|
14367
14843
|
__name(motionGraphicsPriceRangeCents, "motionGraphicsPriceRangeCents");
|
|
@@ -15620,43 +16096,9 @@ var MotionGraphicsTranscriptResponseSchema = z84.discriminatedUnion("status", [
|
|
|
15620
16096
|
}).strict(),
|
|
15621
16097
|
z84.object({
|
|
15622
16098
|
status: z84.literal("skipped"),
|
|
15623
|
-
reason: MotionGraphicsTranscriptSkipReasonSchema
|
|
15624
|
-
}).strict()
|
|
15625
|
-
]);
|
|
15626
|
-
|
|
15627
|
-
// ../../packages/types/src/web-address.ts
|
|
15628
|
-
function normalizeWebAddress(input) {
|
|
15629
|
-
const trimmed = input.trim();
|
|
15630
|
-
if (!trimmed || /\s/.test(trimmed)) return null;
|
|
15631
|
-
const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed);
|
|
15632
|
-
const hasOpaqueScheme = !hasScheme && /^[a-z][a-z0-9+.-]*:(?!\d)/i.test(trimmed);
|
|
15633
|
-
if (hasOpaqueScheme) return null;
|
|
15634
|
-
const candidate = hasScheme ? trimmed : `https://${trimmed}`;
|
|
15635
|
-
let parsed;
|
|
15636
|
-
try {
|
|
15637
|
-
parsed = new URL(candidate);
|
|
15638
|
-
} catch {
|
|
15639
|
-
return null;
|
|
15640
|
-
}
|
|
15641
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
15642
|
-
if (parsed.username || parsed.password) return null;
|
|
15643
|
-
if (!isPublicHostname(parsed.hostname)) return null;
|
|
15644
|
-
return candidate;
|
|
15645
|
-
}
|
|
15646
|
-
__name(normalizeWebAddress, "normalizeWebAddress");
|
|
15647
|
-
var LABEL = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
|
|
15648
|
-
var TLD = /^(?:[a-z]{2,}|xn--[a-z0-9-]+)$/i;
|
|
15649
|
-
function isPublicHostname(hostname) {
|
|
15650
|
-
const host = hostname.replace(/\.$/, "").toLowerCase();
|
|
15651
|
-
if (!host || host.startsWith("[")) return false;
|
|
15652
|
-
if (host === "localhost" || host.endsWith(".localhost")) return false;
|
|
15653
|
-
const labels = host.split(".");
|
|
15654
|
-
if (labels.length < 2) return false;
|
|
15655
|
-
if (!labels.every((label) => label.length <= 63 && LABEL.test(label))) return false;
|
|
15656
|
-
const tld = labels[labels.length - 1] ?? "";
|
|
15657
|
-
return TLD.test(tld);
|
|
15658
|
-
}
|
|
15659
|
-
__name(isPublicHostname, "isPublicHostname");
|
|
16099
|
+
reason: MotionGraphicsTranscriptSkipReasonSchema
|
|
16100
|
+
}).strict()
|
|
16101
|
+
]);
|
|
15660
16102
|
|
|
15661
16103
|
// ../../packages/types/src/internal/deep-freeze.ts
|
|
15662
16104
|
function deepFreeze(value) {
|
|
@@ -19778,253 +20220,6 @@ var MCP_ANGLE_NARRATIVE_STYLES = [
|
|
|
19778
20220
|
];
|
|
19779
20221
|
var McpAngleNarrativeStyleSchema = NarrativeStyle.extract(MCP_ANGLE_NARRATIVE_STYLES);
|
|
19780
20222
|
|
|
19781
|
-
// ../../packages/types/src/public-host.ts
|
|
19782
|
-
function normalizeHostname(value) {
|
|
19783
|
-
const normalized = value.trim().toLowerCase().replace(/\.+$/, "");
|
|
19784
|
-
return normalized.startsWith("[") && normalized.endsWith("]") ? normalized.slice(1, -1) : normalized;
|
|
19785
|
-
}
|
|
19786
|
-
__name(normalizeHostname, "normalizeHostname");
|
|
19787
|
-
function parseIpv4(address) {
|
|
19788
|
-
const octets = address.split(".");
|
|
19789
|
-
if (octets.length !== 4 || !octets.every((octet) => /^(0|[1-9]\d{0,2})$/.test(octet))) {
|
|
19790
|
-
return null;
|
|
19791
|
-
}
|
|
19792
|
-
const parsedOctets = octets.map(Number);
|
|
19793
|
-
if (parsedOctets.some((octet) => octet > 255)) return null;
|
|
19794
|
-
const [first, second, third, fourth] = parsedOctets;
|
|
19795
|
-
if (first === void 0 || second === void 0 || third === void 0 || fourth === void 0) {
|
|
19796
|
-
return null;
|
|
19797
|
-
}
|
|
19798
|
-
return [
|
|
19799
|
-
first,
|
|
19800
|
-
second,
|
|
19801
|
-
third,
|
|
19802
|
-
fourth
|
|
19803
|
-
];
|
|
19804
|
-
}
|
|
19805
|
-
__name(parseIpv4, "parseIpv4");
|
|
19806
|
-
function isPublicIpv4Octets([first, second, third]) {
|
|
19807
|
-
if (first === 0 || first === 10 || first === 127 || first >= 224) return false;
|
|
19808
|
-
if (first === 100 && second >= 64 && second <= 127) return false;
|
|
19809
|
-
if (first === 169 && second === 254) return false;
|
|
19810
|
-
if (first === 172 && second >= 16 && second <= 31) return false;
|
|
19811
|
-
if (first === 192 && second === 0 && (third === 0 || third === 2)) return false;
|
|
19812
|
-
if (first === 192 && second === 88 && third === 99) return false;
|
|
19813
|
-
if (first === 192 && second === 168) return false;
|
|
19814
|
-
if (first === 198 && (second === 18 || second === 19)) return false;
|
|
19815
|
-
if (first === 198 && second === 51 && third === 100) return false;
|
|
19816
|
-
if (first === 203 && second === 0 && third === 113) return false;
|
|
19817
|
-
return true;
|
|
19818
|
-
}
|
|
19819
|
-
__name(isPublicIpv4Octets, "isPublicIpv4Octets");
|
|
19820
|
-
function parseIpv6Hextets(address) {
|
|
19821
|
-
let normalized = address;
|
|
19822
|
-
const lastColon = normalized.lastIndexOf(":");
|
|
19823
|
-
const finalPart = normalized.slice(lastColon + 1);
|
|
19824
|
-
if (finalPart.includes(".")) {
|
|
19825
|
-
const octets = parseIpv4(finalPart);
|
|
19826
|
-
if (octets === null) return null;
|
|
19827
|
-
const [first, second, third, fourth] = octets;
|
|
19828
|
-
normalized = `${normalized.slice(0, lastColon + 1)}${(first << 8 | second).toString(16)}:${(third << 8 | fourth).toString(16)}`;
|
|
19829
|
-
}
|
|
19830
|
-
const parts = normalized.split("::");
|
|
19831
|
-
if (parts.length > 2) return null;
|
|
19832
|
-
const left = parts[0] ? parts[0].split(":") : [];
|
|
19833
|
-
const right = parts[1] ? parts[1].split(":") : [];
|
|
19834
|
-
const explicit = [];
|
|
19835
|
-
for (const part of [
|
|
19836
|
-
...left,
|
|
19837
|
-
...right
|
|
19838
|
-
]) {
|
|
19839
|
-
if (!/^[\da-f]{1,4}$/i.test(part)) return null;
|
|
19840
|
-
explicit.push(Number.parseInt(part, 16));
|
|
19841
|
-
}
|
|
19842
|
-
if (parts.length === 1) return explicit.length === 8 ? explicit : null;
|
|
19843
|
-
if (explicit.length >= 8) return null;
|
|
19844
|
-
return [
|
|
19845
|
-
...explicit.slice(0, left.length),
|
|
19846
|
-
...Array(8 - explicit.length).fill(0),
|
|
19847
|
-
...explicit.slice(left.length)
|
|
19848
|
-
];
|
|
19849
|
-
}
|
|
19850
|
-
__name(parseIpv6Hextets, "parseIpv6Hextets");
|
|
19851
|
-
function matchesIpv6Prefix(hextets, prefix, prefixLength) {
|
|
19852
|
-
const completeHextets = Math.floor(prefixLength / 16);
|
|
19853
|
-
for (let index = 0; index < completeHextets; index += 1) {
|
|
19854
|
-
if (hextets[index] !== prefix[index]) return false;
|
|
19855
|
-
}
|
|
19856
|
-
const remainingBits = prefixLength % 16;
|
|
19857
|
-
if (remainingBits === 0) return true;
|
|
19858
|
-
const mask = 65535 << 16 - remainingBits & 65535;
|
|
19859
|
-
return ((hextets[completeHextets] ?? 0) & mask) === ((prefix[completeHextets] ?? 0) & mask);
|
|
19860
|
-
}
|
|
19861
|
-
__name(matchesIpv6Prefix, "matchesIpv6Prefix");
|
|
19862
|
-
function embeddedIpv4(hextets) {
|
|
19863
|
-
const seventh = hextets[6] ?? 0;
|
|
19864
|
-
const eighth = hextets[7] ?? 0;
|
|
19865
|
-
return [
|
|
19866
|
-
seventh >> 8,
|
|
19867
|
-
seventh & 255,
|
|
19868
|
-
eighth >> 8,
|
|
19869
|
-
eighth & 255
|
|
19870
|
-
];
|
|
19871
|
-
}
|
|
19872
|
-
__name(embeddedIpv4, "embeddedIpv4");
|
|
19873
|
-
function isPublicIpv6(address) {
|
|
19874
|
-
const hextets = parseIpv6Hextets(address);
|
|
19875
|
-
if (hextets === null) return false;
|
|
19876
|
-
const isIpv4Compatible = matchesIpv6Prefix(hextets, [
|
|
19877
|
-
0,
|
|
19878
|
-
0,
|
|
19879
|
-
0,
|
|
19880
|
-
0,
|
|
19881
|
-
0,
|
|
19882
|
-
0
|
|
19883
|
-
], 96);
|
|
19884
|
-
const isIpv4Mapped = matchesIpv6Prefix(hextets, [
|
|
19885
|
-
0,
|
|
19886
|
-
0,
|
|
19887
|
-
0,
|
|
19888
|
-
0,
|
|
19889
|
-
0,
|
|
19890
|
-
65535
|
|
19891
|
-
], 96);
|
|
19892
|
-
if (isIpv4Compatible || isIpv4Mapped) {
|
|
19893
|
-
return isPublicIpv4Octets(embeddedIpv4(hextets));
|
|
19894
|
-
}
|
|
19895
|
-
const first = hextets[0] ?? 0;
|
|
19896
|
-
if (first === 8194) {
|
|
19897
|
-
const second = hextets[1] ?? 0;
|
|
19898
|
-
const third = hextets[2] ?? 0;
|
|
19899
|
-
return isPublicIpv4Octets([
|
|
19900
|
-
second >> 8,
|
|
19901
|
-
second & 255,
|
|
19902
|
-
third >> 8,
|
|
19903
|
-
third & 255
|
|
19904
|
-
]);
|
|
19905
|
-
}
|
|
19906
|
-
const nonPublicPrefixes = [
|
|
19907
|
-
[
|
|
19908
|
-
[
|
|
19909
|
-
100,
|
|
19910
|
-
65435,
|
|
19911
|
-
1
|
|
19912
|
-
],
|
|
19913
|
-
48
|
|
19914
|
-
],
|
|
19915
|
-
[
|
|
19916
|
-
[
|
|
19917
|
-
256,
|
|
19918
|
-
0,
|
|
19919
|
-
0,
|
|
19920
|
-
0
|
|
19921
|
-
],
|
|
19922
|
-
64
|
|
19923
|
-
],
|
|
19924
|
-
[
|
|
19925
|
-
[
|
|
19926
|
-
8193,
|
|
19927
|
-
0
|
|
19928
|
-
],
|
|
19929
|
-
32
|
|
19930
|
-
],
|
|
19931
|
-
[
|
|
19932
|
-
[
|
|
19933
|
-
8193,
|
|
19934
|
-
2,
|
|
19935
|
-
0
|
|
19936
|
-
],
|
|
19937
|
-
48
|
|
19938
|
-
],
|
|
19939
|
-
[
|
|
19940
|
-
[
|
|
19941
|
-
8193,
|
|
19942
|
-
16
|
|
19943
|
-
],
|
|
19944
|
-
28
|
|
19945
|
-
],
|
|
19946
|
-
[
|
|
19947
|
-
[
|
|
19948
|
-
8193,
|
|
19949
|
-
32
|
|
19950
|
-
],
|
|
19951
|
-
28
|
|
19952
|
-
],
|
|
19953
|
-
[
|
|
19954
|
-
[
|
|
19955
|
-
8193,
|
|
19956
|
-
3512
|
|
19957
|
-
],
|
|
19958
|
-
32
|
|
19959
|
-
],
|
|
19960
|
-
[
|
|
19961
|
-
[
|
|
19962
|
-
16383
|
|
19963
|
-
],
|
|
19964
|
-
20
|
|
19965
|
-
],
|
|
19966
|
-
[
|
|
19967
|
-
[
|
|
19968
|
-
24320
|
|
19969
|
-
],
|
|
19970
|
-
16
|
|
19971
|
-
],
|
|
19972
|
-
[
|
|
19973
|
-
[
|
|
19974
|
-
64512
|
|
19975
|
-
],
|
|
19976
|
-
7
|
|
19977
|
-
],
|
|
19978
|
-
[
|
|
19979
|
-
[
|
|
19980
|
-
65152
|
|
19981
|
-
],
|
|
19982
|
-
10
|
|
19983
|
-
],
|
|
19984
|
-
[
|
|
19985
|
-
[
|
|
19986
|
-
65216
|
|
19987
|
-
],
|
|
19988
|
-
10
|
|
19989
|
-
],
|
|
19990
|
-
[
|
|
19991
|
-
[
|
|
19992
|
-
65280
|
|
19993
|
-
],
|
|
19994
|
-
8
|
|
19995
|
-
]
|
|
19996
|
-
];
|
|
19997
|
-
return matchesIpv6Prefix(hextets, [
|
|
19998
|
-
8192
|
|
19999
|
-
], 3) && !nonPublicPrefixes.some(([prefix, length]) => matchesIpv6Prefix(hextets, prefix, length));
|
|
20000
|
-
}
|
|
20001
|
-
__name(isPublicIpv6, "isPublicIpv6");
|
|
20002
|
-
function isPublicHost(value) {
|
|
20003
|
-
const hostname = normalizeHostname(value);
|
|
20004
|
-
if (hostname.length === 0 || hostname === "localhost" || hostname.endsWith(".localhost")) {
|
|
20005
|
-
return false;
|
|
20006
|
-
}
|
|
20007
|
-
const ipv4 = parseIpv4(hostname);
|
|
20008
|
-
if (ipv4 !== null) return isPublicIpv4Octets(ipv4);
|
|
20009
|
-
if (hostname.includes(":")) return isPublicIpv6(hostname);
|
|
20010
|
-
if (/^[\d.]+$/.test(hostname)) return false;
|
|
20011
|
-
return true;
|
|
20012
|
-
}
|
|
20013
|
-
__name(isPublicHost, "isPublicHost");
|
|
20014
|
-
function parsePublicHttpsOrigin(value) {
|
|
20015
|
-
let parsed;
|
|
20016
|
-
try {
|
|
20017
|
-
parsed = new URL(value);
|
|
20018
|
-
} catch {
|
|
20019
|
-
return null;
|
|
20020
|
-
}
|
|
20021
|
-
if (parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash || parsed.port !== "" || !isPublicHost(parsed.hostname)) {
|
|
20022
|
-
return null;
|
|
20023
|
-
}
|
|
20024
|
-
return parsed;
|
|
20025
|
-
}
|
|
20026
|
-
__name(parsePublicHttpsOrigin, "parsePublicHttpsOrigin");
|
|
20027
|
-
|
|
20028
20223
|
// ../../packages/types/src/whatsapp.ts
|
|
20029
20224
|
var WHATSAPP_MAX_AUDIO_BYTES = 16 * 1024 * 1024;
|
|
20030
20225
|
var WHATSAPP_MAX_AUDIO_DURATION_SECONDS = 10 * 60;
|
|
@@ -22234,6 +22429,8 @@ var WebsiteCaptureResponseSchema = z109.object({
|
|
|
22234
22429
|
status: WebsiteCaptureStatusSchema,
|
|
22235
22430
|
expiresAt: z109.string().datetime(),
|
|
22236
22431
|
previewUrl: z109.string().url().optional(),
|
|
22432
|
+
/** Final customer amount for accepted Instagram acquisition still pending payment. */
|
|
22433
|
+
socialAcquisitionPriceCents: z109.number().finite().nonnegative().optional(),
|
|
22237
22434
|
cause: WebsiteCaptureCauseSchema.optional()
|
|
22238
22435
|
});
|
|
22239
22436
|
var WebsiteCaptureJobSchema = WebsiteCaptureRequestSchema.extend({
|
|
@@ -24189,7 +24386,7 @@ var ApiClient = class {
|
|
|
24189
24386
|
};
|
|
24190
24387
|
|
|
24191
24388
|
// src/index.ts
|
|
24192
|
-
var MCP_VERSION = "11.5.
|
|
24389
|
+
var MCP_VERSION = "11.5.6";
|
|
24193
24390
|
|
|
24194
24391
|
// src/meta-upload-app.ts
|
|
24195
24392
|
import { readFileSync } from "fs";
|
|
@@ -26786,15 +26983,11 @@ function centsToCredits(cents) {
|
|
|
26786
26983
|
return Math.round(cents * CREDITS_PER_USD_CENT);
|
|
26787
26984
|
}
|
|
26788
26985
|
__name(centsToCredits, "centsToCredits");
|
|
26789
|
-
function
|
|
26790
|
-
return centsToCredits(motionGraphicsPriceCents(durationSec, {
|
|
26791
|
-
hookVariants
|
|
26792
|
-
}));
|
|
26793
|
-
}
|
|
26794
|
-
__name(animatedVideoCredits, "animatedVideoCredits");
|
|
26795
|
-
function animatedVideoCreditRange(durationSec, hookVariants = DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS) {
|
|
26986
|
+
function animatedVideoCreditRange(durationSec, hookVariants = DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS, acquisition = {}) {
|
|
26796
26987
|
const { minCents, maxCents } = motionGraphicsPriceRangeCents(durationSec, {
|
|
26797
|
-
hookVariants
|
|
26988
|
+
hookVariants,
|
|
26989
|
+
socialSourceUrl: acquisition.sourceUrl,
|
|
26990
|
+
socialAcquisitionPriceCents: acquisition.priceCents
|
|
26798
26991
|
});
|
|
26799
26992
|
return {
|
|
26800
26993
|
minCredits: centsToCredits(minCents),
|
|
@@ -26823,8 +27016,8 @@ function describeAnimatedVideoPrices() {
|
|
|
26823
27016
|
return `${ranges}. Cada versi\xF3n extra del gancho suma ${centsToCredits(MOTION_GRAPHICS_VARIANT_PRICE_CENTS)} cr\xE9ditos (US$${usd(MOTION_GRAPHICS_VARIANT_PRICE_CENTS)})`;
|
|
26824
27017
|
}
|
|
26825
27018
|
__name(describeAnimatedVideoPrices, "describeAnimatedVideoPrices");
|
|
26826
|
-
function animatedVideoMaxPriceText(durationSec, hookVariants = DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS) {
|
|
26827
|
-
return `m\xE1ximo ${
|
|
27019
|
+
function animatedVideoMaxPriceText(durationSec, hookVariants = DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS, acquisition = {}) {
|
|
27020
|
+
return `m\xE1ximo ${animatedVideoCreditRange(durationSec, hookVariants, acquisition).maxCredits} cr\xE9ditos (se devuelve lo que no use: clips IA, voz en off, clips hablados con la voz del narrador y versiones no entregadas)`;
|
|
26828
27021
|
}
|
|
26829
27022
|
__name(animatedVideoMaxPriceText, "animatedVideoMaxPriceText");
|
|
26830
27023
|
function hookVariantsLabel(count) {
|
|
@@ -27056,7 +27249,7 @@ function renderAnimatedVideoStatus(result) {
|
|
|
27056
27249
|
__name(renderAnimatedVideoStatus, "renderAnimatedVideoStatus");
|
|
27057
27250
|
function registerAnimatedVideoTools(server, api) {
|
|
27058
27251
|
server.registerTool("create_animated_video", {
|
|
27059
|
-
description: guidance.summary + ` Hace un video animado de un SERVICIO a partir del enlace de su p\xE1gina, con la identidad visual del sitio, m\xFAsica y efectos, y voz en off si el agente la usa. El agente que lo crea decide libremente la narrativa y la mezcla: solo gr\xE1ficos animados, clips de video generados con IA (incluidas personas hablando a c\xE1mara) o ambos intercalados; como m\xE1ximo un clip IA por cada ${MOTION_GRAPHICS_BROLL_CLIP_SECONDS} s de video. Desde la web el video tambi\xE9n puede usar los videos y fotos propios del usuario; aqu\xED se hace desde el enlace (gr\xE1ficos, clips IA y voz en off), sin archivos subidos. Si el video lleva voz en off, una persona que habla a c\xE1mara (en el gancho y, si acaso, en el cierre) habla con la misma voz del narrador: una sola voz en todo el video. Con hookVariants (2 o 3, solo si el usuario lo pide) entrega adem\xE1s versiones del mismo video con otra apertura, para probar cu\xE1l funciona mejor. Con music=false (solo si el usuario lo pide) sale sin m\xFAsica de fondo, al mismo precio. Primero llama action=prepare con landingUrl e idioma: prepara gratis una captura y NUNCA crea un video aunque responda ready. Sigue con action=status y websiteCaptureId hasta ready o fallo; cancel permite cancelar. Si est\xE1 bloqueada, pide otro enlace p\xFAblico sin iniciar sesi\xF3n; no solicites contrase\xF1as. Muestra la vista previa y confirma formato, duraci\xF3n, idioma y precio con el usuario. \xDAnicamente despu\xE9s llama action=generate con websiteCaptureId y confirmed=true. La generaci\xF3n reutiliza esa captura; no cobra por preparar ni por una captura pendiente/bloqueada. Repite el mismo websiteCaptureId y las mismas opciones para recuperar una respuesta perdida, incluso si la captura ya expir\xF3; la API devolver\xE1 el mismo taskId sin cobrar de nuevo. Conserva tambi\xE9n generationRequestId si lo enviaste. La misma captura, opciones e identidad representan esa generaci\xF3n; si el usuario pide y confirma otro video, usa un generationRequestId nuevo. Nunca cambies esa identidad autom\xE1ticamente por un fallo de transporte. Precio por duraci\xF3n, seg\xFAn lo que el video necesite: ${describeAnimatedVideoPrices()}. Al crearlo se cobra el m\xE1ximo de ese rango; cuando termina, lo que no us\xF3 (cada clip IA que no qued\xF3 en el video, la voz en off si no la us\xF3, cada clip hablado con la voz del narrador que no us\xF3 y cada versi\xF3n del gancho que no se entregue) se devuelve autom\xE1ticamente. Si falla, se devuelve todo. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Generate devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4 (y el de cada versi\xF3n del gancho), o error, que trae el motivo. Es el \xFAnico video de servicio disponible por ahora: no ofrezcas un video con presentador. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
|
|
27252
|
+
description: guidance.summary + ` Hace un video animado de un SERVICIO a partir del enlace de su p\xE1gina, con la identidad visual del sitio, m\xFAsica y efectos, y voz en off si el agente la usa. El agente que lo crea decide libremente la narrativa y la mezcla: solo gr\xE1ficos animados, clips de video generados con IA (incluidas personas hablando a c\xE1mara) o ambos intercalados; como m\xE1ximo un clip IA por cada ${MOTION_GRAPHICS_BROLL_CLIP_SECONDS} s de video. Desde la web el video tambi\xE9n puede usar los videos y fotos propios del usuario; aqu\xED se hace desde el enlace (gr\xE1ficos, clips IA y voz en off), sin archivos subidos. Si el video lleva voz en off, una persona que habla a c\xE1mara (en el gancho y, si acaso, en el cierre) habla con la misma voz del narrador: una sola voz en todo el video. Con hookVariants (2 o 3, solo si el usuario lo pide) entrega adem\xE1s versiones del mismo video con otra apertura, para probar cu\xE1l funciona mejor. Con music=false (solo si el usuario lo pide) sale sin m\xFAsica de fondo, al mismo precio. Primero llama action=prepare con landingUrl e idioma: prepara gratis una captura y NUNCA crea un video aunque responda ready. Sigue con action=status y websiteCaptureId hasta ready o fallo; cancel permite cancelar. Si est\xE1 bloqueada, pide otro enlace p\xFAblico sin iniciar sesi\xF3n; no solicites contrase\xF1as. Muestra la vista previa y confirma formato, duraci\xF3n, idioma y precio con el usuario. \xDAnicamente despu\xE9s llama action=generate con websiteCaptureId y confirmed=true. La generaci\xF3n reutiliza esa captura; no cobra por preparar ni por una captura pendiente/bloqueada. En Instagram, el precio incluye una sola adquisici\xF3n de la fuente a 2x su costo real, usando socialAcquisitionPriceCents de la captura ready; si ya se pag\xF3, ese importe es cero. Repite el mismo websiteCaptureId y las mismas opciones para recuperar una respuesta perdida, incluso si la captura ya expir\xF3; la API devolver\xE1 el mismo taskId sin cobrar de nuevo. Conserva tambi\xE9n generationRequestId si lo enviaste. La misma captura, opciones e identidad representan esa generaci\xF3n; si el usuario pide y confirma otro video, usa un generationRequestId nuevo. Nunca cambies esa identidad autom\xE1ticamente por un fallo de transporte. Precio por duraci\xF3n, seg\xFAn lo que el video necesite: ${describeAnimatedVideoPrices()}. Al crearlo se cobra el m\xE1ximo de ese rango; cuando termina, lo que no us\xF3 (cada clip IA que no qued\xF3 en el video, la voz en off si no la us\xF3, cada clip hablado con la voz del narrador que no us\xF3 y cada versi\xF3n del gancho que no se entregue) se devuelve autom\xE1ticamente. Si falla, se devuelve todo. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Generate devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4 (y el de cada versi\xF3n del gancho), o error, que trae el motivo. Es el \xFAnico video de servicio disponible por ahora: no ofrezcas un video con presentador. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
|
|
27060
27253
|
inputSchema: CreateAnimatedVideoInput.shape,
|
|
27061
27254
|
annotations: CREATES_PAID_OPEN_WORLD
|
|
27062
27255
|
}, async (input) => {
|
|
@@ -27104,8 +27297,14 @@ function registerAnimatedVideoTools(server, api) {
|
|
|
27104
27297
|
const motionGraphics = request.data;
|
|
27105
27298
|
const hookVariants = motionGraphics.hookVariants ?? DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS;
|
|
27106
27299
|
const clipCount = motionGraphicsMaxClips(motionGraphics.durationSec);
|
|
27107
|
-
const
|
|
27108
|
-
const
|
|
27300
|
+
const captureId = input.websiteCaptureId;
|
|
27301
|
+
const captureQuote = socialProfileRequest(landingUrl)?.platform === "instagram" ? await Promise.resolve().then(() => api.getJson(`/v1/motion-graphics/captures/${encodeURIComponent(captureId)}`)).then((value) => WebsiteCaptureResponseSchema.safeParse(value), () => null) : null;
|
|
27302
|
+
const acquisition = {
|
|
27303
|
+
sourceUrl: landingUrl,
|
|
27304
|
+
priceCents: captureQuote?.success ? captureQuote.data.socialAcquisitionPriceCents : void 0
|
|
27305
|
+
};
|
|
27306
|
+
const { minCredits, maxCredits } = animatedVideoCreditRange(motionGraphics.durationSec, hookVariants, acquisition);
|
|
27307
|
+
const priceText = animatedVideoMaxPriceText(motionGraphics.durationSec, hookVariants, acquisition);
|
|
27109
27308
|
const versionsText = hookVariants > 1 ? ` y ${hookVariantsLabel(hookVariants)}` : "";
|
|
27110
27309
|
const music = motionGraphicsMusic(motionGraphics);
|
|
27111
27310
|
const musicText = music ? "" : ", sin m\xFAsica de fondo";
|
|
@@ -28739,7 +28938,9 @@ function registerBrandTools(server, api, options = {}) {
|
|
|
28739
28938
|
}
|
|
28740
28939
|
const estimate = await api.postJson("/v1/billing/estimate", {
|
|
28741
28940
|
type: "brand-extract",
|
|
28742
|
-
options: {
|
|
28941
|
+
options: {
|
|
28942
|
+
sourceUrl
|
|
28943
|
+
}
|
|
28743
28944
|
});
|
|
28744
28945
|
const priceCredits = Math.ceil(estimate.estimatedMaxCostCredits);
|
|
28745
28946
|
if (input.confirmed !== true) {
|
package/dist/stdio.js
CHANGED
|
@@ -8425,7 +8425,9 @@ var CampaignCopyEstimationOptions = z40.object({
|
|
|
8425
8425
|
/** Number of image creatives that can each use one vision analysis (0-10). */
|
|
8426
8426
|
nImages: z40.number().int().min(0).max(10).default(0)
|
|
8427
8427
|
});
|
|
8428
|
-
var BrandExtractEstimationOptions = z40.object({
|
|
8428
|
+
var BrandExtractEstimationOptions = z40.object({
|
|
8429
|
+
sourceUrl: z40.string().url().optional()
|
|
8430
|
+
}).strict();
|
|
8429
8431
|
var PersonaSuggestEstimationOptions = z40.object({}).strict();
|
|
8430
8432
|
var ChatParseEstimationOptions = z40.object({}).strict();
|
|
8431
8433
|
var CodeLandingEditEstimationOptions = z40.object({}).strict();
|
|
@@ -9880,10 +9882,229 @@ var TikTokCreateCampaignResponseSchema = z52.object({
|
|
|
9880
9882
|
var GEMINI_OMNI_FLAT_OUR_COST_CENTS = 84;
|
|
9881
9883
|
var GEMINI_OMNI_FLAT_USER_PRICE_CENTS = 168;
|
|
9882
9884
|
|
|
9885
|
+
// ../../packages/types/src/social-profile-source.ts
|
|
9886
|
+
var INSTAGRAM_HOSTS = /* @__PURE__ */ new Set([
|
|
9887
|
+
"instagram.com",
|
|
9888
|
+
"www.instagram.com",
|
|
9889
|
+
"m.instagram.com",
|
|
9890
|
+
"instagr.am",
|
|
9891
|
+
"www.instagr.am"
|
|
9892
|
+
]);
|
|
9893
|
+
var FACEBOOK_HOSTS = /* @__PURE__ */ new Set([
|
|
9894
|
+
"facebook.com",
|
|
9895
|
+
"www.facebook.com",
|
|
9896
|
+
"m.facebook.com",
|
|
9897
|
+
"mbasic.facebook.com",
|
|
9898
|
+
"web.facebook.com",
|
|
9899
|
+
"fb.com",
|
|
9900
|
+
"www.fb.com"
|
|
9901
|
+
]);
|
|
9902
|
+
var INSTAGRAM_RESERVED = /* @__PURE__ */ new Set([
|
|
9903
|
+
"accounts",
|
|
9904
|
+
"about",
|
|
9905
|
+
"api",
|
|
9906
|
+
"challenge",
|
|
9907
|
+
"developer",
|
|
9908
|
+
"developers",
|
|
9909
|
+
"direct",
|
|
9910
|
+
"directory",
|
|
9911
|
+
"emails",
|
|
9912
|
+
"explore",
|
|
9913
|
+
"legal",
|
|
9914
|
+
"p",
|
|
9915
|
+
"privacy",
|
|
9916
|
+
"reel",
|
|
9917
|
+
"reels",
|
|
9918
|
+
"stories",
|
|
9919
|
+
"tv",
|
|
9920
|
+
"web"
|
|
9921
|
+
]);
|
|
9922
|
+
var FACEBOOK_RESERVED = /* @__PURE__ */ new Set([
|
|
9923
|
+
"about",
|
|
9924
|
+
"ads",
|
|
9925
|
+
"business",
|
|
9926
|
+
"checkpoint",
|
|
9927
|
+
"dialog",
|
|
9928
|
+
"events",
|
|
9929
|
+
"friends",
|
|
9930
|
+
"gaming",
|
|
9931
|
+
"groups",
|
|
9932
|
+
"help",
|
|
9933
|
+
"home.php",
|
|
9934
|
+
"login",
|
|
9935
|
+
"login.php",
|
|
9936
|
+
"logout.php",
|
|
9937
|
+
"marketplace",
|
|
9938
|
+
"messages",
|
|
9939
|
+
"pages",
|
|
9940
|
+
"people",
|
|
9941
|
+
"p",
|
|
9942
|
+
"photo",
|
|
9943
|
+
"photo.php",
|
|
9944
|
+
"photos",
|
|
9945
|
+
"plugins",
|
|
9946
|
+
"policies",
|
|
9947
|
+
"privacy",
|
|
9948
|
+
"profile.php",
|
|
9949
|
+
"recover",
|
|
9950
|
+
"reel",
|
|
9951
|
+
"reels",
|
|
9952
|
+
"search",
|
|
9953
|
+
"settings",
|
|
9954
|
+
"share",
|
|
9955
|
+
"sharer",
|
|
9956
|
+
"sharer.php",
|
|
9957
|
+
"story.php",
|
|
9958
|
+
"video.php",
|
|
9959
|
+
"videos",
|
|
9960
|
+
"watch"
|
|
9961
|
+
]);
|
|
9962
|
+
function socialProfileRequest(input) {
|
|
9963
|
+
let parsed;
|
|
9964
|
+
try {
|
|
9965
|
+
parsed = new URL(input.trim());
|
|
9966
|
+
} catch {
|
|
9967
|
+
return null;
|
|
9968
|
+
}
|
|
9969
|
+
if (![
|
|
9970
|
+
"http:",
|
|
9971
|
+
"https:"
|
|
9972
|
+
].includes(parsed.protocol) || parsed.username || parsed.password || parsed.port || parsed.pathname.includes("%")) return null;
|
|
9973
|
+
const host = parsed.hostname.toLowerCase().replace(/\.$/, "");
|
|
9974
|
+
const segments = parsed.pathname.split("/").filter(Boolean);
|
|
9975
|
+
const first = segments[0]?.toLowerCase();
|
|
9976
|
+
if (INSTAGRAM_HOSTS.has(host)) {
|
|
9977
|
+
if (segments.length !== 1 || !first || !/^[a-z0-9._]{1,30}$/.test(first) || INSTAGRAM_RESERVED.has(first)) return null;
|
|
9978
|
+
return {
|
|
9979
|
+
platform: "instagram",
|
|
9980
|
+
handle: first,
|
|
9981
|
+
url: `https://www.instagram.com/${first}/`
|
|
9982
|
+
};
|
|
9983
|
+
}
|
|
9984
|
+
if (!FACEBOOK_HOSTS.has(host) || !first) return null;
|
|
9985
|
+
const numericId = first === "profile.php" && segments.length === 1 ? parsed.searchParams.get("id") : first === "people" && segments.length === 3 ? segments[2] : first === "p" && segments.length === 2 ? segments[1]?.match(/-(\d+)$/)?.[1] : void 0;
|
|
9986
|
+
if (numericId && /^[1-9]\d{0,29}$/.test(numericId)) {
|
|
9987
|
+
return {
|
|
9988
|
+
platform: "facebook",
|
|
9989
|
+
handle: numericId,
|
|
9990
|
+
url: `https://www.facebook.com/profile.php?id=${numericId}`
|
|
9991
|
+
};
|
|
9992
|
+
}
|
|
9993
|
+
if (segments.length !== 1 || !/^[a-z0-9._-]{1,100}$/.test(first) || FACEBOOK_RESERVED.has(first)) return null;
|
|
9994
|
+
return {
|
|
9995
|
+
platform: "facebook",
|
|
9996
|
+
handle: first,
|
|
9997
|
+
url: `https://www.facebook.com/${first}/`
|
|
9998
|
+
};
|
|
9999
|
+
}
|
|
10000
|
+
__name(socialProfileRequest, "socialProfileRequest");
|
|
10001
|
+
|
|
10002
|
+
// ../../packages/types/src/web-address.ts
|
|
10003
|
+
function normalizeWebAddress(input) {
|
|
10004
|
+
const trimmed = input.trim();
|
|
10005
|
+
if (!trimmed || /\s/.test(trimmed)) return null;
|
|
10006
|
+
const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed);
|
|
10007
|
+
const hasOpaqueScheme = !hasScheme && /^[a-z][a-z0-9+.-]*:(?!\d)/i.test(trimmed);
|
|
10008
|
+
if (hasOpaqueScheme) return null;
|
|
10009
|
+
const candidate = hasScheme ? trimmed : `https://${trimmed}`;
|
|
10010
|
+
let parsed;
|
|
10011
|
+
try {
|
|
10012
|
+
parsed = new URL(candidate);
|
|
10013
|
+
} catch {
|
|
10014
|
+
return null;
|
|
10015
|
+
}
|
|
10016
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
10017
|
+
if (parsed.username || parsed.password) return null;
|
|
10018
|
+
if (!isPublicHostname(parsed.hostname)) return null;
|
|
10019
|
+
return candidate;
|
|
10020
|
+
}
|
|
10021
|
+
__name(normalizeWebAddress, "normalizeWebAddress");
|
|
10022
|
+
var LOGIN_REDIRECTS = [
|
|
10023
|
+
{
|
|
10024
|
+
hosts: /* @__PURE__ */ new Set([
|
|
10025
|
+
"instagram.com",
|
|
10026
|
+
"m.instagram.com"
|
|
10027
|
+
]),
|
|
10028
|
+
loginPath: /^\/accounts\/login\/?$/i,
|
|
10029
|
+
canonicalOrigin: "https://www.instagram.com"
|
|
10030
|
+
},
|
|
10031
|
+
{
|
|
10032
|
+
hosts: /* @__PURE__ */ new Set([
|
|
10033
|
+
"facebook.com",
|
|
10034
|
+
"m.facebook.com"
|
|
10035
|
+
]),
|
|
10036
|
+
loginPath: /^\/login(?:\.php)?\/?$/i,
|
|
10037
|
+
canonicalOrigin: "https://www.facebook.com"
|
|
10038
|
+
}
|
|
10039
|
+
];
|
|
10040
|
+
function unwrapLoginRedirectUrl(input) {
|
|
10041
|
+
let parsed;
|
|
10042
|
+
try {
|
|
10043
|
+
parsed = new URL(input.trim());
|
|
10044
|
+
} catch {
|
|
10045
|
+
return input;
|
|
10046
|
+
}
|
|
10047
|
+
const host = parsed.hostname.toLowerCase().replace(/^www\./, "");
|
|
10048
|
+
const rule = LOGIN_REDIRECTS.find((candidate) => candidate.hosts.has(host) && candidate.loginPath.test(parsed.pathname));
|
|
10049
|
+
const next = rule ? parsed.searchParams.get("next") : null;
|
|
10050
|
+
if (!rule || !next) return input;
|
|
10051
|
+
let target;
|
|
10052
|
+
try {
|
|
10053
|
+
target = new URL(next, rule.canonicalOrigin);
|
|
10054
|
+
} catch {
|
|
10055
|
+
return input;
|
|
10056
|
+
}
|
|
10057
|
+
const targetHost = target.hostname.toLowerCase().replace(/^www\./, "");
|
|
10058
|
+
if (!rule.hosts.has(targetHost) || ![
|
|
10059
|
+
"http:",
|
|
10060
|
+
"https:"
|
|
10061
|
+
].includes(target.protocol) || rule.loginPath.test(target.pathname) || target.pathname === "/") return input;
|
|
10062
|
+
return `${rule.canonicalOrigin}${target.pathname}${target.search}`;
|
|
10063
|
+
}
|
|
10064
|
+
__name(unwrapLoginRedirectUrl, "unwrapLoginRedirectUrl");
|
|
10065
|
+
var LABEL = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
|
|
10066
|
+
var TLD = /^(?:[a-z]{2,}|xn--[a-z0-9-]+)$/i;
|
|
10067
|
+
function isPublicHostname(hostname) {
|
|
10068
|
+
const host = hostname.replace(/\.$/, "").toLowerCase();
|
|
10069
|
+
if (!host || host.startsWith("[")) return false;
|
|
10070
|
+
if (host === "localhost" || host.endsWith(".localhost")) return false;
|
|
10071
|
+
const labels = host.split(".");
|
|
10072
|
+
if (labels.length < 2) return false;
|
|
10073
|
+
if (!labels.every((label) => label.length <= 63 && LABEL.test(label))) return false;
|
|
10074
|
+
const tld = labels[labels.length - 1] ?? "";
|
|
10075
|
+
return TLD.test(tld);
|
|
10076
|
+
}
|
|
10077
|
+
__name(isPublicHostname, "isPublicHostname");
|
|
10078
|
+
|
|
9883
10079
|
// ../../packages/types/src/pricing.ts
|
|
9884
10080
|
var GEMINI_TTS_CREDIT_PRICING_ACTION = "tts-generation:gemini-3-1-flash-tts-percredit";
|
|
9885
10081
|
var CREDITS_PER_USD_CENT = 10;
|
|
9886
10082
|
var CREDITS_PER_DOLLAR = 100 * CREDITS_PER_USD_CENT;
|
|
10083
|
+
var APIFY_SOCIAL_PROFILE_MAX_RUN_COST_USD = 0.1;
|
|
10084
|
+
var APIFY_SOCIAL_PROFILE_EXPECTED_RUN_COST_CENTS = 0.23;
|
|
10085
|
+
function apifySocialProfileUserPriceCents(costCents) {
|
|
10086
|
+
if (!Number.isFinite(costCents * 2) || costCents < 0) {
|
|
10087
|
+
throw new RangeError("APIFY_SOCIAL_INVALID_COST");
|
|
10088
|
+
}
|
|
10089
|
+
return Number((costCents * 2).toFixed(10));
|
|
10090
|
+
}
|
|
10091
|
+
__name(apifySocialProfileUserPriceCents, "apifySocialProfileUserPriceCents");
|
|
10092
|
+
var APIFY_INSTAGRAM_PROFILE_PRICE_RANGE_CENTS = Object.freeze({
|
|
10093
|
+
min: apifySocialProfileUserPriceCents(APIFY_SOCIAL_PROFILE_EXPECTED_RUN_COST_CENTS),
|
|
10094
|
+
max: apifySocialProfileUserPriceCents(APIFY_SOCIAL_PROFILE_MAX_RUN_COST_USD * 100)
|
|
10095
|
+
});
|
|
10096
|
+
function estimateInstagramProfileAcquisitionCostCents(sourceUrl) {
|
|
10097
|
+
if (socialProfileRequest(unwrapLoginRedirectUrl(sourceUrl ?? ""))?.platform !== "instagram") {
|
|
10098
|
+
return {
|
|
10099
|
+
min: 0,
|
|
10100
|
+
max: 0
|
|
10101
|
+
};
|
|
10102
|
+
}
|
|
10103
|
+
return {
|
|
10104
|
+
...APIFY_INSTAGRAM_PROFILE_PRICE_RANGE_CENTS
|
|
10105
|
+
};
|
|
10106
|
+
}
|
|
10107
|
+
__name(estimateInstagramProfileAcquisitionCostCents, "estimateInstagramProfileAcquisitionCostCents");
|
|
9887
10108
|
var AD_CREATIVE_MODELS = {
|
|
9888
10109
|
STANDARD: IMAGE_WRITE_TOKENS["1k"],
|
|
9889
10110
|
PREMIUM: IMAGE_WRITE_TOKENS["2k"]
|
|
@@ -14381,9 +14602,17 @@ function motionGraphicsPriceCents(durationSec, options = {}) {
|
|
|
14381
14602
|
}
|
|
14382
14603
|
__name(motionGraphicsPriceCents, "motionGraphicsPriceCents");
|
|
14383
14604
|
function motionGraphicsPriceRangeCents(durationSec, options = {}) {
|
|
14605
|
+
const pending = options.socialAcquisitionPriceCents;
|
|
14606
|
+
if (pending !== void 0 && (!Number.isFinite(pending) || pending < 0)) {
|
|
14607
|
+
throw new RangeError("APIFY_SOCIAL_INVALID_PRICE");
|
|
14608
|
+
}
|
|
14609
|
+
const acquisition = pending !== void 0 ? {
|
|
14610
|
+
min: pending,
|
|
14611
|
+
max: pending
|
|
14612
|
+
} : estimateInstagramProfileAcquisitionCostCents(options.socialSourceUrl);
|
|
14384
14613
|
return {
|
|
14385
|
-
minCents: roundClipCents(motionGraphicsBasePriceCents(durationSec)),
|
|
14386
|
-
maxCents: motionGraphicsPriceCents(durationSec, options)
|
|
14614
|
+
minCents: roundClipCents(motionGraphicsBasePriceCents(durationSec) + acquisition.min),
|
|
14615
|
+
maxCents: roundClipCents(motionGraphicsPriceCents(durationSec, options) + acquisition.max)
|
|
14387
14616
|
};
|
|
14388
14617
|
}
|
|
14389
14618
|
__name(motionGraphicsPriceRangeCents, "motionGraphicsPriceRangeCents");
|
|
@@ -15646,40 +15875,6 @@ var MotionGraphicsTranscriptResponseSchema = z84.discriminatedUnion("status", [
|
|
|
15646
15875
|
}).strict()
|
|
15647
15876
|
]);
|
|
15648
15877
|
|
|
15649
|
-
// ../../packages/types/src/web-address.ts
|
|
15650
|
-
function normalizeWebAddress(input) {
|
|
15651
|
-
const trimmed = input.trim();
|
|
15652
|
-
if (!trimmed || /\s/.test(trimmed)) return null;
|
|
15653
|
-
const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed);
|
|
15654
|
-
const hasOpaqueScheme = !hasScheme && /^[a-z][a-z0-9+.-]*:(?!\d)/i.test(trimmed);
|
|
15655
|
-
if (hasOpaqueScheme) return null;
|
|
15656
|
-
const candidate = hasScheme ? trimmed : `https://${trimmed}`;
|
|
15657
|
-
let parsed;
|
|
15658
|
-
try {
|
|
15659
|
-
parsed = new URL(candidate);
|
|
15660
|
-
} catch {
|
|
15661
|
-
return null;
|
|
15662
|
-
}
|
|
15663
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
15664
|
-
if (parsed.username || parsed.password) return null;
|
|
15665
|
-
if (!isPublicHostname(parsed.hostname)) return null;
|
|
15666
|
-
return candidate;
|
|
15667
|
-
}
|
|
15668
|
-
__name(normalizeWebAddress, "normalizeWebAddress");
|
|
15669
|
-
var LABEL = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
|
|
15670
|
-
var TLD = /^(?:[a-z]{2,}|xn--[a-z0-9-]+)$/i;
|
|
15671
|
-
function isPublicHostname(hostname) {
|
|
15672
|
-
const host = hostname.replace(/\.$/, "").toLowerCase();
|
|
15673
|
-
if (!host || host.startsWith("[")) return false;
|
|
15674
|
-
if (host === "localhost" || host.endsWith(".localhost")) return false;
|
|
15675
|
-
const labels = host.split(".");
|
|
15676
|
-
if (labels.length < 2) return false;
|
|
15677
|
-
if (!labels.every((label) => label.length <= 63 && LABEL.test(label))) return false;
|
|
15678
|
-
const tld = labels[labels.length - 1] ?? "";
|
|
15679
|
-
return TLD.test(tld);
|
|
15680
|
-
}
|
|
15681
|
-
__name(isPublicHostname, "isPublicHostname");
|
|
15682
|
-
|
|
15683
15878
|
// ../../packages/types/src/internal/deep-freeze.ts
|
|
15684
15879
|
function deepFreeze(value) {
|
|
15685
15880
|
if (value !== null && typeof value === "object") {
|
|
@@ -22002,6 +22197,8 @@ var WebsiteCaptureResponseSchema = z109.object({
|
|
|
22002
22197
|
status: WebsiteCaptureStatusSchema,
|
|
22003
22198
|
expiresAt: z109.string().datetime(),
|
|
22004
22199
|
previewUrl: z109.string().url().optional(),
|
|
22200
|
+
/** Final customer amount for accepted Instagram acquisition still pending payment. */
|
|
22201
|
+
socialAcquisitionPriceCents: z109.number().finite().nonnegative().optional(),
|
|
22005
22202
|
cause: WebsiteCaptureCauseSchema.optional()
|
|
22006
22203
|
});
|
|
22007
22204
|
var WebsiteCaptureJobSchema = WebsiteCaptureRequestSchema.extend({
|
|
@@ -22518,7 +22715,7 @@ var ApiClient = class {
|
|
|
22518
22715
|
};
|
|
22519
22716
|
|
|
22520
22717
|
// src/index.ts
|
|
22521
|
-
var MCP_VERSION = "11.5.
|
|
22718
|
+
var MCP_VERSION = "11.5.6";
|
|
22522
22719
|
|
|
22523
22720
|
// src/meta-upload-app.ts
|
|
22524
22721
|
import { readFileSync } from "fs";
|
|
@@ -25168,15 +25365,11 @@ function centsToCredits(cents) {
|
|
|
25168
25365
|
return Math.round(cents * CREDITS_PER_USD_CENT);
|
|
25169
25366
|
}
|
|
25170
25367
|
__name(centsToCredits, "centsToCredits");
|
|
25171
|
-
function
|
|
25172
|
-
return centsToCredits(motionGraphicsPriceCents(durationSec, {
|
|
25173
|
-
hookVariants
|
|
25174
|
-
}));
|
|
25175
|
-
}
|
|
25176
|
-
__name(animatedVideoCredits, "animatedVideoCredits");
|
|
25177
|
-
function animatedVideoCreditRange(durationSec, hookVariants = DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS) {
|
|
25368
|
+
function animatedVideoCreditRange(durationSec, hookVariants = DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS, acquisition = {}) {
|
|
25178
25369
|
const { minCents, maxCents } = motionGraphicsPriceRangeCents(durationSec, {
|
|
25179
|
-
hookVariants
|
|
25370
|
+
hookVariants,
|
|
25371
|
+
socialSourceUrl: acquisition.sourceUrl,
|
|
25372
|
+
socialAcquisitionPriceCents: acquisition.priceCents
|
|
25180
25373
|
});
|
|
25181
25374
|
return {
|
|
25182
25375
|
minCredits: centsToCredits(minCents),
|
|
@@ -25205,8 +25398,8 @@ function describeAnimatedVideoPrices() {
|
|
|
25205
25398
|
return `${ranges}. Cada versi\xF3n extra del gancho suma ${centsToCredits(MOTION_GRAPHICS_VARIANT_PRICE_CENTS)} cr\xE9ditos (US$${usd(MOTION_GRAPHICS_VARIANT_PRICE_CENTS)})`;
|
|
25206
25399
|
}
|
|
25207
25400
|
__name(describeAnimatedVideoPrices, "describeAnimatedVideoPrices");
|
|
25208
|
-
function animatedVideoMaxPriceText(durationSec, hookVariants = DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS) {
|
|
25209
|
-
return `m\xE1ximo ${
|
|
25401
|
+
function animatedVideoMaxPriceText(durationSec, hookVariants = DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS, acquisition = {}) {
|
|
25402
|
+
return `m\xE1ximo ${animatedVideoCreditRange(durationSec, hookVariants, acquisition).maxCredits} cr\xE9ditos (se devuelve lo que no use: clips IA, voz en off, clips hablados con la voz del narrador y versiones no entregadas)`;
|
|
25210
25403
|
}
|
|
25211
25404
|
__name(animatedVideoMaxPriceText, "animatedVideoMaxPriceText");
|
|
25212
25405
|
function hookVariantsLabel(count) {
|
|
@@ -25438,7 +25631,7 @@ function renderAnimatedVideoStatus(result) {
|
|
|
25438
25631
|
__name(renderAnimatedVideoStatus, "renderAnimatedVideoStatus");
|
|
25439
25632
|
function registerAnimatedVideoTools(server, api) {
|
|
25440
25633
|
server.registerTool("create_animated_video", {
|
|
25441
|
-
description: guidance.summary + ` Hace un video animado de un SERVICIO a partir del enlace de su p\xE1gina, con la identidad visual del sitio, m\xFAsica y efectos, y voz en off si el agente la usa. El agente que lo crea decide libremente la narrativa y la mezcla: solo gr\xE1ficos animados, clips de video generados con IA (incluidas personas hablando a c\xE1mara) o ambos intercalados; como m\xE1ximo un clip IA por cada ${MOTION_GRAPHICS_BROLL_CLIP_SECONDS} s de video. Desde la web el video tambi\xE9n puede usar los videos y fotos propios del usuario; aqu\xED se hace desde el enlace (gr\xE1ficos, clips IA y voz en off), sin archivos subidos. Si el video lleva voz en off, una persona que habla a c\xE1mara (en el gancho y, si acaso, en el cierre) habla con la misma voz del narrador: una sola voz en todo el video. Con hookVariants (2 o 3, solo si el usuario lo pide) entrega adem\xE1s versiones del mismo video con otra apertura, para probar cu\xE1l funciona mejor. Con music=false (solo si el usuario lo pide) sale sin m\xFAsica de fondo, al mismo precio. Primero llama action=prepare con landingUrl e idioma: prepara gratis una captura y NUNCA crea un video aunque responda ready. Sigue con action=status y websiteCaptureId hasta ready o fallo; cancel permite cancelar. Si est\xE1 bloqueada, pide otro enlace p\xFAblico sin iniciar sesi\xF3n; no solicites contrase\xF1as. Muestra la vista previa y confirma formato, duraci\xF3n, idioma y precio con el usuario. \xDAnicamente despu\xE9s llama action=generate con websiteCaptureId y confirmed=true. La generaci\xF3n reutiliza esa captura; no cobra por preparar ni por una captura pendiente/bloqueada. Repite el mismo websiteCaptureId y las mismas opciones para recuperar una respuesta perdida, incluso si la captura ya expir\xF3; la API devolver\xE1 el mismo taskId sin cobrar de nuevo. Conserva tambi\xE9n generationRequestId si lo enviaste. La misma captura, opciones e identidad representan esa generaci\xF3n; si el usuario pide y confirma otro video, usa un generationRequestId nuevo. Nunca cambies esa identidad autom\xE1ticamente por un fallo de transporte. Precio por duraci\xF3n, seg\xFAn lo que el video necesite: ${describeAnimatedVideoPrices()}. Al crearlo se cobra el m\xE1ximo de ese rango; cuando termina, lo que no us\xF3 (cada clip IA que no qued\xF3 en el video, la voz en off si no la us\xF3, cada clip hablado con la voz del narrador que no us\xF3 y cada versi\xF3n del gancho que no se entregue) se devuelve autom\xE1ticamente. Si falla, se devuelve todo. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Generate devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4 (y el de cada versi\xF3n del gancho), o error, que trae el motivo. Es el \xFAnico video de servicio disponible por ahora: no ofrezcas un video con presentador. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
|
|
25634
|
+
description: guidance.summary + ` Hace un video animado de un SERVICIO a partir del enlace de su p\xE1gina, con la identidad visual del sitio, m\xFAsica y efectos, y voz en off si el agente la usa. El agente que lo crea decide libremente la narrativa y la mezcla: solo gr\xE1ficos animados, clips de video generados con IA (incluidas personas hablando a c\xE1mara) o ambos intercalados; como m\xE1ximo un clip IA por cada ${MOTION_GRAPHICS_BROLL_CLIP_SECONDS} s de video. Desde la web el video tambi\xE9n puede usar los videos y fotos propios del usuario; aqu\xED se hace desde el enlace (gr\xE1ficos, clips IA y voz en off), sin archivos subidos. Si el video lleva voz en off, una persona que habla a c\xE1mara (en el gancho y, si acaso, en el cierre) habla con la misma voz del narrador: una sola voz en todo el video. Con hookVariants (2 o 3, solo si el usuario lo pide) entrega adem\xE1s versiones del mismo video con otra apertura, para probar cu\xE1l funciona mejor. Con music=false (solo si el usuario lo pide) sale sin m\xFAsica de fondo, al mismo precio. Primero llama action=prepare con landingUrl e idioma: prepara gratis una captura y NUNCA crea un video aunque responda ready. Sigue con action=status y websiteCaptureId hasta ready o fallo; cancel permite cancelar. Si est\xE1 bloqueada, pide otro enlace p\xFAblico sin iniciar sesi\xF3n; no solicites contrase\xF1as. Muestra la vista previa y confirma formato, duraci\xF3n, idioma y precio con el usuario. \xDAnicamente despu\xE9s llama action=generate con websiteCaptureId y confirmed=true. La generaci\xF3n reutiliza esa captura; no cobra por preparar ni por una captura pendiente/bloqueada. En Instagram, el precio incluye una sola adquisici\xF3n de la fuente a 2x su costo real, usando socialAcquisitionPriceCents de la captura ready; si ya se pag\xF3, ese importe es cero. Repite el mismo websiteCaptureId y las mismas opciones para recuperar una respuesta perdida, incluso si la captura ya expir\xF3; la API devolver\xE1 el mismo taskId sin cobrar de nuevo. Conserva tambi\xE9n generationRequestId si lo enviaste. La misma captura, opciones e identidad representan esa generaci\xF3n; si el usuario pide y confirma otro video, usa un generationRequestId nuevo. Nunca cambies esa identidad autom\xE1ticamente por un fallo de transporte. Precio por duraci\xF3n, seg\xFAn lo que el video necesite: ${describeAnimatedVideoPrices()}. Al crearlo se cobra el m\xE1ximo de ese rango; cuando termina, lo que no us\xF3 (cada clip IA que no qued\xF3 en el video, la voz en off si no la us\xF3, cada clip hablado con la voz del narrador que no us\xF3 y cada versi\xF3n del gancho que no se entregue) se devuelve autom\xE1ticamente. Si falla, se devuelve todo. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Generate devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4 (y el de cada versi\xF3n del gancho), o error, que trae el motivo. Es el \xFAnico video de servicio disponible por ahora: no ofrezcas un video con presentador. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
|
|
25442
25635
|
inputSchema: CreateAnimatedVideoInput.shape,
|
|
25443
25636
|
annotations: CREATES_PAID_OPEN_WORLD
|
|
25444
25637
|
}, async (input) => {
|
|
@@ -25486,8 +25679,14 @@ function registerAnimatedVideoTools(server, api) {
|
|
|
25486
25679
|
const motionGraphics = request.data;
|
|
25487
25680
|
const hookVariants = motionGraphics.hookVariants ?? DEFAULT_MOTION_GRAPHICS_HOOK_VARIANTS;
|
|
25488
25681
|
const clipCount = motionGraphicsMaxClips(motionGraphics.durationSec);
|
|
25489
|
-
const
|
|
25490
|
-
const
|
|
25682
|
+
const captureId = input.websiteCaptureId;
|
|
25683
|
+
const captureQuote = socialProfileRequest(landingUrl)?.platform === "instagram" ? await Promise.resolve().then(() => api.getJson(`/v1/motion-graphics/captures/${encodeURIComponent(captureId)}`)).then((value) => WebsiteCaptureResponseSchema.safeParse(value), () => null) : null;
|
|
25684
|
+
const acquisition = {
|
|
25685
|
+
sourceUrl: landingUrl,
|
|
25686
|
+
priceCents: captureQuote?.success ? captureQuote.data.socialAcquisitionPriceCents : void 0
|
|
25687
|
+
};
|
|
25688
|
+
const { minCredits, maxCredits } = animatedVideoCreditRange(motionGraphics.durationSec, hookVariants, acquisition);
|
|
25689
|
+
const priceText = animatedVideoMaxPriceText(motionGraphics.durationSec, hookVariants, acquisition);
|
|
25491
25690
|
const versionsText = hookVariants > 1 ? ` y ${hookVariantsLabel(hookVariants)}` : "";
|
|
25492
25691
|
const music = motionGraphicsMusic(motionGraphics);
|
|
25493
25692
|
const musicText = music ? "" : ", sin m\xFAsica de fondo";
|
|
@@ -27121,7 +27320,9 @@ function registerBrandTools(server, api, options = {}) {
|
|
|
27121
27320
|
}
|
|
27122
27321
|
const estimate = await api.postJson("/v1/billing/estimate", {
|
|
27123
27322
|
type: "brand-extract",
|
|
27124
|
-
options: {
|
|
27323
|
+
options: {
|
|
27324
|
+
sourceUrl
|
|
27325
|
+
}
|
|
27125
27326
|
});
|
|
27126
27327
|
const priceCredits = Math.ceil(estimate.estimatedMaxCostCredits);
|
|
27127
27328
|
if (input.confirmed !== true) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@productmaker/mcp",
|
|
3
|
-
"version": "11.5.
|
|
3
|
+
"version": "11.5.6",
|
|
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.",
|