axvault 1.0.0 → 1.1.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/README.md +4 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -1
- package/dist/commands/credential.js +4 -2
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.js +18 -1
- package/dist/db/repositories/credentials.d.ts +6 -1
- package/dist/db/repositories/credentials.js +15 -9
- package/dist/db/types.d.ts +3 -1
- package/dist/handlers/get-credential.js +28 -25
- package/dist/handlers/list-credentials.js +1 -0
- package/dist/handlers/put-credential.js +20 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/refresh/refresh-manager.d.ts +3 -1
- package/dist/refresh/refresh-manager.js +5 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -163,11 +163,14 @@ curl -X PUT https://vault.example.com/api/v1/credentials/claude/prod \
|
|
|
163
163
|
-H "Authorization: Bearer <api_key>" \
|
|
164
164
|
-H "Content-Type: application/json" \
|
|
165
165
|
-d '{
|
|
166
|
-
"
|
|
166
|
+
"type": "oauth",
|
|
167
|
+
"data": {"access_token": "...", "refresh_token": "..."},
|
|
167
168
|
"expiresAt": "2025-12-31T23:59:59Z"
|
|
168
169
|
}'
|
|
169
170
|
```
|
|
170
171
|
|
|
172
|
+
The `type` field is required and must be either `"oauth"` (for refreshable tokens) or `"api-key"` (for static keys). Only `oauth` credentials are eligible for auto-refresh.
|
|
173
|
+
|
|
171
174
|
### Retrieve a Credential
|
|
172
175
|
|
|
173
176
|
```bash
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -8,13 +8,14 @@ import { deleteCredential, listCredentials, } from "../db/repositories/credentia
|
|
|
8
8
|
import { containsControlChars, formatDateForJson, formatExpiresAt, formatRelativeTime, getErrorMessage, sanitizeForTsv, } from "../lib/format.js";
|
|
9
9
|
/** Print credentials as TSV table */
|
|
10
10
|
function printCredentialTable(credentials) {
|
|
11
|
-
console.log("AGENT\tNAME\tEXPIRES\tUPDATED");
|
|
11
|
+
console.log("AGENT\tNAME\tTYPE\tEXPIRES\tUPDATED");
|
|
12
12
|
for (const cred of credentials) {
|
|
13
13
|
const agent = sanitizeForTsv(cred.agent);
|
|
14
14
|
const name = sanitizeForTsv(cred.name);
|
|
15
|
+
const type = sanitizeForTsv(cred.type);
|
|
15
16
|
const expires = formatExpiresAt(cred.expiresAt);
|
|
16
17
|
const updated = formatRelativeTime(cred.updatedAt);
|
|
17
|
-
console.log(`${agent}\t${name}\t${expires}\t${updated}`);
|
|
18
|
+
console.log(`${agent}\t${name}\t${type}\t${expires}\t${updated}`);
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
@@ -59,6 +60,7 @@ export function handleCredentialList(options) {
|
|
|
59
60
|
const output = credentials.map((cred) => ({
|
|
60
61
|
agent: cred.agent,
|
|
61
62
|
name: cred.name,
|
|
63
|
+
type: cred.type,
|
|
62
64
|
createdAt: cred.createdAt.toISOString(),
|
|
63
65
|
updatedAt: cred.updatedAt.toISOString(),
|
|
64
66
|
expiresAt: formatDateForJson(cred.expiresAt),
|
package/dist/db/migrations.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Uses a simple version-based migration system.
|
|
5
5
|
*/
|
|
6
6
|
import type Database from "better-sqlite3";
|
|
7
|
-
declare const CURRENT_VERSION =
|
|
7
|
+
declare const CURRENT_VERSION = 3;
|
|
8
8
|
/** Run all pending migrations */
|
|
9
9
|
declare function runMigrations(database: Database.Database): void;
|
|
10
10
|
/** Get current schema version */
|
package/dist/db/migrations.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Uses a simple version-based migration system.
|
|
5
5
|
*/
|
|
6
|
-
const CURRENT_VERSION =
|
|
6
|
+
const CURRENT_VERSION = 3;
|
|
7
7
|
/** Run all pending migrations */
|
|
8
8
|
function runMigrations(database) {
|
|
9
9
|
const version = getSchemaVersion(database);
|
|
@@ -13,6 +13,9 @@ function runMigrations(database) {
|
|
|
13
13
|
if (version < 2) {
|
|
14
14
|
migrateToV2(database);
|
|
15
15
|
}
|
|
16
|
+
if (version < 3) {
|
|
17
|
+
migrateToV3(database);
|
|
18
|
+
}
|
|
16
19
|
}
|
|
17
20
|
/** Get current schema version */
|
|
18
21
|
function getSchemaVersion(database) {
|
|
@@ -93,4 +96,18 @@ function migrateToV2(database) {
|
|
|
93
96
|
setSchemaVersion(database, 2);
|
|
94
97
|
})();
|
|
95
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Migration to version 3: Add type column to credentials
|
|
101
|
+
*
|
|
102
|
+
* Explicit credential type ("oauth" or "api-key") instead of inferring from data.
|
|
103
|
+
* Existing credentials without type must be re-uploaded.
|
|
104
|
+
*/
|
|
105
|
+
function migrateToV3(database) {
|
|
106
|
+
database.transaction(() => {
|
|
107
|
+
database.exec(`
|
|
108
|
+
ALTER TABLE credentials ADD COLUMN type TEXT
|
|
109
|
+
`);
|
|
110
|
+
setSchemaVersion(database, 3);
|
|
111
|
+
})();
|
|
112
|
+
}
|
|
96
113
|
export { CURRENT_VERSION, getSchemaVersion, runMigrations };
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
* Manages encrypted credential storage.
|
|
5
5
|
*/
|
|
6
6
|
import type Database from "better-sqlite3";
|
|
7
|
+
/** Valid credential types */
|
|
8
|
+
type CredentialType = "oauth" | "api-key";
|
|
7
9
|
/** Credential record stored in database */
|
|
8
10
|
interface CredentialRecord {
|
|
9
11
|
agent: string;
|
|
10
12
|
name: string;
|
|
13
|
+
type: CredentialType;
|
|
11
14
|
encryptedData: Buffer;
|
|
12
15
|
salt: Buffer;
|
|
13
16
|
iv: Buffer;
|
|
@@ -20,6 +23,7 @@ interface CredentialRecord {
|
|
|
20
23
|
interface CredentialMetadata {
|
|
21
24
|
agent: string;
|
|
22
25
|
name: string;
|
|
26
|
+
type: CredentialType;
|
|
23
27
|
createdAt: Date;
|
|
24
28
|
updatedAt: Date;
|
|
25
29
|
expiresAt: Date | undefined;
|
|
@@ -28,6 +32,7 @@ interface CredentialMetadata {
|
|
|
28
32
|
declare function upsertCredential(database: Database.Database, credential: {
|
|
29
33
|
agent: string;
|
|
30
34
|
name: string;
|
|
35
|
+
type: CredentialType;
|
|
31
36
|
encryptedData: Buffer;
|
|
32
37
|
salt: Buffer;
|
|
33
38
|
iv: Buffer;
|
|
@@ -45,4 +50,4 @@ declare function deleteCredential(database: Database.Database, agent: string, na
|
|
|
45
50
|
/** Update expiration time after refresh */
|
|
46
51
|
declare function updateExpiresAt(database: Database.Database, agent: string, name: string, expiresAt: Date | undefined): void;
|
|
47
52
|
export { deleteCredential, getCredential, listCredentials, listCredentialsForApiKey, updateExpiresAt, upsertCredential, };
|
|
48
|
-
export type { CredentialMetadata, CredentialRecord };
|
|
53
|
+
export type { CredentialMetadata, CredentialRecord, CredentialType };
|
|
@@ -3,14 +3,19 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Manages encrypted credential storage.
|
|
5
5
|
*/
|
|
6
|
+
/** Validate credential type from database */
|
|
7
|
+
function validateType(type) {
|
|
8
|
+
if (type !== "oauth" && type !== "api-key") {
|
|
9
|
+
throw new Error(`Invalid credential type: ${type}`);
|
|
10
|
+
}
|
|
11
|
+
return type;
|
|
12
|
+
}
|
|
6
13
|
/** Convert database row to record */
|
|
7
14
|
function rowToRecord(row) {
|
|
8
|
-
if (!row.salt) {
|
|
9
|
-
throw new Error("Credential missing salt - database may need migration");
|
|
10
|
-
}
|
|
11
15
|
return {
|
|
12
16
|
agent: row.agent,
|
|
13
17
|
name: row.name,
|
|
18
|
+
type: validateType(row.type),
|
|
14
19
|
encryptedData: row.encrypted_data,
|
|
15
20
|
salt: row.salt,
|
|
16
21
|
iv: row.iv,
|
|
@@ -25,6 +30,7 @@ function rowToMetadata(row) {
|
|
|
25
30
|
return {
|
|
26
31
|
agent: row.agent,
|
|
27
32
|
name: row.name,
|
|
33
|
+
type: validateType(row.type),
|
|
28
34
|
createdAt: new Date(row.created_at),
|
|
29
35
|
updatedAt: new Date(row.updated_at),
|
|
30
36
|
expiresAt: row.expires_at ? new Date(row.expires_at) : undefined,
|
|
@@ -35,25 +41,25 @@ function upsertCredential(database, credential) {
|
|
|
35
41
|
const now = Date.now();
|
|
36
42
|
/* eslint-disable unicorn/no-null -- SQLite requires null for NULL values */
|
|
37
43
|
database
|
|
38
|
-
.prepare(`INSERT INTO credentials (agent, name, encrypted_data, salt, iv, auth_tag, created_at, updated_at, expires_at)
|
|
39
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
44
|
+
.prepare(`INSERT INTO credentials (agent, name, type, encrypted_data, salt, iv, auth_tag, created_at, updated_at, expires_at)
|
|
45
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
40
46
|
ON CONFLICT(agent, name) DO UPDATE SET
|
|
41
|
-
encrypted_data = excluded.encrypted_data, salt = excluded.salt, iv = excluded.iv, auth_tag = excluded.auth_tag,
|
|
47
|
+
type = excluded.type, encrypted_data = excluded.encrypted_data, salt = excluded.salt, iv = excluded.iv, auth_tag = excluded.auth_tag,
|
|
42
48
|
updated_at = excluded.updated_at, expires_at = excluded.expires_at`)
|
|
43
|
-
.run(credential.agent, credential.name, credential.encryptedData, credential.salt, credential.iv, credential.authTag, now, now, credential.expiresAt?.getTime() ?? null);
|
|
49
|
+
.run(credential.agent, credential.name, credential.type, credential.encryptedData, credential.salt, credential.iv, credential.authTag, now, now, credential.expiresAt?.getTime() ?? null);
|
|
44
50
|
/* eslint-enable unicorn/no-null */
|
|
45
51
|
}
|
|
46
52
|
/** Get a credential by agent and name */
|
|
47
53
|
function getCredential(database, agent, name) {
|
|
48
54
|
const row = database
|
|
49
|
-
.prepare(`SELECT agent, name, encrypted_data, salt, iv, auth_tag, created_at, updated_at, expires_at FROM credentials WHERE agent = ? AND name = ?`)
|
|
55
|
+
.prepare(`SELECT agent, name, type, encrypted_data, salt, iv, auth_tag, created_at, updated_at, expires_at FROM credentials WHERE agent = ? AND name = ?`)
|
|
50
56
|
.get(agent, name);
|
|
51
57
|
return row ? rowToRecord(row) : undefined;
|
|
52
58
|
}
|
|
53
59
|
/** List all credentials (metadata only) */
|
|
54
60
|
function listCredentials(database) {
|
|
55
61
|
const rows = database
|
|
56
|
-
.prepare(`SELECT agent, name, created_at, updated_at, expires_at FROM credentials ORDER BY agent, name`)
|
|
62
|
+
.prepare(`SELECT agent, name, type, created_at, updated_at, expires_at FROM credentials ORDER BY agent, name`)
|
|
57
63
|
.all();
|
|
58
64
|
return rows.map((row) => rowToMetadata(row));
|
|
59
65
|
}
|
package/dist/db/types.d.ts
CHANGED
|
@@ -26,8 +26,9 @@ export interface AuditLogRow {
|
|
|
26
26
|
export interface CredentialRow {
|
|
27
27
|
agent: string;
|
|
28
28
|
name: string;
|
|
29
|
+
type: string;
|
|
29
30
|
encrypted_data: Buffer;
|
|
30
|
-
salt: Buffer
|
|
31
|
+
salt: Buffer;
|
|
31
32
|
iv: Buffer;
|
|
32
33
|
auth_tag: Buffer;
|
|
33
34
|
created_at: number;
|
|
@@ -38,6 +39,7 @@ export interface CredentialRow {
|
|
|
38
39
|
export interface MetadataRow {
|
|
39
40
|
agent: string;
|
|
40
41
|
name: string;
|
|
42
|
+
type: string;
|
|
41
43
|
created_at: number;
|
|
42
44
|
updated_at: number;
|
|
43
45
|
expires_at: number | null;
|
|
@@ -30,28 +30,7 @@ function createGetCredentialHandler(database, config) {
|
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
// Fetch credential from database
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
credential = getCredential(database, agent, name);
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
// Handle legacy credentials stored without salt (pre-v2 migration)
|
|
39
|
-
if (error instanceof Error && error.message.includes("missing salt")) {
|
|
40
|
-
logAccess(database, {
|
|
41
|
-
apiKeyId: apiKey.id,
|
|
42
|
-
action: "read",
|
|
43
|
-
agent,
|
|
44
|
-
name,
|
|
45
|
-
success: false,
|
|
46
|
-
errorMessage: "Legacy credential requires re-upload",
|
|
47
|
-
});
|
|
48
|
-
response.status(410).json({
|
|
49
|
-
error: "This credential was stored with legacy encryption and must be deleted and re-uploaded",
|
|
50
|
-
});
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
throw error;
|
|
54
|
-
}
|
|
33
|
+
const credential = getCredential(database, agent, name);
|
|
55
34
|
if (!credential) {
|
|
56
35
|
logAccess(database, {
|
|
57
36
|
apiKeyId: apiKey.id,
|
|
@@ -90,10 +69,11 @@ function createGetCredentialHandler(database, config) {
|
|
|
90
69
|
let wasRefreshed = false;
|
|
91
70
|
let refreshFailed = false;
|
|
92
71
|
if (config.refreshThresholdSeconds > 0 &&
|
|
72
|
+
credential.type === "oauth" &&
|
|
93
73
|
isRefreshable(data) &&
|
|
94
74
|
needsRefresh(data, config.refreshThresholdSeconds)) {
|
|
95
75
|
try {
|
|
96
|
-
const refreshResult = await refreshWithMutex(database, agent, name, data, apiKey.id, credential.updatedAt, { timeoutMs: config.refreshTimeoutMs });
|
|
76
|
+
const refreshResult = await refreshWithMutex(database, agent, name, credential.type, data, apiKey.id, credential.updatedAt, { timeoutMs: config.refreshTimeoutMs });
|
|
97
77
|
if (refreshResult.ok) {
|
|
98
78
|
finalData = refreshResult.data;
|
|
99
79
|
finalExpiresAt = refreshResult.expiresAt;
|
|
@@ -101,8 +81,30 @@ function createGetCredentialHandler(database, config) {
|
|
|
101
81
|
wasRefreshed = true;
|
|
102
82
|
}
|
|
103
83
|
else {
|
|
104
|
-
// Refresh failed -
|
|
105
|
-
|
|
84
|
+
// Refresh failed - re-fetch to check if credential was deleted/modified
|
|
85
|
+
const currentCredential = getCredential(database, agent, name);
|
|
86
|
+
if (!currentCredential) {
|
|
87
|
+
// Credential was deleted during refresh - don't leak old data
|
|
88
|
+
logAccess(database, {
|
|
89
|
+
apiKeyId: apiKey.id,
|
|
90
|
+
action: "read",
|
|
91
|
+
agent,
|
|
92
|
+
name,
|
|
93
|
+
success: false,
|
|
94
|
+
errorMessage: "Credential deleted during refresh",
|
|
95
|
+
});
|
|
96
|
+
response.status(404).json({ error: "Credential not found" });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (currentCredential.updatedAt.getTime() !==
|
|
100
|
+
credential.updatedAt.getTime()) {
|
|
101
|
+
// Credential was modified during refresh - return fresh data
|
|
102
|
+
const freshData = decryptCredential(currentCredential);
|
|
103
|
+
finalData = freshData;
|
|
104
|
+
finalExpiresAt = currentCredential.expiresAt;
|
|
105
|
+
finalUpdatedAt = currentCredential.updatedAt;
|
|
106
|
+
}
|
|
107
|
+
// Otherwise credential unchanged, return original with warning
|
|
106
108
|
refreshFailed = true;
|
|
107
109
|
}
|
|
108
110
|
}
|
|
@@ -134,6 +136,7 @@ function createGetCredentialHandler(database, config) {
|
|
|
134
136
|
response.json({
|
|
135
137
|
agent,
|
|
136
138
|
name,
|
|
139
|
+
type: credential.type,
|
|
137
140
|
data: finalData,
|
|
138
141
|
expiresAt: finalExpiresAt?.toISOString(),
|
|
139
142
|
updatedAt: finalUpdatedAt.toISOString(),
|
|
@@ -26,7 +26,10 @@ function createPutCredentialHandler(database) {
|
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
const body = request.body;
|
|
29
|
-
if (!body ||
|
|
29
|
+
if (!body ||
|
|
30
|
+
typeof body.data !== "object" ||
|
|
31
|
+
body.data === null ||
|
|
32
|
+
Array.isArray(body.data)) {
|
|
30
33
|
logAccess(database, {
|
|
31
34
|
apiKeyId: apiKey.id,
|
|
32
35
|
action: "write",
|
|
@@ -40,6 +43,21 @@ function createPutCredentialHandler(database) {
|
|
|
40
43
|
.json({ error: "Request body must include 'data' object" });
|
|
41
44
|
return;
|
|
42
45
|
}
|
|
46
|
+
if (body.type !== "oauth" && body.type !== "api-key") {
|
|
47
|
+
logAccess(database, {
|
|
48
|
+
apiKeyId: apiKey.id,
|
|
49
|
+
action: "write",
|
|
50
|
+
agent,
|
|
51
|
+
name,
|
|
52
|
+
success: false,
|
|
53
|
+
errorMessage: "Invalid type",
|
|
54
|
+
});
|
|
55
|
+
response.status(400).json({
|
|
56
|
+
error: 'Request body must include \'type\' ("oauth" or "api-key")',
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const credentialType = body.type;
|
|
43
61
|
try {
|
|
44
62
|
const encrypted = encryptCredential(body.data);
|
|
45
63
|
let expiresAt;
|
|
@@ -61,6 +79,7 @@ function createPutCredentialHandler(database) {
|
|
|
61
79
|
upsertCredential(database, {
|
|
62
80
|
agent,
|
|
63
81
|
name,
|
|
82
|
+
type: credentialType,
|
|
64
83
|
...encrypted,
|
|
65
84
|
expiresAt,
|
|
66
85
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* with axauth's refresh functionality.
|
|
6
6
|
*/
|
|
7
7
|
import type Database from "better-sqlite3";
|
|
8
|
+
import type { CredentialType } from "../db/repositories/credentials.js";
|
|
8
9
|
/** Key for credential-specific mutex */
|
|
9
10
|
type CredentialKey = `${string}/${string}`;
|
|
10
11
|
/** Result type for the full refresh operation */
|
|
@@ -40,12 +41,13 @@ declare function buildKey(agent: string, name: string): CredentialKey;
|
|
|
40
41
|
* @param database - Database connection
|
|
41
42
|
* @param agent - Agent name
|
|
42
43
|
* @param name - Credential name
|
|
44
|
+
* @param type - Credential type (must be "oauth"; caller must gate on type)
|
|
43
45
|
* @param data - Current decrypted credential data
|
|
44
46
|
* @param apiKeyId - API key ID for audit logging
|
|
45
47
|
* @param originalUpdatedAt - Original updatedAt for optimistic locking
|
|
46
48
|
* @param options - Refresh options
|
|
47
49
|
* @returns Refresh result with new data, expiresAt, updatedAt or error
|
|
48
50
|
*/
|
|
49
|
-
declare function refreshWithMutex(database: Database.Database, agent: string, name: string, data: Record<string, unknown>, apiKeyId: string, originalUpdatedAt: Date, options: RefreshManagerOptions): Promise<FullRefreshResult>;
|
|
51
|
+
declare function refreshWithMutex(database: Database.Database, agent: string, name: string, type: CredentialType, data: Record<string, unknown>, apiKeyId: string, originalUpdatedAt: Date, options: RefreshManagerOptions): Promise<FullRefreshResult>;
|
|
50
52
|
export { extractExpiryDate, isRefreshable, needsRefresh, toAxauthCredentials, } from "./check-refresh.js";
|
|
51
53
|
export { buildKey, refreshWithMutex };
|
|
@@ -19,7 +19,7 @@ function buildKey(agent, name) {
|
|
|
19
19
|
* Execute the full refresh operation: call axauth, validate, persist.
|
|
20
20
|
* This is the inner operation that gets stored in the mutex.
|
|
21
21
|
*/
|
|
22
|
-
async function executeRefresh(database, agent, name, data, apiKeyId, originalUpdatedAt, refreshStartedAt, options) {
|
|
22
|
+
async function executeRefresh(database, agent, name, type, data, apiKeyId, originalUpdatedAt, refreshStartedAt, options) {
|
|
23
23
|
const logContext = { database, apiKeyId, agent, name };
|
|
24
24
|
// Map to axauth format
|
|
25
25
|
const creds = toAxauthCredentials(agent, data);
|
|
@@ -54,6 +54,7 @@ async function executeRefresh(database, agent, name, data, apiKeyId, originalUpd
|
|
|
54
54
|
upsertCredential(database, {
|
|
55
55
|
agent,
|
|
56
56
|
name,
|
|
57
|
+
type,
|
|
57
58
|
...encrypted,
|
|
58
59
|
expiresAt,
|
|
59
60
|
});
|
|
@@ -98,13 +99,14 @@ async function executeRefresh(database, agent, name, data, apiKeyId, originalUpd
|
|
|
98
99
|
* @param database - Database connection
|
|
99
100
|
* @param agent - Agent name
|
|
100
101
|
* @param name - Credential name
|
|
102
|
+
* @param type - Credential type (must be "oauth"; caller must gate on type)
|
|
101
103
|
* @param data - Current decrypted credential data
|
|
102
104
|
* @param apiKeyId - API key ID for audit logging
|
|
103
105
|
* @param originalUpdatedAt - Original updatedAt for optimistic locking
|
|
104
106
|
* @param options - Refresh options
|
|
105
107
|
* @returns Refresh result with new data, expiresAt, updatedAt or error
|
|
106
108
|
*/
|
|
107
|
-
async function refreshWithMutex(database, agent, name, data, apiKeyId, originalUpdatedAt, options) {
|
|
109
|
+
async function refreshWithMutex(database, agent, name, type, data, apiKeyId, originalUpdatedAt, options) {
|
|
108
110
|
const key = buildKey(agent, name);
|
|
109
111
|
// Check if refresh already in progress
|
|
110
112
|
const existing = pendingRefreshes.get(key);
|
|
@@ -115,7 +117,7 @@ async function refreshWithMutex(database, agent, name, data, apiKeyId, originalU
|
|
|
115
117
|
}
|
|
116
118
|
// Start new refresh - store promise for the FULL operation
|
|
117
119
|
const refreshStartedAt = new Date();
|
|
118
|
-
const fullOperationPromise = executeRefresh(database, agent, name, data, apiKeyId, originalUpdatedAt, refreshStartedAt, options);
|
|
120
|
+
const fullOperationPromise = executeRefresh(database, agent, name, type, data, apiKeyId, originalUpdatedAt, refreshStartedAt, options);
|
|
119
121
|
pendingRefreshes.set(key, {
|
|
120
122
|
promise: fullOperationPromise,
|
|
121
123
|
startedAt: refreshStartedAt,
|
package/package.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"name": "axvault",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "1.
|
|
6
|
-
"description": "Remote credential storage server for
|
|
5
|
+
"version": "1.1.0",
|
|
6
|
+
"description": "Remote credential storage server for axkit",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/Jercik/axvault.git"
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"@types/node": "^25.0.3",
|
|
82
82
|
"@vitest/coverage-v8": "^4.0.16",
|
|
83
83
|
"eslint": "^9.39.2",
|
|
84
|
-
"eslint-config-
|
|
84
|
+
"eslint-config-axkit": "^1.0.0",
|
|
85
85
|
"fta-check": "^1.5.1",
|
|
86
86
|
"fta-cli": "^3.0.0",
|
|
87
87
|
"knip": "^5.80.0",
|