@peers-app/peers-sdk 0.21.7 → 0.23.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/context/user-context-singleton.d.ts +42 -0
- package/dist/context/user-context-singleton.js +45 -0
- package/dist/contracts/__tests__/contract-proxy.test.js +51 -1
- package/dist/contracts/__tests__/contract-resolvers.test.js +65 -0
- package/dist/contracts/__tests__/playground.test.js +5 -2
- package/dist/contracts/__tests__/system-contracts.test.js +3 -0
- package/dist/contracts/contract-proxy.d.ts +27 -0
- package/dist/contracts/contract-proxy.js +37 -1
- package/dist/contracts/contract-resolvers.d.ts +10 -0
- package/dist/contracts/contract-resolvers.js +21 -3
- package/dist/contracts/index.d.ts +3 -2
- package/dist/contracts/index.js +5 -2
- package/dist/contracts/system/index.d.ts +2 -0
- package/dist/contracts/system/index.js +5 -1
- package/dist/contracts/system/tool-access-control-contract.d.ts +35 -0
- package/dist/contracts/system/tool-access-control-contract.js +70 -0
- package/dist/data/access-level.d.ts +72 -0
- package/dist/data/access-level.js +109 -0
- package/dist/data/access-level.test.d.ts +1 -0
- package/dist/data/access-level.test.js +53 -0
- package/dist/data/assistants.d.ts +24 -0
- package/dist/data/assistants.js +21 -0
- package/dist/data/group-member-roles.d.ts +9 -0
- package/dist/data/group-member-roles.js +9 -0
- package/dist/data/group-permissions.d.ts +55 -1
- package/dist/data/group-permissions.js +76 -6
- package/dist/data/index.d.ts +3 -1
- package/dist/data/index.js +3 -1
- package/dist/data/orm/sql.data-source.d.ts +10 -0
- package/dist/data/orm/sql.data-source.js +48 -30
- package/dist/data/orm/sql.data-source.test.js +13 -0
- package/dist/data/package-version-resolver.test.js +2 -0
- package/dist/data/tool-access-approvals.d.ts +126 -0
- package/dist/data/tool-access-approvals.js +86 -0
- package/dist/data/tool-access.d.ts +162 -0
- package/dist/data/tool-access.js +235 -0
- package/dist/data/tool-access.test.d.ts +1 -0
- package/dist/data/tool-access.test.js +159 -0
- package/dist/data/tools.d.ts +15 -0
- package/dist/data/tools.js +11 -0
- package/dist/data/workflow-logs.d.ts +5 -5
- package/dist/data/workflow-runs.d.ts +2 -2
- package/dist/device-pairing/types.d.ts +6 -6
- package/dist/package-installer/package-creator.d.ts +31 -0
- package/dist/package-installer/package-creator.js +140 -40
- package/dist/package-installer/package-creator.test.js +113 -11
- package/dist/rpc-types.d.ts +0 -17
- package/dist/rpc-types.js +0 -15
- package/dist/system-ids.d.ts +13 -0
- package/dist/system-ids.js +14 -1
- package/package.json +1 -1
- package/dist/data/voice-messages.d.ts +0 -33
- package/dist/data/voice-messages.js +0 -33
|
@@ -1,12 +1,54 @@
|
|
|
1
1
|
import type { Table } from "../data/orm";
|
|
2
2
|
import type { DataContext } from "./data-context";
|
|
3
3
|
import { UserContext } from "./user-context";
|
|
4
|
+
/**
|
|
5
|
+
* Return the process user context, waiting until {@link setUserContext} if needed.
|
|
6
|
+
*
|
|
7
|
+
* Prefer an explicit `UserContext` when one is already in hand (multi-device
|
|
8
|
+
* tests and connection providers). Use {@link peekUserContext} to fail closed
|
|
9
|
+
* instead of waiting.
|
|
10
|
+
*/
|
|
4
11
|
export declare function getUserContext(): Promise<UserContext>;
|
|
12
|
+
/**
|
|
13
|
+
* Return the process user context if {@link setUserContext} has already run.
|
|
14
|
+
*
|
|
15
|
+
* Does not wait. Callers that must not hang (role checks, contract tools)
|
|
16
|
+
* should treat `undefined` as fail-closed.
|
|
17
|
+
*/
|
|
18
|
+
export declare function peekUserContext(): UserContext | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Install the process-wide user context. Throws if one is already set, except
|
|
21
|
+
* in a browser/PWA where HMR and navigations may replace it.
|
|
22
|
+
*
|
|
23
|
+
* @param userContext - Context that owns local personal and group data.
|
|
24
|
+
*/
|
|
5
25
|
export declare function setUserContext(userContext: UserContext): void;
|
|
26
|
+
/**
|
|
27
|
+
* Return the current user's default data context after the singleton is ready.
|
|
28
|
+
*/
|
|
6
29
|
export declare function getDefaultDataContext(): Promise<DataContext>;
|
|
30
|
+
/**
|
|
31
|
+
* Return the table container for `dataContext`, or the singleton default.
|
|
32
|
+
*
|
|
33
|
+
* @param dataContext - Context to read tables from. Falls back to the singleton.
|
|
34
|
+
*/
|
|
7
35
|
export declare function getTableContainer(dataContext?: DataContext | undefined): import("../data/orm").TableContainer;
|
|
36
|
+
/**
|
|
37
|
+
* Install a client-proxy user context for renderer/RPC processes.
|
|
38
|
+
*
|
|
39
|
+
* No-ops when a real server-side context is already set in-process.
|
|
40
|
+
*
|
|
41
|
+
* @param userId - Local user id used as the personal data-context id.
|
|
42
|
+
*/
|
|
8
43
|
export declare function setDefaultClientUserContext(userId: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Return every table currently loaded in the default table container, keyed by
|
|
46
|
+
* full table name.
|
|
47
|
+
*/
|
|
9
48
|
export declare function getAllTables(): {
|
|
10
49
|
[tableName: string]: Table<any>;
|
|
11
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Return the singleton user's id. Throws if {@link setUserContext} has not run.
|
|
53
|
+
*/
|
|
12
54
|
export declare const myUserId: () => string;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.myUserId = void 0;
|
|
4
4
|
exports.getUserContext = getUserContext;
|
|
5
|
+
exports.peekUserContext = peekUserContext;
|
|
5
6
|
exports.setUserContext = setUserContext;
|
|
6
7
|
exports.getDefaultDataContext = getDefaultDataContext;
|
|
7
8
|
exports.getTableContainer = getTableContainer;
|
|
@@ -16,6 +17,13 @@ const user_context_1 = require("./user-context");
|
|
|
16
17
|
var userContextInstance;
|
|
17
18
|
var userContextResolved;
|
|
18
19
|
var userContextPromise;
|
|
20
|
+
/**
|
|
21
|
+
* Return the process user context, waiting until {@link setUserContext} if needed.
|
|
22
|
+
*
|
|
23
|
+
* Prefer an explicit `UserContext` when one is already in hand (multi-device
|
|
24
|
+
* tests and connection providers). Use {@link peekUserContext} to fail closed
|
|
25
|
+
* instead of waiting.
|
|
26
|
+
*/
|
|
19
27
|
async function getUserContext() {
|
|
20
28
|
if (userContextInstance) {
|
|
21
29
|
return userContextInstance.loadingPromise;
|
|
@@ -30,6 +38,21 @@ async function getUserContext() {
|
|
|
30
38
|
}
|
|
31
39
|
return userContextPromise;
|
|
32
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Return the process user context if {@link setUserContext} has already run.
|
|
43
|
+
*
|
|
44
|
+
* Does not wait. Callers that must not hang (role checks, contract tools)
|
|
45
|
+
* should treat `undefined` as fail-closed.
|
|
46
|
+
*/
|
|
47
|
+
function peekUserContext() {
|
|
48
|
+
return userContextInstance;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Install the process-wide user context. Throws if one is already set, except
|
|
52
|
+
* in a browser/PWA where HMR and navigations may replace it.
|
|
53
|
+
*
|
|
54
|
+
* @param userContext - Context that owns local personal and group data.
|
|
55
|
+
*/
|
|
33
56
|
function setUserContext(userContext) {
|
|
34
57
|
if (userContextInstance) {
|
|
35
58
|
if (typeof window !== "undefined") {
|
|
@@ -51,10 +74,18 @@ function setUserContext(userContext) {
|
|
|
51
74
|
window.userContext = userContext;
|
|
52
75
|
}
|
|
53
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Return the current user's default data context after the singleton is ready.
|
|
79
|
+
*/
|
|
54
80
|
async function getDefaultDataContext() {
|
|
55
81
|
const userContext = await getUserContext();
|
|
56
82
|
return userContext.defaultDataContext();
|
|
57
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Return the table container for `dataContext`, or the singleton default.
|
|
86
|
+
*
|
|
87
|
+
* @param dataContext - Context to read tables from. Falls back to the singleton.
|
|
88
|
+
*/
|
|
58
89
|
function getTableContainer(dataContext) {
|
|
59
90
|
dataContext ??= userContextInstance?.defaultDataContext();
|
|
60
91
|
if (!dataContext) {
|
|
@@ -62,6 +93,13 @@ function getTableContainer(dataContext) {
|
|
|
62
93
|
}
|
|
63
94
|
return dataContext.tableContainer;
|
|
64
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Install a client-proxy user context for renderer/RPC processes.
|
|
98
|
+
*
|
|
99
|
+
* No-ops when a real server-side context is already set in-process.
|
|
100
|
+
*
|
|
101
|
+
* @param userId - Local user id used as the personal data-context id.
|
|
102
|
+
*/
|
|
65
103
|
function setDefaultClientUserContext(userId) {
|
|
66
104
|
// If a real (server-side) user context is already set in the same process
|
|
67
105
|
// (e.g. PWA where peers-device runs in the browser), don't overwrite it
|
|
@@ -83,6 +121,10 @@ function setDefaultClientUserContext(userId) {
|
|
|
83
121
|
})();
|
|
84
122
|
setUserContext(userContext);
|
|
85
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Return every table currently loaded in the default table container, keyed by
|
|
126
|
+
* full table name.
|
|
127
|
+
*/
|
|
86
128
|
function getAllTables() {
|
|
87
129
|
const tables = getTableContainer().getAllTables();
|
|
88
130
|
const tableMap = {};
|
|
@@ -117,6 +159,9 @@ if (!rpc_types_1.isClient) {
|
|
|
117
159
|
return table[methodName](...args);
|
|
118
160
|
};
|
|
119
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Return the singleton user's id. Throws if {@link setUserContext} has not run.
|
|
164
|
+
*/
|
|
120
165
|
const myUserId = () => {
|
|
121
166
|
if (!userContextInstance) {
|
|
122
167
|
throw new Error(`myUserId called before userContext singleton was initialized`);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const groupPermissions = require("../../data/group-permissions");
|
|
3
4
|
const decorators_1 = require("../../data/orm/decorators");
|
|
4
5
|
const observable_1 = require("../../observable");
|
|
5
6
|
const field_type_1 = require("../../types/field-type");
|
|
@@ -76,7 +77,7 @@ function makeResolution() {
|
|
|
76
77
|
tables: { Widgets: table },
|
|
77
78
|
tools: {
|
|
78
79
|
"make-widget": {
|
|
79
|
-
tool: { toolId: (0, utils_1.newid)(), name: "make-widget" },
|
|
80
|
+
tool: { toolId: (0, utils_1.newid)(), name: "make-widget", accessLevel: 0 },
|
|
80
81
|
toolFn: makeWidget,
|
|
81
82
|
},
|
|
82
83
|
},
|
|
@@ -147,6 +148,55 @@ describe("contract proxy — consumer/provider round-trip", () => {
|
|
|
147
148
|
expect(makeWidget).toHaveBeenCalledWith({ color: "blue" });
|
|
148
149
|
expect(result.color).toBe("blue");
|
|
149
150
|
});
|
|
151
|
+
it("allows a classified tool when the provider data context grants access", async () => {
|
|
152
|
+
const getUserAccessLevel = jest
|
|
153
|
+
.spyOn(groupPermissions, "getUserAccessLevel")
|
|
154
|
+
.mockResolvedValue(100);
|
|
155
|
+
const contract = makeContract();
|
|
156
|
+
const { resolution, makeWidget } = makeResolution();
|
|
157
|
+
const makeWidgetTool = resolution.tools?.["make-widget"];
|
|
158
|
+
if (!makeWidgetTool) {
|
|
159
|
+
throw new Error("expected make-widget tool");
|
|
160
|
+
}
|
|
161
|
+
makeWidgetTool.tool.accessLevel = 80;
|
|
162
|
+
const provider = (0, contract_proxy_1.createContractProvider)(resolution);
|
|
163
|
+
const dataContext = { userContext: { userId: "u1" } };
|
|
164
|
+
const consumer = consumerVia(contract, provider, {
|
|
165
|
+
callerUserId: "u1",
|
|
166
|
+
localUserId: "u1",
|
|
167
|
+
dataContext,
|
|
168
|
+
});
|
|
169
|
+
await expect(consumer.tools["make-widget"]({ color: "blue" })).resolves.toEqual(expect.objectContaining({ color: "blue" }));
|
|
170
|
+
expect(makeWidget).toHaveBeenCalledWith({ color: "blue" });
|
|
171
|
+
expect(getUserAccessLevel).toHaveBeenCalledWith(dataContext, "u1");
|
|
172
|
+
});
|
|
173
|
+
it("fails closed quickly when a classified tool has no user context", async () => {
|
|
174
|
+
const contract = makeContract();
|
|
175
|
+
const { resolution } = makeResolution();
|
|
176
|
+
const makeWidgetTool = resolution.tools?.["make-widget"];
|
|
177
|
+
if (!makeWidgetTool) {
|
|
178
|
+
throw new Error("expected make-widget tool");
|
|
179
|
+
}
|
|
180
|
+
makeWidgetTool.tool.accessLevel = 20;
|
|
181
|
+
const provider = (0, contract_proxy_1.createContractProvider)(resolution);
|
|
182
|
+
const consumer = consumerVia(contract, provider, {
|
|
183
|
+
callerUserId: (0, utils_1.newid)(),
|
|
184
|
+
localUserId: (0, utils_1.newid)(),
|
|
185
|
+
});
|
|
186
|
+
await expect(consumer.tools["make-widget"]({ color: "blue" })).rejects.toThrow("User context is not available");
|
|
187
|
+
});
|
|
188
|
+
it("denies unclassified tools when the caller identity is missing", async () => {
|
|
189
|
+
const contract = makeContract();
|
|
190
|
+
const { resolution } = makeResolution();
|
|
191
|
+
const makeWidgetTool = resolution.tools?.["make-widget"];
|
|
192
|
+
if (!makeWidgetTool) {
|
|
193
|
+
throw new Error("expected make-widget tool");
|
|
194
|
+
}
|
|
195
|
+
makeWidgetTool.tool.accessLevel = undefined;
|
|
196
|
+
const provider = (0, contract_proxy_1.createContractProvider)(resolution);
|
|
197
|
+
const consumer = consumerVia(contract, provider, {});
|
|
198
|
+
await expect(consumer.tools["make-widget"]({ color: "blue" })).rejects.toThrow("missing caller identity");
|
|
199
|
+
});
|
|
150
200
|
it("forwards dataContextId on methods, tools, observables, and subscriptions", async () => {
|
|
151
201
|
const dataContextId = (0, utils_1.newid)();
|
|
152
202
|
const calls = [];
|
|
@@ -5,8 +5,16 @@ const user_trust_levels_1 = require("../../data/user-trust-levels");
|
|
|
5
5
|
const users_1 = require("../../data/users");
|
|
6
6
|
const socket_type_1 = require("../../device/socket.type");
|
|
7
7
|
const keys_1 = require("../../keys");
|
|
8
|
+
const system_ids_1 = require("../../system-ids");
|
|
8
9
|
const utils_1 = require("../../utils");
|
|
9
10
|
const index_1 = require("../index");
|
|
11
|
+
jest.mock("../../data/group-permissions", () => {
|
|
12
|
+
const actual = jest.requireActual("../../data/group-permissions");
|
|
13
|
+
return {
|
|
14
|
+
...actual,
|
|
15
|
+
getUserRole: jest.fn(async () => actual.GroupMemberRole.Founder),
|
|
16
|
+
};
|
|
17
|
+
});
|
|
10
18
|
jest.mock("../../data/user-trust-levels", () => ({
|
|
11
19
|
UserTrustLevels: jest.fn(),
|
|
12
20
|
}));
|
|
@@ -145,6 +153,26 @@ describe("Self-trusted contract caller authorization", () => {
|
|
|
145
153
|
})).rejects.toThrow("Permission denied");
|
|
146
154
|
router.dispose();
|
|
147
155
|
});
|
|
156
|
+
it("rejects remote Tool Access Control as local-only", async () => {
|
|
157
|
+
const { remoteIdentity, user } = makeIdentity();
|
|
158
|
+
const records = new Map();
|
|
159
|
+
const { personalContext, userContext } = setupUserContext(remoteIdentity.userId, records);
|
|
160
|
+
records.set(personalContext, user);
|
|
161
|
+
mockTrustGet.mockResolvedValue({ trustLevel: socket_type_1.TrustLevel.Self });
|
|
162
|
+
const [consumerTransport, providerTransport] = (0, index_1.inProcessTransportPair)();
|
|
163
|
+
const router = (0, index_1.createUserContextContractProviderRouter)(providerTransport, {
|
|
164
|
+
userContext,
|
|
165
|
+
remoteIdentity,
|
|
166
|
+
});
|
|
167
|
+
await expect(consumerTransport.emit(index_1.CONTRACT_REQUEST_CHANNEL, {
|
|
168
|
+
...call,
|
|
169
|
+
contractId: system_ids_1.toolAccessControlContractId,
|
|
170
|
+
member: "tool",
|
|
171
|
+
name: "approve",
|
|
172
|
+
operation: "run",
|
|
173
|
+
})).rejects.toThrow("local-only");
|
|
174
|
+
router.dispose();
|
|
175
|
+
});
|
|
148
176
|
});
|
|
149
177
|
describe("local user-context contract routing", () => {
|
|
150
178
|
function setupLocalRouter() {
|
|
@@ -180,6 +208,7 @@ describe("local user-context contract routing", () => {
|
|
|
180
208
|
outputSchema: { type: "simple", fields: [] },
|
|
181
209
|
code: "",
|
|
182
210
|
packageId: (0, utils_1.newid)(),
|
|
211
|
+
accessLevel: 0,
|
|
183
212
|
},
|
|
184
213
|
toolFn: () => dataContext.dataContextId,
|
|
185
214
|
},
|
|
@@ -239,4 +268,40 @@ describe("local user-context contract routing", () => {
|
|
|
239
268
|
await expect(setup.consumerTransport.emit(index_1.CONTRACT_REQUEST_CHANNEL, makeToolCall(setup.contractId))).rejects.toThrow("contract");
|
|
240
269
|
router.dispose();
|
|
241
270
|
});
|
|
271
|
+
it("appends host-only variable access to local package tool calls", async () => {
|
|
272
|
+
const setup = setupLocalRouter();
|
|
273
|
+
const resolveVariable = jest.fn(async ({ dataContext, variableName, requestingToolId }) => [dataContext.dataContextId, variableName, requestingToolId].join(":"));
|
|
274
|
+
(0, index_1.registerContractResolver)(setup.contractId, 1, () => ({
|
|
275
|
+
contractId: setup.contractId,
|
|
276
|
+
version: 1,
|
|
277
|
+
tools: {
|
|
278
|
+
inspect: {
|
|
279
|
+
tool: {
|
|
280
|
+
toolId: "00localcontractsecrettool",
|
|
281
|
+
name: "inspect",
|
|
282
|
+
usageDescription: "Resolve a local variable.",
|
|
283
|
+
inputSchema: { type: "simple", fields: [] },
|
|
284
|
+
outputSchema: { type: "simple", fields: [] },
|
|
285
|
+
code: "",
|
|
286
|
+
accessLevel: 0,
|
|
287
|
+
},
|
|
288
|
+
toolFn: async (variableName, context) => context.getVariable(variableName, "00localcontractsecrettool"),
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
}));
|
|
292
|
+
const router = (0, index_1.createLocalUserContextContractProviderRouter)(setup.providerTransport, {
|
|
293
|
+
getUserContext: async () => setup.userContext,
|
|
294
|
+
resolveVariable,
|
|
295
|
+
});
|
|
296
|
+
await expect(setup.consumerTransport.emit(index_1.CONTRACT_REQUEST_CHANNEL, {
|
|
297
|
+
...makeToolCall(setup.contractId),
|
|
298
|
+
args: ["OPENAI_API_KEY"],
|
|
299
|
+
})).resolves.toBe(`${setup.userId}:OPENAI_API_KEY:00localcontractsecrettool`);
|
|
300
|
+
expect(resolveVariable).toHaveBeenCalledWith(expect.objectContaining({
|
|
301
|
+
dataContext: expect.objectContaining({ dataContextId: setup.userId }),
|
|
302
|
+
variableName: "OPENAI_API_KEY",
|
|
303
|
+
requestingToolId: "00localcontractsecrettool",
|
|
304
|
+
}));
|
|
305
|
+
router.dispose();
|
|
306
|
+
});
|
|
242
307
|
});
|
|
@@ -154,7 +154,10 @@ describe("playground", () => {
|
|
|
154
154
|
contractId: CONTRACT_ID,
|
|
155
155
|
version: 1,
|
|
156
156
|
tools: {
|
|
157
|
-
logText: {
|
|
157
|
+
logText: {
|
|
158
|
+
tool: { toolId: "", name: "logText", accessLevel: 0 },
|
|
159
|
+
toolFn: logTextFn,
|
|
160
|
+
},
|
|
158
161
|
},
|
|
159
162
|
observables: { logCount: logCountObs },
|
|
160
163
|
observableWritability: { logCount: false },
|
|
@@ -208,6 +211,6 @@ describe("playground", () => {
|
|
|
208
211
|
expect(logs).toEqual(["log1", "log2"]);
|
|
209
212
|
expect(observedLogCount).toBe(2);
|
|
210
213
|
// TODO test tables so we can see what this looks like and how it works for both providers and consumers
|
|
211
|
-
// TODO consider renaming ContractResolution to ContractProviderInstance or something like that. ContractResolution is awkward.
|
|
214
|
+
// TODO consider renaming ContractResolution to ContractProviderInstance or something like that. ContractResolution is awkward.
|
|
212
215
|
});
|
|
213
216
|
});
|
|
@@ -17,6 +17,7 @@ describe("system contract catalog", () => {
|
|
|
17
17
|
system_ids_1.deviceOperationsContractId,
|
|
18
18
|
system_ids_1.networkDiagnosticsContractId,
|
|
19
19
|
system_ids_1.networkControlContractId,
|
|
20
|
+
system_ids_1.toolAccessControlContractId,
|
|
20
21
|
]));
|
|
21
22
|
});
|
|
22
23
|
it("registers the Logs live resolver", async () => {
|
|
@@ -34,6 +35,8 @@ describe("system contract catalog", () => {
|
|
|
34
35
|
expect(registry.getProviderPackageId(system_ids_1.networkDiagnosticsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
35
36
|
expect(registry.resolve(system_ids_1.networkControlContractId, 1)?.name).toBe("System Network Control");
|
|
36
37
|
expect(registry.getProviderPackageId(system_ids_1.networkControlContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
38
|
+
expect(registry.resolve(system_ids_1.toolAccessControlContractId, 1)?.name).toBe("System Tool Access Control");
|
|
39
|
+
expect(registry.getProviderPackageId(system_ids_1.toolAccessControlContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
37
40
|
});
|
|
38
41
|
it("registerSystemContract makes new contracts installable without loader changes", () => {
|
|
39
42
|
const fakeContractId = (0, utils_1.newid)();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DataContext } from "../context/data-context";
|
|
1
2
|
import type { Table } from "../data/orm/table";
|
|
2
3
|
import type { IToolInstance } from "../data/tools";
|
|
3
4
|
import type { Event, ISubscriptionResult } from "../events";
|
|
@@ -195,6 +196,22 @@ export interface IContractConsumer extends IContractConsumerBase {
|
|
|
195
196
|
subscribe: (handler: (value: any) => void) => ISubscriptionResult;
|
|
196
197
|
}>;
|
|
197
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Trusted host capabilities appended to local package-contract tool calls.
|
|
201
|
+
*
|
|
202
|
+
* The context is constructed by the provider host after it authorizes the data-context
|
|
203
|
+
* route. It is never serialized to the consumer and is intentionally absent for remote
|
|
204
|
+
* contract calls unless a host explicitly opts in.
|
|
205
|
+
*/
|
|
206
|
+
export interface IContractToolContext {
|
|
207
|
+
/** Authorized data context in which the tool is executing. */
|
|
208
|
+
dataContextId: string;
|
|
209
|
+
/**
|
|
210
|
+
* Resolve a persistent variable in the authorized context. Secret values are decrypted
|
|
211
|
+
* by the host and returned only to the provider-side tool implementation.
|
|
212
|
+
*/
|
|
213
|
+
getVariable(variableName: string, requestingToolId: string): Promise<string>;
|
|
214
|
+
}
|
|
198
215
|
/**
|
|
199
216
|
* Build the **consumer** side of a contract proxy from a contract definition and a
|
|
200
217
|
* transport. Member names come from the contract shape; table members are backed by a
|
|
@@ -234,6 +251,11 @@ export interface IContractResolution {
|
|
|
234
251
|
version: number;
|
|
235
252
|
tables?: Record<string, Table<any>>;
|
|
236
253
|
tools?: Record<string, IToolInstance>;
|
|
254
|
+
/**
|
|
255
|
+
* Host-only capabilities appended as the final argument to provider tool functions.
|
|
256
|
+
* Omit this for remote or otherwise untrusted provider routes.
|
|
257
|
+
*/
|
|
258
|
+
toolContext?: IContractToolContext;
|
|
237
259
|
observables?: Record<string, Observable<any>>;
|
|
238
260
|
/**
|
|
239
261
|
* Provider-owned write policy for live observables. A `set` is allowed only when the
|
|
@@ -254,6 +276,11 @@ export interface IContractCallContext {
|
|
|
254
276
|
callerUserId?: string;
|
|
255
277
|
/** User id of the local device executing the call. */
|
|
256
278
|
localUserId?: string;
|
|
279
|
+
/**
|
|
280
|
+
* Provider-side data context used to resolve the caller's group/personal role.
|
|
281
|
+
* In-process only — never serialized across a connection.
|
|
282
|
+
*/
|
|
283
|
+
dataContext?: DataContext;
|
|
257
284
|
}
|
|
258
285
|
/**
|
|
259
286
|
* A gate that decides whether a given call is allowed. Runs before dispatch on the
|
|
@@ -5,6 +5,8 @@ exports.createContractConsumer = createContractConsumer;
|
|
|
5
5
|
exports.createContractProvider = createContractProvider;
|
|
6
6
|
exports.createContractProviderEndpoint = createContractProviderEndpoint;
|
|
7
7
|
exports.createContractProviderSession = createContractProviderSession;
|
|
8
|
+
const access_level_1 = require("../data/access-level");
|
|
9
|
+
const group_permissions_1 = require("../data/group-permissions");
|
|
8
10
|
const decorators_1 = require("../data/orm/decorators");
|
|
9
11
|
const observable_1 = require("../observable");
|
|
10
12
|
const utils_1 = require("../utils");
|
|
@@ -340,6 +342,37 @@ const sameUserContractPermissionCheck = (_call, context) => {
|
|
|
340
342
|
return Boolean(context.localUserId) && context.callerUserId === context.localUserId;
|
|
341
343
|
};
|
|
342
344
|
exports.sameUserContractPermissionCheck = sameUserContractPermissionCheck;
|
|
345
|
+
/**
|
|
346
|
+
* Deny a contract tool when the caller’s group/personal access is below the tool.
|
|
347
|
+
*
|
|
348
|
+
* Tools at {@link AccessLevel.None} are unrestricted and do not need a caller
|
|
349
|
+
* identity. Higher levels fail closed if the transport omitted `callerUserId`
|
|
350
|
+
* and `localUserId`. Role lookup uses {@link IContractCallContext.dataContext}
|
|
351
|
+
* when the host attached one, so multi-device processes do not wait on the
|
|
352
|
+
* user-context singleton.
|
|
353
|
+
*
|
|
354
|
+
* Remote Self-trust is a separate, stricter gate applied by the connection router.
|
|
355
|
+
*
|
|
356
|
+
* @param tool - Live tool instance being dispatched.
|
|
357
|
+
* @param call - Inbound contract call (provides dataContextId).
|
|
358
|
+
* @param context - Caller identity from the transport.
|
|
359
|
+
*/
|
|
360
|
+
async function assertContractToolAccess(tool, call, context) {
|
|
361
|
+
const required = (0, access_level_1.resolveAccessLevel)(tool.tool.accessLevel);
|
|
362
|
+
if (required <= access_level_1.AccessLevel.None) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const userId = context.callerUserId ?? context.localUserId;
|
|
366
|
+
if (!userId) {
|
|
367
|
+
throw new Error(`Permission denied: missing caller identity for tool '${tool.tool.name}'`);
|
|
368
|
+
}
|
|
369
|
+
const userLevel = context.dataContext
|
|
370
|
+
? await (0, group_permissions_1.getUserAccessLevel)(context.dataContext, userId)
|
|
371
|
+
: (0, access_level_1.accessLevelFromGroupRole)(await (0, group_permissions_1.getUserRole)(call.dataContextId || context.localUserId || userId, userId));
|
|
372
|
+
if (userLevel < required) {
|
|
373
|
+
throw new Error(`Permission denied: ${tool.tool.name} requires ${(0, access_level_1.getAccessLevelLabel)(required)} (${required})`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
343
376
|
/**
|
|
344
377
|
* Build the **provider** side of a contract proxy: an async handler that permission-checks
|
|
345
378
|
* an {@link IContractCall} and dispatches it to the live table method / tool fn / observable
|
|
@@ -394,7 +427,10 @@ function createContractProvider(resolution, opts = {}) {
|
|
|
394
427
|
if (!tool) {
|
|
395
428
|
throw new Error(`Contract ${call.contractId} does not provide tool '${call.name}'`);
|
|
396
429
|
}
|
|
397
|
-
|
|
430
|
+
await assertContractToolAccess(tool, call, context);
|
|
431
|
+
return resolution.toolContext
|
|
432
|
+
? tool.toolFn(...call.args, resolution.toolContext)
|
|
433
|
+
: tool.toolFn(...call.args);
|
|
398
434
|
}
|
|
399
435
|
case "observable": {
|
|
400
436
|
const obs = resolution.observables?.[call.name];
|
|
@@ -12,6 +12,14 @@ import type { IContractTransport } from "./contract-transport";
|
|
|
12
12
|
export type ContractResolver = (ctx: {
|
|
13
13
|
dataContext: DataContext;
|
|
14
14
|
}) => IContractResolution | Promise<IContractResolution>;
|
|
15
|
+
/** Input supplied to a trusted local host when a package tool resolves a pvar. */
|
|
16
|
+
export interface ILocalContractVariableRequest {
|
|
17
|
+
dataContext: DataContext;
|
|
18
|
+
variableName: string;
|
|
19
|
+
requestingToolId: string;
|
|
20
|
+
}
|
|
21
|
+
/** Host callback that resolves plaintext only inside a local provider process. */
|
|
22
|
+
export type LocalContractVariableResolver = (request: ILocalContractVariableRequest) => Promise<string>;
|
|
15
23
|
/** Connection-authenticated identity fields used to authorize remote contract calls. */
|
|
16
24
|
export type ContractRemoteIdentity = Pick<IDeviceInfo, "deviceId" | "userId" | "publicKey" | "publicBoxKey">;
|
|
17
25
|
/**
|
|
@@ -45,10 +53,12 @@ export declare function isSelfTrustedContractCaller(userContext: UserContext, re
|
|
|
45
53
|
* @param transport Contract transport backed by an authenticated local session.
|
|
46
54
|
* @param opts.getUserContext Lazy accessor for the host's loaded user context.
|
|
47
55
|
* @param opts.allowedContractIds Optional contract allowlist for this session.
|
|
56
|
+
* @param opts.resolveVariable Optional host-only pvar resolver exposed to local package tools.
|
|
48
57
|
*/
|
|
49
58
|
export declare function createLocalUserContextContractProviderRouter(transport: IContractTransport, opts: {
|
|
50
59
|
getUserContext: () => Promise<UserContext>;
|
|
51
60
|
allowedContractIds?: ReadonlySet<string>;
|
|
61
|
+
resolveVariable?: LocalContractVariableResolver;
|
|
52
62
|
}): IContractProviderRouter;
|
|
53
63
|
/**
|
|
54
64
|
* Create the local-object provider router for one verified device connection.
|
|
@@ -10,6 +10,7 @@ const user_permissions_1 = require("../data/user-permissions");
|
|
|
10
10
|
const user_trust_levels_1 = require("../data/user-trust-levels");
|
|
11
11
|
const users_1 = require("../data/users");
|
|
12
12
|
const socket_type_1 = require("../device/socket.type");
|
|
13
|
+
const system_ids_1 = require("../system-ids");
|
|
13
14
|
const contract_provider_router_1 = require("./contract-provider-router");
|
|
14
15
|
const contract_proxy_1 = require("./contract-proxy");
|
|
15
16
|
const types_1 = require("./types");
|
|
@@ -63,15 +64,20 @@ async function isSelfTrustedContractCaller(userContext, remoteIdentity) {
|
|
|
63
64
|
return trustLevel === socket_type_1.TrustLevel.Self;
|
|
64
65
|
}
|
|
65
66
|
async function authorizeUserContextCall(call, userContext, remoteIdentity) {
|
|
67
|
+
if (call.contractId === system_ids_1.toolAccessControlContractId) {
|
|
68
|
+
throw new Error("Permission denied: tool access control is local-only");
|
|
69
|
+
}
|
|
70
|
+
const dataContextId = call.dataContextId || userContext.userId;
|
|
66
71
|
const context = {
|
|
67
72
|
callerUserId: remoteIdentity.userId,
|
|
68
73
|
localUserId: userContext.userId,
|
|
74
|
+
dataContext: userContext.getDataContext(dataContextId),
|
|
69
75
|
};
|
|
70
76
|
if (!(await isSelfTrustedContractCaller(userContext, remoteIdentity))) {
|
|
71
77
|
throw new Error(`Permission denied: ${call.member} '${call.name}'.${call.operation} on contract ${call.contractId}`);
|
|
72
78
|
}
|
|
73
79
|
return {
|
|
74
|
-
dataContextId
|
|
80
|
+
dataContextId,
|
|
75
81
|
context,
|
|
76
82
|
};
|
|
77
83
|
}
|
|
@@ -100,9 +106,10 @@ function getAuthorizedLocalDataContext(userContext, requestedId) {
|
|
|
100
106
|
* @param transport Contract transport backed by an authenticated local session.
|
|
101
107
|
* @param opts.getUserContext Lazy accessor for the host's loaded user context.
|
|
102
108
|
* @param opts.allowedContractIds Optional contract allowlist for this session.
|
|
109
|
+
* @param opts.resolveVariable Optional host-only pvar resolver exposed to local package tools.
|
|
103
110
|
*/
|
|
104
111
|
function createLocalUserContextContractProviderRouter(transport, opts) {
|
|
105
|
-
const { getUserContext, allowedContractIds } = opts;
|
|
112
|
+
const { getUserContext, allowedContractIds, resolveVariable } = opts;
|
|
106
113
|
return (0, contract_provider_router_1.createContractProviderRouter)(transport, {
|
|
107
114
|
authorizeCall: async (call) => {
|
|
108
115
|
if (allowedContractIds && !allowedContractIds.has(call.contractId)) {
|
|
@@ -113,6 +120,7 @@ function createLocalUserContextContractProviderRouter(transport, opts) {
|
|
|
113
120
|
const context = {
|
|
114
121
|
callerUserId: userContext.userId,
|
|
115
122
|
localUserId: userContext.userId,
|
|
123
|
+
dataContext,
|
|
116
124
|
};
|
|
117
125
|
return {
|
|
118
126
|
dataContextId: dataContext.dataContextId,
|
|
@@ -127,7 +135,16 @@ function createLocalUserContextContractProviderRouter(transport, opts) {
|
|
|
127
135
|
}
|
|
128
136
|
const dataContext = getAuthorizedLocalDataContext(userContext, dataContextId);
|
|
129
137
|
const resolution = await resolver({ dataContext });
|
|
130
|
-
|
|
138
|
+
const localResolution = resolveVariable
|
|
139
|
+
? {
|
|
140
|
+
...resolution,
|
|
141
|
+
toolContext: {
|
|
142
|
+
dataContextId: dataContext.dataContextId,
|
|
143
|
+
getVariable: (variableName, requestingToolId) => resolveVariable({ dataContext, variableName, requestingToolId }),
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
: resolution;
|
|
147
|
+
return (0, contract_proxy_1.createContractProviderEndpoint)(localResolution, { context, notify });
|
|
131
148
|
},
|
|
132
149
|
});
|
|
133
150
|
}
|
|
@@ -150,6 +167,7 @@ function createUserContextContractProviderRouter(transport, opts) {
|
|
|
150
167
|
const context = {
|
|
151
168
|
callerUserId: remoteIdentity.userId,
|
|
152
169
|
localUserId: userContext.userId,
|
|
170
|
+
dataContext: userContext.userDataContext,
|
|
153
171
|
};
|
|
154
172
|
return (0, contract_provider_router_1.createContractProviderRouter)(transport, {
|
|
155
173
|
context,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
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
|
-
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, createLocalUserContextContractProviderRouter, createUserContextContractProviderRouter, getContractResolver, handleContractCall, isSelfTrustedContractCaller, registerContractResolver, } from "./contract-resolvers";
|
|
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 IContractToolContext, type ITableProxy, sameUserContractPermissionCheck, } from "./contract-proxy";
|
|
5
|
+
export { type ContractRemoteIdentity, type ContractResolver, createLocalUserContextContractProviderRouter, createUserContextContractProviderRouter, getContractResolver, handleContractCall, type ILocalContractVariableRequest, isSelfTrustedContractCaller, type LocalContractVariableResolver, 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";
|
|
@@ -13,6 +13,7 @@ export { ContractRegistry } from "./registry";
|
|
|
13
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";
|
|
14
14
|
export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./system/logs-contract";
|
|
15
15
|
export * from "./system/network-contracts";
|
|
16
|
+
export { getToolAccessControlContractDefinition, type IToolAccessControlConsumer, TOOL_ACCESS_CONTROL_CONTRACT_VERSION, } from "./system/tool-access-control-contract";
|
|
16
17
|
export { type ISystemContractRegistration, installSystemContracts, listSystemContracts, registerSystemContract, } from "./system-contracts";
|
|
17
18
|
export type { IAlsoImplementsDeclaration, IConsumedContract, IConsumedContractHandle, IConsumedContractOptions, IContractDefinition, IContractEvent, IContractObservable, IContractTable, IContractTool, IPackageDefinitionResult, IResolvedContract, IValidationError, IValidationResult, } from "./types";
|
|
18
19
|
export { contractKey } from "./types";
|
package/dist/contracts/index.js
CHANGED
|
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
18
|
-
exports.validateProviderSatisfiesContract = exports.validateImmutability = exports.validateAlsoImplements = exports.contractKey = exports.registerSystemContract = exports.listSystemContracts = void 0;
|
|
17
|
+
exports.getToolAccessControlContractDefinition = 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 = exports.installSystemContracts = exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = void 0;
|
|
19
19
|
var builder_1 = require("./builder");
|
|
20
20
|
Object.defineProperty(exports, "ContractBuilder", { enumerable: true, get: function () { return builder_1.ContractBuilder; } });
|
|
21
21
|
Object.defineProperty(exports, "definePackage", { enumerable: true, get: function () { return builder_1.definePackage; } });
|
|
@@ -80,6 +80,9 @@ Object.defineProperty(exports, "getLogsContractDefinition", { enumerable: true,
|
|
|
80
80
|
Object.defineProperty(exports, "LOGS_CONTRACT_VERSION", { enumerable: true, get: function () { return logs_contract_1.LOGS_CONTRACT_VERSION; } });
|
|
81
81
|
Object.defineProperty(exports, "resolveLogsContract", { enumerable: true, get: function () { return logs_contract_1.resolveLogsContract; } });
|
|
82
82
|
__exportStar(require("./system/network-contracts"), exports);
|
|
83
|
+
var tool_access_control_contract_1 = require("./system/tool-access-control-contract");
|
|
84
|
+
Object.defineProperty(exports, "getToolAccessControlContractDefinition", { enumerable: true, get: function () { return tool_access_control_contract_1.getToolAccessControlContractDefinition; } });
|
|
85
|
+
Object.defineProperty(exports, "TOOL_ACCESS_CONTROL_CONTRACT_VERSION", { enumerable: true, get: function () { return tool_access_control_contract_1.TOOL_ACCESS_CONTROL_CONTRACT_VERSION; } });
|
|
83
86
|
var system_contracts_1 = require("./system-contracts");
|
|
84
87
|
Object.defineProperty(exports, "installSystemContracts", { enumerable: true, get: function () { return system_contracts_1.installSystemContracts; } });
|
|
85
88
|
Object.defineProperty(exports, "listSystemContracts", { enumerable: true, get: function () { return system_contracts_1.listSystemContracts; } });
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import "./device-operations-contract";
|
|
6
6
|
import "./logs-contract";
|
|
7
7
|
import "./network-contracts";
|
|
8
|
+
import "./tool-access-control-contract";
|
|
8
9
|
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";
|
|
9
10
|
export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./logs-contract";
|
|
10
11
|
export * from "./network-contracts";
|
|
12
|
+
export { getToolAccessControlContractDefinition, type IToolAccessControlConsumer, TOOL_ACCESS_CONTROL_CONTRACT_VERSION, } from "./tool-access-control-contract";
|