rst-auth 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/CODE_OF_CONDUCT.md +73 -0
- package/CONTRIBUTING.md +35 -0
- package/LICENSE +21 -0
- package/README.md +212 -2
- package/SECURITY.md +13 -0
- package/dist/config.d.ts +59 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +187 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +54 -0
- package/dist/errors.js.map +1 -0
- package/dist/express/index.d.ts +74 -0
- package/dist/express/index.d.ts.map +1 -0
- package/dist/express/index.js +185 -0
- package/dist/express/index.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-refresh-token-store.d.ts +15 -0
- package/dist/memory-refresh-token-store.d.ts.map +1 -0
- package/dist/memory-refresh-token-store.js +75 -0
- package/dist/memory-refresh-token-store.js.map +1 -0
- package/dist/password.d.ts +7 -0
- package/dist/password.d.ts.map +1 -0
- package/dist/password.js +36 -0
- package/dist/password.js.map +1 -0
- package/dist/refresh-store.d.ts +48 -0
- package/dist/refresh-store.d.ts.map +1 -0
- package/dist/refresh-store.js +2 -0
- package/dist/refresh-store.js.map +1 -0
- package/dist/refresh.d.ts +27 -0
- package/dist/refresh.d.ts.map +1 -0
- package/dist/refresh.js +93 -0
- package/dist/refresh.js.map +1 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/refresh-store-conformance.d.ts +11 -0
- package/dist/testing/refresh-store-conformance.d.ts.map +1 -0
- package/dist/testing/refresh-store-conformance.js +110 -0
- package/dist/testing/refresh-store-conformance.js.map +1 -0
- package/dist/tokens.d.ts +15 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +90 -0
- package/dist/tokens.js.map +1 -0
- package/dist/validation.d.ts +7 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +2 -0
- package/dist/validation.js.map +1 -0
- package/dist/zod/index.d.ts +5 -0
- package/dist/zod/index.d.ts.map +1 -0
- package/dist/zod/index.js +22 -0
- package/dist/zod/index.js.map +1 -0
- package/docs/access-tokens.md +15 -0
- package/docs/before-first-release.md +31 -0
- package/docs/claims.md +40 -0
- package/docs/configuration.md +30 -0
- package/docs/cookies-vs-bearer.md +82 -0
- package/docs/error-handling.md +15 -0
- package/docs/installation.md +39 -0
- package/docs/middleware.md +24 -0
- package/docs/migration.md +17 -0
- package/docs/passwords.md +23 -0
- package/docs/refresh-tokens.md +47 -0
- package/docs/security.md +16 -0
- package/docs/validation.md +24 -0
- package/package.json +91 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to rst-auth are recorded here.
|
|
4
|
+
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
- Added a standalone HTML/CSS/JavaScript documentation site and GitHub Pages deployment workflow.
|
|
8
|
+
- Added a browser-based auth flow demo to the Express example.
|
|
9
|
+
- Added a TypeScript Express API example that is installed from an npm pack tarball.
|
|
10
|
+
- Added usage, security, migration, contribution, reporting, and first-release documentation.
|
|
11
|
+
- Added Node 22/24 CI checks and example integration tests.
|
|
12
|
+
|
|
13
|
+
## 0.1.0 - 2026-10-16
|
|
14
|
+
|
|
15
|
+
- Initial alpha API for password hashing, access tokens, and opaque refresh-token rotation.
|
|
16
|
+
- Added Express 4/5 and Zod subpath adapters plus refresh-store conformance utilities.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
|
|
6
|
+
|
|
7
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
|
8
|
+
|
|
9
|
+
## Our Standards
|
|
10
|
+
|
|
11
|
+
Examples of behavior that contributes to a positive environment for our community include:
|
|
12
|
+
|
|
13
|
+
- Demonstrating empathy and kindness toward other people.
|
|
14
|
+
- Being respectful of differing opinions, viewpoints, and experiences.
|
|
15
|
+
- Giving and gracefully accepting constructive feedback.
|
|
16
|
+
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience.
|
|
17
|
+
- Focusing on what is best not just for us as individuals, but for the overall community.
|
|
18
|
+
|
|
19
|
+
Examples of unacceptable behavior include:
|
|
20
|
+
|
|
21
|
+
- The use of sexualized language or imagery, and sexual attention or advances of any kind.
|
|
22
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks.
|
|
23
|
+
- Public or private harassment.
|
|
24
|
+
- Publishing others' private information, such as a physical or email address, without their explicit permission.
|
|
25
|
+
- Other conduct which could reasonably be considered inappropriate in a professional setting.
|
|
26
|
+
|
|
27
|
+
## Enforcement Responsibilities
|
|
28
|
+
|
|
29
|
+
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
|
30
|
+
|
|
31
|
+
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
|
32
|
+
|
|
33
|
+
## Scope
|
|
34
|
+
|
|
35
|
+
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
|
36
|
+
|
|
37
|
+
## Enforcement
|
|
38
|
+
|
|
39
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at the private contact route listed in the repository's `SECURITY.md` or repository moderation settings. All complaints will be reviewed and investigated promptly and fairly.
|
|
40
|
+
|
|
41
|
+
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
|
42
|
+
|
|
43
|
+
## Enforcement Guidelines
|
|
44
|
+
|
|
45
|
+
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
|
46
|
+
|
|
47
|
+
### 1. Correction
|
|
48
|
+
|
|
49
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
|
50
|
+
|
|
51
|
+
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
|
52
|
+
|
|
53
|
+
### 2. Warning
|
|
54
|
+
|
|
55
|
+
**Community Impact**: A violation through a single incident or series of actions.
|
|
56
|
+
|
|
57
|
+
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period. This includes avoiding interactions in community spaces, as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
|
58
|
+
|
|
59
|
+
### 3. Temporary Ban
|
|
60
|
+
|
|
61
|
+
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
|
|
62
|
+
|
|
63
|
+
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
|
64
|
+
|
|
65
|
+
### 4. Permanent Ban
|
|
66
|
+
|
|
67
|
+
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
|
68
|
+
|
|
69
|
+
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
|
70
|
+
|
|
71
|
+
## Attribution
|
|
72
|
+
|
|
73
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping improve rst-auth. The project is alpha software and prioritizes clear security boundaries, small APIs, and honest documentation.
|
|
4
|
+
|
|
5
|
+
## Before opening a change
|
|
6
|
+
|
|
7
|
+
- Read the relevant design and security documentation in `docs/` before changing behavior.
|
|
8
|
+
- Keep user models, DB queries, routes, controllers, and business rules in the application layer.
|
|
9
|
+
- Do not add real credentials, publish packages, or push directly to the upstream default branch. Use a fork and pull request; do not claim production readiness.
|
|
10
|
+
- Every security or feature claim in README must map to a named test in `docs/claims.md`.
|
|
11
|
+
- Never accept a client-supplied privilege or role during signup.
|
|
12
|
+
|
|
13
|
+
## Development checks
|
|
14
|
+
|
|
15
|
+
Use Node 22 or 24 and npm. From the repository root run:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm ci
|
|
19
|
+
npm run build
|
|
20
|
+
npm test
|
|
21
|
+
npm run lint
|
|
22
|
+
npm run typecheck
|
|
23
|
+
npm run format:check
|
|
24
|
+
npm pack --dry-run
|
|
25
|
+
npm run example:install
|
|
26
|
+
npm --prefix examples/express-api run typecheck
|
|
27
|
+
npm --prefix examples/express-api test
|
|
28
|
+
npm --prefix examples/express-api run import-check
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The example install command packs this project and installs the generated tarball into the example. Do not change the example to import source files from `src/`.
|
|
32
|
+
|
|
33
|
+
## Pull requests
|
|
34
|
+
|
|
35
|
+
Explain the user-visible behavior, security consequences, tests, docs, and compatibility impact. Include focused tests for bug fixes and new claims. Keep PRs small enough to review. Maintainers may request changes or decline work outside the project scope. By contributing, you agree to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sayed Risat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,213 @@
|
|
|
1
|
-
#
|
|
1
|
+
# RST-Auth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**[Documentation site](https://sayedrisat.github.io/rst-auth/)** · [GitHub repository](https://github.com/sayedrisat/rst-auth)
|
|
4
|
+
|
|
5
|
+
**Complex authentication. Simple methods. Full control. Open source.**
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
`RST-Auth` is an alpha TypeScript toolkit for Node.js 22+ applications. It provides password hashing, access tokens, stateful refresh-token rotation, and optional Express and Zod adapters. Your application owns its users, database, routes, business rules, and responses.
|
|
10
|
+
|
|
11
|
+
## Problem
|
|
12
|
+
|
|
13
|
+
Authentication code is easy to get subtly wrong, while full authentication frameworks may own user models, database tables, and application flows. This package focuses on reusable security mechanics and leaves application-specific decisions with the developer.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- `bcryptjs` password hashing, 72-byte input checks, and dummy verification.
|
|
18
|
+
- `jose` access tokens with configured algorithms, issuer/audience checks, key resolution, and optional revocation lookup.
|
|
19
|
+
- Opaque refresh tokens with atomic store consumption, rotation, family revocation, and reuse detection.
|
|
20
|
+
- Express 4 and 5 authentication, role authorization, validation, and safe error middleware.
|
|
21
|
+
- Zod adapter and a framework-agnostic refresh-store conformance suite.
|
|
22
|
+
- Injected configuration; the library does not read `process.env`.
|
|
23
|
+
|
|
24
|
+
Feature and security claims are mapped to named tests in [docs/claims.md](docs/claims.md).
|
|
25
|
+
|
|
26
|
+
## Security philosophy
|
|
27
|
+
|
|
28
|
+
The library handles reusable primitives and validates configuration. The application decides who a user is, what a role means, where data is stored, how sessions are delivered, and which HTTP response to return. Tokens are secrets: keep them out of logs and URLs. A valid access token does not establish that its subject still exists or remains enabled, and token-carried roles may be stale.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
npm install rst-auth
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Core password, token, and refresh APIs need no framework peer. For the optional integrations, install the peers you use:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
npm install express zod
|
|
40
|
+
npm install --save-dev @types/express
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
See [installation](docs/installation.md) for Node and package details.
|
|
44
|
+
|
|
45
|
+
## Minimal setup
|
|
46
|
+
|
|
47
|
+
Configuration belongs in your application's config layer. Never commit a real signing secret.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { createAuth } from "rst-auth";
|
|
51
|
+
|
|
52
|
+
const secret = process.env.ACCESS_TOKEN_SECRET;
|
|
53
|
+
if (!secret || Buffer.byteLength(secret, "utf8") < 32) {
|
|
54
|
+
throw new Error("Set ACCESS_TOKEN_SECRET to at least 32 bytes");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const auth = createAuth({
|
|
58
|
+
accessToken: {
|
|
59
|
+
key: new TextEncoder().encode(secret),
|
|
60
|
+
issuer: "my-service",
|
|
61
|
+
audience: "my-api",
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Passwords
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
const passwordHash = await auth.password.hash(password);
|
|
70
|
+
const matches = await auth.password.verify(password, passwordHash);
|
|
71
|
+
|
|
72
|
+
// When no user exists, do a dummy comparison before returning the same login error.
|
|
73
|
+
if (!user) await auth.password.verifyDummy(password);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Passwords above 72 UTF-8 bytes are rejected because bcrypt truncates longer inputs. The default work factor is 12; benchmark it on the deployment hardware because hashing and `createAuth()` startup work increase with the setting. See [passwords](docs/passwords.md).
|
|
77
|
+
|
|
78
|
+
## Access tokens
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const token = await auth.tokens.generateAccessToken({
|
|
82
|
+
sub: user.id,
|
|
83
|
+
role: user.role,
|
|
84
|
+
});
|
|
85
|
+
const verifiedClaims = await auth.tokens.verifyAccessToken(token);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The verifier uses the configured algorithm allowlist and validates signature, expiry, issuer/audience when configured, required claims, and token type. See [access tokens](docs/access-tokens.md).
|
|
89
|
+
|
|
90
|
+
## Refresh tokens
|
|
91
|
+
|
|
92
|
+
Refresh support requires a store. The built-in `MemoryRefreshTokenStore` is for tests and local demonstrations only; it is not a production persistence option.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { createAuth, MemoryRefreshTokenStore } from "rst-auth";
|
|
96
|
+
|
|
97
|
+
const auth = createAuth({
|
|
98
|
+
accessToken: { key: new TextEncoder().encode(secret) },
|
|
99
|
+
refreshToken: {
|
|
100
|
+
store: new MemoryRefreshTokenStore(), // Use a shared persistent store in deployed services.
|
|
101
|
+
refreshTokenTtl: 60 * 60 * 24 * 7,
|
|
102
|
+
absoluteLifetime: 60 * 60 * 24 * 30,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const issued = await auth.refresh!.issue({ subject: user.id });
|
|
107
|
+
const next = await auth.refresh!.rotate(issued.refreshToken);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The application creates an access token from the returned subject and its current user/permission data. Rotation consumes a stored hash atomically; presenting a consumed token revokes its family. Read [refresh tokens](docs/refresh-tokens.md) before implementing a store.
|
|
111
|
+
|
|
112
|
+
## Express middleware
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { expressAuth } from "rst-auth/express";
|
|
116
|
+
|
|
117
|
+
const middleware = expressAuth(auth);
|
|
118
|
+
app.get("/profile", middleware.authenticate(), profileController);
|
|
119
|
+
app.delete(
|
|
120
|
+
"/admin/users/:id",
|
|
121
|
+
middleware.authenticate(),
|
|
122
|
+
middleware.authorize({ roles: ["admin"] }),
|
|
123
|
+
deleteUserController,
|
|
124
|
+
);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Authentication defaults to strict `Authorization: Bearer` parsing. Optional auth is available with `authenticate({ required: false })`; a present invalid token still fails. See [middleware](docs/middleware.md).
|
|
128
|
+
|
|
129
|
+
## Validation
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { expressAuth } from "rst-auth/express";
|
|
133
|
+
import { zodAdapter } from "rst-auth/zod";
|
|
134
|
+
|
|
135
|
+
const middleware = expressAuth(auth, { validator: zodAdapter() });
|
|
136
|
+
app.post(
|
|
137
|
+
"/items",
|
|
138
|
+
middleware.validate({ body: itemSchema }),
|
|
139
|
+
createItemController,
|
|
140
|
+
);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Parsed values are placed on `req.validated`; `req.body`, `req.params`, and `req.query` are not silently replaced. See [validation](docs/validation.md).
|
|
144
|
+
|
|
145
|
+
## Errors
|
|
146
|
+
|
|
147
|
+
`AuthError` exposes a stable code, developer message, safe public message, status, and optional cause. The Express error handler emits only safe fields by default; an application may provide a formatter. See [error handling](docs/error-handling.md).
|
|
148
|
+
|
|
149
|
+
## Configuration reference
|
|
150
|
+
|
|
151
|
+
| Setting | Purpose | Default / constraint |
|
|
152
|
+
| ---------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------ |
|
|
153
|
+
| `mode` | Runtime validation profile | `development`; `production` requires issuer and audience and access expiry <= 1 hour |
|
|
154
|
+
| `password.workFactor` | bcrypt cost | `12`, integer 4–31 |
|
|
155
|
+
| `accessToken.key` | Signing key | Required; HMAC keys need at least 32 bytes |
|
|
156
|
+
| `accessToken.algorithm` | Signing algorithm | `HS256`; supported JOSE algorithms are explicitly listed in config types |
|
|
157
|
+
| `accessToken.algorithms` | Verification allowlist | Signing algorithm by default; must contain it |
|
|
158
|
+
| `accessToken.issuer`, `audience` | JWT issuer/audience checks | Optional outside production |
|
|
159
|
+
| `accessToken.expiresInSeconds` | Access-token lifetime | `900` seconds |
|
|
160
|
+
| `accessToken.keyId`, `keyResolver` | Key rotation support | Optional; resolver requires a `kid` |
|
|
161
|
+
| `accessToken.requiredClaims` | Additional required JWT claims | `sub`, `iat`, and `exp` are required automatically |
|
|
162
|
+
| `accessToken.isRevoked` | Stateful verification check | Optional; callback latency/availability is part of each verification |
|
|
163
|
+
| `refreshToken.store` | Atomic refresh-token state | Omit to disable refresh support |
|
|
164
|
+
| `refreshToken.refreshTokenTtl` | Idle refresh expiry | Required when refresh is enabled, in seconds |
|
|
165
|
+
| `refreshToken.absoluteLifetime` | Family lifetime cap | Required when refresh is enabled, in seconds |
|
|
166
|
+
|
|
167
|
+
See [configuration](docs/configuration.md) for validation details and asymmetric-key examples.
|
|
168
|
+
|
|
169
|
+
## TypeScript
|
|
170
|
+
|
|
171
|
+
The package ships declarations and strict public types. `req.auth` and `req.validated` are augmented when the Express subpath is imported. For schema-specific parsed values, use the exported `ValidatedRequest<TSchemas>` type. Install `@types/express` when using the Express integration.
|
|
172
|
+
|
|
173
|
+
## Database integration model
|
|
174
|
+
|
|
175
|
+
The toolkit does not create a user table or issue database queries. Your repository/controller code stores password hashes and looks up users. Refresh support uses the `RefreshTokenStore` interface; implement it with your own persistence and atomic compare-and-swap operation, then run the `rst-auth/testing` conformance suite against it. See [installation](docs/installation.md#database-integration-model) and [refresh tokens](docs/refresh-tokens.md).
|
|
176
|
+
|
|
177
|
+
## Limitations
|
|
178
|
+
|
|
179
|
+
This is alpha software, not a security audit or a complete identity system. It does not provide a production refresh store, user/session database, OAuth, MFA, account lockout, password reset, email verification, CORS policy, rate limiting, or CSRF protection. The memory refresh store is process-local. A token's roles can be stale unless the app performs current identity/permission checks. See [security](docs/security.md).
|
|
180
|
+
|
|
181
|
+
## Testing
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
npm ci
|
|
185
|
+
npm run build
|
|
186
|
+
npm test
|
|
187
|
+
npm run lint
|
|
188
|
+
npm run typecheck
|
|
189
|
+
npm run format:check
|
|
190
|
+
npm pack --dry-run
|
|
191
|
+
npm run example:install
|
|
192
|
+
npm --prefix examples/express-api run typecheck
|
|
193
|
+
npm --prefix examples/express-api test
|
|
194
|
+
npm --prefix examples/express-api run import-check
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The example installer creates a package tarball and installs that tarball into the example; it does not import source files from this repository. CI checks Node 22 and 24.
|
|
198
|
+
|
|
199
|
+
## Contributing
|
|
200
|
+
|
|
201
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md), keep every documented security/feature claim connected to a test, and run all quality gates before proposing changes. The project follows the [Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities using [SECURITY.md](SECURITY.md), not a public issue.
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
MIT; Copyright (c) 2026 Sayed Risat. See [LICENSE](LICENSE).
|
|
206
|
+
|
|
207
|
+
## Project status
|
|
208
|
+
|
|
209
|
+
Version `0.1.0` is an alpha under active development. Public API names, policies, and docs may change before a stable release. No production-readiness claim is made.
|
|
210
|
+
|
|
211
|
+
## Comparison
|
|
212
|
+
|
|
213
|
+
This is a README-level comparison based on this project's checked-in competitive review, not an independent source audit. The reviewed JWT utility examples generally describe issuing new stateless JWTs on refresh without documented stored-token reuse detection; this package instead requires server-side refresh state and atomic consume for rotation. Broader authentication frameworks may manage schemas and migrations; this package leaves database schema and queries to the application. `express-jwt` focuses on middleware rather than passwords, refresh rotation, or validation. The reviewed analysis did not verify every package in the market, so these points describe only that review's scope and are not universal claims.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security reports are accepted for the current alpha release line. Alpha software may change without a migration path and has not received an independent security audit.
|
|
6
|
+
|
|
7
|
+
## Reporting a vulnerability privately
|
|
8
|
+
|
|
9
|
+
Please do not open a public issue or pull request for a suspected vulnerability. If GitHub private vulnerability reporting is enabled for this repository, use **Security → Report a vulnerability** to submit a private advisory. If it is not enabled, contact the maintainers through the repository's private contact channel and ask them to provide a secure reporting route; do not include exploit details in a public issue.
|
|
10
|
+
|
|
11
|
+
Include the affected version/commit, impact, reproduction steps, and any suggested mitigation. Do not include real user data, tokens, or production secrets. The maintainers will acknowledge receipt and coordinate a fix and disclosure timeline with the reporter.
|
|
12
|
+
|
|
13
|
+
Before the first public release, maintainers must enable and verify a private reporting route in the repository settings.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { CompactJWSHeaderParameters, KeyInput } from "jose";
|
|
2
|
+
import type { RefreshTokenStore } from "./refresh-store.js";
|
|
3
|
+
export declare const DEFAULT_BCRYPT_ROUNDS = 12;
|
|
4
|
+
export declare const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 900;
|
|
5
|
+
export declare const SUPPORTED_ALGORITHMS: readonly ["HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512", "EdDSA"];
|
|
6
|
+
export type SupportedAlgorithm = (typeof SUPPORTED_ALGORITHMS)[number];
|
|
7
|
+
export type RuntimeMode = "development" | "production";
|
|
8
|
+
export type TokenKey = KeyInput;
|
|
9
|
+
export type KeyResolver = (header: CompactJWSHeaderParameters) => TokenKey | Promise<TokenKey>;
|
|
10
|
+
export interface AuthConfig {
|
|
11
|
+
mode?: RuntimeMode;
|
|
12
|
+
password?: {
|
|
13
|
+
workFactor?: number;
|
|
14
|
+
};
|
|
15
|
+
accessToken: {
|
|
16
|
+
algorithm?: SupportedAlgorithm;
|
|
17
|
+
algorithms?: readonly SupportedAlgorithm[];
|
|
18
|
+
key: TokenKey;
|
|
19
|
+
keyId?: string;
|
|
20
|
+
keyResolver?: KeyResolver;
|
|
21
|
+
issuer?: string;
|
|
22
|
+
audience?: string | readonly string[];
|
|
23
|
+
expiresInSeconds?: number;
|
|
24
|
+
requiredClaims?: readonly string[];
|
|
25
|
+
isRevoked?: (claims: Readonly<Record<string, unknown>>, context?: unknown) => boolean | Promise<boolean>;
|
|
26
|
+
};
|
|
27
|
+
/** Omit to disable refresh-token support. A configured refresh store is mandatory. */
|
|
28
|
+
refreshToken?: {
|
|
29
|
+
store: RefreshTokenStore;
|
|
30
|
+
refreshTokenTtl: number;
|
|
31
|
+
absoluteLifetime: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface ValidatedAuthConfig {
|
|
35
|
+
mode: RuntimeMode;
|
|
36
|
+
password: {
|
|
37
|
+
workFactor: number;
|
|
38
|
+
};
|
|
39
|
+
accessToken: {
|
|
40
|
+
algorithm: SupportedAlgorithm;
|
|
41
|
+
algorithms: readonly SupportedAlgorithm[];
|
|
42
|
+
key: TokenKey;
|
|
43
|
+
keyId?: string;
|
|
44
|
+
keyResolver?: KeyResolver;
|
|
45
|
+
issuer?: string;
|
|
46
|
+
audience?: string | readonly string[];
|
|
47
|
+
expiresInSeconds: number;
|
|
48
|
+
requiredClaims: readonly string[];
|
|
49
|
+
isRevoked?: AuthConfig["accessToken"]["isRevoked"];
|
|
50
|
+
};
|
|
51
|
+
refreshToken?: {
|
|
52
|
+
store: RefreshTokenStore;
|
|
53
|
+
refreshTokenTtl: number;
|
|
54
|
+
absoluteLifetime: number;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export declare function isReservedClaim(name: string): boolean;
|
|
58
|
+
export declare function validateAuthConfig(config: AuthConfig): ValidatedAuthConfig;
|
|
59
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAEpD,eAAO,MAAM,oBAAoB,gIAcvB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACvE,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,YAAY,CAAC;AACvD,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAChC,MAAM,MAAM,WAAW,GAAG,CACxB,MAAM,EAAE,0BAA0B,KAC/B,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElC,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,WAAW,EAAE;QACX,SAAS,CAAC,EAAE,kBAAkB,CAAC;QAC/B,UAAU,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;QAC3C,GAAG,EAAE,QAAQ,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,WAAW,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;QACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACnC,SAAS,CAAC,EAAE,CACV,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,OAAO,CAAC,EAAE,OAAO,KACd,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KACjC,CAAC;IACF,sFAAsF;IACtF,YAAY,CAAC,EAAE;QACb,KAAK,EAAE,iBAAiB,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,WAAW,EAAE;QACX,SAAS,EAAE,kBAAkB,CAAC;QAC9B,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;QAC1C,GAAG,EAAE,QAAQ,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,WAAW,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;QACtC,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;QAClC,SAAS,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,WAAW,CAAC,CAAC;KACpD,CAAC;IACF,YAAY,CAAC,EAAE;QACb,KAAK,EAAE,iBAAiB,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAYD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAqBD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,mBAAmB,CAqL1E"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { AuthError } from "./errors.js";
|
|
2
|
+
export const DEFAULT_BCRYPT_ROUNDS = 12;
|
|
3
|
+
export const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 900;
|
|
4
|
+
const MAX_REFRESH_LIFETIME_SECONDS = 8_000_000_000_000;
|
|
5
|
+
export const SUPPORTED_ALGORITHMS = [
|
|
6
|
+
"HS256",
|
|
7
|
+
"HS384",
|
|
8
|
+
"HS512",
|
|
9
|
+
"RS256",
|
|
10
|
+
"RS384",
|
|
11
|
+
"RS512",
|
|
12
|
+
"PS256",
|
|
13
|
+
"PS384",
|
|
14
|
+
"PS512",
|
|
15
|
+
"ES256",
|
|
16
|
+
"ES384",
|
|
17
|
+
"ES512",
|
|
18
|
+
"EdDSA",
|
|
19
|
+
];
|
|
20
|
+
const RESERVED_CLAIMS = new Set([
|
|
21
|
+
"iss",
|
|
22
|
+
"aud",
|
|
23
|
+
"exp",
|
|
24
|
+
"iat",
|
|
25
|
+
"nbf",
|
|
26
|
+
"jti",
|
|
27
|
+
"token_use",
|
|
28
|
+
]);
|
|
29
|
+
export function isReservedClaim(name) {
|
|
30
|
+
return RESERVED_CLAIMS.has(name);
|
|
31
|
+
}
|
|
32
|
+
function invalid(message) {
|
|
33
|
+
throw new AuthError("INVALID_CONFIGURATION", message);
|
|
34
|
+
}
|
|
35
|
+
function validateKey(key, algorithm) {
|
|
36
|
+
if (algorithm.startsWith("HS")) {
|
|
37
|
+
if (!(key instanceof Uint8Array) || key.byteLength < 32) {
|
|
38
|
+
invalid("HMAC access-token keys must be Uint8Array values of at least 32 bytes");
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (key instanceof Uint8Array) {
|
|
43
|
+
invalid(`${algorithm} requires a CryptoKey or KeyObject, not a byte array`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function validateAuthConfig(config) {
|
|
47
|
+
if (!config || typeof config !== "object") {
|
|
48
|
+
invalid("Configuration must be an object");
|
|
49
|
+
}
|
|
50
|
+
const mode = config.mode ?? "development";
|
|
51
|
+
if (mode !== "development" && mode !== "production") {
|
|
52
|
+
invalid('mode must be "development" or "production"');
|
|
53
|
+
}
|
|
54
|
+
if (config.password !== undefined &&
|
|
55
|
+
(typeof config.password !== "object" || config.password === null)) {
|
|
56
|
+
invalid("password must be an object when provided");
|
|
57
|
+
}
|
|
58
|
+
const workFactor = config.password?.workFactor ?? DEFAULT_BCRYPT_ROUNDS;
|
|
59
|
+
if (!Number.isInteger(workFactor) || workFactor < 4 || workFactor > 31) {
|
|
60
|
+
invalid("password.workFactor must be an integer between 4 and 31");
|
|
61
|
+
}
|
|
62
|
+
const tokenConfig = config.accessToken;
|
|
63
|
+
if (!tokenConfig || typeof tokenConfig !== "object" || !tokenConfig.key) {
|
|
64
|
+
invalid("accessToken.key is required");
|
|
65
|
+
}
|
|
66
|
+
const algorithm = tokenConfig.algorithm ?? "HS256";
|
|
67
|
+
if (!SUPPORTED_ALGORITHMS.includes(algorithm)) {
|
|
68
|
+
invalid("accessToken.algorithm is not supported");
|
|
69
|
+
}
|
|
70
|
+
const algorithms = [...new Set(tokenConfig.algorithms ?? [algorithm])];
|
|
71
|
+
if (algorithms.length === 0 ||
|
|
72
|
+
!algorithms.includes(algorithm) ||
|
|
73
|
+
algorithms.some((entry) => !SUPPORTED_ALGORITHMS.includes(entry))) {
|
|
74
|
+
invalid("accessToken.algorithms must be a non-empty allowlist containing the signing algorithm");
|
|
75
|
+
}
|
|
76
|
+
validateKey(tokenConfig.key, algorithm);
|
|
77
|
+
const expiresInSeconds = tokenConfig.expiresInSeconds ?? DEFAULT_ACCESS_TOKEN_TTL_SECONDS;
|
|
78
|
+
if (!Number.isSafeInteger(expiresInSeconds) || expiresInSeconds <= 0) {
|
|
79
|
+
invalid("accessToken.expiresInSeconds must be a positive safe integer");
|
|
80
|
+
}
|
|
81
|
+
if (tokenConfig.issuer !== undefined &&
|
|
82
|
+
(typeof tokenConfig.issuer !== "string" || tokenConfig.issuer.length === 0)) {
|
|
83
|
+
invalid("accessToken.issuer must be a non-empty string when provided");
|
|
84
|
+
}
|
|
85
|
+
if (tokenConfig.audience !== undefined) {
|
|
86
|
+
const audience = tokenConfig.audience;
|
|
87
|
+
if (!((typeof audience === "string" && audience.length > 0) ||
|
|
88
|
+
(Array.isArray(audience) &&
|
|
89
|
+
audience.length > 0 &&
|
|
90
|
+
audience.every((item) => typeof item === "string" && item.length > 0)))) {
|
|
91
|
+
invalid("accessToken.audience must contain non-empty string values");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (mode === "production") {
|
|
95
|
+
if (!tokenConfig.issuer || !tokenConfig.audience) {
|
|
96
|
+
invalid("Production mode requires accessToken.issuer and accessToken.audience");
|
|
97
|
+
}
|
|
98
|
+
if (expiresInSeconds > 3600) {
|
|
99
|
+
invalid("Production access tokens must expire within one hour");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (tokenConfig.keyId !== undefined && tokenConfig.keyId.length === 0) {
|
|
103
|
+
invalid("accessToken.keyId must be non-empty when provided");
|
|
104
|
+
}
|
|
105
|
+
if (tokenConfig.keyResolver !== undefined &&
|
|
106
|
+
typeof tokenConfig.keyResolver !== "function") {
|
|
107
|
+
invalid("accessToken.keyResolver must be a function");
|
|
108
|
+
}
|
|
109
|
+
if (tokenConfig.requiredClaims !== undefined &&
|
|
110
|
+
!Array.isArray(tokenConfig.requiredClaims)) {
|
|
111
|
+
invalid("accessToken.requiredClaims must be an array");
|
|
112
|
+
}
|
|
113
|
+
if (tokenConfig.isRevoked !== undefined &&
|
|
114
|
+
typeof tokenConfig.isRevoked !== "function") {
|
|
115
|
+
invalid("accessToken.isRevoked must be a function");
|
|
116
|
+
}
|
|
117
|
+
let refreshToken;
|
|
118
|
+
if (config.refreshToken !== undefined) {
|
|
119
|
+
const refreshConfig = config.refreshToken;
|
|
120
|
+
if (!refreshConfig || typeof refreshConfig !== "object") {
|
|
121
|
+
invalid("refreshToken must be an object when provided");
|
|
122
|
+
}
|
|
123
|
+
const store = refreshConfig.store;
|
|
124
|
+
if (!store ||
|
|
125
|
+
typeof store.create !== "function" ||
|
|
126
|
+
typeof store.consume !== "function" ||
|
|
127
|
+
typeof store.revokeToken !== "function" ||
|
|
128
|
+
typeof store.revokeFamily !== "function" ||
|
|
129
|
+
typeof store.revokeAllForSubject !== "function") {
|
|
130
|
+
invalid("refreshToken.store must implement the complete RefreshTokenStore interface");
|
|
131
|
+
}
|
|
132
|
+
if (!Number.isSafeInteger(refreshConfig.refreshTokenTtl) ||
|
|
133
|
+
refreshConfig.refreshTokenTtl <= 0 ||
|
|
134
|
+
refreshConfig.refreshTokenTtl > MAX_REFRESH_LIFETIME_SECONDS) {
|
|
135
|
+
invalid("refreshToken.refreshTokenTtl must be a positive safe integer in seconds");
|
|
136
|
+
}
|
|
137
|
+
if (!Number.isSafeInteger(refreshConfig.absoluteLifetime) ||
|
|
138
|
+
refreshConfig.absoluteLifetime <= 0 ||
|
|
139
|
+
refreshConfig.absoluteLifetime > MAX_REFRESH_LIFETIME_SECONDS) {
|
|
140
|
+
invalid("refreshToken.absoluteLifetime must be a positive safe integer in seconds");
|
|
141
|
+
}
|
|
142
|
+
refreshToken = {
|
|
143
|
+
store,
|
|
144
|
+
refreshTokenTtl: refreshConfig.refreshTokenTtl,
|
|
145
|
+
absoluteLifetime: refreshConfig.absoluteLifetime,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const requiredClaims = [
|
|
149
|
+
...new Set([
|
|
150
|
+
"sub",
|
|
151
|
+
"iat",
|
|
152
|
+
"exp",
|
|
153
|
+
...(tokenConfig.issuer ? ["iss"] : []),
|
|
154
|
+
...(tokenConfig.audience ? ["aud"] : []),
|
|
155
|
+
...(tokenConfig.requiredClaims ?? []),
|
|
156
|
+
]),
|
|
157
|
+
];
|
|
158
|
+
if (requiredClaims.some((claim) => typeof claim !== "string" || !claim)) {
|
|
159
|
+
invalid("accessToken.requiredClaims must contain non-empty claim names");
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
mode,
|
|
163
|
+
password: { workFactor },
|
|
164
|
+
accessToken: {
|
|
165
|
+
algorithm,
|
|
166
|
+
algorithms,
|
|
167
|
+
key: tokenConfig.key,
|
|
168
|
+
...(tokenConfig.keyId === undefined ? {} : { keyId: tokenConfig.keyId }),
|
|
169
|
+
...(tokenConfig.keyResolver === undefined
|
|
170
|
+
? {}
|
|
171
|
+
: { keyResolver: tokenConfig.keyResolver }),
|
|
172
|
+
...(tokenConfig.issuer === undefined
|
|
173
|
+
? {}
|
|
174
|
+
: { issuer: tokenConfig.issuer }),
|
|
175
|
+
...(tokenConfig.audience === undefined
|
|
176
|
+
? {}
|
|
177
|
+
: { audience: tokenConfig.audience }),
|
|
178
|
+
expiresInSeconds,
|
|
179
|
+
requiredClaims,
|
|
180
|
+
...(tokenConfig.isRevoked === undefined
|
|
181
|
+
? {}
|
|
182
|
+
: { isRevoked: tokenConfig.isRevoked }),
|
|
183
|
+
},
|
|
184
|
+
...(refreshToken === undefined ? {} : { refreshToken }),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|