axvault 1.13.1 → 1.14.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 +107 -14
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +21 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +88 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/serve.d.ts +1 -2
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +13 -20
- package/dist/commands/serve.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/db/bootstrap-api-key.d.ts +4 -4
- package/dist/db/bootstrap-api-key.d.ts.map +1 -1
- package/dist/db/bootstrap-api-key.js +39 -6
- package/dist/db/bootstrap-api-key.js.map +1 -1
- package/dist/db/repositories/api-key-utilities.d.ts +3 -3
- package/dist/db/repositories/api-key-utilities.d.ts.map +1 -1
- package/dist/db/repositories/api-key-utilities.js +12 -1
- package/dist/db/repositories/api-key-utilities.js.map +1 -1
- package/dist/db/repositories/api-keys.d.ts +4 -2
- package/dist/db/repositories/api-keys.d.ts.map +1 -1
- package/dist/db/repositories/api-keys.js +7 -2
- package/dist/db/repositories/api-keys.js.map +1 -1
- package/dist/db/repositories/create-api-key.d.ts +1 -0
- package/dist/db/repositories/create-api-key.d.ts.map +1 -1
- package/dist/db/repositories/create-api-key.js +2 -2
- package/dist/db/repositories/create-api-key.js.map +1 -1
- package/dist/db/verify-database-initialization.d.ts +4 -0
- package/dist/db/verify-database-initialization.d.ts.map +1 -0
- package/dist/db/verify-database-initialization.js +66 -0
- package/dist/db/verify-database-initialization.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/resolve-database-url.d.ts +4 -0
- package/dist/resolve-database-url.d.ts.map +1 -0
- package/dist/resolve-database-url.js +11 -0
- package/dist/resolve-database-url.js.map +1 -0
- package/dist/resolve-secret-source.d.ts +11 -0
- package/dist/resolve-secret-source.d.ts.map +1 -0
- package/dist/resolve-secret-source.js +36 -0
- package/dist/resolve-secret-source.js.map +1 -0
- package/dist/server/plugins/auth.d.ts.map +1 -1
- package/dist/server/plugins/auth.js +1 -3
- package/dist/server/plugins/auth.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Remote credential storage server for a╳kit.
|
|
4
4
|
|
|
5
|
+
Uses the standard a╳kit stateful server lifecycle: `init` for migrations and
|
|
6
|
+
admin bootstrap, `serve` for the long-running server.
|
|
7
|
+
|
|
5
8
|
## Prerequisites
|
|
6
9
|
|
|
7
10
|
- Node.js 22.19+
|
|
@@ -29,26 +32,39 @@ set -a
|
|
|
29
32
|
. ./.env
|
|
30
33
|
set +a
|
|
31
34
|
|
|
32
|
-
#
|
|
35
|
+
# Initialize database and create the first admin key
|
|
36
|
+
npx -y axvault init --create-admin-key
|
|
37
|
+
|
|
38
|
+
# Or, instead of generating one, provision a deterministic admin key for deployment
|
|
39
|
+
export AXVAULT_ADMIN_KEY='axv_sk_0123456789abcdef0123456789abcdef'
|
|
40
|
+
npx -y axvault init --create-admin-key \
|
|
41
|
+
--admin-key-env AXVAULT_ADMIN_KEY
|
|
42
|
+
|
|
43
|
+
# Start server
|
|
33
44
|
npx -y axvault serve
|
|
34
45
|
```
|
|
35
46
|
|
|
36
|
-
|
|
47
|
+
Generated and provisioned admin keys use the same format: `axv_sk_` followed by
|
|
48
|
+
32 lowercase hexadecimal characters.
|
|
37
49
|
|
|
38
50
|
Keep the `.env` file and reuse the same encryption key between restarts to avoid losing access to existing credentials.
|
|
39
51
|
|
|
40
52
|
## Architecture
|
|
41
53
|
|
|
42
|
-
axvault is a server-only tool
|
|
54
|
+
axvault is a server-only tool with an explicit `init` / `serve` lifecycle.
|
|
55
|
+
Initialization and long-running serving are separate operations.
|
|
43
56
|
|
|
44
|
-
|
|
57
|
+
The CLI provides:
|
|
45
58
|
|
|
46
|
-
1.
|
|
47
|
-
2.
|
|
48
|
-
|
|
59
|
+
1. `axvault init` for database migrations and first admin key bootstrap
|
|
60
|
+
2. `axvault serve` for starting the HTTP server
|
|
61
|
+
|
|
62
|
+
`axvault init --create-admin-key` is idempotent with respect to bootstrap: it
|
|
63
|
+
uses an advisory lock and creates the first bootstrap-capable key only when no
|
|
64
|
+
existing key has `grantAccess: ["*"]`.
|
|
49
65
|
|
|
50
66
|
Migration files must remain replay-safe because axvault re-runs them on every
|
|
51
|
-
|
|
67
|
+
`init` instead of tracking applied versions. Use guarded SQL such as
|
|
52
68
|
`CREATE ... IF NOT EXISTS` or `ALTER ... ADD COLUMN IF NOT EXISTS`. If a future
|
|
53
69
|
schema change cannot be written safely that way, switch back to tracked
|
|
54
70
|
migrations rather than adding a one-shot file to this runner.
|
|
@@ -62,9 +78,9 @@ Add to your `CLAUDE.md` or `AGENTS.md`:
|
|
|
62
78
|
|
|
63
79
|
Run `npx -y axvault --help` to learn available options.
|
|
64
80
|
|
|
65
|
-
Use `axvault
|
|
66
|
-
|
|
67
|
-
|
|
81
|
+
Use `axvault init` for migrations and admin bootstrap, then `axvault serve` to
|
|
82
|
+
start the credential vault server. Ongoing key and credential management is done
|
|
83
|
+
via the HTTP API.
|
|
68
84
|
```
|
|
69
85
|
|
|
70
86
|
## Configuration
|
|
@@ -83,9 +99,14 @@ is created and printed to stderr.
|
|
|
83
99
|
|
|
84
100
|
### CLI Flags
|
|
85
101
|
|
|
86
|
-
The `serve`
|
|
102
|
+
The `init` and `serve` commands accept `--database-url`. The `serve` command
|
|
103
|
+
also accepts runtime flags that override environment variables:
|
|
87
104
|
|
|
88
105
|
```bash
|
|
106
|
+
npx -y axvault init \
|
|
107
|
+
--database-url postgresql://localhost:5432/axvault \
|
|
108
|
+
--create-admin-key
|
|
109
|
+
|
|
89
110
|
npx -y axvault serve \
|
|
90
111
|
--port 8080 \
|
|
91
112
|
--host 0.0.0.0 \
|
|
@@ -107,7 +128,13 @@ API keys control access to the credential API. Each key has configurable permiss
|
|
|
107
128
|
|
|
108
129
|
### Bootstrap Key
|
|
109
130
|
|
|
110
|
-
|
|
131
|
+
`axvault init --create-admin-key` creates a "Bootstrap Admin" key with full
|
|
132
|
+
access (`*` for read, write, and grant) only when no full-admin key exists yet.
|
|
133
|
+
Omit `--admin-key`, `--admin-key-env`, and `--admin-key-file` to generate a
|
|
134
|
+
one-time secret. For production, prefer `--admin-key-env` or
|
|
135
|
+
`--admin-key-file` over raw `--admin-key`: command-line arguments are visible
|
|
136
|
+
in process listings. Generated secrets are printed once to stdout; provided
|
|
137
|
+
secrets are used without being echoed back.
|
|
111
138
|
|
|
112
139
|
### Managing Keys via API
|
|
113
140
|
|
|
@@ -183,19 +210,84 @@ podman run -d \
|
|
|
183
210
|
|
|
184
211
|
**Note:** `AXVAULT_DATABASE_URL` must point to an accessible PostgreSQL instance. The Containerfile default (`postgresql://localhost:5432/axvault`) refers to the container itself, so standalone `docker run` users must provide this variable. For a batteries-included setup, use `docker-compose.yml` which includes a PostgreSQL service.
|
|
185
212
|
|
|
186
|
-
|
|
213
|
+
Initialize the database and first admin key with a one-shot container before
|
|
214
|
+
starting the long-running service:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# Docker
|
|
218
|
+
docker run --rm \
|
|
219
|
+
-u 1000:1000 \
|
|
220
|
+
-e AXVAULT_ENCRYPTION_KEY="your-secret-key-minimum-32-chars!" \
|
|
221
|
+
-e AXVAULT_DATABASE_URL="postgresql://user:pass@db-host:5432/axvault" \
|
|
222
|
+
registry.j4k.dev/axvault:latest init --create-admin-key
|
|
223
|
+
|
|
224
|
+
# Podman
|
|
225
|
+
podman run --rm \
|
|
226
|
+
--user 1000:1000 \
|
|
227
|
+
-e AXVAULT_ENCRYPTION_KEY="your-secret-key-minimum-32-chars!" \
|
|
228
|
+
-e AXVAULT_DATABASE_URL="postgresql://user:pass@db-host:5432/axvault" \
|
|
229
|
+
registry.j4k.dev/axvault:latest init --create-admin-key
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
When using `docker-compose.yml` or `podman-compose`, initialize against the
|
|
233
|
+
bundled PostgreSQL service, then start the long-running server:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Docker Compose
|
|
237
|
+
docker compose up -d db
|
|
238
|
+
docker compose run --rm axvault init --create-admin-key
|
|
239
|
+
docker compose up -d axvault
|
|
240
|
+
|
|
241
|
+
# Podman Compose
|
|
242
|
+
podman-compose up -d db
|
|
243
|
+
podman-compose run --rm axvault init --create-admin-key
|
|
244
|
+
podman-compose up -d axvault
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
For production, prefer provisioning a deterministic admin key rather than
|
|
248
|
+
capturing a one-time generated secret from logs:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
docker compose run --rm \
|
|
252
|
+
-e AXVAULT_ADMIN_KEY='axv_sk_0123456789abcdef0123456789abcdef' \
|
|
253
|
+
axvault init --create-admin-key \
|
|
254
|
+
--admin-key-env AXVAULT_ADMIN_KEY
|
|
255
|
+
```
|
|
187
256
|
|
|
188
257
|
#### Quadlet (systemd)
|
|
189
258
|
|
|
190
259
|
This example references `axvault-db.service`, which is a PostgreSQL container you must provide separately as a companion Quadlet (`axvault-db.container`). Alternatively, point `AXVAULT_DATABASE_URL` at an existing PostgreSQL instance and remove the `Requires`/`After` lines.
|
|
191
260
|
|
|
261
|
+
Create `/etc/containers/systemd/axvault-init.container`:
|
|
262
|
+
|
|
263
|
+
```ini
|
|
264
|
+
[Unit]
|
|
265
|
+
Description=axvault bootstrap initialization
|
|
266
|
+
Requires=axvault-db.service
|
|
267
|
+
After=axvault-db.service
|
|
268
|
+
|
|
269
|
+
[Container]
|
|
270
|
+
Image=registry.j4k.dev/axvault:latest
|
|
271
|
+
User=1000
|
|
272
|
+
Group=1000
|
|
273
|
+
Environment=AXVAULT_ENCRYPTION_KEY=your-secret-key-minimum-32-chars!
|
|
274
|
+
Environment=AXVAULT_DATABASE_URL=postgresql://axvault:axvault@axvault-db:5432/axvault
|
|
275
|
+
Exec=init --create-admin-key
|
|
276
|
+
|
|
277
|
+
[Service]
|
|
278
|
+
Type=oneshot
|
|
279
|
+
RemainAfterExit=yes
|
|
280
|
+
```
|
|
281
|
+
|
|
192
282
|
Create `/etc/containers/systemd/axvault.container`:
|
|
193
283
|
|
|
194
284
|
```ini
|
|
195
285
|
[Unit]
|
|
196
286
|
Description=axvault credential server
|
|
197
287
|
Requires=axvault-db.service
|
|
288
|
+
Requires=axvault-init.service
|
|
198
289
|
After=axvault-db.service
|
|
290
|
+
After=axvault-init.service
|
|
199
291
|
|
|
200
292
|
[Container]
|
|
201
293
|
Image=registry.j4k.dev/axvault:latest
|
|
@@ -216,6 +308,7 @@ Then reload and start:
|
|
|
216
308
|
|
|
217
309
|
```bash
|
|
218
310
|
sudo systemctl daemon-reload
|
|
311
|
+
sudo systemctl start axvault-init
|
|
219
312
|
sudo systemctl start axvault
|
|
220
313
|
```
|
|
221
314
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* axvault - Remote credential storage server for axkit.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* via the HTTP API once the server is running.
|
|
5
|
+
* Initializes and starts the vault server. Key and credential management is
|
|
6
|
+
* done via explicit bootstrap plus the HTTP API once the server is running.
|
|
7
7
|
*/
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* axvault - Remote credential storage server for axkit.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* via the HTTP API once the server is running.
|
|
5
|
+
* Initializes and starts the vault server. Key and credential management is
|
|
6
|
+
* done via explicit bootstrap plus the HTTP API once the server is running.
|
|
7
7
|
*/
|
|
8
8
|
import { Command } from "@commander-js/extra-typings";
|
|
9
9
|
import packageJson from "../package.json" with { type: "json" };
|
|
10
|
+
import { handleInit } from "./commands/init.js";
|
|
10
11
|
import { handleServe } from "./commands/serve.js";
|
|
11
12
|
const program = new Command()
|
|
12
13
|
.name(packageJson.name)
|
|
@@ -17,7 +18,14 @@ const program = new Command()
|
|
|
17
18
|
.helpCommand(false)
|
|
18
19
|
.addHelpText("after", String.raw `
|
|
19
20
|
Examples:
|
|
20
|
-
#
|
|
21
|
+
# Initialize database and create the first admin key
|
|
22
|
+
axvault init --create-admin-key
|
|
23
|
+
|
|
24
|
+
# Initialize database and provision a deterministic admin key from an env var
|
|
25
|
+
AXVAULT_ADMIN_KEY=axv_sk_0123456789abcdef0123456789abcdef \
|
|
26
|
+
axvault init --create-admin-key --admin-key-env AXVAULT_ADMIN_KEY
|
|
27
|
+
|
|
28
|
+
# Start server
|
|
21
29
|
axvault serve
|
|
22
30
|
|
|
23
31
|
# Start server on custom port
|
|
@@ -25,6 +33,16 @@ Examples:
|
|
|
25
33
|
|
|
26
34
|
# Start with debug logging
|
|
27
35
|
axvault serve --log-level debug`);
|
|
36
|
+
program
|
|
37
|
+
.command("init")
|
|
38
|
+
.description("Initialize database")
|
|
39
|
+
.option("--database-url <url>", "PostgreSQL connection URL")
|
|
40
|
+
.option("--create-admin-key", "Create an admin key with full access")
|
|
41
|
+
.option("--admin-key <key>", "Provision a specific admin API key (requires --create-admin-key; exposes the secret in the process list)")
|
|
42
|
+
.option("--admin-key-env <name>", "Read the admin API key from an environment variable (requires --create-admin-key)")
|
|
43
|
+
.option("--admin-key-file <path>", "Read the admin API key from a file (requires --create-admin-key)")
|
|
44
|
+
.option("-v, --verbose", "Enable verbose output")
|
|
45
|
+
.action(handleInit);
|
|
28
46
|
program
|
|
29
47
|
.command("serve")
|
|
30
48
|
.description("Start the vault server")
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEtD,OAAO,WAAW,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;KAC1B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;KACtB,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;KACpC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,eAAe,CAAC;KAC7C,kBAAkB,CAAC,yCAAyC,CAAC;KAC7D,wBAAwB,EAAE;KAC1B,WAAW,CAAC,KAAK,CAAC;KAClB,WAAW,CACV,OAAO,EACP,MAAM,CAAC,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEtD,OAAO,WAAW,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;KAC1B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;KACtB,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;KACpC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,eAAe,CAAC;KAC7C,kBAAkB,CAAC,yCAAyC,CAAC;KAC7D,wBAAwB,EAAE;KAC1B,WAAW,CAAC,KAAK,CAAC;KAClB,WAAW,CACV,OAAO,EACP,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;kCAgBoB,CAC/B,CAAC;AAEJ,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,qBAAqB,CAAC;KAClC,MAAM,CAAC,sBAAsB,EAAE,2BAA2B,CAAC;KAC3D,MAAM,CAAC,oBAAoB,EAAE,sCAAsC,CAAC;KACpE,MAAM,CACL,mBAAmB,EACnB,0GAA0G,CAC3G;KACA,MAAM,CACL,wBAAwB,EACxB,mFAAmF,CACpF;KACA,MAAM,CACL,yBAAyB,EACzB,kEAAkE,CACnE;KACA,MAAM,CAAC,eAAe,EAAE,uBAAuB,CAAC;KAChD,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,wBAAwB,CAAC;KACrC,MAAM,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;KAChD,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;KAC9C,MAAM,CAAC,sBAAsB,EAAE,2BAA2B,CAAC;KAC3D,MAAM,CACL,+BAA+B,EAC/B,sEAAsE,CACvE;KACA,MAAM,CACL,wBAAwB,EACxB,gDAAgD,CACjD;KACA,MAAM,CACL,qBAAqB,EACrB,4DAA4D,CAC7D;KACA,MAAM,CAAC,eAAe,EAAE,uBAAuB,CAAC;KAChD,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize database command handler.
|
|
3
|
+
*/
|
|
4
|
+
interface InitOptions {
|
|
5
|
+
databaseUrl?: string;
|
|
6
|
+
createAdminKey?: boolean;
|
|
7
|
+
adminKey?: string;
|
|
8
|
+
adminKeyEnv?: string;
|
|
9
|
+
adminKeyFile?: string;
|
|
10
|
+
verbose?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function handleInit(options: InitOptions): Promise<void>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,UAAU,WAAW;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAmFpE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize database command handler.
|
|
3
|
+
*/
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { formatErrorMessage } from "../format-error-message.js";
|
|
6
|
+
import { bootstrapApiKey } from "../db/bootstrap-api-key.js";
|
|
7
|
+
import { closePool, createPool } from "../db/create-pool.js";
|
|
8
|
+
import { resolveApiKeySecret } from "../db/repositories/api-keys.js";
|
|
9
|
+
import { runMigrations } from "../db/run-migrations.js";
|
|
10
|
+
import { resolveSecretSource } from "../resolve-secret-source.js";
|
|
11
|
+
import { resolveDatabaseUrl } from "../resolve-database-url.js";
|
|
12
|
+
const migrationsDirectory = fileURLToPath(new URL("../db/migrations", import.meta.url));
|
|
13
|
+
export async function handleInit(options) {
|
|
14
|
+
const verbose = options.verbose === true;
|
|
15
|
+
if ((options.adminKey || options.adminKeyEnv || options.adminKeyFile) &&
|
|
16
|
+
options.createAdminKey !== true) {
|
|
17
|
+
console.error("Invalid option: --admin-key, --admin-key-env, and --admin-key-file require --create-admin-key.");
|
|
18
|
+
process.exitCode = 2;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
let adminKey;
|
|
22
|
+
try {
|
|
23
|
+
adminKey = await resolveSecretSource({
|
|
24
|
+
directValue: options.adminKey,
|
|
25
|
+
envName: options.adminKeyEnv,
|
|
26
|
+
filePath: options.adminKeyFile,
|
|
27
|
+
directOption: "--admin-key",
|
|
28
|
+
envOption: "--admin-key-env",
|
|
29
|
+
fileOption: "--admin-key-file",
|
|
30
|
+
});
|
|
31
|
+
adminKey =
|
|
32
|
+
adminKey === undefined ? undefined : resolveApiKeySecret(adminKey);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const message = formatErrorMessage(error);
|
|
36
|
+
console.error(message);
|
|
37
|
+
process.exitCode = 1;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
let pool;
|
|
41
|
+
try {
|
|
42
|
+
const databaseUrl = resolveDatabaseUrl(options.databaseUrl);
|
|
43
|
+
const initializedPool = createPool(databaseUrl);
|
|
44
|
+
pool = initializedPool;
|
|
45
|
+
await runMigrations(initializedPool, migrationsDirectory);
|
|
46
|
+
if (verbose) {
|
|
47
|
+
try {
|
|
48
|
+
const sanitizedUrl = new URL(databaseUrl);
|
|
49
|
+
if (sanitizedUrl.password) {
|
|
50
|
+
sanitizedUrl.password = "***";
|
|
51
|
+
}
|
|
52
|
+
console.error(`Database initialized at: ${sanitizedUrl.toString()}`);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
console.error("Database initialized.");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (options.createAdminKey === true) {
|
|
59
|
+
const key = await bootstrapApiKey(initializedPool, {
|
|
60
|
+
key: adminKey,
|
|
61
|
+
});
|
|
62
|
+
if (!key) {
|
|
63
|
+
console.error("Admin API key already exists; bootstrap skipped.");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.error("");
|
|
67
|
+
console.error(`Created admin API key: ${key.name}`);
|
|
68
|
+
console.error(`ID: ${key.id}`);
|
|
69
|
+
console.error("");
|
|
70
|
+
if (adminKey === undefined) {
|
|
71
|
+
console.error("Save this key securely - it cannot be retrieved later.");
|
|
72
|
+
console.error("");
|
|
73
|
+
console.log(key.key);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const message = formatErrorMessage(error);
|
|
79
|
+
console.error(`Failed to initialize database: ${message}`);
|
|
80
|
+
process.exitCode = 1;
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
if (pool) {
|
|
84
|
+
await closePool(pool);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/serve.d.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* Start server command handler.
|
|
3
3
|
*
|
|
4
4
|
* Builds the Fastify app, registers plugins in dependency order
|
|
5
|
-
* (database → auth → routes),
|
|
6
|
-
* API key on first startup, and starts listening.
|
|
5
|
+
* (database → auth → routes), verifies initialization, and starts listening.
|
|
7
6
|
*/
|
|
8
7
|
interface ServeOptions {
|
|
9
8
|
port?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAyGtE"}
|
package/dist/commands/serve.js
CHANGED
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
* Start server command handler.
|
|
3
3
|
*
|
|
4
4
|
* Builds the Fastify app, registers plugins in dependency order
|
|
5
|
-
* (database → auth → routes),
|
|
6
|
-
* API key on first startup, and starts listening.
|
|
5
|
+
* (database → auth → routes), verifies initialization, and starts listening.
|
|
7
6
|
*/
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
7
|
import closeWithGrace from "close-with-grace";
|
|
10
8
|
import { formatErrorMessage } from "../format-error-message.js";
|
|
11
9
|
import { resolveBuildAppConfig } from "../config.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
10
|
+
import { countApiKeys } from "../db/repositories/api-keys.js";
|
|
11
|
+
import { verifyDatabaseInitialization } from "../db/verify-database-initialization.js";
|
|
14
12
|
import configPlugin from "../server/plugins/config.js";
|
|
15
13
|
import databasePlugin from "../server/plugins/database.js";
|
|
16
14
|
import authPlugin from "../server/plugins/auth.js";
|
|
@@ -18,7 +16,6 @@ import credentialRoutes from "../server/routes/credentials.js";
|
|
|
18
16
|
import healthRoutes from "../server/routes/health.js";
|
|
19
17
|
import keyRoutes from "../server/routes/keys.js";
|
|
20
18
|
import { buildApp } from "../server/server.js";
|
|
21
|
-
const migrationsDirectory = fileURLToPath(new URL("../db/migrations", import.meta.url));
|
|
22
19
|
export async function handleServe(options) {
|
|
23
20
|
let buildConfig;
|
|
24
21
|
try {
|
|
@@ -66,32 +63,28 @@ export async function handleServe(options) {
|
|
|
66
63
|
// eslint-disable-next-line unicorn/no-process-exit -- CLI config/startup error
|
|
67
64
|
process.exit(1);
|
|
68
65
|
}
|
|
69
|
-
//
|
|
66
|
+
// `serve` assumes `init` already prepared the database schema.
|
|
70
67
|
try {
|
|
71
|
-
await
|
|
68
|
+
await verifyDatabaseInitialization(app.pg);
|
|
72
69
|
}
|
|
73
70
|
catch (error) {
|
|
74
71
|
const message = formatErrorMessage(error);
|
|
75
|
-
app.log.error(`Failed to
|
|
72
|
+
app.log.error(`Failed to verify database initialization: ${message}`);
|
|
73
|
+
console.error("Database is not initialized or the schema is outdated. Run `axvault init` first.");
|
|
76
74
|
await app.close();
|
|
77
75
|
// eslint-disable-next-line unicorn/no-process-exit -- CLI startup failure
|
|
78
76
|
process.exit(1);
|
|
79
77
|
}
|
|
80
|
-
|
|
78
|
+
let apiKeyCount;
|
|
81
79
|
try {
|
|
82
|
-
|
|
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
|
-
}
|
|
80
|
+
apiKeyCount = await countApiKeys(app.pg);
|
|
88
81
|
}
|
|
89
82
|
catch (error) {
|
|
90
83
|
const message = formatErrorMessage(error);
|
|
91
|
-
app.log.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
84
|
+
app.log.warn(`Failed to check API key count: ${message}`);
|
|
85
|
+
}
|
|
86
|
+
if (apiKeyCount === 0) {
|
|
87
|
+
app.log.warn("No API keys configured. Run `axvault init --create-admin-key` before relying on the server.");
|
|
95
88
|
}
|
|
96
89
|
// Graceful shutdown
|
|
97
90
|
closeWithGrace({ delay: 5000, logger: false }, async ({ signal, err }) => {
|
|
@@ -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.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,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;AAsBD,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
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* `fastify.config`. Logger level is resolved separately because the logger is
|
|
6
6
|
* configured before plugins are registered.
|
|
7
7
|
*/
|
|
8
|
+
import { DEFAULT_DATABASE_URL } from "./resolve-database-url.js";
|
|
8
9
|
const DEFAULT_PORT = 3847;
|
|
9
10
|
const DEFAULT_HOST = "127.0.0.1";
|
|
10
|
-
const DEFAULT_DATABASE_URL = "postgresql://localhost:5432/axvault";
|
|
11
11
|
const DEFAULT_REFRESH_THRESHOLD_SECONDS = 3600; // 1 hour
|
|
12
12
|
const DEFAULT_REFRESH_TIMEOUT_MS = 30_000; // 30 seconds
|
|
13
13
|
const DEFAULT_LOG_LEVEL = "info";
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAyCjE,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,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"}
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Serializes the bootstrap check inside a transaction-scoped advisory lock so
|
|
5
5
|
* concurrent first-time startups cannot mint multiple root keys.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { Pool } from "pg";
|
|
8
8
|
import { type ApiKeyWithSecret } from "./repositories/api-keys.js";
|
|
9
|
-
interface
|
|
10
|
-
|
|
9
|
+
interface BootstrapApiKeyOptions {
|
|
10
|
+
key?: string;
|
|
11
11
|
}
|
|
12
|
-
declare function bootstrapApiKey(
|
|
12
|
+
declare function bootstrapApiKey(pool: Pool, options?: BootstrapApiKeyOptions): Promise<ApiKeyWithSecret | undefined>;
|
|
13
13
|
export { bootstrapApiKey };
|
|
14
14
|
//# sourceMappingURL=bootstrap-api-key.d.ts.map
|
|
@@ -1 +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,
|
|
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,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,4BAA4B,CAAC;AASpC,UAAU,sBAAsB;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,iBAAe,eAAe,CAC5B,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAsDvC;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -5,22 +5,55 @@
|
|
|
5
5
|
* concurrent first-time startups cannot mint multiple root keys.
|
|
6
6
|
*/
|
|
7
7
|
import { createApiKey, } from "./repositories/api-keys.js";
|
|
8
|
+
import { findApiKeyByKey, hasGrantAccess, listApiKeys, } from "./repositories/api-keys.js";
|
|
8
9
|
const BOOTSTRAP_API_KEY_LOCK_ID = 980_641_073;
|
|
9
|
-
async function bootstrapApiKey(
|
|
10
|
-
|
|
10
|
+
async function bootstrapApiKey(pool, options = {}) {
|
|
11
|
+
const client = await pool.connect();
|
|
12
|
+
try {
|
|
13
|
+
await client.query("BEGIN");
|
|
11
14
|
await client.query("SELECT pg_advisory_xact_lock($1)", [
|
|
12
15
|
BOOTSTRAP_API_KEY_LOCK_ID,
|
|
13
16
|
]);
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
if (options.key !== undefined) {
|
|
18
|
+
const existingBootstrapKey = await findApiKeyByKey(client, options.key);
|
|
19
|
+
if (existingBootstrapKey) {
|
|
20
|
+
if (hasGrantAccess(existingBootstrapKey, "*")) {
|
|
21
|
+
await client.query("COMMIT");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
throw new Error("The requested bootstrap admin key does not match the existing database state.");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const existingKeys = await listApiKeys(client);
|
|
28
|
+
if (existingKeys.some((key) => hasGrantAccess(key, "*"))) {
|
|
29
|
+
if (options.key !== undefined) {
|
|
30
|
+
throw new Error("The requested bootstrap admin key does not match the existing database state.");
|
|
31
|
+
}
|
|
32
|
+
await client.query("COMMIT");
|
|
16
33
|
return;
|
|
17
|
-
|
|
34
|
+
}
|
|
35
|
+
const createdKey = await createApiKey(client, {
|
|
18
36
|
name: "Bootstrap Admin",
|
|
19
37
|
readAccess: ["*"],
|
|
20
38
|
writeAccess: ["*"],
|
|
21
39
|
grantAccess: ["*"],
|
|
40
|
+
key: options.key,
|
|
22
41
|
});
|
|
23
|
-
|
|
42
|
+
await client.query("COMMIT");
|
|
43
|
+
return createdKey;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
try {
|
|
47
|
+
await client.query("ROLLBACK");
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// PostgreSQL automatically rolls back on disconnect; preserve the cause.
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
client.release();
|
|
56
|
+
}
|
|
24
57
|
}
|
|
25
58
|
export { bootstrapApiKey };
|
|
26
59
|
//# sourceMappingURL=bootstrap-api-key.js.map
|
|
@@ -1 +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;
|
|
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;AACpC,OAAO,EACL,eAAe,EACf,cAAc,EACd,WAAW,GACZ,MAAM,4BAA4B,CAAC;AAEpC,MAAM,yBAAyB,GAAG,WAAW,CAAC;AAM9C,KAAK,UAAU,eAAe,CAC5B,IAAU,EACV,UAAkC,EAAE;IAEpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,MAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE;YACrD,yBAAyB;SAC1B,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,oBAAoB,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YACxE,IAAI,oBAAoB,EAAE,CAAC;gBACzB,IAAI,cAAc,CAAC,oBAAoB,EAAE,GAAG,CAAC,EAAE,CAAC;oBAC9C,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC7B,OAAO;gBACT,CAAC;gBAED,MAAM,IAAI,KAAK,CACb,+EAA+E,CAChF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;YACzD,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CACb,+EAA+E,CAChF,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE;YAC5C,IAAI,EAAE,iBAAiB;YACvB,UAAU,EAAE,CAAC,GAAG,CAAC;YACjB,WAAW,EAAE,CAAC,GAAG,CAAC;YAClB,WAAW,EAAE,CAAC,GAAG,CAAC;YAClB,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,UAAU,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;QAC3E,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/** Generate a new API key ID */
|
|
7
7
|
declare function generateKeyId(): string;
|
|
8
|
-
/** Generate
|
|
9
|
-
declare function
|
|
8
|
+
/** Generate or validate an API key secret for deterministic provisioning. */
|
|
9
|
+
declare function resolveApiKeySecret(key?: string): string;
|
|
10
10
|
/** Hash an API key for storage */
|
|
11
11
|
declare function hashApiKey(key: string): string;
|
|
12
12
|
/** Extract key prefix for display (axv_sk_ + first 8 hex chars of secret) */
|
|
@@ -23,5 +23,5 @@ declare function hasReadAccess(apiKey: AccessLists, name: string): boolean;
|
|
|
23
23
|
declare function hasWriteAccess(apiKey: AccessLists, name: string): boolean;
|
|
24
24
|
/** Check if API key has grant access to a credential */
|
|
25
25
|
declare function hasGrantAccess(apiKey: AccessLists, name: string): boolean;
|
|
26
|
-
export { extractKeyPrefix, generateKeyId,
|
|
26
|
+
export { extractKeyPrefix, generateKeyId, hashApiKey, hasGrantAccess, hasReadAccess, hasWriteAccess, resolveApiKeySecret, };
|
|
27
27
|
//# sourceMappingURL=api-key-utilities.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-key-utilities.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/api-key-utilities.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"api-key-utilities.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/api-key-utilities.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,gCAAgC;AAChC,iBAAS,aAAa,IAAI,MAAM,CAE/B;AAOD,6EAA6E;AAC7E,iBAAS,mBAAmB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAYjD;AAED,kCAAkC;AAClC,iBAAS,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,6EAA6E;AAC7E,iBAAS,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED,4CAA4C;AAC5C,UAAU,WAAW;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAOD,uDAAuD;AACvD,iBAAS,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,wDAAwD;AACxD,iBAAS,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAElE;AAED,wDAAwD;AACxD,iBAAS,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAElE;AAED,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,mBAAmB,GACpB,CAAC"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { createHash, randomBytes } from "node:crypto";
|
|
7
7
|
/** Key prefix for identification (e.g., "axv_sk_01234567") */
|
|
8
8
|
const KEY_PREFIX_LENGTH = 8;
|
|
9
|
+
const API_KEY_SECRET_PATTERN = /^axv_sk_[0-9a-f]{32}$/u;
|
|
9
10
|
/** Generate a new API key ID */
|
|
10
11
|
function generateKeyId() {
|
|
11
12
|
return `k_${randomBytes(6).toString("hex")}`;
|
|
@@ -14,6 +15,16 @@ function generateKeyId() {
|
|
|
14
15
|
function generateKeySecret() {
|
|
15
16
|
return `axv_sk_${randomBytes(16).toString("hex")}`;
|
|
16
17
|
}
|
|
18
|
+
/** Generate or validate an API key secret for deterministic provisioning. */
|
|
19
|
+
function resolveApiKeySecret(key) {
|
|
20
|
+
if (key === undefined) {
|
|
21
|
+
return generateKeySecret();
|
|
22
|
+
}
|
|
23
|
+
if (!API_KEY_SECRET_PATTERN.test(key)) {
|
|
24
|
+
throw new Error("Invalid API key secret: expected axv_sk_ followed by 32 lowercase hexadecimal characters.");
|
|
25
|
+
}
|
|
26
|
+
return key;
|
|
27
|
+
}
|
|
17
28
|
/** Hash an API key for storage */
|
|
18
29
|
function hashApiKey(key) {
|
|
19
30
|
return createHash("sha256").update(key).digest("hex");
|
|
@@ -39,5 +50,5 @@ function hasWriteAccess(apiKey, name) {
|
|
|
39
50
|
function hasGrantAccess(apiKey, name) {
|
|
40
51
|
return hasAccess(apiKey.grantAccess, name);
|
|
41
52
|
}
|
|
42
|
-
export { extractKeyPrefix, generateKeyId,
|
|
53
|
+
export { extractKeyPrefix, generateKeyId, hashApiKey, hasGrantAccess, hasReadAccess, hasWriteAccess, resolveApiKeySecret, };
|
|
43
54
|
//# sourceMappingURL=api-key-utilities.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-key-utilities.js","sourceRoot":"","sources":["../../../src/db/repositories/api-key-utilities.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,8DAA8D;AAC9D,MAAM,iBAAiB,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"api-key-utilities.js","sourceRoot":"","sources":["../../../src/db/repositories/api-key-utilities.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,8DAA8D;AAC9D,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAC5B,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAExD,gCAAgC;AAChC,SAAS,aAAa;IACpB,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,oCAAoC;AACpC,SAAS,iBAAiB;IACxB,OAAO,UAAU,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,6EAA6E;AAC7E,SAAS,mBAAmB,CAAC,GAAY;IACvC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,iBAAiB,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CACb,2FAA2F,CAC5F,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kCAAkC;AAClC,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,6EAA6E;AAC7E,SAAS,gBAAgB,CAAC,GAAW;IACnC,qCAAqC;IACrC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,0BAA0B;AACxE,CAAC;AASD,8DAA8D;AAC9D,SAAS,SAAS,CAAC,UAAoB,EAAE,IAAY;IACnD,OAAO,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED,uDAAuD;AACvD,SAAS,aAAa,CAAC,MAAmB,EAAE,IAAY;IACtD,OAAO,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,wDAAwD;AACxD,SAAS,cAAc,CAAC,MAAmB,EAAE,IAAY;IACvD,OAAO,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,wDAAwD;AACxD,SAAS,cAAc,CAAC,MAAmB,EAAE,IAAY;IACvD,OAAO,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,mBAAmB,GACpB,CAAC"}
|
|
@@ -11,13 +11,15 @@ declare function findApiKeyByKey(database: Queryable, key: string): Promise<ApiK
|
|
|
11
11
|
declare function findApiKeyById(database: Queryable, id: string): Promise<ApiKeyRecord | undefined>;
|
|
12
12
|
/** List all API keys (without revealing the raw key values) */
|
|
13
13
|
declare function listApiKeys(database: Queryable): Promise<ApiKeyRecord[]>;
|
|
14
|
+
/** Count API keys without loading full records. */
|
|
15
|
+
declare function countApiKeys(database: Queryable): Promise<number>;
|
|
14
16
|
/** Update last used timestamp */
|
|
15
17
|
declare function updateLastUsed(database: Queryable, id: string): Promise<void>;
|
|
16
18
|
/** Delete an API key */
|
|
17
19
|
declare function deleteApiKey(database: Queryable, id: string): Promise<boolean>;
|
|
18
|
-
export { deleteApiKey, findApiKeyById, findApiKeyByKey, listApiKeys, updateLastUsed, };
|
|
20
|
+
export { countApiKeys, deleteApiKey, findApiKeyById, findApiKeyByKey, listApiKeys, updateLastUsed, };
|
|
19
21
|
export { createApiKey } from "./create-api-key.js";
|
|
20
|
-
export { hasGrantAccess, hasReadAccess, hasWriteAccess, } from "./api-key-utilities.js";
|
|
22
|
+
export { hasGrantAccess, hasReadAccess, hasWriteAccess, resolveApiKeySecret, } from "./api-key-utilities.js";
|
|
21
23
|
export { updateApiKeyAccess } from "./update-api-key-access.js";
|
|
22
24
|
export type { ApiKeyRecord, ApiKeyWithSecret } from "./create-api-key.js";
|
|
23
25
|
//# sourceMappingURL=api-keys.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-keys.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/api-keys.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAmBxD,oCAAoC;AACpC,iBAAe,eAAe,CAC5B,QAAQ,EAAE,SAAS,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAOnC;AAED,yBAAyB;AACzB,iBAAe,cAAc,CAC3B,QAAQ,EAAE,SAAS,EACnB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAOnC;AAED,+DAA+D;AAC/D,iBAAe,WAAW,CAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAKvE;AAED,iCAAiC;AACjC,iBAAe,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5E;AAED,wBAAwB;AACxB,iBAAe,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAK7E;AAED,OAAO,EACL,YAAY,EACZ,cAAc,EACd,eAAe,EACf,WAAW,EACX,cAAc,GACf,CAAC;AACF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,cAAc,EACd,aAAa,EACb,cAAc,
|
|
1
|
+
{"version":3,"file":"api-keys.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/api-keys.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAmBxD,oCAAoC;AACpC,iBAAe,eAAe,CAC5B,QAAQ,EAAE,SAAS,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAOnC;AAED,yBAAyB;AACzB,iBAAe,cAAc,CAC3B,QAAQ,EAAE,SAAS,EACnB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAOnC;AAED,+DAA+D;AAC/D,iBAAe,WAAW,CAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAKvE;AAED,mDAAmD;AACnD,iBAAe,YAAY,CAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAKhE;AAED,iCAAiC;AACjC,iBAAe,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5E;AAED,wBAAwB;AACxB,iBAAe,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAK7E;AAED,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,eAAe,EACf,WAAW,EACX,cAAc,GACf,CAAC;AACF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,cAAc,EACd,aAAa,EACb,cAAc,EACd,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -36,6 +36,11 @@ async function listApiKeys(database) {
|
|
|
36
36
|
const result = await database.query(`SELECT ${SELECT_COLUMNS} FROM api_keys ORDER BY created_at DESC`);
|
|
37
37
|
return result.rows.map((row) => rowToRecord(row));
|
|
38
38
|
}
|
|
39
|
+
/** Count API keys without loading full records. */
|
|
40
|
+
async function countApiKeys(database) {
|
|
41
|
+
const result = await database.query("SELECT COUNT(*)::int AS count FROM api_keys");
|
|
42
|
+
return result.rows[0]?.count ?? 0;
|
|
43
|
+
}
|
|
39
44
|
/** Update last used timestamp */
|
|
40
45
|
async function updateLastUsed(database, id) {
|
|
41
46
|
await database.query(`UPDATE api_keys SET last_used_at = $1 WHERE id = $2`, [
|
|
@@ -50,8 +55,8 @@ async function deleteApiKey(database, id) {
|
|
|
50
55
|
]);
|
|
51
56
|
return (result.rowCount ?? 0) > 0;
|
|
52
57
|
}
|
|
53
|
-
export { deleteApiKey, findApiKeyById, findApiKeyByKey, listApiKeys, updateLastUsed, };
|
|
58
|
+
export { countApiKeys, deleteApiKey, findApiKeyById, findApiKeyByKey, listApiKeys, updateLastUsed, };
|
|
54
59
|
export { createApiKey } from "./create-api-key.js";
|
|
55
|
-
export { hasGrantAccess, hasReadAccess, hasWriteAccess, } from "./api-key-utilities.js";
|
|
60
|
+
export { hasGrantAccess, hasReadAccess, hasWriteAccess, resolveApiKeySecret, } from "./api-key-utilities.js";
|
|
56
61
|
export { updateApiKeyAccess } from "./update-api-key-access.js";
|
|
57
62
|
//# sourceMappingURL=api-keys.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../../../src/db/repositories/api-keys.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,qCAAqC;AACrC,SAAS,WAAW,CAAC,GAAc;IACjC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,SAAS,EAAE,GAAG,CAAC,UAAU,IAAI,SAAS;QACtC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAa;QACnD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAa;QACrD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAa;QACrD,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;QACnC,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;KACtE,CAAC;AACJ,CAAC;AAED,MAAM,cAAc,GAAG,mGAAmG,CAAC;AAE3H,oCAAoC;AACpC,KAAK,UAAU,eAAe,CAC5B,QAAmB,EACnB,GAAW;IAEX,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CACjC,UAAU,cAAc,oCAAoC,EAC5D,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAClB,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5C,CAAC;AAED,yBAAyB;AACzB,KAAK,UAAU,cAAc,CAC3B,QAAmB,EACnB,EAAU;IAEV,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CACjC,UAAU,cAAc,8BAA8B,EACtD,CAAC,EAAE,CAAC,CACL,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5C,CAAC;AAED,+DAA+D;AAC/D,KAAK,UAAU,WAAW,CAAC,QAAmB;IAC5C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CACjC,UAAU,cAAc,yCAAyC,CAClE,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,iCAAiC;AACjC,KAAK,UAAU,cAAc,CAAC,QAAmB,EAAE,EAAU;IAC3D,MAAM,QAAQ,CAAC,KAAK,CAAC,qDAAqD,EAAE;QAC1E,IAAI,CAAC,GAAG,EAAE;QACV,EAAE;KACH,CAAC,CAAC;AACL,CAAC;AAED,wBAAwB;AACxB,KAAK,UAAU,YAAY,CAAC,QAAmB,EAAE,EAAU;IACzD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,oCAAoC,EAAE;QACxE,EAAE;KACH,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,OAAO,EACL,YAAY,EACZ,cAAc,EACd,eAAe,EACf,WAAW,EACX,cAAc,GACf,CAAC;AACF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,cAAc,EACd,aAAa,EACb,cAAc,
|
|
1
|
+
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../../../src/db/repositories/api-keys.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,qCAAqC;AACrC,SAAS,WAAW,CAAC,GAAc;IACjC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,SAAS,EAAE,GAAG,CAAC,UAAU,IAAI,SAAS;QACtC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAa;QACnD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAa;QACrD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAa;QACrD,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;QACnC,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;KACtE,CAAC;AACJ,CAAC;AAED,MAAM,cAAc,GAAG,mGAAmG,CAAC;AAE3H,oCAAoC;AACpC,KAAK,UAAU,eAAe,CAC5B,QAAmB,EACnB,GAAW;IAEX,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CACjC,UAAU,cAAc,oCAAoC,EAC5D,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAClB,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5C,CAAC;AAED,yBAAyB;AACzB,KAAK,UAAU,cAAc,CAC3B,QAAmB,EACnB,EAAU;IAEV,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CACjC,UAAU,cAAc,8BAA8B,EACtD,CAAC,EAAE,CAAC,CACL,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5C,CAAC;AAED,+DAA+D;AAC/D,KAAK,UAAU,WAAW,CAAC,QAAmB;IAC5C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CACjC,UAAU,cAAc,yCAAyC,CAClE,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,mDAAmD;AACnD,KAAK,UAAU,YAAY,CAAC,QAAmB;IAC7C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CACjC,6CAA6C,CAC9C,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,iCAAiC;AACjC,KAAK,UAAU,cAAc,CAAC,QAAmB,EAAE,EAAU;IAC3D,MAAM,QAAQ,CAAC,KAAK,CAAC,qDAAqD,EAAE;QAC1E,IAAI,CAAC,GAAG,EAAE;QACV,EAAE;KACH,CAAC,CAAC;AACL,CAAC;AAED,wBAAwB;AACxB,KAAK,UAAU,YAAY,CAAC,QAAmB,EAAE,EAAU;IACzD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,oCAAoC,EAAE;QACxE,EAAE;KACH,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,eAAe,EACf,WAAW,EACX,cAAc,GACf,CAAC;AACF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,cAAc,EACd,aAAa,EACb,cAAc,EACd,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -24,6 +24,7 @@ declare function createApiKey(database: Queryable, options: {
|
|
|
24
24
|
readAccess: string[];
|
|
25
25
|
writeAccess: string[];
|
|
26
26
|
grantAccess: string[];
|
|
27
|
+
key?: string;
|
|
27
28
|
}): Promise<ApiKeyWithSecret>;
|
|
28
29
|
export { createApiKey };
|
|
29
30
|
export type { ApiKeyRecord, ApiKeyWithSecret };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-api-key.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/create-api-key.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAQ7C,sCAAsC;AACtC,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,GAAG,SAAS,CAAC;CAC9B;AAED,2DAA2D;AAC3D,UAAU,gBAAiB,SAAQ,YAAY;IAC7C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2BAA2B;AAC3B,iBAAe,YAAY,CACzB,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAE;IACP,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"create-api-key.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/create-api-key.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAQ7C,sCAAsC;AACtC,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,GAAG,SAAS,CAAC;CAC9B;AAED,2DAA2D;AAC3D,UAAU,gBAAiB,SAAQ,YAAY;IAC7C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2BAA2B;AAC3B,iBAAe,YAAY,CACzB,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAE;IACP,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GACA,OAAO,CAAC,gBAAgB,CAAC,CAkC3B;AAED,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Create a new API key.
|
|
3
3
|
*/
|
|
4
|
-
import { extractKeyPrefix, generateKeyId,
|
|
4
|
+
import { extractKeyPrefix, generateKeyId, hashApiKey, resolveApiKeySecret, } from "./api-key-utilities.js";
|
|
5
5
|
/** Create a new API key */
|
|
6
6
|
async function createApiKey(database, options) {
|
|
7
7
|
const id = generateKeyId();
|
|
8
|
-
const key =
|
|
8
|
+
const key = resolveApiKeySecret(options.key);
|
|
9
9
|
const keyHash = hashApiKey(key);
|
|
10
10
|
const keyPrefix = extractKeyPrefix(key);
|
|
11
11
|
const now = Date.now();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-api-key.js","sourceRoot":"","sources":["../../../src/db/repositories/create-api-key.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,
|
|
1
|
+
{"version":3,"file":"create-api-key.js","sourceRoot":"","sources":["../../../src/db/repositories/create-api-key.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAoBhC,2BAA2B;AAC3B,KAAK,UAAU,YAAY,CACzB,QAAmB,EACnB,OAMC;IAED,MAAM,EAAE,GAAG,aAAa,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,MAAM,QAAQ,CAAC,KAAK,CAClB;6CACyC,EACzC;QACE,EAAE;QACF,OAAO,CAAC,IAAI;QACZ,OAAO;QACP,SAAS;QACT,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC;QACnC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC;QACnC,GAAG;KACJ,CACF,CAAC;IAEF,OAAO;QACL,EAAE;QACF,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,GAAG;QACH,OAAO;QACP,SAAS;QACT,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC;QACxB,UAAU,EAAE,SAAS;KACtB,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-database-initialization.d.ts","sourceRoot":"","sources":["../../src/db/verify-database-initialization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAwB5C,iBAAe,4BAA4B,CACzC,QAAQ,EAAE,SAAS,GAClB,OAAO,CAAC,IAAI,CAAC,CAsDf;AAED,OAAO,EAAE,4BAA4B,EAAE,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const REQUIRED_CREDENTIAL_COLUMNS = [
|
|
2
|
+
"name",
|
|
3
|
+
"agent",
|
|
4
|
+
"provider",
|
|
5
|
+
"display_name",
|
|
6
|
+
"notes",
|
|
7
|
+
"encrypted_data",
|
|
8
|
+
"salt",
|
|
9
|
+
"iv",
|
|
10
|
+
"auth_tag",
|
|
11
|
+
"created_at",
|
|
12
|
+
"updated_at",
|
|
13
|
+
];
|
|
14
|
+
async function verifyDatabaseInitialization(database) {
|
|
15
|
+
const result = await database.query(`
|
|
16
|
+
SELECT
|
|
17
|
+
to_regclass('api_keys') IS NOT NULL AS has_api_keys,
|
|
18
|
+
to_regclass('credentials') IS NOT NULL AS has_credentials,
|
|
19
|
+
to_regclass('audit_log') IS NOT NULL AS has_audit_log,
|
|
20
|
+
EXISTS (
|
|
21
|
+
SELECT 1
|
|
22
|
+
FROM information_schema.columns
|
|
23
|
+
WHERE table_schema = current_schema()
|
|
24
|
+
AND table_name = 'audit_log'
|
|
25
|
+
AND column_name = 'detail'
|
|
26
|
+
) AS has_audit_log_detail,
|
|
27
|
+
COALESCE(
|
|
28
|
+
ARRAY(
|
|
29
|
+
SELECT column_name
|
|
30
|
+
FROM information_schema.columns
|
|
31
|
+
WHERE table_schema = current_schema()
|
|
32
|
+
AND table_name = 'credentials'
|
|
33
|
+
),
|
|
34
|
+
ARRAY[]::text[]
|
|
35
|
+
) AS credential_columns
|
|
36
|
+
`);
|
|
37
|
+
const status = result.rows[0];
|
|
38
|
+
if (!status) {
|
|
39
|
+
throw new Error("Failed to inspect database schema.");
|
|
40
|
+
}
|
|
41
|
+
const missingParts = [];
|
|
42
|
+
if (!status.has_api_keys) {
|
|
43
|
+
missingParts.push("table api_keys");
|
|
44
|
+
}
|
|
45
|
+
if (status.has_credentials) {
|
|
46
|
+
for (const column of REQUIRED_CREDENTIAL_COLUMNS) {
|
|
47
|
+
if (!status.credential_columns.includes(column)) {
|
|
48
|
+
missingParts.push(`column credentials.${column}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
missingParts.push("table credentials");
|
|
54
|
+
}
|
|
55
|
+
if (!status.has_audit_log) {
|
|
56
|
+
missingParts.push("table audit_log");
|
|
57
|
+
}
|
|
58
|
+
else if (!status.has_audit_log_detail) {
|
|
59
|
+
missingParts.push("column audit_log.detail");
|
|
60
|
+
}
|
|
61
|
+
if (missingParts.length > 0) {
|
|
62
|
+
throw new Error(`Database schema is missing ${missingParts.join(", ")}.`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export { verifyDatabaseInitialization };
|
|
66
|
+
//# sourceMappingURL=verify-database-initialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-database-initialization.js","sourceRoot":"","sources":["../../src/db/verify-database-initialization.ts"],"names":[],"mappings":"AAUA,MAAM,2BAA2B,GAAG;IAClC,MAAM;IACN,OAAO;IACP,UAAU;IACV,cAAc;IACd,OAAO;IACP,gBAAgB;IAChB,MAAM;IACN,IAAI;IACJ,UAAU;IACV,YAAY;IACZ,YAAY;CACJ,CAAC;AAEX,KAAK,UAAU,4BAA4B,CACzC,QAAmB;IAEnB,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAA0B;;;;;;;;;;;;;;;;;;;;;GAqB5D,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QAC3B,KAAK,MAAM,MAAM,IAAI,2BAA2B,EAAE,CAAC;YACjD,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAChD,YAAY,CAAC,IAAI,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,YAAY,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;QAC1B,YAAY,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACvC,CAAC;SAAM,IAAI,CAAC,MAAM,CAAC,oBAAoB,EAAE,CAAC;QACxC,YAAY,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,8BAA8B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,OAAO,EAAE,4BAA4B,EAAE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export type { ServerConfig } from "./config.js";
|
|
9
9
|
export type { BuildAppConfig } from "./config.js";
|
|
10
|
+
export { createConfigData, resolveBuildAppConfig, serverConfigSchema, } from "./config.js";
|
|
11
|
+
export { resolveDatabaseUrl } from "./resolve-database-url.js";
|
|
10
12
|
export { buildApp } from "./server/server.js";
|
|
11
13
|
export { default as configPlugin } from "./server/plugins/config.js";
|
|
12
14
|
export { default as databasePlugin } from "./server/plugins/database.js";
|
|
@@ -15,10 +17,10 @@ export { default as healthRoutes } from "./server/routes/health.js";
|
|
|
15
17
|
export { default as credentialRoutes } from "./server/routes/credentials.js";
|
|
16
18
|
export { default as keyRoutes } from "./server/routes/keys.js";
|
|
17
19
|
export { runMigrations } from "./db/run-migrations.js";
|
|
18
|
-
export {
|
|
20
|
+
export { closePool, createPool } from "./db/create-pool.js";
|
|
19
21
|
export type { Queryable } from "./db/types.js";
|
|
20
22
|
export type { ApiKeyRecord, ApiKeyWithSecret, } from "./db/repositories/api-keys.js";
|
|
21
|
-
export { createApiKey, deleteApiKey, findApiKeyById, findApiKeyByKey, hasGrantAccess, hasReadAccess, hasWriteAccess, listApiKeys, updateApiKeyAccess, updateLastUsed, } from "./db/repositories/api-keys.js";
|
|
23
|
+
export { countApiKeys, createApiKey, deleteApiKey, findApiKeyById, findApiKeyByKey, hasGrantAccess, hasReadAccess, hasWriteAccess, listApiKeys, resolveApiKeySecret, updateApiKeyAccess, updateLastUsed, } from "./db/repositories/api-keys.js";
|
|
22
24
|
export type { AuditLogEntry } from "./db/repositories/audit-log.js";
|
|
23
25
|
export { getLogsForCredential, getRecentLogs, logAccess, pruneOldLogs, } from "./db/repositories/audit-log.js";
|
|
24
26
|
export type { CredentialMetadata, CredentialRecord, } from "./db/repositories/credentials.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGjE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGjE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,YAAY,EACV,YAAY,EACZ,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,SAAS,EACT,YAAY,GACb,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,wBAAwB,EACxB,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,kCAAkC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* The legacy createServer/createPool surface was intentionally removed; build
|
|
6
6
|
* the app with `buildApp()` plus the exported Fastify plugins instead.
|
|
7
7
|
*/
|
|
8
|
+
export { createConfigData, resolveBuildAppConfig, serverConfigSchema, } from "./config.js";
|
|
9
|
+
export { resolveDatabaseUrl } from "./resolve-database-url.js";
|
|
8
10
|
export { buildApp } from "./server/server.js";
|
|
9
11
|
// Plugins
|
|
10
12
|
export { default as configPlugin } from "./server/plugins/config.js";
|
|
@@ -16,8 +18,8 @@ export { default as credentialRoutes } from "./server/routes/credentials.js";
|
|
|
16
18
|
export { default as keyRoutes } from "./server/routes/keys.js";
|
|
17
19
|
// Database
|
|
18
20
|
export { runMigrations } from "./db/run-migrations.js";
|
|
19
|
-
export {
|
|
20
|
-
export { createApiKey, deleteApiKey, findApiKeyById, findApiKeyByKey, hasGrantAccess, hasReadAccess, hasWriteAccess, listApiKeys, updateApiKeyAccess, updateLastUsed, } from "./db/repositories/api-keys.js";
|
|
21
|
+
export { closePool, createPool } from "./db/create-pool.js";
|
|
22
|
+
export { countApiKeys, createApiKey, deleteApiKey, findApiKeyById, findApiKeyByKey, hasGrantAccess, hasReadAccess, hasWriteAccess, listApiKeys, resolveApiKeySecret, updateApiKeyAccess, updateLastUsed, } from "./db/repositories/api-keys.js";
|
|
21
23
|
export { getLogsForCredential, getRecentLogs, logAccess, pruneOldLogs, } from "./db/repositories/audit-log.js";
|
|
22
24
|
export { deleteCredential, getCredential, listCredentials, listCredentialsForApiKey, listCredentialsPaginated, upsertCredential, } from "./db/repositories/credentials.js";
|
|
23
25
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,UAAU;AACV,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEjE,gBAAgB;AAChB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE/D,WAAW;AACX,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,UAAU;AACV,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEjE,gBAAgB;AAChB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE/D,WAAW;AACX,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAQ5D,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,SAAS,EACT,YAAY,GACb,MAAM,gCAAgC,CAAC;AAKxC,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,wBAAwB,EACxB,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,kCAAkC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-database-url.d.ts","sourceRoot":"","sources":["../src/resolve-database-url.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,oBAAoB,wCAAwC,CAAC;AAEnE,iBAAS,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAUxD;AAED,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const DEFAULT_DATABASE_URL = "postgresql://localhost:5432/axvault";
|
|
2
|
+
function resolveDatabaseUrl(databaseUrl) {
|
|
3
|
+
const value = databaseUrl ?? process.env.AXVAULT_DATABASE_URL ?? DEFAULT_DATABASE_URL;
|
|
4
|
+
const trimmedValue = value.trim();
|
|
5
|
+
if (trimmedValue.length === 0) {
|
|
6
|
+
throw new Error("Database URL must not be empty.");
|
|
7
|
+
}
|
|
8
|
+
return trimmedValue;
|
|
9
|
+
}
|
|
10
|
+
export { DEFAULT_DATABASE_URL, resolveDatabaseUrl };
|
|
11
|
+
//# sourceMappingURL=resolve-database-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-database-url.js","sourceRoot":"","sources":["../src/resolve-database-url.ts"],"names":[],"mappings":"AAAA,MAAM,oBAAoB,GAAG,qCAAqC,CAAC;AAEnE,SAAS,kBAAkB,CAAC,WAAoB;IAC9C,MAAM,KAAK,GACT,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,oBAAoB,CAAC;IAC1E,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAElC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface SecretSourceOptions {
|
|
2
|
+
directValue?: string;
|
|
3
|
+
envName?: string;
|
|
4
|
+
filePath?: string;
|
|
5
|
+
directOption: string;
|
|
6
|
+
envOption: string;
|
|
7
|
+
fileOption: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveSecretSource(options: SecretSourceOptions): Promise<string | undefined>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=resolve-secret-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-secret-source.d.ts","sourceRoot":"","sources":["../src/resolve-secret-source.ts"],"names":[],"mappings":"AAEA,UAAU,mBAAmB;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA2C7B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
export async function resolveSecretSource(options) {
|
|
3
|
+
const configuredSources = [];
|
|
4
|
+
if (typeof options.directValue === "string") {
|
|
5
|
+
configuredSources.push(options.directOption);
|
|
6
|
+
}
|
|
7
|
+
if (typeof options.envName === "string") {
|
|
8
|
+
configuredSources.push(options.envOption);
|
|
9
|
+
}
|
|
10
|
+
if (typeof options.filePath === "string") {
|
|
11
|
+
configuredSources.push(options.fileOption);
|
|
12
|
+
}
|
|
13
|
+
if (configuredSources.length > 1) {
|
|
14
|
+
throw new Error(`Choose only one of ${configuredSources.join(", ")}.`);
|
|
15
|
+
}
|
|
16
|
+
if (typeof options.directValue === "string") {
|
|
17
|
+
return options.directValue;
|
|
18
|
+
}
|
|
19
|
+
if (typeof options.envName === "string") {
|
|
20
|
+
const value = process.env[options.envName]?.trim();
|
|
21
|
+
if (!value) {
|
|
22
|
+
throw new Error(`Environment variable ${options.envName} is not set or is empty.`);
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
if (typeof options.filePath === "string") {
|
|
27
|
+
const fileContents = await readFile(options.filePath, "utf8");
|
|
28
|
+
const value = fileContents.trim();
|
|
29
|
+
if (!value) {
|
|
30
|
+
throw new Error(`Secret file ${options.filePath} is empty.`);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=resolve-secret-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-secret-source.js","sourceRoot":"","sources":["../src/resolve-secret-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAW5C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA4B;IAE5B,MAAM,iBAAiB,GAAa,EAAE,CAAC;IAEvC,IAAI,OAAO,OAAO,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;QAC5C,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACxC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACzC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,sBAAsB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,OAAO,OAAO,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,OAAO,CAAC,WAAW,CAAC;IAC7B,CAAC;IAED,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC;QACnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACb,wBAAwB,OAAO,CAAC,OAAO,0BAA0B,CAClE,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACzC,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,eAAe,OAAO,CAAC,QAAQ,YAAY,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/server/plugins/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,MAAM,EAAE,YAAY,CAAC;KACtB;IAED,UAAU,eAAe;QACvB,YAAY,EAAE,CACZ,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,IAAI,CAAC,CAAC;QACnB,kBAAkB,EAAE,CAClB,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,IAAI,CAAC,CAAC;KACpB;CACF;;AAWD,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/server/plugins/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,MAAM,EAAE,YAAY,CAAC;KACtB;IAED,UAAU,eAAe;QACvB,YAAY,EAAE,CACZ,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,IAAI,CAAC,CAAC;QACnB,kBAAkB,EAAE,CAClB,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,IAAI,CAAC,CAAC;KACpB;CACF;;AAWD,wBA8CE"}
|
|
@@ -14,9 +14,7 @@ function extractBearerToken(authorizationHeader) {
|
|
|
14
14
|
const match = /^Bearer\s+(\S+)$/iu.exec(authorizationHeader);
|
|
15
15
|
return match?.[1];
|
|
16
16
|
}
|
|
17
|
-
export default fp(
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/require-await -- Fastify plugin signature requires async
|
|
19
|
-
async function authPlugin(fastify) {
|
|
17
|
+
export default fp(async function authPlugin(fastify) {
|
|
20
18
|
// eslint-disable-next-line unicorn/no-null -- Fastify decorator requires an initial value
|
|
21
19
|
fastify.decorateRequest("apiKey", null);
|
|
22
20
|
fastify.decorate("authenticate", async (request, reply) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/server/plugins/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEhC,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,GAEf,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAmB/D,qDAAqD;AACrD,SAAS,kBAAkB,CACzB,mBAAuC;IAEvC,IAAI,CAAC,mBAAmB;QAAE,OAAO,SAAS,CAAC;IAC3C,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC7D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,eAAe,EAAE
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/server/plugins/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEhC,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,GAEf,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAmB/D,qDAAqD;AACrD,SAAS,kBAAkB,CACzB,mBAAuC;IAEvC,IAAI,CAAC,mBAAmB;QAAE,OAAO,SAAS,CAAC;IAC3C,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC7D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,eAAe,EAAE,CACf,KAAK,UAAU,UAAU,CAAC,OAAO;IAC/B,0FAA0F;IAC1F,OAAO,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAa,CAAC,CAAC;IAEjD,OAAO,CAAC,QAAQ,CACd,cAAc,EACd,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAiB,EAAE;QACpE,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAEhE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE;gBAC1B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,8BAA8B;aAC7C,CAAC,CAAC;YACH,OAAO,KAAK,CAAC,YAAY,CAAC,8BAA8B,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAExD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE;gBAC1B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,iBAAiB;aAChC,CAAC,CAAC;YACH,OAAO,KAAK,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5C,sGAAsG;QACtG,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;IAC1B,CAAC,CACF,CAAC;IAEF,OAAO,CAAC,QAAQ,CACd,oBAAoB,EACpB,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAiB,EAAE;QACpE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;QAClD,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC,EACD,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,UAAU,CAAC,EAAE,CAC7C,CAAC"}
|