@enbox/browser 0.3.70 → 0.3.72

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 (39) hide show
  1. package/README.md +30 -7
  2. package/dist/browser.mjs +14 -14
  3. package/dist/browser.mjs.map +4 -4
  4. package/dist/esm/blob-url-pool.js +36 -0
  5. package/dist/esm/blob-url-pool.js.map +1 -0
  6. package/dist/esm/browser-connect-handler.js +3 -1
  7. package/dist/esm/browser-connect-handler.js.map +1 -1
  8. package/dist/esm/file-envelope-url-store.js +203 -0
  9. package/dist/esm/file-envelope-url-store.js.map +1 -0
  10. package/dist/esm/index.js +12 -12
  11. package/dist/esm/index.js.map +1 -1
  12. package/dist/esm/object-url-reference.js +68 -0
  13. package/dist/esm/object-url-reference.js.map +1 -0
  14. package/dist/esm/relay-connect-runner.js +9 -1
  15. package/dist/esm/relay-connect-runner.js.map +1 -1
  16. package/dist/esm/ui/connect-modal.js +134 -16
  17. package/dist/esm/ui/connect-modal.js.map +1 -1
  18. package/dist/types/blob-url-pool.d.ts +16 -0
  19. package/dist/types/blob-url-pool.d.ts.map +1 -0
  20. package/dist/types/browser-connect-handler.d.ts +8 -2
  21. package/dist/types/browser-connect-handler.d.ts.map +1 -1
  22. package/dist/types/file-envelope-url-store.d.ts +30 -0
  23. package/dist/types/file-envelope-url-store.d.ts.map +1 -0
  24. package/dist/types/index.d.ts +16 -14
  25. package/dist/types/index.d.ts.map +1 -1
  26. package/dist/types/object-url-reference.d.ts +20 -0
  27. package/dist/types/object-url-reference.d.ts.map +1 -0
  28. package/dist/types/relay-connect-runner.d.ts +4 -0
  29. package/dist/types/relay-connect-runner.d.ts.map +1 -1
  30. package/dist/types/ui/connect-modal.d.ts +24 -11
  31. package/dist/types/ui/connect-modal.d.ts.map +1 -1
  32. package/package.json +7 -7
  33. package/src/blob-url-pool.ts +55 -0
  34. package/src/browser-connect-handler.ts +13 -2
  35. package/src/file-envelope-url-store.ts +260 -0
  36. package/src/index.ts +23 -159
  37. package/src/object-url-reference.ts +82 -0
  38. package/src/relay-connect-runner.ts +17 -2
  39. package/src/ui/connect-modal.ts +187 -28
package/src/index.ts CHANGED
@@ -8,14 +8,17 @@
8
8
  * @example Single-import dapp setup
9
9
  * ```ts
10
10
  * import {
11
- * Enbox, BrowserConnectHandler,
12
- * defineProtocol, recordCodecs,
11
+ * BrowserConnectHandler, createConnectionStore,
12
+ * defineApplicationManifest,
13
13
  * } from '@enbox/browser';
14
+ * import { MyProtocol } from './my-protocol.js';
14
15
  *
15
- * const { enbox, session } = await Enbox.connect({
16
- * connectHandler: BrowserConnectHandler({ appName: 'My App' }),
17
- * protocols: [MyProtocol],
16
+ * const store = createConnectionStore({
17
+ * application : defineApplicationManifest({ protocols: [MyProtocol] }),
18
+ * connectHandler : BrowserConnectHandler({ appName: 'My App' }),
18
19
  * });
20
+ * const snapshot = await store.connect();
21
+ * if (snapshot.phase !== 'connected') throw snapshot.error ?? new Error('Connection failed.');
19
22
  * ```
20
23
  *
21
24
  * For non-browser environments (Node.js, CLI, desktop), import from
@@ -28,150 +31,13 @@
28
31
  //
29
32
  // The high-level Enbox API: DWN records and protocols.
30
33
 
31
- export {
32
- AudienceDecryptError,
33
- createConnectionStore,
34
- ContextNotReadyError,
35
- ContextRetiredError,
36
- defineApplicationManifest,
37
- DwnResponseError,
38
- Enbox,
39
- defineProtocol,
40
- getApplicationProtocolRequests,
41
- ProtocolReadinessError,
42
- RecordConflictError,
43
- RecordParentNotFoundError,
44
- RecordSquashBackstopError,
45
- RecordValidationError,
46
- protocolContextKey,
47
- recordCodecs,
48
- ServiceConfigProtocol,
49
- } from '@enbox/api';
50
-
51
- export type {
52
- ApplicationConnectionStore,
53
- ApplicationConnectionStoreConnectOptions,
54
- ApplicationConnectionStoreOptions,
55
- ApplicationConnectionStoreRefreshOptions,
56
- ApplicationManifest,
57
- ApplicationManifestProtocol,
58
- ApplicationManifestProtocolInput,
59
- AudienceDecryptFailureCause,
60
- ConnectionPhase,
61
- ConnectionSnapshot,
62
- ConnectionSnapshotListener,
63
- ConnectionStore,
64
- ConnectionStoreOptions,
65
- ContextView,
66
- ContextViewListener,
67
- ContextViewState,
68
- ContextMember,
69
- ContextMembersApi,
70
- ContextInvitation,
71
- ContextInvitationPreview,
72
- ContextInvitationsApi,
73
- ContextMaterializedRecord,
74
- ContextRecord,
75
- ContextRecordDeleteParams,
76
- ContextRecordsApi,
77
- ContextRecordUpdateParams,
78
- ContextRoleGroup,
79
- ContextRoleGroups,
80
- ContextRolePath,
81
- ContextsApi,
82
- DataForPath,
83
- DefineApplicationManifestOptions,
84
- DwnEndpointResolution,
85
- EnboxAnonymousOptions,
86
- EnboxConnectOptions,
87
- EnboxConnectResult,
88
- EnboxParams,
89
- EnboxSessionParams,
90
- EncodedRecordData,
91
- EnsureProtocolsReadyOptions,
92
- ExpandableRecordView,
93
- FileEnvelopeCodec,
94
- FileEnvelopeCodecOptions,
95
- FileEnvelopeData,
96
- FollowContextOptions,
97
- JsonRecordCodecOptions,
98
- MaterializedMemberContext,
99
- MaterializedRecord,
100
- MemberContext,
101
- OwnedContext,
102
- ProtocolContext,
103
- ProtocolRolePaths,
104
- SquashProtocolPaths,
105
- RecordCodec,
106
- RecordCodecContext,
107
- RecordCodecValue,
108
- RecordFilter,
109
- RecordPage,
110
- RecordPatch,
111
- RecordPatchInput,
112
- RecordQuery,
113
- RecordSubscription,
114
- RecordSubscriptionEvent,
115
- RecordSubscriptionListener,
116
- RecordView,
117
- RecordViewListener,
118
- RecordViewState,
119
- RecordValidationFailure,
120
- RecordValidator,
121
- ReplicationCurrentness,
122
- RoleDeliveryState,
123
- SyncStatusSnapshot,
124
- TypedMaterializedRecord,
125
- TypedRecord,
126
- } from '@enbox/api';
34
+ export * from '@enbox/api';
127
35
 
128
36
  // ─── Re-exports from @enbox/auth ────────────────────────────────
129
37
  //
130
38
  // Authentication lifecycle, session management, connect handlers.
131
39
 
132
- export {
133
- AuthManager,
134
- AuthSession,
135
- ConnectDeniedError,
136
- SESSION_EXPIRED_ERROR_CODE,
137
- SESSION_REVOKED_ERROR_CODE,
138
- computeConnectionStatus,
139
- isConnectDeniedError,
140
- isSessionExpiredError,
141
- isSessionInvalidError,
142
- normalizeProtocolRequests,
143
- WalletConnect,
144
- } from '@enbox/auth/browser';
145
-
146
- export type {
147
- AuthEvent,
148
- AuthEventHandler,
149
- AuthManagerOptions,
150
- AuthState,
151
- ComputeConnectionStatusOptions,
152
- ConnectionMonitorOptions,
153
- ConnectionState,
154
- ConnectionStatus,
155
- ConnectionStatusGrant,
156
- ConnectHandler,
157
- ConnectOptions,
158
- ConnectResult,
159
- DisconnectOptions,
160
- GetConnectionStatusOptions,
161
- HandlerConnectOptions,
162
- ImportFromPortableOptions,
163
- VaultConnectOptions,
164
- Permission,
165
- PortableIdentity,
166
- ProtocolDefinitionCarrier,
167
- ProtocolPermissionRequest,
168
- ProtocolRequest,
169
- RefreshOptions,
170
- RegistrationOptions,
171
- StorageAdapter,
172
- SyncOption,
173
- WalletConnectOptions,
174
- } from '@enbox/auth/browser';
40
+ export * from '@enbox/auth/browser';
175
41
 
176
42
  // ─── Re-exports from @enbox/connect ─────────────────────────────
177
43
  //
@@ -179,7 +45,7 @@ export type {
179
45
  // transports: opening/sealing envelopes and the deny token.
180
46
 
181
47
  export { CONNECT_DENIED_TOKEN, ConnectProvider } from '@enbox/connect';
182
- export type { ConnectApproval, ConnectPermissionRequest, ConnectRequest, ConnectRequestType } from '@enbox/connect';
48
+ export type { ConnectApproval, ConnectRequest } from '@enbox/connect';
183
49
 
184
50
  // ─── Browser-specific exports ───────────────────────────────────
185
51
  //
@@ -213,6 +79,14 @@ export { MAX_PIN_ATTEMPTS, RelayConnectCancelledError, runRelayConnect } from '.
213
79
  export type { RelayConnectOptions } from './relay-connect-runner.js';
214
80
  export { encodeQr, qrToSvg } from './ui/qr.js';
215
81
  export type { QrCode, QrSvgOptions } from './ui/qr.js';
82
+ export { createBlobUrlPool } from './blob-url-pool.js';
83
+ export type { BlobUrlLease, BlobUrlPool } from './blob-url-pool.js';
84
+ export { createFileEnvelopeUrlStore } from './file-envelope-url-store.js';
85
+ export type {
86
+ FileEnvelopeUrlLease,
87
+ FileEnvelopeUrlStore,
88
+ FileEnvelopeUrlStoreOptions,
89
+ } from './file-envelope-url-store.js';
216
90
 
217
91
  // ─── Convenience re-exports for dapps ───────────────────────────
218
92
  //
@@ -222,14 +96,6 @@ export type { QrCode, QrSvgOptions } from './ui/qr.js';
222
96
  // more specialized is still available by importing the underlying package
223
97
  // directly.
224
98
 
225
- // Canonical typed record (from @enbox/api).
226
- export { Record } from '@enbox/api';
227
-
228
- // Custom storage adapter + DWN registration provider-auth callback shapes
229
- // (from @enbox/auth).
230
- export { BrowserStorage } from '@enbox/auth/browser';
231
- export type { ProviderAuthParams, ProviderAuthResult } from '@enbox/auth/browser';
232
-
233
99
  // Public-profile read/cache layer (from @enbox/protocols): fetch other
234
100
  // users' published profiles (displayName + avatar/hero) from their DWNs
235
101
  // with caching, retries, negative caching, and refcounted subscriptions.
@@ -255,12 +121,9 @@ export type {
255
121
  // DWN interface enum for typing agent requests (from @enbox/agent).
256
122
  export { DwnInterface } from '@enbox/agent';
257
123
 
258
- // Sync-status observability for dapp "remotes" panels (from @enbox/agent).
259
- // Subscribe with `agent.sync.on(event => …)` and snapshot per-remote health
260
- // (healthy / quota-blocked / degraded / offline), including when a
261
- // quota-blocked remote will next be re-probed, via
262
- // `agent.sync.getRemoteSyncStatus()`; resume immediately with
263
- // `agent.sync.retryRemoteNow(tenantDid, remoteEndpoint)`.
124
+ // Low-level sync-status types for advanced agent consumers. Dapps using a
125
+ // ConnectionStore receive current advertised rows through `snapshot.sync.remotes`
126
+ // and can call `store.retryRemote(remoteEndpoint)` without wiring agent events.
264
127
  export type {
265
128
  DeadLetterEntry,
266
129
  RemoteSyncState,
@@ -270,6 +133,7 @@ export type {
270
133
  SyncEvent,
271
134
  SyncEventListener,
272
135
  SyncHealthSummary,
136
+ SyncIdentityStatus,
273
137
  } from '@enbox/agent';
274
138
 
275
139
  // Common DWN primitives for record queries, permission scopes, and protocol
@@ -0,0 +1,82 @@
1
+ export type ObjectUrlLease = Readonly<{
2
+ url: string;
3
+ /** Release immediately, cancelling any deferred release. Idempotent. */
4
+ release(): void;
5
+ /** Release after a grace period. The first deferred release wins. */
6
+ releaseAfter(delayMs: number): void;
7
+ }>;
8
+
9
+ const MAX_TIMER_DELAY_MS = 2_147_483_647;
10
+
11
+ function assertReleaseDelay(delayMs: number): void {
12
+ if (!Number.isSafeInteger(delayMs) || delayMs < 0 || delayMs > MAX_TIMER_DELAY_MS) {
13
+ throw new TypeError(`delayMs must be an integer between 0 and ${MAX_TIMER_DELAY_MS}.`);
14
+ }
15
+ }
16
+
17
+ /** Private reference-counted ownership for one object URL. */
18
+ export class ObjectUrlReference {
19
+ public readonly url: string;
20
+ private _isRevoked = false;
21
+ private _references = 0;
22
+ private readonly _releaseTimers = new Set<ReturnType<typeof setTimeout>>();
23
+
24
+ public constructor(blob: Blob, private readonly _onEmpty: (reference: ObjectUrlReference) => void) {
25
+ this.url = globalThis.URL.createObjectURL(blob);
26
+ }
27
+
28
+ public get references(): number {
29
+ return this._references;
30
+ }
31
+
32
+ public acquire(): ObjectUrlLease {
33
+ if (this._isRevoked) {
34
+ throw new Error('Object URL has been revoked.');
35
+ }
36
+
37
+ this._references += 1;
38
+ let released = false;
39
+ let releaseTimer: ReturnType<typeof setTimeout> | undefined;
40
+ const release = (): void => {
41
+ if (released) {
42
+ return;
43
+ }
44
+ released = true;
45
+ if (releaseTimer !== undefined) {
46
+ clearTimeout(releaseTimer);
47
+ this._releaseTimers.delete(releaseTimer);
48
+ }
49
+ if (this._isRevoked) {
50
+ return;
51
+ }
52
+ this._references -= 1;
53
+ if (this._references === 0) {
54
+ this._onEmpty(this);
55
+ }
56
+ };
57
+ return Object.freeze({
58
+ url : this.url,
59
+ release,
60
+ releaseAfter : (delayMs: number): void => {
61
+ assertReleaseDelay(delayMs);
62
+ if (released || this._isRevoked || releaseTimer !== undefined) {
63
+ return;
64
+ }
65
+ releaseTimer = setTimeout(release, delayMs);
66
+ this._releaseTimers.add(releaseTimer);
67
+ },
68
+ });
69
+ }
70
+
71
+ public revoke(): void {
72
+ if (!this._isRevoked) {
73
+ this._isRevoked = true;
74
+ for (const timer of this._releaseTimers) {
75
+ clearTimeout(timer);
76
+ }
77
+ this._releaseTimers.clear();
78
+ this._references = 0;
79
+ globalThis.URL.revokeObjectURL(this.url);
80
+ }
81
+ }
82
+ }
@@ -66,6 +66,9 @@ export interface RelayConnectOptions {
66
66
  /** Optional icon URL for the app, shown in the wallet consent UI. */
67
67
  appIcon?: string;
68
68
 
69
+ /** Stable application identifier hint available to the wallet during approval. */
70
+ applicationId?: string;
71
+
69
72
  /** Optional client/environment metadata for wallet session display. */
70
73
  clientMetadata?: ConnectClientMetadata;
71
74
 
@@ -78,6 +81,9 @@ export interface RelayConnectOptions {
78
81
  /** User-facing request purpose. Absent means a normal connect. */
79
82
  requestType?: ConnectRequestType;
80
83
 
84
+ /** Wallet profile DID that a refresh must renew. */
85
+ expectedProviderDid?: string;
86
+
81
87
  /** Total milliseconds to poll the relay for a wallet response. */
82
88
  timeoutMs?: number;
83
89
 
@@ -193,10 +199,12 @@ export async function runRelayConnect(options: RelayConnectOptions): Promise<Con
193
199
  clientDid : clientDid.uri,
194
200
  appName : options.appName,
195
201
  appIcon : options.appIcon,
202
+ applicationId : options.applicationId,
196
203
  clientMetadata : options.clientMetadata,
197
204
  permissionRequests : options.permissionRequests,
198
205
  delegateDid : options.delegatePortableDid?.uri,
199
206
  requestType : options.requestType,
207
+ expectedProviderDid : options.expectedProviderDid,
200
208
  supportedDidMethods : ['did:dht', 'did:jwk'],
201
209
  nonce,
202
210
  state,
@@ -243,6 +251,7 @@ export async function runRelayConnect(options: RelayConnectOptions): Promise<Con
243
251
  nonce,
244
252
  state,
245
253
  pin,
254
+ expectedProviderDid : options.expectedProviderDid,
246
255
  delegatePortableDid : options.delegatePortableDid,
247
256
  confirmComplete : transport.confirmComplete?.bind(transport),
248
257
  });
@@ -274,6 +283,7 @@ async function attemptPinOpen(params: {
274
283
  nonce: string;
275
284
  state: string;
276
285
  pin: string;
286
+ expectedProviderDid: string | undefined;
277
287
  delegatePortableDid: PortableDid | undefined;
278
288
  confirmComplete: (() => Promise<void>) | undefined;
279
289
  }): Promise<PinAttemptOutcome> {
@@ -281,8 +291,13 @@ async function attemptPinOpen(params: {
281
291
  const response = await openResponse({
282
292
  jwe : params.responseCiphertext,
283
293
  recipientPrivateKey : params.responsePrivateKey,
284
- expected : { clientDid: params.clientDid, nonce: params.nonce, state: params.state },
285
- pin : params.pin,
294
+ expected : {
295
+ clientDid : params.clientDid,
296
+ nonce : params.nonce,
297
+ state : params.state,
298
+ providerDid : params.expectedProviderDid,
299
+ },
300
+ pin: params.pin,
286
301
  });
287
302
 
288
303
  const delegatePortableDid = resolveDelegatePortableDid({