@mdbase-dev/connect 0.1.0-beta.100
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/LICENSE +21 -0
- package/README.md +696 -0
- package/dist/advanced.d.ts +9 -0
- package/dist/advanced.js +6 -0
- package/dist/application-contract.d.ts +22 -0
- package/dist/application-contract.js +75 -0
- package/dist/application-identity.d.ts +34 -0
- package/dist/application-identity.js +148 -0
- package/dist/application-session.d.ts +167 -0
- package/dist/application-session.js +722 -0
- package/dist/async.d.ts +1 -0
- package/dist/async.js +19 -0
- package/dist/authority-proof.d.ts +3 -0
- package/dist/authority-proof.js +24 -0
- package/dist/authority-sync-request.d.ts +3 -0
- package/dist/authority-sync-request.js +20 -0
- package/dist/authorization-refresh.d.ts +14 -0
- package/dist/authorization-refresh.js +41 -0
- package/dist/authorization-types.d.ts +7 -0
- package/dist/authorization-types.js +1 -0
- package/dist/authorization-url.d.ts +5 -0
- package/dist/authorization-url.js +34 -0
- package/dist/base64.d.ts +3 -0
- package/dist/base64.js +21 -0
- package/dist/browser/integrity.json +4 -0
- package/dist/browser/mdbase-connect.min.js +3 -0
- package/dist/browser/mdbase-connect.min.js.sha384 +1 -0
- package/dist/browser.d.ts +3 -0
- package/dist/browser.js +5 -0
- package/dist/capabilities.d.ts +24 -0
- package/dist/capabilities.js +91 -0
- package/dist/collection-client.d.ts +66 -0
- package/dist/collection-client.js +686 -0
- package/dist/connect-authorization-helpers.d.ts +4 -0
- package/dist/connect-authorization-helpers.js +25 -0
- package/dist/connect-options.d.ts +35 -0
- package/dist/connect-options.js +1 -0
- package/dist/connect.d.ts +66 -0
- package/dist/connect.js +711 -0
- package/dist/connection-file-transport.d.ts +34 -0
- package/dist/connection-file-transport.js +85 -0
- package/dist/connection-index.d.ts +3 -0
- package/dist/connection-index.js +20 -0
- package/dist/connection-notifications.d.ts +31 -0
- package/dist/connection-notifications.js +197 -0
- package/dist/connection-transport-internals.d.ts +24 -0
- package/dist/connection-transport-internals.js +1 -0
- package/dist/connection-transport.d.ts +64 -0
- package/dist/connection-transport.js +725 -0
- package/dist/connection-types.d.ts +38 -0
- package/dist/connection-types.js +1 -0
- package/dist/connection.d.ts +175 -0
- package/dist/connection.js +606 -0
- package/dist/crypto-entry.d.ts +7 -0
- package/dist/crypto-entry.js +4 -0
- package/dist/crypto.d.ts +63 -0
- package/dist/crypto.js +409 -0
- package/dist/direct-access.d.ts +3 -0
- package/dist/direct-access.js +29 -0
- package/dist/errors.d.ts +45 -0
- package/dist/errors.js +142 -0
- package/dist/external-store.d.ts +10 -0
- package/dist/external-store.js +10 -0
- package/dist/file-crypto.d.ts +25 -0
- package/dist/file-crypto.js +132 -0
- package/dist/file-sha256.d.ts +12 -0
- package/dist/file-sha256.js +143 -0
- package/dist/file-stream-source.d.ts +17 -0
- package/dist/file-stream-source.js +157 -0
- package/dist/file-transfer-internals.d.ts +23 -0
- package/dist/file-transfer-internals.js +228 -0
- package/dist/files.d.ts +115 -0
- package/dist/files.js +563 -0
- package/dist/fresh-encrypted-request.d.ts +4 -0
- package/dist/fresh-encrypted-request.js +28 -0
- package/dist/grant-key-leases.d.ts +24 -0
- package/dist/grant-key-leases.js +144 -0
- package/dist/hosted-file-request.d.ts +6 -0
- package/dist/hosted-file-request.js +63 -0
- package/dist/hosted-operation-response.d.ts +5 -0
- package/dist/hosted-operation-response.js +26 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +10 -0
- package/dist/internal-types.d.ts +100 -0
- package/dist/internal-types.js +1 -0
- package/dist/local-file-transport.d.ts +37 -0
- package/dist/local-file-transport.js +457 -0
- package/dist/mdbase-connect.d.ts +28 -0
- package/dist/mdbase-connect.js +53 -0
- package/dist/notifications.d.ts +48 -0
- package/dist/notifications.js +52 -0
- package/dist/operation-helpers.d.ts +27 -0
- package/dist/operation-helpers.js +144 -0
- package/dist/operation-types.d.ts +707 -0
- package/dist/operation-types.js +1 -0
- package/dist/outcomes.d.ts +51 -0
- package/dist/outcomes.js +194 -0
- package/dist/pending-mutation-store.d.ts +13 -0
- package/dist/pending-mutation-store.js +64 -0
- package/dist/pending-recovery-transports.d.ts +5 -0
- package/dist/pending-recovery-transports.js +52 -0
- package/dist/popup-authorization.d.ts +31 -0
- package/dist/popup-authorization.js +100 -0
- package/dist/query-pagination.d.ts +6 -0
- package/dist/query-pagination.js +119 -0
- package/dist/request-budget.d.ts +34 -0
- package/dist/request-budget.js +104 -0
- package/dist/request-coordinator.d.ts +29 -0
- package/dist/request-coordinator.js +213 -0
- package/dist/retired-grant-keys.d.ts +9 -0
- package/dist/retired-grant-keys.js +56 -0
- package/dist/runtime-utils.d.ts +52 -0
- package/dist/runtime-utils.js +368 -0
- package/dist/saved-view-pagination.d.ts +6 -0
- package/dist/saved-view-pagination.js +76 -0
- package/dist/selection.d.ts +48 -0
- package/dist/selection.js +112 -0
- package/dist/session.d.ts +114 -0
- package/dist/session.js +569 -0
- package/dist/shared-operation.d.ts +7 -0
- package/dist/shared-operation.js +41 -0
- package/dist/stored-token.d.ts +10 -0
- package/dist/stored-token.js +64 -0
- package/dist/structured-readiness.d.ts +77 -0
- package/dist/structured-readiness.js +126 -0
- package/dist/token-response.d.ts +12 -0
- package/dist/token-response.js +81 -0
- package/dist/transient-retry.d.ts +22 -0
- package/dist/transient-retry.js +59 -0
- package/dist/watch-policy.d.ts +8 -0
- package/dist/watch-policy.js +12 -0
- package/package.json +51 -0
package/dist/async.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function abortableDelay(milliseconds: number, signal?: AbortSignal): Promise<void>;
|
package/dist/async.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function abortableDelay(milliseconds, signal) {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
if (signal?.aborted) {
|
|
4
|
+
reject(signal?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const cleanup = () => signal?.removeEventListener("abort", abort);
|
|
8
|
+
const timeout = setTimeout(() => {
|
|
9
|
+
cleanup();
|
|
10
|
+
resolve();
|
|
11
|
+
}, milliseconds);
|
|
12
|
+
const abort = () => {
|
|
13
|
+
clearTimeout(timeout);
|
|
14
|
+
cleanup();
|
|
15
|
+
reject(signal?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
16
|
+
};
|
|
17
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type GrantKeyStore } from "./crypto.js";
|
|
2
|
+
import type { StoredToken } from "./internal-types.js";
|
|
3
|
+
export declare function authorityProofHeaders(keyStore: GrantKeyStore, token: StoredToken, method: string, url: string, body: string | undefined, credential: string): Promise<Record<string, string>>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RelayCryptoError, signAuthorityRequest } from "./crypto.js";
|
|
2
|
+
import { connectError, serverConnectError } from "./errors.js";
|
|
3
|
+
export async function authorityProofHeaders(keyStore, token, method, url, body, credential) {
|
|
4
|
+
if (!token.authority?.proofPublicKey)
|
|
5
|
+
return {};
|
|
6
|
+
if (!token.keyHandle) {
|
|
7
|
+
throw connectError("missing_grant_key", "Reconnect this application to restore remote authority request signing.");
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const target = new URL(url);
|
|
11
|
+
return await signAuthorityRequest(keyStore, token.keyHandle, token.authority.proofPublicKey, {
|
|
12
|
+
method,
|
|
13
|
+
target: `${target.pathname}${target.search}`,
|
|
14
|
+
body,
|
|
15
|
+
credential
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error instanceof RelayCryptoError) {
|
|
20
|
+
throw serverConnectError(error.code, error.message);
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { GrantKeyStore } from "./crypto.js";
|
|
2
|
+
import type { StoredToken } from "./internal-types.js";
|
|
3
|
+
export declare function sendAuthoritySyncRequest(keyStore: GrantKeyStore, token: StoredToken, method: "GET" | "POST", path: string, input: unknown, signal: AbortSignal): Promise<Response>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { authorityProofHeaders } from "./authority-proof.js";
|
|
2
|
+
import { connectError } from "./errors.js";
|
|
3
|
+
export async function sendAuthoritySyncRequest(keyStore, token, method, path, input, signal) {
|
|
4
|
+
if (!token.authority) {
|
|
5
|
+
throw connectError("not_remote_authority", "This authorization has no remote authority endpoint.");
|
|
6
|
+
}
|
|
7
|
+
const url = `${token.authority.syncUrl}/${path}`;
|
|
8
|
+
const body = input === undefined ? undefined : JSON.stringify(input);
|
|
9
|
+
const proof = await authorityProofHeaders(keyStore, token, method, url, body, token.authority.accessToken);
|
|
10
|
+
return fetch(url, {
|
|
11
|
+
method,
|
|
12
|
+
headers: {
|
|
13
|
+
authorization: `Bearer ${token.authority.accessToken}`,
|
|
14
|
+
...(input === undefined ? {} : { "content-type": "application/json" }),
|
|
15
|
+
...proof
|
|
16
|
+
},
|
|
17
|
+
...(body === undefined ? {} : { body }),
|
|
18
|
+
signal
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { GrantKeyStore } from "./crypto.js";
|
|
2
|
+
import type { StoredToken } from "./internal-types.js";
|
|
3
|
+
interface AuthorizationRefreshOptions {
|
|
4
|
+
current: StoredToken | null;
|
|
5
|
+
serverUrl: string;
|
|
6
|
+
keyStore: GrantKeyStore;
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
currentToken(): StoredToken | null;
|
|
9
|
+
directCapable(token: StoredToken): boolean;
|
|
10
|
+
removeToken(keyHandle?: string): void;
|
|
11
|
+
storeTokenResponse(body: any, clientId: string, keyHandle?: string): StoredToken;
|
|
12
|
+
}
|
|
13
|
+
export declare function performAuthorizationRefresh(options: AuthorizationRefreshOptions): Promise<StoredToken>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { authorityProofHeaders } from "./authority-proof.js";
|
|
2
|
+
import { apiError, decodeJsonResponse, oauthErrorCode } from "./runtime-utils.js";
|
|
3
|
+
import { connectError } from "./errors.js";
|
|
4
|
+
export async function performAuthorizationRefresh(options) {
|
|
5
|
+
const current = options.current;
|
|
6
|
+
if (!current?.refreshToken) {
|
|
7
|
+
throw connectError("not_authorized", "Reconnect this application to continue.");
|
|
8
|
+
}
|
|
9
|
+
if ((current.refreshExpiresAt ?? 0) <= Date.now()) {
|
|
10
|
+
throw connectError("relay_authorization_expired", "Direct access is still available on this computer, but using the relay requires reconnecting this application.");
|
|
11
|
+
}
|
|
12
|
+
const attemptedRefreshToken = current.refreshToken;
|
|
13
|
+
const refreshUrl = `${options.serverUrl}/oauth/token`;
|
|
14
|
+
const refreshBody = new URLSearchParams({
|
|
15
|
+
grant_type: "refresh_token",
|
|
16
|
+
refresh_token: current.refreshToken,
|
|
17
|
+
client_id: current.clientId
|
|
18
|
+
}).toString();
|
|
19
|
+
const proof = current.authority
|
|
20
|
+
? await authorityProofHeaders(options.keyStore, current, "POST", refreshUrl, refreshBody, current.refreshToken)
|
|
21
|
+
: {};
|
|
22
|
+
const response = await fetch(refreshUrl, {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "content-type": "application/x-www-form-urlencoded", ...proof },
|
|
25
|
+
body: refreshBody,
|
|
26
|
+
signal: options.signal
|
|
27
|
+
});
|
|
28
|
+
const body = await decodeJsonResponse(response, "invalid_token_response", "The authorization service returned an invalid token response.");
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
const latest = options.currentToken();
|
|
31
|
+
if (latest?.refreshToken && latest.refreshToken !== attemptedRefreshToken)
|
|
32
|
+
return latest;
|
|
33
|
+
if (!options.directCapable(current))
|
|
34
|
+
options.removeToken(current.keyHandle);
|
|
35
|
+
if ((oauthErrorCode(body) ?? body?.error?.code) === "invalid_grant") {
|
|
36
|
+
throw connectError("authorization_expired", body?.error_description ?? body?.error?.message ?? "Reconnect this application to continue.", { status: response.status });
|
|
37
|
+
}
|
|
38
|
+
throw apiError(body, "authorization_expired", "Reconnect this application to continue.", response.status);
|
|
39
|
+
}
|
|
40
|
+
return options.storeTokenResponse(body, current.clientId, current.keyHandle);
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ConnectProblem } from "@mdbase-dev/connect-protocol";
|
|
2
|
+
export declare function cleanAuthorizationParameters(url: URL): URL;
|
|
3
|
+
export declare function isAuthorizationCallbackUrl(value: string): boolean;
|
|
4
|
+
export declare function authorizationCallbackState(value: string): string | null;
|
|
5
|
+
export declare function authorizationReturnToFromProblem(problem: ConnectProblem): string | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function cleanAuthorizationParameters(url) {
|
|
2
|
+
for (const parameter of ["code", "state", "error", "error_description"]) {
|
|
3
|
+
url.searchParams.delete(parameter);
|
|
4
|
+
}
|
|
5
|
+
return url;
|
|
6
|
+
}
|
|
7
|
+
export function isAuthorizationCallbackUrl(value) {
|
|
8
|
+
let url;
|
|
9
|
+
try {
|
|
10
|
+
url = new URL(value);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
return url.searchParams.has("state")
|
|
16
|
+
&& (url.searchParams.has("code") || url.searchParams.has("error"));
|
|
17
|
+
}
|
|
18
|
+
export function authorizationCallbackState(value) {
|
|
19
|
+
try {
|
|
20
|
+
const state = new URL(value).searchParams.get("state");
|
|
21
|
+
return state && state.length > 0 ? state : null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function authorizationReturnToFromProblem(problem) {
|
|
28
|
+
if (!problem.details
|
|
29
|
+
|| typeof problem.details !== "object"
|
|
30
|
+
|| Array.isArray(problem.details))
|
|
31
|
+
return undefined;
|
|
32
|
+
const returnTo = problem.details.return_to;
|
|
33
|
+
return typeof returnTo === "string" ? returnTo : undefined;
|
|
34
|
+
}
|
package/dist/base64.d.ts
ADDED
package/dist/base64.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function randomBase64Url(size) {
|
|
2
|
+
const bytes = new Uint8Array(size);
|
|
3
|
+
crypto.getRandomValues(bytes);
|
|
4
|
+
return bytesToBase64Url(bytes);
|
|
5
|
+
}
|
|
6
|
+
export function bytesToBase64Url(bytes) {
|
|
7
|
+
let binary = "";
|
|
8
|
+
for (const byte of bytes)
|
|
9
|
+
binary += String.fromCharCode(byte);
|
|
10
|
+
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
11
|
+
}
|
|
12
|
+
export function base64UrlBytes(value) {
|
|
13
|
+
const padded = value.replaceAll("-", "+").replaceAll("_", "/")
|
|
14
|
+
.padEnd(Math.ceil(value.length / 4) * 4, "=");
|
|
15
|
+
const binary = atob(padded);
|
|
16
|
+
const bytes = new Uint8Array(new ArrayBuffer(binary.length));
|
|
17
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
18
|
+
bytes[index] = binary.charCodeAt(index);
|
|
19
|
+
}
|
|
20
|
+
return bytes;
|
|
21
|
+
}
|