@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.
Files changed (53) hide show
  1. package/dist/context/user-context-singleton.d.ts +42 -0
  2. package/dist/context/user-context-singleton.js +45 -0
  3. package/dist/contracts/__tests__/contract-proxy.test.js +51 -1
  4. package/dist/contracts/__tests__/contract-resolvers.test.js +65 -0
  5. package/dist/contracts/__tests__/playground.test.js +5 -2
  6. package/dist/contracts/__tests__/system-contracts.test.js +3 -0
  7. package/dist/contracts/contract-proxy.d.ts +27 -0
  8. package/dist/contracts/contract-proxy.js +37 -1
  9. package/dist/contracts/contract-resolvers.d.ts +10 -0
  10. package/dist/contracts/contract-resolvers.js +21 -3
  11. package/dist/contracts/index.d.ts +3 -2
  12. package/dist/contracts/index.js +5 -2
  13. package/dist/contracts/system/index.d.ts +2 -0
  14. package/dist/contracts/system/index.js +5 -1
  15. package/dist/contracts/system/tool-access-control-contract.d.ts +35 -0
  16. package/dist/contracts/system/tool-access-control-contract.js +70 -0
  17. package/dist/data/access-level.d.ts +72 -0
  18. package/dist/data/access-level.js +109 -0
  19. package/dist/data/access-level.test.d.ts +1 -0
  20. package/dist/data/access-level.test.js +53 -0
  21. package/dist/data/assistants.d.ts +24 -0
  22. package/dist/data/assistants.js +21 -0
  23. package/dist/data/group-member-roles.d.ts +9 -0
  24. package/dist/data/group-member-roles.js +9 -0
  25. package/dist/data/group-permissions.d.ts +55 -1
  26. package/dist/data/group-permissions.js +76 -6
  27. package/dist/data/index.d.ts +3 -1
  28. package/dist/data/index.js +3 -1
  29. package/dist/data/orm/sql.data-source.d.ts +10 -0
  30. package/dist/data/orm/sql.data-source.js +48 -30
  31. package/dist/data/orm/sql.data-source.test.js +13 -0
  32. package/dist/data/package-version-resolver.test.js +2 -0
  33. package/dist/data/tool-access-approvals.d.ts +126 -0
  34. package/dist/data/tool-access-approvals.js +86 -0
  35. package/dist/data/tool-access.d.ts +162 -0
  36. package/dist/data/tool-access.js +235 -0
  37. package/dist/data/tool-access.test.d.ts +1 -0
  38. package/dist/data/tool-access.test.js +159 -0
  39. package/dist/data/tools.d.ts +15 -0
  40. package/dist/data/tools.js +11 -0
  41. package/dist/data/workflow-logs.d.ts +5 -5
  42. package/dist/data/workflow-runs.d.ts +2 -2
  43. package/dist/device-pairing/types.d.ts +6 -6
  44. package/dist/package-installer/package-creator.d.ts +31 -0
  45. package/dist/package-installer/package-creator.js +140 -40
  46. package/dist/package-installer/package-creator.test.js +113 -11
  47. package/dist/rpc-types.d.ts +0 -17
  48. package/dist/rpc-types.js +0 -15
  49. package/dist/system-ids.d.ts +13 -0
  50. package/dist/system-ids.js +14 -1
  51. package/package.json +1 -1
  52. package/dist/data/voice-messages.d.ts +0 -33
  53. package/dist/data/voice-messages.js +0 -33
@@ -3,19 +3,41 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GroupMemberRole = void 0;
4
4
  exports.getUserRole = getUserRole;
5
5
  exports.getUserRoleFromPublicKey = getUserRoleFromPublicKey;
6
+ exports.getCurrentUserAccessLevel = getCurrentUserAccessLevel;
7
+ exports.getUserAccessLevel = getUserAccessLevel;
6
8
  exports.verifyGroupSignature = verifyGroupSignature;
7
9
  exports.isGroupMemberSignatureValid = isGroupMemberSignatureValid;
8
10
  const context_1 = require("../context");
9
11
  const keys_1 = require("../keys");
12
+ const access_level_1 = require("./access-level");
10
13
  const group_member_roles_1 = require("./group-member-roles");
11
14
  Object.defineProperty(exports, "GroupMemberRole", { enumerable: true, get: function () { return group_member_roles_1.GroupMemberRole; } });
12
- async function getUserRole(groupId, userId) {
15
+ /**
16
+ * Return a user's {@link GroupMemberRole} in `groupId`.
17
+ *
18
+ * Missing groups and the group's founder resolve to {@link GroupMemberRole.Founder},
19
+ * which is how a personal context (no Groups row) becomes access 100.
20
+ *
21
+ * Prefer passing `userContext` from the provider that owns the data. The
22
+ * process singleton is only a fallback and is not awaited — multi-device
23
+ * tests never set it, and hanging here would stall contract calls.
24
+ *
25
+ * @param groupId - Group id, or the user's id for their personal context.
26
+ * @param userId - User whose role is requested.
27
+ * @param userContext - Provider-owned context. Falls back to {@link peekUserContext}.
28
+ * @throws If neither an explicit context nor the process singleton is available.
29
+ */
30
+ async function getUserRole(groupId, userId, userContext) {
13
31
  const { Groups } = await Promise.resolve().then(() => require("./groups"));
14
32
  const { GroupMembers } = await Promise.resolve().then(() => require("./group-members"));
15
- const userContext = await (0, context_1.getUserContext)();
16
- const groupDataContext = userContext.getDataContext(groupId);
33
+ const ctx = userContext ?? (0, context_1.peekUserContext)();
34
+ if (!ctx) {
35
+ throw new Error("User context is not available");
36
+ }
37
+ await ctx.loadingPromise;
38
+ const groupDataContext = ctx.getDataContext(groupId);
17
39
  const group = (await Groups(groupDataContext).get(groupId)) ||
18
- (await Groups(userContext.userDataContext).get(groupId));
40
+ (await Groups(ctx.userDataContext).get(groupId));
19
41
  // If the group doesn't exist or the current user is explicitly the founder, return Founder role
20
42
  if (!group || group.founderUserId === userId) {
21
43
  return group_member_roles_1.GroupMemberRole.Founder;
@@ -26,17 +48,57 @@ async function getUserRole(groupId, userId) {
26
48
  }
27
49
  return group.publicRole || group_member_roles_1.GroupMemberRole.None;
28
50
  }
51
+ /**
52
+ * Resolve a group role from the signing public key of a Users record.
53
+ *
54
+ * Uses {@link peekUserContext}; throws if the process singleton is unset.
55
+ *
56
+ * @param groupId - Group or personal context id.
57
+ * @param publicKey - User public key that signed a record.
58
+ */
29
59
  async function getUserRoleFromPublicKey(groupId, publicKey) {
30
60
  const { Users } = await Promise.resolve().then(() => require("./users"));
31
- const userContext = await (0, context_1.getUserContext)();
61
+ const userContext = (0, context_1.peekUserContext)();
62
+ if (!userContext) {
63
+ throw new Error("User context is not available");
64
+ }
65
+ await userContext.loadingPromise;
32
66
  const groupDataContext = userContext.getDataContext(groupId);
33
67
  const user = (await Users(groupDataContext).findOne({ publicKey })) ||
34
68
  (await Users(userContext.userDataContext).findOne({ publicKey }));
35
69
  if (user) {
36
- return getUserRole(groupId, user?.userId);
70
+ return getUserRole(groupId, user?.userId, userContext);
37
71
  }
38
72
  return group_member_roles_1.GroupMemberRole.None;
39
73
  }
74
+ /**
75
+ * Return the current user's access level in `dataContext`.
76
+ *
77
+ * Personal contexts (no `groupId`) use the user's id and resolve to 100.
78
+ *
79
+ * @param dataContext - Context whose group/personal role is evaluated.
80
+ */
81
+ async function getCurrentUserAccessLevel(dataContext) {
82
+ const userId = dataContext.userContext.userId;
83
+ return getUserAccessLevel(dataContext, userId);
84
+ }
85
+ /**
86
+ * Return `userId`'s access level in `dataContext`.
87
+ *
88
+ * @param dataContext - Context whose group/personal role is evaluated.
89
+ * @param userId - User to resolve.
90
+ */
91
+ async function getUserAccessLevel(dataContext, userId) {
92
+ const contextKey = dataContext.groupId ?? dataContext.userContext.userId;
93
+ const role = await getUserRole(contextKey, userId, dataContext.userContext);
94
+ return (0, access_level_1.accessLevelFromGroupRole)(role);
95
+ }
96
+ /**
97
+ * Verify that a group record was signed by an Admin+ member (Founder to change founder).
98
+ *
99
+ * @param group - Proposed group record.
100
+ * @param oldGroup - Previous record when this is an update.
101
+ */
40
102
  async function verifyGroupSignature(group, oldGroup) {
41
103
  (0, keys_1.verifyObjectSignature)(group);
42
104
  const publicKey = (0, keys_1.getPublicKeyFromObjectSignature)(group) ?? "";
@@ -50,6 +112,14 @@ async function verifyGroupSignature(group, oldGroup) {
50
112
  throw new Error("Only group admins can modify group settings");
51
113
  }
52
114
  }
115
+ /**
116
+ * Return whether a group-member write is signed by someone allowed to make it.
117
+ *
118
+ * @param groupId - Group the membership belongs to.
119
+ * @param newGroupMember - Proposed membership row.
120
+ * @param oldGroupMember - Previous row when this is an update.
121
+ * @param signerRole - Optional precomputed signer role.
122
+ */
53
123
  async function isGroupMemberSignatureValid(groupId, newGroupMember, oldGroupMember, signerRole) {
54
124
  oldGroupMember ??= newGroupMember;
55
125
  // Basic signature verification
@@ -1,3 +1,4 @@
1
+ export * from "./access-level";
1
2
  export * from "./assistants";
2
3
  export * from "./change-tracking";
3
4
  export * from "./channels";
@@ -20,12 +21,13 @@ export * from "./peer-types";
20
21
  export * from "./persistent-vars";
21
22
  export * from "./sync-recovery-queue";
22
23
  export * from "./table-definitions-table";
24
+ export * from "./tool-access";
25
+ export * from "./tool-access-approvals";
23
26
  export * from "./tool-tests";
24
27
  export * from "./tools";
25
28
  export * from "./user-permissions";
26
29
  export * from "./user-trust-levels";
27
30
  export * from "./users";
28
- export * from "./voice-messages";
29
31
  export * from "./welcome-modal.pvar";
30
32
  export * from "./workflow-logs";
31
33
  export * from "./workflow-runs";
@@ -14,6 +14,7 @@ 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
+ __exportStar(require("./access-level"), exports);
17
18
  __exportStar(require("./assistants"), exports);
18
19
  __exportStar(require("./change-tracking"), exports);
19
20
  __exportStar(require("./channels"), exports);
@@ -36,12 +37,13 @@ __exportStar(require("./peer-types"), exports);
36
37
  __exportStar(require("./persistent-vars"), exports);
37
38
  __exportStar(require("./sync-recovery-queue"), exports);
38
39
  __exportStar(require("./table-definitions-table"), exports);
40
+ __exportStar(require("./tool-access"), exports);
41
+ __exportStar(require("./tool-access-approvals"), exports);
39
42
  __exportStar(require("./tool-tests"), exports);
40
43
  __exportStar(require("./tools"), exports);
41
44
  __exportStar(require("./user-permissions"), exports);
42
45
  __exportStar(require("./user-trust-levels"), exports);
43
46
  __exportStar(require("./users"), exports);
44
- __exportStar(require("./voice-messages"), exports);
45
47
  __exportStar(require("./welcome-modal.pvar"), exports);
46
48
  __exportStar(require("./workflow-logs"), exports);
47
49
  __exportStar(require("./workflow-runs"), exports);
@@ -34,6 +34,16 @@ export declare class SQLDataSource<T extends {
34
34
  delete(idOrRecord: string | T): Promise<void>;
35
35
  dropTableIfExists(): Promise<void>;
36
36
  clearTable(): Promise<void>;
37
+ /**
38
+ * Validate `record` and copy Zod defaults onto missing keys so NOT NULL
39
+ * columns (for example `accessLevel`) are written on insert.
40
+ */
41
+ private applySchemaDefaults;
42
+ /**
43
+ * Columns to SET on update. Required fields that are missing are omitted so
44
+ * older peers without a new column do not overwrite a local value with NULL.
45
+ */
46
+ private fieldsForUpdate;
37
47
  initRecord(data?: Partial<T>): T;
38
48
  /**
39
49
  * Synchronous insert for use within transactions.
@@ -245,13 +245,7 @@ class SQLDataSource {
245
245
  // @ts-expect-error - need to figure out how to get typescript to understand what's going on here
246
246
  record[this.metaData.primaryKeyName] = (0, utils_1.newid)();
247
247
  }
248
- // validate data
249
- try {
250
- this.schema.parse(record);
251
- }
252
- catch (e) {
253
- throw new Error(`Validation on insert failed for ${this.tableName}: ${e}`);
254
- }
248
+ this.applySchemaDefaults(record);
255
249
  const fields = this.metaData.fields.map((field) => `"${field.name}"`).join(", ");
256
250
  const values = this.metaData.fields.map((field) => jsValueToSqlValue(record[field.name]));
257
251
  const placeholders = values.map((_v) => "?").join(", ");
@@ -265,16 +259,14 @@ class SQLDataSource {
265
259
  // @ts-expect-error - need to figure out how to get typescript to understand what's going on here
266
260
  record[this.metaData.primaryKeyName] = (0, utils_1.newid)();
267
261
  }
268
- // validate data
269
262
  this.schema.parse(record);
270
263
  const primaryKey = record[this.metaData.primaryKeyName];
271
- const fields = this.metaData.fields
272
- .filter((field) => field.name !== this.metaData.primaryKeyName)
273
- .map((field) => `"${field.name}" = ?`)
274
- .join(",\n");
275
- const values = this.metaData.fields
276
- .filter((field) => field.name !== this.metaData.primaryKeyName)
277
- .map((field) => jsValueToSqlValue(record[field.name]));
264
+ const updateFields = this.fieldsForUpdate(record);
265
+ if (updateFields.length === 0) {
266
+ return record;
267
+ }
268
+ const fields = updateFields.map((field) => `"${field.name}" = ?`).join(",\n");
269
+ const values = updateFields.map((field) => jsValueToSqlValue(record[field.name]));
278
270
  const sql = [
279
271
  `UPDATE "${this.tableName}"`,
280
272
  `SET ${fields}`,
@@ -299,6 +291,40 @@ class SQLDataSource {
299
291
  const sql = `DELETE FROM "${this.tableName}"`;
300
292
  await this.db.exec(sql, []);
301
293
  }
294
+ /**
295
+ * Validate `record` and copy Zod defaults onto missing keys so NOT NULL
296
+ * columns (for example `accessLevel`) are written on insert.
297
+ */
298
+ applySchemaDefaults(record) {
299
+ let parsed;
300
+ try {
301
+ parsed = this.schema.parse(record);
302
+ }
303
+ catch (e) {
304
+ throw new Error(`Validation on insert failed for ${this.tableName}: ${e}`);
305
+ }
306
+ const writable = record;
307
+ for (const field of this.metaData.fields) {
308
+ if (writable[field.name] === undefined && parsed[field.name] !== undefined) {
309
+ writable[field.name] = parsed[field.name];
310
+ }
311
+ }
312
+ }
313
+ /**
314
+ * Columns to SET on update. Required fields that are missing are omitted so
315
+ * older peers without a new column do not overwrite a local value with NULL.
316
+ */
317
+ fieldsForUpdate(record) {
318
+ return this.metaData.fields.filter((field) => {
319
+ if (field.name === this.metaData.primaryKeyName) {
320
+ return false;
321
+ }
322
+ if (record[field.name] === undefined && !field.optional) {
323
+ return false;
324
+ }
325
+ return true;
326
+ });
327
+ }
302
328
  initRecord(data = {}) {
303
329
  const defaults = {};
304
330
  for (const field of this.metaData.fields) {
@@ -323,13 +349,7 @@ class SQLDataSource {
323
349
  // @ts-expect-error - need to figure out how to get typescript to understand what's going on here
324
350
  record[this.metaData.primaryKeyName] = (0, utils_1.newid)();
325
351
  }
326
- // validate data
327
- try {
328
- this.schema.parse(record);
329
- }
330
- catch (e) {
331
- throw new Error(`Validation on insert failed for ${this.tableName}: ${e}`);
332
- }
352
+ this.applySchemaDefaults(record);
333
353
  const fields = this.metaData.fields.map((field) => `"${field.name}"`).join(", ");
334
354
  const values = this.metaData.fields.map((field) => jsValueToSqlValue(record[field.name]));
335
355
  const placeholders = values.map((_v) => "?").join(", ");
@@ -346,16 +366,14 @@ class SQLDataSource {
346
366
  // @ts-expect-error - need to figure out how to get typescript to understand what's going on here
347
367
  record[this.metaData.primaryKeyName] = (0, utils_1.newid)();
348
368
  }
349
- // validate data
350
369
  this.schema.parse(record);
351
370
  const primaryKey = record[this.metaData.primaryKeyName];
352
- const fields = this.metaData.fields
353
- .filter((field) => field.name !== this.metaData.primaryKeyName)
354
- .map((field) => `"${field.name}" = ?`)
355
- .join(",\n");
356
- const values = this.metaData.fields
357
- .filter((field) => field.name !== this.metaData.primaryKeyName)
358
- .map((field) => jsValueToSqlValue(record[field.name]));
371
+ const updateFields = this.fieldsForUpdate(record);
372
+ if (updateFields.length === 0) {
373
+ return record;
374
+ }
375
+ const fields = updateFields.map((field) => `"${field.name}" = ?`).join(",\n");
376
+ const values = updateFields.map((field) => jsValueToSqlValue(record[field.name]));
359
377
  const sql = [
360
378
  `UPDATE "${this.tableName}"`,
361
379
  `SET ${fields}`,
@@ -205,6 +205,19 @@ describe("table", () => {
205
205
  newTask.title = "Test Task";
206
206
  expect(() => TasksTable.schema.parse(newTask)).not.toThrow();
207
207
  });
208
+ it("applies schema defaults on insert and preserves required fields on partial update", async () => {
209
+ const inserted = await TasksTable.insert({ title: "Defaulted body" });
210
+ expect(inserted.body).toBe("");
211
+ const stored = await TasksTable.get(inserted.taskId);
212
+ expect(stored?.body).toBe("");
213
+ await TasksTable.update({
214
+ taskId: inserted.taskId,
215
+ title: "Renamed",
216
+ });
217
+ const afterUpdate = await TasksTable.get(inserted.taskId);
218
+ expect(afterUpdate?.title).toBe("Renamed");
219
+ expect(afterUpdate?.body).toBe("");
220
+ });
208
221
  afterAll(async () => {
209
222
  await TasksTable.dropTableIfExists();
210
223
  await TasksTable.db.close();
@@ -7,6 +7,7 @@ const SQLiteDB = require("better-sqlite3");
7
7
  const user_context_1 = require("../context/user-context");
8
8
  const user_context_singleton_1 = require("../context/user-context-singleton");
9
9
  const utils_1 = require("../utils");
10
+ const access_level_1 = require("./access-level");
10
11
  const assistants_1 = require("./assistants");
11
12
  const group_member_roles_1 = require("./group-member-roles");
12
13
  const groups_1 = require("./groups");
@@ -375,6 +376,7 @@ describe("resolveDevicePackageVersion — expected behavior (control)", () => {
375
376
  const savedAssistant = await (0, assistants_1.Assistants)(dc).get(testAssistantId);
376
377
  expect(savedAssistant).toBeDefined();
377
378
  expect(savedAssistant?.name).toBe("Upgrade Test Assistant");
379
+ expect(savedAssistant?.accessLevel).toBe(access_level_1.DEFAULT_ACCESS_LEVEL);
378
380
  const savedWorkflow = await (0, workflows_1.Workflows)(dc).get(testWorkflowId);
379
381
  expect(savedWorkflow).toBeDefined();
380
382
  expect(savedWorkflow?.name).toBe("Upgrade Test Workflow");
@@ -0,0 +1,126 @@
1
+ import { z } from "zod";
2
+ import type { DataContext } from "../context/data-context";
3
+ /** Lifecycle of a tool-access approval request or reusable grant. */
4
+ export declare enum ToolAccessApprovalStatus {
5
+ pending = "pending",
6
+ approved = "approved",
7
+ executed = "executed",
8
+ rejected = "rejected",
9
+ expired = "expired",
10
+ failed = "failed"
11
+ }
12
+ /** How far a granted approval applies after the first execution. */
13
+ export declare enum ToolAccessApprovalScope {
14
+ once = "once",
15
+ thread = "thread",
16
+ context = "context"
17
+ }
18
+ /**
19
+ * Local-only record of a step-up tool approval.
20
+ *
21
+ * Stores identifiers, a frozen argument hash, and sanitized preview text.
22
+ * Do not put secrets, tokens, or raw log bodies in this table.
23
+ */
24
+ export declare const toolAccessApprovalSchema: z.ZodObject<{
25
+ toolAccessApprovalId: z.ZodEffects<z.ZodString, string, string>;
26
+ userId: z.ZodEffects<z.ZodString, string, string>;
27
+ assistantId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
28
+ toolId: z.ZodEffects<z.ZodString, string, string>;
29
+ toolName: z.ZodString;
30
+ dataContextId: z.ZodString;
31
+ workflowRunId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
32
+ threadMessageId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
33
+ workflowLogId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
34
+ argsHash: z.ZodString;
35
+ argsPreview: z.ZodDefault<z.ZodString>;
36
+ frozenArgs: z.ZodObject<{}, "strip", z.ZodAny, z.objectOutputType<{}, z.ZodAny, "strip">, z.objectInputType<{}, z.ZodAny, "strip">>;
37
+ requiredAccessLevel: z.ZodDefault<z.ZodNumber>;
38
+ scope: z.ZodDefault<z.ZodNativeEnum<typeof ToolAccessApprovalScope>>;
39
+ status: z.ZodDefault<z.ZodNativeEnum<typeof ToolAccessApprovalStatus>>;
40
+ nonce: z.ZodString;
41
+ expiresAt: z.ZodDate;
42
+ createdAt: z.ZodDefault<z.ZodDate>;
43
+ decidedAt: z.ZodOptional<z.ZodDate>;
44
+ executedAt: z.ZodOptional<z.ZodDate>;
45
+ resultSummary: z.ZodOptional<z.ZodString>;
46
+ }, "strip", z.ZodTypeAny, {
47
+ nonce: string;
48
+ status: ToolAccessApprovalStatus;
49
+ scope: ToolAccessApprovalScope;
50
+ userId: string;
51
+ expiresAt: Date;
52
+ toolId: string;
53
+ createdAt: Date;
54
+ dataContextId: string;
55
+ toolAccessApprovalId: string;
56
+ toolName: string;
57
+ argsHash: string;
58
+ argsPreview: string;
59
+ frozenArgs: {} & {
60
+ [k: string]: any;
61
+ };
62
+ requiredAccessLevel: number;
63
+ assistantId?: string | undefined;
64
+ threadMessageId?: string | undefined;
65
+ workflowRunId?: string | undefined;
66
+ workflowLogId?: string | undefined;
67
+ decidedAt?: Date | undefined;
68
+ executedAt?: Date | undefined;
69
+ resultSummary?: string | undefined;
70
+ }, {
71
+ nonce: string;
72
+ userId: string;
73
+ expiresAt: Date;
74
+ toolId: string;
75
+ dataContextId: string;
76
+ toolAccessApprovalId: string;
77
+ toolName: string;
78
+ argsHash: string;
79
+ frozenArgs: {} & {
80
+ [k: string]: any;
81
+ };
82
+ status?: ToolAccessApprovalStatus | undefined;
83
+ scope?: ToolAccessApprovalScope | undefined;
84
+ assistantId?: string | undefined;
85
+ createdAt?: Date | undefined;
86
+ threadMessageId?: string | undefined;
87
+ workflowRunId?: string | undefined;
88
+ workflowLogId?: string | undefined;
89
+ argsPreview?: string | undefined;
90
+ requiredAccessLevel?: number | undefined;
91
+ decidedAt?: Date | undefined;
92
+ executedAt?: Date | undefined;
93
+ resultSummary?: string | undefined;
94
+ }>;
95
+ /** A local-only tool-access approval or grant. */
96
+ export type IToolAccessApproval = z.infer<typeof toolAccessApprovalSchema>;
97
+ /**
98
+ * Accessor for the local-only {@link ToolAccessApprovals} table.
99
+ *
100
+ * @param dataContext - Optional data context; defaults to the current singleton.
101
+ */
102
+ export declare function ToolAccessApprovals(dataContext?: DataContext): import("..").Table<{
103
+ nonce: string;
104
+ status: ToolAccessApprovalStatus;
105
+ scope: ToolAccessApprovalScope;
106
+ userId: string;
107
+ expiresAt: Date;
108
+ toolId: string;
109
+ createdAt: Date;
110
+ dataContextId: string;
111
+ toolAccessApprovalId: string;
112
+ toolName: string;
113
+ argsHash: string;
114
+ argsPreview: string;
115
+ frozenArgs: {} & {
116
+ [k: string]: any;
117
+ };
118
+ requiredAccessLevel: number;
119
+ assistantId?: string | undefined;
120
+ threadMessageId?: string | undefined;
121
+ workflowRunId?: string | undefined;
122
+ workflowLogId?: string | undefined;
123
+ decidedAt?: Date | undefined;
124
+ executedAt?: Date | undefined;
125
+ resultSummary?: string | undefined;
126
+ }>;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolAccessApprovalSchema = exports.ToolAccessApprovalScope = exports.ToolAccessApprovalStatus = void 0;
4
+ exports.ToolAccessApprovals = ToolAccessApprovals;
5
+ const zod_1 = require("zod");
6
+ const user_context_singleton_1 = require("../context/user-context-singleton");
7
+ const zod_types_1 = require("../types/zod-types");
8
+ const access_level_1 = require("./access-level");
9
+ const table_definitions_system_1 = require("./orm/table-definitions.system");
10
+ const types_1 = require("./orm/types");
11
+ /** Lifecycle of a tool-access approval request or reusable grant. */
12
+ var ToolAccessApprovalStatus;
13
+ (function (ToolAccessApprovalStatus) {
14
+ ToolAccessApprovalStatus["pending"] = "pending";
15
+ ToolAccessApprovalStatus["approved"] = "approved";
16
+ ToolAccessApprovalStatus["executed"] = "executed";
17
+ ToolAccessApprovalStatus["rejected"] = "rejected";
18
+ ToolAccessApprovalStatus["expired"] = "expired";
19
+ ToolAccessApprovalStatus["failed"] = "failed";
20
+ })(ToolAccessApprovalStatus || (exports.ToolAccessApprovalStatus = ToolAccessApprovalStatus = {}));
21
+ /** How far a granted approval applies after the first execution. */
22
+ var ToolAccessApprovalScope;
23
+ (function (ToolAccessApprovalScope) {
24
+ ToolAccessApprovalScope["once"] = "once";
25
+ ToolAccessApprovalScope["thread"] = "thread";
26
+ ToolAccessApprovalScope["context"] = "context";
27
+ })(ToolAccessApprovalScope || (exports.ToolAccessApprovalScope = ToolAccessApprovalScope = {}));
28
+ /**
29
+ * Local-only record of a step-up tool approval.
30
+ *
31
+ * Stores identifiers, a frozen argument hash, and sanitized preview text.
32
+ * Do not put secrets, tokens, or raw log bodies in this table.
33
+ */
34
+ exports.toolAccessApprovalSchema = zod_1.z.object({
35
+ toolAccessApprovalId: zod_types_1.zodPeerId,
36
+ userId: zod_types_1.zodPeerId.describe("User who must approve and who requested the elevation"),
37
+ assistantId: zod_types_1.zodPeerId
38
+ .optional()
39
+ .describe("Assistant that requested the tool; omitted for direct user calls"),
40
+ toolId: zod_types_1.zodPeerId,
41
+ toolName: zod_1.z.string().describe("Display name of the tool at request time"),
42
+ dataContextId: zod_1.z.string().describe("Data context the tool would run in"),
43
+ workflowRunId: zod_types_1.zodPeerId.optional(),
44
+ threadMessageId: zod_types_1.zodPeerId
45
+ .optional()
46
+ .describe("User message / thread root that owns the workflow"),
47
+ workflowLogId: zod_types_1.zodPeerId.optional(),
48
+ argsHash: zod_1.z.string().describe("Canonical hash of the frozen tool arguments"),
49
+ argsPreview: zod_1.z
50
+ .string()
51
+ .default("")
52
+ .describe("Sanitized, truncated argument summary for the approval card"),
53
+ frozenArgs: zod_types_1.zodAnyObject.describe("Frozen arguments executed on approve; no secrets"),
54
+ requiredAccessLevel: access_level_1.accessLevelSchema,
55
+ scope: zod_1.z.nativeEnum(ToolAccessApprovalScope).default(ToolAccessApprovalScope.once),
56
+ status: zod_1.z.nativeEnum(ToolAccessApprovalStatus).default(ToolAccessApprovalStatus.pending),
57
+ nonce: zod_1.z.string().describe("Single-use token; empty after consume"),
58
+ expiresAt: zod_1.z.date(),
59
+ createdAt: zod_1.z.date().default(() => new Date()),
60
+ decidedAt: zod_1.z.date().optional(),
61
+ executedAt: zod_1.z.date().optional(),
62
+ resultSummary: zod_1.z.string().optional().describe("Sanitized outcome after execute or deny"),
63
+ });
64
+ const metaData = {
65
+ name: "ToolAccessApprovals",
66
+ description: "Local-only pending and granted step-up approvals for privileged tools.",
67
+ primaryKeyName: "toolAccessApprovalId",
68
+ fields: (0, types_1.schemaToFields)(exports.toolAccessApprovalSchema),
69
+ iconClassName: "bi bi-shield-lock",
70
+ localOnly: true,
71
+ indexes: [
72
+ { fields: ["threadMessageId"] },
73
+ { fields: ["workflowRunId"] },
74
+ { fields: ["status"] },
75
+ { fields: ["toolId"] },
76
+ ],
77
+ };
78
+ (0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.toolAccessApprovalSchema);
79
+ /**
80
+ * Accessor for the local-only {@link ToolAccessApprovals} table.
81
+ *
82
+ * @param dataContext - Optional data context; defaults to the current singleton.
83
+ */
84
+ function ToolAccessApprovals(dataContext) {
85
+ return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, exports.toolAccessApprovalSchema);
86
+ }