@frontmcp/plugin-approval 1.8.6 → 1.8.7
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/esm/index.mjs +44 -6
- package/esm/package.json +4 -4
- package/index.js +43 -6
- package/package.json +4 -4
- package/services/approval.service.d.ts +9 -1
- package/services/approval.service.d.ts.map +1 -1
- package/stores/approval-storage.store.d.ts +4 -0
- package/stores/approval-storage.store.d.ts.map +1 -1
- package/stores/approval-store.interface.d.ts +6 -1
- package/stores/approval-store.interface.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -615,16 +615,19 @@ var ApprovalService = class {
|
|
|
615
615
|
/**
|
|
616
616
|
* Who a grant is recorded as when the call names no one: the signed-in user whose tool call made it.
|
|
617
617
|
* It used to be `'policy'`, so an audit trail showed every approval a user gave as a policy's.
|
|
618
|
-
* Without a signed-in user it is
|
|
618
|
+
* Without a signed-in user it is a user with no identifier.
|
|
619
|
+
*
|
|
620
|
+
* The method is `'implicit'`: a tool that grants through `this.approval` asked no one, so the grant
|
|
621
|
+
* is not an `'interactive'` answer. A tool that did ask passes `grantedBy: userGrantor(id)`.
|
|
619
622
|
*/
|
|
620
623
|
defaultGrantor() {
|
|
621
624
|
const userId = this.signedInUserId;
|
|
622
|
-
return userId ? userGrantor(userId) : { source: "user" };
|
|
625
|
+
return userId ? userGrantor(userId, void 0, { method: "implicit" }) : { source: "user", method: "implicit" };
|
|
623
626
|
}
|
|
624
627
|
/** Who a revocation is recorded as when the call names no one, by the same rule as a grant. */
|
|
625
628
|
defaultRevoker() {
|
|
626
629
|
const userId = this.signedInUserId;
|
|
627
|
-
return userId ?
|
|
630
|
+
return userId ? { source: "user", identifier: userId, method: "implicit" } : { source: "user", method: "implicit" };
|
|
628
631
|
}
|
|
629
632
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
630
633
|
// Query Methods
|
|
@@ -681,6 +684,13 @@ var ApprovalService = class {
|
|
|
681
684
|
(record) => record.sessionId === this.sessionId || this.userId !== void 0 && record.userId === this.userId
|
|
682
685
|
);
|
|
683
686
|
}
|
|
687
|
+
/**
|
|
688
|
+
* The caller's recent revocations of a tool, newest last: each is the approval that was revoked,
|
|
689
|
+
* with `revokedBy`, `revokedAt` and `revocationReason`. Empty when the store keeps no revocations.
|
|
690
|
+
*/
|
|
691
|
+
async getRevocations(toolId) {
|
|
692
|
+
return await this.store.getRevocations?.(toolId, this.sessionId, this.userId) ?? [];
|
|
693
|
+
}
|
|
684
694
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
685
695
|
// Grant Methods
|
|
686
696
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -948,14 +958,18 @@ function createMemoryChallengeService(options = {}) {
|
|
|
948
958
|
import { Provider as Provider3, ProviderScope as ProviderScope3 } from "@frontmcp/sdk";
|
|
949
959
|
import {
|
|
950
960
|
createMemoryStorage as createMemoryStorage2,
|
|
961
|
+
createNamespacedStorage,
|
|
951
962
|
createStorage as createStorage2
|
|
952
963
|
} from "@frontmcp/utils";
|
|
953
964
|
function escapePattern(str) {
|
|
954
965
|
return str.replace(/[*?[\]\\]/g, "\\$&");
|
|
955
966
|
}
|
|
967
|
+
var REVOCATION_RETENTION_SECONDS = 24 * 60 * 60;
|
|
956
968
|
var TIME_LIMITED_KEY_SEGMENT = `scope:${"time_limited" /* TIME_LIMITED */}`;
|
|
957
969
|
var ApprovalStorageStore = class {
|
|
958
970
|
storage;
|
|
971
|
+
/** Revoked approvals live beside the live ones, in a namespace no live-approval query scans. */
|
|
972
|
+
revocationStorage;
|
|
959
973
|
options;
|
|
960
974
|
cleanupInterval;
|
|
961
975
|
initialized = false;
|
|
@@ -991,6 +1005,13 @@ var ApprovalStorageStore = class {
|
|
|
991
1005
|
}
|
|
992
1006
|
this.initialized = true;
|
|
993
1007
|
}
|
|
1008
|
+
get revocations() {
|
|
1009
|
+
this.revocationStorage ??= createNamespacedStorage(
|
|
1010
|
+
this.storage.root,
|
|
1011
|
+
`${this.storage.prefix.replace(/:$/, "")}-revoked`
|
|
1012
|
+
);
|
|
1013
|
+
return this.revocationStorage;
|
|
1014
|
+
}
|
|
994
1015
|
ensureInitialized() {
|
|
995
1016
|
if (!this.initialized) {
|
|
996
1017
|
throw new Error("ApprovalStorageStore not initialized. Call initialize() first.");
|
|
@@ -1152,27 +1173,43 @@ var ApprovalStorageStore = class {
|
|
|
1152
1173
|
const keys = await this.storage.keys(`${escapePattern(toolId)}:*`);
|
|
1153
1174
|
const values = await this.storage.mget(keys);
|
|
1154
1175
|
const keysToDelete = [];
|
|
1176
|
+
const revoked = /* @__PURE__ */ new Map();
|
|
1155
1177
|
for (let i = 0; i < keys.length; i++) {
|
|
1156
1178
|
const record = this.parseRecord(values[i]);
|
|
1157
1179
|
if (!record || record.toolId !== toolId || record.state === "denied" /* DENIED */) continue;
|
|
1180
|
+
const matches = keysToDelete.length;
|
|
1158
1181
|
if (context) {
|
|
1159
1182
|
const sameSession = sessionId !== void 0 && record.sessionId === sessionId;
|
|
1160
1183
|
if (record.context?.type === context.type && record.context.identifier === context.identifier && (!sessionId || sameSession) && // A context approval granted to the session before it had a user applies to that user too.
|
|
1161
1184
|
(!userId || record.userId === userId || sameSession && record.userId === void 0)) {
|
|
1162
1185
|
keysToDelete.push(keys[i]);
|
|
1163
1186
|
}
|
|
1164
|
-
|
|
1165
|
-
}
|
|
1166
|
-
if (sessionId && record.sessionId === sessionId || userId && record.userId === userId) {
|
|
1187
|
+
} else if (sessionId && record.sessionId === sessionId || userId && record.userId === userId) {
|
|
1167
1188
|
keysToDelete.push(keys[i]);
|
|
1168
1189
|
}
|
|
1190
|
+
if (keysToDelete.length > matches) revoked.set(keys[i], record);
|
|
1169
1191
|
}
|
|
1170
1192
|
if (keysToDelete.length === 0) {
|
|
1171
1193
|
return false;
|
|
1172
1194
|
}
|
|
1195
|
+
const revokedAt = Date.now();
|
|
1196
|
+
const revokedBy = normalizeRevoker(options.revokedBy);
|
|
1197
|
+
for (const [key, record] of revoked) {
|
|
1198
|
+
const entry = { ...record, revokedAt, revokedBy, revocationReason: options.reason };
|
|
1199
|
+
await this.revocations.set(key, JSON.stringify(entry), { ttlSeconds: REVOCATION_RETENTION_SECONDS });
|
|
1200
|
+
}
|
|
1173
1201
|
await this.storage.mdelete(keysToDelete);
|
|
1174
1202
|
return true;
|
|
1175
1203
|
}
|
|
1204
|
+
async getRevocations(toolId, sessionId, userId, context) {
|
|
1205
|
+
this.ensureInitialized();
|
|
1206
|
+
const records = [];
|
|
1207
|
+
for (const key of this.callerKeys(toolId, sessionId, userId, context)) {
|
|
1208
|
+
const record = this.parseRecord(await this.revocations.get(key));
|
|
1209
|
+
if (record && record.toolId === toolId) records.push(record);
|
|
1210
|
+
}
|
|
1211
|
+
return records.sort((a, b) => (a.revokedAt ?? 0) - (b.revokedAt ?? 0));
|
|
1212
|
+
}
|
|
1176
1213
|
async isApproved(toolId, sessionId, userId, context) {
|
|
1177
1214
|
const approval = await this.getApproval(toolId, sessionId, userId, context);
|
|
1178
1215
|
return approval?.state === "approved" /* APPROVED */;
|
|
@@ -1248,6 +1285,7 @@ var ApprovalStorageStore = class {
|
|
|
1248
1285
|
if (this.ownedStorage && this.storage) {
|
|
1249
1286
|
await this.storage.root.disconnect();
|
|
1250
1287
|
}
|
|
1288
|
+
this.revocationStorage = void 0;
|
|
1251
1289
|
this.initialized = false;
|
|
1252
1290
|
}
|
|
1253
1291
|
};
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-approval",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.7",
|
|
4
4
|
"description": "Approval plugin for FrontMCP - tool authorization workflow with PKCE webhook security",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@frontmcp/sdk": "1.8.
|
|
53
|
-
"@frontmcp/utils": "1.8.
|
|
52
|
+
"@frontmcp/sdk": "1.8.7",
|
|
53
|
+
"@frontmcp/utils": "1.8.7",
|
|
54
54
|
"ioredis": "^5.8.0",
|
|
55
55
|
"reflect-metadata": "^0.2.2"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
58
|
+
"@frontmcp/lazy-zod": "1.8.7",
|
|
59
59
|
"@vercel/kv": "^2.0.0 || ^3.0.0"
|
|
60
60
|
},
|
|
61
61
|
"peerDependenciesMeta": {
|
package/index.js
CHANGED
|
@@ -667,16 +667,19 @@ var ApprovalService = class {
|
|
|
667
667
|
/**
|
|
668
668
|
* Who a grant is recorded as when the call names no one: the signed-in user whose tool call made it.
|
|
669
669
|
* It used to be `'policy'`, so an audit trail showed every approval a user gave as a policy's.
|
|
670
|
-
* Without a signed-in user it is
|
|
670
|
+
* Without a signed-in user it is a user with no identifier.
|
|
671
|
+
*
|
|
672
|
+
* The method is `'implicit'`: a tool that grants through `this.approval` asked no one, so the grant
|
|
673
|
+
* is not an `'interactive'` answer. A tool that did ask passes `grantedBy: userGrantor(id)`.
|
|
671
674
|
*/
|
|
672
675
|
defaultGrantor() {
|
|
673
676
|
const userId = this.signedInUserId;
|
|
674
|
-
return userId ? userGrantor(userId) : { source: "user" };
|
|
677
|
+
return userId ? userGrantor(userId, void 0, { method: "implicit" }) : { source: "user", method: "implicit" };
|
|
675
678
|
}
|
|
676
679
|
/** Who a revocation is recorded as when the call names no one, by the same rule as a grant. */
|
|
677
680
|
defaultRevoker() {
|
|
678
681
|
const userId = this.signedInUserId;
|
|
679
|
-
return userId ?
|
|
682
|
+
return userId ? { source: "user", identifier: userId, method: "implicit" } : { source: "user", method: "implicit" };
|
|
680
683
|
}
|
|
681
684
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
682
685
|
// Query Methods
|
|
@@ -733,6 +736,13 @@ var ApprovalService = class {
|
|
|
733
736
|
(record) => record.sessionId === this.sessionId || this.userId !== void 0 && record.userId === this.userId
|
|
734
737
|
);
|
|
735
738
|
}
|
|
739
|
+
/**
|
|
740
|
+
* The caller's recent revocations of a tool, newest last: each is the approval that was revoked,
|
|
741
|
+
* with `revokedBy`, `revokedAt` and `revocationReason`. Empty when the store keeps no revocations.
|
|
742
|
+
*/
|
|
743
|
+
async getRevocations(toolId) {
|
|
744
|
+
return await this.store.getRevocations?.(toolId, this.sessionId, this.userId) ?? [];
|
|
745
|
+
}
|
|
736
746
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
737
747
|
// Grant Methods
|
|
738
748
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -997,9 +1007,12 @@ var import_utils3 = require("@frontmcp/utils");
|
|
|
997
1007
|
function escapePattern(str) {
|
|
998
1008
|
return str.replace(/[*?[\]\\]/g, "\\$&");
|
|
999
1009
|
}
|
|
1010
|
+
var REVOCATION_RETENTION_SECONDS = 24 * 60 * 60;
|
|
1000
1011
|
var TIME_LIMITED_KEY_SEGMENT = `scope:${"time_limited" /* TIME_LIMITED */}`;
|
|
1001
1012
|
var ApprovalStorageStore = class {
|
|
1002
1013
|
storage;
|
|
1014
|
+
/** Revoked approvals live beside the live ones, in a namespace no live-approval query scans. */
|
|
1015
|
+
revocationStorage;
|
|
1003
1016
|
options;
|
|
1004
1017
|
cleanupInterval;
|
|
1005
1018
|
initialized = false;
|
|
@@ -1035,6 +1048,13 @@ var ApprovalStorageStore = class {
|
|
|
1035
1048
|
}
|
|
1036
1049
|
this.initialized = true;
|
|
1037
1050
|
}
|
|
1051
|
+
get revocations() {
|
|
1052
|
+
this.revocationStorage ??= (0, import_utils3.createNamespacedStorage)(
|
|
1053
|
+
this.storage.root,
|
|
1054
|
+
`${this.storage.prefix.replace(/:$/, "")}-revoked`
|
|
1055
|
+
);
|
|
1056
|
+
return this.revocationStorage;
|
|
1057
|
+
}
|
|
1038
1058
|
ensureInitialized() {
|
|
1039
1059
|
if (!this.initialized) {
|
|
1040
1060
|
throw new Error("ApprovalStorageStore not initialized. Call initialize() first.");
|
|
@@ -1196,27 +1216,43 @@ var ApprovalStorageStore = class {
|
|
|
1196
1216
|
const keys = await this.storage.keys(`${escapePattern(toolId)}:*`);
|
|
1197
1217
|
const values = await this.storage.mget(keys);
|
|
1198
1218
|
const keysToDelete = [];
|
|
1219
|
+
const revoked = /* @__PURE__ */ new Map();
|
|
1199
1220
|
for (let i = 0; i < keys.length; i++) {
|
|
1200
1221
|
const record = this.parseRecord(values[i]);
|
|
1201
1222
|
if (!record || record.toolId !== toolId || record.state === "denied" /* DENIED */) continue;
|
|
1223
|
+
const matches = keysToDelete.length;
|
|
1202
1224
|
if (context) {
|
|
1203
1225
|
const sameSession = sessionId !== void 0 && record.sessionId === sessionId;
|
|
1204
1226
|
if (record.context?.type === context.type && record.context.identifier === context.identifier && (!sessionId || sameSession) && // A context approval granted to the session before it had a user applies to that user too.
|
|
1205
1227
|
(!userId || record.userId === userId || sameSession && record.userId === void 0)) {
|
|
1206
1228
|
keysToDelete.push(keys[i]);
|
|
1207
1229
|
}
|
|
1208
|
-
|
|
1209
|
-
}
|
|
1210
|
-
if (sessionId && record.sessionId === sessionId || userId && record.userId === userId) {
|
|
1230
|
+
} else if (sessionId && record.sessionId === sessionId || userId && record.userId === userId) {
|
|
1211
1231
|
keysToDelete.push(keys[i]);
|
|
1212
1232
|
}
|
|
1233
|
+
if (keysToDelete.length > matches) revoked.set(keys[i], record);
|
|
1213
1234
|
}
|
|
1214
1235
|
if (keysToDelete.length === 0) {
|
|
1215
1236
|
return false;
|
|
1216
1237
|
}
|
|
1238
|
+
const revokedAt = Date.now();
|
|
1239
|
+
const revokedBy = normalizeRevoker(options.revokedBy);
|
|
1240
|
+
for (const [key, record] of revoked) {
|
|
1241
|
+
const entry = { ...record, revokedAt, revokedBy, revocationReason: options.reason };
|
|
1242
|
+
await this.revocations.set(key, JSON.stringify(entry), { ttlSeconds: REVOCATION_RETENTION_SECONDS });
|
|
1243
|
+
}
|
|
1217
1244
|
await this.storage.mdelete(keysToDelete);
|
|
1218
1245
|
return true;
|
|
1219
1246
|
}
|
|
1247
|
+
async getRevocations(toolId, sessionId, userId, context) {
|
|
1248
|
+
this.ensureInitialized();
|
|
1249
|
+
const records = [];
|
|
1250
|
+
for (const key of this.callerKeys(toolId, sessionId, userId, context)) {
|
|
1251
|
+
const record = this.parseRecord(await this.revocations.get(key));
|
|
1252
|
+
if (record && record.toolId === toolId) records.push(record);
|
|
1253
|
+
}
|
|
1254
|
+
return records.sort((a, b) => (a.revokedAt ?? 0) - (b.revokedAt ?? 0));
|
|
1255
|
+
}
|
|
1220
1256
|
async isApproved(toolId, sessionId, userId, context) {
|
|
1221
1257
|
const approval = await this.getApproval(toolId, sessionId, userId, context);
|
|
1222
1258
|
return approval?.state === "approved" /* APPROVED */;
|
|
@@ -1292,6 +1328,7 @@ var ApprovalStorageStore = class {
|
|
|
1292
1328
|
if (this.ownedStorage && this.storage) {
|
|
1293
1329
|
await this.storage.root.disconnect();
|
|
1294
1330
|
}
|
|
1331
|
+
this.revocationStorage = void 0;
|
|
1295
1332
|
this.initialized = false;
|
|
1296
1333
|
}
|
|
1297
1334
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-approval",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.7",
|
|
4
4
|
"description": "Approval plugin for FrontMCP - tool authorization workflow with PKCE webhook security",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@frontmcp/sdk": "1.8.
|
|
53
|
-
"@frontmcp/utils": "1.8.
|
|
52
|
+
"@frontmcp/sdk": "1.8.7",
|
|
53
|
+
"@frontmcp/utils": "1.8.7",
|
|
54
54
|
"ioredis": "^5.8.0",
|
|
55
55
|
"reflect-metadata": "^0.2.2"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
58
|
+
"@frontmcp/lazy-zod": "1.8.7",
|
|
59
59
|
"@vercel/kv": "^2.0.0 || ^3.0.0"
|
|
60
60
|
},
|
|
61
61
|
"peerDependenciesMeta": {
|
|
@@ -46,7 +46,10 @@ export declare class ApprovalService {
|
|
|
46
46
|
/**
|
|
47
47
|
* Who a grant is recorded as when the call names no one: the signed-in user whose tool call made it.
|
|
48
48
|
* It used to be `'policy'`, so an audit trail showed every approval a user gave as a policy's.
|
|
49
|
-
* Without a signed-in user it is
|
|
49
|
+
* Without a signed-in user it is a user with no identifier.
|
|
50
|
+
*
|
|
51
|
+
* The method is `'implicit'`: a tool that grants through `this.approval` asked no one, so the grant
|
|
52
|
+
* is not an `'interactive'` answer. A tool that did ask passes `grantedBy: userGrantor(id)`.
|
|
50
53
|
*/
|
|
51
54
|
private defaultGrantor;
|
|
52
55
|
/** Who a revocation is recorded as when the call names no one, by the same rule as a grant. */
|
|
@@ -73,6 +76,11 @@ export declare class ApprovalService {
|
|
|
73
76
|
* another caller's records. Read the store directly for administrative queries.
|
|
74
77
|
*/
|
|
75
78
|
queryApprovals(query: Partial<ApprovalQuery>): Promise<ApprovalRecord[]>;
|
|
79
|
+
/**
|
|
80
|
+
* The caller's recent revocations of a tool, newest last: each is the approval that was revoked,
|
|
81
|
+
* with `revokedBy`, `revokedAt` and `revocationReason`. Empty when the store keeps no revocations.
|
|
82
|
+
*/
|
|
83
|
+
getRevocations(toolId: string): Promise<ApprovalRecord[]>;
|
|
76
84
|
/**
|
|
77
85
|
* Grant session-scoped approval for a tool.
|
|
78
86
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval.service.d.ts","sourceRoot":"","sources":["../../src/services/approval.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC7B,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,uBAAuB,GAAG,SAAS,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8GAA8G;IAC9G,SAAS,CAAC,EAAE,eAAe,GAAG,kBAAkB,CAAC;IACjD,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8GAA8G;IAC9G,SAAS,CAAC,EAAE,eAAe,GAAG,oBAAoB,CAAC;IACnD,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAKa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAHb,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,aAAa,GAAE,yBAA2C;IAG7E,kGAAkG;IAClG,OAAO,CAAC,UAAU;IAIlB,qGAAqG;IACrG,OAAO,KAAK,cAAc,GAEzB;IAED
|
|
1
|
+
{"version":3,"file":"approval.service.d.ts","sourceRoot":"","sources":["../../src/services/approval.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,6 +37,8 @@ export interface ApprovalStorageStoreOptions {
|
|
|
37
37
|
*/
|
|
38
38
|
export declare class ApprovalStorageStore implements ApprovalStore {
|
|
39
39
|
private storage;
|
|
40
|
+
/** Revoked approvals live beside the live ones, in a namespace no live-approval query scans. */
|
|
41
|
+
private revocationStorage?;
|
|
40
42
|
private readonly options;
|
|
41
43
|
private cleanupInterval?;
|
|
42
44
|
private initialized;
|
|
@@ -46,6 +48,7 @@ export declare class ApprovalStorageStore implements ApprovalStore {
|
|
|
46
48
|
* Initialize the storage connection.
|
|
47
49
|
*/
|
|
48
50
|
initialize(): Promise<void>;
|
|
51
|
+
private get revocations();
|
|
49
52
|
private ensureInitialized;
|
|
50
53
|
private buildKey;
|
|
51
54
|
/**
|
|
@@ -85,6 +88,7 @@ export declare class ApprovalStorageStore implements ApprovalStore {
|
|
|
85
88
|
* (session, user, time-limited and context approvals alike). Recorded denials are kept.
|
|
86
89
|
*/
|
|
87
90
|
revokeApproval(options: RevokeApprovalOptions): Promise<boolean>;
|
|
91
|
+
getRevocations(toolId: string, sessionId: string, userId?: string, context?: ApprovalContext): Promise<ApprovalRecord[]>;
|
|
88
92
|
isApproved(toolId: string, sessionId: string, userId?: string, context?: ApprovalContext): Promise<boolean>;
|
|
89
93
|
clearSessionApprovals(sessionId: string): Promise<number>;
|
|
90
94
|
clearExpiredApprovals(): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-storage.store.d.ts","sourceRoot":"","sources":["../../src/stores/approval-storage.store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"approval-storage.store.d.ts","sourceRoot":"","sources":["../../src/stores/approval-storage.store.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module @frontmcp/plugin-approval
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { ApprovalContext, ApprovalGrantor, ApprovalRecord, ApprovalRevoker, ApprovalScope, ApprovalSourceType, ApprovalState, RevocationSourceType } from '../types';
|
|
7
7
|
/**
|
|
8
8
|
* Query options for finding approvals.
|
|
9
9
|
*/
|
|
@@ -101,6 +101,11 @@ export interface ApprovalStore {
|
|
|
101
101
|
* (only the given context's, when `context` is set). Recorded denials are kept.
|
|
102
102
|
*/
|
|
103
103
|
revokeApproval(options: RevokeApprovalOptions): Promise<boolean>;
|
|
104
|
+
/**
|
|
105
|
+
* The caller's recent revocations of a tool: each is the approval that was revoked, with `revokedBy`,
|
|
106
|
+
* `revokedAt` and `revocationReason`. Optional: a store that keeps no revocations leaves it out.
|
|
107
|
+
*/
|
|
108
|
+
getRevocations?(toolId: string, sessionId: string, userId?: string, context?: ApprovalContext): Promise<ApprovalRecord[]>;
|
|
104
109
|
/**
|
|
105
110
|
* Check if a tool is approved.
|
|
106
111
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-store.interface.d.ts","sourceRoot":"","sources":["../../src/stores/approval-store.interface.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,
|
|
1
|
+
{"version":3,"file":"approval-store.interface.d.ts","sourceRoot":"","sources":["../../src/stores/approval-store.interface.ts"],"names":[],"mappings":"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"}
|