@superbee/core 0.2.0-pre.14 → 0.2.0-pre.16
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 +213 -0
- package/dist/backend.d.ts +3 -0
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +7 -0
- package/dist/backend.js.map +1 -1
- package/dist/blob-contract.d.ts +80 -0
- package/dist/blob-contract.d.ts.map +1 -0
- package/dist/blob-contract.js +131 -0
- package/dist/blob-contract.js.map +1 -0
- package/dist/blob-journal.d.ts +117 -0
- package/dist/blob-journal.d.ts.map +1 -0
- package/dist/blob-journal.js +168 -0
- package/dist/blob-journal.js.map +1 -0
- package/dist/engine.d.ts +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js.map +1 -1
- package/dist/file-journaled-backend-internal.d.ts +2 -0
- package/dist/file-journaled-backend-internal.d.ts.map +1 -1
- package/dist/file-journaled-backend-internal.js +2 -0
- package/dist/file-journaled-backend-internal.js.map +1 -1
- package/dist/file-journaled-backend.d.ts +14 -2
- package/dist/file-journaled-backend.d.ts.map +1 -1
- package/dist/file-journaled-backend.js +245 -37
- package/dist/file-journaled-backend.js.map +1 -1
- package/dist/hosted-client/binding.d.ts +7 -0
- package/dist/hosted-client/binding.d.ts.map +1 -0
- package/dist/hosted-client/binding.js +10 -0
- package/dist/hosted-client/binding.js.map +1 -0
- package/dist/hosted-client/blob-delivery.d.ts +61 -0
- package/dist/hosted-client/blob-delivery.d.ts.map +1 -0
- package/dist/hosted-client/blob-delivery.js +147 -0
- package/dist/hosted-client/blob-delivery.js.map +1 -0
- package/dist/hosted-client/bundle-listing.d.ts +46 -0
- package/dist/hosted-client/bundle-listing.d.ts.map +1 -0
- package/dist/hosted-client/bundle-listing.js +36 -0
- package/dist/hosted-client/bundle-listing.js.map +1 -0
- package/dist/hosted-client/client.d.ts +155 -0
- package/dist/hosted-client/client.d.ts.map +1 -0
- package/dist/hosted-client/client.js +278 -0
- package/dist/hosted-client/client.js.map +1 -0
- package/dist/hosted-client/errors.d.ts +16 -0
- package/dist/hosted-client/errors.d.ts.map +1 -0
- package/dist/hosted-client/errors.js +22 -0
- package/dist/hosted-client/errors.js.map +1 -0
- package/dist/hosted-client/index.d.ts +23 -0
- package/dist/hosted-client/index.d.ts.map +1 -0
- package/dist/hosted-client/index.js +25 -0
- package/dist/hosted-client/index.js.map +1 -0
- package/dist/hosted-client/node.d.ts +70 -0
- package/dist/hosted-client/node.d.ts.map +1 -0
- package/dist/hosted-client/node.js +214 -0
- package/dist/hosted-client/node.js.map +1 -0
- package/dist/hosted-client/reference.d.ts +12 -0
- package/dist/hosted-client/reference.d.ts.map +1 -0
- package/dist/hosted-client/reference.js +29 -0
- package/dist/hosted-client/reference.js.map +1 -0
- package/dist/hosted-client/write.d.ts +191 -0
- package/dist/hosted-client/write.d.ts.map +1 -0
- package/dist/hosted-client/write.js +396 -0
- package/dist/hosted-client/write.js.map +1 -0
- package/dist/hosted-transport/answer-rows.d.ts +26 -0
- package/dist/hosted-transport/answer-rows.d.ts.map +1 -1
- package/dist/hosted-transport/answer-rows.js +59 -1
- package/dist/hosted-transport/answer-rows.js.map +1 -1
- package/dist/hosted-transport/blob-reads.d.ts +35 -0
- package/dist/hosted-transport/blob-reads.d.ts.map +1 -0
- package/dist/hosted-transport/blob-reads.js +179 -0
- package/dist/hosted-transport/blob-reads.js.map +1 -0
- package/dist/hosted-transport/blob-write.d.ts +34 -0
- package/dist/hosted-transport/blob-write.d.ts.map +1 -0
- package/dist/hosted-transport/blob-write.js +115 -0
- package/dist/hosted-transport/blob-write.js.map +1 -0
- package/dist/hosted-transport/carrier.d.ts +8 -9
- package/dist/hosted-transport/carrier.d.ts.map +1 -1
- package/dist/hosted-transport/carrier.js +40 -41
- package/dist/hosted-transport/carrier.js.map +1 -1
- package/dist/hosted-transport/index.d.ts +4 -4
- package/dist/hosted-transport/index.d.ts.map +1 -1
- package/dist/hosted-transport/index.js +4 -4
- package/dist/hosted-transport/index.js.map +1 -1
- package/dist/hosted-transport/read-adapter.d.ts +6 -0
- package/dist/hosted-transport/read-adapter.d.ts.map +1 -1
- package/dist/hosted-transport/read-adapter.js +11 -0
- package/dist/hosted-transport/read-adapter.js.map +1 -1
- package/dist/hosted-transport/whole-document-transport.d.ts +9 -8
- package/dist/hosted-transport/whole-document-transport.d.ts.map +1 -1
- package/dist/hosted-transport/whole-document-transport.js +10 -9
- package/dist/hosted-transport/whole-document-transport.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/journaled-backend.d.ts +10 -2
- package/dist/journaled-backend.d.ts.map +1 -1
- package/dist/journaled-backend.js +3 -3
- package/dist/journaled-backend.js.map +1 -1
- package/dist/link-types.d.ts +26 -0
- package/dist/link-types.d.ts.map +1 -0
- package/dist/link-types.js +57 -0
- package/dist/link-types.js.map +1 -0
- package/dist/platform.d.ts +4 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +16 -0
- package/dist/platform.js.map +1 -1
- package/dist/recipe-lifecycle/errors.d.ts +77 -0
- package/dist/recipe-lifecycle/errors.d.ts.map +1 -0
- package/dist/recipe-lifecycle/errors.js +96 -0
- package/dist/recipe-lifecycle/errors.js.map +1 -0
- package/dist/recipe-lifecycle/evolution.d.ts +71 -0
- package/dist/recipe-lifecycle/evolution.d.ts.map +1 -0
- package/dist/recipe-lifecycle/evolution.js +659 -0
- package/dist/recipe-lifecycle/evolution.js.map +1 -0
- package/dist/recipe-lifecycle/index.d.ts +23 -0
- package/dist/recipe-lifecycle/index.d.ts.map +1 -0
- package/dist/recipe-lifecycle/index.js +19 -0
- package/dist/recipe-lifecycle/index.js.map +1 -0
- package/dist/recipe-lifecycle/install.d.ts +111 -0
- package/dist/recipe-lifecycle/install.d.ts.map +1 -0
- package/dist/recipe-lifecycle/install.js +412 -0
- package/dist/recipe-lifecycle/install.js.map +1 -0
- package/dist/recipe-lifecycle/legacy-aliases.d.ts +16 -0
- package/dist/recipe-lifecycle/legacy-aliases.d.ts.map +1 -0
- package/dist/recipe-lifecycle/legacy-aliases.js +51 -0
- package/dist/recipe-lifecycle/legacy-aliases.js.map +1 -0
- package/dist/recipe-lifecycle/stamp.d.ts +98 -0
- package/dist/recipe-lifecycle/stamp.d.ts.map +1 -0
- package/dist/recipe-lifecycle/stamp.js +260 -0
- package/dist/recipe-lifecycle/stamp.js.map +1 -0
- package/dist/recipes.d.ts +5 -0
- package/dist/recipes.d.ts.map +1 -1
- package/dist/recipes.js +5 -0
- package/dist/recipes.js.map +1 -1
- package/dist/storage.d.ts +3 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +3 -0
- package/dist/storage.js.map +1 -1
- package/dist/uncertain-write.d.ts +70 -2
- package/dist/uncertain-write.d.ts.map +1 -1
- package/dist/uncertain-write.js +45 -32
- package/dist/uncertain-write.js.map +1 -1
- package/dist/write-identity.d.ts +5 -0
- package/dist/write-identity.d.ts.map +1 -0
- package/dist/write-identity.js +9 -0
- package/dist/write-identity.js.map +1 -0
- package/package.json +13 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@superbee/core/hosted-client/node`: the hosted client's Node-only half, a supported public API
|
|
3
|
+
* under core's normal versioning. It downloads a hosted bundle's portable export
|
|
4
|
+
* (`<prefix>/export`) and verifies it with `@superbee/core/portable-export`, whose digests and
|
|
5
|
+
* file placement need Node, so it is kept off the browser-safe `@superbee/core/hosted-client`.
|
|
6
|
+
*
|
|
7
|
+
* The result is a verified export or a typed failure, never files: a stopped, tampered or
|
|
8
|
+
* oversized export is refused before anything is returned, and placing the verified entries is
|
|
9
|
+
* the caller's (`materializeExport`, or its own staging).
|
|
10
|
+
*/
|
|
11
|
+
import { type VerifiedExport } from "../portable-export.js";
|
|
12
|
+
import type { HostedClient } from "./client.js";
|
|
13
|
+
export { ExportArchiveError, MAX_EXPORT_BYTES, type VerifiedExport } from "../portable-export.js";
|
|
14
|
+
/**
|
|
15
|
+
* The host's export window: an export (or one page of a paged one) is answered within 60 s. A
|
|
16
|
+
* client that downloads exports should be created with at least this `deadlineMs`; the default
|
|
17
|
+
* 15 s read deadline would cut a large bundle.
|
|
18
|
+
*/
|
|
19
|
+
export declare const EXPORT_WINDOW_MS = 60000;
|
|
20
|
+
/**
|
|
21
|
+
* Why a download was refused, apart from the host's refusals and the verifier's:
|
|
22
|
+
* `stopped` — the answer's body failed part way (the network, or the carrier's idle deadline), so
|
|
23
|
+
* the same request may succeed; `too_large` — the answer ran past what an export carries
|
|
24
|
+
* ({@link MAX_EXPORT_BYTES} in all); `source_changed` — the bundle kept changing between the pages
|
|
25
|
+
* of a paged export, every attempt.
|
|
26
|
+
*/
|
|
27
|
+
export type HostedExportProblem = "stopped" | "too_large" | "source_changed";
|
|
28
|
+
export declare class HostedExportError extends Error {
|
|
29
|
+
readonly name = "HostedExportError";
|
|
30
|
+
readonly problem: HostedExportProblem;
|
|
31
|
+
readonly bundleId: string;
|
|
32
|
+
/** With `too_large`: the bound the answer ran past, in bytes. */
|
|
33
|
+
readonly maximum?: number;
|
|
34
|
+
constructor(problem: HostedExportProblem, bundleId: string, message: string, options?: {
|
|
35
|
+
cause?: unknown;
|
|
36
|
+
maximum?: number;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/** True when `error` is a {@link HostedExportError}, with `problem` when one is named. */
|
|
40
|
+
export declare function isHostedExportError(error: unknown, problem?: HostedExportProblem): error is HostedExportError;
|
|
41
|
+
export interface DownloadExportOptions {
|
|
42
|
+
/** Aborting it stops the download; it is thrown as the signal's reason. The client's own signal applies too. */
|
|
43
|
+
readonly signal?: AbortSignal;
|
|
44
|
+
}
|
|
45
|
+
/** What a download needs of a client: its carrier, its sync prefix and its signal. A `within` client qualifies the bundle. */
|
|
46
|
+
export type HostedExportClient = Pick<HostedClient, "carrier" | "prefix" | "signal">;
|
|
47
|
+
/**
|
|
48
|
+
* The verified portable export of `bundleId` at its latest confirmed revision: every document,
|
|
49
|
+
* reserved file and blob, byte for byte, read whole and checked against the host's digest
|
|
50
|
+
* manifests before it is returned.
|
|
51
|
+
*
|
|
52
|
+
* A host that pages the export answers it a page at a time; each page is verified as it arrives,
|
|
53
|
+
* checked against the pages before it, and the pages are joined (`ExportPageChain`). A host from
|
|
54
|
+
* before paging refuses the paged request as `invalid_input`, and the whole bundle is then read as
|
|
55
|
+
* one archive. A bundle that changes between pages (`concurrent_change`) is read again from its
|
|
56
|
+
* first page, up to three attempts. A page the host was too busy for (`backend_unavailable`, its
|
|
57
|
+
* one export slot) or stopped part way is asked for once more.
|
|
58
|
+
*
|
|
59
|
+
* Failures are typed:
|
|
60
|
+
* - `HostedCarrierError` — transport (the request may not have been answered);
|
|
61
|
+
* - `HostedRouteNotServed` — a host from before the export route;
|
|
62
|
+
* - `RemoteError` — the host's refusal, with its code and status (`bundle_not_found`,
|
|
63
|
+
* `result_too_large`, `validation_failed`, `unauthenticated` and so on);
|
|
64
|
+
* - `ExportArchiveError` — the verifier refused the archive (`incomplete` when the host stopped it);
|
|
65
|
+
* - {@link HostedExportError} — the answer stopped part way, ran past {@link MAX_EXPORT_BYTES}, or
|
|
66
|
+
* the bundle kept changing;
|
|
67
|
+
* - the signal's reason, once `options.signal` or the client's signal aborts.
|
|
68
|
+
*/
|
|
69
|
+
export declare function downloadExport(client: HostedExportClient, bundleId: string, options?: DownloadExportOptions): Promise<VerifiedExport>;
|
|
70
|
+
//# sourceMappingURL=node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/hosted-client/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAElG;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAS,CAAC;AASvC;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,WAAW,GAAG,gBAAgB,CAAC;AAE7E,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,SAAkB,IAAI,uBAAuB;IAC7C,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;gBACd,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;CAMjI;AAED,0FAA0F;AAC1F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,KAAK,IAAI,iBAAiB,CAE7G;AAED,MAAM,WAAW,qBAAqB;IACpC,gHAAgH;IAChH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,8HAA8H;AAC9H,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAErF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,cAAc,CAAC,CA4C/I"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@superbee/core/hosted-client/node`: the hosted client's Node-only half, a supported public API
|
|
3
|
+
* under core's normal versioning. It downloads a hosted bundle's portable export
|
|
4
|
+
* (`<prefix>/export`) and verifies it with `@superbee/core/portable-export`, whose digests and
|
|
5
|
+
* file placement need Node, so it is kept off the browser-safe `@superbee/core/hosted-client`.
|
|
6
|
+
*
|
|
7
|
+
* The result is a verified export or a typed failure, never files: a stopped, tampered or
|
|
8
|
+
* oversized export is refused before anything is returned, and placing the verified entries is
|
|
9
|
+
* the caller's (`materializeExport`, or its own staging).
|
|
10
|
+
*/
|
|
11
|
+
import { ExportArchiveError, ExportPageChain, MAX_EXPORT_BYTES, verifyExport, } from "../portable-export.js";
|
|
12
|
+
import { RemoteError } from "../remote-error.js";
|
|
13
|
+
import { HostedRouteNotServed } from "./errors.js";
|
|
14
|
+
export { ExportArchiveError, MAX_EXPORT_BYTES } from "../portable-export.js";
|
|
15
|
+
/**
|
|
16
|
+
* The host's export window: an export (or one page of a paged one) is answered within 60 s. A
|
|
17
|
+
* client that downloads exports should be created with at least this `deadlineMs`; the default
|
|
18
|
+
* 15 s read deadline would cut a large bundle.
|
|
19
|
+
*/
|
|
20
|
+
export const EXPORT_WINDOW_MS = 60_000;
|
|
21
|
+
/** How many times a paged export starts again from its first page when the bundle moves under it. */
|
|
22
|
+
const PAGED_EXPORT_ATTEMPTS = 3;
|
|
23
|
+
/** The pause before each restart, so a burst of writes can settle (with jitter). */
|
|
24
|
+
const PAGED_EXPORT_RESTART_MS = [500, 1500];
|
|
25
|
+
/** The pause before asking for a page again after a busy host or a page it stopped part way. */
|
|
26
|
+
const PAGE_RETRY_MS = 1000;
|
|
27
|
+
export class HostedExportError extends Error {
|
|
28
|
+
name = "HostedExportError";
|
|
29
|
+
problem;
|
|
30
|
+
bundleId;
|
|
31
|
+
/** With `too_large`: the bound the answer ran past, in bytes. */
|
|
32
|
+
maximum;
|
|
33
|
+
constructor(problem, bundleId, message, options = {}) {
|
|
34
|
+
super(message, options.cause === undefined ? undefined : { cause: options.cause });
|
|
35
|
+
this.problem = problem;
|
|
36
|
+
this.bundleId = bundleId;
|
|
37
|
+
if (options.maximum !== undefined)
|
|
38
|
+
this.maximum = options.maximum;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** True when `error` is a {@link HostedExportError}, with `problem` when one is named. */
|
|
42
|
+
export function isHostedExportError(error, problem) {
|
|
43
|
+
return error instanceof HostedExportError && (problem === undefined || error.problem === problem);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The verified portable export of `bundleId` at its latest confirmed revision: every document,
|
|
47
|
+
* reserved file and blob, byte for byte, read whole and checked against the host's digest
|
|
48
|
+
* manifests before it is returned.
|
|
49
|
+
*
|
|
50
|
+
* A host that pages the export answers it a page at a time; each page is verified as it arrives,
|
|
51
|
+
* checked against the pages before it, and the pages are joined (`ExportPageChain`). A host from
|
|
52
|
+
* before paging refuses the paged request as `invalid_input`, and the whole bundle is then read as
|
|
53
|
+
* one archive. A bundle that changes between pages (`concurrent_change`) is read again from its
|
|
54
|
+
* first page, up to three attempts. A page the host was too busy for (`backend_unavailable`, its
|
|
55
|
+
* one export slot) or stopped part way is asked for once more.
|
|
56
|
+
*
|
|
57
|
+
* Failures are typed:
|
|
58
|
+
* - `HostedCarrierError` — transport (the request may not have been answered);
|
|
59
|
+
* - `HostedRouteNotServed` — a host from before the export route;
|
|
60
|
+
* - `RemoteError` — the host's refusal, with its code and status (`bundle_not_found`,
|
|
61
|
+
* `result_too_large`, `validation_failed`, `unauthenticated` and so on);
|
|
62
|
+
* - `ExportArchiveError` — the verifier refused the archive (`incomplete` when the host stopped it);
|
|
63
|
+
* - {@link HostedExportError} — the answer stopped part way, ran past {@link MAX_EXPORT_BYTES}, or
|
|
64
|
+
* the bundle kept changing;
|
|
65
|
+
* - the signal's reason, once `options.signal` or the client's signal aborts.
|
|
66
|
+
*/
|
|
67
|
+
export async function downloadExport(client, bundleId, options = {}) {
|
|
68
|
+
if (typeof bundleId !== "string" || bundleId === "")
|
|
69
|
+
throw new TypeError("an export names its bundle");
|
|
70
|
+
const signal = options.signal ? AbortSignal.any([client.signal, options.signal]) : client.signal;
|
|
71
|
+
const download = { client, bundleId, signal, route: `${client.prefix}/export` };
|
|
72
|
+
signal.throwIfAborted();
|
|
73
|
+
for (let attempt = 1;; attempt += 1) {
|
|
74
|
+
const chain = new ExportPageChain();
|
|
75
|
+
let bytes = 0;
|
|
76
|
+
let cursor;
|
|
77
|
+
let moved = false;
|
|
78
|
+
for (;;) {
|
|
79
|
+
let page;
|
|
80
|
+
for (let tries = 1; page === undefined; tries += 1) {
|
|
81
|
+
const answer = await exportAnswer(download, { bundleId, paged: true, ...(cursor !== undefined ? { cursor } : {}) });
|
|
82
|
+
// Only the very first request can meet a host from before paging.
|
|
83
|
+
if (answer.refused === "invalid_input" && cursor === undefined && attempt === 1)
|
|
84
|
+
return await wholeExport(download);
|
|
85
|
+
if (answer.refused === "concurrent_change") {
|
|
86
|
+
moved = true;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
if (answer.refused !== undefined)
|
|
91
|
+
throw refusal(download, answer);
|
|
92
|
+
page = verifyExport(await readArchive(download, answer.ok, MAX_EXPORT_BYTES - bytes), bundleId, { paged: true });
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
signal.throwIfAborted();
|
|
96
|
+
const again = isHostedExportError(error, "stopped") ||
|
|
97
|
+
(error instanceof ExportArchiveError && error.problem === "incomplete") ||
|
|
98
|
+
(answer.refused === "backend_unavailable" && answer.status >= 500);
|
|
99
|
+
if (!again || tries >= 2)
|
|
100
|
+
throw error;
|
|
101
|
+
await pause(PAGE_RETRY_MS, signal);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (moved)
|
|
105
|
+
break;
|
|
106
|
+
bytes += page.bytes;
|
|
107
|
+
cursor = chain.add(page);
|
|
108
|
+
if (cursor === undefined)
|
|
109
|
+
return chain.joined();
|
|
110
|
+
}
|
|
111
|
+
if (attempt >= PAGED_EXPORT_ATTEMPTS) {
|
|
112
|
+
throw new HostedExportError("source_changed", bundleId, `'${bundleId}' kept changing while it was exported (${attempt} attempts)`);
|
|
113
|
+
}
|
|
114
|
+
const base = PAGED_EXPORT_RESTART_MS[attempt - 1];
|
|
115
|
+
await pause(Math.round(base / 2 + (Math.random() * base) / 2), signal);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** One export request's answer: the archive's body, or the refusal code the host answered. */
|
|
119
|
+
async function exportAnswer({ client, signal, route }, input) {
|
|
120
|
+
signal.throwIfAborted();
|
|
121
|
+
let answer;
|
|
122
|
+
try {
|
|
123
|
+
answer = await client.carrier.stream(route, input, signal);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
signal.throwIfAborted();
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
if (!answer.ok)
|
|
130
|
+
return { refused: refusalCode(answer.body) ?? "RUNTIME", status: answer.status, body: answer.body };
|
|
131
|
+
return { ok: answer.body };
|
|
132
|
+
}
|
|
133
|
+
/** The whole bundle as one archive (a host from before paged export). */
|
|
134
|
+
async function wholeExport(download) {
|
|
135
|
+
const answer = await exportAnswer(download, { bundleId: download.bundleId });
|
|
136
|
+
if (answer.refused !== undefined)
|
|
137
|
+
throw refusal(download, answer);
|
|
138
|
+
return verifyExport(await readArchive(download, answer.ok, MAX_EXPORT_BYTES), download.bundleId);
|
|
139
|
+
}
|
|
140
|
+
function refusalCode(body) {
|
|
141
|
+
const error = body?.error;
|
|
142
|
+
if (typeof error === "string")
|
|
143
|
+
return error;
|
|
144
|
+
const code = error?.code;
|
|
145
|
+
return typeof code === "string" ? code : undefined;
|
|
146
|
+
}
|
|
147
|
+
/** The typed error a refused export is: the family's unknown-route answer, or the host's refusal. */
|
|
148
|
+
function refusal({ route }, answer) {
|
|
149
|
+
if (answer.status === 404 && isUnknownRoute(answer.body))
|
|
150
|
+
return new HostedRouteNotServed(route);
|
|
151
|
+
return new RemoteError(`hosted export answered ${answer.status}`, answer.refused, answer.status);
|
|
152
|
+
}
|
|
153
|
+
/** The sync family's answer to a route it does not have: `404 {"error":"not_found"}`, nothing else. */
|
|
154
|
+
function isUnknownRoute(body) {
|
|
155
|
+
return typeof body === "object" && body !== null && !Array.isArray(body) && Object.keys(body).length === 1 && body.error === "not_found";
|
|
156
|
+
}
|
|
157
|
+
/** One archive's body, read whole and bounded by `budget` (what the export may still hold). */
|
|
158
|
+
async function readArchive({ bundleId, signal }, body, budget) {
|
|
159
|
+
const reader = body.getReader();
|
|
160
|
+
const chunks = [];
|
|
161
|
+
let size = 0;
|
|
162
|
+
const onAbort = () => void reader.cancel(signal.reason).catch(() => { });
|
|
163
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
164
|
+
try {
|
|
165
|
+
for (;;) {
|
|
166
|
+
let part;
|
|
167
|
+
try {
|
|
168
|
+
part = await reader.read();
|
|
169
|
+
}
|
|
170
|
+
catch (cause) {
|
|
171
|
+
signal.throwIfAborted();
|
|
172
|
+
throw new HostedExportError("stopped", bundleId, `the export of '${bundleId}' stopped part way`, { cause });
|
|
173
|
+
}
|
|
174
|
+
signal.throwIfAborted();
|
|
175
|
+
if (part.done)
|
|
176
|
+
break;
|
|
177
|
+
size += part.value.byteLength;
|
|
178
|
+
if (size > budget) {
|
|
179
|
+
throw new HostedExportError("too_large", bundleId, `the export of '${bundleId}' is larger than ${MAX_EXPORT_BYTES} bytes`, { maximum: MAX_EXPORT_BYTES });
|
|
180
|
+
}
|
|
181
|
+
chunks.push(part.value);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
signal.removeEventListener("abort", onAbort);
|
|
186
|
+
void reader.cancel().catch(() => { });
|
|
187
|
+
}
|
|
188
|
+
const archive = new Uint8Array(size);
|
|
189
|
+
let offset = 0;
|
|
190
|
+
for (const chunk of chunks) {
|
|
191
|
+
archive.set(chunk, offset);
|
|
192
|
+
offset += chunk.byteLength;
|
|
193
|
+
}
|
|
194
|
+
return archive;
|
|
195
|
+
}
|
|
196
|
+
/** A pause the signal cuts short (its reason thrown), leaving no timer behind either way. */
|
|
197
|
+
function pause(ms, signal) {
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
if (signal.aborted) {
|
|
200
|
+
reject(signal.reason);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const onAbort = () => {
|
|
204
|
+
clearTimeout(timer);
|
|
205
|
+
reject(signal.reason);
|
|
206
|
+
};
|
|
207
|
+
const timer = setTimeout(() => {
|
|
208
|
+
signal.removeEventListener("abort", onAbort);
|
|
209
|
+
resolve();
|
|
210
|
+
}, ms);
|
|
211
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/hosted-client/node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** True for a workspace slug as the host reports it. */
|
|
2
|
+
export declare function isWorkspaceSlug(value: unknown): value is string;
|
|
3
|
+
export interface HostedBundleReference {
|
|
4
|
+
/** The workspace the reference names, or null for a bare id. */
|
|
5
|
+
readonly slug: string | null;
|
|
6
|
+
readonly bundleId: string;
|
|
7
|
+
}
|
|
8
|
+
/** The reference a string names, or null when it is neither a hosted bundle id nor `<slug>/<id>`. */
|
|
9
|
+
export declare function parseHostedBundleReference(value: string): HostedBundleReference | null;
|
|
10
|
+
/** The reference's spelling: the bare id, or `<slug>/<bundle-id>`. */
|
|
11
|
+
export declare function hostedBundleReferenceText(reference: HostedBundleReference): string;
|
|
12
|
+
//# sourceMappingURL=reference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../../src/hosted-client/reference.ts"],"names":[],"mappings":"AAYA,wDAAwD;AACxD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE/D;AAED,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,qGAAqG;AACrG,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAOtF;AAED,sEAAsE;AACtE,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,qBAAqB,GAAG,MAAM,CAElF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// A hosted bundle reference: how a person, a command and the host's bundle list name one hosted
|
|
2
|
+
// bundle. `<bundle-id>` names it when one of the person's workspaces holds that id;
|
|
3
|
+
// `<workspace-slug>/<bundle-id>` names the workspace too, for an id more than one of them holds.
|
|
4
|
+
// The slug is the workspace's own (the first label of its host, as `whoami` reports it), resolved
|
|
5
|
+
// by the host among the person's own workspaces. The bundle id part is held to the one rule
|
|
6
|
+
// `isHostedBundleId` states, so a reference never carries an id a bare one could not.
|
|
7
|
+
import { isHostedBundleId } from "../dependencies.js";
|
|
8
|
+
/** One lowercase DNS label: the host's workspace slug grammar. */
|
|
9
|
+
const SLUG = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
10
|
+
/** True for a workspace slug as the host reports it. */
|
|
11
|
+
export function isWorkspaceSlug(value) {
|
|
12
|
+
return typeof value === "string" && SLUG.test(value);
|
|
13
|
+
}
|
|
14
|
+
/** The reference a string names, or null when it is neither a hosted bundle id nor `<slug>/<id>`. */
|
|
15
|
+
export function parseHostedBundleReference(value) {
|
|
16
|
+
const at = value.indexOf("/");
|
|
17
|
+
const slug = at < 0 ? null : value.slice(0, at);
|
|
18
|
+
const bundleId = at < 0 ? value : value.slice(at + 1);
|
|
19
|
+
if (slug !== null && !SLUG.test(slug))
|
|
20
|
+
return null;
|
|
21
|
+
if (!isHostedBundleId(bundleId))
|
|
22
|
+
return null;
|
|
23
|
+
return { slug, bundleId };
|
|
24
|
+
}
|
|
25
|
+
/** The reference's spelling: the bare id, or `<slug>/<bundle-id>`. */
|
|
26
|
+
export function hostedBundleReferenceText(reference) {
|
|
27
|
+
return reference.slug === null ? reference.bundleId : `${reference.slug}/${reference.bundleId}`;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../../src/hosted-client/reference.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,oFAAoF;AACpF,iGAAiG;AACjG,kGAAkG;AAClG,4FAA4F;AAC5F,sFAAsF;AAEtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,kEAAkE;AAClE,MAAM,IAAI,GAAG,wCAAwC,CAAC;AAEtD,wDAAwD;AACxD,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvD,CAAC;AAQD,qGAAqG;AACrG,MAAM,UAAU,0BAA0B,CAAC,KAAa;IACtD,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACtD,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,yBAAyB,CAAC,SAAgC;IACxE,OAAO,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;AAClG,CAAC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { type HostedCarrier, type HostedCapabilities, type HostedReadAdapter, type HostedReadRoutes, type WriteErrorCode } from "../hosted-transport/index.js";
|
|
2
|
+
import type { Version } from "../types.js";
|
|
3
|
+
import { type OperationState } from "../uncertain-write.js";
|
|
4
|
+
/** What one write asks: a create of an absent document, or a replace at exactly `expectedVersion`. */
|
|
5
|
+
export type HostedWriteInput = {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly document: string;
|
|
8
|
+
readonly expectedVersion: Version;
|
|
9
|
+
readonly expectAbsent?: never;
|
|
10
|
+
} | {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly document: string;
|
|
13
|
+
readonly expectAbsent: true;
|
|
14
|
+
readonly expectedVersion?: never;
|
|
15
|
+
};
|
|
16
|
+
export interface HostedWriteOptions {
|
|
17
|
+
/**
|
|
18
|
+
* The request identity to send under, a lowercase UUID v4. Default: a fresh one. Pass the
|
|
19
|
+
* identity of a write this client's intent store holds to confirm it again: the same write
|
|
20
|
+
* resumes under that identity (nothing new is applied), and a different write is refused.
|
|
21
|
+
*/
|
|
22
|
+
readonly requestId?: string;
|
|
23
|
+
/** Ends this write's requests; an abort after sending leaves the outcome unknown. */
|
|
24
|
+
readonly signal?: AbortSignal;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A recorded write, everything its outcome lookup needs to rebuild the exact request: the
|
|
28
|
+
* operation, the bundle (and the workspace it was named in), the document and its digest, the
|
|
29
|
+
* precondition, the request identity and the binding.
|
|
30
|
+
*/
|
|
31
|
+
export interface HostedWriteIntent {
|
|
32
|
+
readonly requestId: string;
|
|
33
|
+
/** The client binding (`X-Superbee-Checkout`) the write and every lookup of it carry. */
|
|
34
|
+
readonly binding: string;
|
|
35
|
+
readonly bundleId: string;
|
|
36
|
+
/** The workspace slug the bundle was named in (`within`), or null. */
|
|
37
|
+
readonly workspace: string | null;
|
|
38
|
+
readonly operation: "create" | "replace";
|
|
39
|
+
readonly documentId: string;
|
|
40
|
+
/** The whole serialized document, as sent. */
|
|
41
|
+
readonly document: string;
|
|
42
|
+
/** `sha256:<hex>` of the document's UTF-8 bytes. */
|
|
43
|
+
readonly digest: Version;
|
|
44
|
+
/** The version replaced, or null for a create. */
|
|
45
|
+
readonly expectedVersion: Version | null;
|
|
46
|
+
/** The bundle's OKF edition the document was parsed under, or null when the bundle names none. */
|
|
47
|
+
readonly okfVersion: string | null;
|
|
48
|
+
/** When the intent was recorded (ISO instant): its age decides whether absence is still evidence. */
|
|
49
|
+
readonly createdAt: string;
|
|
50
|
+
/** Submissions made or about to leave; a non-zero count starts any later delivery at the lookup. */
|
|
51
|
+
readonly attempts: number;
|
|
52
|
+
readonly state: OperationState;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Where a client keeps its writes until they settle. The default is in memory
|
|
56
|
+
* ({@link createMemoryIntentStore}); a service that must recover a write across restarts passes
|
|
57
|
+
* a durable one. `put` replaces the record under its request identity; a settled write is
|
|
58
|
+
* deleted, and a write whose outcome is unknown stays for `lookupWrite` and `settleWrite`.
|
|
59
|
+
* `list`, when the store has it, yields every record it holds, so a service restarting with a
|
|
60
|
+
* durable store finds its unsettled writes (`heldWrites`).
|
|
61
|
+
*/
|
|
62
|
+
export interface HostedIntentStore {
|
|
63
|
+
put(intent: HostedWriteIntent): Promise<void> | void;
|
|
64
|
+
get(requestId: string): Promise<HostedWriteIntent | undefined> | HostedWriteIntent | undefined;
|
|
65
|
+
delete(requestId: string): Promise<void> | void;
|
|
66
|
+
list?(): AsyncIterable<HostedWriteIntent>;
|
|
67
|
+
}
|
|
68
|
+
/** An in-memory {@link HostedIntentStore}: records live as long as the store. */
|
|
69
|
+
export declare function createMemoryIntentStore(): HostedIntentStore;
|
|
70
|
+
/** The code of {@link HostedIntentsNotListable}. */
|
|
71
|
+
export declare const INTENTS_NOT_LISTABLE = "INTENTS_NOT_LISTABLE";
|
|
72
|
+
/** `heldWrites` was asked of a client whose intent store has no `list`. */
|
|
73
|
+
export declare class HostedIntentsNotListable extends Error {
|
|
74
|
+
readonly code = "INTENTS_NOT_LISTABLE";
|
|
75
|
+
constructor();
|
|
76
|
+
}
|
|
77
|
+
/** A refusal's code: the host's own (`validation_failed`, ...) or one the client names. */
|
|
78
|
+
export type HostedWriteRefusalCode = "AUTH_REQUIRED" | "PERMISSION_DENIED" | "REQUEST_CAPACITY_PRINCIPAL" | "REQUEST_CAPACITY_BUNDLE"
|
|
79
|
+
/** The host serves this bundle no identified writes. */
|
|
80
|
+
| "read_only" | "unsupported_operation" | WriteErrorCode | (string & {});
|
|
81
|
+
interface WriteResultBase {
|
|
82
|
+
readonly requestId: string;
|
|
83
|
+
readonly documentId: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A write's settled answer, or `unknown`. A conflict is final for this request identity: nothing
|
|
87
|
+
* was written, and a further attempt is the caller's decision, as a new write.
|
|
88
|
+
*/
|
|
89
|
+
export type HostedWriteResult = (WriteResultBase & {
|
|
90
|
+
readonly status: "committed";
|
|
91
|
+
readonly version: Version;
|
|
92
|
+
})
|
|
93
|
+
/**
|
|
94
|
+
* The document is not at the expected version (or, for a create, exists): `currentVersion` is
|
|
95
|
+
* the version the host serves, or null when it serves none. `tombstone` names the deletion a
|
|
96
|
+
* create of a deleted id ran into, when the host named one.
|
|
97
|
+
*/
|
|
98
|
+
| (WriteResultBase & {
|
|
99
|
+
readonly status: "conflict";
|
|
100
|
+
readonly reason: "version_conflict";
|
|
101
|
+
readonly currentVersion: Version | null;
|
|
102
|
+
readonly tombstone?: Version;
|
|
103
|
+
})
|
|
104
|
+
/** Another write to the bundle overlapped this one past the host's own retries; nothing was applied. */
|
|
105
|
+
| (WriteResultBase & {
|
|
106
|
+
readonly status: "conflict";
|
|
107
|
+
readonly reason: "concurrent_change";
|
|
108
|
+
readonly message: string;
|
|
109
|
+
}) | (WriteResultBase & {
|
|
110
|
+
readonly status: "refused";
|
|
111
|
+
readonly code: HostedWriteRefusalCode;
|
|
112
|
+
readonly message: string;
|
|
113
|
+
})
|
|
114
|
+
/** The host may or may not hold the write. `lookupWrite` or `settleWrite` asks again later. */
|
|
115
|
+
| (WriteResultBase & {
|
|
116
|
+
readonly status: "unknown";
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* What `lookupWrite` and `settleWrite` answer: a write's result, or `unrecorded` when the intent
|
|
120
|
+
* store holds no write under the identity (never recorded, or already settled and deleted).
|
|
121
|
+
*/
|
|
122
|
+
export type HostedWriteLookupResult = HostedWriteResult | {
|
|
123
|
+
readonly status: "unrecorded";
|
|
124
|
+
readonly requestId: string;
|
|
125
|
+
};
|
|
126
|
+
/** What a write needs from its client: the carrier for a workspace, the routes and the store. */
|
|
127
|
+
export interface HostedWriteContext {
|
|
128
|
+
readonly binding: string;
|
|
129
|
+
readonly store: HostedIntentStore;
|
|
130
|
+
/** One chain per request identity in flight, shared by a client and its `within` clients. */
|
|
131
|
+
readonly inFlight: Map<string, Promise<unknown>>;
|
|
132
|
+
readonly prefix: string;
|
|
133
|
+
readonly workspace: string | null;
|
|
134
|
+
readonly signal: AbortSignal;
|
|
135
|
+
/** The wait between outcome lookups (default 250 ms). */
|
|
136
|
+
readonly lookupDelayMs?: number;
|
|
137
|
+
/** Each bundle's capabilities as writes use them, shared by a client and its `within` clients. */
|
|
138
|
+
readonly capabilities: HostedCapabilitiesCache;
|
|
139
|
+
carrierFor(workspace: string | null): HostedCarrier;
|
|
140
|
+
readRoutes: HostedReadRoutes;
|
|
141
|
+
}
|
|
142
|
+
/** The capabilities a write uses, from one answer: the flags and bounds, and the edition its root declares. */
|
|
143
|
+
interface WriteSideAnswer {
|
|
144
|
+
readonly capabilities: HostedCapabilities;
|
|
145
|
+
readonly okfVersion: "0.1" | "0.2" | null;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* One bundle's write side: a reader of its own (never the public `reader()`, whose held answer
|
|
149
|
+
* is checked against heads answers) and its one capabilities answer, in flight or arrived.
|
|
150
|
+
*/
|
|
151
|
+
interface WriteSide {
|
|
152
|
+
readonly reader: HostedReadAdapter;
|
|
153
|
+
readonly answer: Promise<WriteSideAnswer>;
|
|
154
|
+
/** When the answer arrived, by the cache's clock; undefined while it is in flight. */
|
|
155
|
+
answeredAt: number | undefined;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Each bundle's write side, keyed by the workspace the bundle is named in and its id, and held
|
|
159
|
+
* for `ttlMs` after its answer arrives. A `ttlMs` of 0 holds nothing: every write reads anew.
|
|
160
|
+
*/
|
|
161
|
+
export interface HostedCapabilitiesCache {
|
|
162
|
+
readonly ttlMs: number;
|
|
163
|
+
readonly now: () => number;
|
|
164
|
+
readonly entries: Map<string, WriteSide>;
|
|
165
|
+
}
|
|
166
|
+
/** The default time a bundle's capabilities answer serves writes: 60 s. */
|
|
167
|
+
export declare const DEFAULT_CAPABILITIES_TTL_MS = 60000;
|
|
168
|
+
export declare function createCapabilitiesCache(ttlMs?: number, now?: () => number): HostedCapabilitiesCache;
|
|
169
|
+
/** `HostedClient.write`. */
|
|
170
|
+
export declare function hostedWrite(context: HostedWriteContext, bundleId: string, input: HostedWriteInput, options?: HostedWriteOptions): Promise<HostedWriteResult>;
|
|
171
|
+
/**
|
|
172
|
+
* `HostedClient.lookupWrite`: what the host recorded for a held write, by one outcome lookup under
|
|
173
|
+
* the identity and binding it was sent with. It never sends the write: a host that holds no
|
|
174
|
+
* outcome yet (absent or pending), or a lookup that fails, is `unknown`.
|
|
175
|
+
*/
|
|
176
|
+
export declare function hostedLookupWrite(context: HostedWriteContext, requestId: string, options?: {
|
|
177
|
+
signal?: AbortSignal;
|
|
178
|
+
}): Promise<HostedWriteLookupResult>;
|
|
179
|
+
/**
|
|
180
|
+
* `HostedClient.settleWrite`: settle a held write. It looks the identity up under the binding it
|
|
181
|
+
* was sent with; when the host never recorded it (within the retention window it serves), it
|
|
182
|
+
* delivers that same identity once more, as the write itself would have. An unclear lookup is
|
|
183
|
+
* `unknown` again. A bundle the host serves no writes for is only looked up.
|
|
184
|
+
*/
|
|
185
|
+
export declare function hostedSettleWrite(context: HostedWriteContext, requestId: string, options?: {
|
|
186
|
+
signal?: AbortSignal;
|
|
187
|
+
}): Promise<HostedWriteLookupResult>;
|
|
188
|
+
/** `HostedClient.heldWrites`: every write the intent store holds. */
|
|
189
|
+
export declare function hostedHeldWrites(context: HostedWriteContext): Promise<HostedWriteIntent[]>;
|
|
190
|
+
export {};
|
|
191
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/hosted-client/write.ts"],"names":[],"mappings":"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"}
|