@opencoredev/social-sdk 0.1.2 → 0.2.0
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/README.md +6 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +235 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud/common.d.ts +26 -0
- package/dist/cloud/common.d.ts.map +1 -0
- package/dist/cloud/common.js +335 -0
- package/dist/cloud/common.js.map +1 -0
- package/dist/cloud/lifecycle.d.ts +11 -0
- package/dist/cloud/lifecycle.d.ts.map +1 -0
- package/dist/cloud/lifecycle.js +113 -0
- package/dist/cloud/lifecycle.js.map +1 -0
- package/dist/cloud/media.d.ts +24 -0
- package/dist/cloud/media.d.ts.map +1 -0
- package/dist/cloud/media.js +101 -0
- package/dist/cloud/media.js.map +1 -0
- package/dist/cloud/outcomes.d.ts +10 -0
- package/dist/cloud/outcomes.d.ts.map +1 -0
- package/dist/cloud/outcomes.js +196 -0
- package/dist/cloud/outcomes.js.map +1 -0
- package/dist/cloud/post-for-me.d.ts +70 -0
- package/dist/cloud/post-for-me.d.ts.map +1 -0
- package/dist/cloud/post-for-me.js +397 -0
- package/dist/cloud/post-for-me.js.map +1 -0
- package/dist/cloud/zernio.d.ts +112 -0
- package/dist/cloud/zernio.d.ts.map +1 -0
- package/dist/cloud/zernio.js +633 -0
- package/dist/cloud/zernio.js.map +1 -0
- package/dist/core/adapter.d.ts +159 -0
- package/dist/core/adapter.d.ts.map +1 -0
- package/dist/core/adapter.js +4 -0
- package/dist/core/adapter.js.map +1 -0
- package/dist/core/client.d.ts +142 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +1286 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/concurrency.d.ts +10 -0
- package/dist/core/concurrency.d.ts.map +1 -0
- package/dist/core/concurrency.js +80 -0
- package/dist/core/concurrency.js.map +1 -0
- package/dist/core/errors.d.ts +45 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +51 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/idempotency.d.ts +34 -0
- package/dist/core/idempotency.d.ts.map +1 -0
- package/dist/core/idempotency.js +59 -0
- package/dist/core/idempotency.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/pagination.d.ts +12 -0
- package/dist/core/pagination.d.ts.map +1 -0
- package/dist/core/pagination.js +82 -0
- package/dist/core/pagination.js.map +1 -0
- package/dist/core/types.d.ts +397 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +17 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/platforms/bluesky.d.ts +262 -0
- package/dist/platforms/bluesky.d.ts.map +1 -0
- package/dist/platforms/bluesky.js +1777 -0
- package/dist/platforms/bluesky.js.map +1 -0
- package/dist/platforms/instagram.d.ts +130 -0
- package/dist/platforms/instagram.d.ts.map +1 -0
- package/dist/platforms/instagram.js +1032 -0
- package/dist/platforms/instagram.js.map +1 -0
- package/dist/platforms/linkedin.d.ts +109 -0
- package/dist/platforms/linkedin.d.ts.map +1 -0
- package/dist/platforms/linkedin.js +891 -0
- package/dist/platforms/linkedin.js.map +1 -0
- package/dist/platforms/threads.d.ts +135 -0
- package/dist/platforms/threads.d.ts.map +1 -0
- package/dist/platforms/threads.js +946 -0
- package/dist/platforms/threads.js.map +1 -0
- package/dist/platforms/tiktok.d.ts +32 -0
- package/dist/platforms/tiktok.d.ts.map +1 -0
- package/dist/platforms/tiktok.js +594 -0
- package/dist/platforms/tiktok.js.map +1 -0
- package/dist/platforms/x-engagement.d.ts +17 -0
- package/dist/platforms/x-engagement.d.ts.map +1 -0
- package/dist/platforms/x-engagement.js +51 -0
- package/dist/platforms/x-engagement.js.map +1 -0
- package/dist/platforms/x.d.ts +300 -0
- package/dist/platforms/x.d.ts.map +1 -0
- package/dist/platforms/x.js +1288 -0
- package/dist/platforms/x.js.map +1 -0
- package/dist/platforms/youtube-upload.d.ts +33 -0
- package/dist/platforms/youtube-upload.d.ts.map +1 -0
- package/dist/platforms/youtube-upload.js +297 -0
- package/dist/platforms/youtube-upload.js.map +1 -0
- package/dist/platforms/youtube.d.ts +109 -0
- package/dist/platforms/youtube.d.ts.map +1 -0
- package/dist/platforms/youtube.js +1101 -0
- package/dist/platforms/youtube.js.map +1 -0
- package/dist/server/connections.d.ts +124 -0
- package/dist/server/connections.d.ts.map +1 -0
- package/dist/server/connections.js +336 -0
- package/dist/server/connections.js.map +1 -0
- package/dist/server/credentials.d.ts +52 -0
- package/dist/server/credentials.d.ts.map +1 -0
- package/dist/server/credentials.js +109 -0
- package/dist/server/credentials.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +5 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/oauth.d.ts +53 -0
- package/dist/server/oauth.d.ts.map +1 -0
- package/dist/server/oauth.js +554 -0
- package/dist/server/oauth.js.map +1 -0
- package/dist/server/webhooks.d.ts +58 -0
- package/dist/server/webhooks.d.ts.map +1 -0
- package/dist/server/webhooks.js +205 -0
- package/dist/server/webhooks.js.map +1 -0
- package/dist/testing/index.d.ts +47 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +565 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +2 -0
- package/dist/testing.js.map +1 -0
- package/dist/transport/binary.d.ts +3 -0
- package/dist/transport/binary.d.ts.map +1 -0
- package/dist/transport/binary.js +30 -0
- package/dist/transport/binary.js.map +1 -0
- package/dist/transport/budget.d.ts +4 -0
- package/dist/transport/budget.d.ts.map +1 -0
- package/dist/transport/budget.js +27 -0
- package/dist/transport/budget.js.map +1 -0
- package/dist/transport/http.d.ts +45 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +260 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/transport/json.d.ts +9 -0
- package/dist/transport/json.d.ts.map +1 -0
- package/dist/transport/json.js +17 -0
- package/dist/transport/json.js.map +1 -0
- package/dist/transport/upload.d.ts +26 -0
- package/dist/transport/upload.d.ts.map +1 -0
- package/dist/transport/upload.js +154 -0
- package/dist/transport/upload.js.map +1 -0
- package/dist/transport/validation.d.ts +6 -0
- package/dist/transport/validation.d.ts.map +1 -0
- package/dist/transport/validation.js +25 -0
- package/dist/transport/validation.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AdapterOperationContext } from "../core/types.js";
|
|
2
|
+
/** Sequential requests sharing an operation context consume one elapsed budget. */
|
|
3
|
+
export declare function remainingBudget(context: AdapterOperationContext, now?: number): number;
|
|
4
|
+
//# sourceMappingURL=budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../src/transport/budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAKhE,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,SAAoB,GAAG,MAAM,CA2BjG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SocialError } from "../core/errors.js";
|
|
2
|
+
const deadlines = new WeakMap();
|
|
3
|
+
/** Sequential requests sharing an operation context consume one elapsed budget. */
|
|
4
|
+
export function remainingBudget(context, now = performance.now()) {
|
|
5
|
+
const duration = context.retryBudget.maxElapsedMs;
|
|
6
|
+
if (!Number.isFinite(duration) || duration <= 0)
|
|
7
|
+
throw new SocialError({
|
|
8
|
+
code: "invalid_input",
|
|
9
|
+
operation: "transport",
|
|
10
|
+
message: "Elapsed request budget must be positive and finite.",
|
|
11
|
+
});
|
|
12
|
+
let deadline = deadlines.get(context);
|
|
13
|
+
if (deadline === undefined) {
|
|
14
|
+
deadline = now + duration;
|
|
15
|
+
deadlines.set(context, deadline);
|
|
16
|
+
}
|
|
17
|
+
const remaining = deadline - now;
|
|
18
|
+
if (remaining <= 0)
|
|
19
|
+
throw new SocialError({
|
|
20
|
+
code: "timeout",
|
|
21
|
+
operation: "transport",
|
|
22
|
+
message: "The operation exhausted its elapsed request budget before the next dispatch.",
|
|
23
|
+
retryDisposition: { kind: "never" },
|
|
24
|
+
});
|
|
25
|
+
return remaining;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/transport/budget.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,SAAS,GAAG,IAAI,OAAO,EAAmC,CAAC;AAEjE,mFAAmF;AACnF,MAAM,UAAU,eAAe,CAAC,OAAgC,EAAE,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE;IACvF,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,YAAY,CAAC;IAElD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC;QAC7C,MAAM,IAAI,WAAW,CAAC;YACpB,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,WAAW;YACtB,OAAO,EAAE,qDAAqD;SAC/D,CAAC,CAAC;IACL,IAAI,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAEtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,QAAQ,GAAG,GAAG,GAAG,QAAQ,CAAC;QAC1B,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,GAAG,GAAG,CAAC;IAEjC,IAAI,SAAS,IAAI,CAAC;QAChB,MAAM,IAAI,WAAW,CAAC;YACpB,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,WAAW;YACtB,OAAO,EAAE,8EAA8E;YACvF,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;SACpC,CAAC,CAAC;IAEL,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type JsonValue } from "./json.js";
|
|
2
|
+
/** Portable, bounded HTTP transport. Construction performs no I/O. */
|
|
3
|
+
export interface HttpOptions {
|
|
4
|
+
fetch?: typeof globalThis.fetch;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
maxResponseBytes?: number;
|
|
7
|
+
now?: () => number;
|
|
8
|
+
random?: () => number;
|
|
9
|
+
sleep?: (milliseconds: number, signal: AbortSignal) => Promise<void>;
|
|
10
|
+
onRequest?: (event: RequestEvent) => void | Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export interface RequestEvent {
|
|
13
|
+
method: string;
|
|
14
|
+
status?: number;
|
|
15
|
+
attempt: number;
|
|
16
|
+
elapsedMs: number;
|
|
17
|
+
}
|
|
18
|
+
export interface HttpRequest {
|
|
19
|
+
url: URL;
|
|
20
|
+
method?: "GET" | "HEAD" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
21
|
+
headers?: HeadersInit;
|
|
22
|
+
body?: BodyInit;
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
/** Read retries only. Writes are never replayed by this transport. */
|
|
25
|
+
maxAttempts?: number;
|
|
26
|
+
/** Return only these selected response headers alongside the parsed body. */
|
|
27
|
+
responseHeaders?: readonly string[];
|
|
28
|
+
/** Per-operation elapsed budget, capped by the transport's configured deadline. */
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
}
|
|
31
|
+
export declare class HttpError extends Error {
|
|
32
|
+
readonly kind: "http" | "network" | "timeout" | "cancelled" | "invalid-response" | "invalid-input";
|
|
33
|
+
readonly dispatched: boolean;
|
|
34
|
+
readonly status?: number | undefined;
|
|
35
|
+
readonly retryAfterMs?: number | undefined;
|
|
36
|
+
readonly requestId?: string | undefined;
|
|
37
|
+
readonly name = "HttpError";
|
|
38
|
+
constructor(message: string, kind: "http" | "network" | "timeout" | "cancelled" | "invalid-response" | "invalid-input", dispatched: boolean, status?: number | undefined, retryAfterMs?: number | undefined, requestId?: string | undefined);
|
|
39
|
+
}
|
|
40
|
+
export declare function retryDelay(value: string | null, now: number): number | undefined;
|
|
41
|
+
/** Enforce cancellation even when an injected I/O implementation ignores signals. */
|
|
42
|
+
export declare function abortable<T>(work: Promise<T>, signal: AbortSignal): Promise<T>;
|
|
43
|
+
export declare function readJson(response: Response, limit: number, signal?: AbortSignal): Promise<JsonValue>;
|
|
44
|
+
export declare function createHttp(options?: HttpOptions): (input: HttpRequest) => Promise<unknown>;
|
|
45
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAItD,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC9D,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,SAAU,SAAQ,KAAK;IAIhC,QAAQ,CAAC,IAAI,EACT,MAAM,GACN,SAAS,GACT,SAAS,GACT,WAAW,GACX,kBAAkB,GAClB,eAAe;IACnB,QAAQ,CAAC,UAAU,EAAE,OAAO;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM;IAb7B,SAAkB,IAAI,eAAe;gBAEnC,OAAO,EAAE,MAAM,EACN,IAAI,EACT,MAAM,GACN,SAAS,GACT,SAAS,GACT,WAAW,GACX,kBAAkB,GAClB,eAAe,EACV,UAAU,EAAE,OAAO,EACnB,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,YAAY,CAAC,EAAE,MAAM,YAAA,EACrB,SAAS,CAAC,EAAE,MAAM,YAAA;CAI9B;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQhF;AAqCD,qFAAqF;AACrF,wBAAsB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAkBpF;AAED,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,SAAS,CAAC,CA+DpB;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,WAAgB,IAoBpB,OAAO,WAAW,KAAG,OAAO,CAAC,OAAO,CAAC,CAiMpE"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { parseJson } from "./json.js";
|
|
2
|
+
export class HttpError extends Error {
|
|
3
|
+
kind;
|
|
4
|
+
dispatched;
|
|
5
|
+
status;
|
|
6
|
+
retryAfterMs;
|
|
7
|
+
requestId;
|
|
8
|
+
name = "HttpError";
|
|
9
|
+
constructor(message, kind, dispatched, status, retryAfterMs, requestId) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.kind = kind;
|
|
12
|
+
this.dispatched = dispatched;
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.retryAfterMs = retryAfterMs;
|
|
15
|
+
this.requestId = requestId;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function retryDelay(value, now) {
|
|
19
|
+
if (value === null)
|
|
20
|
+
return undefined;
|
|
21
|
+
const seconds = Number(value);
|
|
22
|
+
if (value.trim() !== "" && Number.isFinite(seconds) && seconds >= 0)
|
|
23
|
+
return seconds * 1000;
|
|
24
|
+
const timestamp = Date.parse(value);
|
|
25
|
+
return Number.isFinite(timestamp) ? Math.max(0, timestamp - now) : undefined;
|
|
26
|
+
}
|
|
27
|
+
function requestId(headers) {
|
|
28
|
+
for (const name of ["x-request-id", "x-fb-trace-id", "x-amzn-requestid", "x-amzn-trace-id"]) {
|
|
29
|
+
const value = headers.get(name);
|
|
30
|
+
if (value)
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
function rateLimitResetDelay(value, now) {
|
|
36
|
+
if (value === null)
|
|
37
|
+
return undefined;
|
|
38
|
+
const seconds = Number(value);
|
|
39
|
+
return Number.isFinite(seconds) && seconds >= 0 ? Math.max(0, seconds * 1000 - now) : undefined;
|
|
40
|
+
}
|
|
41
|
+
function sleep(milliseconds, signal) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
signal.throwIfAborted();
|
|
44
|
+
const abort = () => {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
reject(signal.reason);
|
|
47
|
+
};
|
|
48
|
+
const timer = setTimeout(() => {
|
|
49
|
+
signal.removeEventListener("abort", abort);
|
|
50
|
+
resolve();
|
|
51
|
+
}, milliseconds);
|
|
52
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/** Enforce cancellation even when an injected I/O implementation ignores signals. */
|
|
56
|
+
export async function abortable(work, signal) {
|
|
57
|
+
if (signal.aborted) {
|
|
58
|
+
void work.catch(() => undefined);
|
|
59
|
+
throw signal.reason;
|
|
60
|
+
}
|
|
61
|
+
let abort = () => { };
|
|
62
|
+
const cancelled = new Promise((_resolve, reject) => {
|
|
63
|
+
abort = () => reject(signal.reason);
|
|
64
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
65
|
+
});
|
|
66
|
+
try {
|
|
67
|
+
return await Promise.race([work, cancelled]);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
signal.removeEventListener("abort", abort);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export async function readJson(response, limit, signal) {
|
|
74
|
+
if (response.status === 204 || !response.body)
|
|
75
|
+
return null;
|
|
76
|
+
const length = Number(response.headers.get("content-length"));
|
|
77
|
+
if (Number.isFinite(length) && length > limit) {
|
|
78
|
+
void response.body.cancel().catch(() => undefined);
|
|
79
|
+
throw new HttpError("Upstream response exceeds the configured byte limit.", "invalid-response", true, response.status);
|
|
80
|
+
}
|
|
81
|
+
const reader = response.body.getReader();
|
|
82
|
+
const chunks = [];
|
|
83
|
+
let total = 0;
|
|
84
|
+
try {
|
|
85
|
+
for (;;) {
|
|
86
|
+
const chunk = await (signal ? abortable(reader.read(), signal) : reader.read());
|
|
87
|
+
if (chunk.done)
|
|
88
|
+
break;
|
|
89
|
+
total += chunk.value.byteLength;
|
|
90
|
+
if (total > limit)
|
|
91
|
+
throw new HttpError("Upstream response exceeds the configured byte limit.", "invalid-response", true, response.status);
|
|
92
|
+
chunks.push(chunk.value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
void reader.cancel().catch(() => undefined);
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
reader.releaseLock();
|
|
101
|
+
}
|
|
102
|
+
const bytes = new Uint8Array(total);
|
|
103
|
+
let offset = 0;
|
|
104
|
+
for (const chunk of chunks) {
|
|
105
|
+
bytes.set(chunk, offset);
|
|
106
|
+
offset += chunk.byteLength;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
110
|
+
if (!text.trim())
|
|
111
|
+
return null;
|
|
112
|
+
return parseJson(text);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
throw new HttpError("Upstream returned an invalid JSON response.", "invalid-response", true, response.status);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export function createHttp(options = {}) {
|
|
119
|
+
const timeoutMs = options.timeoutMs ?? 30_000;
|
|
120
|
+
const maxBytes = options.maxResponseBytes ?? 2 * 1024 * 1024;
|
|
121
|
+
if (!Number.isFinite(timeoutMs) ||
|
|
122
|
+
timeoutMs <= 0 ||
|
|
123
|
+
!Number.isSafeInteger(maxBytes) ||
|
|
124
|
+
maxBytes <= 0) {
|
|
125
|
+
throw new HttpError("HTTP timeout and response byte limit must be positive.", "invalid-input", false);
|
|
126
|
+
}
|
|
127
|
+
const now = options.now ?? Date.now;
|
|
128
|
+
const random = options.random ?? Math.random;
|
|
129
|
+
return async function request(input) {
|
|
130
|
+
const deadlineMs = Math.min(timeoutMs, input.timeoutMs ?? timeoutMs);
|
|
131
|
+
if (!Number.isFinite(deadlineMs) || deadlineMs <= 0)
|
|
132
|
+
throw new HttpError("Request elapsed budget must be positive.", "invalid-input", false);
|
|
133
|
+
if (input.url.protocol !== "https:" || input.url.username || input.url.password) {
|
|
134
|
+
throw new HttpError("API URLs must use HTTPS without embedded credentials.", "invalid-input", false);
|
|
135
|
+
}
|
|
136
|
+
const method = input.method ?? "GET";
|
|
137
|
+
const safe = method === "GET" || method === "HEAD";
|
|
138
|
+
const attempts = input.maxAttempts ?? 1;
|
|
139
|
+
if (!Number.isSafeInteger(attempts) ||
|
|
140
|
+
attempts < 1 ||
|
|
141
|
+
attempts > 5 ||
|
|
142
|
+
(!safe && attempts !== 1)) {
|
|
143
|
+
throw new HttpError("Use one attempt for mutations and at most five attempts for reads.", "invalid-input", false);
|
|
144
|
+
}
|
|
145
|
+
if (input.signal?.aborted)
|
|
146
|
+
throw new HttpError("Request cancelled before dispatch.", "cancelled", false);
|
|
147
|
+
const controller = new AbortController();
|
|
148
|
+
const abort = () => controller.abort(input.signal?.reason);
|
|
149
|
+
input.signal?.addEventListener("abort", abort, { once: true });
|
|
150
|
+
const timer = setTimeout(() => controller.abort(new Error("HTTP deadline exceeded")), deadlineMs);
|
|
151
|
+
const started = now();
|
|
152
|
+
let dispatched = false;
|
|
153
|
+
let lastRequestId;
|
|
154
|
+
try {
|
|
155
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
156
|
+
controller.signal.throwIfAborted();
|
|
157
|
+
const attemptStarted = now();
|
|
158
|
+
let status;
|
|
159
|
+
let delay;
|
|
160
|
+
try {
|
|
161
|
+
dispatched = true;
|
|
162
|
+
const requestInit = {
|
|
163
|
+
method,
|
|
164
|
+
signal: controller.signal,
|
|
165
|
+
redirect: "error",
|
|
166
|
+
};
|
|
167
|
+
if (input.headers)
|
|
168
|
+
requestInit.headers = input.headers;
|
|
169
|
+
if (input.body !== undefined)
|
|
170
|
+
requestInit.body = input.body;
|
|
171
|
+
const pendingResponse = (options.fetch ?? globalThis.fetch)(input.url, requestInit);
|
|
172
|
+
void pendingResponse.then((response) => {
|
|
173
|
+
if (controller.signal.aborted)
|
|
174
|
+
void response.body?.cancel().catch(() => undefined);
|
|
175
|
+
}, () => undefined);
|
|
176
|
+
const response = await abortable(pendingResponse, controller.signal);
|
|
177
|
+
status = response.status;
|
|
178
|
+
if (response.ok) {
|
|
179
|
+
const body = method === "HEAD" ? null : await readJson(response, maxBytes, controller.signal);
|
|
180
|
+
if (!input.responseHeaders)
|
|
181
|
+
return body;
|
|
182
|
+
const headers = {};
|
|
183
|
+
for (const name of input.responseHeaders) {
|
|
184
|
+
const value = response.headers.get(name);
|
|
185
|
+
if (value !== null)
|
|
186
|
+
headers[name.toLowerCase()] = value;
|
|
187
|
+
}
|
|
188
|
+
return { body, headers };
|
|
189
|
+
}
|
|
190
|
+
const currentTime = now();
|
|
191
|
+
delay = retryDelay(response.headers.get("retry-after"), currentTime);
|
|
192
|
+
delay ??= rateLimitResetDelay(response.headers.get("x-rate-limit-reset"), currentTime);
|
|
193
|
+
const responseRequestId = requestId(response.headers);
|
|
194
|
+
lastRequestId = responseRequestId ?? lastRequestId;
|
|
195
|
+
void response.body?.cancel().catch(() => undefined);
|
|
196
|
+
// Response bodies and URL query strings may contain credentials or user content.
|
|
197
|
+
throw new HttpError(`Upstream request failed with HTTP ${response.status}.`, "http", true, response.status, delay, responseRequestId);
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
if (controller.signal.aborted)
|
|
201
|
+
throw error;
|
|
202
|
+
const retryable = !(error instanceof HttpError) ||
|
|
203
|
+
(error.kind === "http" &&
|
|
204
|
+
(error.status === 429 || (error.status !== undefined && error.status >= 500)));
|
|
205
|
+
if (!safe || !retryable || attempt >= attempts) {
|
|
206
|
+
if (error instanceof HttpError)
|
|
207
|
+
throw error;
|
|
208
|
+
throw new HttpError(safe
|
|
209
|
+
? "Network request failed."
|
|
210
|
+
: "Network request failed; a dispatched mutation may have been accepted.", "network", true);
|
|
211
|
+
}
|
|
212
|
+
delay ??=
|
|
213
|
+
Math.min(200 * 2 ** (attempt - 1), 5_000) * (0.5 + Math.max(0, Math.min(1, random())));
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
if (options.onRequest) {
|
|
217
|
+
// Diagnostics cannot change a write's outcome or leak a rejected promise.
|
|
218
|
+
try {
|
|
219
|
+
const requestEvent = {
|
|
220
|
+
method,
|
|
221
|
+
attempt,
|
|
222
|
+
elapsedMs: now() - attemptStarted,
|
|
223
|
+
};
|
|
224
|
+
if (status !== undefined)
|
|
225
|
+
requestEvent.status = status;
|
|
226
|
+
const pending = options.onRequest(requestEvent);
|
|
227
|
+
if (pending)
|
|
228
|
+
void pending.catch(() => undefined);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
/* application-owned diagnostics */
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (delay !== undefined) {
|
|
236
|
+
if (now() - started + delay >= deadlineMs) {
|
|
237
|
+
if (status === 429)
|
|
238
|
+
throw new HttpError("Upstream request failed with HTTP 429.", "http", dispatched, status, delay);
|
|
239
|
+
throw new HttpError("Retry delay exceeds the request deadline.", "timeout", dispatched, status, delay, lastRequestId);
|
|
240
|
+
}
|
|
241
|
+
// oxlint-disable-next-line anti-slop/require-readable-spacing -- await is the guarded retry step.
|
|
242
|
+
await abortable((options.sleep ?? sleep)(delay, controller.signal), controller.signal);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
throw new HttpError("Request attempt budget exhausted.", "network", dispatched);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
if (input.signal?.aborted)
|
|
249
|
+
throw new HttpError("Request cancelled; a dispatched mutation may still complete remotely.", "cancelled", dispatched);
|
|
250
|
+
if (controller.signal.aborted)
|
|
251
|
+
throw new HttpError("Request deadline exceeded; reconcile dispatched mutations before retrying.", "timeout", dispatched);
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
input.signal?.removeEventListener("abort", abort);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Preserve integer IDs that JSON.parse would otherwise round. */
|
|
2
|
+
export type JsonValue = null | boolean | number | string | JsonValue[] | {
|
|
3
|
+
[key: string]: JsonValue;
|
|
4
|
+
};
|
|
5
|
+
export declare function parseJson(text: string): JsonValue;
|
|
6
|
+
export declare function jsonObject(value: JsonValue): {
|
|
7
|
+
readonly [key: string]: JsonValue;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/transport/json.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,MAAM,SAAS,GACjB,IAAI,GACJ,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEjC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAcjD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAMlF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function parseJson(text) {
|
|
2
|
+
// Match quoted strings first so digits within strings are never rewritten.
|
|
3
|
+
const lossless = text.replace(/"(?:[^"\\]|\\[\s\S])*"|-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/g, (token) => {
|
|
4
|
+
if (token.startsWith('"') || /[.eE]/.test(token) || Number.isSafeInteger(Number(token)))
|
|
5
|
+
return token;
|
|
6
|
+
return `"${token}"`;
|
|
7
|
+
});
|
|
8
|
+
// SAFETY: JSON.parse returns the recursive JSON grammar represented by JsonValue.
|
|
9
|
+
return JSON.parse(lossless);
|
|
10
|
+
}
|
|
11
|
+
export function jsonObject(value) {
|
|
12
|
+
if (value === null || Array.isArray(value) || Object(value) !== value)
|
|
13
|
+
throw new TypeError("Expected a JSON object");
|
|
14
|
+
// SAFETY: Object(value) === value and Array.isArray(value) is false establish a JSON object.
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/transport/json.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAC3B,qEAAqE,EACrE,CAAC,KAAK,EAAE,EAAE;QACR,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACrF,OAAO,KAAK,CAAC;QAEf,OAAO,IAAI,KAAK,GAAG,CAAC;IACtB,CAAC,CACF,CAAC;IAEF,kFAAkF;IAClF,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAc,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAgB;IACzC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK;QACnE,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAEhD,6FAA6F;IAC7F,OAAO,KAA8C,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface UploadSource {
|
|
2
|
+
mimeType: string;
|
|
3
|
+
size?: number;
|
|
4
|
+
body?: Blob;
|
|
5
|
+
/** Called exactly once per explicit upload. Return a fresh stream each time. */
|
|
6
|
+
open: () => ReadableStream<Uint8Array>;
|
|
7
|
+
}
|
|
8
|
+
export interface UploadOptions {
|
|
9
|
+
url: string;
|
|
10
|
+
source: UploadSource;
|
|
11
|
+
/** Trusted application/adapter policy, never browser-supplied. */
|
|
12
|
+
allowHost: (hostname: string) => boolean;
|
|
13
|
+
maxBytes: number;
|
|
14
|
+
maxChunkBytes?: number;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
fetch?: typeof globalThis.fetch;
|
|
18
|
+
onProgress?: (bytes: number) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare function httpsUrl(value: string): URL;
|
|
21
|
+
/** A provider-issued upload URL is used once, without API authorization or redirects. */
|
|
22
|
+
export declare function upload(options: UploadOptions): Promise<{
|
|
23
|
+
bytes: number;
|
|
24
|
+
etag?: string;
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=upload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/transport/upload.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,gFAAgF;IAChF,IAAI,EAAE,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,kEAAkE;IAClE,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAwC3C;AAED,yFAAyF;AACzF,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA4M9F"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { abortable, HttpError } from "./http.js";
|
|
2
|
+
export function httpsUrl(value) {
|
|
3
|
+
let url;
|
|
4
|
+
try {
|
|
5
|
+
url = new URL(value);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
throw new HttpError("Media URL must be an absolute HTTPS URL.", "invalid-input", false);
|
|
9
|
+
}
|
|
10
|
+
if (url.protocol !== "https:" ||
|
|
11
|
+
url.username ||
|
|
12
|
+
url.password ||
|
|
13
|
+
(url.port && url.port !== "443") ||
|
|
14
|
+
url.hash) {
|
|
15
|
+
throw new HttpError("Media URL must use HTTPS port 443 without credentials or a fragment.", "invalid-input", false);
|
|
16
|
+
}
|
|
17
|
+
const hostname = url.hostname.toLowerCase();
|
|
18
|
+
if (hostname === "localhost" ||
|
|
19
|
+
hostname.endsWith(".localhost") ||
|
|
20
|
+
hostname.endsWith(".local") ||
|
|
21
|
+
hostname.includes(":") ||
|
|
22
|
+
/^\d+(\.\d+){3}$/.test(hostname)) {
|
|
23
|
+
throw new HttpError("Local and IP-literal media hosts are not permitted.", "invalid-input", false);
|
|
24
|
+
}
|
|
25
|
+
return url;
|
|
26
|
+
}
|
|
27
|
+
/** A provider-issued upload URL is used once, without API authorization or redirects. */
|
|
28
|
+
export async function upload(options) {
|
|
29
|
+
const url = httpsUrl(options.url);
|
|
30
|
+
if (!options.allowHost(url.hostname))
|
|
31
|
+
throw new HttpError("Upload host is outside the configured storage policy.", "invalid-input", false);
|
|
32
|
+
const maxChunkBytes = options.maxChunkBytes ?? 1024 * 1024;
|
|
33
|
+
if (!Number.isSafeInteger(options.maxBytes) ||
|
|
34
|
+
options.maxBytes <= 0 ||
|
|
35
|
+
!Number.isSafeInteger(maxChunkBytes) ||
|
|
36
|
+
maxChunkBytes <= 0) {
|
|
37
|
+
throw new HttpError("Upload size and chunk limits must be positive integers.", "invalid-input", false);
|
|
38
|
+
}
|
|
39
|
+
const { source } = options;
|
|
40
|
+
if (!/^(image|video|application)\/[a-z0-9.+-]+$/i.test(source.mimeType))
|
|
41
|
+
throw new HttpError("An explicit supported media MIME type is required.", "invalid-input", false);
|
|
42
|
+
if (source.size !== undefined &&
|
|
43
|
+
(!Number.isSafeInteger(source.size) || source.size < 0 || source.size > options.maxBytes)) {
|
|
44
|
+
throw new HttpError("Media size exceeds the upload limit or is invalid.", "invalid-input", false);
|
|
45
|
+
}
|
|
46
|
+
if (source.body !== undefined &&
|
|
47
|
+
(source.body.size > options.maxBytes ||
|
|
48
|
+
(source.size !== undefined && source.body.size !== source.size)))
|
|
49
|
+
throw new HttpError("Media body exceeds the upload limit or does not match its declared size.", "invalid-input", false);
|
|
50
|
+
if (options.signal?.aborted)
|
|
51
|
+
throw new HttpError("Upload cancelled before opening the stream.", "cancelled", false);
|
|
52
|
+
const timeout = options.timeoutMs ?? 120_000;
|
|
53
|
+
if (!Number.isFinite(timeout) || timeout <= 0)
|
|
54
|
+
throw new HttpError("Upload deadline must be positive.", "invalid-input", false);
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
const abort = () => controller.abort(options.signal?.reason);
|
|
57
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
58
|
+
const timer = setTimeout(() => controller.abort(new Error("Upload deadline exceeded")), timeout);
|
|
59
|
+
let reader;
|
|
60
|
+
let buffered;
|
|
61
|
+
let bufferedOffset = 0;
|
|
62
|
+
let bytes = 0;
|
|
63
|
+
let dispatched = false;
|
|
64
|
+
try {
|
|
65
|
+
reader = source.open().getReader();
|
|
66
|
+
const sourceReader = reader;
|
|
67
|
+
const bodyStream = new ReadableStream({
|
|
68
|
+
async pull(output) {
|
|
69
|
+
try {
|
|
70
|
+
controller.signal.throwIfAborted();
|
|
71
|
+
if (buffered === undefined || bufferedOffset >= buffered.byteLength) {
|
|
72
|
+
const next = await abortable(sourceReader.read(), controller.signal);
|
|
73
|
+
if (next.done) {
|
|
74
|
+
if (source.size !== undefined && bytes !== source.size)
|
|
75
|
+
throw new HttpError("Upload stream length does not match declared size.", "invalid-input", dispatched);
|
|
76
|
+
output.close();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (bytes + next.value.byteLength > options.maxBytes) {
|
|
80
|
+
// oxlint-disable-next-line anti-slop/require-readable-spacing -- compact guarded error construction.
|
|
81
|
+
throw new HttpError("Upload stream exceeds its total byte limit.", "invalid-input", dispatched);
|
|
82
|
+
}
|
|
83
|
+
buffered = next.value;
|
|
84
|
+
bufferedOffset = 0;
|
|
85
|
+
}
|
|
86
|
+
const chunk = buffered.subarray(bufferedOffset, Math.min(buffered.byteLength, bufferedOffset + maxChunkBytes));
|
|
87
|
+
bufferedOffset += chunk.byteLength;
|
|
88
|
+
bytes += chunk.byteLength;
|
|
89
|
+
output.enqueue(chunk);
|
|
90
|
+
try {
|
|
91
|
+
options.onProgress?.(bytes);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
/* diagnostics cannot alter upload */
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
void sourceReader.cancel().catch(() => undefined);
|
|
99
|
+
output.error(error);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
cancel(reason) {
|
|
103
|
+
void sourceReader.cancel(reason).catch(() => undefined);
|
|
104
|
+
},
|
|
105
|
+
}, { highWaterMark: 1 });
|
|
106
|
+
const requestBody = source.body ?? bodyStream;
|
|
107
|
+
if (source.body !== undefined)
|
|
108
|
+
bytes = source.body.size;
|
|
109
|
+
const headers = new Headers({ "Content-Type": source.mimeType });
|
|
110
|
+
if (source.size !== undefined)
|
|
111
|
+
headers.set("Content-Length", String(source.size));
|
|
112
|
+
const init = {
|
|
113
|
+
method: "PUT",
|
|
114
|
+
headers,
|
|
115
|
+
body: requestBody,
|
|
116
|
+
redirect: "error",
|
|
117
|
+
signal: controller.signal,
|
|
118
|
+
};
|
|
119
|
+
if (source.body === undefined)
|
|
120
|
+
init.duplex = "half";
|
|
121
|
+
dispatched = true;
|
|
122
|
+
const pending = (options.fetch ?? globalThis.fetch)(url, init);
|
|
123
|
+
void pending.then((response) => {
|
|
124
|
+
if (controller.signal.aborted)
|
|
125
|
+
void response.body?.cancel().catch(() => undefined);
|
|
126
|
+
}, () => undefined);
|
|
127
|
+
const response = await abortable(pending, controller.signal);
|
|
128
|
+
void response.body?.cancel().catch(() => undefined);
|
|
129
|
+
if (!response.ok)
|
|
130
|
+
throw new HttpError(`Storage upload failed with HTTP ${response.status}.`, "http", true, response.status);
|
|
131
|
+
if (source.size !== undefined && bytes !== source.size)
|
|
132
|
+
throw new HttpError("Storage accepted before the full declared upload was consumed.", "invalid-response", true);
|
|
133
|
+
const etag = response.headers.get("etag");
|
|
134
|
+
if (etag === null)
|
|
135
|
+
return { bytes };
|
|
136
|
+
return { bytes, etag };
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
if (options.signal?.aborted)
|
|
140
|
+
throw new HttpError("Upload cancelled; remote acceptance is uncertain after dispatch.", "cancelled", dispatched);
|
|
141
|
+
if (controller.signal.aborted)
|
|
142
|
+
throw new HttpError("Upload deadline exceeded.", "timeout", dispatched);
|
|
143
|
+
if (error instanceof HttpError)
|
|
144
|
+
throw error;
|
|
145
|
+
throw new HttpError("Upload failed. Reconcile the upload before explicitly reopening its source.", "network", dispatched);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
clearTimeout(timer);
|
|
149
|
+
options.signal?.removeEventListener("abort", abort);
|
|
150
|
+
void reader?.cancel().catch(() => undefined);
|
|
151
|
+
reader?.releaseLock();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/transport/upload.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function object(value: unknown): Record<string, unknown>;
|
|
2
|
+
export declare function array(value: unknown): unknown[];
|
|
3
|
+
export declare function string(value: unknown): string;
|
|
4
|
+
export declare function optionalString(value: unknown): string | undefined;
|
|
5
|
+
export declare function optionalNumber(value: unknown): number | undefined;
|
|
6
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/transport/validation.ts"],"names":[],"mappings":"AAIA,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM9D;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAK/C;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAS7C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEjE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEjE"}
|