@mdbase-dev/connect 0.1.0-beta.110 → 0.1.0-beta.111
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/browser/integrity.json +1 -1
- package/dist/browser/mdbase-connect.min.js +3 -3
- package/dist/browser/mdbase-connect.min.js.sha384 +1 -1
- package/dist/connection-transport.js +11 -5
- package/dist/direct-access.js +13 -8
- package/dist/local-file-transport.js +4 -4
- package/dist/operation-helpers.d.ts +1 -1
- package/dist/operation-helpers.js +7 -2
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
sha384
|
|
1
|
+
sha384-/62JQssTDGRQGVQwcO5KLWO7BOqrDVxB0ne307QlEFVO3/MzYMBJfjmbz/OdCRWP
|
|
@@ -5,7 +5,7 @@ import { ConnectionFileTransport } from "./connection-file-transport.js";
|
|
|
5
5
|
import { authorityProofHeaders } from "./authority-proof.js";
|
|
6
6
|
import { performAuthorizationRefresh } from "./authorization-refresh.js";
|
|
7
7
|
import { PendingMutationStore } from "./pending-mutation-store.js";
|
|
8
|
-
import {
|
|
8
|
+
import { directFallbackResponse, encryptedOperationError, fetchOperationRequest, isMutation, localNetworkPermission, loopbackRequest, operationFingerprint, operationTransportError, sameAuthorization, throwIfCancelled, unknownMutationOutcome, withOperationDeadline } from "./operation-helpers.js";
|
|
9
9
|
import { apiError, decodeJsonResponse, parseStored, } from "./runtime-utils.js";
|
|
10
10
|
import { readStoredToken } from "./stored-token.js";
|
|
11
11
|
import { requestOptionsWithinBudget, withCooperativeRequestBudget, withRequestBudget } from "./request-budget.js";
|
|
@@ -467,7 +467,7 @@ export class ConnectionTransport {
|
|
|
467
467
|
body: JSON.stringify(encryptedRequest),
|
|
468
468
|
signal: options.signal
|
|
469
469
|
}));
|
|
470
|
-
if (!
|
|
470
|
+
if (!await directFallbackResponse(response)
|
|
471
471
|
|| await isExplicitConnectorBusyResponse(response)) {
|
|
472
472
|
if (response.ok) {
|
|
473
473
|
this.markDirectAvailable();
|
|
@@ -603,9 +603,15 @@ export class ConnectionTransport {
|
|
|
603
603
|
}
|
|
604
604
|
async probeDirectAccess(signal) {
|
|
605
605
|
this.setDirectStatus("checking");
|
|
606
|
-
|
|
607
|
-
this.
|
|
608
|
-
|
|
606
|
+
try {
|
|
607
|
+
if (await probeLoopbackAccess(this.loopbackUrl, OPERATION_TRANSPORT_PROTOCOL_VERSION, signal)) {
|
|
608
|
+
this.markDirectAvailable();
|
|
609
|
+
return "available";
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
catch (error) {
|
|
613
|
+
this.markDirectUnavailable();
|
|
614
|
+
throw error;
|
|
609
615
|
}
|
|
610
616
|
if ((await localNetworkPermission()) === "denied")
|
|
611
617
|
return this.setDirectStatus("denied");
|
package/dist/direct-access.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { loopbackRequest } from "./operation-helpers.js";
|
|
2
|
-
import { decodeJsonResponse } from "./runtime-utils.js";
|
|
2
|
+
import { decodeJsonResponse, portableApplicationOrigin } from "./runtime-utils.js";
|
|
3
|
+
import { serverConnectError } from "./errors.js";
|
|
3
4
|
export function tokenSupportsDirectAccess(token, mode) {
|
|
4
5
|
if (!token || token.authority || !token.encryption || !token.grantId || !token.keyHandle) {
|
|
5
6
|
return false;
|
|
@@ -8,22 +9,26 @@ export function tokenSupportsDirectAccess(token, mode) {
|
|
|
8
9
|
return false;
|
|
9
10
|
return typeof location === "undefined"
|
|
10
11
|
|| !token.applicationOrigin
|
|
11
|
-
|| token.applicationOrigin ===
|
|
12
|
+
|| token.applicationOrigin === portableApplicationOrigin();
|
|
12
13
|
}
|
|
13
14
|
export async function probeLoopbackAccess(loopbackUrl, expectedOperationProtocol, signal) {
|
|
15
|
+
let response;
|
|
14
16
|
try {
|
|
15
|
-
|
|
17
|
+
response = await fetch(`${loopbackUrl}/v1/ready`, loopbackRequest({
|
|
16
18
|
method: "GET",
|
|
17
19
|
cache: "no-store",
|
|
18
20
|
signal
|
|
19
21
|
}));
|
|
20
|
-
const body = await decodeJsonResponse(response, "invalid_operation_response", "The connector returned an invalid readiness response.").catch(() => null);
|
|
21
|
-
return response.ok
|
|
22
|
-
&& body?.service === "mdbase-connect"
|
|
23
|
-
&& body?.loopback_protocol_version === 1
|
|
24
|
-
&& body?.operation_transport_protocol_version === expectedOperationProtocol;
|
|
25
22
|
}
|
|
26
23
|
catch {
|
|
27
24
|
return false;
|
|
28
25
|
}
|
|
26
|
+
if (response.status === 403) {
|
|
27
|
+
throw serverConnectError("operation_failed", "The connector rejected direct access from this application. Relay access remains available.", { status: response.status });
|
|
28
|
+
}
|
|
29
|
+
const body = await decodeJsonResponse(response, "invalid_operation_response", "The connector returned an invalid readiness response.").catch(() => null);
|
|
30
|
+
return response.ok
|
|
31
|
+
&& body?.service === "mdbase-connect"
|
|
32
|
+
&& body?.loopback_protocol_version === 1
|
|
33
|
+
&& body?.operation_transport_protocol_version === expectedOperationProtocol;
|
|
29
34
|
}
|
|
@@ -3,7 +3,7 @@ import { decryptRelayResponse, encryptRelayRequest } from "./crypto.js";
|
|
|
3
3
|
import { MdbaseConnectError, connectError, serverConnectError } from "./errors.js";
|
|
4
4
|
import { GrantFileTransferCipher } from "./file-crypto.js";
|
|
5
5
|
import { GrantKeyLeaseSet, retainCurrentGrantToken } from "./grant-key-leases.js";
|
|
6
|
-
import {
|
|
6
|
+
import { directFallbackResponse, loopbackRequest } from "./operation-helpers.js";
|
|
7
7
|
import { apiError, decodeJsonResponse } from "./runtime-utils.js";
|
|
8
8
|
import { isConnectorBusy, isExplicitConnectorBusyResponse, MAX_CONNECTOR_BUSY_RETRIES, waitForConnectorAvailability } from "./transient-retry.js";
|
|
9
9
|
/** Keeps grant-bound file crypto and loopback framing out of the operation transport. */
|
|
@@ -42,7 +42,7 @@ export class LocalFileTransport {
|
|
|
42
42
|
throw error;
|
|
43
43
|
this.options.onDirectUnavailable();
|
|
44
44
|
}
|
|
45
|
-
if (response && (!
|
|
45
|
+
if (response && (!await directFallbackResponse(response)
|
|
46
46
|
|| await isExplicitConnectorBusyResponse(response))) {
|
|
47
47
|
if (response.ok)
|
|
48
48
|
this.options.onDirectAvailable();
|
|
@@ -134,7 +134,7 @@ export class LocalFileTransport {
|
|
|
134
134
|
throw error;
|
|
135
135
|
this.options.onDirectUnavailable();
|
|
136
136
|
}
|
|
137
|
-
if (response && (!
|
|
137
|
+
if (response && (!await directFallbackResponse(response)
|
|
138
138
|
|| await isExplicitConnectorBusyResponse(response))) {
|
|
139
139
|
if (response.ok)
|
|
140
140
|
this.options.onDirectAvailable();
|
|
@@ -180,7 +180,7 @@ export class LocalFileTransport {
|
|
|
180
180
|
throw error;
|
|
181
181
|
this.options.onDirectUnavailable();
|
|
182
182
|
}
|
|
183
|
-
if (response && (!
|
|
183
|
+
if (response && (!await directFallbackResponse(response)
|
|
184
184
|
|| await isExplicitConnectorBusyResponse(response))) {
|
|
185
185
|
if (response.ok)
|
|
186
186
|
this.options.onDirectAvailable();
|
|
@@ -7,7 +7,7 @@ export type LoopbackRequestInit = RequestInit & {
|
|
|
7
7
|
};
|
|
8
8
|
export declare function loopbackRequest(init: RequestInit): LoopbackRequestInit;
|
|
9
9
|
export declare function localNetworkPermission(): Promise<PermissionState | null>;
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function directFallbackResponse(response: Response): Promise<boolean>;
|
|
11
11
|
export declare function isMutation(operation: CollectionOperation, input?: unknown): boolean;
|
|
12
12
|
export declare function withOperationDeadline(request: EncryptedRelayOperationRequest, deadlineUnixMs?: number): EncryptedRelayOperationRequest;
|
|
13
13
|
export declare function uniqueOperations(operations: CollectionOperation[]): CollectionOperation[];
|
|
@@ -16,8 +16,13 @@ export async function localNetworkPermission() {
|
|
|
16
16
|
return null;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
export function
|
|
20
|
-
|
|
19
|
+
export async function directFallbackResponse(response) {
|
|
20
|
+
const { status } = response;
|
|
21
|
+
if (status === 404 || status === 405 || status === 426 || status >= 500)
|
|
22
|
+
return true;
|
|
23
|
+
// Loopback rejects browser requests before execution with an empty 403.
|
|
24
|
+
// Structured grant/policy rejections must remain terminal, not route failures.
|
|
25
|
+
return status === 403 && (await response.clone().text()).trim() === "";
|
|
21
26
|
}
|
|
22
27
|
export function isMutation(operation, input) {
|
|
23
28
|
return isMutatingOperation(operation, input);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mdbase-dev/connect",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.111",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"README.md"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@mdbase-dev/connect-protocol": "0.1.0-beta.
|
|
36
|
+
"@mdbase-dev/connect-protocol": "0.1.0-beta.111"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"esbuild": "^0.28.1",
|