@bevel-software/platform-core-backend 0.3.0 → 0.3.2
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/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +5 -0
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/modules/auth/account.routes.d.ts +2 -2
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +3 -0
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/mcp/manual-failure-memo.d.ts +53 -0
- package/dist/modules/mcp/manual-failure-memo.d.ts.map +1 -0
- package/dist/modules/mcp/manual-failure-memo.js +87 -0
- package/dist/modules/mcp/manual-failure-memo.js.map +1 -0
- package/dist/modules/mcp/mcp.service.d.ts +12 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +41 -4
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +3 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +33 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
- package/package.json +2 -2
- package/src/core/create-core-services.ts +5 -0
- package/src/modules/auth/__tests__/account.routes.test.ts +16 -3
- package/src/modules/auth/account.routes.ts +8 -2
- package/src/modules/mcp/__tests__/manual-failure-memo.test.ts +70 -0
- package/src/modules/mcp/manual-failure-memo.ts +89 -0
- package/src/modules/mcp/mcp.service.ts +44 -6
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +39 -0
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +35 -0
|
@@ -95,6 +95,27 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
95
95
|
return this.cryptoInstance;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// ── Mutation listeners ─────────────────────────────────────────────────────
|
|
99
|
+
// Notified after any secret mutation: `userId` for a per-user secret, null
|
|
100
|
+
// for a SHARED one (affects every user). Lets caches keyed on credential
|
|
101
|
+
// validity (e.g. the MCP proxy's manual-failure memo) invalidate the moment
|
|
102
|
+
// a credential changes instead of waiting out a TTL.
|
|
103
|
+
private readonly mutationListeners: Array<(userId: string | null) => void> = [];
|
|
104
|
+
|
|
105
|
+
onMutation(listener: (userId: string | null) => void): void {
|
|
106
|
+
this.mutationListeners.push(listener);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private notifyMutation(userId: string | null): void {
|
|
110
|
+
for (const listener of this.mutationListeners) {
|
|
111
|
+
try {
|
|
112
|
+
listener(userId);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.warn('[vault] mutation listener failed:', err instanceof Error ? err.message : err);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
98
119
|
async list(userId: string): Promise<SecretSummary[]> {
|
|
99
120
|
const rows = await this.db
|
|
100
121
|
.select()
|
|
@@ -130,6 +151,7 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
130
151
|
set: { kind: 'static', label, valueEncrypted, oauthMeta: null, updatedAt: new Date() },
|
|
131
152
|
})
|
|
132
153
|
.returning();
|
|
154
|
+
this.notifyMutation(userId);
|
|
133
155
|
return this.toSummary(row);
|
|
134
156
|
}
|
|
135
157
|
|
|
@@ -153,6 +175,7 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
153
175
|
set: { kind: 'oauth', label, valueEncrypted, oauthMeta, updatedAt: new Date() },
|
|
154
176
|
})
|
|
155
177
|
.returning();
|
|
178
|
+
this.notifyMutation(userId);
|
|
156
179
|
return this.toSummary(row);
|
|
157
180
|
}
|
|
158
181
|
|
|
@@ -162,6 +185,7 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
162
185
|
.where(and(eq(secrets.id, id), eq(secrets.userId, userId)))
|
|
163
186
|
.returning({ id: secrets.id });
|
|
164
187
|
if (res.length === 0) throw new SecretNotFoundError(id);
|
|
188
|
+
this.notifyMutation(userId);
|
|
165
189
|
}
|
|
166
190
|
|
|
167
191
|
async putSharedStatic(input: PutSharedStaticSecretInput): Promise<SecretSummary> {
|
|
@@ -186,6 +210,7 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
186
210
|
set: { kind: 'static', label, valueEncrypted, oauthMeta: null, updatedAt: new Date() },
|
|
187
211
|
})
|
|
188
212
|
.returning();
|
|
213
|
+
this.notifyMutation(null);
|
|
189
214
|
return this.toSummary(row);
|
|
190
215
|
}
|
|
191
216
|
|
|
@@ -195,6 +220,7 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
195
220
|
.where(and(isNull(secrets.userId), eq(secrets.key, key)))
|
|
196
221
|
.returning({ id: secrets.id });
|
|
197
222
|
if (res.length === 0) throw new SecretNotFoundError(key);
|
|
223
|
+
this.notifyMutation(null);
|
|
198
224
|
}
|
|
199
225
|
|
|
200
226
|
async removeUserByKey(userId: string, key: string): Promise<void> {
|
|
@@ -203,6 +229,7 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
203
229
|
.where(and(eq(secrets.userId, userId), eq(secrets.key, key)))
|
|
204
230
|
.returning({ id: secrets.id });
|
|
205
231
|
if (res.length === 0) throw new SecretNotFoundError(key);
|
|
232
|
+
this.notifyMutation(userId);
|
|
206
233
|
}
|
|
207
234
|
|
|
208
235
|
async statusFor(userId: string, keys: string[]): Promise<SecretConfigStatus[]> {
|
|
@@ -319,6 +346,8 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
319
346
|
.update(secrets)
|
|
320
347
|
.set({ valueEncrypted: this.crypto().encrypt(JSON.stringify(next)), updatedAt: new Date() })
|
|
321
348
|
.where(and(eq(secrets.id, id), eq(secrets.userId, userId)));
|
|
349
|
+
// Fresh tokens just landed — let credential-validity caches retry NOW.
|
|
350
|
+
this.notifyMutation(userId);
|
|
322
351
|
}
|
|
323
352
|
|
|
324
353
|
async putSharedOAuthClientSecret(input: {
|
|
@@ -345,6 +374,7 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
345
374
|
targetWhere: isNull(secrets.userId),
|
|
346
375
|
set: { kind: 'oauth', valueEncrypted, oauthMeta, updatedAt: new Date() },
|
|
347
376
|
});
|
|
377
|
+
this.notifyMutation(null);
|
|
348
378
|
}
|
|
349
379
|
|
|
350
380
|
async beginToolOAuthByKey(input: {
|
|
@@ -552,6 +582,10 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
552
582
|
.update(secrets)
|
|
553
583
|
.set({ valueEncrypted: this.crypto().encrypt(JSON.stringify(next)), updatedAt: new Date() })
|
|
554
584
|
.where(and(eq(secrets.id, row.id), eq(secrets.valueEncrypted, row.valueEncrypted)));
|
|
585
|
+
// A successful refresh is a credential repair — notify so dependent caches
|
|
586
|
+
// (the MCP proxy's manual-failure memo) retry immediately. `row.userId` is
|
|
587
|
+
// null for a shared (admin-scope) row, which maps to "affects everyone".
|
|
588
|
+
this.notifyMutation(row.userId);
|
|
555
589
|
return refreshed.access_token;
|
|
556
590
|
}
|
|
557
591
|
|
|
@@ -579,6 +613,7 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
579
613
|
targetWhere: isNull(secrets.userId),
|
|
580
614
|
set: { kind: 'oauth', valueEncrypted, oauthMeta, updatedAt: new Date() },
|
|
581
615
|
});
|
|
616
|
+
this.notifyMutation(null);
|
|
582
617
|
}
|
|
583
618
|
|
|
584
619
|
async getSharedOAuthProvider(key: string): Promise<OAuthProviderConfig | null> {
|