@mdbase-dev/connect 0.1.0-beta.100

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 (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +696 -0
  3. package/dist/advanced.d.ts +9 -0
  4. package/dist/advanced.js +6 -0
  5. package/dist/application-contract.d.ts +22 -0
  6. package/dist/application-contract.js +75 -0
  7. package/dist/application-identity.d.ts +34 -0
  8. package/dist/application-identity.js +148 -0
  9. package/dist/application-session.d.ts +167 -0
  10. package/dist/application-session.js +722 -0
  11. package/dist/async.d.ts +1 -0
  12. package/dist/async.js +19 -0
  13. package/dist/authority-proof.d.ts +3 -0
  14. package/dist/authority-proof.js +24 -0
  15. package/dist/authority-sync-request.d.ts +3 -0
  16. package/dist/authority-sync-request.js +20 -0
  17. package/dist/authorization-refresh.d.ts +14 -0
  18. package/dist/authorization-refresh.js +41 -0
  19. package/dist/authorization-types.d.ts +7 -0
  20. package/dist/authorization-types.js +1 -0
  21. package/dist/authorization-url.d.ts +5 -0
  22. package/dist/authorization-url.js +34 -0
  23. package/dist/base64.d.ts +3 -0
  24. package/dist/base64.js +21 -0
  25. package/dist/browser/integrity.json +4 -0
  26. package/dist/browser/mdbase-connect.min.js +3 -0
  27. package/dist/browser/mdbase-connect.min.js.sha384 +1 -0
  28. package/dist/browser.d.ts +3 -0
  29. package/dist/browser.js +5 -0
  30. package/dist/capabilities.d.ts +24 -0
  31. package/dist/capabilities.js +91 -0
  32. package/dist/collection-client.d.ts +66 -0
  33. package/dist/collection-client.js +686 -0
  34. package/dist/connect-authorization-helpers.d.ts +4 -0
  35. package/dist/connect-authorization-helpers.js +25 -0
  36. package/dist/connect-options.d.ts +35 -0
  37. package/dist/connect-options.js +1 -0
  38. package/dist/connect.d.ts +66 -0
  39. package/dist/connect.js +711 -0
  40. package/dist/connection-file-transport.d.ts +34 -0
  41. package/dist/connection-file-transport.js +85 -0
  42. package/dist/connection-index.d.ts +3 -0
  43. package/dist/connection-index.js +20 -0
  44. package/dist/connection-notifications.d.ts +31 -0
  45. package/dist/connection-notifications.js +197 -0
  46. package/dist/connection-transport-internals.d.ts +24 -0
  47. package/dist/connection-transport-internals.js +1 -0
  48. package/dist/connection-transport.d.ts +64 -0
  49. package/dist/connection-transport.js +725 -0
  50. package/dist/connection-types.d.ts +38 -0
  51. package/dist/connection-types.js +1 -0
  52. package/dist/connection.d.ts +175 -0
  53. package/dist/connection.js +606 -0
  54. package/dist/crypto-entry.d.ts +7 -0
  55. package/dist/crypto-entry.js +4 -0
  56. package/dist/crypto.d.ts +63 -0
  57. package/dist/crypto.js +409 -0
  58. package/dist/direct-access.d.ts +3 -0
  59. package/dist/direct-access.js +29 -0
  60. package/dist/errors.d.ts +45 -0
  61. package/dist/errors.js +142 -0
  62. package/dist/external-store.d.ts +10 -0
  63. package/dist/external-store.js +10 -0
  64. package/dist/file-crypto.d.ts +25 -0
  65. package/dist/file-crypto.js +132 -0
  66. package/dist/file-sha256.d.ts +12 -0
  67. package/dist/file-sha256.js +143 -0
  68. package/dist/file-stream-source.d.ts +17 -0
  69. package/dist/file-stream-source.js +157 -0
  70. package/dist/file-transfer-internals.d.ts +23 -0
  71. package/dist/file-transfer-internals.js +228 -0
  72. package/dist/files.d.ts +115 -0
  73. package/dist/files.js +563 -0
  74. package/dist/fresh-encrypted-request.d.ts +4 -0
  75. package/dist/fresh-encrypted-request.js +28 -0
  76. package/dist/grant-key-leases.d.ts +24 -0
  77. package/dist/grant-key-leases.js +144 -0
  78. package/dist/hosted-file-request.d.ts +6 -0
  79. package/dist/hosted-file-request.js +63 -0
  80. package/dist/hosted-operation-response.d.ts +5 -0
  81. package/dist/hosted-operation-response.js +26 -0
  82. package/dist/index.d.ts +27 -0
  83. package/dist/index.js +10 -0
  84. package/dist/internal-types.d.ts +100 -0
  85. package/dist/internal-types.js +1 -0
  86. package/dist/local-file-transport.d.ts +37 -0
  87. package/dist/local-file-transport.js +457 -0
  88. package/dist/mdbase-connect.d.ts +28 -0
  89. package/dist/mdbase-connect.js +53 -0
  90. package/dist/notifications.d.ts +48 -0
  91. package/dist/notifications.js +52 -0
  92. package/dist/operation-helpers.d.ts +27 -0
  93. package/dist/operation-helpers.js +144 -0
  94. package/dist/operation-types.d.ts +707 -0
  95. package/dist/operation-types.js +1 -0
  96. package/dist/outcomes.d.ts +51 -0
  97. package/dist/outcomes.js +194 -0
  98. package/dist/pending-mutation-store.d.ts +13 -0
  99. package/dist/pending-mutation-store.js +64 -0
  100. package/dist/pending-recovery-transports.d.ts +5 -0
  101. package/dist/pending-recovery-transports.js +52 -0
  102. package/dist/popup-authorization.d.ts +31 -0
  103. package/dist/popup-authorization.js +100 -0
  104. package/dist/query-pagination.d.ts +6 -0
  105. package/dist/query-pagination.js +119 -0
  106. package/dist/request-budget.d.ts +34 -0
  107. package/dist/request-budget.js +104 -0
  108. package/dist/request-coordinator.d.ts +29 -0
  109. package/dist/request-coordinator.js +213 -0
  110. package/dist/retired-grant-keys.d.ts +9 -0
  111. package/dist/retired-grant-keys.js +56 -0
  112. package/dist/runtime-utils.d.ts +52 -0
  113. package/dist/runtime-utils.js +368 -0
  114. package/dist/saved-view-pagination.d.ts +6 -0
  115. package/dist/saved-view-pagination.js +76 -0
  116. package/dist/selection.d.ts +48 -0
  117. package/dist/selection.js +112 -0
  118. package/dist/session.d.ts +114 -0
  119. package/dist/session.js +569 -0
  120. package/dist/shared-operation.d.ts +7 -0
  121. package/dist/shared-operation.js +41 -0
  122. package/dist/stored-token.d.ts +10 -0
  123. package/dist/stored-token.js +64 -0
  124. package/dist/structured-readiness.d.ts +77 -0
  125. package/dist/structured-readiness.js +126 -0
  126. package/dist/token-response.d.ts +12 -0
  127. package/dist/token-response.js +81 -0
  128. package/dist/transient-retry.d.ts +22 -0
  129. package/dist/transient-retry.js +59 -0
  130. package/dist/watch-policy.d.ts +8 -0
  131. package/dist/watch-policy.js +12 -0
  132. package/package.json +51 -0
@@ -0,0 +1,228 @@
1
+ import { MdbaseConnectError, connectError } from "./errors.js";
2
+ import { IncrementalSha256 } from "./file-sha256.js";
3
+ import { MAX_TRANSIENT_CHUNK_ATTEMPTS, waitForTransientChunkRetry } from "./transient-retry.js";
4
+ const HASH_CHUNK_BYTES = 1024 * 1024;
5
+ const DEFAULT_CONCURRENCY = 4;
6
+ const MAX_CONCURRENCY = 8;
7
+ export const MAX_OBJECT_ATTEMPTS = 3;
8
+ export const MAX_BUFFERED_DOWNLOAD_BYTES = 64 * 1024 * 1024;
9
+ export const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
10
+ export const SHA256_DIGEST = /^sha256:[0-9a-f]{64}$/u;
11
+ export async function hashBlob(blob, signal, progress) {
12
+ const hash = new IncrementalSha256();
13
+ for (let offset = 0; offset < blob.size; offset += HASH_CHUNK_BYTES) {
14
+ throwIfAborted(signal);
15
+ const chunk = new Uint8Array(await blob.slice(offset, offset + HASH_CHUNK_BYTES).arrayBuffer());
16
+ hash.update(chunk);
17
+ progress(Math.min(blob.size, offset + chunk.byteLength));
18
+ }
19
+ if (blob.size === 0)
20
+ progress(0);
21
+ return hash.digestHex();
22
+ }
23
+ export function sourceBlob(source, mediaType) {
24
+ if (source instanceof Blob) {
25
+ return mediaType && mediaType !== source.type
26
+ ? source.slice(0, source.size, mediaType)
27
+ : source;
28
+ }
29
+ if (source instanceof ArrayBuffer)
30
+ return new Blob([source], { type: mediaType });
31
+ const copy = new Uint8Array(source.byteLength);
32
+ copy.set(new Uint8Array(source.buffer, source.byteOffset, source.byteLength));
33
+ return new Blob([copy.buffer], { type: mediaType });
34
+ }
35
+ export function uploadBodyLength(body) {
36
+ return body instanceof Blob ? body.size : body.byteLength;
37
+ }
38
+ export async function uploadBodyBytes(body) {
39
+ return body instanceof Blob
40
+ ? new Uint8Array(await body.arrayBuffer())
41
+ : body;
42
+ }
43
+ export function validConcurrency(value = DEFAULT_CONCURRENCY) {
44
+ if (!Number.isInteger(value) || value < 1 || value > MAX_CONCURRENCY) {
45
+ throw connectError("invalid_request", `File concurrency must be between 1 and ${MAX_CONCURRENCY}.`);
46
+ }
47
+ return value;
48
+ }
49
+ export function validPageSize(value) {
50
+ if (!Number.isInteger(value) || value < 1 || value > 1_000) {
51
+ throw connectError("invalid_request", "File page size must be between 1 and 1000.");
52
+ }
53
+ return value;
54
+ }
55
+ export function requireTransferSession(session, transferId, direction) {
56
+ if (session.protocol_version !== 1
57
+ || session.type !== "file_transfer"
58
+ || session.transfer_id !== transferId
59
+ || session.direction !== direction
60
+ || !Number.isSafeInteger(session.total_size)
61
+ || session.total_size < 0
62
+ || !Array.isArray(session.received)
63
+ || !validTransferStrategy(session)) {
64
+ throw connectError("invalid_operation_response", "The authority returned an invalid file transfer session.");
65
+ }
66
+ const partSize = session.strategy.kind === "framed_chunks"
67
+ ? session.strategy.chunk_size
68
+ : session.strategy.kind === "object_put"
69
+ ? Math.max(1, session.total_size)
70
+ : session.strategy.part_size;
71
+ const partCount = session.strategy.kind === "object_put"
72
+ ? 1
73
+ : Math.ceil(session.total_size / partSize);
74
+ if (new Set(session.received).size !== session.received.length
75
+ || session.received.some((index) => !Number.isSafeInteger(index) || index < 0 || index >= partCount)) {
76
+ throw connectError("invalid_operation_response", "The authority returned invalid transfer progress.");
77
+ }
78
+ const uploadedParts = session.uploaded_parts ?? [];
79
+ if (!Array.isArray(uploadedParts)
80
+ || uploadedParts.some((part, index) => !Number.isSafeInteger(part?.part_number)
81
+ || part.part_number < 1
82
+ || part.part_number > partCount
83
+ || typeof part.etag !== "string"
84
+ || part.etag.length === 0
85
+ || part.etag.length > 255
86
+ || (index > 0 && uploadedParts[index - 1].part_number >= part.part_number))
87
+ || (session.strategy.kind === "object_multipart"
88
+ ? uploadedParts.length !== session.received.length
89
+ || uploadedParts.some((part, index) => part.part_number - 1 !== session.received[index])
90
+ : uploadedParts.length !== 0)) {
91
+ throw connectError("invalid_operation_response", "The authority returned invalid uploaded part receipts.");
92
+ }
93
+ }
94
+ export function requireTransferStatus(status, session) {
95
+ const partSize = session.strategy.kind === "framed_chunks"
96
+ ? session.strategy.chunk_size
97
+ : session.strategy.kind === "object_put"
98
+ ? Math.max(1, session.total_size)
99
+ : session.strategy.part_size;
100
+ const partCount = session.strategy.kind === "object_put"
101
+ ? 1
102
+ : Math.ceil(session.total_size / partSize);
103
+ if (status?.protocol_version !== 1
104
+ || status.type !== "file_transfer_status"
105
+ || status.transfer_id !== session.transfer_id
106
+ || !["open", "committed", "aborted", "expired"].includes(status.state)
107
+ || !Array.isArray(status.received)
108
+ || new Set(status.received).size !== status.received.length
109
+ || status.received.some((index) => !Number.isSafeInteger(index) || index < 0 || index >= partCount)
110
+ || !Number.isSafeInteger(status.received_bytes)
111
+ || status.received_bytes < 0
112
+ || status.received_bytes > session.total_size
113
+ || status.received.reduce((total, index) => total + chunkLength(session.total_size, partSize, index), 0) !== status.received_bytes) {
114
+ throw connectError("invalid_operation_response", "The authority returned invalid transfer status.");
115
+ }
116
+ const uploadedParts = status.uploaded_parts;
117
+ if (!Array.isArray(uploadedParts)
118
+ || uploadedParts.some((part, index) => !Number.isSafeInteger(part?.part_number)
119
+ || part.part_number < 1
120
+ || part.part_number > partCount
121
+ || typeof part.etag !== "string"
122
+ || part.etag.length === 0
123
+ || part.etag.length > 255
124
+ || (index > 0 && uploadedParts[index - 1].part_number >= part.part_number))
125
+ || (session.strategy.kind === "object_multipart"
126
+ ? uploadedParts.length !== status.received.length
127
+ || uploadedParts.some((part, index) => part.part_number - 1 !== status.received[index])
128
+ : uploadedParts.length !== 0)) {
129
+ throw connectError("invalid_operation_response", "The authority returned invalid uploaded part status.");
130
+ }
131
+ }
132
+ function validTransferStrategy(session) {
133
+ if (session.strategy.kind === "framed_chunks") {
134
+ return session.protection === "grant_aead_v1"
135
+ && Number.isSafeInteger(session.strategy.chunk_size)
136
+ && session.strategy.chunk_size > 0;
137
+ }
138
+ if (session.protection !== "transport_tls")
139
+ return false;
140
+ if (session.strategy.kind === "object_put")
141
+ return true;
142
+ return Number.isSafeInteger(session.strategy.part_size) && session.strategy.part_size > 0;
143
+ }
144
+ export function chunkLength(totalSize, partSize, index) {
145
+ return Math.min(partSize, Math.max(0, totalSize - index * partSize));
146
+ }
147
+ export async function retryChunk(work, signal) {
148
+ for (let attempt = 1; attempt <= MAX_TRANSIENT_CHUNK_ATTEMPTS; attempt += 1) {
149
+ throwIfAborted(signal);
150
+ try {
151
+ return await work();
152
+ }
153
+ catch (error) {
154
+ if (signal?.aborted
155
+ || attempt === MAX_TRANSIENT_CHUNK_ATTEMPTS
156
+ || (error instanceof MdbaseConnectError && !error.retryable))
157
+ throw error;
158
+ await waitForTransientChunkRetry(attempt, signal);
159
+ }
160
+ }
161
+ throw new Error("Unreachable file chunk retry state.");
162
+ }
163
+ export function requirePreparedPart(part, transferId, partIndex, offset, contentLength, method) {
164
+ let url;
165
+ try {
166
+ url = new URL(part.url);
167
+ }
168
+ catch {
169
+ throw connectError("invalid_operation_response", "The authority returned an invalid object URL.");
170
+ }
171
+ if (part.protocol_version !== 1
172
+ || part.type !== "file_part"
173
+ || part.transfer_id !== transferId
174
+ || part.part_index !== partIndex
175
+ || part.offset !== offset
176
+ || part.content_length !== contentLength
177
+ || part.method.toUpperCase() !== method
178
+ || url.protocol !== "https:"
179
+ && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]", "::1"].includes(url.hostname))
180
+ || url.username
181
+ || url.password) {
182
+ throw connectError("invalid_operation_response", "The authority returned an invalid prepared file part.");
183
+ }
184
+ }
185
+ export function browserObjectHeaders(headers) {
186
+ const result = new Headers();
187
+ for (const [name, value] of Object.entries(headers)) {
188
+ if (["host", "content-length"].includes(name.toLowerCase()))
189
+ continue;
190
+ result.set(name, value);
191
+ }
192
+ return result;
193
+ }
194
+ export async function mapConcurrent(count, concurrency, work) {
195
+ const results = new Array(count);
196
+ let next = 0;
197
+ await Promise.all(Array.from({ length: Math.min(count, concurrency) }, async () => {
198
+ while (next < count) {
199
+ const index = next;
200
+ next += 1;
201
+ results[index] = await work(index);
202
+ }
203
+ }));
204
+ return results;
205
+ }
206
+ export function throwIfAborted(signal) {
207
+ if (signal?.aborted) {
208
+ throw connectError("operation_cancelled", "The file transfer was cancelled.", {
209
+ operationOutcome: "not_sent",
210
+ cause: signal.reason
211
+ });
212
+ }
213
+ }
214
+ export function normalizeFileError(error) {
215
+ if (error instanceof MdbaseConnectError)
216
+ return error;
217
+ if (typeof DOMException !== "undefined"
218
+ && error instanceof DOMException
219
+ && error.name === "AbortError") {
220
+ return connectError("operation_cancelled", "The file transfer was cancelled.", {
221
+ operationOutcome: "not_sent",
222
+ cause: error
223
+ });
224
+ }
225
+ return connectError("temporarily_unavailable", "The file transfer could not be completed.", {
226
+ cause: error
227
+ });
228
+ }
@@ -0,0 +1,115 @@
1
+ import type { FileCapability, FileTransferSession } from "@mdbase-dev/connect-protocol";
2
+ import { type FileSource } from "./file-transfer-internals.js";
3
+ import type { ConnectRequestOptions } from "./operation-types.js";
4
+ import { type ResolvedConnectTimeouts } from "./request-budget.js";
5
+ export type MdbaseFileSource = FileSource;
6
+ export interface CollectionFileDescriptor {
7
+ fileId: string;
8
+ path: string;
9
+ revision: string;
10
+ contentDigest: `sha256:${string}`;
11
+ size: number;
12
+ mediaType?: string;
13
+ mediaClass: import("@mdbase-dev/connect-protocol").FileMediaClass;
14
+ modifiedAt: string;
15
+ }
16
+ export interface MdbaseFileDeleteReceipt {
17
+ protocolVersion: 1;
18
+ type: "file_deleted";
19
+ mutationId: string;
20
+ fileId: string;
21
+ previousPath: string;
22
+ revision: string;
23
+ }
24
+ export interface MdbaseFileStreamSource {
25
+ /** Exact plaintext byte length. */
26
+ size: number;
27
+ /** SHA-256 commitment verified by both this client and the authority. */
28
+ contentDigest: `sha256:${string}`;
29
+ /**
30
+ * A one-shot byte source. Each yielded chunk must fit within the upload part
31
+ * size negotiated by the authority; ordinary browser and Node streams do.
32
+ */
33
+ stream: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>;
34
+ mediaType?: string;
35
+ }
36
+ export interface MdbaseFileProgress {
37
+ phase: "hashing" | "uploading" | "downloading";
38
+ transferredBytes: number;
39
+ totalBytes: number;
40
+ }
41
+ export interface MdbaseFileListOptions extends ConnectRequestOptions {
42
+ folder?: string;
43
+ pageSize?: number;
44
+ /** Called while a cold or changed collection builds its verified binary index. */
45
+ onIndexing?: () => void;
46
+ }
47
+ export interface MdbaseFileUploadOptions extends ConnectRequestOptions {
48
+ mediaType?: string;
49
+ ifRevision?: string;
50
+ concurrency?: number;
51
+ /** Stable retry key. Reuse it after an ambiguous failure to resume or replay commit. */
52
+ transferId?: string;
53
+ onProgress?: (progress: MdbaseFileProgress) => void;
54
+ }
55
+ export type MdbaseFileStreamUploadOptions = Omit<MdbaseFileUploadOptions, "concurrency">;
56
+ export interface MdbaseFileDownloadOptions extends ConnectRequestOptions {
57
+ concurrency?: number;
58
+ onProgress?: (progress: MdbaseFileProgress) => void;
59
+ }
60
+ export interface MdbaseFileMoveOptions extends ConnectRequestOptions {
61
+ ifRevision?: string;
62
+ /** Reuse after an ambiguous network failure to receive the original receipt. */
63
+ mutationId?: string;
64
+ }
65
+ export interface MdbaseFileDeleteOptions extends ConnectRequestOptions {
66
+ ifRevision?: string;
67
+ /** Reuse after an ambiguous network failure to receive the original receipt. */
68
+ mutationId?: string;
69
+ }
70
+ /** Internal transport seam used by direct and relayed encrypted chunk delivery. */
71
+ export interface MdbaseFramedFileTransport {
72
+ uploadChunk(session: FileTransferSession, chunkIndex: number, bytes: Uint8Array, signal?: AbortSignal): Promise<void>;
73
+ downloadChunk(session: FileTransferSession, chunkIndex: number, signal?: AbortSignal): Promise<Uint8Array>;
74
+ }
75
+ /** Internal authenticated hosted-object delivery seam. */
76
+ export interface MdbaseHostedFileTransport {
77
+ downloadPart(session: FileTransferSession, partIndex: number, expectedLength: number, signal?: AbortSignal): Promise<ReadableStream<Uint8Array>>;
78
+ }
79
+ type ControlRequest = <Result>(method: "GET" | "POST" | "DELETE", path?: string, input?: unknown, signal?: AbortSignal) => Promise<Result>;
80
+ /** Ergonomic facade over resumable, authority-specific file delivery. */
81
+ export declare class MdbaseFileClient {
82
+ private readonly capability;
83
+ private readonly request;
84
+ private readonly framed?;
85
+ private readonly hosted?;
86
+ private readonly timeouts;
87
+ constructor(capability: () => FileCapability | null, request: ControlRequest, framed?: MdbaseFramedFileTransport | undefined, hosted?: MdbaseHostedFileTransport | undefined, timeouts?: ResolvedConnectTimeouts);
88
+ list(options?: MdbaseFileListOptions): AsyncGenerator<CollectionFileDescriptor>;
89
+ upload(path: string, source: MdbaseFileSource, options?: MdbaseFileUploadOptions): Promise<CollectionFileDescriptor>;
90
+ private uploadWithinBudget;
91
+ /**
92
+ * Upload a one-shot byte stream without accumulating multiple file parts.
93
+ * SDK memory is bounded by one assembled negotiated part plus at most one
94
+ * source chunk; a single-part upload may therefore hold the complete file.
95
+ * Reuse `transferId` with a newly opened source after an ambiguous failure.
96
+ */
97
+ uploadStream(path: string, source: MdbaseFileStreamSource, options?: MdbaseFileStreamUploadOptions): Promise<CollectionFileDescriptor>;
98
+ private uploadStreamWithinBudget;
99
+ private uploadKnownSource;
100
+ download(file: CollectionFileDescriptor, options?: MdbaseFileDownloadOptions): Promise<Blob>;
101
+ /** Download and verify a file with network backpressure and bounded buffering. */
102
+ downloadStream(file: CollectionFileDescriptor, options?: MdbaseFileDownloadOptions): Promise<ReadableStream<Uint8Array>>;
103
+ private openDownloadStream;
104
+ downloadBytes(file: CollectionFileDescriptor, options?: MdbaseFileDownloadOptions): Promise<Uint8Array>;
105
+ move(file: CollectionFileDescriptor, path: string, options?: MdbaseFileMoveOptions): Promise<CollectionFileDescriptor>;
106
+ private moveWithinBudget;
107
+ delete(file: CollectionFileDescriptor, options?: MdbaseFileDeleteOptions): Promise<MdbaseFileDeleteReceipt>;
108
+ private deleteWithinBudget;
109
+ private uploadPart;
110
+ private tryReplayUploadCommit;
111
+ private commitUpload;
112
+ private requireAction;
113
+ private abort;
114
+ }
115
+ export {};