@telecrypt-io/storage 0.6.0 → 0.7.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 -9
- package/dist/TeleCryptIOStorage.d.ts +3 -1
- package/dist/TeleCryptIOStorage.js +39 -83
- package/dist/core/constants.d.ts +2 -4
- package/dist/core/constants.js +8 -10
- package/dist/core/http.d.ts +2 -2
- package/dist/core/http.js +24 -95
- package/dist/core/oidc.d.ts +2 -6
- package/dist/core/oidc.js +86 -333
- package/dist/core/operations.js +24 -32
- package/package.json +2 -4
package/dist/core/http.js
CHANGED
|
@@ -12,7 +12,6 @@ export class ResponseBodyReadError extends Error {
|
|
|
12
12
|
this.bytes = bytes;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
const RESPONSE_CLEANUP_TIMEOUT_MS = 5_000;
|
|
16
15
|
function abortError() {
|
|
17
16
|
return new DOMException("The operation was aborted", "AbortError");
|
|
18
17
|
}
|
|
@@ -53,79 +52,32 @@ export function raceWithAbort(operation, signal, error) {
|
|
|
53
52
|
abort();
|
|
54
53
|
});
|
|
55
54
|
}
|
|
56
|
-
function
|
|
57
|
-
const errors = primaryError === undefined ? [...cleanupFailures] : [primaryError, ...cleanupFailures];
|
|
58
|
-
return new AggregateError(errors, message, {
|
|
59
|
-
cause: primaryError ?? cleanupFailures[0],
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
async function runBoundedCleanup(cleanup, operation) {
|
|
63
|
-
const pending = Promise.resolve().then(cleanup);
|
|
64
|
-
let timer;
|
|
65
|
-
const deadline = new Promise((_, reject) => {
|
|
66
|
-
timer = setTimeout(() => {
|
|
67
|
-
reject(new Error(`${operation} cleanup timed out`));
|
|
68
|
-
}, RESPONSE_CLEANUP_TIMEOUT_MS);
|
|
69
|
-
});
|
|
55
|
+
function startCancellation(cancel) {
|
|
70
56
|
try {
|
|
71
|
-
|
|
57
|
+
void Promise.resolve(cancel()).catch(() => { });
|
|
72
58
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
clearTimeout(timer);
|
|
59
|
+
catch {
|
|
60
|
+
// Cleanup must not delay or replace the operation result.
|
|
76
61
|
}
|
|
77
62
|
}
|
|
78
|
-
/**
|
|
79
|
-
export
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
await runBoundedCleanup(() => response.body.cancel(), `${operation} response`);
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
throw combineCleanupFailures(primaryError, [error], primaryError === undefined
|
|
87
|
-
? `${operation} response cleanup was incomplete`
|
|
88
|
-
: `${operation} failed and response cleanup was incomplete`);
|
|
89
|
-
}
|
|
63
|
+
/** Start discarding a rejected response without waiting for provider cleanup. */
|
|
64
|
+
export function cancelResponseBody(response) {
|
|
65
|
+
if (response.body)
|
|
66
|
+
startCancellation(() => response.body.cancel());
|
|
90
67
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
await runBoundedCleanup(() => reader.cancel(), `${operation} reader cancellation`);
|
|
95
|
-
}
|
|
96
|
-
catch (error) {
|
|
97
|
-
cleanupFailures.push(error);
|
|
98
|
-
}
|
|
99
|
-
// Cancellation is awaited before releasing the reader, so cleanup failures
|
|
100
|
-
// stay part of the current operation instead of mutating a later error.
|
|
68
|
+
function cancelReaderAndRelease(reader) {
|
|
69
|
+
startCancellation(() => reader.cancel());
|
|
101
70
|
try {
|
|
102
71
|
reader.releaseLock();
|
|
103
72
|
}
|
|
104
|
-
catch
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
if (cleanupFailures.length > 0) {
|
|
108
|
-
throw combineCleanupFailures(primaryError, cleanupFailures, primaryError === undefined
|
|
109
|
-
? `${operation} reader cleanup was incomplete`
|
|
110
|
-
: `${operation} failed and reader cleanup was incomplete`);
|
|
73
|
+
catch {
|
|
74
|
+
// The reader may still have a pending read; the caller's error remains authoritative.
|
|
111
75
|
}
|
|
112
76
|
}
|
|
113
77
|
async function readResponseBodyInternal(response, signal, options = {}, maxBytes) {
|
|
114
|
-
const cancelAbortedResponse = async (failure) => {
|
|
115
|
-
if (!response.body)
|
|
116
|
-
return;
|
|
117
|
-
let reader;
|
|
118
|
-
try {
|
|
119
|
-
reader = response.body.getReader();
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
throw combineCleanupFailures(failure, [error], "response reader setup failed after abort");
|
|
123
|
-
}
|
|
124
|
-
await cancelReaderAndRelease(reader, "response body", failure);
|
|
125
|
-
};
|
|
126
78
|
if (signal?.aborted) {
|
|
127
79
|
const failure = options.abortError?.() ?? abortError();
|
|
128
|
-
|
|
80
|
+
cancelResponseBody(response);
|
|
129
81
|
throw failure;
|
|
130
82
|
}
|
|
131
83
|
if (maxBytes !== undefined &&
|
|
@@ -136,7 +88,7 @@ async function readResponseBodyInternal(response, signal, options = {}, maxBytes
|
|
|
136
88
|
const contentLength = response.headers.get("content-length");
|
|
137
89
|
if (contentLength !== null && /^\d+$/u.test(contentLength) && Number(contentLength) > maxBytes) {
|
|
138
90
|
const tooLarge = new FileTooLargeError();
|
|
139
|
-
|
|
91
|
+
cancelResponseBody(response);
|
|
140
92
|
throw tooLarge;
|
|
141
93
|
}
|
|
142
94
|
}
|
|
@@ -147,18 +99,15 @@ async function readResponseBodyInternal(response, signal, options = {}, maxBytes
|
|
|
147
99
|
reader = response.body.getReader();
|
|
148
100
|
}
|
|
149
101
|
catch (error) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
await cancelResponseBody(response, "response body reader setup", error);
|
|
153
|
-
}
|
|
154
|
-
catch (cleanupError) {
|
|
155
|
-
failure = cleanupError;
|
|
156
|
-
}
|
|
157
|
-
throw new ResponseBodyReadError(new Uint8Array(), failure);
|
|
102
|
+
cancelResponseBody(response);
|
|
103
|
+
throw new ResponseBodyReadError(new Uint8Array(), error);
|
|
158
104
|
}
|
|
159
|
-
let
|
|
105
|
+
let cancellationStarted = false;
|
|
160
106
|
const cancelReader = () => {
|
|
161
|
-
|
|
107
|
+
if (cancellationStarted)
|
|
108
|
+
return;
|
|
109
|
+
cancellationStarted = true;
|
|
110
|
+
startCancellation(() => reader.cancel());
|
|
162
111
|
};
|
|
163
112
|
const chunks = [];
|
|
164
113
|
let bytesRead = 0;
|
|
@@ -213,34 +162,14 @@ async function readResponseBodyInternal(response, signal, options = {}, maxBytes
|
|
|
213
162
|
catch (error) {
|
|
214
163
|
if (signal?.aborted) {
|
|
215
164
|
const failure = new ResponseBodyReadError(joinBytes(chunks, bytesRead), error);
|
|
216
|
-
|
|
217
|
-
if (abortCancellation) {
|
|
218
|
-
try {
|
|
219
|
-
await abortCancellation;
|
|
220
|
-
}
|
|
221
|
-
catch (cleanupError) {
|
|
222
|
-
cleanupFailures.push(cleanupError);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
165
|
+
cancelReader();
|
|
225
166
|
try {
|
|
226
167
|
reader.releaseLock();
|
|
227
168
|
}
|
|
228
|
-
catch
|
|
229
|
-
cleanupFailures.push(cleanupError);
|
|
230
|
-
}
|
|
231
|
-
if (cleanupFailures.length > 0) {
|
|
232
|
-
throw combineCleanupFailures(failure, cleanupFailures, "response body read failed and reader cleanup was incomplete");
|
|
233
|
-
}
|
|
169
|
+
catch { /* Pending reads release with cancellation. */ }
|
|
234
170
|
throw failure;
|
|
235
171
|
}
|
|
236
|
-
|
|
237
|
-
await cancelReaderAndRelease(reader, "response body", error);
|
|
238
|
-
}
|
|
239
|
-
catch (cleanupError) {
|
|
240
|
-
if (error instanceof FileTooLargeError)
|
|
241
|
-
throw cleanupError;
|
|
242
|
-
throw new ResponseBodyReadError(joinBytes(chunks, bytesRead), cleanupError);
|
|
243
|
-
}
|
|
172
|
+
cancelReaderAndRelease(reader);
|
|
244
173
|
if (error instanceof FileTooLargeError)
|
|
245
174
|
throw error;
|
|
246
175
|
throw new ResponseBodyReadError(joinBytes(chunks, bytesRead), error);
|
package/dist/core/oidc.d.ts
CHANGED
|
@@ -34,9 +34,6 @@ export type OidcTokenEndpointMetadata = Pick<OidcClientConfig, "issuer" | "token
|
|
|
34
34
|
* identifiers, or control characters from an untrusted response to cross the
|
|
35
35
|
* SDK boundary. */
|
|
36
36
|
export declare function sanitizeDiagnosticText(value: string): string;
|
|
37
|
-
/** Copy a transport error's useful details across the SDK boundary after the
|
|
38
|
-
* same secret/control-character sanitization used for provider responses. */
|
|
39
|
-
export declare function diagnosticCause(error: unknown, seen?: WeakSet<object>): Error;
|
|
40
37
|
/**
|
|
41
38
|
* Discovers the OIDC/MAS issuer and endpoints for a homeserver via the
|
|
42
39
|
* Matrix client's stable `/auth_metadata` endpoint. Matrix 42 performs this
|
|
@@ -44,9 +41,8 @@ export declare function diagnosticCause(error: unknown, seen?: WeakSet<object>):
|
|
|
44
41
|
*/
|
|
45
42
|
export declare function discoverOidcIssuer(homeserverBaseUrl: string, signal?: AbortSignal): Promise<OidcClientConfig>;
|
|
46
43
|
/**
|
|
47
|
-
* Dynamic client registration (DCR).
|
|
48
|
-
*
|
|
49
|
-
* does; a production issuer may not).
|
|
44
|
+
* Dynamic client registration (DCR). The issuer validates the supplied
|
|
45
|
+
* metadata; the PKCE flow separately binds its callback to the current app.
|
|
50
46
|
*/
|
|
51
47
|
export declare function registerClient(authMetadata: OidcClientConfig, metadata: OidcRegistrationClientMetadata, signal?: AbortSignal): Promise<string>;
|
|
52
48
|
/**
|