@sprigr/apps-app-sdk 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -0
- package/dist/index.js +33 -8
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1278,6 +1278,13 @@ declare function putAppFile(env: AppFilesEnv, args: PutAppFileArgs): Promise<Put
|
|
|
1278
1278
|
* and (with a `ReadableStream` body) never buffers them whole in the
|
|
1279
1279
|
* isolate — pipe a source `Response.body` directly through for multi-MB
|
|
1280
1280
|
* blobs. Metadata travels in headers; the body is opaque bytes.
|
|
1281
|
+
*
|
|
1282
|
+
* The platform's put-stream route cannot retry a transient R2 fault itself
|
|
1283
|
+
* (its body is spent once read), so a resendable body — `ArrayBuffer` /
|
|
1284
|
+
* `Uint8Array` already in hand, not a `ReadableStream` — gets a bounded
|
|
1285
|
+
* retry here instead. The key is deterministic, so a retry is a full
|
|
1286
|
+
* overwrite, exactly the argument the platform's buffered `put` route makes
|
|
1287
|
+
* for its own retry (wfp-files.ts, sprigr-team).
|
|
1281
1288
|
*/
|
|
1282
1289
|
declare function putAppFileStream(env: AppFilesEnv, args: PutAppFileStreamArgs): Promise<PutAppFileResult>;
|
|
1283
1290
|
/** Mint a signed, time-limited download URL for an app file. */
|
package/dist/index.js
CHANGED
|
@@ -893,6 +893,17 @@ function putAppFile(env, args) {
|
|
|
893
893
|
filename: args.filename
|
|
894
894
|
});
|
|
895
895
|
}
|
|
896
|
+
var STREAM_PUT_MAX_ATTEMPTS = 3;
|
|
897
|
+
var STREAM_PUT_BASE_DELAY_MS = 500;
|
|
898
|
+
function isTransientPutStreamFailure(status, message) {
|
|
899
|
+
if (status === 503) return true;
|
|
900
|
+
if (status !== 502) return false;
|
|
901
|
+
const msg = message.toLowerCase();
|
|
902
|
+
return msg.includes("(10001)") || msg.includes("(10043)");
|
|
903
|
+
}
|
|
904
|
+
function sleep2(ms) {
|
|
905
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
906
|
+
}
|
|
896
907
|
async function putAppFileStream(env, args) {
|
|
897
908
|
const token = requireToken(env);
|
|
898
909
|
const headers = {
|
|
@@ -905,14 +916,28 @@ async function putAppFileStream(env, args) {
|
|
|
905
916
|
if (typeof args.contentLength === "number" && Number.isFinite(args.contentLength)) {
|
|
906
917
|
headers["x-app-file-length"] = String(args.contentLength);
|
|
907
918
|
}
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
919
|
+
const resendable = !(args.body instanceof ReadableStream);
|
|
920
|
+
const attempts = resendable ? STREAM_PUT_MAX_ATTEMPTS : 1;
|
|
921
|
+
let lastErr;
|
|
922
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
923
|
+
const res = await fetch(`${platformBase(env)}/internal/wfp/file/put-stream`, {
|
|
924
|
+
method: "POST",
|
|
925
|
+
headers,
|
|
926
|
+
body: args.body,
|
|
927
|
+
// Required by the Workers runtime when sending a streaming request body.
|
|
928
|
+
...args.body instanceof ReadableStream ? { duplex: "half" } : {}
|
|
929
|
+
});
|
|
930
|
+
try {
|
|
931
|
+
return await parseResult(res, "put-stream");
|
|
932
|
+
} catch (err) {
|
|
933
|
+
lastErr = err;
|
|
934
|
+
if (!resendable || attempt === attempts || !(err instanceof AppFilesError) || !isTransientPutStreamFailure(err.status, err.message)) {
|
|
935
|
+
throw err;
|
|
936
|
+
}
|
|
937
|
+
await sleep2(STREAM_PUT_BASE_DELAY_MS * 2 ** (attempt - 1));
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
throw lastErr;
|
|
916
941
|
}
|
|
917
942
|
function appFileUrl(env, args) {
|
|
918
943
|
return call(env, "url", { key: args.key, expiresIn: args.expiresIn });
|