@mdbase-dev/connect 0.1.0-beta.21 → 0.1.0-beta.22

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 (49) hide show
  1. package/README.md +108 -38
  2. package/dist/authorization-url.d.ts +2 -1
  3. package/dist/authorization-url.js +5 -7
  4. package/dist/browser/integrity.json +1 -1
  5. package/dist/browser/mdbase-connect.min.js +3 -3
  6. package/dist/browser/mdbase-connect.min.js.sha384 +1 -1
  7. package/dist/collection-client.d.ts +34 -31
  8. package/dist/collection-client.js +107 -61
  9. package/dist/connect.d.ts +4 -3
  10. package/dist/connect.js +53 -38
  11. package/dist/connection-file-transport.d.ts +31 -0
  12. package/dist/connection-file-transport.js +42 -0
  13. package/dist/connection-notifications.js +21 -21
  14. package/dist/connection-transport.d.ts +2 -0
  15. package/dist/connection-transport.js +95 -37
  16. package/dist/connection-types.d.ts +2 -1
  17. package/dist/connection.d.ts +49 -45
  18. package/dist/connection.js +73 -33
  19. package/dist/crypto.d.ts +5 -6
  20. package/dist/crypto.js +13 -13
  21. package/dist/errors.d.ts +38 -24
  22. package/dist/errors.js +130 -71
  23. package/dist/file-crypto.d.ts +25 -0
  24. package/dist/file-crypto.js +132 -0
  25. package/dist/file-sha256.d.ts +12 -0
  26. package/dist/file-sha256.js +143 -0
  27. package/dist/file-stream-source.d.ts +17 -0
  28. package/dist/file-stream-source.js +157 -0
  29. package/dist/files.d.ts +91 -0
  30. package/dist/files.js +644 -0
  31. package/dist/hosted-file-request.d.ts +6 -0
  32. package/dist/hosted-file-request.js +63 -0
  33. package/dist/index.d.ts +4 -1
  34. package/dist/index.js +3 -0
  35. package/dist/internal-types.d.ts +3 -1
  36. package/dist/local-file-transport.d.ts +30 -0
  37. package/dist/local-file-transport.js +367 -0
  38. package/dist/notifications.js +5 -5
  39. package/dist/operation-helpers.d.ts +2 -2
  40. package/dist/operation-helpers.js +22 -18
  41. package/dist/operation-types.d.ts +3 -4
  42. package/dist/outcomes.d.ts +51 -0
  43. package/dist/outcomes.js +168 -0
  44. package/dist/runtime-utils.d.ts +6 -1
  45. package/dist/runtime-utils.js +90 -11
  46. package/dist/selection.js +3 -3
  47. package/dist/session.d.ts +9 -8
  48. package/dist/session.js +31 -20
  49. package/package.json +2 -2
@@ -1,4 +1,5 @@
1
- import type { CollectionChange, CollectionChangesPage, CollectionDescription, CollectionOperation, CollectionTypeDocument, CreateViewSourceInput, DeleteViewSourceInput, DeleteViewSourceResult, ExecuteViewInput, JsonObject, MdbaseOperationEnvelope, ReadViewSourceInput, RecordDocument, SavedViewExecution, SavedViewList, SavedViewSourceDocument, TypePackInstallResult, TypePackProvision, UpdateViewSourceInput } from "@mdbase-dev/connect-protocol";
1
+ import type { CollectionChange, CollectionChangesPage, CollectionDescription, CollectionOperation, CollectionTypeDocument, CreateViewSourceInput, DeleteViewSourceInput, DeleteViewSourceResult, ExecuteViewInput, JsonObject, ReadViewSourceInput, RecordDocument, SavedViewExecution, SavedViewList, SavedViewSourceDocument, TypePackInstallResult, TypePackProvision, UpdateViewSourceInput } from "@mdbase-dev/connect-protocol";
2
+ import { type CollectionChangesProblemCode, type CollectionDescriptionProblemCode, type CollectionMutationProblemCode, type CollectionQueryProblemCode, type CollectionReadProblemCode, type CollectionTypeProblemCode, type ConnectOutcome } from "./outcomes.js";
2
3
  import type { ChangesInput, CreateInput, CreateTypeInput, DeleteInput, DeletePreflightResult, DeleteResult, MdbaseCollectionTransport, MdbaseDesiredTimer, MdbaseTimer, MdbaseTimerList, MdbaseTimerReconciliation, OperationRequestOptions, QueryInput, QueryPage, QueryPagesOptions, QueryResult, ReadInput, ReadTypeInput, RenameInput, RenamePreflightResult, RenameResult, UpdateInput, UpdateTypeInput, WatchOptions } from "./operation-types.js";
3
4
  /**
4
5
  * Typed collection operations independent of OAuth, HTTP, or storage.
@@ -9,49 +10,51 @@ import type { ChangesInput, CreateInput, CreateTypeInput, DeleteInput, DeletePre
9
10
  export declare class MdbaseCollectionClient<Frontmatter extends JsonObject = JsonObject> {
10
11
  private readonly transport;
11
12
  constructor(transport: MdbaseCollectionTransport);
12
- operation<Result>(operation: CollectionOperation, input: unknown, options?: OperationRequestOptions): Promise<Result>;
13
- describe(): Promise<CollectionDescription>;
14
- changes(input?: ChangesInput, options?: OperationRequestOptions): Promise<CollectionChangesPage>;
15
- read(input: ReadInput): Promise<MdbaseOperationEnvelope<RecordDocument<Frontmatter>>>;
16
- query(input?: QueryInput, options?: OperationRequestOptions): Promise<MdbaseOperationEnvelope<QueryResult<Frontmatter>>>;
17
- queryPages(input?: QueryInput, options?: QueryPagesOptions<Frontmatter>): AsyncGenerator<QueryPage<Frontmatter>>;
18
- queryAll(input?: QueryInput, options?: QueryPagesOptions<Frontmatter>): Promise<QueryResult<Frontmatter>>;
19
- listViews(): Promise<MdbaseOperationEnvelope<SavedViewList>>;
20
- executeView(input: ExecuteViewInput): Promise<MdbaseOperationEnvelope<SavedViewExecution<Frontmatter>>>;
21
- readViewSource(input: ReadViewSourceInput): Promise<MdbaseOperationEnvelope<SavedViewSourceDocument>>;
22
- createViewSource(input: CreateViewSourceInput): Promise<MdbaseOperationEnvelope<SavedViewSourceDocument>>;
23
- updateViewSource(input: UpdateViewSourceInput): Promise<MdbaseOperationEnvelope<SavedViewSourceDocument>>;
24
- deleteViewSource(input: DeleteViewSourceInput): Promise<MdbaseOperationEnvelope<DeleteViewSourceResult>>;
25
- create(input: CreateInput<Frontmatter>): Promise<MdbaseOperationEnvelope<RecordDocument<Frontmatter>>>;
26
- update(input: UpdateInput<Frontmatter>): Promise<MdbaseOperationEnvelope<RecordDocument<Frontmatter>>>;
27
- delete(input: DeleteInput, options?: OperationRequestOptions): Promise<MdbaseOperationEnvelope<DeleteResult>>;
28
- preflightDelete(input: DeleteInput, options?: OperationRequestOptions): Promise<MdbaseOperationEnvelope<DeletePreflightResult>>;
29
- rename(input: RenameInput, options?: OperationRequestOptions): Promise<MdbaseOperationEnvelope<RenameResult>>;
30
- preflightRename(input: RenameInput, options?: OperationRequestOptions): Promise<MdbaseOperationEnvelope<RenamePreflightResult>>;
31
- validate(input?: JsonObject): Promise<MdbaseOperationEnvelope>;
32
- readType(input: ReadTypeInput): Promise<MdbaseOperationEnvelope<CollectionTypeDocument>>;
33
- createType(input: CreateTypeInput): Promise<MdbaseOperationEnvelope<CollectionTypeDocument>>;
34
- updateType(input: UpdateTypeInput): Promise<MdbaseOperationEnvelope<CollectionTypeDocument>>;
35
- installTypePack(input: TypePackProvision): Promise<MdbaseOperationEnvelope<TypePackInstallResult>>;
36
- listTimers(namespace: string): Promise<MdbaseTimerList>;
13
+ operation<Result>(operation: CollectionOperation, input: unknown, options?: OperationRequestOptions): Promise<ConnectOutcome<Result>>;
14
+ describe(): Promise<ConnectOutcome<CollectionDescription, CollectionDescriptionProblemCode>>;
15
+ changes(input?: ChangesInput, options?: OperationRequestOptions): Promise<ConnectOutcome<CollectionChangesPage, CollectionChangesProblemCode>>;
16
+ read(input: ReadInput): Promise<ConnectOutcome<RecordDocument<Frontmatter>, CollectionReadProblemCode>>;
17
+ query(input?: QueryInput, options?: OperationRequestOptions): Promise<ConnectOutcome<QueryResult<Frontmatter>, CollectionQueryProblemCode>>;
18
+ queryPages(input?: QueryInput, options?: QueryPagesOptions<Frontmatter>): AsyncGenerator<ConnectOutcome<QueryPage<Frontmatter>, CollectionQueryProblemCode>>;
19
+ queryAll(input?: QueryInput, options?: QueryPagesOptions<Frontmatter>): Promise<ConnectOutcome<QueryResult<Frontmatter>, CollectionQueryProblemCode>>;
20
+ listViews(): Promise<ConnectOutcome<SavedViewList, CollectionReadProblemCode>>;
21
+ executeView(input: ExecuteViewInput): Promise<ConnectOutcome<SavedViewExecution<Frontmatter>, CollectionReadProblemCode>>;
22
+ readViewSource(input: ReadViewSourceInput): Promise<ConnectOutcome<SavedViewSourceDocument, CollectionReadProblemCode>>;
23
+ createViewSource(input: CreateViewSourceInput): Promise<ConnectOutcome<SavedViewSourceDocument, CollectionMutationProblemCode>>;
24
+ updateViewSource(input: UpdateViewSourceInput): Promise<ConnectOutcome<SavedViewSourceDocument, CollectionMutationProblemCode>>;
25
+ deleteViewSource(input: DeleteViewSourceInput): Promise<ConnectOutcome<DeleteViewSourceResult, CollectionMutationProblemCode>>;
26
+ create(input: CreateInput<Frontmatter>): Promise<ConnectOutcome<RecordDocument<Frontmatter>, CollectionMutationProblemCode>>;
27
+ update(input: UpdateInput<Frontmatter>): Promise<ConnectOutcome<RecordDocument<Frontmatter>, CollectionMutationProblemCode>>;
28
+ delete(input: DeleteInput, options?: OperationRequestOptions): Promise<ConnectOutcome<DeleteResult, CollectionMutationProblemCode>>;
29
+ preflightDelete(input: DeleteInput, options?: OperationRequestOptions): Promise<ConnectOutcome<DeletePreflightResult, CollectionMutationProblemCode>>;
30
+ rename(input: RenameInput, options?: OperationRequestOptions): Promise<ConnectOutcome<RenameResult, CollectionMutationProblemCode>>;
31
+ preflightRename(input: RenameInput, options?: OperationRequestOptions): Promise<ConnectOutcome<RenamePreflightResult, CollectionMutationProblemCode>>;
32
+ validate(input?: JsonObject): Promise<ConnectOutcome<JsonObject, CollectionReadProblemCode>>;
33
+ readType(input: ReadTypeInput): Promise<ConnectOutcome<CollectionTypeDocument, CollectionTypeProblemCode>>;
34
+ createType(input: CreateTypeInput): Promise<ConnectOutcome<CollectionTypeDocument, CollectionTypeProblemCode>>;
35
+ updateType(input: UpdateTypeInput): Promise<ConnectOutcome<CollectionTypeDocument, CollectionTypeProblemCode>>;
36
+ installTypePack(input: TypePackProvision): Promise<ConnectOutcome<TypePackInstallResult, CollectionTypeProblemCode>>;
37
+ listTimers(namespace: string): Promise<ConnectOutcome<MdbaseTimerList, CollectionReadProblemCode>>;
37
38
  putTimer(input: {
38
39
  namespace: string;
39
40
  criterion_id: string;
40
41
  timer: MdbaseDesiredTimer;
41
- }): Promise<MdbaseTimer>;
42
+ }): Promise<ConnectOutcome<MdbaseTimer, CollectionMutationProblemCode>>;
42
43
  cancelTimer(input: {
43
44
  namespace: string;
44
45
  id: string;
45
46
  generation?: number;
46
- }): Promise<{
47
+ }): Promise<ConnectOutcome<{
47
48
  namespace: string;
48
49
  id: string;
49
50
  cancelled: boolean;
50
- }>;
51
+ }, CollectionMutationProblemCode>>;
51
52
  reconcileTimers(input: {
52
53
  namespace: string;
53
54
  criterion_id: string;
54
55
  timers: MdbaseDesiredTimer[];
55
- }): Promise<MdbaseTimerReconciliation>;
56
- watch(options?: WatchOptions): AsyncGenerator<CollectionChange>;
56
+ }): Promise<ConnectOutcome<MdbaseTimerReconciliation, CollectionMutationProblemCode>>;
57
+ watch(options?: WatchOptions): AsyncGenerator<ConnectOutcome<CollectionChange, CollectionChangesProblemCode>>;
58
+ private rawOperation;
59
+ private envelopeOperation;
57
60
  }
@@ -1,5 +1,6 @@
1
1
  import { abortableDelay } from "./async.js";
2
- import { MdbaseConnectError, isRetryableConnectError, unwrapOperation } from "./errors.js";
2
+ import { connectError, connectProblem, operationProblem } from "./errors.js";
3
+ import { COLLECTION_CHANGES_PROBLEM_CODES, COLLECTION_DESCRIPTION_PROBLEM_CODES, COLLECTION_MUTATION_PROBLEM_CODES, COLLECTION_QUERY_PROBLEM_CODES, COLLECTION_READ_PROBLEM_CODES, COLLECTION_TYPE_PROBLEM_CODES, ALL_CONNECT_PROBLEM_CODES, captureConnectOutcome, connectFailure, connectSuccess } from "./outcomes.js";
3
4
  /**
4
5
  * Typed collection operations independent of OAuth, HTTP, or storage.
5
6
  *
@@ -12,19 +13,19 @@ export class MdbaseCollectionClient {
12
13
  this.transport = transport;
13
14
  }
14
15
  operation(operation, input, options) {
15
- return this.transport.operation(operation, input, options);
16
+ return captureConnectOutcome(() => this.transport.operation(operation, input, options), ALL_CONNECT_PROBLEM_CODES);
16
17
  }
17
18
  describe() {
18
- return this.operation("describe", {});
19
+ return this.rawOperation("describe", {}, COLLECTION_DESCRIPTION_PROBLEM_CODES);
19
20
  }
20
21
  changes(input = {}, options) {
21
- return this.operation("changes", input, options);
22
+ return this.rawOperation("changes", input, COLLECTION_CHANGES_PROBLEM_CODES, options);
22
23
  }
23
24
  read(input) {
24
- return this.operation("read", input);
25
+ return this.envelopeOperation("read", input, COLLECTION_READ_PROBLEM_CODES);
25
26
  }
26
27
  query(input = {}, options) {
27
- return this.operation("query", input, options);
28
+ return this.envelopeOperation("query", input, COLLECTION_QUERY_PROBLEM_CODES, options);
28
29
  }
29
30
  async *queryPages(input = {}, options = {}) {
30
31
  const { offset: requestedOffset, limit: requestedLimit, snapshot: requestedSnapshot, ...criteria } = input;
@@ -35,15 +36,21 @@ export class MdbaseCollectionClient {
35
36
  let loaded = 0;
36
37
  let pageNumber = 0;
37
38
  while (!options.signal?.aborted) {
38
- const result = unwrapOperation(await this.query({
39
+ const queried = await this.query({
39
40
  ...criteria,
40
41
  offset,
41
42
  limit: pageNumber === 0 ? firstPageSize : pageSize,
42
43
  ...(snapshot ? { snapshot } : {})
43
- }, { signal: options.signal }));
44
+ }, { signal: options.signal });
45
+ if (!queried.ok) {
46
+ yield queried;
47
+ return;
48
+ }
49
+ const result = queried.value;
44
50
  const returnedSnapshot = result.meta?.snapshot;
45
51
  if (snapshot && returnedSnapshot && snapshot !== returnedSnapshot) {
46
- throw new MdbaseConnectError("query_snapshot_changed", "The collection query snapshot changed while paging. Refresh the query before continuing.", { recovery: "refresh" });
52
+ yield connectFailure(connectProblem("query_snapshot_changed", "The collection query snapshot changed while paging. Refresh the query before continuing."));
53
+ return;
47
54
  }
48
55
  if (!snapshot && returnedSnapshot)
49
56
  snapshot = returnedSnapshot;
@@ -59,7 +66,7 @@ export class MdbaseCollectionClient {
59
66
  ...(snapshot ? { snapshot } : {})
60
67
  };
61
68
  options.onProgress?.(page);
62
- yield page;
69
+ yield connectSuccess(page, queried.diagnostics);
63
70
  if (complete)
64
71
  return;
65
72
  offset += result.results.length;
@@ -69,11 +76,16 @@ export class MdbaseCollectionClient {
69
76
  async queryAll(input = {}, options = {}) {
70
77
  const results = [];
71
78
  let finalPage;
72
- for await (const page of this.queryPages(input, options)) {
79
+ const diagnostics = [];
80
+ for await (const outcome of this.queryPages(input, options)) {
81
+ if (!outcome.ok)
82
+ return outcome;
83
+ const page = outcome.value;
73
84
  results.push(...page.results);
74
85
  finalPage = page;
86
+ diagnostics.push(...outcome.diagnostics);
75
87
  }
76
- return {
88
+ return connectSuccess({
77
89
  results,
78
90
  meta: {
79
91
  ...(finalPage?.meta ?? {}),
@@ -81,70 +93,70 @@ export class MdbaseCollectionClient {
81
93
  has_more: finalPage ? !finalPage.complete : false,
82
94
  ...(finalPage?.snapshot ? { snapshot: finalPage.snapshot } : {})
83
95
  }
84
- };
96
+ }, diagnostics);
85
97
  }
86
98
  listViews() {
87
- return this.operation("list_views", {});
99
+ return this.envelopeOperation("list_views", {}, COLLECTION_READ_PROBLEM_CODES);
88
100
  }
89
101
  executeView(input) {
90
- return this.operation("execute_view", input);
102
+ return this.envelopeOperation("execute_view", input, COLLECTION_READ_PROBLEM_CODES);
91
103
  }
92
104
  readViewSource(input) {
93
- return this.operation("read_view_source", input);
105
+ return this.envelopeOperation("read_view_source", input, COLLECTION_READ_PROBLEM_CODES);
94
106
  }
95
107
  createViewSource(input) {
96
- return this.operation("create_view_source", input);
108
+ return this.envelopeOperation("create_view_source", input, COLLECTION_MUTATION_PROBLEM_CODES);
97
109
  }
98
110
  updateViewSource(input) {
99
- return this.operation("update_view_source", input);
111
+ return this.envelopeOperation("update_view_source", input, COLLECTION_MUTATION_PROBLEM_CODES);
100
112
  }
101
113
  deleteViewSource(input) {
102
- return this.operation("delete_view_source", input);
114
+ return this.envelopeOperation("delete_view_source", input, COLLECTION_MUTATION_PROBLEM_CODES);
103
115
  }
104
116
  create(input) {
105
- return this.operation("create", input);
117
+ return this.envelopeOperation("create", input, COLLECTION_MUTATION_PROBLEM_CODES);
106
118
  }
107
119
  update(input) {
108
- return this.operation("update", input);
120
+ return this.envelopeOperation("update", input, COLLECTION_MUTATION_PROBLEM_CODES);
109
121
  }
110
122
  delete(input, options) {
111
- return this.operation("delete", input, options);
123
+ return this.envelopeOperation("delete", input, COLLECTION_MUTATION_PROBLEM_CODES, options);
112
124
  }
113
125
  preflightDelete(input, options) {
114
- return this.operation("delete", { ...input, check_backlinks: true, dry_run: true }, options);
126
+ return this.envelopeOperation("delete", { ...input, check_backlinks: true, dry_run: true }, COLLECTION_MUTATION_PROBLEM_CODES, options);
115
127
  }
116
128
  rename(input, options) {
117
- return this.operation("rename", input, options);
129
+ return this.envelopeOperation("rename", input, COLLECTION_MUTATION_PROBLEM_CODES, options);
118
130
  }
119
131
  preflightRename(input, options) {
120
- return this.operation("rename", { ...input, dry_run: true }, options);
132
+ return this.envelopeOperation("rename", { ...input, dry_run: true }, COLLECTION_MUTATION_PROBLEM_CODES, options);
121
133
  }
122
134
  validate(input = {}) {
123
- return this.operation("validate", input);
135
+ return this.envelopeOperation("validate", input, COLLECTION_READ_PROBLEM_CODES);
124
136
  }
125
137
  readType(input) {
126
- return this.operation("read_type", input);
138
+ return this.envelopeOperation("read_type", input, COLLECTION_TYPE_PROBLEM_CODES);
127
139
  }
128
140
  createType(input) {
129
- return this.operation("create_type", input);
141
+ return this.envelopeOperation("create_type", input, COLLECTION_TYPE_PROBLEM_CODES);
130
142
  }
131
143
  updateType(input) {
132
- return this.operation("update_type", input);
144
+ return this.envelopeOperation("update_type", input, COLLECTION_TYPE_PROBLEM_CODES);
133
145
  }
134
146
  installTypePack(input) {
135
- return this.operation("install_type_pack", input);
147
+ return this.envelopeOperation("install_type_pack", input, COLLECTION_TYPE_PROBLEM_CODES);
136
148
  }
137
149
  listTimers(namespace) {
138
- return this.operation("list_timers", { namespace });
150
+ return this.rawOperation("list_timers", { namespace }, COLLECTION_READ_PROBLEM_CODES);
139
151
  }
140
152
  putTimer(input) {
141
- return this.operation("put_timer", input);
153
+ return this.rawOperation("put_timer", input, COLLECTION_MUTATION_PROBLEM_CODES);
142
154
  }
143
155
  cancelTimer(input) {
144
- return this.operation("cancel_timer", input);
156
+ return this.rawOperation("cancel_timer", input, COLLECTION_MUTATION_PROBLEM_CODES);
145
157
  }
146
158
  reconcileTimers(input) {
147
- return this.operation("reconcile_timers", input);
159
+ return this.rawOperation("reconcile_timers", input, COLLECTION_MUTATION_PROBLEM_CODES);
148
160
  }
149
161
  async *watch(options = {}) {
150
162
  let cursor = options.cursor;
@@ -154,47 +166,81 @@ export class MdbaseCollectionClient {
154
166
  let connected = false;
155
167
  options.onStatus?.({ state: "connecting", ...(cursor === undefined ? {} : { cursor }) });
156
168
  while (!options.signal?.aborted) {
157
- try {
158
- if (cursor === undefined)
159
- cursor = (await this.changes({}, { signal: options.signal })).cursor;
160
- const page = await this.changes({ after: cursor, limit: 200 }, { signal: options.signal });
161
- if (page.reset) {
162
- const error = new MdbaseConnectError("change_cursor_reset", "The collection change cursor expired. Refresh collection state before subscribing again.");
163
- options.onStatus?.({ state: "reset_required", cursor, error });
164
- throw error;
165
- }
166
- const recovered = failures > 0;
167
- failures = 0;
168
- if (!connected || recovered)
169
- options.onStatus?.({ state: "connected", cursor, recovered });
170
- connected = true;
171
- for (const event of page.events)
172
- yield event;
173
- cursor = page.cursor;
174
- if (!page.has_more)
175
- await abortableDelay(pollInterval, options.signal);
176
- }
177
- catch (error) {
169
+ const changed = await this.changes(cursor === undefined ? {} : { after: cursor, limit: 200 }, { signal: options.signal });
170
+ if (!changed.ok) {
171
+ const problem = changed.problem;
178
172
  if (options.signal?.aborted)
179
173
  return;
180
- if (!retry || !isRetryableConnectError(error))
181
- throw error;
174
+ if (!retry || problem.recovery !== "retry") {
175
+ yield changed;
176
+ return;
177
+ }
182
178
  connected = false;
183
179
  failures += 1;
184
- if (retry.maxAttempts !== undefined && failures > retry.maxAttempts)
185
- throw error;
180
+ if (retry.maxAttempts !== undefined && failures > retry.maxAttempts) {
181
+ yield changed;
182
+ return;
183
+ }
186
184
  const retryInMs = Math.min(retry.maxDelayMs, Math.round(retry.initialDelayMs * retry.multiplier ** (failures - 1)));
187
185
  options.onStatus?.({
188
186
  state: "reconnecting",
189
187
  ...(cursor === undefined ? {} : { cursor }),
190
188
  attempt: failures,
191
189
  retryInMs,
192
- error
190
+ problem
193
191
  });
194
- await abortableDelay(retryInMs, options.signal);
192
+ try {
193
+ await abortableDelay(retryInMs, options.signal);
194
+ }
195
+ catch {
196
+ if (!options.signal?.aborted)
197
+ throw connectError("operation_failed", "Watch retry delay failed unexpectedly.");
198
+ }
199
+ continue;
200
+ }
201
+ const page = changed.value;
202
+ if (cursor === undefined) {
203
+ cursor = page.cursor;
204
+ continue;
205
+ }
206
+ if (page.reset) {
207
+ const problem = connectProblem("change_cursor_reset", "The collection change cursor expired. Refresh collection state before subscribing again.");
208
+ options.onStatus?.({ state: "reset_required", cursor, problem });
209
+ yield connectFailure(problem);
210
+ return;
211
+ }
212
+ const recovered = failures > 0;
213
+ failures = 0;
214
+ if (!connected || recovered)
215
+ options.onStatus?.({ state: "connected", cursor, recovered });
216
+ connected = true;
217
+ for (const event of page.events)
218
+ yield connectSuccess(event);
219
+ cursor = page.cursor;
220
+ if (!page.has_more) {
221
+ try {
222
+ await abortableDelay(pollInterval, options.signal);
223
+ }
224
+ catch {
225
+ if (!options.signal?.aborted)
226
+ throw connectError("operation_failed", "Watch polling delay failed unexpectedly.");
227
+ }
195
228
  }
196
229
  }
197
230
  }
231
+ rawOperation(operation, input, allowedCodes, options) {
232
+ return captureConnectOutcome(() => this.transport.operation(operation, input, options), allowedCodes);
233
+ }
234
+ async envelopeOperation(operation, input, allowedCodes, options) {
235
+ const transported = await captureConnectOutcome(() => this.transport.operation(operation, input, options), allowedCodes);
236
+ if (!transported.ok)
237
+ return transported;
238
+ const envelope = transported.value;
239
+ if (!envelope.valid) {
240
+ return connectFailure(operationProblem(envelope));
241
+ }
242
+ return connectSuccess(envelope.result, envelope.diagnostics);
243
+ }
198
244
  }
199
245
  function watchRetryPolicy(options) {
200
246
  if (options === false)
package/dist/connect.d.ts CHANGED
@@ -3,6 +3,7 @@ import { MdbaseConnection, type MdbaseAuthorizationOutcome, type MdbaseAuthoriza
3
3
  import type { MdbaseConnectionInfo } from "./connection-types.js";
4
4
  import { type GrantKeyStore } from "./crypto.js";
5
5
  import { type Application } from "./internal-types.js";
6
+ import { type AuthorizationProblemCode, type ConnectOutcome, type RegistrationProblemCode } from "./outcomes.js";
6
7
  import { MdbaseSession, type MdbaseSessionOptions, type MdbaseUnavailableReason } from "./session.js";
7
8
  export interface MdbaseConnectOptions {
8
9
  serverUrl: string;
@@ -26,11 +27,11 @@ export interface MdbaseConnectOptions {
26
27
  export declare class MdbaseConnect<Frontmatter extends JsonObject = JsonObject> {
27
28
  private readonly internals;
28
29
  constructor(options: MdbaseConnectOptions);
29
- register(): Promise<Application>;
30
- authorize(options?: MdbaseAuthorizeOptions): Promise<MdbaseAuthorizationOutcome<Frontmatter>>;
30
+ register(): Promise<ConnectOutcome<Application, RegistrationProblemCode>>;
31
+ authorize(options?: MdbaseAuthorizeOptions): Promise<ConnectOutcome<MdbaseAuthorizationOutcome<Frontmatter>, AuthorizationProblemCode>>;
31
32
  createSession(options: MdbaseSessionOptions): MdbaseSession<Frontmatter>;
32
33
  environment(): MdbaseConnectEnvironment;
33
- completeAuthorization(callbackUrl?: string): Promise<MdbaseAuthorizationResult<Frontmatter>>;
34
+ completeAuthorization(callbackUrl?: string): Promise<ConnectOutcome<MdbaseAuthorizationResult<Frontmatter>, AuthorizationProblemCode>>;
34
35
  connections(): MdbaseConnectionInfo[];
35
36
  connection(collectionId: string): MdbaseConnection<Frontmatter> | null;
36
37
  unavailableReason(collectionId: string): MdbaseUnavailableReason | null;