deepline 0.1.317 → 0.1.319
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/bundling-sources/sdk/src/client.ts +60 -25
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +18 -4
- package/dist/cli/index.js +121 -29
- package/dist/cli/index.mjs +121 -29
- package/dist/index.d.mts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.js +46 -27
- package/dist/index.mjs +46 -27
- package/dist/viewer/viewer.css +64 -61
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1022,7 +1022,7 @@ var SDK_RELEASE = {
|
|
|
1022
1022
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
1023
1023
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
1024
1024
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
1025
|
-
version: "0.1.
|
|
1025
|
+
version: "0.1.319",
|
|
1026
1026
|
contracts: {
|
|
1027
1027
|
api: {
|
|
1028
1028
|
name: "sdk-http-api",
|
|
@@ -3512,6 +3512,9 @@ function stagedUploadIdentity(logicalPath, contentHash) {
|
|
|
3512
3512
|
function isStagedUploadMintUnsupported(error) {
|
|
3513
3513
|
return error instanceof DeeplineError && error.statusCode === 404;
|
|
3514
3514
|
}
|
|
3515
|
+
function isStagedUploadDirectEgressDenied(error) {
|
|
3516
|
+
return error instanceof DeeplineError && error.code === "STAGED_FILE_UPLOAD_EGRESS_DENIED";
|
|
3517
|
+
}
|
|
3515
3518
|
function formatMegabytes(bytes) {
|
|
3516
3519
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
3517
3520
|
}
|
|
@@ -3532,10 +3535,11 @@ async function uploadStagedFileToPresignedUrl(input2) {
|
|
|
3532
3535
|
return;
|
|
3533
3536
|
}
|
|
3534
3537
|
const text = await response.text().catch(() => "");
|
|
3538
|
+
const egressDenied = response.status === 403 && response.headers.get("x-deny-reason")?.trim().toLowerCase() === "host_not_allowed";
|
|
3535
3539
|
lastError = new DeeplineError(
|
|
3536
3540
|
`Direct storage upload of ${input2.logicalPath} failed: ${response.status} ${text.slice(0, 200)}`,
|
|
3537
3541
|
response.status,
|
|
3538
|
-
"STAGED_FILE_UPLOAD_FAILED",
|
|
3542
|
+
egressDenied ? "STAGED_FILE_UPLOAD_EGRESS_DENIED" : "STAGED_FILE_UPLOAD_FAILED",
|
|
3539
3543
|
{ logicalPath: input2.logicalPath }
|
|
3540
3544
|
);
|
|
3541
3545
|
if (response.status < 500 && response.status !== 429) {
|
|
@@ -4435,7 +4439,7 @@ var DeeplineClient = class {
|
|
|
4435
4439
|
upload
|
|
4436
4440
|
);
|
|
4437
4441
|
}
|
|
4438
|
-
await Promise.all(
|
|
4442
|
+
const directResults = await Promise.all(
|
|
4439
4443
|
files.map(async (file) => {
|
|
4440
4444
|
const upload = uploadByIdentity.get(
|
|
4441
4445
|
stagedUploadIdentity(file.logicalPath, file.contentHash)
|
|
@@ -4448,31 +4452,45 @@ var DeeplineClient = class {
|
|
|
4448
4452
|
);
|
|
4449
4453
|
}
|
|
4450
4454
|
if (upload.alreadyStaged || !upload.uploadUrl) {
|
|
4451
|
-
return;
|
|
4455
|
+
return { ref: upload.ref };
|
|
4456
|
+
}
|
|
4457
|
+
try {
|
|
4458
|
+
await uploadStagedFileToPresignedUrl({
|
|
4459
|
+
url: upload.uploadUrl,
|
|
4460
|
+
headers: upload.uploadHeaders ?? {
|
|
4461
|
+
"content-type": file.contentType
|
|
4462
|
+
},
|
|
4463
|
+
body: decodeBase64Bytes(file.contentBase64),
|
|
4464
|
+
logicalPath: file.logicalPath
|
|
4465
|
+
});
|
|
4466
|
+
return { ref: upload.ref };
|
|
4467
|
+
} catch (error) {
|
|
4468
|
+
if (isStagedUploadDirectEgressDenied(error)) {
|
|
4469
|
+
return { fallbackFile: file };
|
|
4470
|
+
}
|
|
4471
|
+
throw error;
|
|
4452
4472
|
}
|
|
4453
|
-
await uploadStagedFileToPresignedUrl({
|
|
4454
|
-
url: upload.uploadUrl,
|
|
4455
|
-
headers: upload.uploadHeaders ?? {
|
|
4456
|
-
"content-type": file.contentType
|
|
4457
|
-
},
|
|
4458
|
-
body: decodeBase64Bytes(file.contentBase64),
|
|
4459
|
-
logicalPath: file.logicalPath
|
|
4460
|
-
});
|
|
4461
4473
|
})
|
|
4462
4474
|
);
|
|
4463
|
-
return
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4475
|
+
return await Promise.all(
|
|
4476
|
+
directResults.map(async (result) => {
|
|
4477
|
+
if ("fallbackFile" in result) {
|
|
4478
|
+
const [ref] = await this.stagePlayFilesViaMultipart(
|
|
4479
|
+
[result.fallbackFile],
|
|
4480
|
+
"direct-egress-denied"
|
|
4481
|
+
);
|
|
4482
|
+
if (!ref) {
|
|
4483
|
+
throw new DeeplineError(
|
|
4484
|
+
`The staging server did not return an upload target for ${result.fallbackFile.logicalPath}.`,
|
|
4485
|
+
void 0,
|
|
4486
|
+
"STAGED_FILE_MINT_INCOMPLETE"
|
|
4487
|
+
);
|
|
4488
|
+
}
|
|
4489
|
+
return ref;
|
|
4490
|
+
}
|
|
4491
|
+
return result.ref;
|
|
4492
|
+
})
|
|
4493
|
+
);
|
|
4476
4494
|
}
|
|
4477
4495
|
/**
|
|
4478
4496
|
* Mint short-lived presigned upload targets for staged play files.
|
|
@@ -4485,11 +4503,12 @@ var DeeplineClient = class {
|
|
|
4485
4503
|
const response = await this.http.post("/api/v2/plays/files/stage/mint", { files });
|
|
4486
4504
|
return response.uploads ?? [];
|
|
4487
4505
|
}
|
|
4488
|
-
async stagePlayFilesViaMultipart(files) {
|
|
4506
|
+
async stagePlayFilesViaMultipart(files, reason = "mint-unsupported") {
|
|
4489
4507
|
for (const file of files) {
|
|
4490
4508
|
if (file.bytes > STAGE_LEGACY_MULTIPART_MAX_BYTES) {
|
|
4509
|
+
const reasonMessage = reason === "direct-egress-denied" ? "direct storage is blocked by this environment's network egress policy" : "the connected Deepline server does not support direct-to-storage uploads";
|
|
4491
4510
|
throw new DeeplineError(
|
|
4492
|
-
`Cannot stage ${file.logicalPath} (${formatMegabytes(file.bytes)}):
|
|
4511
|
+
`Cannot stage ${file.logicalPath} (${formatMegabytes(file.bytes)}): ${reasonMessage}, and this file exceeds the ~4.5MB request-body limit the legacy upload path is subject to.`,
|
|
4493
4512
|
413,
|
|
4494
4513
|
"STAGED_FILE_TOO_LARGE_FOR_LEGACY_UPLOAD",
|
|
4495
4514
|
{
|
|
@@ -28618,14 +28637,23 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
|
28618
28637
|
"deeplineUsdPerPricingUnit",
|
|
28619
28638
|
"deepline_usd_per_pricing_unit"
|
|
28620
28639
|
);
|
|
28621
|
-
const
|
|
28640
|
+
const deprecation = recordField2(tool, "deprecation");
|
|
28641
|
+
const replacementToolId = stringField2(
|
|
28642
|
+
deprecation,
|
|
28643
|
+
"replacementToolId",
|
|
28644
|
+
"replacement_tool_id"
|
|
28645
|
+
);
|
|
28646
|
+
const deprecationMessage = stringField2(deprecation, "message");
|
|
28647
|
+
const deprecationExecution = stringField2(deprecation, "execution");
|
|
28648
|
+
const deprecated = tool.deprecated === true || stringField2(tool, "credentialStatus", "credential_status") === "deprecated";
|
|
28649
|
+
const starterScript = !deprecated && !isPlayLikeTool(tool) && extractedLists.length > 0 ? starterScriptJson(
|
|
28622
28650
|
seedToolListScript({
|
|
28623
28651
|
toolId,
|
|
28624
28652
|
payload: samplePayloadForInputFields(inputFields),
|
|
28625
28653
|
rows: []
|
|
28626
28654
|
})
|
|
28627
28655
|
) : null;
|
|
28628
|
-
const executeCommand = isPlayLikeTool(tool) ? playRunCommandForTool(tool, toolId) : `deepline tools execute ${toolId} --input '{...}' --json`;
|
|
28656
|
+
const executeCommand = deprecated && replacementToolId ? `deepline tools execute ${replacementToolId} --input '{...}' --json` : isPlayLikeTool(tool) ? playRunCommandForTool(tool, toolId) : `deepline tools execute ${toolId} --input '{...}' --json`;
|
|
28629
28657
|
return {
|
|
28630
28658
|
schemaVersion: 1,
|
|
28631
28659
|
toolId,
|
|
@@ -28633,6 +28661,15 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
|
28633
28661
|
displayName: tool.displayName,
|
|
28634
28662
|
description: tool.description,
|
|
28635
28663
|
categories: tool.categories,
|
|
28664
|
+
...deprecated ? {
|
|
28665
|
+
deprecated: true,
|
|
28666
|
+
callable: tool.callable !== false,
|
|
28667
|
+
deprecation: {
|
|
28668
|
+
replacementToolId,
|
|
28669
|
+
message: deprecationMessage,
|
|
28670
|
+
...deprecationExecution ? { execution: deprecationExecution } : {}
|
|
28671
|
+
}
|
|
28672
|
+
} : {},
|
|
28636
28673
|
inputFields: inputFields.map((field) => ({
|
|
28637
28674
|
name: field.name,
|
|
28638
28675
|
type: field.type ?? "unknown",
|
|
@@ -28775,6 +28812,29 @@ function printCompactToolContract(tool, requestedToolId) {
|
|
|
28775
28812
|
if (Array.isArray(contract.categories) && contract.categories.length) {
|
|
28776
28813
|
console.log(`Tags: ${contract.categories.join(", ")}`);
|
|
28777
28814
|
}
|
|
28815
|
+
if (contract.deprecated === true) {
|
|
28816
|
+
const deprecation = isRecord11(contract.deprecation) ? contract.deprecation : {};
|
|
28817
|
+
const message = stringField2(deprecation, "message");
|
|
28818
|
+
const replacementToolId = stringField2(
|
|
28819
|
+
deprecation,
|
|
28820
|
+
"replacementToolId",
|
|
28821
|
+
"replacement_tool_id"
|
|
28822
|
+
);
|
|
28823
|
+
console.log(
|
|
28824
|
+
contract.callable === false ? "Status: deprecated \u2014 this tool cannot be executed" : "Status: deprecated \u2014 legacy executions forward for compatibility"
|
|
28825
|
+
);
|
|
28826
|
+
if (message) console.log(`Migration: ${message}`);
|
|
28827
|
+
if (replacementToolId) {
|
|
28828
|
+
console.log(
|
|
28829
|
+
`Use: deepline tools execute ${replacementToolId} --input '{...}'`
|
|
28830
|
+
);
|
|
28831
|
+
}
|
|
28832
|
+
console.log("");
|
|
28833
|
+
console.log(
|
|
28834
|
+
`More: deepline tools describe ${replacementToolId || contract.toolId} --json`
|
|
28835
|
+
);
|
|
28836
|
+
return;
|
|
28837
|
+
}
|
|
28778
28838
|
printToolPricingOnly(tool, requestedToolId, { heading: "Cost" });
|
|
28779
28839
|
if (inputFields.length) {
|
|
28780
28840
|
console.log("");
|
|
@@ -29274,6 +29334,32 @@ function samplePayload(samples, key) {
|
|
|
29274
29334
|
function commandEnvelopeFromRawResponse(rawResponse) {
|
|
29275
29335
|
return isRecord11(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
|
|
29276
29336
|
}
|
|
29337
|
+
function extractToolExecutionWarningMessages(rawResponse) {
|
|
29338
|
+
if (!isRecord11(rawResponse)) return [];
|
|
29339
|
+
const candidates = [
|
|
29340
|
+
recordField2(recordField2(rawResponse, "toolResponse"), "meta"),
|
|
29341
|
+
recordField2(
|
|
29342
|
+
recordField2(recordField2(rawResponse, "toolResponse"), "raw"),
|
|
29343
|
+
"meta"
|
|
29344
|
+
),
|
|
29345
|
+
recordField2(rawResponse, "meta"),
|
|
29346
|
+
recordField2(recordField2(rawResponse, "result"), "meta")
|
|
29347
|
+
];
|
|
29348
|
+
const messages = [];
|
|
29349
|
+
for (const candidate of candidates) {
|
|
29350
|
+
const warnings = candidate?.warnings;
|
|
29351
|
+
if (!Array.isArray(warnings)) continue;
|
|
29352
|
+
for (const warning of warnings) {
|
|
29353
|
+
if (typeof warning === "string" && warning.trim()) {
|
|
29354
|
+
messages.push(warning.trim());
|
|
29355
|
+
} else if (isRecord11(warning)) {
|
|
29356
|
+
const message = stringField2(warning, "message");
|
|
29357
|
+
if (message) messages.push(message);
|
|
29358
|
+
}
|
|
29359
|
+
}
|
|
29360
|
+
}
|
|
29361
|
+
return [...new Set(messages)];
|
|
29362
|
+
}
|
|
29277
29363
|
function apifySyncRecoveryNext(rawResponse) {
|
|
29278
29364
|
if (!isRecord11(rawResponse) || rawResponse.status !== "running") return null;
|
|
29279
29365
|
const toolResponse = recordField2(rawResponse, "toolResponse");
|
|
@@ -29541,6 +29627,9 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
29541
29627
|
}
|
|
29542
29628
|
function buildToolExecuteBaseEnvelope(input2) {
|
|
29543
29629
|
const envelope = commandEnvelopeFromRawResponse(input2.rawResponse);
|
|
29630
|
+
const warningMessages = extractToolExecutionWarningMessages(
|
|
29631
|
+
input2.rawResponse
|
|
29632
|
+
);
|
|
29544
29633
|
const apifyRecovery = apifySyncRecoveryNext(input2.rawResponse);
|
|
29545
29634
|
const summaryEntries = Object.entries(input2.summary);
|
|
29546
29635
|
const outputPreview = input2.listConversion ? {
|
|
@@ -29578,6 +29667,7 @@ function buildToolExecuteBaseEnvelope(input2) {
|
|
|
29578
29667
|
...envelope,
|
|
29579
29668
|
...envelopeHasCanonicalOutput || envelopeHasDeclaredOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
29580
29669
|
...summaryEntries.length > 0 ? { summary: input2.summary } : {},
|
|
29670
|
+
...warningMessages.length > 0 ? { warnings: warningMessages } : {},
|
|
29581
29671
|
next: {
|
|
29582
29672
|
inspect: inspectCommand,
|
|
29583
29673
|
...apifyRecovery ?? {},
|
|
@@ -29589,6 +29679,7 @@ function buildToolExecuteBaseEnvelope(input2) {
|
|
|
29589
29679
|
},
|
|
29590
29680
|
render: {
|
|
29591
29681
|
sections: input2.listConversion ? [
|
|
29682
|
+
...warningMessages.length > 0 ? [{ title: "warnings", lines: warningMessages }] : [],
|
|
29592
29683
|
{
|
|
29593
29684
|
title: "output",
|
|
29594
29685
|
lines: [
|
|
@@ -29599,6 +29690,7 @@ function buildToolExecuteBaseEnvelope(input2) {
|
|
|
29599
29690
|
]
|
|
29600
29691
|
}
|
|
29601
29692
|
] : [
|
|
29693
|
+
...warningMessages.length > 0 ? [{ title: "warnings", lines: warningMessages }] : [],
|
|
29602
29694
|
{
|
|
29603
29695
|
title: "result",
|
|
29604
29696
|
lines: apifyRecovery ? [
|
package/dist/index.d.mts
CHANGED
|
@@ -355,16 +355,26 @@ interface ToolDefinition {
|
|
|
355
355
|
}>;
|
|
356
356
|
/**
|
|
357
357
|
* Whether this tool is callable in the current workspace. `false` for a
|
|
358
|
-
* bring-your-own-credential provider
|
|
359
|
-
* connected — the agent should offer to connect it rather than call it.
|
|
358
|
+
* bring-your-own-credential provider that has not been connected.
|
|
360
359
|
*/
|
|
361
360
|
connected?: boolean;
|
|
361
|
+
/** Whether the tool can be executed. Exact lookup may return non-callable deprecated aliases. */
|
|
362
|
+
callable?: boolean;
|
|
363
|
+
/** True when callers should migrate this exact tool id to its replacement. */
|
|
364
|
+
deprecated?: boolean;
|
|
365
|
+
/** Deprecation reason, replacement, and compatibility execution behavior. */
|
|
366
|
+
deprecation?: {
|
|
367
|
+
replacementToolId: string;
|
|
368
|
+
message: string;
|
|
369
|
+
execution?: 'terminal' | 'forward';
|
|
370
|
+
};
|
|
362
371
|
/**
|
|
363
372
|
* Connection status for discovery: `managed` (Deepline-run credentials),
|
|
364
373
|
* `connected` (your own credential is connected), or `requires_connection`
|
|
365
|
-
* (BYO provider not yet connected in this workspace).
|
|
374
|
+
* (BYO provider not yet connected in this workspace). `deprecated` means
|
|
375
|
+
* connecting credentials will not make the tool callable.
|
|
366
376
|
*/
|
|
367
|
-
credentialStatus?: 'managed' | 'connected' | 'requires_connection';
|
|
377
|
+
credentialStatus?: 'managed' | 'connected' | 'requires_connection' | 'deprecated';
|
|
368
378
|
/** True when the tool requires a customer-provided credential to run. */
|
|
369
379
|
requiresOwnCredential?: boolean;
|
|
370
380
|
/** Actionable message shown when a connection is required. */
|
package/dist/index.d.ts
CHANGED
|
@@ -355,16 +355,26 @@ interface ToolDefinition {
|
|
|
355
355
|
}>;
|
|
356
356
|
/**
|
|
357
357
|
* Whether this tool is callable in the current workspace. `false` for a
|
|
358
|
-
* bring-your-own-credential provider
|
|
359
|
-
* connected — the agent should offer to connect it rather than call it.
|
|
358
|
+
* bring-your-own-credential provider that has not been connected.
|
|
360
359
|
*/
|
|
361
360
|
connected?: boolean;
|
|
361
|
+
/** Whether the tool can be executed. Exact lookup may return non-callable deprecated aliases. */
|
|
362
|
+
callable?: boolean;
|
|
363
|
+
/** True when callers should migrate this exact tool id to its replacement. */
|
|
364
|
+
deprecated?: boolean;
|
|
365
|
+
/** Deprecation reason, replacement, and compatibility execution behavior. */
|
|
366
|
+
deprecation?: {
|
|
367
|
+
replacementToolId: string;
|
|
368
|
+
message: string;
|
|
369
|
+
execution?: 'terminal' | 'forward';
|
|
370
|
+
};
|
|
362
371
|
/**
|
|
363
372
|
* Connection status for discovery: `managed` (Deepline-run credentials),
|
|
364
373
|
* `connected` (your own credential is connected), or `requires_connection`
|
|
365
|
-
* (BYO provider not yet connected in this workspace).
|
|
374
|
+
* (BYO provider not yet connected in this workspace). `deprecated` means
|
|
375
|
+
* connecting credentials will not make the tool callable.
|
|
366
376
|
*/
|
|
367
|
-
credentialStatus?: 'managed' | 'connected' | 'requires_connection';
|
|
377
|
+
credentialStatus?: 'managed' | 'connected' | 'requires_connection' | 'deprecated';
|
|
368
378
|
/** True when the tool requires a customer-provided credential to run. */
|
|
369
379
|
requiresOwnCredential?: boolean;
|
|
370
380
|
/** Actionable message shown when a connection is required. */
|
package/dist/index.js
CHANGED
|
@@ -760,7 +760,7 @@ var SDK_RELEASE = {
|
|
|
760
760
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
761
761
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
762
762
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
763
|
-
version: "0.1.
|
|
763
|
+
version: "0.1.319",
|
|
764
764
|
contracts: {
|
|
765
765
|
api: {
|
|
766
766
|
name: "sdk-http-api",
|
|
@@ -3250,6 +3250,9 @@ function stagedUploadIdentity(logicalPath, contentHash) {
|
|
|
3250
3250
|
function isStagedUploadMintUnsupported(error) {
|
|
3251
3251
|
return error instanceof DeeplineError && error.statusCode === 404;
|
|
3252
3252
|
}
|
|
3253
|
+
function isStagedUploadDirectEgressDenied(error) {
|
|
3254
|
+
return error instanceof DeeplineError && error.code === "STAGED_FILE_UPLOAD_EGRESS_DENIED";
|
|
3255
|
+
}
|
|
3253
3256
|
function formatMegabytes(bytes) {
|
|
3254
3257
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
3255
3258
|
}
|
|
@@ -3270,10 +3273,11 @@ async function uploadStagedFileToPresignedUrl(input) {
|
|
|
3270
3273
|
return;
|
|
3271
3274
|
}
|
|
3272
3275
|
const text = await response.text().catch(() => "");
|
|
3276
|
+
const egressDenied = response.status === 403 && response.headers.get("x-deny-reason")?.trim().toLowerCase() === "host_not_allowed";
|
|
3273
3277
|
lastError = new DeeplineError(
|
|
3274
3278
|
`Direct storage upload of ${input.logicalPath} failed: ${response.status} ${text.slice(0, 200)}`,
|
|
3275
3279
|
response.status,
|
|
3276
|
-
"STAGED_FILE_UPLOAD_FAILED",
|
|
3280
|
+
egressDenied ? "STAGED_FILE_UPLOAD_EGRESS_DENIED" : "STAGED_FILE_UPLOAD_FAILED",
|
|
3277
3281
|
{ logicalPath: input.logicalPath }
|
|
3278
3282
|
);
|
|
3279
3283
|
if (response.status < 500 && response.status !== 429) {
|
|
@@ -4173,7 +4177,7 @@ var DeeplineClient = class {
|
|
|
4173
4177
|
upload
|
|
4174
4178
|
);
|
|
4175
4179
|
}
|
|
4176
|
-
await Promise.all(
|
|
4180
|
+
const directResults = await Promise.all(
|
|
4177
4181
|
files.map(async (file) => {
|
|
4178
4182
|
const upload = uploadByIdentity.get(
|
|
4179
4183
|
stagedUploadIdentity(file.logicalPath, file.contentHash)
|
|
@@ -4186,31 +4190,45 @@ var DeeplineClient = class {
|
|
|
4186
4190
|
);
|
|
4187
4191
|
}
|
|
4188
4192
|
if (upload.alreadyStaged || !upload.uploadUrl) {
|
|
4189
|
-
return;
|
|
4193
|
+
return { ref: upload.ref };
|
|
4194
|
+
}
|
|
4195
|
+
try {
|
|
4196
|
+
await uploadStagedFileToPresignedUrl({
|
|
4197
|
+
url: upload.uploadUrl,
|
|
4198
|
+
headers: upload.uploadHeaders ?? {
|
|
4199
|
+
"content-type": file.contentType
|
|
4200
|
+
},
|
|
4201
|
+
body: decodeBase64Bytes(file.contentBase64),
|
|
4202
|
+
logicalPath: file.logicalPath
|
|
4203
|
+
});
|
|
4204
|
+
return { ref: upload.ref };
|
|
4205
|
+
} catch (error) {
|
|
4206
|
+
if (isStagedUploadDirectEgressDenied(error)) {
|
|
4207
|
+
return { fallbackFile: file };
|
|
4208
|
+
}
|
|
4209
|
+
throw error;
|
|
4190
4210
|
}
|
|
4191
|
-
await uploadStagedFileToPresignedUrl({
|
|
4192
|
-
url: upload.uploadUrl,
|
|
4193
|
-
headers: upload.uploadHeaders ?? {
|
|
4194
|
-
"content-type": file.contentType
|
|
4195
|
-
},
|
|
4196
|
-
body: decodeBase64Bytes(file.contentBase64),
|
|
4197
|
-
logicalPath: file.logicalPath
|
|
4198
|
-
});
|
|
4199
4211
|
})
|
|
4200
4212
|
);
|
|
4201
|
-
return
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4213
|
+
return await Promise.all(
|
|
4214
|
+
directResults.map(async (result) => {
|
|
4215
|
+
if ("fallbackFile" in result) {
|
|
4216
|
+
const [ref] = await this.stagePlayFilesViaMultipart(
|
|
4217
|
+
[result.fallbackFile],
|
|
4218
|
+
"direct-egress-denied"
|
|
4219
|
+
);
|
|
4220
|
+
if (!ref) {
|
|
4221
|
+
throw new DeeplineError(
|
|
4222
|
+
`The staging server did not return an upload target for ${result.fallbackFile.logicalPath}.`,
|
|
4223
|
+
void 0,
|
|
4224
|
+
"STAGED_FILE_MINT_INCOMPLETE"
|
|
4225
|
+
);
|
|
4226
|
+
}
|
|
4227
|
+
return ref;
|
|
4228
|
+
}
|
|
4229
|
+
return result.ref;
|
|
4230
|
+
})
|
|
4231
|
+
);
|
|
4214
4232
|
}
|
|
4215
4233
|
/**
|
|
4216
4234
|
* Mint short-lived presigned upload targets for staged play files.
|
|
@@ -4223,11 +4241,12 @@ var DeeplineClient = class {
|
|
|
4223
4241
|
const response = await this.http.post("/api/v2/plays/files/stage/mint", { files });
|
|
4224
4242
|
return response.uploads ?? [];
|
|
4225
4243
|
}
|
|
4226
|
-
async stagePlayFilesViaMultipart(files) {
|
|
4244
|
+
async stagePlayFilesViaMultipart(files, reason = "mint-unsupported") {
|
|
4227
4245
|
for (const file of files) {
|
|
4228
4246
|
if (file.bytes > STAGE_LEGACY_MULTIPART_MAX_BYTES) {
|
|
4247
|
+
const reasonMessage = reason === "direct-egress-denied" ? "direct storage is blocked by this environment's network egress policy" : "the connected Deepline server does not support direct-to-storage uploads";
|
|
4229
4248
|
throw new DeeplineError(
|
|
4230
|
-
`Cannot stage ${file.logicalPath} (${formatMegabytes(file.bytes)}):
|
|
4249
|
+
`Cannot stage ${file.logicalPath} (${formatMegabytes(file.bytes)}): ${reasonMessage}, and this file exceeds the ~4.5MB request-body limit the legacy upload path is subject to.`,
|
|
4231
4250
|
413,
|
|
4232
4251
|
"STAGED_FILE_TOO_LARGE_FOR_LEGACY_UPLOAD",
|
|
4233
4252
|
{
|
package/dist/index.mjs
CHANGED
|
@@ -686,7 +686,7 @@ var SDK_RELEASE = {
|
|
|
686
686
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
687
687
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
688
688
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
689
|
-
version: "0.1.
|
|
689
|
+
version: "0.1.319",
|
|
690
690
|
contracts: {
|
|
691
691
|
api: {
|
|
692
692
|
name: "sdk-http-api",
|
|
@@ -3176,6 +3176,9 @@ function stagedUploadIdentity(logicalPath, contentHash) {
|
|
|
3176
3176
|
function isStagedUploadMintUnsupported(error) {
|
|
3177
3177
|
return error instanceof DeeplineError && error.statusCode === 404;
|
|
3178
3178
|
}
|
|
3179
|
+
function isStagedUploadDirectEgressDenied(error) {
|
|
3180
|
+
return error instanceof DeeplineError && error.code === "STAGED_FILE_UPLOAD_EGRESS_DENIED";
|
|
3181
|
+
}
|
|
3179
3182
|
function formatMegabytes(bytes) {
|
|
3180
3183
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
3181
3184
|
}
|
|
@@ -3196,10 +3199,11 @@ async function uploadStagedFileToPresignedUrl(input) {
|
|
|
3196
3199
|
return;
|
|
3197
3200
|
}
|
|
3198
3201
|
const text = await response.text().catch(() => "");
|
|
3202
|
+
const egressDenied = response.status === 403 && response.headers.get("x-deny-reason")?.trim().toLowerCase() === "host_not_allowed";
|
|
3199
3203
|
lastError = new DeeplineError(
|
|
3200
3204
|
`Direct storage upload of ${input.logicalPath} failed: ${response.status} ${text.slice(0, 200)}`,
|
|
3201
3205
|
response.status,
|
|
3202
|
-
"STAGED_FILE_UPLOAD_FAILED",
|
|
3206
|
+
egressDenied ? "STAGED_FILE_UPLOAD_EGRESS_DENIED" : "STAGED_FILE_UPLOAD_FAILED",
|
|
3203
3207
|
{ logicalPath: input.logicalPath }
|
|
3204
3208
|
);
|
|
3205
3209
|
if (response.status < 500 && response.status !== 429) {
|
|
@@ -4099,7 +4103,7 @@ var DeeplineClient = class {
|
|
|
4099
4103
|
upload
|
|
4100
4104
|
);
|
|
4101
4105
|
}
|
|
4102
|
-
await Promise.all(
|
|
4106
|
+
const directResults = await Promise.all(
|
|
4103
4107
|
files.map(async (file) => {
|
|
4104
4108
|
const upload = uploadByIdentity.get(
|
|
4105
4109
|
stagedUploadIdentity(file.logicalPath, file.contentHash)
|
|
@@ -4112,31 +4116,45 @@ var DeeplineClient = class {
|
|
|
4112
4116
|
);
|
|
4113
4117
|
}
|
|
4114
4118
|
if (upload.alreadyStaged || !upload.uploadUrl) {
|
|
4115
|
-
return;
|
|
4119
|
+
return { ref: upload.ref };
|
|
4120
|
+
}
|
|
4121
|
+
try {
|
|
4122
|
+
await uploadStagedFileToPresignedUrl({
|
|
4123
|
+
url: upload.uploadUrl,
|
|
4124
|
+
headers: upload.uploadHeaders ?? {
|
|
4125
|
+
"content-type": file.contentType
|
|
4126
|
+
},
|
|
4127
|
+
body: decodeBase64Bytes(file.contentBase64),
|
|
4128
|
+
logicalPath: file.logicalPath
|
|
4129
|
+
});
|
|
4130
|
+
return { ref: upload.ref };
|
|
4131
|
+
} catch (error) {
|
|
4132
|
+
if (isStagedUploadDirectEgressDenied(error)) {
|
|
4133
|
+
return { fallbackFile: file };
|
|
4134
|
+
}
|
|
4135
|
+
throw error;
|
|
4116
4136
|
}
|
|
4117
|
-
await uploadStagedFileToPresignedUrl({
|
|
4118
|
-
url: upload.uploadUrl,
|
|
4119
|
-
headers: upload.uploadHeaders ?? {
|
|
4120
|
-
"content-type": file.contentType
|
|
4121
|
-
},
|
|
4122
|
-
body: decodeBase64Bytes(file.contentBase64),
|
|
4123
|
-
logicalPath: file.logicalPath
|
|
4124
|
-
});
|
|
4125
4137
|
})
|
|
4126
4138
|
);
|
|
4127
|
-
return
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4139
|
+
return await Promise.all(
|
|
4140
|
+
directResults.map(async (result) => {
|
|
4141
|
+
if ("fallbackFile" in result) {
|
|
4142
|
+
const [ref] = await this.stagePlayFilesViaMultipart(
|
|
4143
|
+
[result.fallbackFile],
|
|
4144
|
+
"direct-egress-denied"
|
|
4145
|
+
);
|
|
4146
|
+
if (!ref) {
|
|
4147
|
+
throw new DeeplineError(
|
|
4148
|
+
`The staging server did not return an upload target for ${result.fallbackFile.logicalPath}.`,
|
|
4149
|
+
void 0,
|
|
4150
|
+
"STAGED_FILE_MINT_INCOMPLETE"
|
|
4151
|
+
);
|
|
4152
|
+
}
|
|
4153
|
+
return ref;
|
|
4154
|
+
}
|
|
4155
|
+
return result.ref;
|
|
4156
|
+
})
|
|
4157
|
+
);
|
|
4140
4158
|
}
|
|
4141
4159
|
/**
|
|
4142
4160
|
* Mint short-lived presigned upload targets for staged play files.
|
|
@@ -4149,11 +4167,12 @@ var DeeplineClient = class {
|
|
|
4149
4167
|
const response = await this.http.post("/api/v2/plays/files/stage/mint", { files });
|
|
4150
4168
|
return response.uploads ?? [];
|
|
4151
4169
|
}
|
|
4152
|
-
async stagePlayFilesViaMultipart(files) {
|
|
4170
|
+
async stagePlayFilesViaMultipart(files, reason = "mint-unsupported") {
|
|
4153
4171
|
for (const file of files) {
|
|
4154
4172
|
if (file.bytes > STAGE_LEGACY_MULTIPART_MAX_BYTES) {
|
|
4173
|
+
const reasonMessage = reason === "direct-egress-denied" ? "direct storage is blocked by this environment's network egress policy" : "the connected Deepline server does not support direct-to-storage uploads";
|
|
4155
4174
|
throw new DeeplineError(
|
|
4156
|
-
`Cannot stage ${file.logicalPath} (${formatMegabytes(file.bytes)}):
|
|
4175
|
+
`Cannot stage ${file.logicalPath} (${formatMegabytes(file.bytes)}): ${reasonMessage}, and this file exceeds the ~4.5MB request-body limit the legacy upload path is subject to.`,
|
|
4157
4176
|
413,
|
|
4158
4177
|
"STAGED_FILE_TOO_LARGE_FOR_LEGACY_UPLOAD",
|
|
4159
4178
|
{
|