wire-mesh-core 3.0.1 → 3.1.0
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/dist/adapters/memory-storage.d.cts +1 -1
- package/dist/adapters/memory-storage.d.mts +1 -1
- package/dist/adapters/node-fs-storage.d.cts +1 -1
- package/dist/adapters/node-fs-storage.d.mts +1 -1
- package/dist/domain/bulk.d.cts +1 -1
- package/dist/domain/bulk.d.mts +1 -1
- package/dist/domain/data-sync.d.cts +1 -1
- package/dist/domain/data-sync.d.mts +1 -1
- package/dist/domain/hub-mailbox.cjs +81 -0
- package/dist/domain/hub-mailbox.d.cts +29 -0
- package/dist/domain/hub-mailbox.d.mts +29 -0
- package/dist/domain/hub-mailbox.mjs +79 -0
- package/dist/domain/notice-board.d.cts +1 -1
- package/dist/domain/notice-board.d.mts +1 -1
- package/dist/domain/relay-hub.cjs +14 -0
- package/dist/domain/relay-hub.d.cts +10 -0
- package/dist/domain/relay-hub.d.mts +10 -0
- package/dist/domain/relay-hub.mjs +14 -0
- package/dist/ports/storage.d.cts +2 -9
- package/dist/ports/storage.d.mts +2 -9
- package/dist/storage-B403CRyu.d.cts +10 -0
- package/dist/storage-B403CRyu.d.mts +10 -0
- package/package.json +5 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KeyValueStorage } from "../
|
|
1
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
|
|
2
2
|
//#region src/adapters/memory-storage.d.ts
|
|
3
3
|
/** An in-process KeyValueStorage backed by a Map -- for tests and single-process nodes; a real deployment substitutes a persistent adapter behind the same contract without touching anything that depends on the port. Not declared `async`: every operation is genuinely synchronous under the hood, so the contract's Promise return is satisfied directly via Promise.resolve() rather than an async function with no await in its body. */
|
|
4
4
|
export declare function createMemoryStorage(): KeyValueStorage;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KeyValueStorage } from "../
|
|
1
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.mjs";
|
|
2
2
|
//#region src/adapters/memory-storage.d.ts
|
|
3
3
|
/** An in-process KeyValueStorage backed by a Map -- for tests and single-process nodes; a real deployment substitutes a persistent adapter behind the same contract without touching anything that depends on the port. Not declared `async`: every operation is genuinely synchronous under the hood, so the contract's Promise return is satisfied directly via Promise.resolve() rather than an async function with no await in its body. */
|
|
4
4
|
export declare function createMemoryStorage(): KeyValueStorage;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KeyValueStorage } from "../
|
|
1
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
|
|
2
2
|
//#region src/adapters/node-fs-storage.d.ts
|
|
3
3
|
export interface NodeFsStorageOptions {
|
|
4
4
|
/** Directory to store entries under. Created on first write if it doesn't already exist. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KeyValueStorage } from "../
|
|
1
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.mjs";
|
|
2
2
|
//#region src/adapters/node-fs-storage.d.ts
|
|
3
3
|
export interface NodeFsStorageOptions {
|
|
4
4
|
/** Directory to store entries under. Created on first write if it doesn't already exist. */
|
package/dist/domain/bulk.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-DCDae3z4.cjs";
|
|
2
|
-
import { KeyValueStorage } from "../
|
|
2
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
|
|
3
3
|
import { t as Connection } from "../transport-CfW7fsGK.cjs";
|
|
4
4
|
import { IncomingManageRequest, MeshSession } from "./mesh-session.cjs";
|
|
5
5
|
//#region src/domain/bulk.d.ts
|
package/dist/domain/bulk.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-DCDae3z4.mjs";
|
|
2
|
-
import { KeyValueStorage } from "../
|
|
2
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.mjs";
|
|
3
3
|
import { t as Connection } from "../transport-iLBxIkRS.mjs";
|
|
4
4
|
import { IncomingManageRequest, MeshSession } from "./mesh-session.mjs";
|
|
5
5
|
//#region src/domain/bulk.d.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-DCDae3z4.cjs";
|
|
2
|
-
import { KeyValueStorage } from "../
|
|
2
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
|
|
3
3
|
import { t as IdentityPort } from "../identity-DVCNuFLG.cjs";
|
|
4
4
|
//#region src/domain/data-sync.d.ts
|
|
5
5
|
export interface DataSyncOptions {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-DCDae3z4.mjs";
|
|
2
|
-
import { KeyValueStorage } from "../
|
|
2
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.mjs";
|
|
3
3
|
import { t as IdentityPort } from "../identity-DcaYgjXT.mjs";
|
|
4
4
|
//#region src/domain/data-sync.d.ts
|
|
5
5
|
export interface DataSyncOptions {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_domain_device_id = require("./device-id.cjs");
|
|
3
|
+
const require_domain_data_sync = require("./data-sync.cjs");
|
|
4
|
+
//#region src/domain/hub-mailbox.ts
|
|
5
|
+
/** The data frames a mailbox answers. */
|
|
6
|
+
function isDataFrame(frame) {
|
|
7
|
+
return frame.type === "data-have" || frame.type === "data-request" || frame.type === "data-entries";
|
|
8
|
+
}
|
|
9
|
+
const LOG_COUNT_KEY = "mailbox/log-count";
|
|
10
|
+
function logBytesKey(peer) {
|
|
11
|
+
return `mailbox/${require_domain_device_id.deviceIdToHex(peer)}/bytes`;
|
|
12
|
+
}
|
|
13
|
+
function encodeCount(value) {
|
|
14
|
+
return new TextEncoder().encode(String(value));
|
|
15
|
+
}
|
|
16
|
+
async function readCount(storage, key) {
|
|
17
|
+
const raw = await storage.get(key);
|
|
18
|
+
return raw === void 0 ? 0 : Number(new TextDecoder().decode(raw));
|
|
19
|
+
}
|
|
20
|
+
function sameDevice(a, b) {
|
|
21
|
+
return require_domain_device_id.deviceIdToHex(a) === require_domain_device_id.deviceIdToHex(b);
|
|
22
|
+
}
|
|
23
|
+
function createMailbox(options) {
|
|
24
|
+
const { storage, limits } = options;
|
|
25
|
+
async function handleHave(sender, frame, refuse) {
|
|
26
|
+
if (!sameDevice(sender, frame.peer)) {
|
|
27
|
+
refuse("not-the-owner");
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (await require_domain_data_sync.headSeqFor(storage, frame.peer) === 0) {
|
|
31
|
+
if (await readCount(storage, LOG_COUNT_KEY) >= limits.maxLogs) {
|
|
32
|
+
refuse("log-limit");
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return require_domain_data_sync.handleDataHave(storage, frame);
|
|
37
|
+
}
|
|
38
|
+
async function handleEntries(sender, frame, refuse) {
|
|
39
|
+
if (!sameDevice(sender, frame.peer)) {
|
|
40
|
+
refuse("not-the-owner");
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
if (frame.entries.some((entry) => entry.length > limits.maxEntryBytes)) {
|
|
44
|
+
refuse("size-limit");
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const held = await readCount(storage, logBytesKey(frame.peer));
|
|
48
|
+
const added = frame.entries.reduce((sum, entry) => sum + entry.length, 0);
|
|
49
|
+
if (held + added > limits.maxLogBytes) {
|
|
50
|
+
refuse("entry-limit");
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const isNewLog = await require_domain_data_sync.headSeqFor(storage, frame.peer) === 0;
|
|
54
|
+
if (isNewLog && await readCount(storage, LOG_COUNT_KEY) >= limits.maxLogs) {
|
|
55
|
+
refuse("log-limit");
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (!(await require_domain_data_sync.handleDataEntries(storage, frame)).ok) {
|
|
59
|
+
refuse("gap");
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
await storage.set(logBytesKey(frame.peer), encodeCount(held + added));
|
|
63
|
+
if (isNewLog && frame.entries.length > 0) await storage.set(LOG_COUNT_KEY, encodeCount(await readCount(storage, LOG_COUNT_KEY) + 1));
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return { async handle(sender, frame, onRefused) {
|
|
67
|
+
const refuse = (reason) => {
|
|
68
|
+
onRefused?.(reason);
|
|
69
|
+
};
|
|
70
|
+
if (sender === void 0) {
|
|
71
|
+
refuse("unregistered-sender");
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (frame.type === "data-have") return handleHave(sender, frame, refuse);
|
|
75
|
+
if (frame.type === "data-entries") return handleEntries(sender, frame, refuse);
|
|
76
|
+
return require_domain_data_sync.handleDataRequest(storage, frame, limits.readBatch);
|
|
77
|
+
} };
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
exports.createMailbox = createMailbox;
|
|
81
|
+
exports.isDataFrame = isDataFrame;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-DCDae3z4.cjs";
|
|
2
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
|
|
3
|
+
//#region src/domain/hub-mailbox.d.ts
|
|
4
|
+
export interface MailboxLimits {
|
|
5
|
+
/** How many devices' logs the mailbox will hold at once. */
|
|
6
|
+
readonly maxLogs: number;
|
|
7
|
+
/** How many bytes of entries one log may hold in total. */
|
|
8
|
+
readonly maxLogBytes: number;
|
|
9
|
+
/** How large one entry may be. */
|
|
10
|
+
readonly maxEntryBytes: number;
|
|
11
|
+
/** How many entries one reply carries at most; a longer log takes more rounds. */
|
|
12
|
+
readonly readBatch: number;
|
|
13
|
+
}
|
|
14
|
+
export interface MailboxOptions {
|
|
15
|
+
readonly storage: KeyValueStorage;
|
|
16
|
+
readonly limits: Readonly<MailboxLimits>;
|
|
17
|
+
}
|
|
18
|
+
/** Called for a data frame the mailbox refuses, so the host can report why; the sender is given no reply, since data-domain.cddl defines no error frame. */
|
|
19
|
+
export type MailboxRefusalReason = "not-the-owner" | "unregistered-sender" | "log-limit" | "size-limit" | "entry-limit" | "gap";
|
|
20
|
+
export interface Mailbox {
|
|
21
|
+
/**
|
|
22
|
+
* Handles one data frame from a connection. `sender` is the device the hub has verified that connection to be, or undefined when it has not gossiped one. Returns the frame to send back, or null for none. `onRefused` is told when the frame was refused and why.
|
|
23
|
+
*/
|
|
24
|
+
handle: (sender: DeviceId | undefined, frame: Readonly<DataHaveFrame | DataRequestFrame | DataEntriesFrame>, onRefused?: (reason: MailboxRefusalReason) => void) => Promise<Frame | null>;
|
|
25
|
+
}
|
|
26
|
+
/** The data frames a mailbox answers. */
|
|
27
|
+
export declare function isDataFrame(frame: Readonly<Frame>): frame is DataHaveFrame | DataRequestFrame | DataEntriesFrame;
|
|
28
|
+
export declare function createMailbox(options: Readonly<MailboxOptions>): Mailbox;
|
|
29
|
+
//#endregion
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-DCDae3z4.mjs";
|
|
2
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.mjs";
|
|
3
|
+
//#region src/domain/hub-mailbox.d.ts
|
|
4
|
+
export interface MailboxLimits {
|
|
5
|
+
/** How many devices' logs the mailbox will hold at once. */
|
|
6
|
+
readonly maxLogs: number;
|
|
7
|
+
/** How many bytes of entries one log may hold in total. */
|
|
8
|
+
readonly maxLogBytes: number;
|
|
9
|
+
/** How large one entry may be. */
|
|
10
|
+
readonly maxEntryBytes: number;
|
|
11
|
+
/** How many entries one reply carries at most; a longer log takes more rounds. */
|
|
12
|
+
readonly readBatch: number;
|
|
13
|
+
}
|
|
14
|
+
export interface MailboxOptions {
|
|
15
|
+
readonly storage: KeyValueStorage;
|
|
16
|
+
readonly limits: Readonly<MailboxLimits>;
|
|
17
|
+
}
|
|
18
|
+
/** Called for a data frame the mailbox refuses, so the host can report why; the sender is given no reply, since data-domain.cddl defines no error frame. */
|
|
19
|
+
export type MailboxRefusalReason = "not-the-owner" | "unregistered-sender" | "log-limit" | "size-limit" | "entry-limit" | "gap";
|
|
20
|
+
export interface Mailbox {
|
|
21
|
+
/**
|
|
22
|
+
* Handles one data frame from a connection. `sender` is the device the hub has verified that connection to be, or undefined when it has not gossiped one. Returns the frame to send back, or null for none. `onRefused` is told when the frame was refused and why.
|
|
23
|
+
*/
|
|
24
|
+
handle: (sender: DeviceId | undefined, frame: Readonly<DataHaveFrame | DataRequestFrame | DataEntriesFrame>, onRefused?: (reason: MailboxRefusalReason) => void) => Promise<Frame | null>;
|
|
25
|
+
}
|
|
26
|
+
/** The data frames a mailbox answers. */
|
|
27
|
+
export declare function isDataFrame(frame: Readonly<Frame>): frame is DataHaveFrame | DataRequestFrame | DataEntriesFrame;
|
|
28
|
+
export declare function createMailbox(options: Readonly<MailboxOptions>): Mailbox;
|
|
29
|
+
//#endregion
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { deviceIdToHex } from "./device-id.mjs";
|
|
2
|
+
import { handleDataEntries, handleDataHave, handleDataRequest, headSeqFor } from "./data-sync.mjs";
|
|
3
|
+
//#region src/domain/hub-mailbox.ts
|
|
4
|
+
/** The data frames a mailbox answers. */
|
|
5
|
+
function isDataFrame(frame) {
|
|
6
|
+
return frame.type === "data-have" || frame.type === "data-request" || frame.type === "data-entries";
|
|
7
|
+
}
|
|
8
|
+
const LOG_COUNT_KEY = "mailbox/log-count";
|
|
9
|
+
function logBytesKey(peer) {
|
|
10
|
+
return `mailbox/${deviceIdToHex(peer)}/bytes`;
|
|
11
|
+
}
|
|
12
|
+
function encodeCount(value) {
|
|
13
|
+
return new TextEncoder().encode(String(value));
|
|
14
|
+
}
|
|
15
|
+
async function readCount(storage, key) {
|
|
16
|
+
const raw = await storage.get(key);
|
|
17
|
+
return raw === void 0 ? 0 : Number(new TextDecoder().decode(raw));
|
|
18
|
+
}
|
|
19
|
+
function sameDevice(a, b) {
|
|
20
|
+
return deviceIdToHex(a) === deviceIdToHex(b);
|
|
21
|
+
}
|
|
22
|
+
function createMailbox(options) {
|
|
23
|
+
const { storage, limits } = options;
|
|
24
|
+
async function handleHave(sender, frame, refuse) {
|
|
25
|
+
if (!sameDevice(sender, frame.peer)) {
|
|
26
|
+
refuse("not-the-owner");
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (await headSeqFor(storage, frame.peer) === 0) {
|
|
30
|
+
if (await readCount(storage, LOG_COUNT_KEY) >= limits.maxLogs) {
|
|
31
|
+
refuse("log-limit");
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return handleDataHave(storage, frame);
|
|
36
|
+
}
|
|
37
|
+
async function handleEntries(sender, frame, refuse) {
|
|
38
|
+
if (!sameDevice(sender, frame.peer)) {
|
|
39
|
+
refuse("not-the-owner");
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (frame.entries.some((entry) => entry.length > limits.maxEntryBytes)) {
|
|
43
|
+
refuse("size-limit");
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const held = await readCount(storage, logBytesKey(frame.peer));
|
|
47
|
+
const added = frame.entries.reduce((sum, entry) => sum + entry.length, 0);
|
|
48
|
+
if (held + added > limits.maxLogBytes) {
|
|
49
|
+
refuse("entry-limit");
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const isNewLog = await headSeqFor(storage, frame.peer) === 0;
|
|
53
|
+
if (isNewLog && await readCount(storage, LOG_COUNT_KEY) >= limits.maxLogs) {
|
|
54
|
+
refuse("log-limit");
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
if (!(await handleDataEntries(storage, frame)).ok) {
|
|
58
|
+
refuse("gap");
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
await storage.set(logBytesKey(frame.peer), encodeCount(held + added));
|
|
62
|
+
if (isNewLog && frame.entries.length > 0) await storage.set(LOG_COUNT_KEY, encodeCount(await readCount(storage, LOG_COUNT_KEY) + 1));
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return { async handle(sender, frame, onRefused) {
|
|
66
|
+
const refuse = (reason) => {
|
|
67
|
+
onRefused?.(reason);
|
|
68
|
+
};
|
|
69
|
+
if (sender === void 0) {
|
|
70
|
+
refuse("unregistered-sender");
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
if (frame.type === "data-have") return handleHave(sender, frame, refuse);
|
|
74
|
+
if (frame.type === "data-entries") return handleEntries(sender, frame, refuse);
|
|
75
|
+
return handleDataRequest(storage, frame, limits.readBatch);
|
|
76
|
+
} };
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { createMailbox, isDataFrame };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-DCDae3z4.cjs";
|
|
2
|
-
import { KeyValueStorage } from "../
|
|
2
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
|
|
3
3
|
import { t as IdentityPort } from "../identity-DVCNuFLG.cjs";
|
|
4
4
|
import { t as Clock } from "../clock-DiSx-WKM.cjs";
|
|
5
5
|
import { a as RevocationCheck } from "../tokens-DqFu7iMX.cjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-DCDae3z4.mjs";
|
|
2
|
-
import { KeyValueStorage } from "../
|
|
2
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.mjs";
|
|
3
3
|
import { t as IdentityPort } from "../identity-DcaYgjXT.mjs";
|
|
4
4
|
import { t as Clock } from "../clock-DiSx-WKM.mjs";
|
|
5
5
|
import { a as RevocationCheck } from "../tokens-CBiSYuzp.mjs";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_domain_peer_advert = require("./peer-advert.cjs");
|
|
3
3
|
const require_domain_advert_extension_policy = require("./advert-extension-policy.cjs");
|
|
4
|
+
const require_domain_hub_mailbox = require("./hub-mailbox.cjs");
|
|
4
5
|
//#region src/domain/relay-hub.ts
|
|
5
6
|
const HEX_RADIX = 16;
|
|
6
7
|
const HEX_DIGITS_PER_BYTE = 2;
|
|
@@ -192,6 +193,19 @@ function createRelayHub(options) {
|
|
|
192
193
|
});
|
|
193
194
|
return;
|
|
194
195
|
}
|
|
196
|
+
if (options.mailbox !== void 0 && require_domain_hub_mailbox.isDataFrame(frame)) {
|
|
197
|
+
const sender = connectionDevice.get(connection);
|
|
198
|
+
const reply = await options.mailbox.handle(sender, frame, (reason) => {
|
|
199
|
+
options.onMailboxRefused?.({
|
|
200
|
+
device: sender,
|
|
201
|
+
reason
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
if (reply !== null) try {
|
|
205
|
+
await connection.send(reply);
|
|
206
|
+
} catch {}
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
195
209
|
if (frame.type === "ping") {
|
|
196
210
|
try {
|
|
197
211
|
await connection.send({ type: "pong" });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { D as DeviceId, N as Frame, et as PeerAdvert } from "../protocol-DCDae3z4.cjs";
|
|
2
2
|
import { t as Connection } from "../transport-CfW7fsGK.cjs";
|
|
3
3
|
import { AdvertExtensionPolicy } from "./advert-extension-policy.cjs";
|
|
4
|
+
import { Mailbox, MailboxRefusalReason } from "./hub-mailbox.cjs";
|
|
4
5
|
import { PeerAdvertVerifier } from "./peer-advert.cjs";
|
|
5
6
|
//#region src/domain/relay-hub.d.ts
|
|
6
7
|
/**
|
|
@@ -36,6 +37,15 @@ export interface RelayHubOptions {
|
|
|
36
37
|
readonly extensionPolicy?: AdvertExtensionPolicy;
|
|
37
38
|
/** Called with each advert refused by extensionPolicy, so the host can report it; the advert's sender is given no reply, since the transport spec defines none. */
|
|
38
39
|
readonly onAdvertRefused?: (refusal: Readonly<AdvertRefusal>) => void;
|
|
40
|
+
/**
|
|
41
|
+
* The announcer role: a mailbox that holds other devices' `core/data` logs while they are offline (hub-mailbox.ts). Absent, data frames sent to this hub are ignored, as they always were.
|
|
42
|
+
*/
|
|
43
|
+
readonly mailbox?: Mailbox;
|
|
44
|
+
/** Called with each data frame the mailbox refused and why, so the host can report it; the sender is given no reply. */
|
|
45
|
+
readonly onMailboxRefused?: (refusal: Readonly<{
|
|
46
|
+
device: DeviceId | undefined;
|
|
47
|
+
reason: MailboxRefusalReason;
|
|
48
|
+
}>) => void;
|
|
39
49
|
/** Called whenever the value exportConnection returns for a connection changes: it gossiped an advert, gained or lost a pairing, or had one of its adverts taken over by another connection. A host whose own instance can be torn down while its connections stay open (the Cloudflare hub's hibernating Durable Object) reads the new value back with exportConnection, persists it against the connection, and hands it to a later instance through restoreConnections. */
|
|
40
50
|
readonly onConnectionStateChanged?: (connection: Readonly<Connection>) => void;
|
|
41
51
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { D as DeviceId, N as Frame, et as PeerAdvert } from "../protocol-DCDae3z4.mjs";
|
|
2
2
|
import { t as Connection } from "../transport-iLBxIkRS.mjs";
|
|
3
3
|
import { AdvertExtensionPolicy } from "./advert-extension-policy.mjs";
|
|
4
|
+
import { Mailbox, MailboxRefusalReason } from "./hub-mailbox.mjs";
|
|
4
5
|
import { PeerAdvertVerifier } from "./peer-advert.mjs";
|
|
5
6
|
//#region src/domain/relay-hub.d.ts
|
|
6
7
|
/**
|
|
@@ -36,6 +37,15 @@ export interface RelayHubOptions {
|
|
|
36
37
|
readonly extensionPolicy?: AdvertExtensionPolicy;
|
|
37
38
|
/** Called with each advert refused by extensionPolicy, so the host can report it; the advert's sender is given no reply, since the transport spec defines none. */
|
|
38
39
|
readonly onAdvertRefused?: (refusal: Readonly<AdvertRefusal>) => void;
|
|
40
|
+
/**
|
|
41
|
+
* The announcer role: a mailbox that holds other devices' `core/data` logs while they are offline (hub-mailbox.ts). Absent, data frames sent to this hub are ignored, as they always were.
|
|
42
|
+
*/
|
|
43
|
+
readonly mailbox?: Mailbox;
|
|
44
|
+
/** Called with each data frame the mailbox refused and why, so the host can report it; the sender is given no reply. */
|
|
45
|
+
readonly onMailboxRefused?: (refusal: Readonly<{
|
|
46
|
+
device: DeviceId | undefined;
|
|
47
|
+
reason: MailboxRefusalReason;
|
|
48
|
+
}>) => void;
|
|
39
49
|
/** Called whenever the value exportConnection returns for a connection changes: it gossiped an advert, gained or lost a pairing, or had one of its adverts taken over by another connection. A host whose own instance can be torn down while its connections stay open (the Cloudflare hub's hibernating Durable Object) reads the new value back with exportConnection, persists it against the connection, and hands it to a later instance through restoreConnections. */
|
|
40
50
|
readonly onConnectionStateChanged?: (connection: Readonly<Connection>) => void;
|
|
41
51
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { verifyPeerAdvert } from "./peer-advert.mjs";
|
|
2
2
|
import { checkAdvertExtensions } from "./advert-extension-policy.mjs";
|
|
3
|
+
import { isDataFrame } from "./hub-mailbox.mjs";
|
|
3
4
|
//#region src/domain/relay-hub.ts
|
|
4
5
|
const HEX_RADIX = 16;
|
|
5
6
|
const HEX_DIGITS_PER_BYTE = 2;
|
|
@@ -191,6 +192,19 @@ function createRelayHub(options) {
|
|
|
191
192
|
});
|
|
192
193
|
return;
|
|
193
194
|
}
|
|
195
|
+
if (options.mailbox !== void 0 && isDataFrame(frame)) {
|
|
196
|
+
const sender = connectionDevice.get(connection);
|
|
197
|
+
const reply = await options.mailbox.handle(sender, frame, (reason) => {
|
|
198
|
+
options.onMailboxRefused?.({
|
|
199
|
+
device: sender,
|
|
200
|
+
reason
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
if (reply !== null) try {
|
|
204
|
+
await connection.send(reply);
|
|
205
|
+
} catch {}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
194
208
|
if (frame.type === "ping") {
|
|
195
209
|
try {
|
|
196
210
|
await connection.send({ type: "pong" });
|
package/dist/ports/storage.d.cts
CHANGED
|
@@ -1,9 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
get: (key: string) => Promise<Uint8Array<ArrayBuffer> | undefined>;
|
|
4
|
-
set: (key: string, value: Uint8Array<ArrayBuffer>) => Promise<void>;
|
|
5
|
-
delete: (key: string) => Promise<void>;
|
|
6
|
-
/** Keys with the given prefix, in no particular order. */
|
|
7
|
-
keys: (prefix: string) => Promise<string[]>;
|
|
8
|
-
}
|
|
9
|
-
//#endregion
|
|
1
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
|
|
2
|
+
export { KeyValueStorage };
|
package/dist/ports/storage.d.mts
CHANGED
|
@@ -1,9 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
get: (key: string) => Promise<Uint8Array<ArrayBuffer> | undefined>;
|
|
4
|
-
set: (key: string, value: Uint8Array<ArrayBuffer>) => Promise<void>;
|
|
5
|
-
delete: (key: string) => Promise<void>;
|
|
6
|
-
/** Keys with the given prefix, in no particular order. */
|
|
7
|
-
keys: (prefix: string) => Promise<string[]>;
|
|
8
|
-
}
|
|
9
|
-
//#endregion
|
|
1
|
+
import { t as KeyValueStorage } from "../storage-B403CRyu.mjs";
|
|
2
|
+
export { KeyValueStorage };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/ports/storage.d.ts
|
|
2
|
+
interface KeyValueStorage {
|
|
3
|
+
get: (key: string) => Promise<Uint8Array<ArrayBuffer> | undefined>;
|
|
4
|
+
set: (key: string, value: Uint8Array<ArrayBuffer>) => Promise<void>;
|
|
5
|
+
delete: (key: string) => Promise<void>;
|
|
6
|
+
/** Keys with the given prefix, in no particular order. */
|
|
7
|
+
keys: (prefix: string) => Promise<string[]>;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { KeyValueStorage as t };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/ports/storage.d.ts
|
|
2
|
+
interface KeyValueStorage {
|
|
3
|
+
get: (key: string) => Promise<Uint8Array<ArrayBuffer> | undefined>;
|
|
4
|
+
set: (key: string, value: Uint8Array<ArrayBuffer>) => Promise<void>;
|
|
5
|
+
delete: (key: string) => Promise<void>;
|
|
6
|
+
/** Keys with the given prefix, in no particular order. */
|
|
7
|
+
keys: (prefix: string) => Promise<string[]>;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { KeyValueStorage as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wire-mesh-core",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"cbor2": "2.3.0",
|
|
6
6
|
"cddl.js": "1.0.1",
|
|
@@ -118,6 +118,10 @@
|
|
|
118
118
|
"import": "./dist/domain/handshake.mjs",
|
|
119
119
|
"require": "./dist/domain/handshake.cjs"
|
|
120
120
|
},
|
|
121
|
+
"./domain/hub-mailbox": {
|
|
122
|
+
"import": "./dist/domain/hub-mailbox.mjs",
|
|
123
|
+
"require": "./dist/domain/hub-mailbox.cjs"
|
|
124
|
+
},
|
|
121
125
|
"./domain/mesh-session": {
|
|
122
126
|
"import": "./dist/domain/mesh-session.mjs",
|
|
123
127
|
"require": "./dist/domain/mesh-session.cjs"
|