@cef-ai/widget-runtime 2.0.0 → 2.1.1
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 +10 -1
- package/dist/entry.js +30 -3
- package/dist/host-bridge.d.ts +25 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/mount.js +26 -0
- package/dist/vault-client.d.ts +50 -1
- package/dist/vault-client.js +77 -8
- package/dist/widget-runtime.js +52 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -91,7 +91,7 @@ something the widget never sent.
|
|
|
91
91
|
| Message | Direction | Fields |
|
|
92
92
|
| --- | --- | --- |
|
|
93
93
|
| `cef-widget:identity-request` | widget → host | `requestId: string`, `v: number` |
|
|
94
|
-
| `cef-widget:identity-response` | host → widget | `requestId: string`, `v?: number`, `pubkey?: string`, `sigType?: 'ed25519' \| 'sr25519'` (default `ed25519`), `error?: string`, `errorCode?: 'unsupported-version'` |
|
|
94
|
+
| `cef-widget:identity-response` | host → widget | `requestId: string`, `v?: number`, `pubkey?: string`, `sigType?: 'ed25519' \| 'sr25519'` (default `ed25519`), `token?: string` (a bearer delegation the widget uses instead of asking you to sign), `context?: { runId?, recordId?, vaultId? }`, `error?: string`, `errorCode?: 'unsupported-version'` |
|
|
95
95
|
| `cef-widget:sign-request` | widget → host | `requestId: string`, `v: number`, `bytes: number[]` |
|
|
96
96
|
| `cef-widget:sign-response` | host → widget | `requestId: string`, `v?: number`, `signature: number[] \| null` (`null` = user declined), `error?: string`, `errorCode?: 'unsupported-version'` |
|
|
97
97
|
|
|
@@ -105,6 +105,15 @@ Rules:
|
|
|
105
105
|
answers with `errorCode: 'unsupported-version'` — its own reply is still a v1
|
|
106
106
|
message, so `v` itself cannot carry the rejection, and without the code the
|
|
107
107
|
receiver would just see an opaque error string and keep retrying.
|
|
108
|
+
- **Which vault (`context.vaultId`).** By default a widget opens the
|
|
109
|
+
**caller's own** vault (`vault.ensure()`), and a `token` does not change that
|
|
110
|
+
— a delegation says *who*, not *which vault*. A workflow, meanwhile, runs in
|
|
111
|
+
the vault of the org that owns its agent service, so a host showing somebody
|
|
112
|
+
else's run must name that vault or the widget reads a different database and
|
|
113
|
+
reports it as empty. Optional: a host that sends none gets exactly today's
|
|
114
|
+
behaviour. A host that **does** send one and the widget cannot open it gets
|
|
115
|
+
`WidgetVaultUnreachableError` — the runtime refuses rather than falling back,
|
|
116
|
+
because a fallback is indistinguishable from a run that produced nothing.
|
|
108
117
|
- **Sign verbatim.** The host must sign the exact bytes it receives with
|
|
109
118
|
**`ed25519_signRaw`**. Do **not** use the high-level `signMessage` /
|
|
110
119
|
`wallet_signMessage`, which wrap the payload in Substrate's
|
package/dist/entry.js
CHANGED
|
@@ -47,7 +47,23 @@ function boot() {
|
|
|
47
47
|
// Remembered for buildVaultClient, which is synchronous and runs after
|
|
48
48
|
// this. The resolver is memoised, so this is the same identity.
|
|
49
49
|
hostDelegation = id.token;
|
|
50
|
-
|
|
50
|
+
/*
|
|
51
|
+
* THE CONTEXT TRAVELS THE LAST STEP TOO.
|
|
52
|
+
*
|
|
53
|
+
* It was dropped here: the resolver put the host's `context` on the
|
|
54
|
+
* resolved identity, `createWidgetRuntime` reads `id.context` and hands
|
|
55
|
+
* it to `identity()` — and this literal, the only production
|
|
56
|
+
* implementation of `resolveIdentity`, rebuilt the object without it. So
|
|
57
|
+
* the handshake carried the run all the way to the runtime's front door
|
|
58
|
+
* and no widget could ever read it. Spread rather than re-listed, so the
|
|
59
|
+
* next key on the bag does not have to remember to come through here.
|
|
60
|
+
*/
|
|
61
|
+
return {
|
|
62
|
+
source: id.source,
|
|
63
|
+
publicKey: id.publicKey,
|
|
64
|
+
sigType: id.sigType,
|
|
65
|
+
...(id.context ? { context: id.context } : {}),
|
|
66
|
+
};
|
|
51
67
|
},
|
|
52
68
|
buildVaultClient: (m, id) => {
|
|
53
69
|
const sigType = id.sigType ?? 'ed25519';
|
|
@@ -69,7 +85,12 @@ function boot() {
|
|
|
69
85
|
// asked for a passkey forever. `sign` stays wired for hosts that supply
|
|
70
86
|
// no token.
|
|
71
87
|
const makeSdk = () => new VaultSDK(toVaultSdkConfig(m.endpoints, vaultSdkSigner, hostToken));
|
|
72
|
-
|
|
88
|
+
// WHICH VAULT, when the host named one. It rides `context` rather than
|
|
89
|
+
// a field of its own because it is the same kind of fact as the run id —
|
|
90
|
+
// why this widget was opened — and because an optional key on an
|
|
91
|
+
// already-optional bag is the only shape that leaves a host which sends
|
|
92
|
+
// nothing behaving exactly as it does today.
|
|
93
|
+
return createVaultClient(m, makeSdk, hostToken, id.context?.vaultId);
|
|
73
94
|
},
|
|
74
95
|
};
|
|
75
96
|
// Build the mount deps (audio uploader) for config-driven audio kinds.
|
|
@@ -101,7 +122,13 @@ function boot() {
|
|
|
101
122
|
// the same `chainUrl`, since this `ensure({ onboard: false })` runs
|
|
102
123
|
// the vault-delegate grant step too.
|
|
103
124
|
const sdk = new VaultSDK(toVaultSdkConfig(manifest.endpoints, vaultSdkSigner, id.token));
|
|
104
|
-
|
|
125
|
+
// With a token that SDK has no signer, and `ensure()` does not read
|
|
126
|
+
// `auth`: it needs the token handed to it, or it throws before the
|
|
127
|
+
// first chunk. Without one the key stays absent so the signer path runs.
|
|
128
|
+
const ensuredVault = await sdk.vault.ensure({
|
|
129
|
+
onboard: false,
|
|
130
|
+
...(id.token ? { delegationToken: id.token } : {}),
|
|
131
|
+
});
|
|
105
132
|
return createVaultObjectUploader({ objects: ensuredVault.scope(manifest.scope).objects });
|
|
106
133
|
})().catch((err) => { uploaderP = null; throw err; });
|
|
107
134
|
return uploaderP;
|
package/dist/host-bridge.d.ts
CHANGED
|
@@ -33,6 +33,31 @@ export interface WidgetHostContext {
|
|
|
33
33
|
runId?: string;
|
|
34
34
|
/** One record, when the widget was opened from a row rather than a run. */
|
|
35
35
|
recordId?: string;
|
|
36
|
+
/**
|
|
37
|
+
* WHICH VAULT THE RUN HAPPENED IN — and therefore which one to read.
|
|
38
|
+
*
|
|
39
|
+
* A widget authenticates as the viewer and then opened the VIEWER'S OWN
|
|
40
|
+
* vault, because `vault.ensure()` claims the caller's vault and a delegation
|
|
41
|
+
* says WHO, not WHICH. A workflow, meanwhile, runs in the vault of the org
|
|
42
|
+
* that owns its agent SERVICE. Those are the same database only when the
|
|
43
|
+
* viewer happens to own that org — so for a member of somebody else's
|
|
44
|
+
* service the widget read a different database, found nothing, and said so:
|
|
45
|
+
* "No candidate has been reviewed yet" about a run whose own INSERT had
|
|
46
|
+
* reported `rowsAffected: 1`. An empty answer and a wrong-database answer
|
|
47
|
+
* were indistinguishable.
|
|
48
|
+
*
|
|
49
|
+
* OPTIONAL, and that is the compatibility story — the same one `token` and
|
|
50
|
+
* `context` itself have. A host that sends none gets exactly today's
|
|
51
|
+
* `ensure()`, the viewer's own vault, so every already-deployed widget and
|
|
52
|
+
* every host that has not been taught this key is untouched.
|
|
53
|
+
*
|
|
54
|
+
* CONTEXT, NOT A COMMAND still holds, in the only sense it can here: a widget
|
|
55
|
+
* that reads nothing from `context` never notices this key. But the runtime
|
|
56
|
+
* acts on it before any widget code runs, and when it cannot open the named
|
|
57
|
+
* vault it REFUSES — see `WidgetVaultUnreachableError`. Falling back to the
|
|
58
|
+
* viewer's own vault is what produced the confident lie above.
|
|
59
|
+
*/
|
|
60
|
+
vaultId?: string;
|
|
36
61
|
}
|
|
37
62
|
export interface IdentityRequest {
|
|
38
63
|
type: typeof IDENTITY_REQUEST_TYPE;
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { renderSubmit } from './kinds/submit.js';
|
|
|
12
12
|
export { renderConversation } from './kinds/conversation.js';
|
|
13
13
|
export { renderComposite, registerCompositePanel, getCompositePanel, type CompositePanelRenderer } from './kinds/composite.js';
|
|
14
14
|
export * from './render-helpers.js';
|
|
15
|
+
export { WidgetVaultUnreachableError } from './vault-client.js';
|
|
15
16
|
export type { WidgetKind, WidgetConfig, RecordConfig, ListConfig, DashboardConfig, SubmitConfig, ConversationConfig, CustomPanelConfig, CompositePanel, CompositeConfig } from './types.js';
|
|
16
17
|
export { captureAndUploadAudio, createVaultObjectUploader, createVaultObjectStore } from './audio/capture-upload.js';
|
|
17
18
|
export type { CaptureUploadInput, CaptureUploadDeps, VaultObjectUploaderConfig, VaultObjectsLike, VaultStoreConfig, VaultObjectStore } from './audio/capture-upload.js';
|
|
@@ -21,6 +22,7 @@ export { encodeWav } from './audio/wav.js';
|
|
|
21
22
|
export { segmentPcm, decodeToMono16k } from './audio/segment.js';
|
|
22
23
|
export { requestMicStream } from './audio/mic.js';
|
|
23
24
|
export { createHostBridge, type HostBridge } from './host-bridge.js';
|
|
25
|
+
export type { WidgetHostContext } from './host-bridge.js';
|
|
24
26
|
export { IDENTITY_REQUEST_TYPE, IDENTITY_RESPONSE_TYPE, SIGN_REQUEST_TYPE, SIGN_RESPONSE_TYPE, PROTOCOL_VERSION, UNSUPPORTED_VERSION_CODE, MAX_SIGN_BYTES, isByteArray, WidgetProtocolVersionError, WidgetMalformedMessageError, } from './host-bridge.js';
|
|
25
27
|
export type { SigType, IdentityRequest, IdentityResponse, SignRequest, SignResponse, } from './host-bridge.js';
|
|
26
28
|
export { createWidgetHost, type WidgetHostOptions, type WidgetHostIdentity } from './widget-host.js';
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export { renderSubmit } from './kinds/submit.js';
|
|
|
11
11
|
export { renderConversation } from './kinds/conversation.js';
|
|
12
12
|
export { renderComposite, registerCompositePanel, getCompositePanel } from './kinds/composite.js';
|
|
13
13
|
export * from './render-helpers.js';
|
|
14
|
+
export { WidgetVaultUnreachableError } from './vault-client.js';
|
|
14
15
|
export { captureAndUploadAudio, createVaultObjectUploader, createVaultObjectStore } from './audio/capture-upload.js';
|
|
15
16
|
export { mintDelegationToken, Operation } from './audio/ddc-delegation.js';
|
|
16
17
|
export { encodeWav } from './audio/wav.js';
|
package/dist/mount.js
CHANGED
|
@@ -27,6 +27,32 @@ export async function mountKind(root, config, runtime, deps) {
|
|
|
27
27
|
await renderer(root, config, runtime, deps);
|
|
28
28
|
}
|
|
29
29
|
catch (err) {
|
|
30
|
+
/*
|
|
31
|
+
* THE RUN IS SOMEWHERE THIS WIDGET CANNOT LOOK — said here, once, rather
|
|
32
|
+
* than in each widget.
|
|
33
|
+
*
|
|
34
|
+
* This case used to arrive as zero rows, so every widget answered it with
|
|
35
|
+
* its own `empty` copy: "No candidate has been reviewed yet", about a run
|
|
36
|
+
* whose own INSERT had reported `rowsAffected: 1`. No widget can tell an
|
|
37
|
+
* empty result from a wrong-database result, so no widget should have to
|
|
38
|
+
* — the runtime is what knows which vault it could not open, and it is
|
|
39
|
+
* the only layer that can name it.
|
|
40
|
+
*
|
|
41
|
+
* Matched on `name`, like AgentNotConnectedError below, so an error that
|
|
42
|
+
* crossed a bundle boundary still lands here — widget-runtime ships both
|
|
43
|
+
* as this package and as a vendored IIFE.
|
|
44
|
+
*/
|
|
45
|
+
if (err && err.name === 'WidgetVaultUnreachableError') {
|
|
46
|
+
const vaultId = err.vaultId;
|
|
47
|
+
root.innerHTML =
|
|
48
|
+
'<p class="error">This run executed in a vault this widget cannot read'
|
|
49
|
+
+ (vaultId ? ` (<code>${esc(vaultId)}</code>)` : '')
|
|
50
|
+
+ '.</p>'
|
|
51
|
+
+ '<p class="muted">Nothing is shown, on purpose: your own vault is a different '
|
|
52
|
+
+ 'database, and reading that one here would look exactly like a run that produced '
|
|
53
|
+
+ 'nothing. Ask an admin of that organization for access.</p>';
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
30
56
|
if (err && err.name === 'AgentNotConnectedError') {
|
|
31
57
|
root.innerHTML = `<p class="muted">Connect your account to view this.</p><button id="cta">Connect</button>`;
|
|
32
58
|
root.querySelector('#cta').addEventListener('click', async () => {
|
package/dist/vault-client.d.ts
CHANGED
|
@@ -5,8 +5,42 @@ export interface VaultSdkLike {
|
|
|
5
5
|
onboard?: boolean;
|
|
6
6
|
delegationToken?: string;
|
|
7
7
|
}) => Promise<VaultLike>;
|
|
8
|
+
/**
|
|
9
|
+
* SOMEBODY ELSE'S VAULT, by id — what `ensure()` structurally cannot give
|
|
10
|
+
* you. `ensure` claims the CALLER'S OWN vault, and the host's delegation
|
|
11
|
+
* authenticates the caller rather than naming a vault, so with only those
|
|
12
|
+
* two a widget opened on an org's run read the viewer's own database.
|
|
13
|
+
*
|
|
14
|
+
* OPTIONAL on this structural type because a host pinned to an older
|
|
15
|
+
* vault-sdk does not have it — and a widget the host named a vault for must
|
|
16
|
+
* then refuse rather than quietly read the wrong one.
|
|
17
|
+
*/
|
|
18
|
+
byId?: (vaultId: string) => Promise<VaultLike>;
|
|
8
19
|
};
|
|
9
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* The host named a vault this widget cannot open.
|
|
23
|
+
*
|
|
24
|
+
* WHY THIS IS AN ERROR AND NOT AN EMPTY RESULT, which is the whole point of the
|
|
25
|
+
* type. The failure it replaces was silent: the widget opened the wrong vault,
|
|
26
|
+
* queried it successfully, got zero rows, and rendered "No candidate has been
|
|
27
|
+
* reviewed yet" — about a run whose own `_cubbyQueries` log showed the INSERT
|
|
28
|
+
* landing with `rowsAffected: 1`. A confident lie, indistinguishable from the
|
|
29
|
+
* honest empty case, and it cost hours. So when the id is supplied and unusable
|
|
30
|
+
* the runtime says so instead of answering; there is no fallback path, because
|
|
31
|
+
* the fallback IS the bug.
|
|
32
|
+
*
|
|
33
|
+
* Shaped after `WidgetSignedOutError`: a named class whose message names itself
|
|
34
|
+
* first, so it reads the same in a console, in a rejected promise, and in the
|
|
35
|
+
* frame `mountKind` renders it into.
|
|
36
|
+
*/
|
|
37
|
+
export declare class WidgetVaultUnreachableError extends Error {
|
|
38
|
+
/** The vault the host named. Carried so a renderer can name it too. */
|
|
39
|
+
readonly vaultId: string;
|
|
40
|
+
/** What `vault.byId` said, when it said anything. */
|
|
41
|
+
readonly reason: string;
|
|
42
|
+
constructor(vaultId: string, cause?: unknown);
|
|
43
|
+
}
|
|
10
44
|
interface VaultLike {
|
|
11
45
|
id: string;
|
|
12
46
|
agents: {
|
|
@@ -86,5 +120,20 @@ export declare function createVaultClient(manifest: WidgetManifest, makeSdk: ()
|
|
|
86
120
|
* one. The token IS the authorization, which is exactly the case `ensure`
|
|
87
121
|
* documents `delegationToken` for.
|
|
88
122
|
*/
|
|
89
|
-
hostToken?: string
|
|
123
|
+
hostToken?: string,
|
|
124
|
+
/**
|
|
125
|
+
* WHICH VAULT, when the host named one (`WidgetHostContext.vaultId`).
|
|
126
|
+
*
|
|
127
|
+
* WHY IT IS SEPARATE FROM THE TOKEN, which is the mistake this fixes. The
|
|
128
|
+
* host already passed a credential, so the widget authenticated fine and
|
|
129
|
+
* raised no passkey — but a delegation says WHO, not WHICH VAULT, and
|
|
130
|
+
* `ensure()` claims the caller's OWN. A workflow runs in the vault of the org
|
|
131
|
+
* that owns its agent service, so for a member of somebody else's service the
|
|
132
|
+
* two are different databases and the widget read the empty one.
|
|
133
|
+
*
|
|
134
|
+
* ABSENT IS THE DEFAULT AND STAYS EXACTLY AS IT WAS: `ensure({onboard:false})`
|
|
135
|
+
* with the host's delegation. Present means open THAT vault and, if it cannot
|
|
136
|
+
* be opened, refuse — see {@link WidgetVaultUnreachableError}.
|
|
137
|
+
*/
|
|
138
|
+
hostVaultId?: string): VaultClient;
|
|
90
139
|
export {};
|
package/dist/vault-client.js
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
// packages/widget-runtime/src/vault-client.ts
|
|
2
2
|
import {} from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The host named a vault this widget cannot open.
|
|
5
|
+
*
|
|
6
|
+
* WHY THIS IS AN ERROR AND NOT AN EMPTY RESULT, which is the whole point of the
|
|
7
|
+
* type. The failure it replaces was silent: the widget opened the wrong vault,
|
|
8
|
+
* queried it successfully, got zero rows, and rendered "No candidate has been
|
|
9
|
+
* reviewed yet" — about a run whose own `_cubbyQueries` log showed the INSERT
|
|
10
|
+
* landing with `rowsAffected: 1`. A confident lie, indistinguishable from the
|
|
11
|
+
* honest empty case, and it cost hours. So when the id is supplied and unusable
|
|
12
|
+
* the runtime says so instead of answering; there is no fallback path, because
|
|
13
|
+
* the fallback IS the bug.
|
|
14
|
+
*
|
|
15
|
+
* Shaped after `WidgetSignedOutError`: a named class whose message names itself
|
|
16
|
+
* first, so it reads the same in a console, in a rejected promise, and in the
|
|
17
|
+
* frame `mountKind` renders it into.
|
|
18
|
+
*/
|
|
19
|
+
export class WidgetVaultUnreachableError extends Error {
|
|
20
|
+
constructor(vaultId, cause) {
|
|
21
|
+
const reason = cause === undefined
|
|
22
|
+
? 'this build of the runtime has no vault.byId to open it with'
|
|
23
|
+
: (cause instanceof Error ? cause.message : String(cause));
|
|
24
|
+
super(`WidgetVaultUnreachableError: the host opened this widget on vault ${vaultId}, `
|
|
25
|
+
+ `and it cannot be read from here (${reason}). Falling back to your own vault would `
|
|
26
|
+
+ 'answer from a different database — which looks exactly like a run that produced nothing.');
|
|
27
|
+
this.name = 'WidgetVaultUnreachableError';
|
|
28
|
+
this.vaultId = vaultId;
|
|
29
|
+
this.reason = reason;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
3
32
|
/**
|
|
4
33
|
* Normalise the raw result from cubbies.query into a uniform QueryResult.
|
|
5
34
|
* The platform returns `{columns: string[], rows: unknown[][]}` (positional).
|
|
@@ -42,18 +71,58 @@ export function createVaultClient(manifest, makeSdk,
|
|
|
42
71
|
* one. The token IS the authorization, which is exactly the case `ensure`
|
|
43
72
|
* documents `delegationToken` for.
|
|
44
73
|
*/
|
|
45
|
-
hostToken
|
|
74
|
+
hostToken,
|
|
75
|
+
/**
|
|
76
|
+
* WHICH VAULT, when the host named one (`WidgetHostContext.vaultId`).
|
|
77
|
+
*
|
|
78
|
+
* WHY IT IS SEPARATE FROM THE TOKEN, which is the mistake this fixes. The
|
|
79
|
+
* host already passed a credential, so the widget authenticated fine and
|
|
80
|
+
* raised no passkey — but a delegation says WHO, not WHICH VAULT, and
|
|
81
|
+
* `ensure()` claims the caller's OWN. A workflow runs in the vault of the org
|
|
82
|
+
* that owns its agent service, so for a member of somebody else's service the
|
|
83
|
+
* two are different databases and the widget read the empty one.
|
|
84
|
+
*
|
|
85
|
+
* ABSENT IS THE DEFAULT AND STAYS EXACTLY AS IT WAS: `ensure({onboard:false})`
|
|
86
|
+
* with the host's delegation. Present means open THAT vault and, if it cannot
|
|
87
|
+
* be opened, refuse — see {@link WidgetVaultUnreachableError}.
|
|
88
|
+
*/
|
|
89
|
+
hostVaultId) {
|
|
46
90
|
let sdk;
|
|
47
91
|
let vaultP;
|
|
48
92
|
const getSdk = () => (sdk ?? (sdk = makeSdk()));
|
|
93
|
+
/**
|
|
94
|
+
* THE VAULT THIS WIDGET READS — the one the host named, else the caller's.
|
|
95
|
+
*
|
|
96
|
+
* There is deliberately no third branch. A named vault that will not open is
|
|
97
|
+
* an error, never a quiet fall-through to `ensure()`: the fall-through is
|
|
98
|
+
* indistinguishable from an empty result, and being indistinguishable from an
|
|
99
|
+
* empty result is the bug.
|
|
100
|
+
*/
|
|
101
|
+
const openVault = async () => {
|
|
102
|
+
if (!hostVaultId) {
|
|
103
|
+
// `onboard: false` preserves the old lightweight ensure(): claim the vault
|
|
104
|
+
// with a wallet-built delegation token, skipping the gateway onboarding
|
|
105
|
+
// status/bootstrap round-trip (widgets assume a provisioned wallet).
|
|
106
|
+
return getSdk().vault.ensure({
|
|
107
|
+
onboard: false,
|
|
108
|
+
...(hostToken ? { delegationToken: hostToken } : {}),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const vaultNs = getSdk().vault;
|
|
112
|
+
if (typeof vaultNs.byId !== 'function') {
|
|
113
|
+
throw new WidgetVaultUnreachableError(hostVaultId);
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
return await vaultNs.byId(hostVaultId);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
// Not found, no access, network — all one answer to the reader: this is
|
|
120
|
+
// not your vault and nothing here can show you what is in it.
|
|
121
|
+
throw new WidgetVaultUnreachableError(hostVaultId, err);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
49
124
|
const getVault = () => {
|
|
50
|
-
|
|
51
|
-
// with a wallet-built delegation token, skipping the gateway onboarding
|
|
52
|
-
// status/bootstrap round-trip (widgets assume a provisioned wallet).
|
|
53
|
-
vaultP ?? (vaultP = getSdk().vault.ensure({
|
|
54
|
-
onboard: false,
|
|
55
|
-
...(hostToken ? { delegationToken: hostToken } : {}),
|
|
56
|
-
}).catch((err) => {
|
|
125
|
+
vaultP ?? (vaultP = openVault().catch((err) => {
|
|
57
126
|
vaultP = undefined;
|
|
58
127
|
throw err;
|
|
59
128
|
}));
|