@mdbase-dev/connect 0.1.0-beta.123 → 0.1.0-beta.125
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 +77 -2
- package/dist/application-session.js +9 -3
- package/dist/authority-features.d.ts +29 -0
- package/dist/authority-features.js +84 -0
- package/dist/browser/integrity.json +1 -1
- package/dist/browser/mdbase-connect.min.js +4 -4
- package/dist/browser/mdbase-connect.min.js.sha384 +1 -1
- package/dist/change-events.js +2 -9
- package/dist/collection-client.d.ts +7 -2
- package/dist/collection-client.js +76 -97
- package/dist/connection.d.ts +8 -1
- package/dist/connection.js +55 -116
- package/dist/description-cache.js +1 -28
- package/dist/file-descriptor.d.ts +2 -0
- package/dist/file-descriptor.js +17 -0
- package/dist/file-metadata.d.ts +21 -0
- package/dist/file-metadata.js +112 -0
- package/dist/files.d.ts +7 -8
- package/dist/files.js +13 -45
- package/dist/index.d.ts +2 -2
- package/dist/local-file-transport.js +18 -16
- package/dist/operation-types.d.ts +44 -16
- package/dist/query-pagination.d.ts +7 -3
- package/dist/query-pagination.js +3 -1
- package/dist/query-wire.d.ts +61 -0
- package/dist/query-wire.js +110 -0
- package/dist/read-many.d.ts +4 -3
- package/dist/read-many.js +160 -55
- package/dist/watch-policy.d.ts +22 -1
- package/dist/watch-policy.js +104 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
sha384-
|
|
1
|
+
sha384-JJDoYra3MuCFJxyktOaw/6TQwPZCx8ZC2YcJhJxOZqXF8xU67X+tyXiEm5KKZwcf
|
package/dist/change-events.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CHANGE_EVENT_KINDS } from "@mdbase-dev/connect-protocol";
|
|
2
|
-
import { clientFileDescriptor } from "./file-descriptor.js";
|
|
2
|
+
import { clientFileDescriptor, validFileDescriptor } from "./file-descriptor.js";
|
|
3
3
|
const RECORD_FIELDS = Object.entries({
|
|
4
4
|
path: string, from: string, to: string, revision: string, previous_revision: string,
|
|
5
5
|
types: strings, previous_types: strings, changed_fields: strings, body_changed: boolean,
|
|
@@ -43,7 +43,7 @@ export function normalizeCollectionChange(raw) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
if (kind === "file.put") {
|
|
46
|
-
return
|
|
46
|
+
return validFileDescriptor(p.file)
|
|
47
47
|
? { ...base, kind, file: clientFileDescriptor(p.file) }
|
|
48
48
|
: unknown("invalid_payload");
|
|
49
49
|
}
|
|
@@ -93,10 +93,3 @@ function object(value) { return value !== null && typeof value === "object" && !
|
|
|
93
93
|
function validFields(value, fields) {
|
|
94
94
|
return fields.every(([key, valid]) => value[key] == null || valid(value[key]));
|
|
95
95
|
}
|
|
96
|
-
function clientFileDescriptorIsValid(value) {
|
|
97
|
-
return object(value) && string(value.file_id) && string(value.path) && string(value.revision)
|
|
98
|
-
&& string(value.content_digest) && value.content_digest.startsWith("sha256:")
|
|
99
|
-
&& typeof value.size === "number" && Number.isSafeInteger(value.size) && value.size >= 0
|
|
100
|
-
&& ["image", "audio", "video", "pdf", "other"].includes(value.media_class)
|
|
101
|
-
&& string(value.modified_at) && (value.media_type == null || string(value.media_type));
|
|
102
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CollectionOperation, CollectionTypeDocument, JsonObject } from "@mdbase-dev/connect-protocol";
|
|
2
2
|
import { type CollectionChangesProblemCode, type CollectionDescriptionProblemCode, type CollectionMutationProblemCode, type CollectionQueryProblemCode, type CollectionReadProblemCode, type CollectionTypeProblemCode, type ConnectOutcome } from "./outcomes.js";
|
|
3
|
-
import type { ChangesInput, DescribeOptions, CollectionChange, CollectionChangesPage, CollectionDescription, CollectionSetupApplyResult, CollectionSetupAssessment, AssessCollectionSetupInput, AssessTypePackInput, ApplyCollectionSetupInput, ApplyTypePackInput, CreateInput, CreateTypeInput, CreateViewSourceInput, DeleteInput, DeletePreflightResult, DeleteResult, DeleteViewSourceInput, DeleteViewSourceResult, ExecuteViewInput, MdbaseCollectionTransport, MdbaseDesiredTimer, MdbaseTimer, MdbaseTimerList, MdbaseTimerReconciliation, ConnectRequestOptions, QueryAllOptions, QueryInput, QueryPage, QueryPagesOptions, QueryResult, ReadInput, ReadManyOptions, ReadManyResult, ReadTypeInput, ReadViewSourceInput, RenameInput, RenamePreflightResult, RenameResult, RecordDocument, SavedViewExecution, SavedViewPage, SavedViewPagesOptions, SavedViewList, SavedViewSourceDocument, TypePackApplyResult, TypePackAssessment, UpdateInput, UpdateTypeInput, UpdateViewSourceInput, WatchOptions } from "./operation-types.js";
|
|
3
|
+
import type { ChangesInput, DescribeOptions, CollectionChange, CollectionChangesPage, CollectionDescription, CollectionSetupApplyResult, CollectionSetupAssessment, AssessCollectionSetupInput, AssessTypePackInput, ApplyCollectionSetupInput, ApplyTypePackInput, CreateInput, CreateTypeInput, CreateViewSourceInput, DeleteInput, DeletePreflightResult, DeleteResult, DeleteViewSourceInput, DeleteViewSourceResult, ExecuteViewInput, MdbaseCollectionTransport, MdbaseDesiredTimer, MdbaseTimer, MdbaseTimerList, MdbaseTimerReconciliation, ConnectRequestOptions, QueryAllOptions, QueryInput, QueryMetadataInput, QueryMetadataRecord, QueryMetadataResult, QueryMetadataPage, QueryPage, QueryPagesOptions, QueryResult, ReadInput, ReadManyOptions, ReadManyResult, ReadTypeInput, ReadViewSourceInput, RenameInput, RenamePreflightResult, RenameResult, RecordDocument, SavedViewExecution, SavedViewPage, SavedViewPagesOptions, SavedViewList, SavedViewSourceDocument, TypePackApplyResult, TypePackAssessment, UpdateInput, UpdateTypeInput, UpdateViewSourceInput, WatchOptions } from "./operation-types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Typed collection operations independent of OAuth, HTTP, or storage.
|
|
6
6
|
*
|
|
@@ -10,18 +10,23 @@ import type { ChangesInput, DescribeOptions, CollectionChange, CollectionChanges
|
|
|
10
10
|
export declare class MdbaseCollectionClient<Frontmatter extends JsonObject = JsonObject> {
|
|
11
11
|
private readonly transport;
|
|
12
12
|
private readonly requestTimeoutMs;
|
|
13
|
+
private readonly supportsAuthorityFeature?;
|
|
13
14
|
private readonly descriptions;
|
|
14
15
|
private lastSchemaCursor;
|
|
15
16
|
/** Local cache generation, not an authority revision or cross-connection identity. */
|
|
16
17
|
get schemaGeneration(): number;
|
|
17
|
-
constructor(transport: MdbaseCollectionTransport, requestTimeoutMs?: number | null);
|
|
18
|
+
constructor(transport: MdbaseCollectionTransport, requestTimeoutMs?: number | null, supportsAuthorityFeature?: ((id: string, options?: ConnectRequestOptions) => Promise<ConnectOutcome<boolean>>) | undefined);
|
|
18
19
|
operation<Result>(operation: CollectionOperation, input: unknown, options?: ConnectRequestOptions): Promise<ConnectOutcome<Result>>;
|
|
19
20
|
describe(options?: DescribeOptions): Promise<ConnectOutcome<CollectionDescription, CollectionDescriptionProblemCode>>;
|
|
20
21
|
changes(input?: ChangesInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<CollectionChangesPage, CollectionChangesProblemCode>>;
|
|
21
22
|
read(input: ReadInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<RecordDocument<Frontmatter>, CollectionReadProblemCode>>;
|
|
22
23
|
readMany(paths: readonly string[], options?: ReadManyOptions): Promise<ConnectOutcome<ReadManyResult<Frontmatter>, CollectionQueryProblemCode>>;
|
|
24
|
+
query(input: QueryMetadataInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<QueryMetadataResult, CollectionQueryProblemCode>>;
|
|
23
25
|
query(input?: QueryInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<QueryResult<Frontmatter>, CollectionQueryProblemCode>>;
|
|
26
|
+
query(input: QueryInput | QueryMetadataInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<QueryResult<Frontmatter> | QueryMetadataResult, CollectionQueryProblemCode>>;
|
|
27
|
+
queryPages(input: QueryMetadataInput, options?: QueryPagesOptions<JsonObject, QueryMetadataRecord>): AsyncGenerator<ConnectOutcome<QueryMetadataPage, CollectionQueryProblemCode>>;
|
|
24
28
|
queryPages(input?: QueryInput, options?: QueryPagesOptions<Frontmatter>): AsyncGenerator<ConnectOutcome<QueryPage<Frontmatter>, CollectionQueryProblemCode>>;
|
|
29
|
+
queryAll(input: QueryMetadataInput, options?: QueryAllOptions<JsonObject, QueryMetadataRecord>): Promise<ConnectOutcome<QueryMetadataResult, CollectionQueryProblemCode>>;
|
|
25
30
|
queryAll(input?: QueryInput, options?: QueryAllOptions<Frontmatter>): Promise<ConnectOutcome<QueryResult<Frontmatter>, CollectionQueryProblemCode>>;
|
|
26
31
|
listViews(options?: ConnectRequestOptions): Promise<ConnectOutcome<SavedViewList, CollectionReadProblemCode>>;
|
|
27
32
|
executeView(input: ExecuteViewInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<SavedViewExecution<Frontmatter>, CollectionReadProblemCode>>;
|
|
@@ -2,11 +2,12 @@ import { abortableDelay } from "./async.js";
|
|
|
2
2
|
import { invalidatesDescription, normalizeChangesPage } from "./change-events.js";
|
|
3
3
|
import { CollectionDescriptionCache } from "./description-cache.js";
|
|
4
4
|
import { coordinatedQueryPages } from "./query-pagination.js";
|
|
5
|
-
import {
|
|
5
|
+
import { readMany as readManyRecords } from "./read-many.js";
|
|
6
|
+
import { wireDataContractIdentity, wireQueryInput, wireQueryRecord, wireQueryResult } from "./query-wire.js";
|
|
6
7
|
import { coordinatedSavedViewPages } from "./saved-view-pagination.js";
|
|
7
8
|
import { MdbaseConnectError, connectError, connectProblem, operationProblem } from "./errors.js";
|
|
8
9
|
import { COLLECTION_CHANGES_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";
|
|
9
|
-
import { createRequestBudget, DEFAULT_REQUEST_TIMEOUT_MS, requestAbortReason } from "./request-budget.js";
|
|
10
|
+
import { createRequestBudget, DEFAULT_REQUEST_TIMEOUT_MS, requestAbortReason, requestOptionsWithinBudget, withRequestBudget } from "./request-budget.js";
|
|
10
11
|
import { watchRetryPolicy } from "./watch-policy.js";
|
|
11
12
|
/**
|
|
12
13
|
* Typed collection operations independent of OAuth, HTTP, or storage.
|
|
@@ -17,13 +18,15 @@ import { watchRetryPolicy } from "./watch-policy.js";
|
|
|
17
18
|
export class MdbaseCollectionClient {
|
|
18
19
|
transport;
|
|
19
20
|
requestTimeoutMs;
|
|
21
|
+
supportsAuthorityFeature;
|
|
20
22
|
descriptions;
|
|
21
23
|
lastSchemaCursor = -1;
|
|
22
24
|
/** Local cache generation, not an authority revision or cross-connection identity. */
|
|
23
25
|
get schemaGeneration() { return this.descriptions.schemaGeneration; }
|
|
24
|
-
constructor(transport, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
26
|
+
constructor(transport, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, supportsAuthorityFeature) {
|
|
25
27
|
this.transport = transport;
|
|
26
28
|
this.requestTimeoutMs = requestTimeoutMs;
|
|
29
|
+
this.supportsAuthorityFeature = supportsAuthorityFeature;
|
|
27
30
|
this.descriptions = new CollectionDescriptionCache(transport, requestTimeoutMs);
|
|
28
31
|
}
|
|
29
32
|
operation(operation, input, options) {
|
|
@@ -49,27 +52,35 @@ export class MdbaseCollectionClient {
|
|
|
49
52
|
return mapOutcome(outcome, wireRecordDocument);
|
|
50
53
|
}
|
|
51
54
|
readMany(paths, options = {}) {
|
|
52
|
-
return
|
|
55
|
+
return readManyRecords((input, requestOptions) => this.queryAll(input, requestOptions), (selected, includeBody, requestOptions) => this.envelopeOperation("read", { paths: selected, include_body: includeBody, include_document: false }, COLLECTION_READ_PROBLEM_CODES, requestOptions), this.supportsAuthorityFeature, paths, options, this.requestTimeoutMs);
|
|
53
56
|
}
|
|
54
57
|
async query(input = {}, options) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
if (input.output !== undefined && input.output !== "metadata") {
|
|
59
|
+
return connectFailure(connectProblem("invalid_request", "Unknown query output mode."));
|
|
60
|
+
}
|
|
61
|
+
if (input.output !== "metadata") {
|
|
62
|
+
const outcome = await this.envelopeOperation("query", wireQueryInput(input), COLLECTION_QUERY_PROBLEM_CODES, options);
|
|
63
|
+
return mapOutcome(outcome, value => wireQueryResult(value, undefined));
|
|
64
|
+
}
|
|
65
|
+
const captured = await captureConnectOutcome(() => withRequestBudget(options, this.requestTimeoutMs, async (budget) => {
|
|
66
|
+
const requestOptions = requestOptionsWithinBudget({ ...options, timeoutMs: null }, budget);
|
|
67
|
+
if (input.includeBody)
|
|
68
|
+
throw connectError("invalid_request", "Metadata queries cannot include a body.");
|
|
69
|
+
const support = await this.supportsAuthorityFeature?.("query-metadata-v1", requestOptions);
|
|
70
|
+
if (support && !support.ok)
|
|
71
|
+
throw new MdbaseConnectError(support.problem);
|
|
72
|
+
if (!support?.value)
|
|
73
|
+
throw connectError("unsupported_operation", "This authority does not support metadata queries. Use an ordinary query on legacy authorities.");
|
|
74
|
+
const outcome = await this.envelopeOperation("query", wireQueryInput(input), COLLECTION_QUERY_PROBLEM_CODES, requestOptions);
|
|
75
|
+
return mapOutcome(outcome, value => wireQueryResult(value, input.output));
|
|
76
|
+
}), COLLECTION_QUERY_PROBLEM_CODES);
|
|
77
|
+
return captured.ok ? captured.value : captured;
|
|
70
78
|
}
|
|
71
79
|
async *queryPages(input = {}, options = {}) {
|
|
72
|
-
yield* coordinatedQueryPages((pageInput, pageOptions) => this.query(pageInput, pageOptions), (cursor) => this.releaseQueryCursor(cursor), input,
|
|
80
|
+
yield* coordinatedQueryPages((pageInput, pageOptions) => this.query(pageInput, pageOptions), (cursor) => this.releaseQueryCursor(cursor, input.output), input,
|
|
81
|
+
// The overload ties callback row types to input.output; the wire parser
|
|
82
|
+
// rejects mode mismatch before pagination can deliver a page.
|
|
83
|
+
options);
|
|
73
84
|
}
|
|
74
85
|
async queryAll(input = {}, options = {}) {
|
|
75
86
|
const budget = createRequestBudget(options, this.requestTimeoutMs);
|
|
@@ -77,15 +88,18 @@ export class MdbaseCollectionClient {
|
|
|
77
88
|
let finalPage;
|
|
78
89
|
const diagnostics = [];
|
|
79
90
|
try {
|
|
80
|
-
|
|
91
|
+
const pageOptions = {
|
|
81
92
|
firstPageSize: options.firstPageSize,
|
|
82
93
|
pageSize: options.pageSize,
|
|
83
94
|
maxResults: options.maxResults,
|
|
84
95
|
signal: budget.signal,
|
|
85
96
|
pageTimeoutMs: null,
|
|
86
|
-
coordination: options.coordination
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
coordination: options.coordination
|
|
98
|
+
};
|
|
99
|
+
const pages = input.output === "metadata"
|
|
100
|
+
? this.queryPages(input, { ...pageOptions, onProgress: options.onProgress })
|
|
101
|
+
: this.queryPages(input, { ...pageOptions, onProgress: options.onProgress });
|
|
102
|
+
for await (const outcome of pages) {
|
|
89
103
|
if (!outcome.ok)
|
|
90
104
|
return outcome;
|
|
91
105
|
const page = outcome.value;
|
|
@@ -95,17 +109,19 @@ export class MdbaseCollectionClient {
|
|
|
95
109
|
}
|
|
96
110
|
if (budget.signal.aborted)
|
|
97
111
|
throw requestAbortReason(budget.signal);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
112
|
+
const meta = finalPage ? {
|
|
113
|
+
...(finalPage.meta?.totalCount === undefined
|
|
114
|
+
? (!finalPage.meta?.hasMore ? { totalCount: results.length } : {})
|
|
115
|
+
: { totalCount: finalPage.meta.totalCount }),
|
|
116
|
+
...(finalPage.meta?.hasMore && finalPage.meta.totalCountOutcome ? { totalCountOutcome: finalPage.meta.totalCountOutcome } : {}),
|
|
117
|
+
hasMore: finalPage.meta?.hasMore ?? false,
|
|
118
|
+
...(finalPage.snapshot ? { snapshot: finalPage.snapshot } : {})
|
|
119
|
+
} : undefined;
|
|
120
|
+
// Every page is parsed in the requested mode, never converted from full
|
|
121
|
+
// rows to revision-required metadata (or from partial rows to documents).
|
|
122
|
+
return input.output === "metadata"
|
|
123
|
+
? connectSuccess({ output: "metadata", results: results, ...(meta ? { meta } : {}) }, diagnostics)
|
|
124
|
+
: connectSuccess({ results: results, ...(meta ? { meta } : {}) }, diagnostics);
|
|
109
125
|
}
|
|
110
126
|
catch (error) {
|
|
111
127
|
if (error instanceof MdbaseConnectError) {
|
|
@@ -305,9 +321,19 @@ export class MdbaseCollectionClient {
|
|
|
305
321
|
rawOperation(operation, input, allowedCodes, options) {
|
|
306
322
|
return captureConnectOutcome(() => this.transport.operation(operation, input, options), allowedCodes);
|
|
307
323
|
}
|
|
308
|
-
async releaseQueryCursor(cursor) {
|
|
324
|
+
async releaseQueryCursor(cursor, output) {
|
|
309
325
|
try {
|
|
310
|
-
await
|
|
326
|
+
await withRequestBudget({ timeoutMs: 2_000 }, null, async (budget) => {
|
|
327
|
+
const options = requestOptionsWithinBudget({ signal: budget.signal, timeoutMs: null, coordination: { coalesce: false } }, budget);
|
|
328
|
+
if (output) {
|
|
329
|
+
// A supplied/stale cursor can reach cleanup even when the page was
|
|
330
|
+
// rejected before dispatch. Never send metadata release to an old route.
|
|
331
|
+
const support = await this.supportsAuthorityFeature?.("query-metadata-v1", options);
|
|
332
|
+
if (!support?.ok || !support.value)
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
await this.envelopeOperation("query", { release_cursor: cursor, ...(output ? { output } : {}) }, COLLECTION_QUERY_PROBLEM_CODES, options);
|
|
336
|
+
});
|
|
311
337
|
}
|
|
312
338
|
catch {
|
|
313
339
|
// Lease expiry is bounded by the authority; cleanup never masks query results.
|
|
@@ -328,7 +354,16 @@ export class MdbaseCollectionClient {
|
|
|
328
354
|
}
|
|
329
355
|
}
|
|
330
356
|
function mapOutcome(outcome, map) {
|
|
331
|
-
|
|
357
|
+
if (!outcome.ok)
|
|
358
|
+
return outcome;
|
|
359
|
+
try {
|
|
360
|
+
return connectSuccess(map(outcome.value), outcome.diagnostics);
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
if (error instanceof MdbaseConnectError)
|
|
364
|
+
return connectFailure(error.problem);
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
332
367
|
}
|
|
333
368
|
function wireReadInput(input) {
|
|
334
369
|
return {
|
|
@@ -337,47 +372,6 @@ function wireReadInput(input) {
|
|
|
337
372
|
...(input.includeDocument === undefined ? {} : { include_document: input.includeDocument })
|
|
338
373
|
};
|
|
339
374
|
}
|
|
340
|
-
function wireQueryInput(input) {
|
|
341
|
-
return {
|
|
342
|
-
...(input.types ? { types: input.types } : {}),
|
|
343
|
-
...(input.timezone ? { timezone: input.timezone } : {}),
|
|
344
|
-
...(input.context ? { context: input.context } : {}),
|
|
345
|
-
...(input.projections ? {
|
|
346
|
-
projections: Object.fromEntries(Object.entries(input.projections).map(([name, projection]) => [
|
|
347
|
-
name,
|
|
348
|
-
{ expr: projection.expression, ...(projection.description ? { description: projection.description } : {}) }
|
|
349
|
-
]))
|
|
350
|
-
} : {}),
|
|
351
|
-
...(input.where ? { where: input.where } : {}),
|
|
352
|
-
...(input.select ? {
|
|
353
|
-
select: input.select.map((selection) => typeof selection === "string"
|
|
354
|
-
? selection
|
|
355
|
-
: {
|
|
356
|
-
name: selection.name,
|
|
357
|
-
expr: selection.expression,
|
|
358
|
-
...(selection.label ? { label: selection.label } : {}),
|
|
359
|
-
...(selection.description ? { description: selection.description } : {})
|
|
360
|
-
})
|
|
361
|
-
} : {}),
|
|
362
|
-
...(input.orderBy ? { order_by: input.orderBy } : {}),
|
|
363
|
-
...(input.groupBy ? { group_by: input.groupBy } : {}),
|
|
364
|
-
...(input.summaryFunctions ? {
|
|
365
|
-
summary_functions: Object.fromEntries(Object.entries(input.summaryFunctions).map(([name, projection]) => [
|
|
366
|
-
name,
|
|
367
|
-
{ expr: projection.expression, ...(projection.description ? { description: projection.description } : {}) }
|
|
368
|
-
]))
|
|
369
|
-
} : {}),
|
|
370
|
-
...(input.summaries ? { summaries: input.summaries } : {}),
|
|
371
|
-
...(input.limit === undefined ? {} : { limit: input.limit }),
|
|
372
|
-
...(input.offset === undefined ? {} : { offset: input.offset }),
|
|
373
|
-
...(input.pagination ? { pagination: input.pagination } : {}),
|
|
374
|
-
...(input.cursor ? { cursor: input.cursor } : {}),
|
|
375
|
-
...(input.snapshot ? { snapshot: input.snapshot } : {}),
|
|
376
|
-
...(input.includeBody === undefined ? {} : { include_body: input.includeBody }),
|
|
377
|
-
...(input.frontmatterMode ? { frontmatter_mode: input.frontmatterMode } : {}),
|
|
378
|
-
...(input.contract ? { contract: input.contract } : {})
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
375
|
function wireCreateInput(input) {
|
|
382
376
|
return {
|
|
383
377
|
...(input.path ? { path: input.path } : {}),
|
|
@@ -525,23 +519,6 @@ function wireContractSetupChoice(choice) {
|
|
|
525
519
|
...(choice.binding ? { binding: choice.binding } : {})
|
|
526
520
|
};
|
|
527
521
|
}
|
|
528
|
-
function wireDataContractIdentity(value) {
|
|
529
|
-
return {
|
|
530
|
-
id: value.id,
|
|
531
|
-
version: value.version,
|
|
532
|
-
digest: value.digest,
|
|
533
|
-
type: value.type,
|
|
534
|
-
implementationDigest: value.implementation_digest
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
function wireQueryRecord(value) {
|
|
538
|
-
const { effective_frontmatter, contract, ...record } = value;
|
|
539
|
-
return {
|
|
540
|
-
...record,
|
|
541
|
-
...(effective_frontmatter === undefined ? {} : { effectiveFrontmatter: effective_frontmatter }),
|
|
542
|
-
...(contract ? { contract: wireDataContractIdentity(contract) } : {})
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
522
|
function wireRecordDocument(value) {
|
|
546
523
|
const { effective_frontmatter, contract, ...record } = value;
|
|
547
524
|
return {
|
|
@@ -580,6 +557,7 @@ function wireTypePackResource(value) {
|
|
|
580
557
|
...(value.current_digest ? { currentDigest: value.current_digest } : {}),
|
|
581
558
|
...(value.installed_digest ? { installedDigest: value.installed_digest } : {}),
|
|
582
559
|
...(value.adopted_from_digest ? { adoptedFromDigest: value.adopted_from_digest } : {}),
|
|
560
|
+
...(value.upgrade_baseline ? { upgradeBaseline: value.upgrade_baseline } : {}),
|
|
583
561
|
...(value.reason ? { reason: value.reason } : {})
|
|
584
562
|
};
|
|
585
563
|
}
|
|
@@ -595,7 +573,8 @@ function wireTypePackReceipt(value) {
|
|
|
595
573
|
kind: resource.kind,
|
|
596
574
|
mode: resource.mode,
|
|
597
575
|
digest: resource.digest,
|
|
598
|
-
...(resource.adopted_from_digest ? { adoptedFromDigest: resource.adopted_from_digest } : {})
|
|
576
|
+
...(resource.adopted_from_digest ? { adoptedFromDigest: resource.adopted_from_digest } : {}),
|
|
577
|
+
...(resource.origin_digest ? { originDigest: resource.origin_digest } : {})
|
|
599
578
|
}))
|
|
600
579
|
};
|
|
601
580
|
}
|
package/dist/connection.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { MdbaseFileClient } from "./files.js";
|
|
|
9
9
|
import { MdbaseRecords } from "./records.js";
|
|
10
10
|
import { type Application } from "./internal-types.js";
|
|
11
11
|
import type { MdbaseNativeNotificationRegistration, MdbaseNativeNotificationRegistrationOptions, MdbaseNotificationRegistration, MdbaseNotificationRegistrationOptions } from "./notifications.js";
|
|
12
|
-
import type { ChangesInput, CollectionChangesPage, DescribeOptions, CollectionDescription, CollectionSetupApplyResult, CollectionSetupAssessment, ApplyCollectionSetupInput, ApplyTypePackInput, AssessCollectionSetupInput, AssessTypePackInput, CreateInput, CreateTypeInput, CreateViewSourceInput, DeleteInput, DeletePreflightResult, DeleteProgressOptions, DeleteResult, DeleteViewSourceInput, DeleteViewSourceResult, ExecuteViewInput, MdbaseDesiredTimer, MdbaseTimer, MdbaseTimerList, MdbaseTimerReconciliation, ConnectRequestOptions, PendingMutation, QueryAllOptions, QueryInput, QueryPage, QueryPagesOptions, QueryResult, ReadInput, ReadTypeInput, ReadViewSourceInput, RenameInput, RenamePreflightResult, RenameProgressOptions, RenameResult, RecordDocument, SavedViewExecution, SavedViewPage, SavedViewPagesOptions, SavedViewList, SavedViewSourceDocument, TypePackApplyResult, TypePackAssessment, UpdateInput, UpdateTypeInput, UpdateViewSourceInput, MdbaseWatchSubscription, WatchInput } from "./operation-types.js";
|
|
12
|
+
import type { ChangesInput, CollectionChangesPage, DescribeOptions, CollectionDescription, CollectionSetupApplyResult, CollectionSetupAssessment, ApplyCollectionSetupInput, ApplyTypePackInput, AssessCollectionSetupInput, AssessTypePackInput, CreateInput, CreateTypeInput, CreateViewSourceInput, DeleteInput, DeletePreflightResult, DeleteProgressOptions, DeleteResult, DeleteViewSourceInput, DeleteViewSourceResult, ExecuteViewInput, MdbaseDesiredTimer, MdbaseTimer, MdbaseTimerList, MdbaseTimerReconciliation, ConnectRequestOptions, PendingMutation, QueryAllOptions, QueryInput, QueryMetadataInput, QueryMetadataRecord, QueryMetadataResult, QueryMetadataPage, QueryPage, QueryPagesOptions, QueryResult, ReadInput, ReadTypeInput, ReadViewSourceInput, RenameInput, RenamePreflightResult, RenameProgressOptions, RenameResult, RecordDocument, SavedViewExecution, SavedViewPage, SavedViewPagesOptions, SavedViewList, SavedViewSourceDocument, TypePackApplyResult, TypePackAssessment, UpdateInput, UpdateTypeInput, UpdateViewSourceInput, MdbaseWatchSubscription, WatchInput } from "./operation-types.js";
|
|
13
13
|
import { type AuthorizationProblemCode, type CollectionChangesProblemCode, type CollectionDescriptionProblemCode, type CollectionMutationProblemCode, type CollectionQueryProblemCode, type CollectionReadProblemCode, type CollectionTypeProblemCode, type ConnectOutcome, type DirectAccessProblemCode, type NotificationProblemCode, type RegistrationProblemCode } from "./outcomes.js";
|
|
14
14
|
import type { MdbaseDeviceAuthorization } from "./connection-types.js";
|
|
15
15
|
import { type ResolvedConnectTimeouts } from "./request-budget.js";
|
|
@@ -76,6 +76,7 @@ export declare class MdbaseConnection<Frontmatter extends JsonObject = JsonObjec
|
|
|
76
76
|
private readonly collectionClient;
|
|
77
77
|
private readonly notifications;
|
|
78
78
|
private readonly transport;
|
|
79
|
+
private readonly authorityFeatures;
|
|
79
80
|
readonly files: MdbaseFileClient;
|
|
80
81
|
/** Editable record sessions shared by every view of this connection. */
|
|
81
82
|
readonly records: MdbaseRecords<Frontmatter>;
|
|
@@ -89,6 +90,9 @@ export declare class MdbaseConnection<Frontmatter extends JsonObject = JsonObjec
|
|
|
89
90
|
get fileCapability(): FileCapability | null;
|
|
90
91
|
get directAccess(): DirectAccessStatus;
|
|
91
92
|
get route(): MdbaseConnectionRoute;
|
|
93
|
+
/** Implementation support for this connection lifetime; not an authorization check. */
|
|
94
|
+
supportsAuthorityFeature(id: string, options?: ConnectRequestOptions): Promise<ConnectOutcome<boolean>>;
|
|
95
|
+
get authorityCapabilities(): readonly string[];
|
|
92
96
|
register(options?: ConnectRequestOptions): Promise<ConnectOutcome<Application, RegistrationProblemCode>>;
|
|
93
97
|
info(): MdbaseConnectionInfo | null;
|
|
94
98
|
authorizationCapabilities(requiredOperations?: CollectionOperation[]): MdbaseAuthorizationCapabilities;
|
|
@@ -129,8 +133,11 @@ export declare class MdbaseConnection<Frontmatter extends JsonObject = JsonObjec
|
|
|
129
133
|
describe(options?: DescribeOptions): Promise<ConnectOutcome<CollectionDescription, CollectionDescriptionProblemCode>>;
|
|
130
134
|
changes(input?: ChangesInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<CollectionChangesPage, CollectionChangesProblemCode>>;
|
|
131
135
|
read(input: ReadInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<RecordDocument<Frontmatter>, CollectionReadProblemCode>>;
|
|
136
|
+
query(input: QueryMetadataInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<QueryMetadataResult, CollectionQueryProblemCode>>;
|
|
132
137
|
query(input?: QueryInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<QueryResult<Frontmatter>, CollectionQueryProblemCode>>;
|
|
138
|
+
queryPages(input: QueryMetadataInput, options?: QueryPagesOptions<JsonObject, QueryMetadataRecord>): AsyncGenerator<ConnectOutcome<QueryMetadataPage, CollectionQueryProblemCode>>;
|
|
133
139
|
queryPages(input?: QueryInput, options?: QueryPagesOptions<Frontmatter>): AsyncGenerator<ConnectOutcome<QueryPage<Frontmatter>, CollectionQueryProblemCode>>;
|
|
140
|
+
queryAll(input: QueryMetadataInput, options?: QueryAllOptions<JsonObject, QueryMetadataRecord>): Promise<ConnectOutcome<QueryMetadataResult, CollectionQueryProblemCode>>;
|
|
134
141
|
queryAll(input?: QueryInput, options?: QueryAllOptions<Frontmatter>): Promise<ConnectOutcome<QueryResult<Frontmatter>, CollectionQueryProblemCode>>;
|
|
135
142
|
listViews(options?: ConnectRequestOptions): Promise<ConnectOutcome<SavedViewList, CollectionReadProblemCode>>;
|
|
136
143
|
executeView(input: ExecuteViewInput, options?: ConnectRequestOptions): Promise<ConnectOutcome<SavedViewExecution<Frontmatter>, CollectionReadProblemCode>>;
|
package/dist/connection.js
CHANGED
|
@@ -2,9 +2,13 @@ import { MdbasePeopleClient, requestPeople } from "./people-client.js";
|
|
|
2
2
|
import { capabilityOperationsForContractVersion } from "@mdbase-dev/connect-protocol";
|
|
3
3
|
import { retainedCapabilities, semanticContractVersion, validateAuthorizationSelection } from "./application-contract.js";
|
|
4
4
|
import { MdbaseCollectionClient } from "./collection-client.js";
|
|
5
|
+
import { AuthorityFeatures, authorityCapabilities } from "./authority-features.js";
|
|
6
|
+
import { filePage } from "./file-metadata.js";
|
|
7
|
+
import { wireCollectionDescription } from "./query-wire.js";
|
|
8
|
+
import { CollectionWatchSubscription } from "./watch-policy.js";
|
|
5
9
|
import { ConnectionNotifications } from "./connection-notifications.js";
|
|
6
10
|
import { ConnectionTransport } from "./connection-transport.js";
|
|
7
|
-
import { MdbaseConnectError, connectProblem, operationProblem } from "./errors.js";
|
|
11
|
+
import { MdbaseConnectError, connectError, connectProblem, operationProblem } from "./errors.js";
|
|
8
12
|
import { MdbaseFileClient } from "./files.js";
|
|
9
13
|
import { MdbaseRecords } from "./records.js";
|
|
10
14
|
import { DEFAULT_OPERATIONS } from "./internal-types.js";
|
|
@@ -18,6 +22,7 @@ export class MdbaseConnection {
|
|
|
18
22
|
collectionClient;
|
|
19
23
|
notifications;
|
|
20
24
|
transport;
|
|
25
|
+
authorityFeatures;
|
|
21
26
|
files;
|
|
22
27
|
/** Editable record sessions shared by every view of this connection. */
|
|
23
28
|
records;
|
|
@@ -36,8 +41,34 @@ export class MdbaseConnection {
|
|
|
36
41
|
collectionId,
|
|
37
42
|
internals,
|
|
38
43
|
timeouts: internals.timeouts,
|
|
39
|
-
onChange: () =>
|
|
44
|
+
onChange: () => {
|
|
45
|
+
this.authorityFeatures.refreshLifetime();
|
|
46
|
+
this.emitConnection();
|
|
47
|
+
}
|
|
40
48
|
});
|
|
49
|
+
this.authorityFeatures = new AuthorityFeatures({
|
|
50
|
+
lifetime: () => {
|
|
51
|
+
const token = this.transport.currentToken();
|
|
52
|
+
return JSON.stringify([token?.savedAt, token?.grantId, token?.keyHandle,
|
|
53
|
+
token?.authority?.operationsUrl, token?.authority?.filesUrl, token?.authority?.replicaId,
|
|
54
|
+
token?.authority?.proofPublicKey, token?.clientId, token?.applicationOrigin,
|
|
55
|
+
token?.encryption, token?.scope, token?.operations, token?.fileCapability, this.transport.route]);
|
|
56
|
+
},
|
|
57
|
+
operations: () => this.operations,
|
|
58
|
+
fileCapability: () => this.fileCapability,
|
|
59
|
+
// Catalog TTL/in-flight loads are not evidence for a new authority route.
|
|
60
|
+
// B1 owns this authenticated baseline's sharing, deadline and lifetime.
|
|
61
|
+
describe: async (options) => {
|
|
62
|
+
const value = wireCollectionDescription(await this.transport.performOperation("describe", {}, options));
|
|
63
|
+
if (value.collectionId.toLowerCase() !== this.collectionId.toLowerCase())
|
|
64
|
+
throw connectError("invalid_operation_response", "The authority described a different collection.");
|
|
65
|
+
return connectSuccess(value);
|
|
66
|
+
},
|
|
67
|
+
filesPage: async (folder, signal) => {
|
|
68
|
+
const page = await filePage((method, path, input, signal) => this.transport.files.control(method, path, input, signal), new URLSearchParams({ protocol_version: "1", limit: "1", ...(folder ? { folder } : {}) }), signal);
|
|
69
|
+
return authorityCapabilities(page.authority_capabilities);
|
|
70
|
+
}
|
|
71
|
+
}, internals.timeouts.requestMs);
|
|
41
72
|
this.people = new MdbasePeopleClient({
|
|
42
73
|
request: (resource, options) => requestPeople(resource, options ?? {}, {
|
|
43
74
|
serverUrl: internals.serverUrl, collectionId, requestMs: internals.timeouts.requestMs,
|
|
@@ -51,11 +82,11 @@ export class MdbaseConnection {
|
|
|
51
82
|
downloadChunk: (session, chunkIndex, signal) => this.transport.files.downloadChunk(session, chunkIndex, signal)
|
|
52
83
|
}, {
|
|
53
84
|
downloadPart: (session, partIndex, expectedLength, signal) => this.transport.files.downloadHostedPart(session, partIndex, expectedLength, signal)
|
|
54
|
-
}, internals.timeouts);
|
|
85
|
+
}, internals.timeouts, (id, options) => this.supportsAuthorityFeature(id, options));
|
|
55
86
|
this.records = new MdbaseRecords(this, (path) => this.transport.pendingUpdate(path));
|
|
56
87
|
this.collectionClient = new MdbaseCollectionClient(new CollectionRequestCoordinator({
|
|
57
88
|
operation: (operation, input, requestOptions) => this.transport.performOperation(operation, input, requestOptions)
|
|
58
|
-
}, internals.timeouts.requestMs), internals.timeouts.requestMs);
|
|
89
|
+
}, internals.timeouts.requestMs), internals.timeouts.requestMs, (id, options) => this.supportsAuthorityFeature(id, options));
|
|
59
90
|
this.readMany = this.collectionClient.readMany.bind(this.collectionClient);
|
|
60
91
|
this.notifications = new ConnectionNotifications({
|
|
61
92
|
serverUrl: internals.serverUrl,
|
|
@@ -85,6 +116,11 @@ export class MdbaseConnection {
|
|
|
85
116
|
get route() {
|
|
86
117
|
return this.transport.route;
|
|
87
118
|
}
|
|
119
|
+
/** Implementation support for this connection lifetime; not an authorization check. */
|
|
120
|
+
supportsAuthorityFeature(id, options) {
|
|
121
|
+
return this.authorityFeatures.supports(id, options);
|
|
122
|
+
}
|
|
123
|
+
get authorityCapabilities() { return this.authorityFeatures.capabilities; }
|
|
88
124
|
register(options) {
|
|
89
125
|
return captureConnectOutcome(() => this.internals.register(options), REGISTRATION_PROBLEM_CODES);
|
|
90
126
|
}
|
|
@@ -168,6 +204,7 @@ export class MdbaseConnection {
|
|
|
168
204
|
return () => this.connectionListeners.delete(listener);
|
|
169
205
|
}
|
|
170
206
|
notifyStorageChanged() {
|
|
207
|
+
this.authorityFeatures.invalidate();
|
|
171
208
|
this.transport.notifyStorageChanged();
|
|
172
209
|
}
|
|
173
210
|
checkDirectAccess(options) {
|
|
@@ -257,7 +294,13 @@ export class MdbaseConnection {
|
|
|
257
294
|
this.transport.notifyStorageChanged();
|
|
258
295
|
}
|
|
259
296
|
get schemaGeneration() { return this.collectionClient.schemaGeneration; }
|
|
260
|
-
describe(options) {
|
|
297
|
+
async describe(options) {
|
|
298
|
+
const outcome = await this.collectionClient.describe(options);
|
|
299
|
+
if (outcome.ok && outcome.value.collectionId.toLowerCase() !== this.collectionId.toLowerCase()) {
|
|
300
|
+
return connectFailure(connectProblem("invalid_operation_response", "The authority described a different collection."));
|
|
301
|
+
}
|
|
302
|
+
return outcome;
|
|
303
|
+
}
|
|
261
304
|
changes(input = {}, options) {
|
|
262
305
|
return this.collectionClient.changes(input, options);
|
|
263
306
|
}
|
|
@@ -268,10 +311,14 @@ export class MdbaseConnection {
|
|
|
268
311
|
return this.collectionClient.query(input, options);
|
|
269
312
|
}
|
|
270
313
|
queryPages(input = {}, options = {}) {
|
|
271
|
-
return
|
|
314
|
+
return input.output === "metadata"
|
|
315
|
+
? this.collectionClient.queryPages(input, options)
|
|
316
|
+
: this.collectionClient.queryPages(input, options);
|
|
272
317
|
}
|
|
273
318
|
queryAll(input = {}, options = {}) {
|
|
274
|
-
return
|
|
319
|
+
return input.output === "metadata"
|
|
320
|
+
? this.collectionClient.queryAll(input, options)
|
|
321
|
+
: this.collectionClient.queryAll(input, options);
|
|
275
322
|
}
|
|
276
323
|
listViews(options) {
|
|
277
324
|
return this.collectionClient.listViews(options);
|
|
@@ -493,7 +540,7 @@ export class MdbaseConnection {
|
|
|
493
540
|
if (initial.value.reset) {
|
|
494
541
|
throw new MdbaseConnectError(connectProblem("change_cursor_reset", "The collection change cursor expired. Refresh collection state before subscribing again."));
|
|
495
542
|
}
|
|
496
|
-
return new CollectionWatchSubscription(this.collectionClient, initial.value.cursor, input, input.cursor === undefined ? [] : initial.value.events, this.internals.timeouts.watchStartMs);
|
|
543
|
+
return new CollectionWatchSubscription(options => this.collectionClient.watch(options), initial.value.cursor, input, input.cursor === undefined ? [] : initial.value.events, this.internals.timeouts.watchStartMs);
|
|
497
544
|
}), COLLECTION_CHANGES_PROBLEM_CODES);
|
|
498
545
|
}
|
|
499
546
|
emitConnection() {
|
|
@@ -502,114 +549,6 @@ export class MdbaseConnection {
|
|
|
502
549
|
listener(connection);
|
|
503
550
|
}
|
|
504
551
|
}
|
|
505
|
-
class CollectionWatchSubscription {
|
|
506
|
-
client;
|
|
507
|
-
input;
|
|
508
|
-
watchStartTimeoutMs;
|
|
509
|
-
changes = new Set();
|
|
510
|
-
statuses = new Set();
|
|
511
|
-
problems = new Set();
|
|
512
|
-
controller = new AbortController();
|
|
513
|
-
removeLifetimeAbort;
|
|
514
|
-
currentStatus;
|
|
515
|
-
currentProblem = null;
|
|
516
|
-
pendingChanges;
|
|
517
|
-
constructor(client, cursor, input, pendingChanges, watchStartTimeoutMs) {
|
|
518
|
-
this.client = client;
|
|
519
|
-
this.input = input;
|
|
520
|
-
this.watchStartTimeoutMs = watchStartTimeoutMs;
|
|
521
|
-
this.pendingChanges = [...pendingChanges];
|
|
522
|
-
this.currentStatus = { state: "connected", cursor, recovered: false };
|
|
523
|
-
const lifetimeSignal = input.lifetimeSignal;
|
|
524
|
-
if (lifetimeSignal?.aborted)
|
|
525
|
-
this.close();
|
|
526
|
-
else if (lifetimeSignal) {
|
|
527
|
-
const close = () => this.close();
|
|
528
|
-
lifetimeSignal.addEventListener("abort", close, { once: true });
|
|
529
|
-
this.removeLifetimeAbort = () => lifetimeSignal.removeEventListener("abort", close);
|
|
530
|
-
}
|
|
531
|
-
if (!this.controller.signal.aborted)
|
|
532
|
-
void this.run(cursor);
|
|
533
|
-
}
|
|
534
|
-
get status() {
|
|
535
|
-
return this.currentStatus;
|
|
536
|
-
}
|
|
537
|
-
get problem() {
|
|
538
|
-
return this.currentProblem;
|
|
539
|
-
}
|
|
540
|
-
subscribe(listener, onStatus, onProblem) {
|
|
541
|
-
this.changes.add(listener);
|
|
542
|
-
if (onStatus) {
|
|
543
|
-
this.statuses.add(onStatus);
|
|
544
|
-
onStatus(this.currentStatus);
|
|
545
|
-
}
|
|
546
|
-
if (onProblem) {
|
|
547
|
-
this.problems.add(onProblem);
|
|
548
|
-
if (this.currentProblem)
|
|
549
|
-
onProblem(this.currentProblem);
|
|
550
|
-
}
|
|
551
|
-
for (const change of this.pendingChanges)
|
|
552
|
-
listener(change);
|
|
553
|
-
this.pendingChanges = [];
|
|
554
|
-
return () => {
|
|
555
|
-
this.changes.delete(listener);
|
|
556
|
-
if (onStatus)
|
|
557
|
-
this.statuses.delete(onStatus);
|
|
558
|
-
if (onProblem)
|
|
559
|
-
this.problems.delete(onProblem);
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
close() {
|
|
563
|
-
if (this.controller.signal.aborted)
|
|
564
|
-
return;
|
|
565
|
-
this.controller.abort();
|
|
566
|
-
this.removeLifetimeAbort?.();
|
|
567
|
-
this.removeLifetimeAbort = undefined;
|
|
568
|
-
const cursor = "cursor" in this.currentStatus ? this.currentStatus.cursor : undefined;
|
|
569
|
-
this.publishStatus({ state: "closed", ...(cursor === undefined ? {} : { cursor }) });
|
|
570
|
-
}
|
|
571
|
-
async run(cursor) {
|
|
572
|
-
let firstStatus = true;
|
|
573
|
-
const iterator = this.client.watch({
|
|
574
|
-
cursor,
|
|
575
|
-
pollIntervalMs: this.input.pollIntervalMs,
|
|
576
|
-
retry: this.input.retry,
|
|
577
|
-
signal: this.controller.signal,
|
|
578
|
-
timeoutMs: this.watchStartTimeoutMs,
|
|
579
|
-
onStatus: (status) => {
|
|
580
|
-
if (firstStatus && status.state === "connecting") {
|
|
581
|
-
firstStatus = false;
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
firstStatus = false;
|
|
585
|
-
this.publishStatus(status);
|
|
586
|
-
}
|
|
587
|
-
});
|
|
588
|
-
try {
|
|
589
|
-
for await (const outcome of iterator) {
|
|
590
|
-
if (this.controller.signal.aborted)
|
|
591
|
-
return;
|
|
592
|
-
if (!outcome.ok) {
|
|
593
|
-
this.currentProblem = outcome.problem;
|
|
594
|
-
for (const listener of this.problems)
|
|
595
|
-
listener(outcome.problem);
|
|
596
|
-
return;
|
|
597
|
-
}
|
|
598
|
-
for (const listener of this.changes)
|
|
599
|
-
listener(outcome.value);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
finally {
|
|
603
|
-
if (!this.controller.signal.aborted)
|
|
604
|
-
this.close();
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
publishStatus(status) {
|
|
608
|
-
this.currentStatus = status;
|
|
609
|
-
for (const listener of this.statuses)
|
|
610
|
-
listener(status);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
552
|
function syncRequestOptions(options, defaultTimeoutMs) {
|
|
614
553
|
return {
|
|
615
554
|
...options,
|