@peers-app/peers-sdk 0.21.2 → 0.21.3
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/contracts/__tests__/contract-resolvers.test.js +94 -0
- package/dist/contracts/__tests__/host-contract-transport.test.d.ts +1 -0
- package/dist/contracts/__tests__/host-contract-transport.test.js +51 -0
- package/dist/contracts/__tests__/system-contracts.test.js +11 -2
- package/dist/contracts/contract-resolvers.d.ts +20 -0
- package/dist/contracts/contract-resolvers.js +57 -0
- package/dist/contracts/host-contract-transport.d.ts +38 -0
- package/dist/contracts/host-contract-transport.js +107 -0
- package/dist/contracts/index.d.ts +3 -1
- package/dist/contracts/index.js +23 -2
- package/dist/contracts/system/index.d.ts +2 -0
- package/dist/contracts/system/index.js +16 -0
- package/dist/contracts/system/network-contracts.d.ts +231 -0
- package/dist/contracts/system/network-contracts.js +192 -0
- package/dist/system-ids.d.ts +4 -0
- package/dist/system-ids.js +5 -1
- package/package.json +1 -1
|
@@ -146,3 +146,97 @@ describe("Self-trusted contract caller authorization", () => {
|
|
|
146
146
|
router.dispose();
|
|
147
147
|
});
|
|
148
148
|
});
|
|
149
|
+
describe("local user-context contract routing", () => {
|
|
150
|
+
function setupLocalRouter() {
|
|
151
|
+
const userId = (0, utils_1.newid)();
|
|
152
|
+
const groupId = (0, utils_1.newid)();
|
|
153
|
+
const personalContext = { dataContextId: userId };
|
|
154
|
+
const groupContext = { dataContextId: groupId };
|
|
155
|
+
const getDataContext = jest.fn((dataContextId) => {
|
|
156
|
+
if (dataContextId === userId)
|
|
157
|
+
return personalContext;
|
|
158
|
+
if (dataContextId === groupId)
|
|
159
|
+
return groupContext;
|
|
160
|
+
throw new Error("unexpected data context");
|
|
161
|
+
});
|
|
162
|
+
const userContext = {
|
|
163
|
+
userId,
|
|
164
|
+
userDataContext: personalContext,
|
|
165
|
+
groupDataContexts: new Map([[groupId, groupContext]]),
|
|
166
|
+
groupIds: jest.fn(() => [groupId]),
|
|
167
|
+
getDataContext,
|
|
168
|
+
};
|
|
169
|
+
const contractId = (0, utils_1.newid)();
|
|
170
|
+
(0, index_1.registerContractResolver)(contractId, 1, ({ dataContext }) => ({
|
|
171
|
+
contractId,
|
|
172
|
+
version: 1,
|
|
173
|
+
tools: {
|
|
174
|
+
inspect: {
|
|
175
|
+
tool: {
|
|
176
|
+
toolId: (0, utils_1.newid)(),
|
|
177
|
+
name: "inspect",
|
|
178
|
+
usageDescription: "Return the authorized route.",
|
|
179
|
+
inputSchema: { type: "simple", fields: [] },
|
|
180
|
+
outputSchema: { type: "simple", fields: [] },
|
|
181
|
+
code: "",
|
|
182
|
+
packageId: (0, utils_1.newid)(),
|
|
183
|
+
},
|
|
184
|
+
toolFn: () => dataContext.dataContextId,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
}));
|
|
188
|
+
const [consumerTransport, providerTransport] = (0, index_1.inProcessTransportPair)();
|
|
189
|
+
return {
|
|
190
|
+
consumerTransport,
|
|
191
|
+
contractId,
|
|
192
|
+
getDataContext,
|
|
193
|
+
groupId,
|
|
194
|
+
providerTransport,
|
|
195
|
+
userContext,
|
|
196
|
+
userId,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const makeToolCall = (contractId, dataContextId) => ({
|
|
200
|
+
contractId,
|
|
201
|
+
version: 1,
|
|
202
|
+
member: "tool",
|
|
203
|
+
name: "inspect",
|
|
204
|
+
operation: "run",
|
|
205
|
+
args: [],
|
|
206
|
+
dataContextId,
|
|
207
|
+
});
|
|
208
|
+
it("registers synchronously and waits for a lazily loaded user context", async () => {
|
|
209
|
+
const setup = setupLocalRouter();
|
|
210
|
+
let resolveUserContext;
|
|
211
|
+
const userContextPromise = new Promise((resolve) => {
|
|
212
|
+
resolveUserContext = resolve;
|
|
213
|
+
});
|
|
214
|
+
const router = (0, index_1.createLocalUserContextContractProviderRouter)(setup.providerTransport, {
|
|
215
|
+
getUserContext: () => userContextPromise,
|
|
216
|
+
});
|
|
217
|
+
const result = setup.consumerTransport.emit(index_1.CONTRACT_REQUEST_CHANNEL, makeToolCall(setup.contractId));
|
|
218
|
+
resolveUserContext(setup.userContext);
|
|
219
|
+
await expect(result).resolves.toBe(setup.userId);
|
|
220
|
+
router.dispose();
|
|
221
|
+
});
|
|
222
|
+
it("routes known groups and rejects unknown contexts without creating them", async () => {
|
|
223
|
+
const setup = setupLocalRouter();
|
|
224
|
+
const router = (0, index_1.createLocalUserContextContractProviderRouter)(setup.providerTransport, {
|
|
225
|
+
getUserContext: async () => setup.userContext,
|
|
226
|
+
});
|
|
227
|
+
await expect(setup.consumerTransport.emit(index_1.CONTRACT_REQUEST_CHANNEL, makeToolCall(setup.contractId, setup.groupId))).resolves.toBe(setup.groupId);
|
|
228
|
+
const unknownId = (0, utils_1.newid)();
|
|
229
|
+
await expect(setup.consumerTransport.emit(index_1.CONTRACT_REQUEST_CHANNEL, makeToolCall(setup.contractId, unknownId))).rejects.toThrow("not available locally");
|
|
230
|
+
expect(setup.getDataContext).not.toHaveBeenCalledWith(unknownId);
|
|
231
|
+
router.dispose();
|
|
232
|
+
});
|
|
233
|
+
it("enforces an optional contract allowlist before resolving a provider", async () => {
|
|
234
|
+
const setup = setupLocalRouter();
|
|
235
|
+
const router = (0, index_1.createLocalUserContextContractProviderRouter)(setup.providerTransport, {
|
|
236
|
+
getUserContext: async () => setup.userContext,
|
|
237
|
+
allowedContractIds: new Set([(0, utils_1.newid)()]),
|
|
238
|
+
});
|
|
239
|
+
await expect(setup.consumerTransport.emit(index_1.CONTRACT_REQUEST_CHANNEL, makeToolCall(setup.contractId))).rejects.toThrow("contract");
|
|
240
|
+
router.dispose();
|
|
241
|
+
});
|
|
242
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../index");
|
|
4
|
+
describe("host contract transport", () => {
|
|
5
|
+
const disposers = [];
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
while (disposers.length > 0) {
|
|
8
|
+
disposers.pop()?.();
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
it("publishes registration lifecycle and clears the active transport", () => {
|
|
12
|
+
const [transport] = (0, index_1.inProcessTransportPair)();
|
|
13
|
+
const values = [];
|
|
14
|
+
const unsubscribe = (0, index_1.subscribeHostContractTransport)((value) => values.push(value));
|
|
15
|
+
const dispose = (0, index_1.registerHostContractTransport)(transport);
|
|
16
|
+
disposers.push(dispose);
|
|
17
|
+
expect((0, index_1.getHostContractTransport)()).toBe(transport);
|
|
18
|
+
dispose();
|
|
19
|
+
unsubscribe();
|
|
20
|
+
expect((0, index_1.getHostContractTransport)()).toBeUndefined();
|
|
21
|
+
expect(values).toEqual([undefined, transport, undefined]);
|
|
22
|
+
});
|
|
23
|
+
it("does not let a stale registration disposer clear its replacement", () => {
|
|
24
|
+
const [first] = (0, index_1.inProcessTransportPair)();
|
|
25
|
+
const [second] = (0, index_1.inProcessTransportPair)();
|
|
26
|
+
const disposeFirst = (0, index_1.registerHostContractTransport)(first);
|
|
27
|
+
const disposeSecond = (0, index_1.registerHostContractTransport)(second);
|
|
28
|
+
disposers.push(disposeFirst, disposeSecond);
|
|
29
|
+
disposeFirst();
|
|
30
|
+
expect((0, index_1.getHostContractTransport)()).toBe(second);
|
|
31
|
+
});
|
|
32
|
+
it("waits for a transport registered after startup", async () => {
|
|
33
|
+
const pending = (0, index_1.waitForHostContractTransport)();
|
|
34
|
+
const [transport] = (0, index_1.inProcessTransportPair)();
|
|
35
|
+
const dispose = (0, index_1.registerHostContractTransport)(transport);
|
|
36
|
+
disposers.push(dispose);
|
|
37
|
+
await expect(pending).resolves.toBe(transport);
|
|
38
|
+
});
|
|
39
|
+
it("rejects when no transport arrives before timeoutMs", async () => {
|
|
40
|
+
jest.useFakeTimers();
|
|
41
|
+
try {
|
|
42
|
+
const pending = (0, index_1.waitForHostContractTransport)({ timeoutMs: 25 });
|
|
43
|
+
const expectation = expect(pending).rejects.toThrow("Timed out waiting for host contract transport after 25ms");
|
|
44
|
+
await jest.advanceTimersByTimeAsync(25);
|
|
45
|
+
await expectation;
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
jest.useRealTimers();
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -8,11 +8,16 @@ const system_contracts_1 = require("../system-contracts");
|
|
|
8
8
|
// Populate the catalog with built-in system contracts.
|
|
9
9
|
require("../system");
|
|
10
10
|
describe("system contract catalog", () => {
|
|
11
|
-
it("self-registers
|
|
11
|
+
it("self-registers the built-in system contracts", () => {
|
|
12
12
|
const ids = (0, system_contracts_1.listSystemContracts)()
|
|
13
13
|
.map((entry) => entry.contractId)
|
|
14
14
|
.filter(Boolean);
|
|
15
|
-
expect(ids).toEqual(expect.arrayContaining([
|
|
15
|
+
expect(ids).toEqual(expect.arrayContaining([
|
|
16
|
+
system_ids_1.logsContractId,
|
|
17
|
+
system_ids_1.deviceOperationsContractId,
|
|
18
|
+
system_ids_1.networkDiagnosticsContractId,
|
|
19
|
+
system_ids_1.networkControlContractId,
|
|
20
|
+
]));
|
|
16
21
|
});
|
|
17
22
|
it("registers the Logs live resolver", async () => {
|
|
18
23
|
await new Promise((resolve) => queueMicrotask(resolve));
|
|
@@ -25,6 +30,10 @@ describe("system contract catalog", () => {
|
|
|
25
30
|
expect(registry.getProviderPackageId(system_ids_1.logsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
26
31
|
expect(registry.resolve(system_ids_1.deviceOperationsContractId, 1)?.name).toBe("System Device Operations");
|
|
27
32
|
expect(registry.getProviderPackageId(system_ids_1.deviceOperationsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
33
|
+
expect(registry.resolve(system_ids_1.networkDiagnosticsContractId, 1)?.name).toBe("System Network Diagnostics");
|
|
34
|
+
expect(registry.getProviderPackageId(system_ids_1.networkDiagnosticsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
35
|
+
expect(registry.resolve(system_ids_1.networkControlContractId, 1)?.name).toBe("System Network Control");
|
|
36
|
+
expect(registry.getProviderPackageId(system_ids_1.networkControlContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
28
37
|
});
|
|
29
38
|
it("registerSystemContract makes new contracts installable without loader changes", () => {
|
|
30
39
|
const fakeContractId = (0, utils_1.newid)();
|
|
@@ -30,6 +30,26 @@ export declare function getContractResolver(contractId: string, version: number)
|
|
|
30
30
|
* {@link TrustLevel.Self}. Unsigned discovery stubs and key mismatches fail closed.
|
|
31
31
|
*/
|
|
32
32
|
export declare function isSelfTrustedContractCaller(userContext: UserContext, remoteIdentity: ContractRemoteIdentity): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* Create a provider router for one authenticated UI-to-local-host session.
|
|
35
|
+
*
|
|
36
|
+
* The request listener is registered synchronously while user-context loading is
|
|
37
|
+
* deferred until each call. This prevents renderer startup from racing provider
|
|
38
|
+
* registration. Calls may target only the local user's personal context or a
|
|
39
|
+
* currently known group context; arbitrary valid IDs are rejected before
|
|
40
|
+
* `UserContext.getDataContext` can create a new context.
|
|
41
|
+
*
|
|
42
|
+
* This helper trusts the host transport's session authentication. It does not
|
|
43
|
+
* infer package-level authority from renderer-supplied data.
|
|
44
|
+
*
|
|
45
|
+
* @param transport Contract transport backed by an authenticated local session.
|
|
46
|
+
* @param opts.getUserContext Lazy accessor for the host's loaded user context.
|
|
47
|
+
* @param opts.allowedContractIds Optional contract allowlist for this session.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createLocalUserContextContractProviderRouter(transport: IContractTransport, opts: {
|
|
50
|
+
getUserContext: () => Promise<UserContext>;
|
|
51
|
+
allowedContractIds?: ReadonlySet<string>;
|
|
52
|
+
}): IContractProviderRouter;
|
|
33
53
|
/**
|
|
34
54
|
* Create the local-object provider router for one verified device connection.
|
|
35
55
|
*
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.registerContractResolver = registerContractResolver;
|
|
4
4
|
exports.getContractResolver = getContractResolver;
|
|
5
5
|
exports.isSelfTrustedContractCaller = isSelfTrustedContractCaller;
|
|
6
|
+
exports.createLocalUserContextContractProviderRouter = createLocalUserContextContractProviderRouter;
|
|
6
7
|
exports.createUserContextContractProviderRouter = createUserContextContractProviderRouter;
|
|
7
8
|
exports.handleContractCall = handleContractCall;
|
|
8
9
|
const user_permissions_1 = require("../data/user-permissions");
|
|
@@ -74,6 +75,62 @@ async function authorizeUserContextCall(call, userContext, remoteIdentity) {
|
|
|
74
75
|
context,
|
|
75
76
|
};
|
|
76
77
|
}
|
|
78
|
+
function getAuthorizedLocalDataContext(userContext, requestedId) {
|
|
79
|
+
const dataContextId = requestedId || userContext.userId;
|
|
80
|
+
if (dataContextId === userContext.userId) {
|
|
81
|
+
return userContext.userDataContext;
|
|
82
|
+
}
|
|
83
|
+
if (!userContext.groupIds().includes(dataContextId)) {
|
|
84
|
+
throw new Error(`Permission denied: data context '${dataContextId}' is not available locally`);
|
|
85
|
+
}
|
|
86
|
+
return userContext.getDataContext(dataContextId);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Create a provider router for one authenticated UI-to-local-host session.
|
|
90
|
+
*
|
|
91
|
+
* The request listener is registered synchronously while user-context loading is
|
|
92
|
+
* deferred until each call. This prevents renderer startup from racing provider
|
|
93
|
+
* registration. Calls may target only the local user's personal context or a
|
|
94
|
+
* currently known group context; arbitrary valid IDs are rejected before
|
|
95
|
+
* `UserContext.getDataContext` can create a new context.
|
|
96
|
+
*
|
|
97
|
+
* This helper trusts the host transport's session authentication. It does not
|
|
98
|
+
* infer package-level authority from renderer-supplied data.
|
|
99
|
+
*
|
|
100
|
+
* @param transport Contract transport backed by an authenticated local session.
|
|
101
|
+
* @param opts.getUserContext Lazy accessor for the host's loaded user context.
|
|
102
|
+
* @param opts.allowedContractIds Optional contract allowlist for this session.
|
|
103
|
+
*/
|
|
104
|
+
function createLocalUserContextContractProviderRouter(transport, opts) {
|
|
105
|
+
const { getUserContext, allowedContractIds } = opts;
|
|
106
|
+
return (0, contract_provider_router_1.createContractProviderRouter)(transport, {
|
|
107
|
+
authorizeCall: async (call) => {
|
|
108
|
+
if (allowedContractIds && !allowedContractIds.has(call.contractId)) {
|
|
109
|
+
throw new Error(`Permission denied: contract ${call.contractId} is not available locally`);
|
|
110
|
+
}
|
|
111
|
+
const userContext = await getUserContext();
|
|
112
|
+
const dataContext = getAuthorizedLocalDataContext(userContext, call.dataContextId);
|
|
113
|
+
const context = {
|
|
114
|
+
callerUserId: userContext.userId,
|
|
115
|
+
localUserId: userContext.userId,
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
dataContextId: dataContext.dataContextId,
|
|
119
|
+
context,
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
resolveEndpoint: async ({ contractId, version, dataContextId, context, notify }) => {
|
|
123
|
+
const userContext = await getUserContext();
|
|
124
|
+
const resolver = getContractResolver(contractId, version);
|
|
125
|
+
if (!resolver) {
|
|
126
|
+
throw new Error(`No contract provider registered for ${contractId} v${version}`);
|
|
127
|
+
}
|
|
128
|
+
const dataContext = getAuthorizedLocalDataContext(userContext, dataContextId);
|
|
129
|
+
const resolution = await resolver({ dataContext });
|
|
130
|
+
return (0, contract_proxy_1.createContractProviderEndpoint)(resolution, { context, notify });
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
77
134
|
/**
|
|
78
135
|
* Create the local-object provider router for one verified device connection.
|
|
79
136
|
*
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { IContractTransport } from "./contract-transport";
|
|
2
|
+
/** Listener notified whenever the active UI-to-host contract transport changes. */
|
|
3
|
+
export type HostContractTransportListener = (transport: IContractTransport | undefined) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Register the transport used by renderer code to call its trusted local host.
|
|
6
|
+
*
|
|
7
|
+
* A newer registration replaces the previous active transport. The returned
|
|
8
|
+
* disposer clears only its own registration, so disposing a stale Electron
|
|
9
|
+
* connection cannot remove a transport installed by a later reconnect.
|
|
10
|
+
*
|
|
11
|
+
* @param transport UI-side transport connected to the local host provider router.
|
|
12
|
+
* @returns A disposer for this exact registration.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerHostContractTransport(transport: IContractTransport): () => void;
|
|
15
|
+
/** Return the currently registered UI-to-host contract transport, if ready. */
|
|
16
|
+
export declare function getHostContractTransport(): IContractTransport | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Subscribe to UI-to-host contract transport lifecycle changes.
|
|
19
|
+
*
|
|
20
|
+
* The current value is delivered synchronously by default so a consumer owner
|
|
21
|
+
* can create or dispose its proxy immediately.
|
|
22
|
+
*
|
|
23
|
+
* @param listener Callback receiving the active transport or `undefined`.
|
|
24
|
+
* @param opts.emitCurrent Whether to deliver the current value immediately.
|
|
25
|
+
* @returns An idempotent unsubscribe function.
|
|
26
|
+
*/
|
|
27
|
+
export declare function subscribeHostContractTransport(listener: HostContractTransportListener, opts?: {
|
|
28
|
+
emitCurrent?: boolean;
|
|
29
|
+
}): () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Wait for the next available UI-to-host contract transport.
|
|
32
|
+
*
|
|
33
|
+
* @param opts.timeoutMs Optional deadline; rejects if no transport registers in time.
|
|
34
|
+
* @returns The current transport immediately, or the next registered transport.
|
|
35
|
+
*/
|
|
36
|
+
export declare function waitForHostContractTransport(opts?: {
|
|
37
|
+
timeoutMs?: number;
|
|
38
|
+
}): Promise<IContractTransport>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerHostContractTransport = registerHostContractTransport;
|
|
4
|
+
exports.getHostContractTransport = getHostContractTransport;
|
|
5
|
+
exports.subscribeHostContractTransport = subscribeHostContractTransport;
|
|
6
|
+
exports.waitForHostContractTransport = waitForHostContractTransport;
|
|
7
|
+
let activeRegistration;
|
|
8
|
+
const listeners = new Set();
|
|
9
|
+
function notifyListeners() {
|
|
10
|
+
const transport = activeRegistration?.transport;
|
|
11
|
+
for (const listener of [...listeners]) {
|
|
12
|
+
listener(transport);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Register the transport used by renderer code to call its trusted local host.
|
|
17
|
+
*
|
|
18
|
+
* A newer registration replaces the previous active transport. The returned
|
|
19
|
+
* disposer clears only its own registration, so disposing a stale Electron
|
|
20
|
+
* connection cannot remove a transport installed by a later reconnect.
|
|
21
|
+
*
|
|
22
|
+
* @param transport UI-side transport connected to the local host provider router.
|
|
23
|
+
* @returns A disposer for this exact registration.
|
|
24
|
+
*/
|
|
25
|
+
function registerHostContractTransport(transport) {
|
|
26
|
+
const registration = { id: Symbol("host-contract-transport"), transport };
|
|
27
|
+
activeRegistration = registration;
|
|
28
|
+
notifyListeners();
|
|
29
|
+
let disposed = false;
|
|
30
|
+
return () => {
|
|
31
|
+
if (disposed) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
disposed = true;
|
|
35
|
+
if (activeRegistration?.id === registration.id) {
|
|
36
|
+
activeRegistration = undefined;
|
|
37
|
+
notifyListeners();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Return the currently registered UI-to-host contract transport, if ready. */
|
|
42
|
+
function getHostContractTransport() {
|
|
43
|
+
return activeRegistration?.transport;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Subscribe to UI-to-host contract transport lifecycle changes.
|
|
47
|
+
*
|
|
48
|
+
* The current value is delivered synchronously by default so a consumer owner
|
|
49
|
+
* can create or dispose its proxy immediately.
|
|
50
|
+
*
|
|
51
|
+
* @param listener Callback receiving the active transport or `undefined`.
|
|
52
|
+
* @param opts.emitCurrent Whether to deliver the current value immediately.
|
|
53
|
+
* @returns An idempotent unsubscribe function.
|
|
54
|
+
*/
|
|
55
|
+
function subscribeHostContractTransport(listener, opts = {}) {
|
|
56
|
+
listeners.add(listener);
|
|
57
|
+
if (opts.emitCurrent !== false) {
|
|
58
|
+
listener(activeRegistration?.transport);
|
|
59
|
+
}
|
|
60
|
+
let subscribed = true;
|
|
61
|
+
return () => {
|
|
62
|
+
if (!subscribed) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
subscribed = false;
|
|
66
|
+
listeners.delete(listener);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Wait for the next available UI-to-host contract transport.
|
|
71
|
+
*
|
|
72
|
+
* @param opts.timeoutMs Optional deadline; rejects if no transport registers in time.
|
|
73
|
+
* @returns The current transport immediately, or the next registered transport.
|
|
74
|
+
*/
|
|
75
|
+
function waitForHostContractTransport(opts = {}) {
|
|
76
|
+
const current = getHostContractTransport();
|
|
77
|
+
if (current) {
|
|
78
|
+
return Promise.resolve(current);
|
|
79
|
+
}
|
|
80
|
+
const { timeoutMs } = opts;
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
let settled = false;
|
|
83
|
+
let timer;
|
|
84
|
+
const finish = (action) => {
|
|
85
|
+
if (settled) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
settled = true;
|
|
89
|
+
if (timer !== undefined) {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
}
|
|
92
|
+
unsubscribe();
|
|
93
|
+
action();
|
|
94
|
+
};
|
|
95
|
+
const unsubscribe = subscribeHostContractTransport((transport) => {
|
|
96
|
+
if (!transport) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
finish(() => resolve(transport));
|
|
100
|
+
}, { emitCurrent: false });
|
|
101
|
+
if (timeoutMs !== undefined) {
|
|
102
|
+
timer = setTimeout(() => {
|
|
103
|
+
finish(() => reject(new Error(`Timed out waiting for host contract transport after ${timeoutMs}ms`)));
|
|
104
|
+
}, timeoutMs);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -2,15 +2,17 @@ export { ContractBuilder, definePackage, PackageBuilder } from "./builder";
|
|
|
2
2
|
export { type ContractCallAuthorizer, type ContractProviderEndpointResolver, createContractProviderRouter, type IAuthorizedContractRoute, type IContractProviderEndpointRequest, type IContractProviderRouter, type IContractProviderRouterOptions, } from "./contract-provider-router";
|
|
3
3
|
export { ContractProviders, ContractProvidersTable, contractProvidersMetaData, contractProvidersSchema, type IContractProviderRecord, } from "./contract-providers.table";
|
|
4
4
|
export { CONTRACT_CALL_RPC, type ContractMemberType, type ContractNotificationSink, type ContractPermissionCheck, createContractConsumer, createContractProvider, createContractProviderEndpoint, createContractProviderSession, type IContractCall, type IContractCallContext, type IContractConsumer, type IContractConsumerBase, type IContractNotification, type IContractProviderEndpoint, type IContractProviderEndpointOptions, type IContractProviderSession, type IContractProviderSessionOptions, type IContractResolution, type IContractTableProxy, type ITableProxy, sameUserContractPermissionCheck, } from "./contract-proxy";
|
|
5
|
-
export { type ContractRemoteIdentity, type ContractResolver, createUserContextContractProviderRouter, getContractResolver, handleContractCall, isSelfTrustedContractCaller, registerContractResolver, } from "./contract-resolvers";
|
|
5
|
+
export { type ContractRemoteIdentity, type ContractResolver, createLocalUserContextContractProviderRouter, createUserContextContractProviderRouter, getContractResolver, handleContractCall, isSelfTrustedContractCaller, registerContractResolver, } from "./contract-resolvers";
|
|
6
6
|
export { CONTRACT_NOTIFY_CHANNEL, CONTRACT_REQUEST_CHANNEL, connectionContractTransport, type IContractTransport, type IDuplexEmitter, inProcessTransportPair, } from "./contract-transport";
|
|
7
7
|
export { Contracts, ContractsTable, contractsMetaData, contractsSchema, type IContractRecord, } from "./contracts.table";
|
|
8
8
|
export { createLocalContractConsumer } from "./create-local-consumer";
|
|
9
9
|
export { extractTableShape, extractToolShape, type IExtractableTableDef, type IExtractableToolInstance, setSchemaToFieldsFn, } from "./extract";
|
|
10
|
+
export { getHostContractTransport, type HostContractTransportListener, registerHostContractTransport, subscribeHostContractTransport, waitForHostContractTransport, } from "./host-contract-transport";
|
|
10
11
|
export { PersistentContractRegistry } from "./persistent-registry";
|
|
11
12
|
export { ContractRegistry } from "./registry";
|
|
12
13
|
export { DEVICE_OPERATIONS_CONTRACT_VERSION, DEVICE_OPERATIONS_MAX_QUERY_LENGTH, DEVICE_OPERATIONS_MAX_RESULT_BYTES, DEVICE_OPERATIONS_MAX_ROWS, DEVICE_OPERATIONS_MAX_TOOLS, type DeviceOperationCapability, deviceOperationsProviderPackageId, deviceOperationsToolIds, getDeviceOperationsContractDefinition, type IDeviceDatabaseQueryInput, type IDeviceDatabaseQueryResult, type IDeviceOperationStatus, type IDeviceToolListInput, type IDeviceToolLookupInput, type IDeviceToolLookupResult, type IDeviceToolRunInput, } from "./system/device-operations-contract";
|
|
13
14
|
export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./system/logs-contract";
|
|
15
|
+
export * from "./system/network-contracts";
|
|
14
16
|
export { type ISystemContractRegistration, installSystemContracts, listSystemContracts, registerSystemContract, } from "./system-contracts";
|
|
15
17
|
export type { IAlsoImplementsDeclaration, IConsumedContract, IConsumedContractHandle, IConsumedContractOptions, IContractDefinition, IContractEvent, IContractObservable, IContractTable, IContractTool, IPackageDefinitionResult, IResolvedContract, IValidationError, IValidationResult, } from "./types";
|
|
16
18
|
export { contractKey } from "./types";
|
package/dist/contracts/index.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.validateProviderSatisfiesContract = void 0;
|
|
17
|
+
exports.installSystemContracts = exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = exports.DEVICE_OPERATIONS_MAX_TOOLS = exports.DEVICE_OPERATIONS_MAX_ROWS = exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = exports.DEVICE_OPERATIONS_CONTRACT_VERSION = exports.ContractRegistry = exports.PersistentContractRegistry = exports.waitForHostContractTransport = exports.subscribeHostContractTransport = exports.registerHostContractTransport = exports.getHostContractTransport = exports.setSchemaToFieldsFn = exports.extractToolShape = exports.extractTableShape = exports.createLocalContractConsumer = exports.contractsSchema = exports.contractsMetaData = exports.ContractsTable = exports.Contracts = exports.inProcessTransportPair = exports.connectionContractTransport = exports.CONTRACT_REQUEST_CHANNEL = exports.CONTRACT_NOTIFY_CHANNEL = exports.registerContractResolver = exports.isSelfTrustedContractCaller = exports.handleContractCall = exports.getContractResolver = exports.createUserContextContractProviderRouter = exports.createLocalUserContextContractProviderRouter = exports.sameUserContractPermissionCheck = exports.createContractProviderSession = exports.createContractProviderEndpoint = exports.createContractProvider = exports.createContractConsumer = exports.CONTRACT_CALL_RPC = exports.contractProvidersSchema = exports.contractProvidersMetaData = exports.ContractProvidersTable = exports.ContractProviders = exports.createContractProviderRouter = exports.PackageBuilder = exports.definePackage = exports.ContractBuilder = void 0;
|
|
18
|
+
exports.validateProviderSatisfiesContract = exports.validateImmutability = exports.validateAlsoImplements = exports.contractKey = exports.registerSystemContract = exports.listSystemContracts = void 0;
|
|
5
19
|
var builder_1 = require("./builder");
|
|
6
20
|
Object.defineProperty(exports, "ContractBuilder", { enumerable: true, get: function () { return builder_1.ContractBuilder; } });
|
|
7
21
|
Object.defineProperty(exports, "definePackage", { enumerable: true, get: function () { return builder_1.definePackage; } });
|
|
@@ -21,6 +35,7 @@ Object.defineProperty(exports, "createContractProviderEndpoint", { enumerable: t
|
|
|
21
35
|
Object.defineProperty(exports, "createContractProviderSession", { enumerable: true, get: function () { return contract_proxy_1.createContractProviderSession; } });
|
|
22
36
|
Object.defineProperty(exports, "sameUserContractPermissionCheck", { enumerable: true, get: function () { return contract_proxy_1.sameUserContractPermissionCheck; } });
|
|
23
37
|
var contract_resolvers_1 = require("./contract-resolvers");
|
|
38
|
+
Object.defineProperty(exports, "createLocalUserContextContractProviderRouter", { enumerable: true, get: function () { return contract_resolvers_1.createLocalUserContextContractProviderRouter; } });
|
|
24
39
|
Object.defineProperty(exports, "createUserContextContractProviderRouter", { enumerable: true, get: function () { return contract_resolvers_1.createUserContextContractProviderRouter; } });
|
|
25
40
|
Object.defineProperty(exports, "getContractResolver", { enumerable: true, get: function () { return contract_resolvers_1.getContractResolver; } });
|
|
26
41
|
Object.defineProperty(exports, "handleContractCall", { enumerable: true, get: function () { return contract_resolvers_1.handleContractCall; } });
|
|
@@ -42,6 +57,11 @@ var extract_1 = require("./extract");
|
|
|
42
57
|
Object.defineProperty(exports, "extractTableShape", { enumerable: true, get: function () { return extract_1.extractTableShape; } });
|
|
43
58
|
Object.defineProperty(exports, "extractToolShape", { enumerable: true, get: function () { return extract_1.extractToolShape; } });
|
|
44
59
|
Object.defineProperty(exports, "setSchemaToFieldsFn", { enumerable: true, get: function () { return extract_1.setSchemaToFieldsFn; } });
|
|
60
|
+
var host_contract_transport_1 = require("./host-contract-transport");
|
|
61
|
+
Object.defineProperty(exports, "getHostContractTransport", { enumerable: true, get: function () { return host_contract_transport_1.getHostContractTransport; } });
|
|
62
|
+
Object.defineProperty(exports, "registerHostContractTransport", { enumerable: true, get: function () { return host_contract_transport_1.registerHostContractTransport; } });
|
|
63
|
+
Object.defineProperty(exports, "subscribeHostContractTransport", { enumerable: true, get: function () { return host_contract_transport_1.subscribeHostContractTransport; } });
|
|
64
|
+
Object.defineProperty(exports, "waitForHostContractTransport", { enumerable: true, get: function () { return host_contract_transport_1.waitForHostContractTransport; } });
|
|
45
65
|
var persistent_registry_1 = require("./persistent-registry");
|
|
46
66
|
Object.defineProperty(exports, "PersistentContractRegistry", { enumerable: true, get: function () { return persistent_registry_1.PersistentContractRegistry; } });
|
|
47
67
|
var registry_1 = require("./registry");
|
|
@@ -59,6 +79,7 @@ var logs_contract_1 = require("./system/logs-contract");
|
|
|
59
79
|
Object.defineProperty(exports, "getLogsContractDefinition", { enumerable: true, get: function () { return logs_contract_1.getLogsContractDefinition; } });
|
|
60
80
|
Object.defineProperty(exports, "LOGS_CONTRACT_VERSION", { enumerable: true, get: function () { return logs_contract_1.LOGS_CONTRACT_VERSION; } });
|
|
61
81
|
Object.defineProperty(exports, "resolveLogsContract", { enumerable: true, get: function () { return logs_contract_1.resolveLogsContract; } });
|
|
82
|
+
__exportStar(require("./system/network-contracts"), exports);
|
|
62
83
|
var system_contracts_1 = require("./system-contracts");
|
|
63
84
|
Object.defineProperty(exports, "installSystemContracts", { enumerable: true, get: function () { return system_contracts_1.installSystemContracts; } });
|
|
64
85
|
Object.defineProperty(exports, "listSystemContracts", { enumerable: true, get: function () { return system_contracts_1.listSystemContracts; } });
|
|
@@ -4,5 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import "./device-operations-contract";
|
|
6
6
|
import "./logs-contract";
|
|
7
|
+
import "./network-contracts";
|
|
7
8
|
export { DEVICE_OPERATIONS_CONTRACT_VERSION, DEVICE_OPERATIONS_MAX_QUERY_LENGTH, DEVICE_OPERATIONS_MAX_RESULT_BYTES, DEVICE_OPERATIONS_MAX_ROWS, DEVICE_OPERATIONS_MAX_TOOLS, type DeviceOperationCapability, deviceOperationsProviderPackageId, deviceOperationsToolIds, getDeviceOperationsContractDefinition, type IDeviceDatabaseQueryInput, type IDeviceDatabaseQueryResult, type IDeviceOperationStatus, type IDeviceToolListInput, type IDeviceToolLookupInput, type IDeviceToolLookupResult, type IDeviceToolRunInput, } from "./device-operations-contract";
|
|
8
9
|
export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./logs-contract";
|
|
10
|
+
export * from "./network-contracts";
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
17
|
exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = exports.DEVICE_OPERATIONS_MAX_TOOLS = exports.DEVICE_OPERATIONS_MAX_ROWS = exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = exports.DEVICE_OPERATIONS_CONTRACT_VERSION = void 0;
|
|
4
18
|
/**
|
|
@@ -7,6 +21,7 @@ exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsCon
|
|
|
7
21
|
*/
|
|
8
22
|
require("./device-operations-contract");
|
|
9
23
|
require("./logs-contract");
|
|
24
|
+
require("./network-contracts");
|
|
10
25
|
var device_operations_contract_1 = require("./device-operations-contract");
|
|
11
26
|
Object.defineProperty(exports, "DEVICE_OPERATIONS_CONTRACT_VERSION", { enumerable: true, get: function () { return device_operations_contract_1.DEVICE_OPERATIONS_CONTRACT_VERSION; } });
|
|
12
27
|
Object.defineProperty(exports, "DEVICE_OPERATIONS_MAX_QUERY_LENGTH", { enumerable: true, get: function () { return device_operations_contract_1.DEVICE_OPERATIONS_MAX_QUERY_LENGTH; } });
|
|
@@ -20,3 +35,4 @@ var logs_contract_1 = require("./logs-contract");
|
|
|
20
35
|
Object.defineProperty(exports, "getLogsContractDefinition", { enumerable: true, get: function () { return logs_contract_1.getLogsContractDefinition; } });
|
|
21
36
|
Object.defineProperty(exports, "LOGS_CONTRACT_VERSION", { enumerable: true, get: function () { return logs_contract_1.LOGS_CONTRACT_VERSION; } });
|
|
22
37
|
Object.defineProperty(exports, "resolveLogsContract", { enumerable: true, get: function () { return logs_contract_1.resolveLogsContract; } });
|
|
38
|
+
__exportStar(require("./network-contracts"), exports);
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import type { TrustLevel } from "../../device/socket.type";
|
|
2
|
+
import type { IConsoleLog } from "../../logging/console-logs.table";
|
|
3
|
+
import type { Observable } from "../../observable";
|
|
4
|
+
import type { INetworkInfo } from "../../types/peer-device";
|
|
5
|
+
import type { IContractConsumerBase } from "../contract-proxy";
|
|
6
|
+
import type { IContractDefinition } from "../types";
|
|
7
|
+
/** Version of the built-in System Network Diagnostics contract. */
|
|
8
|
+
export declare const NETWORK_DIAGNOSTICS_CONTRACT_VERSION = 1;
|
|
9
|
+
/** Version of the built-in System Network Control contract. */
|
|
10
|
+
export declare const NETWORK_CONTROL_CONTRACT_VERSION = 1;
|
|
11
|
+
/** Stable IDs for tools in System Network Diagnostics v1. */
|
|
12
|
+
export declare const networkDiagnosticsToolIds: {
|
|
13
|
+
readonly getOverview: "00ms1yb50ym353ads0gel5jpv";
|
|
14
|
+
readonly getConnections: "00ms1yb50ykny9kdgiclpa1t4";
|
|
15
|
+
readonly getGroupSyncStatus: "00ms1yb50yp2q7jr0jglzsztq";
|
|
16
|
+
readonly getDeviceDetails: "00ms1yb50yw792rslve1q99qg";
|
|
17
|
+
readonly getGroupDetails: "00ms1yb50yuru8h1fg4t9na3e";
|
|
18
|
+
readonly getDisconnectedDevices: "00ms1yb50y3jpoby5zomltahr";
|
|
19
|
+
readonly queryRemoteLogs: "00ms1yb50y2fbfnth22yz52eu";
|
|
20
|
+
};
|
|
21
|
+
/** Stable IDs for tools in System Network Control v1. */
|
|
22
|
+
export declare const networkControlToolIds: {
|
|
23
|
+
readonly refreshNetworkInfo: "00ms1yb50y9rsdyqmr81vjoli";
|
|
24
|
+
readonly connectToDevice: "00ms1yb50y40ty8tr0sic875x";
|
|
25
|
+
readonly disconnectDevice: "00ms1yb50yqvboqmhshqvlibr";
|
|
26
|
+
readonly deleteDevice: "00ms1yb50y5mc448nuavlex86";
|
|
27
|
+
readonly syncGroupNow: "00ms1yb50ylnqlra26jx232py";
|
|
28
|
+
readonly resetChangeTracking: "00ms1yb50yfuackpl1w37hmxc";
|
|
29
|
+
};
|
|
30
|
+
/** Overall status shown by the shell's compact network indicator. */
|
|
31
|
+
export type NetworkStatusState = "offline" | "syncing" | "synced" | "error";
|
|
32
|
+
/** Runtime synchronization state for one personal or shared-group context. */
|
|
33
|
+
export type NetworkSyncState = "idle" | "syncing" | "error";
|
|
34
|
+
/** Safe, bounded synchronization error detail suitable for local UI display. */
|
|
35
|
+
export interface INetworkSyncError {
|
|
36
|
+
dataContextId: string;
|
|
37
|
+
message: string;
|
|
38
|
+
occurredAt: number;
|
|
39
|
+
}
|
|
40
|
+
/** Reactive summary consumed by the tabs-strip Network Status indicator. */
|
|
41
|
+
export interface INetworkStatusSummary {
|
|
42
|
+
state: NetworkStatusState;
|
|
43
|
+
connectionCount: number;
|
|
44
|
+
syncingContextCount: number;
|
|
45
|
+
errorCount: number;
|
|
46
|
+
lastSuccessfulSyncAt?: number;
|
|
47
|
+
errors: INetworkSyncError[];
|
|
48
|
+
}
|
|
49
|
+
/** Current synchronization lifecycle for one data context. */
|
|
50
|
+
export interface IDataContextSyncStatus {
|
|
51
|
+
dataContextId: string;
|
|
52
|
+
state: NetworkSyncState;
|
|
53
|
+
lastSuccessfulSyncAt?: number;
|
|
54
|
+
lastErrorAt?: number;
|
|
55
|
+
lastError?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Connection/member counts for one personal or shared group. */
|
|
58
|
+
export interface INetworkGroupSummary {
|
|
59
|
+
groupId: string;
|
|
60
|
+
groupName: string;
|
|
61
|
+
connectedDevices: number;
|
|
62
|
+
totalMembers: number;
|
|
63
|
+
}
|
|
64
|
+
/** Portable overview of the local device's network state. */
|
|
65
|
+
export interface INetworkOverview {
|
|
66
|
+
localDeviceId: string;
|
|
67
|
+
localUserId: string;
|
|
68
|
+
totalConnections: number;
|
|
69
|
+
availableSlots: number;
|
|
70
|
+
maxConnections: number;
|
|
71
|
+
cpuPercent: number;
|
|
72
|
+
memPercent: number;
|
|
73
|
+
groups: INetworkGroupSummary[];
|
|
74
|
+
}
|
|
75
|
+
/** Detailed portable information about one active device connection. */
|
|
76
|
+
export interface INetworkConnectionInfo {
|
|
77
|
+
deviceId: string;
|
|
78
|
+
userId: string;
|
|
79
|
+
userName?: string;
|
|
80
|
+
deviceName?: string;
|
|
81
|
+
userTrustLevel: TrustLevel;
|
|
82
|
+
deviceTrustLevel: TrustLevel;
|
|
83
|
+
connectionState: "connected" | "syncing" | "idle";
|
|
84
|
+
sharedGroups: string[];
|
|
85
|
+
roles: Record<string, string>;
|
|
86
|
+
pathType: "direct" | "indirect" | "unknown";
|
|
87
|
+
throughDeviceIds?: string[];
|
|
88
|
+
latencyMs: number;
|
|
89
|
+
errorRate: number;
|
|
90
|
+
isServer: boolean;
|
|
91
|
+
connectionAddress?: string;
|
|
92
|
+
bytesSent?: number;
|
|
93
|
+
bytesReceived?: number;
|
|
94
|
+
sendRateMBps?: number;
|
|
95
|
+
receiveRateMBps?: number;
|
|
96
|
+
}
|
|
97
|
+
/** Serializable synchronization connection detail for one group. */
|
|
98
|
+
export interface INetworkSyncConnection {
|
|
99
|
+
deviceId: string;
|
|
100
|
+
latencyMs: number;
|
|
101
|
+
errorRate: number;
|
|
102
|
+
timestampLastApplied?: number;
|
|
103
|
+
closed?: boolean;
|
|
104
|
+
}
|
|
105
|
+
/** Synchronization status and topology for one data context. */
|
|
106
|
+
export interface INetworkGroupSyncInfo {
|
|
107
|
+
groupId: string;
|
|
108
|
+
groupName: string;
|
|
109
|
+
connectedDevices: INetworkSyncConnection[];
|
|
110
|
+
preferredDeviceIds: string[];
|
|
111
|
+
lastSyncTimestamp: number;
|
|
112
|
+
totalMembers: number;
|
|
113
|
+
syncStatus: IDataContextSyncStatus;
|
|
114
|
+
}
|
|
115
|
+
/** Detailed portable information about one connected device. */
|
|
116
|
+
export interface INetworkDeviceDetails extends INetworkConnectionInfo {
|
|
117
|
+
canReadRemoteLogs: boolean;
|
|
118
|
+
networkInfo?: INetworkInfo;
|
|
119
|
+
syncStatsByGroup: Record<string, {
|
|
120
|
+
lastSyncTime: number;
|
|
121
|
+
isPreferred: boolean;
|
|
122
|
+
}>;
|
|
123
|
+
}
|
|
124
|
+
/** A known device that does not currently have an active connection. */
|
|
125
|
+
export interface INetworkDisconnectedDevice {
|
|
126
|
+
deviceId: string;
|
|
127
|
+
userId: string;
|
|
128
|
+
userName?: string;
|
|
129
|
+
trustLevel: TrustLevel;
|
|
130
|
+
firstSeen: Date;
|
|
131
|
+
lastSeen: Date;
|
|
132
|
+
name?: string;
|
|
133
|
+
serverUrl?: string;
|
|
134
|
+
}
|
|
135
|
+
/** One member shown in Network Viewer's group detail. */
|
|
136
|
+
export interface INetworkGroupMember {
|
|
137
|
+
userId: string;
|
|
138
|
+
userName?: string;
|
|
139
|
+
role: string;
|
|
140
|
+
trustLevel: TrustLevel;
|
|
141
|
+
}
|
|
142
|
+
/** Detailed portable membership information for one data context. */
|
|
143
|
+
export interface INetworkGroupDetails {
|
|
144
|
+
groupId: string;
|
|
145
|
+
groupName: string;
|
|
146
|
+
founderUserId: string;
|
|
147
|
+
founderUserName?: string;
|
|
148
|
+
members: INetworkGroupMember[];
|
|
149
|
+
}
|
|
150
|
+
/** Filters and bounds for a directly connected device's System Logs query. */
|
|
151
|
+
export interface INetworkRemoteLogsQuery {
|
|
152
|
+
sinceTimestamp?: number;
|
|
153
|
+
level?: IConsoleLog["level"];
|
|
154
|
+
process?: string;
|
|
155
|
+
search?: string;
|
|
156
|
+
pageSize?: number;
|
|
157
|
+
timeoutMs?: number;
|
|
158
|
+
}
|
|
159
|
+
/** Bounded remote logs returned through System Network Diagnostics. */
|
|
160
|
+
export interface INetworkRemoteLogsResult {
|
|
161
|
+
deviceId: string;
|
|
162
|
+
truncated: boolean;
|
|
163
|
+
logs: IConsoleLog[];
|
|
164
|
+
queriedAt: number;
|
|
165
|
+
}
|
|
166
|
+
/** Structured result returned by every System Network Control operation. */
|
|
167
|
+
export interface INetworkControlResult {
|
|
168
|
+
success: boolean;
|
|
169
|
+
message: string;
|
|
170
|
+
}
|
|
171
|
+
/** Typed consumer proxy for System Network Diagnostics v1. */
|
|
172
|
+
export interface INetworkDiagnosticsConsumer extends IContractConsumerBase {
|
|
173
|
+
tools: {
|
|
174
|
+
getOverview(): Promise<{
|
|
175
|
+
overview: INetworkOverview;
|
|
176
|
+
}>;
|
|
177
|
+
getConnections(): Promise<{
|
|
178
|
+
connections: INetworkConnectionInfo[];
|
|
179
|
+
}>;
|
|
180
|
+
getGroupSyncStatus(input?: {
|
|
181
|
+
groupId?: string;
|
|
182
|
+
}): Promise<{
|
|
183
|
+
groups: INetworkGroupSyncInfo[];
|
|
184
|
+
}>;
|
|
185
|
+
getDeviceDetails(input: {
|
|
186
|
+
deviceId: string;
|
|
187
|
+
}): Promise<{
|
|
188
|
+
device?: INetworkDeviceDetails;
|
|
189
|
+
}>;
|
|
190
|
+
getGroupDetails(input: {
|
|
191
|
+
groupId: string;
|
|
192
|
+
}): Promise<{
|
|
193
|
+
group?: INetworkGroupDetails;
|
|
194
|
+
}>;
|
|
195
|
+
getDisconnectedDevices(): Promise<{
|
|
196
|
+
devices: INetworkDisconnectedDevice[];
|
|
197
|
+
}>;
|
|
198
|
+
queryRemoteLogs(input: {
|
|
199
|
+
deviceId: string;
|
|
200
|
+
query?: INetworkRemoteLogsQuery;
|
|
201
|
+
}): Promise<INetworkRemoteLogsResult>;
|
|
202
|
+
};
|
|
203
|
+
observables: {
|
|
204
|
+
status: Observable<INetworkStatusSummary>;
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/** Typed consumer proxy for System Network Control v1. */
|
|
208
|
+
export interface INetworkControlConsumer extends IContractConsumerBase {
|
|
209
|
+
tools: {
|
|
210
|
+
refreshNetworkInfo(): Promise<INetworkControlResult>;
|
|
211
|
+
connectToDevice(input: {
|
|
212
|
+
deviceId: string;
|
|
213
|
+
}): Promise<INetworkControlResult>;
|
|
214
|
+
disconnectDevice(input: {
|
|
215
|
+
deviceId: string;
|
|
216
|
+
}): Promise<INetworkControlResult>;
|
|
217
|
+
deleteDevice(input: {
|
|
218
|
+
deviceId: string;
|
|
219
|
+
}): Promise<INetworkControlResult>;
|
|
220
|
+
syncGroupNow(input: {
|
|
221
|
+
groupId: string;
|
|
222
|
+
}): Promise<INetworkControlResult>;
|
|
223
|
+
resetChangeTracking(input: {
|
|
224
|
+
dataContextId: string;
|
|
225
|
+
}): Promise<INetworkControlResult>;
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/** Return the portable read-only network diagnostics contract shape. */
|
|
229
|
+
export declare function getNetworkDiagnosticsContractDefinition(): IContractDefinition;
|
|
230
|
+
/** Return the explicit mutating local network control contract shape. */
|
|
231
|
+
export declare function getNetworkControlContractDefinition(): IContractDefinition;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.networkControlToolIds = exports.networkDiagnosticsToolIds = exports.NETWORK_CONTROL_CONTRACT_VERSION = exports.NETWORK_DIAGNOSTICS_CONTRACT_VERSION = void 0;
|
|
4
|
+
exports.getNetworkDiagnosticsContractDefinition = getNetworkDiagnosticsContractDefinition;
|
|
5
|
+
exports.getNetworkControlContractDefinition = getNetworkControlContractDefinition;
|
|
6
|
+
const system_ids_1 = require("../../system-ids");
|
|
7
|
+
const field_type_1 = require("../../types/field-type");
|
|
8
|
+
const system_contracts_1 = require("../system-contracts");
|
|
9
|
+
/** Version of the built-in System Network Diagnostics contract. */
|
|
10
|
+
exports.NETWORK_DIAGNOSTICS_CONTRACT_VERSION = 1;
|
|
11
|
+
/** Version of the built-in System Network Control contract. */
|
|
12
|
+
exports.NETWORK_CONTROL_CONTRACT_VERSION = 1;
|
|
13
|
+
/** Stable IDs for tools in System Network Diagnostics v1. */
|
|
14
|
+
exports.networkDiagnosticsToolIds = {
|
|
15
|
+
getOverview: "00ms1yb50ym353ads0gel5jpv",
|
|
16
|
+
getConnections: "00ms1yb50ykny9kdgiclpa1t4",
|
|
17
|
+
getGroupSyncStatus: "00ms1yb50yp2q7jr0jglzsztq",
|
|
18
|
+
getDeviceDetails: "00ms1yb50yw792rslve1q99qg",
|
|
19
|
+
getGroupDetails: "00ms1yb50yuru8h1fg4t9na3e",
|
|
20
|
+
getDisconnectedDevices: "00ms1yb50y3jpoby5zomltahr",
|
|
21
|
+
queryRemoteLogs: "00ms1yb50y2fbfnth22yz52eu",
|
|
22
|
+
};
|
|
23
|
+
/** Stable IDs for tools in System Network Control v1. */
|
|
24
|
+
exports.networkControlToolIds = {
|
|
25
|
+
refreshNetworkInfo: "00ms1yb50y9rsdyqmr81vjoli",
|
|
26
|
+
connectToDevice: "00ms1yb50y40ty8tr0sic875x",
|
|
27
|
+
disconnectDevice: "00ms1yb50yqvboqmhshqvlibr",
|
|
28
|
+
deleteDevice: "00ms1yb50y5mc448nuavlex86",
|
|
29
|
+
syncGroupNow: "00ms1yb50ylnqlra26jx232py",
|
|
30
|
+
resetChangeTracking: "00ms1yb50yfuackpl1w37hmxc",
|
|
31
|
+
};
|
|
32
|
+
const field = (name, type, description, opts = {}) => ({ name, type, description, ...opts });
|
|
33
|
+
let diagnosticsDefinition;
|
|
34
|
+
let controlDefinition;
|
|
35
|
+
/** Return the portable read-only network diagnostics contract shape. */
|
|
36
|
+
function getNetworkDiagnosticsContractDefinition() {
|
|
37
|
+
diagnosticsDefinition ??= {
|
|
38
|
+
contractId: system_ids_1.networkDiagnosticsContractId,
|
|
39
|
+
version: exports.NETWORK_DIAGNOSTICS_CONTRACT_VERSION,
|
|
40
|
+
devTag: "dev",
|
|
41
|
+
name: "System Network Diagnostics",
|
|
42
|
+
description: "Portable local network, connection, and synchronization diagnostics.",
|
|
43
|
+
tables: [],
|
|
44
|
+
tools: [
|
|
45
|
+
{
|
|
46
|
+
name: "getOverview",
|
|
47
|
+
usageDescription: "Return aggregate network and group information.",
|
|
48
|
+
inputFields: [],
|
|
49
|
+
outputFields: [field("overview", field_type_1.FieldType.object, "Local network overview.")],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "getConnections",
|
|
53
|
+
usageDescription: "List active device connections and their health.",
|
|
54
|
+
inputFields: [],
|
|
55
|
+
outputFields: [
|
|
56
|
+
field("connections", field_type_1.FieldType.object, "Active connection details.", { isArray: true }),
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "getGroupSyncStatus",
|
|
61
|
+
usageDescription: "Return sync status for one context or every local context.",
|
|
62
|
+
inputFields: [
|
|
63
|
+
field("groupId", field_type_1.FieldType.id, "Optional personal or group context ID.", {
|
|
64
|
+
optional: true,
|
|
65
|
+
}),
|
|
66
|
+
],
|
|
67
|
+
outputFields: [
|
|
68
|
+
field("groups", field_type_1.FieldType.object, "Group synchronization details.", { isArray: true }),
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "getDeviceDetails",
|
|
73
|
+
usageDescription: "Return details for one currently connected device.",
|
|
74
|
+
inputFields: [field("deviceId", field_type_1.FieldType.id, "Connected device ID.")],
|
|
75
|
+
outputFields: [
|
|
76
|
+
field("device", field_type_1.FieldType.object, "Connected device details.", { optional: true }),
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "getGroupDetails",
|
|
81
|
+
usageDescription: "Return membership details for one local data context.",
|
|
82
|
+
inputFields: [field("groupId", field_type_1.FieldType.id, "Personal or group context ID.")],
|
|
83
|
+
outputFields: [
|
|
84
|
+
field("group", field_type_1.FieldType.object, "Group membership details.", { optional: true }),
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "getDisconnectedDevices",
|
|
89
|
+
usageDescription: "List known devices without an active connection.",
|
|
90
|
+
inputFields: [],
|
|
91
|
+
outputFields: [
|
|
92
|
+
field("devices", field_type_1.FieldType.object, "Disconnected device details.", { isArray: true }),
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "queryRemoteLogs",
|
|
97
|
+
usageDescription: "Query bounded logs from a directly connected authorized device.",
|
|
98
|
+
inputFields: [
|
|
99
|
+
field("deviceId", field_type_1.FieldType.id, "Connected device ID."),
|
|
100
|
+
field("query", field_type_1.FieldType.object, "Optional remote log filters.", { optional: true }),
|
|
101
|
+
],
|
|
102
|
+
outputFields: [
|
|
103
|
+
field("deviceId", field_type_1.FieldType.id, "Queried device ID."),
|
|
104
|
+
field("truncated", field_type_1.FieldType.boolean, "Whether matching rows were omitted."),
|
|
105
|
+
field("logs", field_type_1.FieldType.object, "Matching console logs.", { isArray: true }),
|
|
106
|
+
field("queriedAt", field_type_1.FieldType.number, "Local completion timestamp."),
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
observables: [
|
|
111
|
+
{
|
|
112
|
+
name: "status",
|
|
113
|
+
description: "Reactive connection and synchronization status summary.",
|
|
114
|
+
valueType: field_type_1.FieldType.object,
|
|
115
|
+
writable: false,
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
events: [],
|
|
119
|
+
};
|
|
120
|
+
return diagnosticsDefinition;
|
|
121
|
+
}
|
|
122
|
+
/** Return the explicit mutating local network control contract shape. */
|
|
123
|
+
function getNetworkControlContractDefinition() {
|
|
124
|
+
const deviceInput = [field("deviceId", field_type_1.FieldType.id, "Target device ID.")];
|
|
125
|
+
const resultFields = [
|
|
126
|
+
field("success", field_type_1.FieldType.boolean, "Whether the operation completed successfully."),
|
|
127
|
+
field("message", field_type_1.FieldType.string, "Human-readable operation result."),
|
|
128
|
+
];
|
|
129
|
+
controlDefinition ??= {
|
|
130
|
+
contractId: system_ids_1.networkControlContractId,
|
|
131
|
+
version: exports.NETWORK_CONTROL_CONTRACT_VERSION,
|
|
132
|
+
devTag: "dev",
|
|
133
|
+
name: "System Network Control",
|
|
134
|
+
description: "Explicit local device connection and synchronization control operations.",
|
|
135
|
+
tables: [],
|
|
136
|
+
tools: [
|
|
137
|
+
{
|
|
138
|
+
name: "refreshNetworkInfo",
|
|
139
|
+
usageDescription: "Refresh network information and preferred connection choices.",
|
|
140
|
+
inputFields: [],
|
|
141
|
+
outputFields: resultFields,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: "connectToDevice",
|
|
145
|
+
usageDescription: "Start a connection attempt to one known device.",
|
|
146
|
+
inputFields: deviceInput,
|
|
147
|
+
outputFields: resultFields,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: "disconnectDevice",
|
|
151
|
+
usageDescription: "Close the active connection to one device.",
|
|
152
|
+
inputFields: deviceInput,
|
|
153
|
+
outputFields: resultFields,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "deleteDevice",
|
|
157
|
+
usageDescription: "Forget one known, disconnected device.",
|
|
158
|
+
inputFields: deviceInput,
|
|
159
|
+
outputFields: resultFields,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "syncGroupNow",
|
|
163
|
+
usageDescription: "Notify connected devices of changes in one data context.",
|
|
164
|
+
inputFields: [field("groupId", field_type_1.FieldType.id, "Personal or group context ID.")],
|
|
165
|
+
outputFields: resultFields,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: "resetChangeTracking",
|
|
169
|
+
usageDescription: "Reset one data context's change tracking for an expensive full sync.",
|
|
170
|
+
inputFields: [
|
|
171
|
+
field("dataContextId", field_type_1.FieldType.id, "Personal or group context ID to reset."),
|
|
172
|
+
],
|
|
173
|
+
outputFields: resultFields,
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
observables: [],
|
|
177
|
+
events: [],
|
|
178
|
+
};
|
|
179
|
+
return controlDefinition;
|
|
180
|
+
}
|
|
181
|
+
(0, system_contracts_1.registerSystemContract)({
|
|
182
|
+
providerPackageId: system_ids_1.peersSystemPackageId,
|
|
183
|
+
contractId: system_ids_1.networkDiagnosticsContractId,
|
|
184
|
+
version: exports.NETWORK_DIAGNOSTICS_CONTRACT_VERSION,
|
|
185
|
+
getDefinition: getNetworkDiagnosticsContractDefinition,
|
|
186
|
+
});
|
|
187
|
+
(0, system_contracts_1.registerSystemContract)({
|
|
188
|
+
providerPackageId: system_ids_1.peersSystemPackageId,
|
|
189
|
+
contractId: system_ids_1.networkControlContractId,
|
|
190
|
+
version: exports.NETWORK_CONTROL_CONTRACT_VERSION,
|
|
191
|
+
getDefinition: getNetworkControlContractDefinition,
|
|
192
|
+
});
|
package/dist/system-ids.d.ts
CHANGED
|
@@ -32,3 +32,7 @@ export declare const logsContractId = "000peers0logs000000000001";
|
|
|
32
32
|
* explicit owner-authorized status, bounded read-only database, and installed-tool operations.
|
|
33
33
|
*/
|
|
34
34
|
export declare const deviceOperationsContractId = "00mriijkhq94msfe9m2j6quwp";
|
|
35
|
+
/** Contract id for portable read-only network and synchronization diagnostics. */
|
|
36
|
+
export declare const networkDiagnosticsContractId = "00ms1yb50w29oi116uwwrg7rl";
|
|
37
|
+
/** Contract id for explicit local network and synchronization control operations. */
|
|
38
|
+
export declare const networkControlContractId = "00ms1yb50yj9w5qbytl69qfht";
|
package/dist/system-ids.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.deviceOperationsContractId = exports.logsContractId = exports.peersSystemPackageId = exports.peersCorePublishPublicKey = exports.peersCorePackageRepoUrl = exports.peersCorePackageId = exports.runWorkflowToolId = exports.defaultSendMessageToolId = exports.defaultAssistantRunnerToolId = exports.openCodeAssistantId = exports.defaultAssistantId = exports.peersRootUserId = void 0;
|
|
3
|
+
exports.networkControlContractId = exports.networkDiagnosticsContractId = exports.deviceOperationsContractId = exports.logsContractId = exports.peersSystemPackageId = exports.peersCorePublishPublicKey = exports.peersCorePackageRepoUrl = exports.peersCorePackageId = exports.runWorkflowToolId = exports.defaultSendMessageToolId = exports.defaultAssistantRunnerToolId = exports.openCodeAssistantId = exports.defaultAssistantId = exports.peersRootUserId = void 0;
|
|
4
4
|
/** Stable user ID that owns built-in Peers system records. */
|
|
5
5
|
exports.peersRootUserId = "000peers0user000000000001";
|
|
6
6
|
/** Default assistant used when no user-selected assistant is available. */
|
|
@@ -36,3 +36,7 @@ exports.logsContractId = "000peers0logs000000000001";
|
|
|
36
36
|
* explicit owner-authorized status, bounded read-only database, and installed-tool operations.
|
|
37
37
|
*/
|
|
38
38
|
exports.deviceOperationsContractId = "00mriijkhq94msfe9m2j6quwp";
|
|
39
|
+
/** Contract id for portable read-only network and synchronization diagnostics. */
|
|
40
|
+
exports.networkDiagnosticsContractId = "00ms1yb50w29oi116uwwrg7rl";
|
|
41
|
+
/** Contract id for explicit local network and synchronization control operations. */
|
|
42
|
+
exports.networkControlContractId = "00ms1yb50yj9w5qbytl69qfht";
|