@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.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +696 -0
  3. package/dist/advanced.d.ts +9 -0
  4. package/dist/advanced.js +6 -0
  5. package/dist/application-contract.d.ts +22 -0
  6. package/dist/application-contract.js +75 -0
  7. package/dist/application-identity.d.ts +34 -0
  8. package/dist/application-identity.js +148 -0
  9. package/dist/application-session.d.ts +167 -0
  10. package/dist/application-session.js +722 -0
  11. package/dist/async.d.ts +1 -0
  12. package/dist/async.js +19 -0
  13. package/dist/authority-proof.d.ts +3 -0
  14. package/dist/authority-proof.js +24 -0
  15. package/dist/authority-sync-request.d.ts +3 -0
  16. package/dist/authority-sync-request.js +20 -0
  17. package/dist/authorization-refresh.d.ts +14 -0
  18. package/dist/authorization-refresh.js +41 -0
  19. package/dist/authorization-types.d.ts +7 -0
  20. package/dist/authorization-types.js +1 -0
  21. package/dist/authorization-url.d.ts +5 -0
  22. package/dist/authorization-url.js +34 -0
  23. package/dist/base64.d.ts +3 -0
  24. package/dist/base64.js +21 -0
  25. package/dist/browser/integrity.json +4 -0
  26. package/dist/browser/mdbase-connect.min.js +3 -0
  27. package/dist/browser/mdbase-connect.min.js.sha384 +1 -0
  28. package/dist/browser.d.ts +3 -0
  29. package/dist/browser.js +5 -0
  30. package/dist/capabilities.d.ts +24 -0
  31. package/dist/capabilities.js +91 -0
  32. package/dist/collection-client.d.ts +66 -0
  33. package/dist/collection-client.js +686 -0
  34. package/dist/connect-authorization-helpers.d.ts +4 -0
  35. package/dist/connect-authorization-helpers.js +25 -0
  36. package/dist/connect-options.d.ts +35 -0
  37. package/dist/connect-options.js +1 -0
  38. package/dist/connect.d.ts +66 -0
  39. package/dist/connect.js +711 -0
  40. package/dist/connection-file-transport.d.ts +34 -0
  41. package/dist/connection-file-transport.js +85 -0
  42. package/dist/connection-index.d.ts +3 -0
  43. package/dist/connection-index.js +20 -0
  44. package/dist/connection-notifications.d.ts +31 -0
  45. package/dist/connection-notifications.js +197 -0
  46. package/dist/connection-transport-internals.d.ts +24 -0
  47. package/dist/connection-transport-internals.js +1 -0
  48. package/dist/connection-transport.d.ts +64 -0
  49. package/dist/connection-transport.js +725 -0
  50. package/dist/connection-types.d.ts +38 -0
  51. package/dist/connection-types.js +1 -0
  52. package/dist/connection.d.ts +175 -0
  53. package/dist/connection.js +606 -0
  54. package/dist/crypto-entry.d.ts +7 -0
  55. package/dist/crypto-entry.js +4 -0
  56. package/dist/crypto.d.ts +63 -0
  57. package/dist/crypto.js +409 -0
  58. package/dist/direct-access.d.ts +3 -0
  59. package/dist/direct-access.js +29 -0
  60. package/dist/errors.d.ts +45 -0
  61. package/dist/errors.js +142 -0
  62. package/dist/external-store.d.ts +10 -0
  63. package/dist/external-store.js +10 -0
  64. package/dist/file-crypto.d.ts +25 -0
  65. package/dist/file-crypto.js +132 -0
  66. package/dist/file-sha256.d.ts +12 -0
  67. package/dist/file-sha256.js +143 -0
  68. package/dist/file-stream-source.d.ts +17 -0
  69. package/dist/file-stream-source.js +157 -0
  70. package/dist/file-transfer-internals.d.ts +23 -0
  71. package/dist/file-transfer-internals.js +228 -0
  72. package/dist/files.d.ts +115 -0
  73. package/dist/files.js +563 -0
  74. package/dist/fresh-encrypted-request.d.ts +4 -0
  75. package/dist/fresh-encrypted-request.js +28 -0
  76. package/dist/grant-key-leases.d.ts +24 -0
  77. package/dist/grant-key-leases.js +144 -0
  78. package/dist/hosted-file-request.d.ts +6 -0
  79. package/dist/hosted-file-request.js +63 -0
  80. package/dist/hosted-operation-response.d.ts +5 -0
  81. package/dist/hosted-operation-response.js +26 -0
  82. package/dist/index.d.ts +27 -0
  83. package/dist/index.js +10 -0
  84. package/dist/internal-types.d.ts +100 -0
  85. package/dist/internal-types.js +1 -0
  86. package/dist/local-file-transport.d.ts +37 -0
  87. package/dist/local-file-transport.js +457 -0
  88. package/dist/mdbase-connect.d.ts +28 -0
  89. package/dist/mdbase-connect.js +53 -0
  90. package/dist/notifications.d.ts +48 -0
  91. package/dist/notifications.js +52 -0
  92. package/dist/operation-helpers.d.ts +27 -0
  93. package/dist/operation-helpers.js +144 -0
  94. package/dist/operation-types.d.ts +707 -0
  95. package/dist/operation-types.js +1 -0
  96. package/dist/outcomes.d.ts +51 -0
  97. package/dist/outcomes.js +194 -0
  98. package/dist/pending-mutation-store.d.ts +13 -0
  99. package/dist/pending-mutation-store.js +64 -0
  100. package/dist/pending-recovery-transports.d.ts +5 -0
  101. package/dist/pending-recovery-transports.js +52 -0
  102. package/dist/popup-authorization.d.ts +31 -0
  103. package/dist/popup-authorization.js +100 -0
  104. package/dist/query-pagination.d.ts +6 -0
  105. package/dist/query-pagination.js +119 -0
  106. package/dist/request-budget.d.ts +34 -0
  107. package/dist/request-budget.js +104 -0
  108. package/dist/request-coordinator.d.ts +29 -0
  109. package/dist/request-coordinator.js +213 -0
  110. package/dist/retired-grant-keys.d.ts +9 -0
  111. package/dist/retired-grant-keys.js +56 -0
  112. package/dist/runtime-utils.d.ts +52 -0
  113. package/dist/runtime-utils.js +368 -0
  114. package/dist/saved-view-pagination.d.ts +6 -0
  115. package/dist/saved-view-pagination.js +76 -0
  116. package/dist/selection.d.ts +48 -0
  117. package/dist/selection.js +112 -0
  118. package/dist/session.d.ts +114 -0
  119. package/dist/session.js +569 -0
  120. package/dist/shared-operation.d.ts +7 -0
  121. package/dist/shared-operation.js +41 -0
  122. package/dist/stored-token.d.ts +10 -0
  123. package/dist/stored-token.js +64 -0
  124. package/dist/structured-readiness.d.ts +77 -0
  125. package/dist/structured-readiness.js +126 -0
  126. package/dist/token-response.d.ts +12 -0
  127. package/dist/token-response.js +81 -0
  128. package/dist/transient-retry.d.ts +22 -0
  129. package/dist/transient-retry.js +59 -0
  130. package/dist/watch-policy.d.ts +8 -0
  131. package/dist/watch-policy.js +12 -0
  132. package/package.json +51 -0
@@ -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,7 @@
1
+ export interface MdbaseDeviceAuthorization {
2
+ userCode: string;
3
+ verificationUri: string;
4
+ verificationUriComplete: string;
5
+ expiresAt: number;
6
+ intervalSeconds: number;
7
+ }
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ export declare function randomBase64Url(size: number): string;
2
+ export declare function bytesToBase64Url(bytes: Uint8Array): string;
3
+ export declare function base64UrlBytes(value: string): Uint8Array<ArrayBuffer>;
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
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "file": "mdbase-connect.min.js",
3
+ "integrity": "sha384-qa5e6QDDjQFkjqKf4HstaDjyvJmQnvu4PkubKmMs2QIDou3qqMn+uYWQG2Z0ImA2"
4
+ }