@mdbase-dev/connect 0.1.0-beta.31 → 0.1.0-beta.33

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 (68) hide show
  1. package/README.md +112 -34
  2. package/dist/advanced.d.ts +9 -0
  3. package/dist/advanced.js +6 -0
  4. package/dist/application-session.d.ts +39 -14
  5. package/dist/application-session.js +201 -70
  6. package/dist/async.js +11 -5
  7. package/dist/authority-proof.d.ts +3 -0
  8. package/dist/authority-proof.js +24 -0
  9. package/dist/browser/integrity.json +1 -1
  10. package/dist/browser/mdbase-connect.min.js +3 -3
  11. package/dist/browser/mdbase-connect.min.js.sha384 +1 -1
  12. package/dist/browser.d.ts +3 -0
  13. package/dist/browser.js +5 -0
  14. package/dist/capabilities.js +2 -1
  15. package/dist/collection-client.d.ts +36 -33
  16. package/dist/collection-client.js +549 -104
  17. package/dist/connect-authorization-helpers.d.ts +3 -0
  18. package/dist/connect-authorization-helpers.js +13 -0
  19. package/dist/connect-options.d.ts +12 -4
  20. package/dist/connect.d.ts +12 -4
  21. package/dist/connect.js +102 -103
  22. package/dist/connection-file-transport.d.ts +2 -2
  23. package/dist/connection-file-transport.js +4 -4
  24. package/dist/connection-notifications.d.ts +10 -4
  25. package/dist/connection-notifications.js +41 -23
  26. package/dist/connection-transport.d.ts +19 -15
  27. package/dist/connection-transport.js +202 -202
  28. package/dist/connection-types.d.ts +5 -4
  29. package/dist/connection.d.ts +47 -46
  30. package/dist/connection.js +320 -162
  31. package/dist/crypto-entry.d.ts +7 -0
  32. package/dist/crypto-entry.js +4 -0
  33. package/dist/crypto.js +4 -4
  34. package/dist/external-store.d.ts +10 -0
  35. package/dist/external-store.js +10 -0
  36. package/dist/file-transfer-internals.d.ts +23 -0
  37. package/dist/file-transfer-internals.js +224 -0
  38. package/dist/files.d.ts +36 -14
  39. package/dist/files.js +92 -222
  40. package/dist/hosted-file-request.js +3 -3
  41. package/dist/index.d.ts +24 -19
  42. package/dist/index.js +10 -18
  43. package/dist/internal-types.d.ts +9 -1
  44. package/dist/local-file-transport.d.ts +2 -2
  45. package/dist/local-file-transport.js +13 -13
  46. package/dist/mdbase-connect.d.ts +6 -4
  47. package/dist/mdbase-connect.js +9 -8
  48. package/dist/notifications.d.ts +3 -2
  49. package/dist/operation-helpers.d.ts +3 -3
  50. package/dist/operation-helpers.js +17 -34
  51. package/dist/operation-types.d.ts +435 -45
  52. package/dist/outcomes.d.ts +15 -15
  53. package/dist/outcomes.js +13 -1
  54. package/dist/pending-mutation-store.d.ts +13 -0
  55. package/dist/pending-mutation-store.js +64 -0
  56. package/dist/request-budget.d.ts +27 -0
  57. package/dist/request-budget.js +95 -0
  58. package/dist/runtime-utils.d.ts +2 -0
  59. package/dist/runtime-utils.js +19 -0
  60. package/dist/session.d.ts +5 -4
  61. package/dist/session.js +6 -5
  62. package/dist/stored-token.d.ts +10 -0
  63. package/dist/stored-token.js +60 -0
  64. package/dist/token-response.d.ts +11 -0
  65. package/dist/token-response.js +77 -0
  66. package/dist/watch-policy.d.ts +8 -0
  67. package/dist/watch-policy.js +12 -0
  68. package/package.json +12 -2
package/README.md CHANGED
@@ -7,6 +7,13 @@ applications. See the [portable application guide](../../docs/portable-apps.md)
7
7
  for the v1 manifest, device-code flow, version-pinned CDN URL, SRI metadata,
8
8
  and `file://` storage boundary.
9
9
 
10
+ Ordinary applications install only `@mdbase-dev/connect`. Add
11
+ `@mdbase-dev/connect-dev` for declaration/type-pack authoring,
12
+ `@mdbase-dev/connect-testing` for supported test fixtures,
13
+ `@mdbase-dev/connect-sync` for an offline mirror, or the Pickle package only
14
+ when the application uses that feature. Wire and authority implementations use
15
+ `@mdbase-dev/connect-protocol`; ordinary application code does not.
16
+
10
17
  The complete developer guide covers
11
18
  [setup](https://mdbase.dev/sdk/quickstart/),
12
19
  [manifests and contracts](https://mdbase.dev/sdk/manifest/),
@@ -20,13 +27,21 @@ The complete developer guide covers
20
27
  const mdbase = new MdbaseConnect({
21
28
  serverUrl: "https://connect.mdbase.dev",
22
29
  manifest: new URL(".well-known/mdbase-app.json", location.href).href,
23
- redirectUri: "https://workouts.example/auth/mdbase/callback"
30
+ redirectUri: "https://workouts.example/auth/mdbase/callback",
31
+ timeouts: {
32
+ requestMs: 15_000,
33
+ watchStartMs: 20_000,
34
+ uploadMs: 120_000,
35
+ syncMs: 60_000
36
+ }
24
37
  });
25
- const session = mdbase.createApplicationSession({
38
+ const session = mdbase.application({
26
39
  selection: new MdbaseBrowserSelection()
27
40
  });
41
+ const unsubscribeSession = session.subscribe(() => render(session.getSnapshot()));
28
42
 
29
- const started = await session.start();
43
+ const startup = new AbortController();
44
+ const started = await session.start({ signal: startup.signal, timeoutMs: 20_000 });
30
45
  if (!started.ok) {
31
46
  renderProblem(started.problem);
32
47
  return;
@@ -49,19 +64,32 @@ if (!queried.ok) {
49
64
  return;
50
65
  }
51
66
  const workouts = queried.value;
67
+ const current = await connection.read({ path: workouts.results[0].path });
68
+ if (!current.ok) {
69
+ renderProblem(current.problem);
70
+ return;
71
+ }
52
72
  const updated = await connection.update({
53
- path: "workouts/monday.md",
73
+ path: current.value.path,
54
74
  patch: { completed: true },
55
- if_revision: workouts.results[0].revision
75
+ ifRevision: current.value.revision
56
76
  });
57
77
  if (!updated.ok) renderProblem(updated.problem);
58
78
 
59
- for await (const change of connection.watch()) {
60
- if (!change.ok) {
61
- renderProblem(change.problem);
62
- break;
63
- }
64
- console.log(change.value.type, change.value.payload.path);
79
+ const pageLifetime = new AbortController();
80
+ const watch = await connection.watch(
81
+ { lifetimeSignal: pageLifetime.signal },
82
+ { timeoutMs: 20_000 }
83
+ );
84
+ if (!watch.ok) {
85
+ renderProblem(watch.problem);
86
+ } else {
87
+ const unsubscribeWatch = watch.value.subscribe(
88
+ (change) => console.log(change.type, change.payload.path),
89
+ renderWatchStatus,
90
+ renderProblem
91
+ );
92
+ // On navigation: unsubscribeWatch(); watch.value.close();
65
93
  }
66
94
  ```
67
95
 
@@ -70,6 +98,51 @@ reserved for programming errors and broken SDK invariants. See
70
98
  [typed outcomes and recovery](../../docs/sdk-outcomes.md) for the complete
71
99
  problem model, setup failures, mutation uncertainty, and UI guidance.
72
100
 
101
+ SDK call options, operation inputs, results, descriptors, and progress events
102
+ use camelCase. The client translates canonical snake_case protocol payloads at
103
+ the authority boundary. Versioned JSON documents such as `MdbaseAppManifest`
104
+ and `TypePackProvision`, problem detail objects, diagnostics, and user-owned
105
+ frontmatter retain the exact field names defined by their own schemas.
106
+
107
+ React applications can use the same session without introducing another state
108
+ owner:
109
+
110
+ ```ts
111
+ const store = externalStore(session);
112
+
113
+ function useMdbaseSession() {
114
+ return useSyncExternalStore(
115
+ store.subscribe,
116
+ store.getSnapshot,
117
+ store.getSnapshot
118
+ );
119
+ }
120
+ ```
121
+
122
+ Browser and native callbacks share the same typed completion boundary:
123
+
124
+ ```ts
125
+ const browserResult = await session.completeAuthorization(location.href, {
126
+ timeoutMs: 15_000
127
+ });
128
+ const nativeResult = await session.completeAuthorization(deepLinkUrl, {
129
+ signal: appForeground.signal,
130
+ timeoutMs: 15_000
131
+ });
132
+ ```
133
+
134
+ Unknown writes are recovered through their durable handles, never by calling
135
+ the original mutation again with reconstructed input:
136
+
137
+ ```ts
138
+ for (const pending of connection.pendingMutations()) {
139
+ showRecoveryAction(pending.requestId, async () => {
140
+ const recovered = await pending.recover({ timeoutMs: 30_000 });
141
+ if (!recovered.ok) renderProblem(recovered.problem);
142
+ });
143
+ }
144
+ ```
145
+
73
146
  `MdbaseConnect` is the application-level authorization registry.
74
147
  `MdbaseApplicationSession` is the normal application boundary: it owns active
75
148
  collection selection, authorization completion, semantic capabilities,
@@ -78,16 +151,16 @@ versioned capabilities in their manifest; they never maintain a parallel array
78
151
  of protocol operations. Use `getSnapshot()` and `subscribe()` directly or
79
152
  through your framework's external-store integration.
80
153
 
81
- The session distinguishes `authorization_required`, `checking_definitions`,
82
- `definition_review_required`, `ready`, `unavailable`, and `blocked`. Definition
154
+ The session distinguishes `authorization_required`, `checking_setup`,
155
+ `setup_review_required`, `ready`, `unavailable`, and `blocked`. Setup
83
156
  inspection is read-only. If an update is needed, render the supplied plan and
84
157
  apply the exact assessment the user reviewed:
85
158
 
86
159
  ```ts
87
160
  const snapshot = session.getSnapshot();
88
- if (snapshot.status === "definition_review_required") {
89
- renderDefinitionChanges(snapshot.updates);
90
- const applied = await session.applyDefinitionUpdates();
161
+ if (snapshot.status === "setup_review_required") {
162
+ renderCollectionSetup(snapshot.update);
163
+ const applied = await session.applyCollectionSetup({ timeoutMs: 30_000 });
91
164
  if (!applied.ok) renderProblem(applied.problem);
92
165
  }
93
166
  ```
@@ -213,10 +286,10 @@ one-shot reminders at the collection authority:
213
286
  ```ts
214
287
  await connection.reconcileTimers({
215
288
  namespace: "workout-reminders",
216
- criterion_id: "workout.reminder",
289
+ criterionId: "workout.reminder",
217
290
  timers: [{
218
291
  id: "workout-42",
219
- fire_at: new Date("2026-07-25T10:00:00Z").toISOString()
292
+ fireAt: new Date("2026-07-25T10:00:00Z").toISOString()
220
293
  }]
221
294
  });
222
295
  ```
@@ -257,7 +330,7 @@ if (!current.ok) return renderProblem(current.problem);
257
330
  const updatedType = await connection.updateType({
258
331
  path: current.value.path,
259
332
  document: current.value.document.replace("version: 1", "version: 2"),
260
- if_revision: current.value.revision
333
+ ifRevision: current.value.revision
261
334
  });
262
335
  if (!updatedType.ok) renderProblem(updatedType.problem);
263
336
  ```
@@ -275,15 +348,15 @@ const provision = await response.json();
275
348
  const installedBy = "dev.example.catalog";
276
349
  const assessment = await connection.assessTypePack({
277
350
  provision,
278
- installed_by: installedBy
351
+ installedBy
279
352
  });
280
353
  if (!assessment.ok) return renderProblem(assessment.problem);
281
354
 
282
355
  renderDefinitionChanges(assessment.value);
283
356
  const applied = await connection.applyTypePack({
284
357
  provision,
285
- installed_by: installedBy,
286
- expected_assessment_digest: assessment.value.assessment_digest
358
+ installedBy,
359
+ expectedAssessmentDigest: assessment.value.assessmentDigest
287
360
  });
288
361
  if (!applied.ok) return renderProblem(applied.problem);
289
362
  ```
@@ -413,10 +486,13 @@ is not granted collection-wide type-management access.
413
486
 
414
487
  The SDK returns typed outcomes, carries successful mdbase diagnostics alongside
415
488
  the value, carries revision tokens in typed record results, and accepts
416
- `if_revision` on mutations. `describe()` exposes
489
+ `ifRevision` on mutations. `describe()` exposes
417
490
  JSON Schemas, portable type definitions, canonical collection settings, and
418
491
  first-class data contracts. `watch()` resumes from a local collection cursor;
419
492
  the Connect server does not store the change feed.
493
+ `queryAll()` treats `timeoutMs` as one deadline for the complete paginated
494
+ query. The caller-driven `queryPages()` iterator instead accepts
495
+ `pageTimeoutMs`, an independent budget for each page, plus a lifetime `signal`.
420
496
  `preflightRename()` and `preflightDelete()` run the canonical collection
421
497
  operation without changing records or advancing the change cursor, so an app
422
498
  can show authoritative reference impact before asking for confirmation.
@@ -424,10 +500,11 @@ can show authoritative reference impact before asking for confirmation.
424
500
  applying, completed, and cancelled phases with an impact estimate. Cancellation
425
501
  remains available during an encrypted local/relay mutation because the SDK
426
502
  persists its exact encrypted request before dispatch. If waiting is cancelled
427
- after dispatch, `pendingMutation()` reports the interruption and
428
- `resumePendingMutation()` safely recovers the connector's durable receipt using
429
- the exact same input. Other providers are cancellable until apply begins and
430
- then run to a definitive response.
503
+ after dispatch, `pendingMutations()` exposes durable handles. A handle's
504
+ `recover()` method resends the exact stored request identity and bytes; callers
505
+ never reconstruct or resupply mutation input. Multiple interrupted writes are
506
+ independently recoverable. Other providers are cancellable until apply begins
507
+ and then run to a definitive response.
431
508
  Authorization is retained in `localStorage` by default. Access tokens are
432
509
  renewed with rotating refresh tokens; passing a custom `Storage` implementation
433
510
  allows a host to choose another persistence boundary.
@@ -441,13 +518,14 @@ and the shell passes that URL to `completeAuthorization()`. PKCE prevents the
441
518
  callback code from being exchanged without the pending application state and
442
519
  verifier.
443
520
 
444
- New authorizations require encrypted relay protocol 1 by default. The SDK keeps
445
- independent non-extractable P-256 ECDH agreement and ECDSA signing keys plus an
446
- atomic message counter in IndexedDB. It encrypts operation inputs for the
447
- connector, decrypts connector results locally, and signs hosted authority
448
- requests with the independent signing key. Set `relayEncryption: "disabled"`
449
- only for development where end-to-end relay encryption is intentionally
450
- unavailable; an encrypted grant never falls back to plaintext.
521
+ New authorizations require operation transport v2 and grant encryption profile
522
+ v1 by default. The SDK keeps independent non-extractable P-256 ECDH agreement
523
+ and ECDSA signing keys plus an atomic message counter in IndexedDB. It encrypts
524
+ operation inputs for the connector, decrypts connector results locally, and
525
+ signs hosted authority requests with the independent signing key. Set
526
+ `relayEncryption: "disabled"` only for development where end-to-end relay
527
+ encryption is intentionally unavailable; an encrypted grant never falls back
528
+ to plaintext.
451
529
 
452
530
  For a hosted collection, the same authorization exchange returns a short-lived,
453
531
  grant-bound provider capability. The SDK routes operations directly to the
@@ -0,0 +1,9 @@
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 { connectError, connectProblem, operationProblem } from "./errors.js";
6
+ export { connectFailure, connectSuccess } from "./outcomes.js";
7
+ export type { MdbaseApplicationVerificationStore, MdbaseApplicationSessionConnect } from "./application-session.js";
8
+ export { MdbaseSession } from "./session.js";
9
+ export type { MdbaseSessionConnect, MdbaseSessionOptions } from "./session.js";
@@ -0,0 +1,6 @@
1
+ /** Low-level construction and test seams. Ordinary applications use the root package. */
2
+ export { MdbaseCollectionClient } from "./collection-client.js";
3
+ export { createPkce } from "./runtime-utils.js";
4
+ export { connectError, connectProblem, operationProblem } from "./errors.js";
5
+ export { connectFailure, connectSuccess } from "./outcomes.js";
6
+ export { MdbaseSession } from "./session.js";
@@ -1,12 +1,16 @@
1
- import { type ApplicationCapabilityId, type JsonObject, type MdbaseAppManifest, type TypePackAssessment } from "@mdbase-dev/connect-protocol";
1
+ import { type ApplicationCapabilityId, type JsonObject, type MdbaseAppManifest } from "@mdbase-dev/connect-protocol";
2
2
  import { type MdbaseEffectiveCapabilities } from "./capabilities.js";
3
3
  import type { MdbaseAuthorizationOutcome, MdbaseAuthorizeOptions, MdbaseConnection } from "./connection.js";
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 { CollectionSetupAssessment, ConfigurationSetupAssessment, ConnectRequestOptions, TypePackAssessment } from "./operation-types.js";
8
+ import { type ResolvedConnectTimeouts } from "./request-budget.js";
9
+ import type { Application } from "./internal-types.js";
7
10
  import { type MdbaseSessionConnect, type MdbaseUnavailableReason } from "./session.js";
8
11
  export interface MdbaseApplicationSessionConnect<Frontmatter extends JsonObject = JsonObject> extends MdbaseSessionConnect<Frontmatter> {
9
- manifest(): Promise<ConnectOutcome<MdbaseAppManifest, RegistrationProblemCode>>;
12
+ register(options?: ConnectRequestOptions): Promise<ConnectOutcome<Application, RegistrationProblemCode>>;
13
+ manifest(options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseAppManifest, RegistrationProblemCode>>;
10
14
  }
11
15
  export interface MdbaseApplicationSessionOptions {
12
16
  selection: MdbaseApplicationSelection;
@@ -33,7 +37,18 @@ export interface MdbaseDefinitionUpdate {
33
37
  currentVersion?: string;
34
38
  desiredVersion: string;
35
39
  resources: TypePackAssessment["resources"];
36
- contractSetups: TypePackAssessment["contract_setups"];
40
+ contractSetups: TypePackAssessment["contractSetups"];
41
+ canApply: boolean;
42
+ reason: string;
43
+ }
44
+ export interface MdbaseCollectionSetupUpdate {
45
+ status: CollectionSetupAssessment["status"];
46
+ applicable: boolean;
47
+ assessmentDigest: string;
48
+ collectionRevision: string;
49
+ provisionDigest: string;
50
+ configuration: ConfigurationSetupAssessment[];
51
+ typePacks: MdbaseDefinitionUpdate[];
37
52
  canApply: boolean;
38
53
  reason: string;
39
54
  }
@@ -52,10 +67,10 @@ export type MdbaseApplicationSessionSnapshot = {
52
67
  } | ({
53
68
  status: "authorization_required";
54
69
  } & ApplicationSessionContext) | ({
55
- status: "checking_definitions";
70
+ status: "checking_setup";
56
71
  } & ApplicationSessionContext) | ({
57
- status: "definition_review_required";
58
- updates: MdbaseDefinitionUpdate[];
72
+ status: "setup_review_required";
73
+ update: MdbaseCollectionSetupUpdate;
59
74
  } & ApplicationSessionContext) | ({
60
75
  status: "ready";
61
76
  verification: "cached" | "verified";
@@ -75,22 +90,29 @@ export type MdbaseApplicationSessionSnapshot = {
75
90
  /**
76
91
  * The application-level lifecycle boundary. It derives authorization from the
77
92
  * bundled manifest, exposes semantic capabilities, and never mutates collection
78
- * definitions without an explicit `applyDefinitionUpdates` call.
93
+ * setup without an explicit `applyCollectionSetup` call.
79
94
  */
80
95
  export declare class MdbaseApplicationSession<Frontmatter extends JsonObject = JsonObject> {
81
96
  private readonly connect;
82
97
  private readonly options;
98
+ private readonly timeouts;
83
99
  private readonly listeners;
84
100
  private readonly verificationStore;
85
101
  private snapshot;
86
102
  private manifest;
103
+ private application;
87
104
  private base;
88
105
  private stopBase?;
89
- private reviewEntries;
106
+ private setupAssessment;
90
107
  private verificationGeneration;
91
- constructor(connect: MdbaseApplicationSessionConnect<Frontmatter>, options: MdbaseApplicationSessionOptions);
92
- start(): Promise<ConnectOutcome<MdbaseApplicationSessionSnapshot, SessionProblemCode>>;
108
+ private lifecycleGeneration;
109
+ private startOperation;
110
+ constructor(connect: MdbaseApplicationSessionConnect<Frontmatter>, options: MdbaseApplicationSessionOptions, timeouts?: ResolvedConnectTimeouts);
111
+ start(options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseApplicationSessionSnapshot, SessionProblemCode>>;
112
+ private beginStart;
113
+ private startWithinBudget;
93
114
  destroy(): void;
115
+ private cleanupBase;
94
116
  getSnapshot(): MdbaseApplicationSessionSnapshot;
95
117
  subscribe(listener: () => void): () => void;
96
118
  connection(): MdbaseConnection<Frontmatter> | null;
@@ -104,17 +126,20 @@ export declare class MdbaseApplicationSession<Frontmatter extends JsonObject = J
104
126
  authorize(target: "choose" | "selected" | {
105
127
  collectionId: string;
106
128
  }, options?: Omit<MdbaseAuthorizeOptions, "operations" | "returnTo" | "target">): Promise<ConnectOutcome<MdbaseAuthorizationOutcome<Frontmatter>, SessionProblemCode>>;
107
- handleAuthorizationCallback(callbackUrl: string): Promise<ConnectOutcome<MdbaseConnection<Frontmatter>, AuthorizationProblemCode>>;
108
- ensureCapabilities(capabilities: ApplicationCapabilityId[]): Promise<ConnectOutcome<MdbaseAuthorizationOutcome<Frontmatter> | {
129
+ handleAuthorizationCallback(callbackUrl: string | URL, options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseConnection<Frontmatter>, AuthorizationProblemCode>>;
130
+ completeAuthorization(callbackUrl?: string | URL, options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseConnection<Frontmatter>, AuthorizationProblemCode>>;
131
+ ensureCapabilities(capabilities: ApplicationCapabilityId[], options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseAuthorizationOutcome<Frontmatter> | {
109
132
  kind: "unchanged";
110
133
  connection: MdbaseConnection<Frontmatter>;
111
134
  }, SessionProblemCode>>;
112
- applyDefinitionUpdates(): Promise<ConnectOutcome<MdbaseApplicationSessionSnapshot, CollectionTypeProblemCode | "collection_not_ready">>;
135
+ applyCollectionSetup(options?: ConnectRequestOptions): Promise<ConnectOutcome<MdbaseApplicationSessionSnapshot, CollectionTypeProblemCode | "collection_not_ready">>;
113
136
  private refresh;
114
- private verifyDefinitions;
137
+ private verifySetup;
138
+ private collectionSetupInput;
115
139
  private context;
116
140
  private publish;
117
141
  private requireBase;
118
142
  private requireManifest;
143
+ private requireApplication;
119
144
  }
120
145
  export {};