@postplus/cli 0.1.45 → 0.1.47
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/build/authed-cloud-request.d.ts +39 -0
- package/build/authed-cloud-request.js +3 -0
- package/build/client-compatibility.js +10 -4
- package/build/generated/hosted-execution-manifest.generated.js +298 -1
- package/build/generated/hosted-field-validation-core.generated.js +84 -0
- package/build/hosted-domain-commands.d.ts +14 -0
- package/build/hosted-domain-commands.js +129 -69
- package/build/hosted-field-validation.js +11 -91
- package/build/hosted-lib.d.ts +34 -0
- package/build/hosted-lib.js +45 -0
- package/build/hosted-manifest-index.d.ts +69 -0
- package/build/hosted-request-schemas.js +0 -108
- package/build/index.js +6 -4
- package/build/update-check.js +1 -2
- package/package.json +14 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type AuthedCloudRequestAuth = {
|
|
2
|
+
apiBaseUrl: string;
|
|
3
|
+
cliSessionToken: string;
|
|
4
|
+
};
|
|
5
|
+
export type AuthedCloudRequestInput = {
|
|
6
|
+
auth: AuthedCloudRequestAuth;
|
|
7
|
+
pathName: string;
|
|
8
|
+
method?: 'GET' | 'POST';
|
|
9
|
+
/**
|
|
10
|
+
* Parsed JSON body. When provided the request sends `content-type:
|
|
11
|
+
* application/json` and the serialized body; when omitted neither is sent.
|
|
12
|
+
*/
|
|
13
|
+
body?: unknown;
|
|
14
|
+
skillName?: string | null;
|
|
15
|
+
/**
|
|
16
|
+
* In-process override for the skills release id header. When provided (the
|
|
17
|
+
* hosted-lib path) it is stamped verbatim and the disk config is NOT read for
|
|
18
|
+
* the release id; when omitted (the bin path) the release id comes from
|
|
19
|
+
* `readLocalConfig()` as before.
|
|
20
|
+
*/
|
|
21
|
+
skillsReleaseId?: string | null;
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Optional once-only 401 refresh. When provided, a `401` response triggers a
|
|
25
|
+
* single retry: `refreshAuth()` returns fresh credentials and the request is
|
|
26
|
+
* re-issued once with them. When omitted, the first response is returned
|
|
27
|
+
* verbatim (the caller keeps its own `!ok` interpretation either way).
|
|
28
|
+
*/
|
|
29
|
+
retryOn401?: () => Promise<AuthedCloudRequestAuth>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Single transport envelope for every authenticated PostPlus Cloud request:
|
|
33
|
+
* canonical header set (`accept` + compatibility headers + `Bearer` token +
|
|
34
|
+
* optional `content-type`), `AbortSignal.timeout`, and an optional once-only
|
|
35
|
+
* 401-refresh-retry. It returns the raw `Response` so each caller keeps its own
|
|
36
|
+
* `!ok` interpretation — this is a narrow transport primitive, not a request
|
|
37
|
+
* framework.
|
|
38
|
+
*/
|
|
39
|
+
export declare function sendAuthedCloudRequest(input: AuthedCloudRequestInput): Promise<Response>;
|
|
@@ -19,6 +19,9 @@ export async function sendAuthedCloudRequest(input) {
|
|
|
19
19
|
async function issueAuthedCloudRequest(auth, input) {
|
|
20
20
|
const compatibilityHeaders = await buildPostPlusClientCompatibilityHeaders({
|
|
21
21
|
skillName: input.skillName ?? null,
|
|
22
|
+
...(input.skillsReleaseId !== undefined
|
|
23
|
+
? { skillsReleaseId: input.skillsReleaseId }
|
|
24
|
+
: {}),
|
|
22
25
|
});
|
|
23
26
|
const hasBody = input.body !== undefined;
|
|
24
27
|
const headers = {
|
|
@@ -2,6 +2,10 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { readLocalConfig, updateLocalConfig } from './local-state.js';
|
|
3
3
|
export const POSTPLUS_CLIENT_CONTRACT_VERSION = 2;
|
|
4
4
|
export const POSTPLUS_CLIENT_RUNTIME = 'postplus-cli';
|
|
5
|
+
// Single source for the CLI self-update command. Lives here (the upgrade-error
|
|
6
|
+
// formatter's home) so update-check.ts can import it without a cycle —
|
|
7
|
+
// update-check already depends on this module for readCurrentCliVersion.
|
|
8
|
+
export const POSTPLUS_CLI_UPDATE_COMMAND = 'npm install -g @postplus/cli@latest';
|
|
5
9
|
export const POSTPLUS_CLIENT_COMPATIBILITY_HEADERS = {
|
|
6
10
|
cliVersion: 'x-postplus-cli-version',
|
|
7
11
|
contractVersion: 'x-postplus-client-contract-version',
|
|
@@ -10,16 +14,19 @@ export const POSTPLUS_CLIENT_COMPATIBILITY_HEADERS = {
|
|
|
10
14
|
skillName: 'x-postplus-skill-name',
|
|
11
15
|
};
|
|
12
16
|
export async function buildPostPlusClientCompatibilityHeaders(input = {}) {
|
|
17
|
+
const hasReleaseIdOverride = input.skillsReleaseId !== undefined;
|
|
13
18
|
const [cliVersion, config] = await Promise.all([
|
|
14
19
|
readCurrentCliVersion(),
|
|
15
|
-
readLocalConfig(),
|
|
20
|
+
hasReleaseIdOverride ? Promise.resolve(null) : readLocalConfig(),
|
|
16
21
|
]);
|
|
17
22
|
const headers = {
|
|
18
23
|
[POSTPLUS_CLIENT_COMPATIBILITY_HEADERS.cliVersion]: cliVersion,
|
|
19
24
|
[POSTPLUS_CLIENT_COMPATIBILITY_HEADERS.contractVersion]: String(POSTPLUS_CLIENT_CONTRACT_VERSION),
|
|
20
25
|
[POSTPLUS_CLIENT_COMPATIBILITY_HEADERS.runtime]: POSTPLUS_CLIENT_RUNTIME,
|
|
21
26
|
};
|
|
22
|
-
const skillsReleaseId =
|
|
27
|
+
const skillsReleaseId = hasReleaseIdOverride
|
|
28
|
+
? input.skillsReleaseId?.trim()
|
|
29
|
+
: config?.managedSkills?.releaseId?.trim();
|
|
23
30
|
const skillName = input.skillName?.trim();
|
|
24
31
|
if (skillsReleaseId) {
|
|
25
32
|
headers[POSTPLUS_CLIENT_COMPATIBILITY_HEADERS.skillsReleaseId] =
|
|
@@ -50,8 +57,7 @@ export function formatPostPlusClientUpgradeError(payload) {
|
|
|
50
57
|
const record = payload && typeof payload === 'object' && !Array.isArray(payload)
|
|
51
58
|
? payload
|
|
52
59
|
: {};
|
|
53
|
-
const cliCommand = record.compatibility?.upgrade?.cli?.command ??
|
|
54
|
-
'npm install -g @postplus/cli@latest';
|
|
60
|
+
const cliCommand = record.compatibility?.upgrade?.cli?.command ?? POSTPLUS_CLI_UPDATE_COMMAND;
|
|
55
61
|
const skillsCommand = record.compatibility?.upgrade?.skills?.command ?? 'postplus update';
|
|
56
62
|
const restart = record.compatibility?.upgrade?.restartAgentSession
|
|
57
63
|
? ' Then restart your agent session.'
|
|
@@ -169,7 +169,8 @@ export const HOSTED_EXECUTION_MANIFESTS = {
|
|
|
169
169
|
"image-seedream-v5-lite-text",
|
|
170
170
|
"image-seedream-v5-lite-sequential",
|
|
171
171
|
"image-seedream-v5-lite-edit",
|
|
172
|
-
"image-seedream-v5-lite-edit-sequential"
|
|
172
|
+
"image-seedream-v5-lite-edit-sequential",
|
|
173
|
+
"image-higgsfield-soul-text"
|
|
173
174
|
],
|
|
174
175
|
"endpoints": [
|
|
175
176
|
{
|
|
@@ -1123,6 +1124,82 @@ export const HOSTED_EXECUTION_MANIFESTS = {
|
|
|
1123
1124
|
"billingDimensions": [
|
|
1124
1125
|
"billableUnitCount"
|
|
1125
1126
|
]
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
"endpointKey": "image-higgsfield-soul-text",
|
|
1130
|
+
"provider": "higgsfield",
|
|
1131
|
+
"providerModelPath": "higgsfield-ai/soul/standard",
|
|
1132
|
+
"fields": [
|
|
1133
|
+
{
|
|
1134
|
+
"name": "prompt",
|
|
1135
|
+
"class": "intent",
|
|
1136
|
+
"flag": "--prompt",
|
|
1137
|
+
"type": "string",
|
|
1138
|
+
"required": true
|
|
1139
|
+
},
|
|
1140
|
+
{
|
|
1141
|
+
"name": "aspect_ratio",
|
|
1142
|
+
"class": "default",
|
|
1143
|
+
"flag": "--aspect-ratio",
|
|
1144
|
+
"type": "string",
|
|
1145
|
+
"enumValues": [
|
|
1146
|
+
"9:16",
|
|
1147
|
+
"16:9",
|
|
1148
|
+
"4:3",
|
|
1149
|
+
"3:4",
|
|
1150
|
+
"1:1",
|
|
1151
|
+
"2:3",
|
|
1152
|
+
"3:2"
|
|
1153
|
+
],
|
|
1154
|
+
"default": "1:1",
|
|
1155
|
+
"required": false
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
"name": "style_id",
|
|
1159
|
+
"class": "intent",
|
|
1160
|
+
"flag": "--style-id",
|
|
1161
|
+
"type": "string",
|
|
1162
|
+
"required": false
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
"name": "style_strength",
|
|
1166
|
+
"class": "intent",
|
|
1167
|
+
"flag": "--style-strength",
|
|
1168
|
+
"type": "number",
|
|
1169
|
+
"required": false
|
|
1170
|
+
},
|
|
1171
|
+
{
|
|
1172
|
+
"name": "seed",
|
|
1173
|
+
"class": "intent",
|
|
1174
|
+
"flag": "--seed",
|
|
1175
|
+
"type": "number",
|
|
1176
|
+
"required": false
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
"name": "enhance_prompt",
|
|
1180
|
+
"class": "intent",
|
|
1181
|
+
"flag": "--enhance-prompt",
|
|
1182
|
+
"type": "boolean",
|
|
1183
|
+
"required": false
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
"name": "operationId",
|
|
1187
|
+
"class": "runner-managed",
|
|
1188
|
+
"flag": null,
|
|
1189
|
+
"type": "string",
|
|
1190
|
+
"required": false
|
|
1191
|
+
},
|
|
1192
|
+
{
|
|
1193
|
+
"name": "quoteConfirmationToken",
|
|
1194
|
+
"class": "runner-managed",
|
|
1195
|
+
"flag": null,
|
|
1196
|
+
"type": "string",
|
|
1197
|
+
"required": false
|
|
1198
|
+
}
|
|
1199
|
+
],
|
|
1200
|
+
"billingDimensions": [
|
|
1201
|
+
"billableUnitCount"
|
|
1202
|
+
]
|
|
1126
1203
|
}
|
|
1127
1204
|
]
|
|
1128
1205
|
}
|
|
@@ -1181,6 +1258,8 @@ export const HOSTED_EXECUTION_MANIFESTS = {
|
|
|
1181
1258
|
"capability": "media-generation",
|
|
1182
1259
|
"endpointKeys": [
|
|
1183
1260
|
"video-seedance-2-image",
|
|
1261
|
+
"video-seedance-2-mini-image",
|
|
1262
|
+
"video-seedance-2-mini-text",
|
|
1184
1263
|
"video-seedance-2-text"
|
|
1185
1264
|
],
|
|
1186
1265
|
"endpoints": [
|
|
@@ -1256,6 +1335,200 @@ export const HOSTED_EXECUTION_MANIFESTS = {
|
|
|
1256
1335
|
"referenceVideoMode"
|
|
1257
1336
|
]
|
|
1258
1337
|
},
|
|
1338
|
+
{
|
|
1339
|
+
"endpointKey": "video-seedance-2-mini-image",
|
|
1340
|
+
"provider": "wavespeed",
|
|
1341
|
+
"providerModelPath": "bytedance/seedance-2.0-mini/image-to-video",
|
|
1342
|
+
"fields": [
|
|
1343
|
+
{
|
|
1344
|
+
"name": "prompt",
|
|
1345
|
+
"class": "intent",
|
|
1346
|
+
"flag": null,
|
|
1347
|
+
"type": "string",
|
|
1348
|
+
"required": true
|
|
1349
|
+
},
|
|
1350
|
+
{
|
|
1351
|
+
"name": "image",
|
|
1352
|
+
"class": "intent",
|
|
1353
|
+
"flag": null,
|
|
1354
|
+
"type": "media-url",
|
|
1355
|
+
"required": true
|
|
1356
|
+
},
|
|
1357
|
+
{
|
|
1358
|
+
"name": "resolution",
|
|
1359
|
+
"class": "default",
|
|
1360
|
+
"flag": null,
|
|
1361
|
+
"type": "string",
|
|
1362
|
+
"enumValues": [
|
|
1363
|
+
"480p",
|
|
1364
|
+
"720p",
|
|
1365
|
+
"1080p",
|
|
1366
|
+
"4k"
|
|
1367
|
+
],
|
|
1368
|
+
"canonicalize": "lowercase",
|
|
1369
|
+
"default": "720p",
|
|
1370
|
+
"required": false
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
"name": "duration",
|
|
1374
|
+
"class": "default",
|
|
1375
|
+
"flag": null,
|
|
1376
|
+
"type": "number",
|
|
1377
|
+
"default": 5,
|
|
1378
|
+
"required": false,
|
|
1379
|
+
"min": 4,
|
|
1380
|
+
"max": 15
|
|
1381
|
+
},
|
|
1382
|
+
{
|
|
1383
|
+
"name": "operationId",
|
|
1384
|
+
"class": "runner-managed",
|
|
1385
|
+
"flag": null,
|
|
1386
|
+
"type": "string",
|
|
1387
|
+
"required": false
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
"name": "quoteConfirmationToken",
|
|
1391
|
+
"class": "runner-managed",
|
|
1392
|
+
"flag": null,
|
|
1393
|
+
"type": "string",
|
|
1394
|
+
"required": false
|
|
1395
|
+
},
|
|
1396
|
+
{
|
|
1397
|
+
"name": "requestDimensions",
|
|
1398
|
+
"class": "runner-managed",
|
|
1399
|
+
"flag": null,
|
|
1400
|
+
"type": "string",
|
|
1401
|
+
"required": false
|
|
1402
|
+
}
|
|
1403
|
+
],
|
|
1404
|
+
"billingDimensions": [
|
|
1405
|
+
"duration",
|
|
1406
|
+
"resolution",
|
|
1407
|
+
"referenceVideoCount",
|
|
1408
|
+
"referenceVideoMode"
|
|
1409
|
+
]
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
"endpointKey": "video-seedance-2-mini-text",
|
|
1413
|
+
"provider": "wavespeed",
|
|
1414
|
+
"providerModelPath": "bytedance/seedance-2.0-mini/text-to-video",
|
|
1415
|
+
"fields": [
|
|
1416
|
+
{
|
|
1417
|
+
"name": "prompt",
|
|
1418
|
+
"class": "intent",
|
|
1419
|
+
"flag": null,
|
|
1420
|
+
"type": "string",
|
|
1421
|
+
"required": true
|
|
1422
|
+
},
|
|
1423
|
+
{
|
|
1424
|
+
"name": "resolution",
|
|
1425
|
+
"class": "default",
|
|
1426
|
+
"flag": null,
|
|
1427
|
+
"type": "string",
|
|
1428
|
+
"enumValues": [
|
|
1429
|
+
"480p",
|
|
1430
|
+
"720p",
|
|
1431
|
+
"1080p",
|
|
1432
|
+
"4k"
|
|
1433
|
+
],
|
|
1434
|
+
"canonicalize": "lowercase",
|
|
1435
|
+
"default": "720p",
|
|
1436
|
+
"required": false
|
|
1437
|
+
},
|
|
1438
|
+
{
|
|
1439
|
+
"name": "aspect_ratio",
|
|
1440
|
+
"class": "intent",
|
|
1441
|
+
"flag": null,
|
|
1442
|
+
"type": "string",
|
|
1443
|
+
"enumValues": [
|
|
1444
|
+
"21:9",
|
|
1445
|
+
"16:9",
|
|
1446
|
+
"4:3",
|
|
1447
|
+
"1:1",
|
|
1448
|
+
"3:4",
|
|
1449
|
+
"9:16"
|
|
1450
|
+
],
|
|
1451
|
+
"required": false
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
"name": "duration",
|
|
1455
|
+
"class": "default",
|
|
1456
|
+
"flag": null,
|
|
1457
|
+
"type": "number",
|
|
1458
|
+
"default": 5,
|
|
1459
|
+
"required": false,
|
|
1460
|
+
"min": 4,
|
|
1461
|
+
"max": 15
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
"name": "reference_images",
|
|
1465
|
+
"class": "intent",
|
|
1466
|
+
"flag": null,
|
|
1467
|
+
"type": "media-url",
|
|
1468
|
+
"repeatable": true,
|
|
1469
|
+
"required": false
|
|
1470
|
+
},
|
|
1471
|
+
{
|
|
1472
|
+
"name": "reference_videos",
|
|
1473
|
+
"class": "intent",
|
|
1474
|
+
"flag": null,
|
|
1475
|
+
"type": "media-url",
|
|
1476
|
+
"repeatable": true,
|
|
1477
|
+
"required": false
|
|
1478
|
+
},
|
|
1479
|
+
{
|
|
1480
|
+
"name": "reference_audios",
|
|
1481
|
+
"class": "intent",
|
|
1482
|
+
"flag": null,
|
|
1483
|
+
"type": "media-url",
|
|
1484
|
+
"repeatable": true,
|
|
1485
|
+
"required": false
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
"name": "enable_web_search",
|
|
1489
|
+
"class": "default",
|
|
1490
|
+
"flag": null,
|
|
1491
|
+
"type": "boolean",
|
|
1492
|
+
"default": false,
|
|
1493
|
+
"required": false
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
"name": "generate_audio",
|
|
1497
|
+
"class": "default",
|
|
1498
|
+
"flag": null,
|
|
1499
|
+
"type": "boolean",
|
|
1500
|
+
"default": true,
|
|
1501
|
+
"required": false
|
|
1502
|
+
},
|
|
1503
|
+
{
|
|
1504
|
+
"name": "operationId",
|
|
1505
|
+
"class": "runner-managed",
|
|
1506
|
+
"flag": null,
|
|
1507
|
+
"type": "string",
|
|
1508
|
+
"required": false
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
"name": "quoteConfirmationToken",
|
|
1512
|
+
"class": "runner-managed",
|
|
1513
|
+
"flag": null,
|
|
1514
|
+
"type": "string",
|
|
1515
|
+
"required": false
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
"name": "requestDimensions",
|
|
1519
|
+
"class": "runner-managed",
|
|
1520
|
+
"flag": null,
|
|
1521
|
+
"type": "string",
|
|
1522
|
+
"required": false
|
|
1523
|
+
}
|
|
1524
|
+
],
|
|
1525
|
+
"billingDimensions": [
|
|
1526
|
+
"duration",
|
|
1527
|
+
"resolution",
|
|
1528
|
+
"referenceVideoCount",
|
|
1529
|
+
"referenceVideoMode"
|
|
1530
|
+
]
|
|
1531
|
+
},
|
|
1259
1532
|
{
|
|
1260
1533
|
"endpointKey": "video-seedance-2-text",
|
|
1261
1534
|
"provider": "wavespeed",
|
|
@@ -1323,6 +1596,30 @@ export const HOSTED_EXECUTION_MANIFESTS = {
|
|
|
1323
1596
|
"repeatable": true,
|
|
1324
1597
|
"required": false
|
|
1325
1598
|
},
|
|
1599
|
+
{
|
|
1600
|
+
"name": "reference_audios",
|
|
1601
|
+
"class": "intent",
|
|
1602
|
+
"flag": null,
|
|
1603
|
+
"type": "media-url",
|
|
1604
|
+
"repeatable": true,
|
|
1605
|
+
"required": false
|
|
1606
|
+
},
|
|
1607
|
+
{
|
|
1608
|
+
"name": "enable_web_search",
|
|
1609
|
+
"class": "default",
|
|
1610
|
+
"flag": null,
|
|
1611
|
+
"type": "boolean",
|
|
1612
|
+
"default": false,
|
|
1613
|
+
"required": false
|
|
1614
|
+
},
|
|
1615
|
+
{
|
|
1616
|
+
"name": "generate_audio",
|
|
1617
|
+
"class": "default",
|
|
1618
|
+
"flag": null,
|
|
1619
|
+
"type": "boolean",
|
|
1620
|
+
"default": true,
|
|
1621
|
+
"required": false
|
|
1622
|
+
},
|
|
1326
1623
|
{
|
|
1327
1624
|
"name": "operationId",
|
|
1328
1625
|
"class": "runner-managed",
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// GENERATED from apps/web/lib/server/postplus-cli/hosted-field-validation-core.ts.
|
|
2
|
+
// Do not edit by hand. Run `pnpm hosted-execution-manifest:sync` to regenerate.
|
|
3
|
+
// Verbatim projection so the canonicalize + enum/range field-validation algorithm stays
|
|
4
|
+
// byte-identical to the Web boundary (the CLI submodule cannot import apps/web TS).
|
|
5
|
+
// k-tier normalization for image resolution ("4K" -> "4k").
|
|
6
|
+
export function canonicalizeImageResolution(value) {
|
|
7
|
+
const trimmed = value.trim();
|
|
8
|
+
const tier = trimmed.match(/^(\d+(?:\.\d+)?)\s*k$/iu);
|
|
9
|
+
return tier ? `${tier[1]}k` : trimmed;
|
|
10
|
+
}
|
|
11
|
+
export function canonicalizeLowercaseToken(value) {
|
|
12
|
+
return value.trim().toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
// Which canonicalization a field uses is decided by the schema `canonicalize` hint —
|
|
15
|
+
// the single source both surfaces read — never re-guessed from the field name.
|
|
16
|
+
export function canonicalizeModelledFieldValue(field, value) {
|
|
17
|
+
switch (field.canonicalize) {
|
|
18
|
+
case 'image-resolution-tier':
|
|
19
|
+
return canonicalizeImageResolution(value);
|
|
20
|
+
case 'lowercase':
|
|
21
|
+
return canonicalizeLowercaseToken(value);
|
|
22
|
+
default:
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function formatReceivedValue(raw) {
|
|
27
|
+
return typeof raw === 'string' ? `"${raw}"` : String(raw);
|
|
28
|
+
}
|
|
29
|
+
function assertModelledNumberFieldValue(endpointKey, field, raw, createError) {
|
|
30
|
+
const enumValues = field.enumValues && field.enumValues.length > 0 ? field.enumValues : null;
|
|
31
|
+
const constraint = enumValues
|
|
32
|
+
? `must be one of ${enumValues.join(', ')}`
|
|
33
|
+
: `must be an integer from ${field.min} to ${field.max}`;
|
|
34
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
|
35
|
+
throw createError(`${endpointKey} ${field.name} ${constraint}; received ${formatReceivedValue(raw)}.`);
|
|
36
|
+
}
|
|
37
|
+
if (enumValues) {
|
|
38
|
+
if (!enumValues.includes(String(raw))) {
|
|
39
|
+
throw createError(`${endpointKey} ${field.name} ${constraint}; received ${raw}.`);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (field.min === undefined || field.max === undefined) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!(Number.isInteger(raw) && raw >= field.min && raw <= field.max)) {
|
|
47
|
+
throw createError(`${endpointKey} ${field.name} ${constraint}; received ${raw}.`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Validates every advertised enum / numeric-range field present in the input against
|
|
51
|
+
// the field contract. Skips runner-managed fields (no caller input), fields with
|
|
52
|
+
// neither an enum nor a range, and fields the input omits. The string value is
|
|
53
|
+
// canonicalized with the schema hint before the enum membership check, so a mixed-case
|
|
54
|
+
// "720P"/"4K" still matches the lowercase registry enum while "english" still fails the
|
|
55
|
+
// Title-cased language enum. The error factory is injected: the Web boundary passes its
|
|
56
|
+
// typed invalid_request error, the CLI early validator passes a plain Error.
|
|
57
|
+
export function assertModelledFieldValuesInRange(endpointKey, fields, input, createError) {
|
|
58
|
+
for (const field of fields) {
|
|
59
|
+
if (field.class === 'runner-managed') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const enumValues = field.enumValues && field.enumValues.length > 0 ? field.enumValues : null;
|
|
63
|
+
const hasRange = field.min !== undefined && field.max !== undefined;
|
|
64
|
+
if (!enumValues && !hasRange) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (!Object.hasOwn(input, field.name)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (field.type === 'number') {
|
|
71
|
+
assertModelledNumberFieldValue(endpointKey, field, input[field.name], createError);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const raw = input[field.name];
|
|
75
|
+
if (typeof raw !== 'string' || !raw.trim()) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const value = raw.trim();
|
|
79
|
+
if (enumValues &&
|
|
80
|
+
!enumValues.includes(canonicalizeModelledFieldValue(field, value))) {
|
|
81
|
+
throw createError(`${endpointKey} ${field.name} must be one of ${enumValues.join(', ')}; received "${value}".`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AuthedCloudRequestAuth } from './authed-cloud-request.js';
|
|
2
|
+
import { type HostedDomain } from './hosted-manifest-index.js';
|
|
3
|
+
export type HostedRequestContext = {
|
|
4
|
+
auth: AuthedCloudRequestAuth;
|
|
5
|
+
skillsReleaseId?: string;
|
|
6
|
+
/**
|
|
7
|
+
* The request-json envelope injected in place of a `--request <file>` read.
|
|
8
|
+
* Surfaces that need a body assert it is present and the right shape (object vs
|
|
9
|
+
* array) exactly as the file-read path validated the parsed file contents.
|
|
10
|
+
*/
|
|
11
|
+
requestJson?: Record<string, unknown> | unknown[];
|
|
12
|
+
};
|
|
13
|
+
export declare function runHostedDomainCommand(domain: HostedDomain, args: string[], context?: HostedRequestContext): Promise<number | unknown>;
|
|
14
|
+
export declare function runMediaFileCommand(args: string[], context?: HostedRequestContext): Promise<number | unknown>;
|