@codecanva/nest-auth 0.1.0 → 0.2.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 CHANGED
@@ -1,164 +1,200 @@
1
- # @codecanva/nest-auth
2
-
3
- Reusable NestJS authentication module. JWT access + refresh-token rotation, multi-device sessions, replay detection, and pluggable persistence (no DB lock-in).
4
-
5
- ## Features
6
-
7
- - Short-lived access JWT + long-lived refresh JWT
8
- - Refresh-token rotation on every refresh (with replay detection → `revokeAllForUser`)
9
- - Multi-device sessions (one row per session, hashed at rest)
10
- - Pluggable `RefreshTokenStore` and `UserValidator` — bring your own DB
11
- - `@CurrentUser()`, `@Public()` decorators
12
- - `JwtAuthGuard` (honours `@Public()`) and `RefreshAuthGuard`
13
- - Configurable issuer, audience, clock tolerance, optional hash pepper
14
-
15
- ## Install
16
-
17
- ```bash
18
- npm install @codecanva/nest-auth \
19
- @nestjs/jwt @nestjs/passport passport passport-jwt \
20
- class-validator class-transformer
21
- ```
22
-
23
- ## Usage
24
-
25
- ### 1. Implement the two interfaces against your data layer
26
-
27
- ```ts
28
- // users/user.validator.ts
29
- import { Injectable } from '@nestjs/common';
30
- import { AuthUser, UserValidator } from '@codecanva/nest-auth';
31
-
32
- @Injectable()
33
- export class MyUserValidator implements UserValidator {
34
- async validateCredentials(email: string, password: string): Promise<AuthUser | null> {
35
- // load user, bcrypt.compare, return { id, email, roles } or null
36
- }
37
- async findById(userId: string | number): Promise<AuthUser | null> {
38
- // load by id, return AuthUser or null
39
- }
40
- }
41
- ```
42
-
43
- ```ts
44
- // auth/refresh-token.store.ts — example with TypeORM
45
- import { Injectable } from '@nestjs/common';
46
- import {
47
- CreateRefreshTokenInput,
48
- RefreshTokenStore,
49
- StoredRefreshToken,
50
- } from '@codecanva/nest-auth';
51
-
52
- @Injectable()
53
- export class MyRefreshTokenStore implements RefreshTokenStore {
54
- // create / findById / consume / revokeById / revokeAllForUser
55
- // IMPORTANT: `consume` must be atomic (single UPDATE ... WHERE revoked_at IS NULL
56
- // AND token_hash = $hash RETURNING *). Non-atomic impls split sessions under load.
57
- }
58
- ```
59
-
60
- ### 2. Register the module
61
-
62
- ```ts
63
- import { AuthModule } from '@codecanva/nest-auth';
64
-
65
- @Module({
66
- imports: [
67
- AuthModule.forRootAsync({
68
- imports: [ConfigModule],
69
- useFactory: (cfg: ConfigService) => ({
70
- accessSecret: cfg.getOrThrow('JWT_ACCESS_SECRET'),
71
- refreshSecret: cfg.getOrThrow('JWT_REFRESH_SECRET'),
72
- accessTtl: '15m',
73
- refreshTtl: '30d',
74
- tokenHashPepper: cfg.get('TOKEN_HASH_PEPPER'),
75
- issuer: 'my-app',
76
- }),
77
- inject: [ConfigService],
78
- store: { useClass: MyRefreshTokenStore },
79
- validator: { useClass: MyUserValidator },
80
- }),
81
- ],
82
- })
83
- export class AppModule {}
84
- ```
85
-
86
- ### 3. Apply the guard globally (optional)
87
-
88
- ```ts
89
- import { APP_GUARD } from '@nestjs/core';
90
- import { JwtAuthGuard } from '@codecanva/nest-auth';
91
-
92
- providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }],
93
- ```
94
-
95
- ### 4. Use in controllers
96
-
97
- ```ts
98
- import {
99
- AuthService, CurrentUser, LoginDto, Public, RefreshTokenDto,
100
- } from '@codecanva/nest-auth';
101
-
102
- @Controller('auth')
103
- export class AuthController {
104
- constructor(private readonly auth: AuthService) {}
105
-
106
- @Public() @Post('login')
107
- login(@Body() dto: LoginDto) { return this.auth.login(dto.email, dto.password); }
108
-
109
- @Public() @Post('refresh')
110
- refresh(@Body() dto: RefreshTokenDto) { return this.auth.refresh(dto.refreshToken); }
111
-
112
- @Post('logout')
113
- logout(@Body() dto: RefreshTokenDto) { return this.auth.logout(dto.refreshToken); }
114
- }
115
-
116
- @Controller('me')
117
- export class MeController {
118
- @Get() me(@CurrentUser() user: AuthUser) { return user; }
119
- }
120
- ```
121
-
122
- ## API surface
123
-
124
- - `AuthModule.forRootAsync(opts)` — only entry point
125
- - `AuthService` `login` / `refresh` / `logout` / `logoutAll`
126
- - Guards — `JwtAuthGuard`, `RefreshAuthGuard`
127
- - Decorators — `@Public()`, `@CurrentUser()`
128
- - DTOs `LoginDto`, `RefreshTokenDto`
129
- - Errors — `AuthError`, `InvalidCredentialsError`, `InvalidRefreshTokenError`, `RefreshTokenExpiredError`, `RefreshTokenReuseDetectedError`, `UserNotFoundError`
130
- - Interfaces — `AuthModuleOptions`, `AuthModuleAsyncOptions`, `AuthUser`, `JwtPayload`, `RefreshTokenStore`, `StoredRefreshToken`, `CreateRefreshTokenInput`, `SessionMetadata`, `UserValidator`
131
-
132
- ## Local development / publishing
133
-
134
- ```bash
135
- npm install # install deps
136
- npm run start:dev # run the demo app at :3000 (uses in-memory store + validator)
137
- npm run build:lib # compile lib → dist/
138
- npm publish # publish (runs build:lib via prepublishOnly)
139
- ```
140
-
141
- To consume from a sibling project before publishing:
142
-
143
- ```bash
144
- # in this repo
145
- npm run build:lib && npm pack
146
- # in the consumer
147
- npm install /path/to/codecanva-nest-auth-0.1.0.tgz
148
- ```
149
-
150
- ## Demo endpoints (when running `start:dev`)
151
-
152
- ```
153
- POST /auth/login { "email": "demo@example.com", "password": "password123" }
154
- POST /auth/refresh { "refreshToken": "..." }
155
- POST /auth/logout { "refreshToken": "..." } # 204
156
- GET /me # bearer access token required
157
- ```
158
-
159
- ## Security notes
160
-
161
- - Refresh tokens are JWTs; the **hash** of the JWT (sha256 + optional pepper) is stored, never the raw token.
162
- - `consume` must be atomic non-atomic impls split sessions under concurrent refresh.
163
- - On replay (token hash mismatch or already-revoked row), every active session for that user is revoked.
164
- - Always serve auth over HTTPS. Store the refresh token in an httpOnly cookie when possible.
1
+ # @codecanva/nest-auth
2
+
3
+ Reusable NestJS authentication module. JWT access + refresh-token rotation, multi-device sessions, replay detection, and pluggable persistence (no DB lock-in).
4
+
5
+ ## Features
6
+
7
+ - Short-lived access JWT + long-lived refresh JWT
8
+ - Refresh-token rotation on every refresh (with replay detection → `revokeAllForUser`)
9
+ - Multi-device sessions (one row per session, hashed at rest)
10
+ - Pluggable `RefreshTokenStore` and `UserValidator` — bring your own DB
11
+ - `@CurrentUser()`, `@Public()` decorators
12
+ - `JwtAuthGuard` (honours `@Public()`) and `RefreshAuthGuard`
13
+ - Configurable issuer, audience, clock tolerance, optional hash pepper
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ npm install @codecanva/nest-auth \
19
+ @nestjs/jwt @nestjs/passport passport passport-jwt \
20
+ class-validator class-transformer
21
+ ```
22
+
23
+ ## Quick install (CLI)
24
+
25
+ Scaffold everything into an existing NestJS project user/auth files, env vars,
26
+ AppModule + `main.ts` wiring, and dependencies — in one command:
27
+
28
+ ```bash
29
+ # Mongoose persistence (default): generates user + refresh-token modules
30
+ npx @codecanva/nest-auth init
31
+
32
+ # In-memory store, no DB — great for a quick trial
33
+ npx @codecanva/nest-auth init --store memory
34
+
35
+ # Preview without writing anything
36
+ npx @codecanva/nest-auth init --dry-run
37
+ ```
38
+
39
+ The installer generates an `AuthIntegrationModule` (a single drop-in module that
40
+ bundles the store, validator, controller, and the global `JwtAuthGuard`), adds it
41
+ to your `AppModule`, and enables a global `ValidationPipe`. Existing files are
42
+ never overwritten without `--force`, and every edited file is backed up to
43
+ `<file>.bak`.
44
+
45
+ | Flag | Effect |
46
+ | --- | --- |
47
+ | `--store <mongoose\|memory>` | Persistence to scaffold (default `mongoose`) |
48
+ | `--dir <path>` | Target project root (default: current directory) |
49
+ | `--no-wire` | Don't touch `app.module.ts` / `main.ts` |
50
+ | `--skip-install` | Don't install npm dependencies |
51
+ | `--force` | Overwrite files that already exist |
52
+ | `--dry-run` | Show planned changes, write nothing |
53
+
54
+ After running it, set real values for `JWT_ACCESS_SECRET`, `JWT_REFRESH_SECRET`,
55
+ and `TOKEN_HASH_PEPPER` in `.env` (and, for `--store mongoose`, make sure a
56
+ `MongooseModule.forRoot(...)` connection exists at the app root). For a fully
57
+ manual, step-by-step walkthrough see [INSTALLATION.md](./INSTALLATION.md).
58
+
59
+ ## Usage
60
+
61
+ ### 1. Implement the two interfaces against your data layer
62
+
63
+ ```ts
64
+ // users/user.validator.ts
65
+ import { Injectable } from '@nestjs/common';
66
+ import { AuthUser, UserValidator } from '@codecanva/nest-auth';
67
+
68
+ @Injectable()
69
+ export class MyUserValidator implements UserValidator {
70
+ async validateCredentials(email: string, password: string): Promise<AuthUser | null> {
71
+ // load user, bcrypt.compare, return { id, email, roles } or null
72
+ }
73
+ async findById(userId: string | number): Promise<AuthUser | null> {
74
+ // load by id, return AuthUser or null
75
+ }
76
+ }
77
+ ```
78
+
79
+ ```ts
80
+ // auth/refresh-token.store.ts — example with TypeORM
81
+ import { Injectable } from '@nestjs/common';
82
+ import {
83
+ CreateRefreshTokenInput,
84
+ RefreshTokenStore,
85
+ StoredRefreshToken,
86
+ } from '@codecanva/nest-auth';
87
+
88
+ @Injectable()
89
+ export class MyRefreshTokenStore implements RefreshTokenStore {
90
+ // create / findById / consume / revokeById / revokeAllForUser
91
+ // IMPORTANT: `consume` must be atomic (single UPDATE ... WHERE revoked_at IS NULL
92
+ // AND token_hash = $hash RETURNING *). Non-atomic impls split sessions under load.
93
+ }
94
+ ```
95
+
96
+ ### 2. Register the module
97
+
98
+ ```ts
99
+ import { AuthModule } from '@codecanva/nest-auth';
100
+
101
+ @Module({
102
+ imports: [
103
+ AuthModule.forRootAsync({
104
+ imports: [ConfigModule],
105
+ useFactory: (cfg: ConfigService) => ({
106
+ accessSecret: cfg.getOrThrow('JWT_ACCESS_SECRET'),
107
+ refreshSecret: cfg.getOrThrow('JWT_REFRESH_SECRET'),
108
+ accessTtl: '15m',
109
+ refreshTtl: '30d',
110
+ tokenHashPepper: cfg.get('TOKEN_HASH_PEPPER'),
111
+ issuer: 'my-app',
112
+ }),
113
+ inject: [ConfigService],
114
+ store: { useClass: MyRefreshTokenStore },
115
+ validator: { useClass: MyUserValidator },
116
+ }),
117
+ ],
118
+ })
119
+ export class AppModule {}
120
+ ```
121
+
122
+ ### 3. Apply the guard globally (optional)
123
+
124
+ ```ts
125
+ import { APP_GUARD } from '@nestjs/core';
126
+ import { JwtAuthGuard } from '@codecanva/nest-auth';
127
+
128
+ providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }],
129
+ ```
130
+
131
+ ### 4. Use in controllers
132
+
133
+ ```ts
134
+ import {
135
+ AuthService, CurrentUser, LoginDto, Public, RefreshTokenDto,
136
+ } from '@codecanva/nest-auth';
137
+
138
+ @Controller('auth')
139
+ export class AuthController {
140
+ constructor(private readonly auth: AuthService) {}
141
+
142
+ @Public() @Post('login')
143
+ login(@Body() dto: LoginDto) { return this.auth.login(dto.email, dto.password); }
144
+
145
+ @Public() @Post('refresh')
146
+ refresh(@Body() dto: RefreshTokenDto) { return this.auth.refresh(dto.refreshToken); }
147
+
148
+ @Post('logout')
149
+ logout(@Body() dto: RefreshTokenDto) { return this.auth.logout(dto.refreshToken); }
150
+ }
151
+
152
+ @Controller('me')
153
+ export class MeController {
154
+ @Get() me(@CurrentUser() user: AuthUser) { return user; }
155
+ }
156
+ ```
157
+
158
+ ## API surface
159
+
160
+ - `AuthModule.forRootAsync(opts)` — only entry point
161
+ - `AuthService` `login` / `refresh` / `logout` / `logoutAll`
162
+ - Guards`JwtAuthGuard`, `RefreshAuthGuard`
163
+ - Decorators `@Public()`, `@CurrentUser()`
164
+ - DTOs `LoginDto`, `RefreshTokenDto`
165
+ - Errors — `AuthError`, `InvalidCredentialsError`, `InvalidRefreshTokenError`, `RefreshTokenExpiredError`, `RefreshTokenReuseDetectedError`, `UserNotFoundError`
166
+ - Interfaces — `AuthModuleOptions`, `AuthModuleAsyncOptions`, `AuthUser`, `JwtPayload`, `RefreshTokenStore`, `StoredRefreshToken`, `CreateRefreshTokenInput`, `SessionMetadata`, `UserValidator`
167
+
168
+ ## Local development / publishing
169
+
170
+ ```bash
171
+ npm install # install deps
172
+ npm run start:dev # run the demo app at :3000 (uses in-memory store + validator)
173
+ npm run build:lib # compile lib → dist/
174
+ npm publish # publish (runs build:lib via prepublishOnly)
175
+ ```
176
+
177
+ To consume from a sibling project before publishing:
178
+
179
+ ```bash
180
+ # in this repo
181
+ npm run build:lib && npm pack
182
+ # in the consumer
183
+ npm install /path/to/codecanva-nest-auth-0.1.0.tgz
184
+ ```
185
+
186
+ ## Demo endpoints (when running `start:dev`)
187
+
188
+ ```
189
+ POST /auth/login { "email": "demo@example.com", "password": "password123" }
190
+ POST /auth/refresh { "refreshToken": "..." }
191
+ POST /auth/logout { "refreshToken": "..." } # 204
192
+ GET /me # bearer access token required
193
+ ```
194
+
195
+ ## Security notes
196
+
197
+ - Refresh tokens are JWTs; the **hash** of the JWT (sha256 + optional pepper) is stored, never the raw token.
198
+ - `consume` must be atomic — non-atomic impls split sessions under concurrent refresh.
199
+ - On replay (token hash mismatch or already-revoked row), every active session for that user is revoked.
200
+ - Always serve auth over HTTPS. Store the refresh token in an httpOnly cookie when possible.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../src/lib/auth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoB,MAAM,gBAAgB,CAAC;AASjE,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,4CAA4C,CAAC;AAKpD,qBACa,UAAU;IACrB,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,sBAAsB,GAAG,aAAa;CAoCpE"}
1
+ {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../src/lib/auth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoB,MAAM,gBAAgB,CAAC;AAWjE,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,4CAA4C,CAAC;AAKpD,qBACa,UAAU;IACrB,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,sBAAsB,GAAG,aAAa;CAwCpE"}
@@ -9,10 +9,12 @@ var AuthModule_1;
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.AuthModule = void 0;
11
11
  const common_1 = require("@nestjs/common");
12
+ const core_1 = require("@nestjs/core");
12
13
  const jwt_1 = require("@nestjs/jwt");
13
14
  const passport_1 = require("@nestjs/passport");
14
15
  const auth_constants_1 = require("./auth.constants");
15
16
  const auth_service_1 = require("./auth.service");
17
+ const auth_exception_filter_1 = require("./filters/auth-exception.filter");
16
18
  const token_service_1 = require("./services/token.service");
17
19
  const jwt_strategy_1 = require("./strategies/jwt.strategy");
18
20
  const refresh_strategy_1 = require("./strategies/refresh.strategy");
@@ -40,6 +42,10 @@ let AuthModule = AuthModule_1 = class AuthModule {
40
42
  jwt_strategy_1.JwtStrategy,
41
43
  refresh_strategy_1.RefreshStrategy,
42
44
  auth_service_1.AuthService,
45
+ // Globally maps AuthError domain errors → HTTP responses (e.g.
46
+ // InvalidCredentialsError → 401), so consumers don't need per-route
47
+ // try/catch to get correct status codes on auth failure.
48
+ { provide: core_1.APP_FILTER, useClass: auth_exception_filter_1.AuthExceptionFilter },
43
49
  ],
44
50
  exports: [
45
51
  auth_service_1.AuthService,
@@ -1 +1 @@
1
- {"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../src/lib/auth.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAiE;AACjE,qCAAwC;AACxC,+CAAkD;AAClD,qDAI0B;AAC1B,iDAA6C;AAM7C,4DAAwD;AACxD,4DAAwD;AACxD,oEAAgE;AAGzD,IAAM,UAAU,kBAAhB,MAAM,UAAU;IACrB,MAAM,CAAC,YAAY,CAAC,OAA+B;QACjD,MAAM,eAAe,GAAa;YAChC,OAAO,EAAE,oCAAmB;YAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;SAC7B,CAAC;QAEF,MAAM,aAAa,GAAG,aAAa,CAAC,oCAAmB,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACxE,MAAM,iBAAiB,GAAG,aAAa,CAAC,+BAAc,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAE3E,OAAO;YACL,MAAM,EAAE,YAAU;YAClB,OAAO,EAAE;gBACP,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;gBAC1B,yBAAc;gBACd,eAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;aACvB;YACD,SAAS,EAAE;gBACT,eAAe;gBACf,aAAa;gBACb,iBAAiB;gBACjB,4BAAY;gBACZ,0BAAW;gBACX,kCAAe;gBACf,0BAAW;aACZ;YACD,OAAO,EAAE;gBACP,0BAAW;gBACX,oCAAmB;gBACnB,oCAAmB;gBACnB,+BAAc;gBACd,eAAS;gBACT,yBAAc;aACf;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AArCY,gCAAU;qBAAV,UAAU;IADtB,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,UAAU,CAqCtB;AAED,SAAS,aAAa,CACpB,KAAa,EACb,GAAsD;IAEtD,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACnB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;SACzB,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;IAC1D,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;IACpD,CAAC;IACD,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,CAAC,QAAQ,EAAE,gDAAgD,CAC7F,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../src/lib/auth.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAiE;AACjE,uCAA0C;AAC1C,qCAAwC;AACxC,+CAAkD;AAClD,qDAI0B;AAC1B,iDAA6C;AAC7C,2EAAsE;AAMtE,4DAAwD;AACxD,4DAAwD;AACxD,oEAAgE;AAGzD,IAAM,UAAU,kBAAhB,MAAM,UAAU;IACrB,MAAM,CAAC,YAAY,CAAC,OAA+B;QACjD,MAAM,eAAe,GAAa;YAChC,OAAO,EAAE,oCAAmB;YAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;SAC7B,CAAC;QAEF,MAAM,aAAa,GAAG,aAAa,CAAC,oCAAmB,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACxE,MAAM,iBAAiB,GAAG,aAAa,CAAC,+BAAc,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAE3E,OAAO;YACL,MAAM,EAAE,YAAU;YAClB,OAAO,EAAE;gBACP,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;gBAC1B,yBAAc;gBACd,eAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;aACvB;YACD,SAAS,EAAE;gBACT,eAAe;gBACf,aAAa;gBACb,iBAAiB;gBACjB,4BAAY;gBACZ,0BAAW;gBACX,kCAAe;gBACf,0BAAW;gBACX,+DAA+D;gBAC/D,oEAAoE;gBACpE,yDAAyD;gBACzD,EAAE,OAAO,EAAE,iBAAU,EAAE,QAAQ,EAAE,2CAAmB,EAAE;aACvD;YACD,OAAO,EAAE;gBACP,0BAAW;gBACX,oCAAmB;gBACnB,oCAAmB;gBACnB,+BAAc;gBACd,eAAS;gBACT,yBAAc;aACf;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAzCY,gCAAU;qBAAV,UAAU;IADtB,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,UAAU,CAyCtB;AAED,SAAS,aAAa,CACpB,KAAa,EACb,GAAsD;IAEtD,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACnB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;SACzB,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;IAC1D,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;IACpD,CAAC;IACD,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,CAAC,QAAQ,EAAE,gDAAgD,CAC7F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/cli/index.ts"],"names":[],"mappings":""}