axvault 1.11.3 → 1.13.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 +91 -147
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -105
- package/dist/cli.js.map +1 -1
- package/dist/commands/serve.d.ts +5 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +88 -79
- package/dist/commands/serve.js.map +1 -1
- package/dist/config.d.ts +60 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +53 -36
- package/dist/config.js.map +1 -1
- package/dist/db/bootstrap-api-key.d.ts +14 -0
- package/dist/db/bootstrap-api-key.d.ts.map +1 -0
- package/dist/db/bootstrap-api-key.js +26 -0
- package/dist/db/bootstrap-api-key.js.map +1 -0
- package/dist/db/create-pool.d.ts +5 -0
- package/dist/db/create-pool.d.ts.map +1 -0
- package/dist/db/create-pool.js +13 -0
- package/dist/db/create-pool.js.map +1 -0
- package/dist/db/migrations/001-initial.sql +41 -0
- package/dist/db/repositories/api-keys.d.ts +11 -37
- package/dist/db/repositories/api-keys.d.ts.map +1 -1
- package/dist/db/repositories/api-keys.js +23 -67
- package/dist/db/repositories/api-keys.js.map +1 -1
- package/dist/db/repositories/audit-log.d.ts +9 -7
- package/dist/db/repositories/audit-log.d.ts.map +1 -1
- package/dist/db/repositories/audit-log.js +25 -24
- package/dist/db/repositories/audit-log.js.map +1 -1
- package/dist/db/repositories/create-api-key.d.ts +30 -0
- package/dist/db/repositories/create-api-key.d.ts.map +1 -0
- package/dist/db/repositories/create-api-key.js +37 -0
- package/dist/db/repositories/create-api-key.js.map +1 -0
- package/dist/db/repositories/credentials-queries.d.ts +6 -6
- package/dist/db/repositories/credentials-queries.d.ts.map +1 -1
- package/dist/db/repositories/credentials-queries.js +8 -8
- package/dist/db/repositories/credentials-queries.js.map +1 -1
- package/dist/db/repositories/credentials.d.ts +9 -25
- package/dist/db/repositories/credentials.d.ts.map +1 -1
- package/dist/db/repositories/credentials.js +38 -34
- package/dist/db/repositories/credentials.js.map +1 -1
- package/dist/db/repositories/list-credentials-paginated.d.ts +2 -2
- package/dist/db/repositories/list-credentials-paginated.d.ts.map +1 -1
- package/dist/db/repositories/list-credentials-paginated.js +26 -26
- package/dist/db/repositories/list-credentials-paginated.js.map +1 -1
- package/dist/db/repositories/update-api-key-access.d.ts +12 -0
- package/dist/db/repositories/update-api-key-access.d.ts.map +1 -0
- package/dist/db/repositories/update-api-key-access.js +29 -0
- package/dist/db/repositories/update-api-key-access.js.map +1 -0
- package/dist/db/repositories/update-credential-if-unchanged.d.ts +20 -0
- package/dist/db/repositories/update-credential-if-unchanged.d.ts.map +1 -0
- package/dist/db/repositories/update-credential-if-unchanged.js +22 -0
- package/dist/db/repositories/update-credential-if-unchanged.js.map +1 -0
- package/dist/db/run-migrations.d.ts +16 -0
- package/dist/db/run-migrations.d.ts.map +1 -0
- package/dist/db/run-migrations.js +26 -0
- package/dist/db/run-migrations.js.map +1 -0
- package/dist/db/types.d.ts +6 -2
- package/dist/db/types.d.ts.map +1 -1
- package/dist/db/types.js +1 -1
- package/dist/format-error-message.d.ts +7 -0
- package/dist/format-error-message.d.ts.map +1 -0
- package/dist/format-error-message.js +19 -0
- package/dist/format-error-message.js.map +1 -0
- package/dist/handlers/refresh-credential-on-read.d.ts +2 -2
- package/dist/handlers/refresh-credential-on-read.d.ts.map +1 -1
- package/dist/handlers/refresh-credential-on-read.js +8 -8
- package/dist/handlers/refresh-credential-on-read.js.map +1 -1
- package/dist/index.d.ts +14 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/access-list.d.ts +13 -0
- package/dist/lib/access-list.d.ts.map +1 -0
- package/dist/lib/access-list.js +22 -0
- package/dist/lib/access-list.js.map +1 -0
- package/dist/lib/credential-name.d.ts +1 -6
- package/dist/lib/credential-name.d.ts.map +1 -1
- package/dist/lib/credential-name.js +1 -4
- package/dist/lib/credential-name.js.map +1 -1
- package/dist/schemas/request.d.ts +35 -0
- package/dist/schemas/request.d.ts.map +1 -0
- package/dist/schemas/request.js +76 -0
- package/dist/schemas/request.js.map +1 -0
- package/dist/schemas/{api.d.ts → response.d.ts} +6 -32
- package/dist/schemas/response.d.ts.map +1 -0
- package/dist/schemas/response.js +59 -0
- package/dist/schemas/response.js.map +1 -0
- package/dist/server/plugins/auth.d.ts +19 -0
- package/dist/server/plugins/auth.d.ts.map +1 -0
- package/dist/server/plugins/auth.js +51 -0
- package/dist/server/plugins/auth.js.map +1 -0
- package/dist/server/plugins/config.d.ts +14 -0
- package/dist/server/plugins/config.d.ts.map +1 -0
- package/dist/server/plugins/config.js +19 -0
- package/dist/server/plugins/config.js.map +1 -0
- package/dist/server/plugins/database.d.ts +12 -0
- package/dist/server/plugins/database.d.ts.map +1 -0
- package/dist/server/plugins/database.js +20 -0
- package/dist/server/plugins/database.js.map +1 -0
- package/dist/server/routes/credentials.d.ts +8 -0
- package/dist/server/routes/credentials.d.ts.map +1 -0
- package/dist/server/routes/credentials.js +82 -0
- package/dist/server/routes/credentials.js.map +1 -0
- package/dist/server/routes/handle-create-key.d.ts +10 -0
- package/dist/server/routes/handle-create-key.d.ts.map +1 -0
- package/dist/server/routes/handle-create-key.js +44 -0
- package/dist/server/routes/handle-create-key.js.map +1 -0
- package/dist/server/routes/handle-delete-credential.d.ts +10 -0
- package/dist/server/routes/handle-delete-credential.d.ts.map +1 -0
- package/dist/server/routes/handle-delete-credential.js +47 -0
- package/dist/server/routes/handle-delete-credential.js.map +1 -0
- package/dist/server/routes/handle-delete-key.d.ts +11 -0
- package/dist/server/routes/handle-delete-key.d.ts.map +1 -0
- package/dist/server/routes/handle-delete-key.js +40 -0
- package/dist/server/routes/handle-delete-key.js.map +1 -0
- package/dist/server/routes/handle-get-credential.d.ts +18 -0
- package/dist/server/routes/handle-get-credential.d.ts.map +1 -0
- package/dist/{handlers/get-credential.js → server/routes/handle-get-credential.js} +23 -40
- package/dist/server/routes/handle-get-credential.js.map +1 -0
- package/dist/server/routes/handle-list-credentials.d.ts +13 -0
- package/dist/server/routes/handle-list-credentials.d.ts.map +1 -0
- package/dist/{handlers/list-credentials.js → server/routes/handle-list-credentials.js} +13 -32
- package/dist/server/routes/handle-list-credentials.js.map +1 -0
- package/dist/server/routes/handle-put-credential.d.ts +14 -0
- package/dist/server/routes/handle-put-credential.d.ts.map +1 -0
- package/dist/{handlers/put-credential.js → server/routes/handle-put-credential.js} +30 -38
- package/dist/server/routes/handle-put-credential.js.map +1 -0
- package/dist/server/routes/handle-update-key.d.ts +13 -0
- package/dist/server/routes/handle-update-key.d.ts.map +1 -0
- package/dist/server/routes/handle-update-key.js +74 -0
- package/dist/server/routes/handle-update-key.js.map +1 -0
- package/dist/server/routes/health.d.ts +7 -0
- package/dist/server/routes/health.d.ts.map +1 -0
- package/dist/server/routes/health.js +25 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/keys.d.ts +12 -0
- package/dist/server/routes/keys.d.ts.map +1 -0
- package/dist/server/routes/keys.js +119 -0
- package/dist/server/routes/keys.js.map +1 -0
- package/dist/server/routes/log-grant-event.d.ts +7 -0
- package/dist/server/routes/log-grant-event.d.ts.map +1 -0
- package/dist/server/routes/log-grant-event.js +15 -0
- package/dist/server/routes/log-grant-event.js.map +1 -0
- package/dist/server/send-sensible-error.d.ts +7 -0
- package/dist/server/send-sensible-error.d.ts.map +1 -0
- package/dist/server/send-sensible-error.js +40 -0
- package/dist/server/send-sensible-error.js.map +1 -0
- package/dist/server/server.d.ts +6 -17
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +72 -56
- package/dist/server/server.js.map +1 -1
- package/package.json +11 -4
- package/dist/commands/credential.d.ts +0 -17
- package/dist/commands/credential.d.ts.map +0 -1
- package/dist/commands/credential.js +0 -126
- package/dist/commands/credential.js.map +0 -1
- package/dist/commands/init.d.ts +0 -10
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -56
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/key-create.d.ts +0 -14
- package/dist/commands/key-create.d.ts.map +0 -1
- package/dist/commands/key-create.js +0 -100
- package/dist/commands/key-create.js.map +0 -1
- package/dist/commands/key-list.d.ts +0 -10
- package/dist/commands/key-list.d.ts.map +0 -1
- package/dist/commands/key-list.js +0 -46
- package/dist/commands/key-list.js.map +0 -1
- package/dist/commands/key-revoke.d.ts +0 -12
- package/dist/commands/key-revoke.d.ts.map +0 -1
- package/dist/commands/key-revoke.js +0 -56
- package/dist/commands/key-revoke.js.map +0 -1
- package/dist/commands/key-update.d.ts +0 -17
- package/dist/commands/key-update.d.ts.map +0 -1
- package/dist/commands/key-update.js +0 -110
- package/dist/commands/key-update.js.map +0 -1
- package/dist/commands/key.d.ts +0 -10
- package/dist/commands/key.d.ts.map +0 -1
- package/dist/commands/key.js +0 -10
- package/dist/commands/key.js.map +0 -1
- package/dist/db/client.d.ts +0 -14
- package/dist/db/client.d.ts.map +0 -1
- package/dist/db/client.js +0 -39
- package/dist/db/client.js.map +0 -1
- package/dist/db/migrations.d.ts +0 -14
- package/dist/db/migrations.d.ts.map +0 -1
- package/dist/db/migrations.js +0 -141
- package/dist/db/migrations.js.map +0 -1
- package/dist/handlers/create-key.d.ts +0 -14
- package/dist/handlers/create-key.d.ts.map +0 -1
- package/dist/handlers/create-key.js +0 -25
- package/dist/handlers/create-key.js.map +0 -1
- package/dist/handlers/delete-credential.d.ts +0 -15
- package/dist/handlers/delete-credential.d.ts.map +0 -1
- package/dist/handlers/delete-credential.js +0 -47
- package/dist/handlers/delete-credential.js.map +0 -1
- package/dist/handlers/delete-key.d.ts +0 -15
- package/dist/handlers/delete-key.d.ts.map +0 -1
- package/dist/handlers/delete-key.js +0 -26
- package/dist/handlers/delete-key.js.map +0 -1
- package/dist/handlers/get-credential.d.ts +0 -27
- package/dist/handlers/get-credential.d.ts.map +0 -1
- package/dist/handlers/get-credential.js.map +0 -1
- package/dist/handlers/get-key.d.ts +0 -15
- package/dist/handlers/get-key.d.ts.map +0 -1
- package/dist/handlers/get-key.js +0 -21
- package/dist/handlers/get-key.js.map +0 -1
- package/dist/handlers/list-credentials.d.ts +0 -27
- package/dist/handlers/list-credentials.d.ts.map +0 -1
- package/dist/handlers/list-credentials.js.map +0 -1
- package/dist/handlers/list-keys.d.ts +0 -11
- package/dist/handlers/list-keys.d.ts.map +0 -1
- package/dist/handlers/list-keys.js +0 -16
- package/dist/handlers/list-keys.js.map +0 -1
- package/dist/handlers/put-credential.d.ts +0 -24
- package/dist/handlers/put-credential.d.ts.map +0 -1
- package/dist/handlers/put-credential.js.map +0 -1
- package/dist/handlers/update-key.d.ts +0 -17
- package/dist/handlers/update-key.d.ts.map +0 -1
- package/dist/handlers/update-key.js +0 -51
- package/dist/handlers/update-key.js.map +0 -1
- package/dist/lib/format.d.ts +0 -89
- package/dist/lib/format.d.ts.map +0 -1
- package/dist/lib/format.js +0 -180
- package/dist/lib/format.js.map +0 -1
- package/dist/lib/parse-access-options.d.ts +0 -38
- package/dist/lib/parse-access-options.d.ts.map +0 -1
- package/dist/lib/parse-access-options.js +0 -85
- package/dist/lib/parse-access-options.js.map +0 -1
- package/dist/middleware/auth.d.ts +0 -22
- package/dist/middleware/auth.d.ts.map +0 -1
- package/dist/middleware/auth.js +0 -48
- package/dist/middleware/auth.js.map +0 -1
- package/dist/middleware/require-grant-access.d.ts +0 -10
- package/dist/middleware/require-grant-access.d.ts.map +0 -1
- package/dist/middleware/require-grant-access.js +0 -14
- package/dist/middleware/require-grant-access.js.map +0 -1
- package/dist/schemas/api.d.ts.map +0 -1
- package/dist/schemas/api.js +0 -119
- package/dist/schemas/api.js.map +0 -1
- package/dist/server/routes.d.ts +0 -14
- package/dist/server/routes.d.ts.map +0 -1
- package/dist/server/routes.js +0 -200
- package/dist/server/routes.js.map +0 -1
package/dist/commands/serve.js
CHANGED
|
@@ -1,111 +1,120 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Start server command handler.
|
|
3
|
+
*
|
|
4
|
+
* Builds the Fastify app, registers plugins in dependency order
|
|
5
|
+
* (database → auth → routes), runs migrations, creates a bootstrap
|
|
6
|
+
* API key on first startup, and starts listening.
|
|
3
7
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
6
9
|
import closeWithGrace from "close-with-grace";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
10
|
+
import { formatErrorMessage } from "../format-error-message.js";
|
|
11
|
+
import { resolveBuildAppConfig } from "../config.js";
|
|
12
|
+
import { bootstrapApiKey } from "../db/bootstrap-api-key.js";
|
|
13
|
+
import { runMigrations } from "../db/run-migrations.js";
|
|
14
|
+
import configPlugin from "../server/plugins/config.js";
|
|
15
|
+
import databasePlugin from "../server/plugins/database.js";
|
|
16
|
+
import authPlugin from "../server/plugins/auth.js";
|
|
17
|
+
import credentialRoutes from "../server/routes/credentials.js";
|
|
18
|
+
import healthRoutes from "../server/routes/health.js";
|
|
19
|
+
import keyRoutes from "../server/routes/keys.js";
|
|
20
|
+
import { buildApp } from "../server/server.js";
|
|
21
|
+
const migrationsDirectory = fileURLToPath(new URL("../db/migrations", import.meta.url));
|
|
12
22
|
export async function handleServe(options) {
|
|
13
|
-
let
|
|
14
|
-
const verbose = options.verbose === true;
|
|
23
|
+
let buildConfig;
|
|
15
24
|
try {
|
|
16
|
-
|
|
17
|
-
port: options.port,
|
|
18
|
-
host: options.host,
|
|
19
|
-
dbPath: options.dbPath,
|
|
20
|
-
refreshThresholdSeconds: options.refreshThreshold,
|
|
21
|
-
refreshTimeoutMs: options.refreshTimeout,
|
|
25
|
+
buildConfig = resolveBuildAppConfig({
|
|
22
26
|
logLevel: options.logLevel,
|
|
23
27
|
});
|
|
24
28
|
}
|
|
25
29
|
catch (error) {
|
|
26
|
-
const message =
|
|
30
|
+
const message = formatErrorMessage(error);
|
|
27
31
|
console.error(`Error: ${message}`);
|
|
28
32
|
// eslint-disable-next-line unicorn/no-process-exit -- CLI config error
|
|
29
33
|
process.exit(1);
|
|
30
34
|
}
|
|
31
|
-
//
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
// Build core app with security middleware and error handling
|
|
36
|
+
const app = buildApp(buildConfig);
|
|
37
|
+
try {
|
|
38
|
+
// Register plugins in dependency order: config → database → auth → routes
|
|
39
|
+
await app.register(configPlugin, {
|
|
40
|
+
overrides: {
|
|
41
|
+
port: options.port,
|
|
42
|
+
host: options.host,
|
|
43
|
+
databaseUrl: options.databaseUrl,
|
|
44
|
+
refreshThresholdSeconds: options.refreshThreshold,
|
|
45
|
+
refreshTimeoutMs: options.refreshTimeout,
|
|
46
|
+
logLevel: options.logLevel,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
await app.register(databasePlugin, (parent) => ({
|
|
50
|
+
connectionString: parent.config.databaseUrl,
|
|
51
|
+
}));
|
|
52
|
+
await app.register(authPlugin);
|
|
53
|
+
await app.register(healthRoutes);
|
|
54
|
+
await app.register(credentialRoutes, (parent) => ({
|
|
55
|
+
refreshThresholdSeconds: parent.config.refreshThresholdSeconds,
|
|
56
|
+
refreshTimeoutMs: parent.config.refreshTimeoutMs,
|
|
57
|
+
}));
|
|
58
|
+
await app.register(keyRoutes);
|
|
59
|
+
// Initialize plugins (creates pool, decorators, validated config)
|
|
60
|
+
await app.ready();
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
const message = formatErrorMessage(error);
|
|
64
|
+
console.error(`Error: ${message}`);
|
|
65
|
+
await app.close();
|
|
66
|
+
// eslint-disable-next-line unicorn/no-process-exit -- CLI config/startup error
|
|
36
67
|
process.exit(1);
|
|
37
68
|
}
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
mkdirSync(dataDirectory, { recursive: true });
|
|
43
|
-
if (verbose)
|
|
44
|
-
console.error(`Created data directory: ${dataDirectory}`);
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
48
|
-
console.error(`Failed to create data directory '${dataDirectory}': ${message}`);
|
|
49
|
-
// eslint-disable-next-line unicorn/no-process-exit -- CLI startup failure
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
69
|
+
// Run migrations using the pool created by @fastify/postgres
|
|
70
|
+
try {
|
|
71
|
+
await runMigrations(app.pg.pool, migrationsDirectory);
|
|
52
72
|
}
|
|
53
|
-
|
|
54
|
-
|
|
73
|
+
catch (error) {
|
|
74
|
+
const message = formatErrorMessage(error);
|
|
75
|
+
app.log.error(`Failed to initialize database: ${message}`);
|
|
76
|
+
await app.close();
|
|
77
|
+
// eslint-disable-next-line unicorn/no-process-exit -- CLI startup failure
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
// Create bootstrap admin key on first startup (no keys exist)
|
|
55
81
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
82
|
+
const bootstrapKey = await bootstrapApiKey(app.pg);
|
|
83
|
+
if (bootstrapKey) {
|
|
84
|
+
app.log.info({ keyId: bootstrapKey.id }, "Created bootstrap admin API key — save this secret, it cannot be retrieved later:");
|
|
85
|
+
// Print the secret to stderr so it's visible but not mixed with structured logs
|
|
86
|
+
console.error(`\n ${bootstrapKey.key}\n`);
|
|
87
|
+
}
|
|
58
88
|
}
|
|
59
89
|
catch (error) {
|
|
60
|
-
const message =
|
|
61
|
-
|
|
62
|
-
|
|
90
|
+
const message = formatErrorMessage(error);
|
|
91
|
+
app.log.error(`Failed to create bootstrap key: ${message}`);
|
|
92
|
+
await app.close();
|
|
63
93
|
// eslint-disable-next-line unicorn/no-process-exit -- CLI startup failure
|
|
64
94
|
process.exit(1);
|
|
65
95
|
}
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
refreshThresholdSeconds: config.refreshThresholdSeconds,
|
|
71
|
-
refreshTimeoutMs: config.refreshTimeoutMs,
|
|
72
|
-
}),
|
|
73
|
-
createKeyPlugin(database),
|
|
74
|
-
]);
|
|
75
|
-
// Graceful shutdown with close-with-grace.
|
|
76
|
-
// The composition root owns both the server and the database, so it is
|
|
77
|
-
// responsible for closing both in the correct order.
|
|
78
|
-
closeWithGrace({
|
|
79
|
-
delay: 5000,
|
|
80
|
-
logger: false,
|
|
81
|
-
}, async ({ signal, err }) => {
|
|
82
|
-
try {
|
|
83
|
-
if (err) {
|
|
84
|
-
server.app.log.error({ err, signal }, "Shutting down due to error");
|
|
85
|
-
}
|
|
86
|
-
else if (verbose) {
|
|
87
|
-
server.app.log.info({ signal }, "Shutting down...");
|
|
88
|
-
}
|
|
96
|
+
// Graceful shutdown
|
|
97
|
+
closeWithGrace({ delay: 5000, logger: false }, async ({ signal, err }) => {
|
|
98
|
+
if (err) {
|
|
99
|
+
app.log.error({ err, signal }, "Shutting down due to error");
|
|
89
100
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (err) {
|
|
93
|
-
console.error("Shutting down due to error:", err);
|
|
94
|
-
}
|
|
95
|
-
else if (verbose) {
|
|
96
|
-
console.error(`Shutting down (signal: ${signal})...`);
|
|
97
|
-
}
|
|
101
|
+
else if (options.verbose) {
|
|
102
|
+
app.log.info({ signal }, "Shutting down...");
|
|
98
103
|
}
|
|
99
|
-
await
|
|
100
|
-
closeDatabase();
|
|
104
|
+
await app.close();
|
|
101
105
|
});
|
|
106
|
+
// Start listening
|
|
102
107
|
try {
|
|
103
|
-
await
|
|
108
|
+
const address = await app.listen({
|
|
109
|
+
port: app.config.port,
|
|
110
|
+
host: app.config.host,
|
|
111
|
+
});
|
|
112
|
+
app.log.info({ address }, "axvault listening");
|
|
104
113
|
}
|
|
105
114
|
catch (error) {
|
|
106
|
-
const message =
|
|
107
|
-
console.error(`Failed to start server on http://${config.host}:${config.port}:`, message);
|
|
108
|
-
|
|
115
|
+
const message = formatErrorMessage(error);
|
|
116
|
+
console.error(`Failed to start server on http://${app.config.host}:${app.config.port}:`, message);
|
|
117
|
+
await app.close();
|
|
109
118
|
// eslint-disable-next-line unicorn/no-process-exit -- CLI startup failure
|
|
110
119
|
process.exit(1);
|
|
111
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,25 +1,76 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Server configuration schema and helpers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Runtime configuration is validated by @fastify/env and exposed as
|
|
5
|
+
* `fastify.config`. Logger level is resolved separately because the logger is
|
|
6
|
+
* configured before plugins are registered.
|
|
5
7
|
*/
|
|
6
|
-
|
|
8
|
+
declare module "fastify" {
|
|
9
|
+
interface FastifyInstance {
|
|
10
|
+
config: ServerConfig;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent";
|
|
14
|
+
interface ServerConfig {
|
|
7
15
|
port: number;
|
|
8
16
|
host: string;
|
|
9
|
-
|
|
17
|
+
databaseUrl: string;
|
|
10
18
|
refreshThresholdSeconds: number;
|
|
11
19
|
refreshTimeoutMs: number;
|
|
12
|
-
logLevel:
|
|
20
|
+
logLevel: LogLevel;
|
|
21
|
+
encryptionKey: string;
|
|
13
22
|
}
|
|
14
23
|
interface ConfigOverrides {
|
|
15
24
|
port?: string;
|
|
16
25
|
host?: string;
|
|
17
|
-
|
|
26
|
+
databaseUrl?: string;
|
|
18
27
|
refreshThresholdSeconds?: string;
|
|
19
28
|
refreshTimeoutMs?: string;
|
|
20
29
|
logLevel?: string;
|
|
30
|
+
encryptionKey?: string;
|
|
31
|
+
}
|
|
32
|
+
interface BuildAppConfig {
|
|
33
|
+
logLevel: LogLevel;
|
|
21
34
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
35
|
+
declare const serverConfigSchema: {
|
|
36
|
+
readonly type: "object";
|
|
37
|
+
readonly required: readonly ["encryptionKey"];
|
|
38
|
+
readonly properties: {
|
|
39
|
+
readonly port: {
|
|
40
|
+
readonly type: "number";
|
|
41
|
+
readonly default: 3847;
|
|
42
|
+
};
|
|
43
|
+
readonly host: {
|
|
44
|
+
readonly type: "string";
|
|
45
|
+
readonly default: "127.0.0.1";
|
|
46
|
+
};
|
|
47
|
+
readonly databaseUrl: {
|
|
48
|
+
readonly type: "string";
|
|
49
|
+
readonly default: "postgresql://localhost:5432/axvault";
|
|
50
|
+
};
|
|
51
|
+
readonly refreshThresholdSeconds: {
|
|
52
|
+
readonly type: "number";
|
|
53
|
+
readonly minimum: 0;
|
|
54
|
+
readonly default: 3600;
|
|
55
|
+
};
|
|
56
|
+
readonly refreshTimeoutMs: {
|
|
57
|
+
readonly type: "number";
|
|
58
|
+
readonly minimum: 0;
|
|
59
|
+
readonly default: 30000;
|
|
60
|
+
};
|
|
61
|
+
readonly logLevel: {
|
|
62
|
+
readonly type: "string";
|
|
63
|
+
readonly enum: readonly ["trace", "debug", "info", "warn", "error", "fatal", "silent"];
|
|
64
|
+
readonly default: "info";
|
|
65
|
+
};
|
|
66
|
+
readonly encryptionKey: {
|
|
67
|
+
readonly type: "string";
|
|
68
|
+
readonly minLength: 32;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
declare function createConfigData(overrides?: ConfigOverrides): Record<string, unknown>;
|
|
73
|
+
declare function resolveBuildAppConfig(overrides?: Pick<ConfigOverrides, "logLevel">): BuildAppConfig;
|
|
74
|
+
export { createConfigData, resolveBuildAppConfig, serverConfigSchema };
|
|
75
|
+
export type { BuildAppConfig, ConfigOverrides, ServerConfig };
|
|
25
76
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QACvB,MAAM,EAAE,YAAY,CAAC;KACtB;CACF;AAED,KAAK,QAAQ,GACT,OAAO,GACP,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,GACP,OAAO,GACP,QAAQ,CAAC;AAEb,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,uBAAuB,EAAE,MAAM,CAAC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,eAAe;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,cAAc;IACtB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAuBD,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Bd,CAAC;AAEX,iBAAS,gBAAgB,CACvB,SAAS,GAAE,eAAoB,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczB;AAED,iBAAS,qBAAqB,CAC5B,SAAS,GAAE,IAAI,CAAC,eAAe,EAAE,UAAU,CAAM,GAChD,cAAc,CAahB;AAED,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,CAAC;AACvE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Server configuration schema and helpers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Runtime configuration is validated by @fastify/env and exposed as
|
|
5
|
+
* `fastify.config`. Logger level is resolved separately because the logger is
|
|
6
|
+
* configured before plugins are registered.
|
|
5
7
|
*/
|
|
6
8
|
const DEFAULT_PORT = 3847;
|
|
7
9
|
const DEFAULT_HOST = "127.0.0.1";
|
|
8
|
-
const
|
|
10
|
+
const DEFAULT_DATABASE_URL = "postgresql://localhost:5432/axvault";
|
|
9
11
|
const DEFAULT_REFRESH_THRESHOLD_SECONDS = 3600; // 1 hour
|
|
10
12
|
const DEFAULT_REFRESH_TIMEOUT_MS = 30_000; // 30 seconds
|
|
11
13
|
const DEFAULT_LOG_LEVEL = "info";
|
|
@@ -18,43 +20,58 @@ const VALID_LOG_LEVELS = [
|
|
|
18
20
|
"fatal",
|
|
19
21
|
"silent",
|
|
20
22
|
];
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
function isLogLevel(value) {
|
|
24
|
+
return VALID_LOG_LEVELS.includes(value);
|
|
25
|
+
}
|
|
26
|
+
const serverConfigSchema = {
|
|
27
|
+
type: "object",
|
|
28
|
+
required: ["encryptionKey"],
|
|
29
|
+
properties: {
|
|
30
|
+
port: { type: "number", default: DEFAULT_PORT },
|
|
31
|
+
host: { type: "string", default: DEFAULT_HOST },
|
|
32
|
+
databaseUrl: { type: "string", default: DEFAULT_DATABASE_URL },
|
|
33
|
+
refreshThresholdSeconds: {
|
|
34
|
+
type: "number",
|
|
35
|
+
minimum: 0,
|
|
36
|
+
default: DEFAULT_REFRESH_THRESHOLD_SECONDS,
|
|
37
|
+
},
|
|
38
|
+
refreshTimeoutMs: {
|
|
39
|
+
type: "number",
|
|
40
|
+
minimum: 0,
|
|
41
|
+
default: DEFAULT_REFRESH_TIMEOUT_MS,
|
|
42
|
+
},
|
|
43
|
+
logLevel: {
|
|
44
|
+
type: "string",
|
|
45
|
+
enum: [...VALID_LOG_LEVELS],
|
|
46
|
+
default: DEFAULT_LOG_LEVEL,
|
|
47
|
+
},
|
|
48
|
+
encryptionKey: {
|
|
49
|
+
type: "string",
|
|
50
|
+
minLength: 32,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
function createConfigData(overrides = {}) {
|
|
55
|
+
return {
|
|
56
|
+
port: overrides.port ?? process.env.AXVAULT_PORT,
|
|
57
|
+
host: overrides.host ?? process.env.AXVAULT_HOST,
|
|
58
|
+
databaseUrl: overrides.databaseUrl ?? process.env.AXVAULT_DATABASE_URL,
|
|
59
|
+
refreshThresholdSeconds: overrides.refreshThresholdSeconds ??
|
|
60
|
+
process.env.AXVAULT_REFRESH_THRESHOLD,
|
|
61
|
+
refreshTimeoutMs: overrides.refreshTimeoutMs ?? process.env.AXVAULT_REFRESH_TIMEOUT_MS,
|
|
62
|
+
logLevel: overrides.logLevel ?? process.env.AXVAULT_LOG_LEVEL,
|
|
63
|
+
encryptionKey: overrides.encryptionKey ?? process.env.AXVAULT_ENCRYPTION_KEY,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function resolveBuildAppConfig(overrides = {}) {
|
|
67
|
+
const rawLogLevel = overrides.logLevel ?? process.env.AXVAULT_LOG_LEVEL;
|
|
68
|
+
const logLevel = rawLogLevel ?? DEFAULT_LOG_LEVEL;
|
|
69
|
+
if (!isLogLevel(logLevel)) {
|
|
30
70
|
throw new Error(`Invalid log level: "${logLevel}". Must be one of: ${VALID_LOG_LEVELS.join(", ")}`);
|
|
31
71
|
}
|
|
32
72
|
return {
|
|
33
|
-
port,
|
|
34
|
-
host,
|
|
35
|
-
databasePath,
|
|
36
|
-
refreshThresholdSeconds,
|
|
37
|
-
refreshTimeoutMs,
|
|
38
73
|
logLevel,
|
|
39
74
|
};
|
|
40
75
|
}
|
|
41
|
-
|
|
42
|
-
if (!value)
|
|
43
|
-
return DEFAULT_PORT;
|
|
44
|
-
const port = Number.parseInt(value, 10);
|
|
45
|
-
if (Number.isNaN(port) || port < 1 || port > 65_535) {
|
|
46
|
-
throw new Error(`Invalid port: ${value}`);
|
|
47
|
-
}
|
|
48
|
-
return port;
|
|
49
|
-
}
|
|
50
|
-
function parseNonNegativeInt(value, defaultValue, name) {
|
|
51
|
-
if (!value)
|
|
52
|
-
return defaultValue;
|
|
53
|
-
const parsed = Number.parseInt(value, 10);
|
|
54
|
-
if (Number.isNaN(parsed) || parsed < 0) {
|
|
55
|
-
console.warn(`Invalid ${name} value "${value}", using default ${defaultValue}`);
|
|
56
|
-
return defaultValue;
|
|
57
|
-
}
|
|
58
|
-
return parsed;
|
|
59
|
-
}
|
|
76
|
+
export { createConfigData, resolveBuildAppConfig, serverConfigSchema };
|
|
60
77
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyCH,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,MAAM,oBAAoB,GAAG,qCAAqC,CAAC;AACnE,MAAM,iCAAiC,GAAG,IAAI,CAAC,CAAC,SAAS;AACzD,MAAM,0BAA0B,GAAG,MAAM,CAAC,CAAC,aAAa;AACxD,MAAM,iBAAiB,GAAa,MAAM,CAAC;AAE3C,MAAM,gBAAgB,GAAG;IACvB,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,QAAQ;CACA,CAAC;AAEX,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAQ,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,kBAAkB,GAAG;IACzB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,eAAe,CAAC;IAC3B,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;QAC/C,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;QAC/C,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,oBAAoB,EAAE;QAC9D,uBAAuB,EAAE;YACvB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,iCAAiC;SAC3C;QACD,gBAAgB,EAAE;YAChB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,0BAA0B;SACpC;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,GAAG,gBAAgB,CAAC;YAC3B,OAAO,EAAE,iBAAiB;SAC3B;QACD,aAAa,EAAE;YACb,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,EAAE;SACd;KACF;CACO,CAAC;AAEX,SAAS,gBAAgB,CACvB,YAA6B,EAAE;IAE/B,OAAO;QACL,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;QAChD,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;QAChD,WAAW,EAAE,SAAS,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtE,uBAAuB,EACrB,SAAS,CAAC,uBAAuB;YACjC,OAAO,CAAC,GAAG,CAAC,yBAAyB;QACvC,gBAAgB,EACd,SAAS,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,0BAA0B;QACtE,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC7D,aAAa,EACX,SAAS,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB;KAChE,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAC5B,YAA+C,EAAE;IAEjD,MAAM,WAAW,GAAG,SAAS,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACxE,MAAM,QAAQ,GAAG,WAAW,IAAI,iBAAiB,CAAC;IAElD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,uBAAuB,QAAQ,sBAAsB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACnF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap API key creation for first server startup.
|
|
3
|
+
*
|
|
4
|
+
* Serializes the bootstrap check inside a transaction-scoped advisory lock so
|
|
5
|
+
* concurrent first-time startups cannot mint multiple root keys.
|
|
6
|
+
*/
|
|
7
|
+
import type { PoolClient } from "pg";
|
|
8
|
+
import { type ApiKeyWithSecret } from "./repositories/api-keys.js";
|
|
9
|
+
interface TransactionalDatabase {
|
|
10
|
+
transact<TResult>(runInTransaction: (client: PoolClient) => Promise<TResult>): Promise<TResult>;
|
|
11
|
+
}
|
|
12
|
+
declare function bootstrapApiKey(database: TransactionalDatabase): Promise<ApiKeyWithSecret | undefined>;
|
|
13
|
+
export { bootstrapApiKey };
|
|
14
|
+
//# sourceMappingURL=bootstrap-api-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap-api-key.d.ts","sourceRoot":"","sources":["../../src/db/bootstrap-api-key.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,4BAA4B,CAAC;AAIpC,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,OAAO,EACd,gBAAgB,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,GACzD,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED,iBAAe,eAAe,CAC5B,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAmBvC;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap API key creation for first server startup.
|
|
3
|
+
*
|
|
4
|
+
* Serializes the bootstrap check inside a transaction-scoped advisory lock so
|
|
5
|
+
* concurrent first-time startups cannot mint multiple root keys.
|
|
6
|
+
*/
|
|
7
|
+
import { createApiKey, } from "./repositories/api-keys.js";
|
|
8
|
+
const BOOTSTRAP_API_KEY_LOCK_ID = 980_641_073;
|
|
9
|
+
async function bootstrapApiKey(database) {
|
|
10
|
+
return database.transact(async (client) => {
|
|
11
|
+
await client.query("SELECT pg_advisory_xact_lock($1)", [
|
|
12
|
+
BOOTSTRAP_API_KEY_LOCK_ID,
|
|
13
|
+
]);
|
|
14
|
+
const result = await client.query("SELECT EXISTS (SELECT 1 FROM api_keys) AS has_api_keys");
|
|
15
|
+
if (result.rows[0]?.has_api_keys)
|
|
16
|
+
return;
|
|
17
|
+
return createApiKey(client, {
|
|
18
|
+
name: "Bootstrap Admin",
|
|
19
|
+
readAccess: ["*"],
|
|
20
|
+
writeAccess: ["*"],
|
|
21
|
+
grantAccess: ["*"],
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export { bootstrapApiKey };
|
|
26
|
+
//# sourceMappingURL=bootstrap-api-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap-api-key.js","sourceRoot":"","sources":["../../src/db/bootstrap-api-key.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,YAAY,GAEb,MAAM,4BAA4B,CAAC;AAEpC,MAAM,yBAAyB,GAAG,WAAW,CAAC;AAQ9C,KAAK,UAAU,eAAe,CAC5B,QAA+B;IAE/B,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,MAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE;YACrD,yBAAyB;SAC1B,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B,wDAAwD,CACzD,CAAC;QAEF,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY;YAAE,OAAO;QAEzC,OAAO,YAAY,CAAC,MAAM,EAAE;YAC1B,IAAI,EAAE,iBAAiB;YACvB,UAAU,EAAE,CAAC,GAAG,CAAC;YACjB,WAAW,EAAE,CAAC,GAAG,CAAC;YAClB,WAAW,EAAE,CAAC,GAAG,CAAC;SACnB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-pool.d.ts","sourceRoot":"","sources":["../../src/db/create-pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAOpB,iBAAS,UAAU,CAAC,gBAAgB,EAAE,MAAM,GAAG,EAAE,CAAC,IAAI,CAErD;AAED,iBAAe,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import pg from "pg";
|
|
2
|
+
// Parse BIGINT (OID 20) as JavaScript numbers instead of strings.
|
|
3
|
+
// Safe for timestamps and auto-increment IDs within Number.MAX_SAFE_INTEGER.
|
|
4
|
+
// Global mutation: pg.types is shared across all Pool instances in this process.
|
|
5
|
+
pg.types.setTypeParser(20, (value) => Number.parseInt(value, 10));
|
|
6
|
+
function createPool(connectionString) {
|
|
7
|
+
return new pg.Pool({ connectionString });
|
|
8
|
+
}
|
|
9
|
+
async function closePool(pool) {
|
|
10
|
+
await pool.end();
|
|
11
|
+
}
|
|
12
|
+
export { closePool, createPool };
|
|
13
|
+
//# sourceMappingURL=create-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-pool.js","sourceRoot":"","sources":["../../src/db/create-pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,kEAAkE;AAClE,6EAA6E;AAC7E,iFAAiF;AACjF,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;AAElE,SAAS,UAAU,CAAC,gBAAwB;IAC1C,OAAO,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAa;IACpC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;AACnB,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- Initial schema for axvault.
|
|
2
|
+
|
|
3
|
+
CREATE TABLE IF NOT EXISTS api_keys (
|
|
4
|
+
id TEXT PRIMARY KEY,
|
|
5
|
+
name TEXT NOT NULL,
|
|
6
|
+
key_hash TEXT NOT NULL UNIQUE,
|
|
7
|
+
key_prefix TEXT,
|
|
8
|
+
read_access TEXT NOT NULL,
|
|
9
|
+
write_access TEXT NOT NULL,
|
|
10
|
+
grant_access TEXT NOT NULL DEFAULT '[]',
|
|
11
|
+
created_at BIGINT NOT NULL,
|
|
12
|
+
last_used_at BIGINT
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE TABLE IF NOT EXISTS credentials (
|
|
16
|
+
name TEXT PRIMARY KEY,
|
|
17
|
+
agent TEXT NOT NULL DEFAULT '',
|
|
18
|
+
provider TEXT DEFAULT NULL,
|
|
19
|
+
display_name TEXT DEFAULT NULL,
|
|
20
|
+
notes TEXT DEFAULT NULL,
|
|
21
|
+
encrypted_data BYTEA NOT NULL,
|
|
22
|
+
salt BYTEA NOT NULL,
|
|
23
|
+
iv BYTEA NOT NULL,
|
|
24
|
+
auth_tag BYTEA NOT NULL,
|
|
25
|
+
created_at BIGINT NOT NULL,
|
|
26
|
+
updated_at BIGINT NOT NULL
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE TABLE IF NOT EXISTS audit_log (
|
|
30
|
+
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
31
|
+
timestamp BIGINT NOT NULL,
|
|
32
|
+
api_key_id TEXT,
|
|
33
|
+
action TEXT NOT NULL,
|
|
34
|
+
credential_name TEXT,
|
|
35
|
+
success BOOLEAN NOT NULL,
|
|
36
|
+
error_message TEXT
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
ALTER TABLE audit_log ADD COLUMN IF NOT EXISTS detail TEXT;
|
|
40
|
+
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_audit_log_timestamp ON audit_log(timestamp DESC);
|
|
@@ -3,47 +3,21 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Manages API keys with read/write access lists for credentials.
|
|
5
5
|
*/
|
|
6
|
-
import type
|
|
7
|
-
|
|
8
|
-
interface ApiKeyRecord {
|
|
9
|
-
id: string;
|
|
10
|
-
name: string;
|
|
11
|
-
keyHash: string;
|
|
12
|
-
keyPrefix: string | undefined;
|
|
13
|
-
readAccess: string[];
|
|
14
|
-
writeAccess: string[];
|
|
15
|
-
grantAccess: string[];
|
|
16
|
-
createdAt: Date;
|
|
17
|
-
lastUsedAt: Date | undefined;
|
|
18
|
-
}
|
|
19
|
-
/** API key with the raw key (only returned on creation) */
|
|
20
|
-
interface ApiKeyWithSecret extends ApiKeyRecord {
|
|
21
|
-
key: string;
|
|
22
|
-
}
|
|
23
|
-
/** Create a new API key */
|
|
24
|
-
declare function createApiKey(database: Database.Database, options: {
|
|
25
|
-
name: string;
|
|
26
|
-
readAccess: string[];
|
|
27
|
-
writeAccess: string[];
|
|
28
|
-
grantAccess: string[];
|
|
29
|
-
}): ApiKeyWithSecret;
|
|
6
|
+
import type { Queryable } from "../types.js";
|
|
7
|
+
import type { ApiKeyRecord } from "./create-api-key.js";
|
|
30
8
|
/** Find API key by raw key value */
|
|
31
|
-
declare function findApiKeyByKey(database:
|
|
9
|
+
declare function findApiKeyByKey(database: Queryable, key: string): Promise<ApiKeyRecord | undefined>;
|
|
32
10
|
/** Find API key by ID */
|
|
33
|
-
declare function findApiKeyById(database:
|
|
11
|
+
declare function findApiKeyById(database: Queryable, id: string): Promise<ApiKeyRecord | undefined>;
|
|
34
12
|
/** List all API keys (without revealing the raw key values) */
|
|
35
|
-
declare function listApiKeys(database:
|
|
13
|
+
declare function listApiKeys(database: Queryable): Promise<ApiKeyRecord[]>;
|
|
36
14
|
/** Update last used timestamp */
|
|
37
|
-
declare function updateLastUsed(database:
|
|
15
|
+
declare function updateLastUsed(database: Queryable, id: string): Promise<void>;
|
|
38
16
|
/** Delete an API key */
|
|
39
|
-
declare function deleteApiKey(database:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
readAccess?: string[];
|
|
43
|
-
writeAccess?: string[];
|
|
44
|
-
grantAccess?: string[];
|
|
45
|
-
}): boolean;
|
|
46
|
-
export { createApiKey, deleteApiKey, findApiKeyById, findApiKeyByKey, listApiKeys, updateApiKeyAccess, updateLastUsed, };
|
|
17
|
+
declare function deleteApiKey(database: Queryable, id: string): Promise<boolean>;
|
|
18
|
+
export { deleteApiKey, findApiKeyById, findApiKeyByKey, listApiKeys, updateLastUsed, };
|
|
19
|
+
export { createApiKey } from "./create-api-key.js";
|
|
47
20
|
export { hasGrantAccess, hasReadAccess, hasWriteAccess, } from "./api-key-utilities.js";
|
|
48
|
-
export
|
|
21
|
+
export { updateApiKeyAccess } from "./update-api-key-access.js";
|
|
22
|
+
export type { ApiKeyRecord, ApiKeyWithSecret } from "./create-api-key.js";
|
|
49
23
|
//# sourceMappingURL=api-keys.d.ts.map
|