deepline 0.1.178 → 0.1.180
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/apps/play-runner-workers/src/coordinator-entry.ts +132 -7
- package/dist/bundling-sources/apps/play-runner-workers/src/dedup-do.ts +25 -8
- package/dist/bundling-sources/apps/play-runner-workers/src/durable-object-deploy-handoff.ts +8 -2
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +414 -196
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +42 -2
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/coordinator-progress.ts +289 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +112 -1
- package/dist/bundling-sources/sdk/src/client.ts +237 -0
- package/dist/bundling-sources/sdk/src/http.ts +100 -9
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +10 -2
- package/dist/bundling-sources/shared_libs/play-runtime/batch-runtime.ts +58 -2
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +99 -25
- package/dist/bundling-sources/shared_libs/play-runtime/db-session.ts +7 -2
- package/dist/bundling-sources/shared_libs/play-runtime/persistence-latch.ts +167 -0
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-salvage.ts +158 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +44 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +74 -30
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +6 -0
- package/dist/cli/index.js +338 -13
- package/dist/cli/index.mjs +338 -13
- package/dist/index.d.mts +44 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +229 -9
- package/dist/index.mjs +229 -9
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -608,10 +608,10 @@ var SDK_RELEASE = {
|
|
|
608
608
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
609
609
|
// fields shipped in 0.1.153.
|
|
610
610
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
611
|
-
version: "0.1.
|
|
611
|
+
version: "0.1.180",
|
|
612
612
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
613
613
|
supportPolicy: {
|
|
614
|
-
latest: "0.1.
|
|
614
|
+
latest: "0.1.180",
|
|
615
615
|
minimumSupported: "0.1.53",
|
|
616
616
|
deprecatedBelow: "0.1.53",
|
|
617
617
|
commandMinimumSupported: [
|
|
@@ -772,6 +772,58 @@ var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
|
|
|
772
772
|
// src/http.ts
|
|
773
773
|
var MAX_DIAGNOSTIC_HEADER_LENGTH = 120;
|
|
774
774
|
var COWORK_NETWORK_HINT = "Claude Cowork appears to be running Deepline in a network-restricted sandbox. In Claude Desktop, open Settings > Capabilities, turn on Allow network egress, and set Domain allowlist to All domains for the Cowork session.";
|
|
775
|
+
var REQUEST_TIMEOUT_MARKER = /* @__PURE__ */ Symbol("deeplineRequestTimeout");
|
|
776
|
+
var REQUEST_ABORT_MARKER = /* @__PURE__ */ Symbol("deeplineRequestAbort");
|
|
777
|
+
function normalizeRequestAbortError(error, input2) {
|
|
778
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
779
|
+
const tagged = normalized;
|
|
780
|
+
if (input2.timedOut) {
|
|
781
|
+
tagged[REQUEST_TIMEOUT_MARKER] = input2.timeoutMs;
|
|
782
|
+
} else if (isAbortLikeError(normalized)) {
|
|
783
|
+
tagged[REQUEST_ABORT_MARKER] = true;
|
|
784
|
+
}
|
|
785
|
+
return normalized;
|
|
786
|
+
}
|
|
787
|
+
function isAbortLikeError(error) {
|
|
788
|
+
const name = error.name.toLowerCase();
|
|
789
|
+
const message = error.message.toLowerCase();
|
|
790
|
+
return name === "aborterror" || message.includes("operation was aborted") || message === "aborted";
|
|
791
|
+
}
|
|
792
|
+
function mapNetworkError(baseUrl, error, targetLabel) {
|
|
793
|
+
const tagged = error;
|
|
794
|
+
const timeoutMs = tagged?.[REQUEST_TIMEOUT_MARKER];
|
|
795
|
+
if (typeof timeoutMs === "number") {
|
|
796
|
+
return {
|
|
797
|
+
message: `Request to ${targetLabel} timed out after ${timeoutMs}ms while waiting for a response.`,
|
|
798
|
+
code: "NETWORK_TIMEOUT",
|
|
799
|
+
details: { timeoutMs, target: targetLabel }
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
if (tagged?.[REQUEST_ABORT_MARKER]) {
|
|
803
|
+
return {
|
|
804
|
+
message: `Request to ${targetLabel} was aborted before it completed.`,
|
|
805
|
+
code: "NETWORK_ABORTED"
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
return {
|
|
809
|
+
message: error?.message ? `Unable to connect to ${baseUrl}. ${error.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`,
|
|
810
|
+
code: "NETWORK_ERROR"
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
function describeRequestTarget(path) {
|
|
814
|
+
const toolExecuteMatch = path.match(
|
|
815
|
+
/^\/api\/v2\/integrations\/([^/?#]+)\/execute(?:[/?#]|$)/
|
|
816
|
+
);
|
|
817
|
+
if (toolExecuteMatch) {
|
|
818
|
+
return providerLabelFromToolId(decodeURIComponent(toolExecuteMatch[1]));
|
|
819
|
+
}
|
|
820
|
+
return "Deepline";
|
|
821
|
+
}
|
|
822
|
+
function providerLabelFromToolId(toolId) {
|
|
823
|
+
const normalized = toolId.trim().toLowerCase();
|
|
824
|
+
const provider = normalized.split(/[_:./-]+/)[0];
|
|
825
|
+
return provider || normalized || "provider";
|
|
826
|
+
}
|
|
775
827
|
var HttpClient = class {
|
|
776
828
|
constructor(config) {
|
|
777
829
|
this.config = config;
|
|
@@ -884,10 +936,12 @@ var HttpClient = class {
|
|
|
884
936
|
}
|
|
885
937
|
for (const candidateUrl of candidateUrls) {
|
|
886
938
|
const controller = new AbortController();
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
939
|
+
const timeoutMs = options?.timeout ?? this.config.timeout;
|
|
940
|
+
let requestTimedOut = false;
|
|
941
|
+
const timeoutId = setTimeout(() => {
|
|
942
|
+
requestTimedOut = true;
|
|
943
|
+
controller.abort();
|
|
944
|
+
}, timeoutMs);
|
|
891
945
|
try {
|
|
892
946
|
const response = await fetch(candidateUrl, {
|
|
893
947
|
method,
|
|
@@ -960,7 +1014,10 @@ var HttpClient = class {
|
|
|
960
1014
|
lastError = error;
|
|
961
1015
|
break;
|
|
962
1016
|
}
|
|
963
|
-
lastError = error
|
|
1017
|
+
lastError = normalizeRequestAbortError(error, {
|
|
1018
|
+
timeoutMs,
|
|
1019
|
+
timedOut: requestTimedOut
|
|
1020
|
+
});
|
|
964
1021
|
}
|
|
965
1022
|
}
|
|
966
1023
|
if (attempt < maxRetries) continue;
|
|
@@ -968,8 +1025,17 @@ var HttpClient = class {
|
|
|
968
1025
|
if (lastError instanceof DeeplineError) {
|
|
969
1026
|
throw lastError;
|
|
970
1027
|
}
|
|
971
|
-
const
|
|
972
|
-
|
|
1028
|
+
const mappedNetworkError = mapNetworkError(
|
|
1029
|
+
baseUrl,
|
|
1030
|
+
lastError,
|
|
1031
|
+
describeRequestTarget(path)
|
|
1032
|
+
);
|
|
1033
|
+
throw new DeeplineError(
|
|
1034
|
+
withCoworkNetworkHint(mappedNetworkError.message),
|
|
1035
|
+
void 0,
|
|
1036
|
+
mappedNetworkError.code,
|
|
1037
|
+
mappedNetworkError.details
|
|
1038
|
+
);
|
|
973
1039
|
}
|
|
974
1040
|
/**
|
|
975
1041
|
* Send a GET request.
|
|
@@ -2240,6 +2306,57 @@ function decodeBase64Bytes(value) {
|
|
|
2240
2306
|
}
|
|
2241
2307
|
return bytes;
|
|
2242
2308
|
}
|
|
2309
|
+
var STAGE_LEGACY_MULTIPART_MAX_BYTES = 4e6;
|
|
2310
|
+
var STAGE_DIRECT_UPLOAD_MAX_ATTEMPTS = 3;
|
|
2311
|
+
function stagedUploadIdentity(logicalPath, contentHash) {
|
|
2312
|
+
return `${contentHash}:${logicalPath}`;
|
|
2313
|
+
}
|
|
2314
|
+
function isStagedUploadMintUnsupported(error) {
|
|
2315
|
+
return error instanceof DeeplineError && error.statusCode === 404;
|
|
2316
|
+
}
|
|
2317
|
+
function formatMegabytes(bytes) {
|
|
2318
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
2319
|
+
}
|
|
2320
|
+
async function uploadStagedFileToPresignedUrl(input2) {
|
|
2321
|
+
const arrayBuffer = input2.body.buffer.slice(
|
|
2322
|
+
input2.body.byteOffset,
|
|
2323
|
+
input2.body.byteOffset + input2.body.byteLength
|
|
2324
|
+
);
|
|
2325
|
+
let lastError;
|
|
2326
|
+
for (let attempt = 1; attempt <= STAGE_DIRECT_UPLOAD_MAX_ATTEMPTS; attempt += 1) {
|
|
2327
|
+
try {
|
|
2328
|
+
const response = await fetch(input2.url, {
|
|
2329
|
+
method: "PUT",
|
|
2330
|
+
headers: input2.headers,
|
|
2331
|
+
body: new Blob([arrayBuffer])
|
|
2332
|
+
});
|
|
2333
|
+
if (response.ok) {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
const text = await response.text().catch(() => "");
|
|
2337
|
+
lastError = new DeeplineError(
|
|
2338
|
+
`Direct storage upload of ${input2.logicalPath} failed: ${response.status} ${text.slice(0, 200)}`,
|
|
2339
|
+
response.status,
|
|
2340
|
+
"STAGED_FILE_UPLOAD_FAILED",
|
|
2341
|
+
{ logicalPath: input2.logicalPath }
|
|
2342
|
+
);
|
|
2343
|
+
if (response.status < 500 && response.status !== 429) {
|
|
2344
|
+
break;
|
|
2345
|
+
}
|
|
2346
|
+
} catch (error) {
|
|
2347
|
+
lastError = error;
|
|
2348
|
+
}
|
|
2349
|
+
if (attempt < STAGE_DIRECT_UPLOAD_MAX_ATTEMPTS) {
|
|
2350
|
+
await sleep2(250 * attempt);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
throw lastError instanceof Error ? lastError : new DeeplineError(
|
|
2354
|
+
`Direct storage upload of ${input2.logicalPath} failed.`,
|
|
2355
|
+
void 0,
|
|
2356
|
+
"STAGED_FILE_UPLOAD_FAILED",
|
|
2357
|
+
{ logicalPath: input2.logicalPath }
|
|
2358
|
+
);
|
|
2359
|
+
}
|
|
2243
2360
|
function readStringArray(value) {
|
|
2244
2361
|
return Array.isArray(value) ? value.filter((line) => typeof line === "string") : [];
|
|
2245
2362
|
}
|
|
@@ -2645,6 +2762,21 @@ var DeeplineClient = class {
|
|
|
2645
2762
|
...input2.maxRows ? { max_rows: input2.maxRows } : {}
|
|
2646
2763
|
});
|
|
2647
2764
|
}
|
|
2765
|
+
/**
|
|
2766
|
+
* Re-establish this workspace's tenant storage contract: role/DB connect
|
|
2767
|
+
* grants plus materialized table grants. Org-admin only. Use when a run fails
|
|
2768
|
+
* with WORKSPACE_STORAGE_NOT_READY.
|
|
2769
|
+
*/
|
|
2770
|
+
async repairIngestionStorage(input2) {
|
|
2771
|
+
return this.http.post(
|
|
2772
|
+
"/api/v2/ingestion/repair",
|
|
2773
|
+
{
|
|
2774
|
+
...input2?.provider ? { provider: input2.provider } : {}
|
|
2775
|
+
},
|
|
2776
|
+
void 0,
|
|
2777
|
+
{ forbiddenAsApiError: true }
|
|
2778
|
+
);
|
|
2779
|
+
}
|
|
2648
2780
|
// ——————————————————————————————————————————————————————————
|
|
2649
2781
|
// Plays — submission and lifecycle
|
|
2650
2782
|
// ——————————————————————————————————————————————————————————
|
|
@@ -3022,6 +3154,94 @@ var DeeplineClient = class {
|
|
|
3022
3154
|
* ```
|
|
3023
3155
|
*/
|
|
3024
3156
|
async stagePlayFiles(files) {
|
|
3157
|
+
let uploads;
|
|
3158
|
+
try {
|
|
3159
|
+
uploads = await this.mintStagedPlayFileUploads(
|
|
3160
|
+
files.map((file) => ({
|
|
3161
|
+
logicalPath: file.logicalPath,
|
|
3162
|
+
contentHash: file.contentHash,
|
|
3163
|
+
contentType: file.contentType,
|
|
3164
|
+
bytes: file.bytes
|
|
3165
|
+
}))
|
|
3166
|
+
);
|
|
3167
|
+
} catch (error) {
|
|
3168
|
+
if (isStagedUploadMintUnsupported(error)) {
|
|
3169
|
+
return this.stagePlayFilesViaMultipart(files);
|
|
3170
|
+
}
|
|
3171
|
+
throw error;
|
|
3172
|
+
}
|
|
3173
|
+
const uploadByIdentity = /* @__PURE__ */ new Map();
|
|
3174
|
+
for (const upload of uploads) {
|
|
3175
|
+
uploadByIdentity.set(
|
|
3176
|
+
stagedUploadIdentity(upload.logicalPath, upload.contentHash),
|
|
3177
|
+
upload
|
|
3178
|
+
);
|
|
3179
|
+
}
|
|
3180
|
+
await Promise.all(
|
|
3181
|
+
files.map(async (file) => {
|
|
3182
|
+
const upload = uploadByIdentity.get(
|
|
3183
|
+
stagedUploadIdentity(file.logicalPath, file.contentHash)
|
|
3184
|
+
);
|
|
3185
|
+
if (!upload) {
|
|
3186
|
+
throw new DeeplineError(
|
|
3187
|
+
`The staging server did not return an upload target for ${file.logicalPath}.`,
|
|
3188
|
+
void 0,
|
|
3189
|
+
"STAGED_FILE_MINT_INCOMPLETE"
|
|
3190
|
+
);
|
|
3191
|
+
}
|
|
3192
|
+
if (upload.alreadyStaged || !upload.uploadUrl) {
|
|
3193
|
+
return;
|
|
3194
|
+
}
|
|
3195
|
+
await uploadStagedFileToPresignedUrl({
|
|
3196
|
+
url: upload.uploadUrl,
|
|
3197
|
+
headers: upload.uploadHeaders ?? {
|
|
3198
|
+
"content-type": file.contentType
|
|
3199
|
+
},
|
|
3200
|
+
body: decodeBase64Bytes(file.contentBase64),
|
|
3201
|
+
logicalPath: file.logicalPath
|
|
3202
|
+
});
|
|
3203
|
+
})
|
|
3204
|
+
);
|
|
3205
|
+
return files.map((file) => {
|
|
3206
|
+
const upload = uploadByIdentity.get(
|
|
3207
|
+
stagedUploadIdentity(file.logicalPath, file.contentHash)
|
|
3208
|
+
);
|
|
3209
|
+
if (!upload) {
|
|
3210
|
+
throw new DeeplineError(
|
|
3211
|
+
`The staging server did not return an upload target for ${file.logicalPath}.`,
|
|
3212
|
+
void 0,
|
|
3213
|
+
"STAGED_FILE_MINT_INCOMPLETE"
|
|
3214
|
+
);
|
|
3215
|
+
}
|
|
3216
|
+
return upload.ref;
|
|
3217
|
+
});
|
|
3218
|
+
}
|
|
3219
|
+
/**
|
|
3220
|
+
* Mint short-lived presigned upload targets for staged play files.
|
|
3221
|
+
*
|
|
3222
|
+
* Internal primitive used by {@link stagePlayFiles}. The server returns an
|
|
3223
|
+
* already-staged ref (no upload needed) for content-addressed files it
|
|
3224
|
+
* already holds, or a presigned PUT URL the caller uploads the body to.
|
|
3225
|
+
*/
|
|
3226
|
+
async mintStagedPlayFileUploads(files) {
|
|
3227
|
+
const response = await this.http.post("/api/v2/plays/files/stage/mint", { files });
|
|
3228
|
+
return response.uploads ?? [];
|
|
3229
|
+
}
|
|
3230
|
+
async stagePlayFilesViaMultipart(files) {
|
|
3231
|
+
for (const file of files) {
|
|
3232
|
+
if (file.bytes > STAGE_LEGACY_MULTIPART_MAX_BYTES) {
|
|
3233
|
+
throw new DeeplineError(
|
|
3234
|
+
`Cannot stage ${file.logicalPath} (${formatMegabytes(file.bytes)}): the connected Deepline server does not support direct-to-storage uploads, and this file exceeds the ~4.5MB request-body limit the legacy upload path is subject to. Update the Deepline server (or target code.deepline.com) to stage files this large.`,
|
|
3235
|
+
413,
|
|
3236
|
+
"STAGED_FILE_TOO_LARGE_FOR_LEGACY_UPLOAD",
|
|
3237
|
+
{
|
|
3238
|
+
logicalPath: file.logicalPath,
|
|
3239
|
+
bytes: file.bytes,
|
|
3240
|
+
maxBytes: STAGE_LEGACY_MULTIPART_MAX_BYTES
|
|
3241
|
+
}
|
|
3242
|
+
);
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3025
3245
|
const buildFormData = () => {
|
|
3026
3246
|
const formData = new FormData();
|
|
3027
3247
|
formData.set(
|
|
@@ -7673,6 +7893,53 @@ async function handleDbQuery(args) {
|
|
|
7673
7893
|
);
|
|
7674
7894
|
return 0;
|
|
7675
7895
|
}
|
|
7896
|
+
async function handleDbRepair(args) {
|
|
7897
|
+
const providerIndex = args.indexOf("--provider");
|
|
7898
|
+
const provider = providerIndex >= 0 ? args[providerIndex + 1]?.trim() : void 0;
|
|
7899
|
+
const jsonOutput = argsWantJson(args);
|
|
7900
|
+
const client2 = new DeeplineClient();
|
|
7901
|
+
let result;
|
|
7902
|
+
try {
|
|
7903
|
+
result = await client2.repairIngestionStorage(
|
|
7904
|
+
provider ? { provider } : void 0
|
|
7905
|
+
);
|
|
7906
|
+
} catch (error) {
|
|
7907
|
+
if (error instanceof DeeplineError && error.statusCode === 403) {
|
|
7908
|
+
console.error(
|
|
7909
|
+
"deepline db repair requires org admin. Ask an organization admin to run it."
|
|
7910
|
+
);
|
|
7911
|
+
return 1;
|
|
7912
|
+
}
|
|
7913
|
+
console.error(errorMessage(error));
|
|
7914
|
+
return 1;
|
|
7915
|
+
}
|
|
7916
|
+
printCommandEnvelope(
|
|
7917
|
+
{
|
|
7918
|
+
command: "db repair",
|
|
7919
|
+
repaired: result.repaired,
|
|
7920
|
+
count: result.count,
|
|
7921
|
+
connection_grants: result.connection_grants,
|
|
7922
|
+
render: {
|
|
7923
|
+
sections: [
|
|
7924
|
+
{
|
|
7925
|
+
title: "storage contract repair",
|
|
7926
|
+
lines: [
|
|
7927
|
+
`Repaired ${result.count} table(s).`,
|
|
7928
|
+
`Runtime role: ${result.connection_grants.runtime_role}`,
|
|
7929
|
+
`Customer DB role: ${result.connection_grants.customer_db_role}`
|
|
7930
|
+
]
|
|
7931
|
+
}
|
|
7932
|
+
]
|
|
7933
|
+
}
|
|
7934
|
+
},
|
|
7935
|
+
{
|
|
7936
|
+
json: jsonOutput,
|
|
7937
|
+
text: `Repaired ${result.count} table(s). Storage grants re-established.
|
|
7938
|
+
`
|
|
7939
|
+
}
|
|
7940
|
+
);
|
|
7941
|
+
return 0;
|
|
7942
|
+
}
|
|
7676
7943
|
function registerDbCommands(program) {
|
|
7677
7944
|
const db = program.command("db").description("Query the tenant customer database.").addHelpText(
|
|
7678
7945
|
"after",
|
|
@@ -7728,6 +7995,26 @@ Examples:
|
|
|
7728
7995
|
...options.json ? ["--json"] : []
|
|
7729
7996
|
]);
|
|
7730
7997
|
});
|
|
7998
|
+
db.command("repair").description(
|
|
7999
|
+
"Repair this workspace storage contract (role/DB grants). Org admin only."
|
|
8000
|
+
).addHelpText(
|
|
8001
|
+
"after",
|
|
8002
|
+
`
|
|
8003
|
+
Notes:
|
|
8004
|
+
Re-establishes tenant runtime and customer-db role grants plus materialized
|
|
8005
|
+
table grants for the active workspace. Run this after a play run fails with
|
|
8006
|
+
WORKSPACE_STORAGE_NOT_READY, then re-run the play. Requires org admin.
|
|
8007
|
+
|
|
8008
|
+
Examples:
|
|
8009
|
+
deepline db repair
|
|
8010
|
+
deepline db repair --json
|
|
8011
|
+
`
|
|
8012
|
+
).option("--provider <provider>", "Limit materialized-table repair to one provider").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
|
|
8013
|
+
process.exitCode = await handleDbRepair([
|
|
8014
|
+
...options.provider ? ["--provider", options.provider] : [],
|
|
8015
|
+
...options.json ? ["--json"] : []
|
|
8016
|
+
]);
|
|
8017
|
+
});
|
|
7731
8018
|
}
|
|
7732
8019
|
|
|
7733
8020
|
// src/cli/commands/enrich.ts
|
|
@@ -12558,6 +12845,26 @@ function resolveDatasetByName(available, datasetPath) {
|
|
|
12558
12845
|
}
|
|
12559
12846
|
return null;
|
|
12560
12847
|
}
|
|
12848
|
+
function assertDatasetHasExportableRows(input2) {
|
|
12849
|
+
if (input2.rowsInfo.rows.length > 0) {
|
|
12850
|
+
return input2.rowsInfo;
|
|
12851
|
+
}
|
|
12852
|
+
const datasetLabel = input2.datasetPath ?? input2.rowsInfo.tableNamespace ?? input2.rowsInfo.source ?? "result.rows";
|
|
12853
|
+
const available = input2.availableRows.map((info) => info.tableNamespace ?? info.source).filter((name) => typeof name === "string");
|
|
12854
|
+
const runStatus = String(input2.status.status ?? "").toLowerCase();
|
|
12855
|
+
const failedBeforePersisting = runStatus !== "completed";
|
|
12856
|
+
throw new DeeplineError(
|
|
12857
|
+
`Run ${input2.status.runId} has zero rows to export from dataset '${datasetLabel}'.` + (failedBeforePersisting ? ` The run status is '${runStatus || "unknown"}', so it likely failed before persisting rows to this dataset \u2014 provider calls may have been billed without a durable row. Fix the run's failure cause and re-run to resume.` : " The run completed but this dataset materialized no rows.") + (available.length > 0 ? ` Available datasets: ${available.join(", ")}.` : " No datasets were materialized for this run."),
|
|
12858
|
+
void 0,
|
|
12859
|
+
"RUN_EXPORT_EMPTY",
|
|
12860
|
+
{
|
|
12861
|
+
runId: input2.status.runId,
|
|
12862
|
+
dataset: datasetLabel,
|
|
12863
|
+
available,
|
|
12864
|
+
runStatus: runStatus || null
|
|
12865
|
+
}
|
|
12866
|
+
);
|
|
12867
|
+
}
|
|
12561
12868
|
async function exportPlayStatusRows(client2, status, outPath, options = {}) {
|
|
12562
12869
|
if (!outPath) {
|
|
12563
12870
|
return null;
|
|
@@ -12603,13 +12910,25 @@ async function exportPlayStatusRows(client2, status, outPath, options = {}) {
|
|
|
12603
12910
|
}
|
|
12604
12911
|
}
|
|
12605
12912
|
if (fetchedRowsInfo?.complete) {
|
|
12913
|
+
const guarded2 = assertDatasetHasExportableRows({
|
|
12914
|
+
rowsInfo: fetchedRowsInfo,
|
|
12915
|
+
status,
|
|
12916
|
+
availableRows,
|
|
12917
|
+
datasetPath: options.datasetPath
|
|
12918
|
+
});
|
|
12606
12919
|
return {
|
|
12607
|
-
path: writeCanonicalRowsCsv(
|
|
12608
|
-
rowsInfo:
|
|
12920
|
+
path: writeCanonicalRowsCsv(guarded2, outPath),
|
|
12921
|
+
rowsInfo: guarded2
|
|
12609
12922
|
};
|
|
12610
12923
|
}
|
|
12611
12924
|
if (rowsInfo.complete) {
|
|
12612
|
-
|
|
12925
|
+
const guarded2 = assertDatasetHasExportableRows({
|
|
12926
|
+
rowsInfo,
|
|
12927
|
+
status,
|
|
12928
|
+
availableRows,
|
|
12929
|
+
datasetPath: options.datasetPath
|
|
12930
|
+
});
|
|
12931
|
+
return { path: writeCanonicalRowsCsv(guarded2, outPath), rowsInfo: guarded2 };
|
|
12613
12932
|
}
|
|
12614
12933
|
if (attempt < attempts && retryDelayMs > 0) {
|
|
12615
12934
|
await sleep5(retryDelayMs);
|
|
@@ -12635,7 +12954,13 @@ async function exportPlayStatusRows(client2, status, outPath, options = {}) {
|
|
|
12635
12954
|
}
|
|
12636
12955
|
);
|
|
12637
12956
|
}
|
|
12638
|
-
|
|
12957
|
+
const guarded = assertDatasetHasExportableRows({
|
|
12958
|
+
rowsInfo,
|
|
12959
|
+
status,
|
|
12960
|
+
availableRows,
|
|
12961
|
+
datasetPath: options.datasetPath
|
|
12962
|
+
});
|
|
12963
|
+
return { path: writeCanonicalRowsCsv(guarded, outPath), rowsInfo: guarded };
|
|
12639
12964
|
}
|
|
12640
12965
|
function extractActiveRunsFromError(error) {
|
|
12641
12966
|
if (!(error instanceof DeeplineError)) {
|
package/dist/index.d.mts
CHANGED
|
@@ -1381,6 +1381,21 @@ type BillingNamespace = {
|
|
|
1381
1381
|
}) => Promise<BillingInvoicesResult>;
|
|
1382
1382
|
};
|
|
1383
1383
|
};
|
|
1384
|
+
/**
|
|
1385
|
+
* A staged-file upload target minted by POST /api/v2/plays/files/stage/mint.
|
|
1386
|
+
* When `alreadyStaged` is true the server already holds the content-addressed
|
|
1387
|
+
* object and `uploadUrl` is null; otherwise the client PUTs the body to
|
|
1388
|
+
* `uploadUrl` with `uploadHeaders`.
|
|
1389
|
+
*/
|
|
1390
|
+
type MintStagedFileUpload = {
|
|
1391
|
+
logicalPath: string;
|
|
1392
|
+
contentHash: string;
|
|
1393
|
+
ref: PlayStagedFileRef;
|
|
1394
|
+
alreadyStaged: boolean;
|
|
1395
|
+
uploadUrl: string | null;
|
|
1396
|
+
uploadHeaders: Record<string, string> | null;
|
|
1397
|
+
uploadExpiresAt: string | null;
|
|
1398
|
+
};
|
|
1384
1399
|
/**
|
|
1385
1400
|
* Low-level client for the Deepline REST API.
|
|
1386
1401
|
*
|
|
@@ -1524,6 +1539,21 @@ declare class DeeplineClient {
|
|
|
1524
1539
|
sql: string;
|
|
1525
1540
|
maxRows?: number;
|
|
1526
1541
|
}): Promise<CustomerDbQueryResult>;
|
|
1542
|
+
/**
|
|
1543
|
+
* Re-establish this workspace's tenant storage contract: role/DB connect
|
|
1544
|
+
* grants plus materialized table grants. Org-admin only. Use when a run fails
|
|
1545
|
+
* with WORKSPACE_STORAGE_NOT_READY.
|
|
1546
|
+
*/
|
|
1547
|
+
repairIngestionStorage(input?: {
|
|
1548
|
+
provider?: string;
|
|
1549
|
+
}): Promise<{
|
|
1550
|
+
connection_grants: {
|
|
1551
|
+
runtime_role: string;
|
|
1552
|
+
customer_db_role: string;
|
|
1553
|
+
};
|
|
1554
|
+
repaired: unknown[];
|
|
1555
|
+
count: number;
|
|
1556
|
+
}>;
|
|
1527
1557
|
/**
|
|
1528
1558
|
* Start a play run.
|
|
1529
1559
|
*
|
|
@@ -1763,6 +1793,20 @@ declare class DeeplineClient {
|
|
|
1763
1793
|
contentType: string;
|
|
1764
1794
|
bytes: number;
|
|
1765
1795
|
}>): Promise<PlayStagedFileRef[]>;
|
|
1796
|
+
/**
|
|
1797
|
+
* Mint short-lived presigned upload targets for staged play files.
|
|
1798
|
+
*
|
|
1799
|
+
* Internal primitive used by {@link stagePlayFiles}. The server returns an
|
|
1800
|
+
* already-staged ref (no upload needed) for content-addressed files it
|
|
1801
|
+
* already holds, or a presigned PUT URL the caller uploads the body to.
|
|
1802
|
+
*/
|
|
1803
|
+
mintStagedPlayFileUploads(files: Array<{
|
|
1804
|
+
logicalPath: string;
|
|
1805
|
+
contentHash: string;
|
|
1806
|
+
contentType: string;
|
|
1807
|
+
bytes: number;
|
|
1808
|
+
}>): Promise<MintStagedFileUpload[]>;
|
|
1809
|
+
private stagePlayFilesViaMultipart;
|
|
1766
1810
|
/**
|
|
1767
1811
|
* Resolve staged play files by content hash without uploading bytes.
|
|
1768
1812
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1381,6 +1381,21 @@ type BillingNamespace = {
|
|
|
1381
1381
|
}) => Promise<BillingInvoicesResult>;
|
|
1382
1382
|
};
|
|
1383
1383
|
};
|
|
1384
|
+
/**
|
|
1385
|
+
* A staged-file upload target minted by POST /api/v2/plays/files/stage/mint.
|
|
1386
|
+
* When `alreadyStaged` is true the server already holds the content-addressed
|
|
1387
|
+
* object and `uploadUrl` is null; otherwise the client PUTs the body to
|
|
1388
|
+
* `uploadUrl` with `uploadHeaders`.
|
|
1389
|
+
*/
|
|
1390
|
+
type MintStagedFileUpload = {
|
|
1391
|
+
logicalPath: string;
|
|
1392
|
+
contentHash: string;
|
|
1393
|
+
ref: PlayStagedFileRef;
|
|
1394
|
+
alreadyStaged: boolean;
|
|
1395
|
+
uploadUrl: string | null;
|
|
1396
|
+
uploadHeaders: Record<string, string> | null;
|
|
1397
|
+
uploadExpiresAt: string | null;
|
|
1398
|
+
};
|
|
1384
1399
|
/**
|
|
1385
1400
|
* Low-level client for the Deepline REST API.
|
|
1386
1401
|
*
|
|
@@ -1524,6 +1539,21 @@ declare class DeeplineClient {
|
|
|
1524
1539
|
sql: string;
|
|
1525
1540
|
maxRows?: number;
|
|
1526
1541
|
}): Promise<CustomerDbQueryResult>;
|
|
1542
|
+
/**
|
|
1543
|
+
* Re-establish this workspace's tenant storage contract: role/DB connect
|
|
1544
|
+
* grants plus materialized table grants. Org-admin only. Use when a run fails
|
|
1545
|
+
* with WORKSPACE_STORAGE_NOT_READY.
|
|
1546
|
+
*/
|
|
1547
|
+
repairIngestionStorage(input?: {
|
|
1548
|
+
provider?: string;
|
|
1549
|
+
}): Promise<{
|
|
1550
|
+
connection_grants: {
|
|
1551
|
+
runtime_role: string;
|
|
1552
|
+
customer_db_role: string;
|
|
1553
|
+
};
|
|
1554
|
+
repaired: unknown[];
|
|
1555
|
+
count: number;
|
|
1556
|
+
}>;
|
|
1527
1557
|
/**
|
|
1528
1558
|
* Start a play run.
|
|
1529
1559
|
*
|
|
@@ -1763,6 +1793,20 @@ declare class DeeplineClient {
|
|
|
1763
1793
|
contentType: string;
|
|
1764
1794
|
bytes: number;
|
|
1765
1795
|
}>): Promise<PlayStagedFileRef[]>;
|
|
1796
|
+
/**
|
|
1797
|
+
* Mint short-lived presigned upload targets for staged play files.
|
|
1798
|
+
*
|
|
1799
|
+
* Internal primitive used by {@link stagePlayFiles}. The server returns an
|
|
1800
|
+
* already-staged ref (no upload needed) for content-addressed files it
|
|
1801
|
+
* already holds, or a presigned PUT URL the caller uploads the body to.
|
|
1802
|
+
*/
|
|
1803
|
+
mintStagedPlayFileUploads(files: Array<{
|
|
1804
|
+
logicalPath: string;
|
|
1805
|
+
contentHash: string;
|
|
1806
|
+
contentType: string;
|
|
1807
|
+
bytes: number;
|
|
1808
|
+
}>): Promise<MintStagedFileUpload[]>;
|
|
1809
|
+
private stagePlayFilesViaMultipart;
|
|
1766
1810
|
/**
|
|
1767
1811
|
* Resolve staged play files by content hash without uploading bytes.
|
|
1768
1812
|
*
|