@o3co/create-auth-provider 0.16.0 → 0.17.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +66 -21
- package/README.md +76 -31
- package/dist/index.d.mts +33 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +118 -59
- package/dist/internal/template-filter.d.mts +7 -10
- package/dist/internal/template-filter.d.mts.map +1 -1
- package/dist/internal/template-filter.mjs +7 -10
- package/package.json +6 -4
- package/templates/standalone/.dockerignore +15 -2
- package/templates/standalone/.env.example +59 -29
- package/templates/standalone/Dockerfile +6 -2
- package/templates/standalone/README.ja.md +324 -169
- package/templates/standalone/README.md +618 -208
- package/templates/standalone/config/application.conf +211 -352
- package/templates/standalone/config/clients.yaml +2 -0
- package/templates/standalone/config/clients.yaml.example +4 -0
- package/templates/standalone/config/development.conf +13 -4
- package/templates/standalone/config/mailpit.conf +8 -0
- package/templates/standalone/config/production.conf +5 -6
- package/templates/standalone/config/reference.conf +418 -0
- package/templates/standalone/docker-compose.mailpit.yml +36 -0
- package/templates/standalone/docker-compose.production.yml +63 -32
- package/templates/standalone/docker-compose.yml +13 -3
- package/templates/standalone/gitignore +1 -0
- package/templates/standalone/package.json +9 -6
- package/templates/standalone/src/__tests__/adapters.test.mts +419 -0
- package/templates/standalone/src/__tests__/admission-lifecycle.test.mts +87 -0
- package/templates/standalone/src/__tests__/all-modules-composition.fixture.mts +287 -198
- package/templates/standalone/src/__tests__/all-modules-composition.multi.test.mts +71 -35
- package/templates/standalone/src/__tests__/all-modules-composition.test.mts +148 -94
- package/templates/standalone/src/__tests__/audit-sink.test.mts +84 -81
- package/templates/standalone/src/__tests__/config-notices.test.mts +154 -0
- package/templates/standalone/src/__tests__/configPath.test.mts +13 -11
- package/templates/standalone/src/__tests__/core-federations.test.mts +249 -0
- package/templates/standalone/src/__tests__/core-sections.test.mts +190 -0
- package/templates/standalone/src/__tests__/device-code-store-client-module.test.mts +10 -15
- package/templates/standalone/src/__tests__/documented-env-overrides.test.mts +970 -288
- package/templates/standalone/src/__tests__/federation-grants-composition.test.mts +421 -86
- package/templates/standalone/src/__tests__/federation-grants-survive-logout.test.mts +87 -72
- package/templates/standalone/src/__tests__/federation-token-refresh-outage.test.mts +16 -8
- package/templates/standalone/src/__tests__/federation-types.test.mts +239 -0
- package/templates/standalone/src/__tests__/google-session.fixture.mts +97 -93
- package/templates/standalone/src/__tests__/host-routes.test.mts +4 -11
- package/templates/standalone/src/__tests__/library-reference-resolution.smoke.test.mts +1 -1
- package/templates/standalone/src/__tests__/library-references.fixture.mts +188 -0
- package/templates/standalone/src/__tests__/lifecycle-pending-close.test.mts +216 -0
- package/templates/standalone/src/__tests__/listen.test.mts +6 -13
- package/templates/standalone/src/__tests__/logger-projection.test.mts +1 -1
- package/templates/standalone/src/__tests__/mail-sender.test.mts +134 -0
- package/templates/standalone/src/__tests__/mailpit-compose.test.mts +326 -0
- package/templates/standalone/src/__tests__/metrics.test.mts +4 -9
- package/templates/standalone/src/__tests__/mfa-routes-budget.test.mts +122 -0
- package/templates/standalone/src/__tests__/mfa-switch.redis.test.mts +123 -0
- package/templates/standalone/src/__tests__/mfa-switch.test.mts +825 -0
- package/templates/standalone/src/__tests__/own-modules.test.mts +1486 -0
- package/templates/standalone/src/__tests__/post-logout-redirect.test.mts +10 -14
- package/templates/standalone/src/__tests__/redis-connection-error-log.test.mts +1 -5
- package/templates/standalone/src/__tests__/redis-rate-limiter-config-survives.test.mts +116 -81
- package/templates/standalone/src/__tests__/refresh-token-family-client-module.test.mts +25 -31
- package/templates/standalone/src/__tests__/replica-safety.test.mts +265 -146
- package/templates/standalone/src/__tests__/router-error-answers.test.mts +4 -7
- package/templates/standalone/src/__tests__/scaffold-assets.test.mts +278 -103
- package/templates/standalone/src/__tests__/sections.test.mts +480 -0
- package/templates/standalone/src/__tests__/session-lifecycle.test.mts +215 -0
- package/templates/standalone/src/__tests__/session-logout-invalidates-token.test.mts +69 -61
- package/templates/standalone/src/__tests__/session-logout-lifecycle.test.mts +130 -0
- package/templates/standalone/src/__tests__/session-requirements.test.mts +382 -0
- package/templates/standalone/src/__tests__/shipped-config-notices.test.mts +270 -0
- package/templates/standalone/src/__tests__/shutdown.test.mts +163 -96
- package/templates/standalone/src/__tests__/smoke.test.mts +176 -258
- package/templates/standalone/src/__tests__/store-credential.test.mts +88 -52
- package/templates/standalone/src/__tests__/supertest-loopback.test.mts +182 -11
- package/templates/standalone/src/__tests__/three-tier-resolution.test.mts +131 -102
- package/templates/standalone/src/__tests__/two-phase-config.test.mts +604 -0
- package/templates/standalone/src/__tests__/upstream-amr.acceptance.test.mts +382 -0
- package/templates/standalone/src/adapters.mts +162 -0
- package/templates/standalone/src/app.mts +65 -79
- package/templates/standalone/src/bootRefusal.mts +117 -0
- package/templates/standalone/src/buildModules.mts +220 -309
- package/templates/standalone/src/configPath.mts +449 -29
- package/templates/standalone/src/listen.mts +12 -18
- package/templates/standalone/src/logger.mts +31 -60
- package/templates/standalone/src/metrics.mts +24 -47
- package/templates/standalone/src/mfaSwitch.mts +285 -0
- package/templates/standalone/src/modules.mts +423 -629
- package/templates/standalone/src/rootRenames.mts +96 -0
- package/templates/standalone/src/routes.mts +8 -14
- package/templates/standalone/src/sections.mts +367 -0
- package/templates/standalone/src/shutdown.mts +45 -123
- package/templates/standalone/tests/index.test.js +6 -5
- package/templates/standalone/tests/package-lock.json +1615 -2223
- package/templates/standalone/tests/package.json +2 -2
- package/templates/standalone/tests/vitest.config.mjs +26 -0
- package/templates/standalone/vitest.config.mts +8 -7
- package/templates/standalone/vitest.supertest-loopback.mts +97 -69
- package/templates/versions.json +18 -15
- package/templates/standalone/src/__tests__/access-token-lifetime-alias.test.mts +0 -135
- package/templates/standalone/src/__tests__/google-federation-config-module.test.mts +0 -199
- package/templates/standalone/src/__tests__/oidc-federation-config-module.test.mts +0 -138
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
# The pem pair is required: EdDSA is the default and there is no key-material
|
|
16
16
|
# default, so a deployment that generates none fails at boot naming the keys to
|
|
17
17
|
# set. It reaches the container as a compose secret rather than through
|
|
18
|
-
# `config/`, which the image COPYs — see the `secrets:` block below.
|
|
18
|
+
# `config/`, which the image COPYs — see the `secrets:` block below. So does
|
|
19
|
+
# the client registry, `config/clients.yaml` (#705): it is per-deployment, so
|
|
20
|
+
# `.gitignore` keeps it out of git and `.dockerignore` out of the image, and
|
|
21
|
+
# the image carries no registry of its own. Create it from
|
|
22
|
+
# `config/clients.yaml.example` before the first `up`.
|
|
19
23
|
#
|
|
20
24
|
# What this file deliberately does NOT do:
|
|
21
25
|
#
|
|
@@ -24,13 +28,13 @@
|
|
|
24
28
|
# and every IP-keyed rate limit — means the client, not the proxy; compose
|
|
25
29
|
# refuses to start until you supply it. See README "Multi-replica
|
|
26
30
|
# deployments".
|
|
27
|
-
# - **Scale out.** This is one replica (
|
|
28
|
-
# `--scale app=N`, set
|
|
31
|
+
# - **Scale out.** This is one replica (CORE_DEPLOYMENT_MODE=single). Before
|
|
32
|
+
# `--scale app=N`, set CORE_DEPLOYMENT_MODE=multi and read that same README
|
|
29
33
|
# section — boot will then refuse any in-memory store that must be shared.
|
|
30
|
-
# - **Invent secrets.**
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
+
# - **Invent secrets.** SESSION_STORE_SECRET comes from `.env`, which is required
|
|
35
|
+
# here — chmod 600 it, keep it out of git (`git local-files` or your secret
|
|
36
|
+
# manager of choice), and never bake it into the image. The client
|
|
37
|
+
# registry's secrets are yours to write too; give them as bcrypt hashes.
|
|
34
38
|
|
|
35
39
|
services:
|
|
36
40
|
app:
|
|
@@ -49,11 +53,11 @@ services:
|
|
|
49
53
|
# security group, a firewall rule, or the proxy's own network. Do not
|
|
50
54
|
# widen this line and call it done.
|
|
51
55
|
- "127.0.0.1:3000:3000"
|
|
52
|
-
#
|
|
56
|
+
# Compose's default grace is ten seconds — the HTTP drain
|
|
53
57
|
# budget alone. With federation grants on, `src/app.mts` gives cleanup 45
|
|
54
58
|
# more for the drain of a rotated upstream credential's write, and SIGKILL
|
|
55
59
|
# has to arrive after that: drain (10) + cleanup (45) + an exit margin.
|
|
56
|
-
# The cleanup allowance grows by itself with `
|
|
60
|
+
# The cleanup allowance grows by itself with `federation-grants.upstreamHardTimeoutMs`,
|
|
57
61
|
# `persistRetryBudgetMs` and `lockWaitMs`; raise this to match when you raise them.
|
|
58
62
|
stop_grace_period: 60s
|
|
59
63
|
depends_on:
|
|
@@ -61,7 +65,7 @@ services:
|
|
|
61
65
|
condition: service_healthy
|
|
62
66
|
env_file:
|
|
63
67
|
# Required, unlike the dev file: a production boot without
|
|
64
|
-
#
|
|
68
|
+
# SESSION_STORE_SECRET (or with the sample one) must fail loudly here, not
|
|
65
69
|
# serve quietly with a guessable secret.
|
|
66
70
|
- path: .env
|
|
67
71
|
required: true
|
|
@@ -80,6 +84,10 @@ services:
|
|
|
80
84
|
# chmod 600 jwt-private.pem
|
|
81
85
|
- jwt_private_key
|
|
82
86
|
- jwt_public_key
|
|
87
|
+
# The client registry (#705), for the same reason: `config/clients.yaml`
|
|
88
|
+
# is per-deployment and may hold client secrets, so it is kept out of the
|
|
89
|
+
# image and mounted here. REPOSITORIES_CLIENT_YAML_PATH below points the process at it.
|
|
90
|
+
- client_registry
|
|
83
91
|
environment:
|
|
84
92
|
NODE_ENV: production
|
|
85
93
|
# One replica. Under `single` the replica-safety guard is SILENT by
|
|
@@ -88,7 +96,7 @@ services:
|
|
|
88
96
|
# why the adapter block further down states every one of them explicitly
|
|
89
97
|
# instead of leaving them to inherit. Before `--scale app=N`, set `multi`
|
|
90
98
|
# and read the README's "Multi-replica deployments".
|
|
91
|
-
|
|
99
|
+
CORE_DEPLOYMENT_MODE: single
|
|
92
100
|
# Behind the TLS terminator this file assumes, `req.ip` is the proxy's
|
|
93
101
|
# address and `req.protocol` reads `http` until this names the hop. The
|
|
94
102
|
# README calls it required for exactly that reason, and the cost of
|
|
@@ -109,32 +117,33 @@ services:
|
|
|
109
117
|
HTTP_TRUST_PROXY: ${HTTP_TRUST_PROXY:?set to your TLS terminator's address or CIDR range (e.g. 10.0.0.0/8, or `loopback` for a same-host sidecar) — never `true` behind an open network}
|
|
110
118
|
# Point the process at the mounted secrets rather than the working-copy
|
|
111
119
|
# paths `.env` carries for local runs.
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
KEY_STORE_LOCAL_PRIVATE_KEY_PATH: /run/secrets/jwt_private_key
|
|
121
|
+
KEY_STORE_LOCAL_PUBLIC_KEY_PATH: /run/secrets/jwt_public_key
|
|
122
|
+
REPOSITORIES_CLIENT_YAML_PATH: /run/secrets/client_registry
|
|
114
123
|
# `environment` wins over `env_file`, which is the point here:
|
|
115
|
-
# `.env.example` ships
|
|
124
|
+
# `.env.example` ships SESSION_STORE_SECURE=false / SESSION_STORE_NAME=auth.sid so a
|
|
116
125
|
# plain-HTTP local run works, and this file requires that same `.env`.
|
|
117
126
|
# Behind the TLS this compose assumes, a non-Secure session cookie is the
|
|
118
127
|
# session handed to anyone who can read one plaintext hop. The default
|
|
119
128
|
# `__Host-` cookie name is restored with it — the prefix browsers only
|
|
120
129
|
# honour on a Secure cookie.
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
SESSION_STORE_SECURE: "true"
|
|
131
|
+
SESSION_STORE_NAME: __Host-auth.session
|
|
123
132
|
# Every Redis-backed store shares the compose-network Redis below.
|
|
124
133
|
#
|
|
125
134
|
# These are stated in full rather than inherited from
|
|
126
|
-
# `config/
|
|
135
|
+
# `config/reference.conf`, so that the deployable file names its own
|
|
127
136
|
# topology: an operator reading only this one can see which stores
|
|
128
|
-
# survive a restart. `
|
|
129
|
-
# `
|
|
130
|
-
#
|
|
137
|
+
# survive a restart. `ADAPTERS_CODE_REPOSITORY` and
|
|
138
|
+
# `ADAPTERS_ACCESS_TOKEN_DENYLIST` already ship as `redis` in that file
|
|
139
|
+
# and are left there on purpose — restating a value that agrees is
|
|
131
140
|
# a second place to forget to change.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
141
|
+
REDIS_CLIENTS_URL: redis://redis:6379
|
|
142
|
+
SESSION_STORE_STORAGE_TYPE: redis
|
|
143
|
+
SESSION_STORE_STORAGE_REDIS_URL: redis://redis:6379
|
|
135
144
|
# The UserSession stores: the provider's own record of who is signed in,
|
|
136
|
-
#
|
|
137
|
-
#
|
|
145
|
+
# the subject index and revocation boundaries beside it, and the session
|
|
146
|
+
# lifecycle records. They MUST be on Redis whenever the express-session
|
|
138
147
|
# store above is, and this line is the fix for what happens when they
|
|
139
148
|
# are not.
|
|
140
149
|
#
|
|
@@ -145,13 +154,16 @@ services:
|
|
|
145
154
|
# authenticated session, finds no user session behind it, and sends the
|
|
146
155
|
# browser to log in again, where the still-valid cookie puts it straight
|
|
147
156
|
# back. A login loop that clears only when the user deletes the cookie.
|
|
148
|
-
# `
|
|
157
|
+
# `CORE_DEPLOYMENT_MODE: single` says nothing about it: the replica guard
|
|
149
158
|
# answers "can these stores be shared", not "do these two stores have the
|
|
150
159
|
# same lifetime".
|
|
151
|
-
|
|
160
|
+
ADAPTERS_USER_SESSION_STORES: redis
|
|
152
161
|
# The memory rate limiter is per-process and evadable under bucket
|
|
153
162
|
# exhaustion (see README) — production points it at Redis.
|
|
154
|
-
|
|
163
|
+
ADAPTERS_RATE_LIMITER: redis
|
|
164
|
+
# The counter behind the login's own attempt limit: on Redis, a restart
|
|
165
|
+
# does not reset it. Redis must keep `maxmemory-policy noeviction`.
|
|
166
|
+
ADAPTERS_ATTEMPT_COUNTER: redis
|
|
155
167
|
# The federation token store is deliberately left at its `memory`
|
|
156
168
|
# default, and that is coherent here rather than an oversight: this
|
|
157
169
|
# template ships every federation disabled, so nothing writes to the
|
|
@@ -159,8 +171,24 @@ services:
|
|
|
159
171
|
# (REDIS_FEDERATION_TOKEN_STORE_ENCRYPTION_KEY) that this file must not
|
|
160
172
|
# invent — the records are long-lived upstream refresh tokens. Enabling
|
|
161
173
|
# a federation means setting BOTH, together:
|
|
162
|
-
#
|
|
174
|
+
# ADAPTERS_FEDERATION_TOKEN_STORE: redis
|
|
163
175
|
# REDIS_FEDERATION_TOKEN_STORE_ENCRYPTION_KEY: <openssl rand -base64 32, from .env>
|
|
176
|
+
#
|
|
177
|
+
# MFA is on by default (MFA_MODE, `required`): every password login
|
|
178
|
+
# needs a second factor. Its two stores are left at their `memory`
|
|
179
|
+
# default, which the template refuses in production before boot; that
|
|
180
|
+
# refusal names everything MFA needs and the opt-out, so it is the first
|
|
181
|
+
# thing a deployment that has decided nothing about MFA meets. Decide in
|
|
182
|
+
# `.env`: either turn it on with all of
|
|
183
|
+
# ADAPTERS_MFA_FACTOR_STORE=redis (or `store`, the factors in your Store)
|
|
184
|
+
# ADAPTERS_MFA_TRANSACTION_STORE=redis
|
|
185
|
+
# MFA_ENCRYPTION_KEY=<openssl rand -base64 32>
|
|
186
|
+
# STANDARD_SMTP_MAIL_SENDER_HOST=... and STANDARD_SMTP_MAIL_SENDER_FROM=...
|
|
187
|
+
# MFA_PAGE_URL=<your MFA page, /mfa by default>
|
|
188
|
+
# or keep the provider without MFA:
|
|
189
|
+
# MFA_MODE=off
|
|
190
|
+
# The Redis below persists (appendonly), as the MFA stores need: a lost
|
|
191
|
+
# factor lets whoever holds the password bind one of their own.
|
|
164
192
|
|
|
165
193
|
redis:
|
|
166
194
|
# Tag-pinned, not digest-pinned. The Dockerfile argues for digests (#289)
|
|
@@ -189,10 +217,13 @@ volumes:
|
|
|
189
217
|
redis-data:
|
|
190
218
|
|
|
191
219
|
secrets:
|
|
192
|
-
# File-backed, so the pem pair
|
|
193
|
-
# read-only at /run/secrets. Keep
|
|
194
|
-
# committed or COPYed into the image is a key you
|
|
220
|
+
# File-backed, so the pem pair and the client registry stay on the host and
|
|
221
|
+
# reach the container read-only at /run/secrets. Keep them out of git
|
|
222
|
+
# alongside `.env`; a key committed or COPYed into the image is a key you
|
|
223
|
+
# have to rotate.
|
|
195
224
|
jwt_private_key:
|
|
196
225
|
file: ./jwt-private.pem
|
|
197
226
|
jwt_public_key:
|
|
198
227
|
file: ./jwt-public.pem
|
|
228
|
+
client_registry:
|
|
229
|
+
file: ./config/clients.yaml
|
|
@@ -8,11 +8,11 @@ services:
|
|
|
8
8
|
volumes:
|
|
9
9
|
- ./src:/home/node/src
|
|
10
10
|
- ./config:/home/node/config
|
|
11
|
-
#
|
|
11
|
+
# Compose's default grace is ten seconds — the HTTP drain
|
|
12
12
|
# budget alone. With federation grants on, `src/app.mts` gives cleanup 45
|
|
13
13
|
# more for the drain of a rotated upstream credential's write, and SIGKILL
|
|
14
14
|
# has to arrive after that: drain (10) + cleanup (45) + an exit margin.
|
|
15
|
-
# The cleanup allowance grows by itself with `
|
|
15
|
+
# The cleanup allowance grows by itself with `federation-grants.upstreamHardTimeoutMs`,
|
|
16
16
|
# `persistRetryBudgetMs` and `lockWaitMs`; raise this to match when you raise them.
|
|
17
17
|
stop_grace_period: 60s
|
|
18
18
|
depends_on:
|
|
@@ -37,7 +37,17 @@ services:
|
|
|
37
37
|
# debug it. Redis is already running and already required by three other
|
|
38
38
|
# stores, so this costs nothing: the shared ioredis socket is open
|
|
39
39
|
# either way.
|
|
40
|
-
|
|
40
|
+
ADAPTERS_USER_SESSION_STORES: redis
|
|
41
|
+
# MFA is on by default (MFA_MODE). Its two stores ship in memory, which
|
|
42
|
+
# this run would empty on every save: every enrolled factor gone while
|
|
43
|
+
# the sessions above survive, so each password login after a save binds
|
|
44
|
+
# a factor anew. On the Redis above they last as the sessions do. These
|
|
45
|
+
# lines, like ADAPTERS_USER_SESSION_STORES above, override `.env`:
|
|
46
|
+
# compose's `environment:` wins over `env_file`. The key ring is
|
|
47
|
+
# config/development.conf's sample key and the mail sender logs each
|
|
48
|
+
# code; MFA_MODE=off in .env runs without MFA.
|
|
49
|
+
ADAPTERS_MFA_FACTOR_STORE: redis
|
|
50
|
+
ADAPTERS_MFA_TRANSACTION_STORE: redis
|
|
41
51
|
|
|
42
52
|
redis:
|
|
43
53
|
# Tag-pinned, not digest-pinned. The Dockerfile argues for digests (#289)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@o3co/auth-provider-standalone",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0-rc.2",
|
|
4
4
|
"private": true,
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"engines": {
|
|
@@ -26,9 +26,11 @@
|
|
|
26
26
|
"@o3co/auth-provider-federation-grants": "workspace:*",
|
|
27
27
|
"@o3co/auth-provider-federation-oidc": "workspace:*",
|
|
28
28
|
"@o3co/auth-provider-foundation": "workspace:*",
|
|
29
|
+
"@o3co/auth-provider-mfa": "workspace:*",
|
|
29
30
|
"@o3co/auth-provider-oauth": "workspace:*",
|
|
30
31
|
"@o3co/auth-provider-redis": "workspace:*",
|
|
31
32
|
"@o3co/auth-provider-session": "workspace:*",
|
|
33
|
+
"@o3co/auth-provider-standard": "workspace:*",
|
|
32
34
|
"@o3co/ts.hocon": "^1.13.0",
|
|
33
35
|
"connect-redis": "^10.0.0",
|
|
34
36
|
"express": "^5.2.1",
|
|
@@ -37,16 +39,17 @@
|
|
|
37
39
|
"ioredis": "^6.0.0",
|
|
38
40
|
"pino": "^10.3.1",
|
|
39
41
|
"prom-client": "^15.1.3",
|
|
40
|
-
"redis": "^6.2.1"
|
|
42
|
+
"redis": "^6.2.1",
|
|
43
|
+
"zod": "^4.6.5"
|
|
41
44
|
},
|
|
42
45
|
"devDependencies": {
|
|
43
46
|
"@types/express": "^5.0.6",
|
|
44
47
|
"@types/express-session": "^1",
|
|
45
|
-
"@types/node": "^26.
|
|
48
|
+
"@types/node": "^26.6.3",
|
|
46
49
|
"@types/supertest": "^7.2.1",
|
|
47
|
-
"supertest": "^7.
|
|
48
|
-
"tsx": "^4.23.
|
|
50
|
+
"supertest": "^7.3.0",
|
|
51
|
+
"tsx": "^4.23.15",
|
|
49
52
|
"typescript": "^6.0.3",
|
|
50
|
-
"vitest": "^5.0.
|
|
53
|
+
"vitest": "^5.0.2"
|
|
51
54
|
}
|
|
52
55
|
}
|