@mdbase-dev/connect 0.1.0-beta.31 → 0.1.0-beta.32
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 +75 -19
- package/dist/advanced.d.ts +7 -0
- package/dist/advanced.js +4 -0
- package/dist/application-session.d.ts +10 -5
- package/dist/application-session.js +32 -16
- package/dist/async.js +11 -5
- package/dist/authority-proof.d.ts +3 -0
- package/dist/authority-proof.js +24 -0
- 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/browser.d.ts +3 -0
- package/dist/browser.js +5 -0
- package/dist/capabilities.js +2 -1
- package/dist/collection-client.d.ts +28 -28
- package/dist/collection-client.js +42 -42
- package/dist/connect-options.d.ts +12 -4
- package/dist/connect.d.ts +12 -4
- package/dist/connect.js +105 -104
- package/dist/connection-file-transport.d.ts +2 -2
- package/dist/connection-file-transport.js +4 -4
- package/dist/connection-notifications.d.ts +10 -4
- package/dist/connection-notifications.js +41 -23
- package/dist/connection-transport.d.ts +19 -15
- package/dist/connection-transport.js +202 -202
- package/dist/connection-types.d.ts +5 -4
- package/dist/connection.d.ts +43 -43
- package/dist/connection.js +221 -77
- package/dist/crypto-entry.d.ts +4 -0
- package/dist/crypto-entry.js +4 -0
- package/dist/crypto.js +4 -4
- package/dist/external-store.d.ts +10 -0
- package/dist/external-store.js +10 -0
- package/dist/file-transfer-internals.d.ts +22 -0
- package/dist/file-transfer-internals.js +186 -0
- package/dist/files.d.ts +16 -12
- package/dist/files.js +52 -206
- package/dist/hosted-file-request.js +3 -3
- package/dist/index.d.ts +2 -5
- package/dist/index.js +1 -5
- package/dist/internal-types.d.ts +8 -1
- package/dist/local-file-transport.d.ts +2 -2
- package/dist/local-file-transport.js +13 -13
- package/dist/mdbase-connect.d.ts +6 -4
- package/dist/mdbase-connect.js +9 -8
- package/dist/notifications.d.ts +3 -2
- package/dist/operation-helpers.d.ts +3 -3
- package/dist/operation-helpers.js +12 -29
- package/dist/operation-types.d.ts +33 -8
- package/dist/outcomes.d.ts +15 -15
- package/dist/outcomes.js +13 -1
- package/dist/pending-mutation-store.d.ts +13 -0
- package/dist/pending-mutation-store.js +64 -0
- package/dist/request-budget.d.ts +27 -0
- package/dist/request-budget.js +95 -0
- package/dist/runtime-utils.d.ts +2 -0
- package/dist/runtime-utils.js +19 -0
- package/dist/session.d.ts +4 -3
- package/dist/session.js +4 -4
- package/dist/stored-token.d.ts +10 -0
- package/dist/stored-token.js +60 -0
- package/dist/token-response.d.ts +11 -0
- package/dist/token-response.js +77 -0
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -20,11 +20,18 @@ The complete developer guide covers
|
|
|
20
20
|
const mdbase = new MdbaseConnect({
|
|
21
21
|
serverUrl: "https://connect.mdbase.dev",
|
|
22
22
|
manifest: new URL(".well-known/mdbase-app.json", location.href).href,
|
|
23
|
-
redirectUri: "https://workouts.example/auth/mdbase/callback"
|
|
23
|
+
redirectUri: "https://workouts.example/auth/mdbase/callback",
|
|
24
|
+
timeouts: {
|
|
25
|
+
requestMs: 15_000,
|
|
26
|
+
watchStartMs: 20_000,
|
|
27
|
+
uploadMs: 120_000,
|
|
28
|
+
syncMs: 60_000
|
|
29
|
+
}
|
|
24
30
|
});
|
|
25
|
-
const session = mdbase.
|
|
31
|
+
const session = mdbase.application({
|
|
26
32
|
selection: new MdbaseBrowserSelection()
|
|
27
33
|
});
|
|
34
|
+
const unsubscribeSession = session.subscribe(() => render(session.getSnapshot()));
|
|
28
35
|
|
|
29
36
|
const started = await session.start();
|
|
30
37
|
if (!started.ok) {
|
|
@@ -56,12 +63,20 @@ const updated = await connection.update({
|
|
|
56
63
|
});
|
|
57
64
|
if (!updated.ok) renderProblem(updated.problem);
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
const pageLifetime = new AbortController();
|
|
67
|
+
const watch = await connection.watch(
|
|
68
|
+
{ lifetimeSignal: pageLifetime.signal },
|
|
69
|
+
{ timeoutMs: 20_000 }
|
|
70
|
+
);
|
|
71
|
+
if (!watch.ok) {
|
|
72
|
+
renderProblem(watch.problem);
|
|
73
|
+
} else {
|
|
74
|
+
const unsubscribeWatch = watch.value.subscribe(
|
|
75
|
+
(change) => console.log(change.type, change.payload.path),
|
|
76
|
+
renderWatchStatus,
|
|
77
|
+
renderProblem
|
|
78
|
+
);
|
|
79
|
+
// On navigation: unsubscribeWatch(); watch.value.close();
|
|
65
80
|
}
|
|
66
81
|
```
|
|
67
82
|
|
|
@@ -70,6 +85,45 @@ reserved for programming errors and broken SDK invariants. See
|
|
|
70
85
|
[typed outcomes and recovery](../../docs/sdk-outcomes.md) for the complete
|
|
71
86
|
problem model, setup failures, mutation uncertainty, and UI guidance.
|
|
72
87
|
|
|
88
|
+
React applications can use the same session without introducing another state
|
|
89
|
+
owner:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const store = externalStore(session);
|
|
93
|
+
|
|
94
|
+
function useMdbaseSession() {
|
|
95
|
+
return useSyncExternalStore(
|
|
96
|
+
store.subscribe,
|
|
97
|
+
store.getSnapshot,
|
|
98
|
+
store.getSnapshot
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Browser and native callbacks share the same typed completion boundary:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
const browserResult = await session.completeAuthorization(location.href, {
|
|
107
|
+
timeoutMs: 15_000
|
|
108
|
+
});
|
|
109
|
+
const nativeResult = await session.completeAuthorization(deepLinkUrl, {
|
|
110
|
+
signal: appForeground.signal,
|
|
111
|
+
timeoutMs: 15_000
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Unknown writes are recovered through their durable handles, never by calling
|
|
116
|
+
the original mutation again with reconstructed input:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
for (const pending of connection.pendingMutations()) {
|
|
120
|
+
showRecoveryAction(pending.requestId, async () => {
|
|
121
|
+
const recovered = await pending.recover({ timeoutMs: 30_000 });
|
|
122
|
+
if (!recovered.ok) renderProblem(recovered.problem);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
73
127
|
`MdbaseConnect` is the application-level authorization registry.
|
|
74
128
|
`MdbaseApplicationSession` is the normal application boundary: it owns active
|
|
75
129
|
collection selection, authorization completion, semantic capabilities,
|
|
@@ -424,10 +478,11 @@ can show authoritative reference impact before asking for confirmation.
|
|
|
424
478
|
applying, completed, and cancelled phases with an impact estimate. Cancellation
|
|
425
479
|
remains available during an encrypted local/relay mutation because the SDK
|
|
426
480
|
persists its exact encrypted request before dispatch. If waiting is cancelled
|
|
427
|
-
after dispatch, `
|
|
428
|
-
`
|
|
429
|
-
|
|
430
|
-
|
|
481
|
+
after dispatch, `pendingMutations()` exposes durable handles. A handle's
|
|
482
|
+
`recover()` method resends the exact stored request identity and bytes; callers
|
|
483
|
+
never reconstruct or resupply mutation input. Multiple interrupted writes are
|
|
484
|
+
independently recoverable. Other providers are cancellable until apply begins
|
|
485
|
+
and then run to a definitive response.
|
|
431
486
|
Authorization is retained in `localStorage` by default. Access tokens are
|
|
432
487
|
renewed with rotating refresh tokens; passing a custom `Storage` implementation
|
|
433
488
|
allows a host to choose another persistence boundary.
|
|
@@ -441,13 +496,14 @@ and the shell passes that URL to `completeAuthorization()`. PKCE prevents the
|
|
|
441
496
|
callback code from being exchanged without the pending application state and
|
|
442
497
|
verifier.
|
|
443
498
|
|
|
444
|
-
New authorizations require
|
|
445
|
-
independent non-extractable P-256 ECDH agreement
|
|
446
|
-
atomic message counter in IndexedDB. It encrypts
|
|
447
|
-
connector, decrypts connector results locally, and
|
|
448
|
-
requests with the independent signing key. Set
|
|
449
|
-
only for development where end-to-end relay
|
|
450
|
-
unavailable; an encrypted grant never falls back
|
|
499
|
+
New authorizations require operation transport v2 and grant encryption profile
|
|
500
|
+
v1 by default. The SDK keeps independent non-extractable P-256 ECDH agreement
|
|
501
|
+
and ECDSA signing keys plus an atomic message counter in IndexedDB. It encrypts
|
|
502
|
+
operation inputs for the connector, decrypts connector results locally, and
|
|
503
|
+
signs hosted authority requests with the independent signing key. Set
|
|
504
|
+
`relayEncryption: "disabled"` only for development where end-to-end relay
|
|
505
|
+
encryption is intentionally unavailable; an encrypted grant never falls back
|
|
506
|
+
to plaintext.
|
|
451
507
|
|
|
452
508
|
For a hosted collection, the same authorization exchange returns a short-lived,
|
|
453
509
|
grant-bound provider capability. The SDK routes operations directly to the
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Low-level construction and test seams. Ordinary applications use the root package. */
|
|
2
|
+
export { MdbaseCollectionClient } from "./collection-client.js";
|
|
3
|
+
export type { MdbaseCollectionTransport } from "./operation-types.js";
|
|
4
|
+
export { createPkce } from "./runtime-utils.js";
|
|
5
|
+
export type { MdbaseApplicationVerificationStore, MdbaseApplicationSessionConnect } from "./application-session.js";
|
|
6
|
+
export { MdbaseSession } from "./session.js";
|
|
7
|
+
export type { MdbaseSessionConnect, MdbaseSessionOptions } from "./session.js";
|
package/dist/advanced.js
ADDED
|
@@ -4,9 +4,11 @@ import type { MdbaseAuthorizationOutcome, MdbaseAuthorizeOptions, MdbaseConnecti
|
|
|
4
4
|
import type { MdbaseConnectionInfo } from "./connection-types.js";
|
|
5
5
|
import { type ConnectOutcome, type CollectionTypeProblemCode, type AuthorizationProblemCode, type RegistrationProblemCode, type SessionProblemCode } from "./outcomes.js";
|
|
6
6
|
import type { MdbaseApplicationSelection, MdbaseSelectionHistory } from "./selection.js";
|
|
7
|
+
import type { ConnectRequestOptions } from "./operation-types.js";
|
|
8
|
+
import { type ResolvedConnectTimeouts } from "./request-budget.js";
|
|
7
9
|
import { type MdbaseSessionConnect, type MdbaseUnavailableReason } from "./session.js";
|
|
8
10
|
export interface MdbaseApplicationSessionConnect<Frontmatter extends JsonObject = JsonObject> extends MdbaseSessionConnect<Frontmatter> {
|
|
9
|
-
manifest(): Promise<ConnectOutcome<MdbaseAppManifest, RegistrationProblemCode>>;
|
|
11
|
+
manifest(options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseAppManifest, RegistrationProblemCode>>;
|
|
10
12
|
}
|
|
11
13
|
export interface MdbaseApplicationSessionOptions {
|
|
12
14
|
selection: MdbaseApplicationSelection;
|
|
@@ -80,6 +82,7 @@ export type MdbaseApplicationSessionSnapshot = {
|
|
|
80
82
|
export declare class MdbaseApplicationSession<Frontmatter extends JsonObject = JsonObject> {
|
|
81
83
|
private readonly connect;
|
|
82
84
|
private readonly options;
|
|
85
|
+
private readonly timeouts;
|
|
83
86
|
private readonly listeners;
|
|
84
87
|
private readonly verificationStore;
|
|
85
88
|
private snapshot;
|
|
@@ -88,8 +91,9 @@ export declare class MdbaseApplicationSession<Frontmatter extends JsonObject = J
|
|
|
88
91
|
private stopBase?;
|
|
89
92
|
private reviewEntries;
|
|
90
93
|
private verificationGeneration;
|
|
91
|
-
constructor(connect: MdbaseApplicationSessionConnect<Frontmatter>, options: MdbaseApplicationSessionOptions);
|
|
92
|
-
start(): Promise<ConnectOutcome<MdbaseApplicationSessionSnapshot, SessionProblemCode>>;
|
|
94
|
+
constructor(connect: MdbaseApplicationSessionConnect<Frontmatter>, options: MdbaseApplicationSessionOptions, timeouts?: ResolvedConnectTimeouts);
|
|
95
|
+
start(options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseApplicationSessionSnapshot, SessionProblemCode>>;
|
|
96
|
+
private startWithinBudget;
|
|
93
97
|
destroy(): void;
|
|
94
98
|
getSnapshot(): MdbaseApplicationSessionSnapshot;
|
|
95
99
|
subscribe(listener: () => void): () => void;
|
|
@@ -104,12 +108,13 @@ export declare class MdbaseApplicationSession<Frontmatter extends JsonObject = J
|
|
|
104
108
|
authorize(target: "choose" | "selected" | {
|
|
105
109
|
collectionId: string;
|
|
106
110
|
}, options?: Omit<MdbaseAuthorizeOptions, "operations" | "returnTo" | "target">): Promise<ConnectOutcome<MdbaseAuthorizationOutcome<Frontmatter>, SessionProblemCode>>;
|
|
107
|
-
handleAuthorizationCallback(callbackUrl: string): Promise<ConnectOutcome<MdbaseConnection<Frontmatter>, AuthorizationProblemCode>>;
|
|
111
|
+
handleAuthorizationCallback(callbackUrl: string | URL, options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseConnection<Frontmatter>, AuthorizationProblemCode>>;
|
|
112
|
+
completeAuthorization(callbackUrl?: string | URL, options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseConnection<Frontmatter>, AuthorizationProblemCode>>;
|
|
108
113
|
ensureCapabilities(capabilities: ApplicationCapabilityId[]): Promise<ConnectOutcome<MdbaseAuthorizationOutcome<Frontmatter> | {
|
|
109
114
|
kind: "unchanged";
|
|
110
115
|
connection: MdbaseConnection<Frontmatter>;
|
|
111
116
|
}, SessionProblemCode>>;
|
|
112
|
-
applyDefinitionUpdates(): Promise<ConnectOutcome<MdbaseApplicationSessionSnapshot, CollectionTypeProblemCode | "collection_not_ready">>;
|
|
117
|
+
applyDefinitionUpdates(options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseApplicationSessionSnapshot, CollectionTypeProblemCode | "collection_not_ready">>;
|
|
113
118
|
private refresh;
|
|
114
119
|
private verifyDefinitions;
|
|
115
120
|
private context;
|
|
@@ -3,6 +3,8 @@ import { capabilityOperations, operationsForApplicationCapabilities } from "@mdb
|
|
|
3
3
|
import { effectiveCapabilities } from "./capabilities.js";
|
|
4
4
|
import { connectProblem } from "./errors.js";
|
|
5
5
|
import { connectFailure, connectSuccess } from "./outcomes.js";
|
|
6
|
+
import { resolveConnectTimeouts, withRequestBudget } from "./request-budget.js";
|
|
7
|
+
import { defaultCallbackUrl } from "./runtime-utils.js";
|
|
6
8
|
import { MdbaseSession } from "./session.js";
|
|
7
9
|
export class MdbaseMemoryVerificationStore {
|
|
8
10
|
values = new Map();
|
|
@@ -24,6 +26,7 @@ export class MdbaseMemoryVerificationStore {
|
|
|
24
26
|
export class MdbaseApplicationSession {
|
|
25
27
|
connect;
|
|
26
28
|
options;
|
|
29
|
+
timeouts;
|
|
27
30
|
listeners = new Set();
|
|
28
31
|
verificationStore;
|
|
29
32
|
snapshot = { status: "opening", connections: [] };
|
|
@@ -32,13 +35,17 @@ export class MdbaseApplicationSession {
|
|
|
32
35
|
stopBase;
|
|
33
36
|
reviewEntries = [];
|
|
34
37
|
verificationGeneration = 0;
|
|
35
|
-
constructor(connect, options) {
|
|
38
|
+
constructor(connect, options, timeouts = resolveConnectTimeouts()) {
|
|
36
39
|
this.connect = connect;
|
|
37
40
|
this.options = options;
|
|
41
|
+
this.timeouts = timeouts;
|
|
38
42
|
this.verificationStore = options.verificationStore ?? defaultVerificationStore();
|
|
39
43
|
}
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
start(options) {
|
|
45
|
+
return withRequestBudget(options, this.timeouts.watchStartMs, (budget) => this.startWithinBudget({ signal: budget.signal, timeoutMs: null }));
|
|
46
|
+
}
|
|
47
|
+
async startWithinBudget(options) {
|
|
48
|
+
const manifest = await this.connect.manifest(options);
|
|
42
49
|
if (!manifest.ok)
|
|
43
50
|
return manifest;
|
|
44
51
|
const capabilities = manifest.value.requirements?.capabilities;
|
|
@@ -61,10 +68,10 @@ export class MdbaseApplicationSession {
|
|
|
61
68
|
operations: operationsForSession(capabilities)
|
|
62
69
|
});
|
|
63
70
|
this.stopBase = this.base.subscribe(() => this.refresh());
|
|
64
|
-
const started = await this.base.start();
|
|
71
|
+
const started = await this.base.start(options);
|
|
65
72
|
if (!started.ok)
|
|
66
73
|
return started;
|
|
67
|
-
await this.refresh(true);
|
|
74
|
+
await this.refresh(true, options);
|
|
68
75
|
return connectSuccess(this.snapshot);
|
|
69
76
|
}
|
|
70
77
|
destroy() {
|
|
@@ -97,8 +104,11 @@ export class MdbaseApplicationSession {
|
|
|
97
104
|
authorize(target, options = {}) {
|
|
98
105
|
return this.requireBase().authorize(target, options);
|
|
99
106
|
}
|
|
100
|
-
handleAuthorizationCallback(callbackUrl) {
|
|
101
|
-
return this.requireBase().handleAuthorizationCallback(callbackUrl);
|
|
107
|
+
handleAuthorizationCallback(callbackUrl, options) {
|
|
108
|
+
return this.requireBase().handleAuthorizationCallback(String(callbackUrl), options);
|
|
109
|
+
}
|
|
110
|
+
completeAuthorization(callbackUrl, options) {
|
|
111
|
+
return this.requireBase().handleAuthorizationCallback(callbackUrl === undefined ? defaultCallbackUrl() : String(callbackUrl), options);
|
|
102
112
|
}
|
|
103
113
|
ensureCapabilities(capabilities) {
|
|
104
114
|
const manifestRequirements = this.requireManifest().requirements?.capabilities;
|
|
@@ -123,7 +133,7 @@ export class MdbaseApplicationSession {
|
|
|
123
133
|
}
|
|
124
134
|
return this.requireBase().ensureOperations(operationsForIds(capabilities));
|
|
125
135
|
}
|
|
126
|
-
async applyDefinitionUpdates() {
|
|
136
|
+
async applyDefinitionUpdates(options) {
|
|
127
137
|
if (this.snapshot.status !== "definition_review_required" || this.reviewEntries.length === 0) {
|
|
128
138
|
return connectFailure(connectProblem("collection_not_ready", "There are no reviewed definition updates to apply."));
|
|
129
139
|
}
|
|
@@ -135,20 +145,23 @@ export class MdbaseApplicationSession {
|
|
|
135
145
|
return connectFailure(connectProblem("collection_not_ready", "The collection is not ready."));
|
|
136
146
|
}
|
|
137
147
|
for (const { provision, assessment } of this.reviewEntries) {
|
|
138
|
-
const
|
|
148
|
+
const input = {
|
|
139
149
|
provision,
|
|
140
150
|
installed_by: this.requireManifest().id,
|
|
141
151
|
expected_assessment_digest: assessment.assessment_digest,
|
|
142
152
|
...(assessment.status === "downgrade" ? { allow_downgrade: true } : {})
|
|
143
|
-
}
|
|
153
|
+
};
|
|
154
|
+
const applied = options
|
|
155
|
+
? await connection.applyTypePack(input, options)
|
|
156
|
+
: await connection.applyTypePack(input);
|
|
144
157
|
if (!applied.ok)
|
|
145
158
|
return applied;
|
|
146
159
|
}
|
|
147
160
|
this.reviewEntries = [];
|
|
148
|
-
await this.verifyDefinitions(this.context(connection), ++this.verificationGeneration);
|
|
161
|
+
await this.verifyDefinitions(this.context(connection), ++this.verificationGeneration, options);
|
|
149
162
|
return connectSuccess(this.snapshot);
|
|
150
163
|
}
|
|
151
|
-
async refresh(awaitVerification = false) {
|
|
164
|
+
async refresh(awaitVerification = false, options) {
|
|
152
165
|
if (!this.base || !this.manifest)
|
|
153
166
|
return;
|
|
154
167
|
const current = this.base.getSnapshot();
|
|
@@ -184,11 +197,11 @@ export class MdbaseApplicationSession {
|
|
|
184
197
|
else {
|
|
185
198
|
this.publish({ status: "checking_definitions", ...context });
|
|
186
199
|
}
|
|
187
|
-
const verification = this.verifyDefinitions(context, generation);
|
|
200
|
+
const verification = this.verifyDefinitions(context, generation, options);
|
|
188
201
|
if (awaitVerification)
|
|
189
202
|
await verification;
|
|
190
203
|
}
|
|
191
|
-
async verifyDefinitions(context, generation) {
|
|
204
|
+
async verifyDefinitions(context, generation, options) {
|
|
192
205
|
const connection = this.connection();
|
|
193
206
|
const manifest = this.requireManifest();
|
|
194
207
|
if (!connection || connection.collectionId !== context.collectionId)
|
|
@@ -197,10 +210,13 @@ export class MdbaseApplicationSession {
|
|
|
197
210
|
const managesDefinitions = manifest.requirements?.capabilities?.required
|
|
198
211
|
.includes("definitions.type-pack.apply") ?? false;
|
|
199
212
|
for (const provision of managesDefinitions ? manifest.provisions?.type_packs ?? [] : []) {
|
|
200
|
-
const
|
|
213
|
+
const input = {
|
|
201
214
|
provision,
|
|
202
215
|
installed_by: manifest.id
|
|
203
|
-
}
|
|
216
|
+
};
|
|
217
|
+
const outcome = options
|
|
218
|
+
? await connection.assessTypePack(input, options)
|
|
219
|
+
: await connection.assessTypePack(input);
|
|
204
220
|
if (generation !== this.verificationGeneration)
|
|
205
221
|
return;
|
|
206
222
|
if (!outcome.ok) {
|
package/dist/async.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
export function abortableDelay(milliseconds, signal) {
|
|
2
2
|
return new Promise((resolve, reject) => {
|
|
3
3
|
if (signal?.aborted) {
|
|
4
|
-
reject(signal
|
|
4
|
+
reject(signal?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const cleanup = () => signal?.removeEventListener("abort", abort);
|
|
8
|
+
const timeout = setTimeout(() => {
|
|
9
|
+
cleanup();
|
|
10
|
+
resolve();
|
|
11
|
+
}, milliseconds);
|
|
12
|
+
const abort = () => {
|
|
9
13
|
clearTimeout(timeout);
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
cleanup();
|
|
15
|
+
reject(signal?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
16
|
+
};
|
|
17
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
12
18
|
});
|
|
13
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
|
+
}
|