nicot-simple-user 1.0.5 → 1.0.6
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 +145 -0
- package/dist/simple-user/aragami-init.d.ts +2 -1
- package/dist/simple-user/aragami-init.js +7 -2
- package/dist/simple-user/aragami-init.js.map +1 -1
- package/dist/simple-user/index.d.ts +1 -0
- package/dist/simple-user/index.js +1 -0
- package/dist/simple-user/index.js.map +1 -1
- package/dist/simple-user/options.d.ts +1 -0
- package/dist/simple-user/simple-user.module.js +2 -2
- package/dist/simple-user/simple-user.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -170,6 +170,151 @@ import { AppUser } from './entities/app-user.entity'
|
|
|
170
170
|
export class AppModule {}
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## ⚠️ About `registerAsync`, request-scoped providers, and Aragami
|
|
176
|
+
|
|
177
|
+
When using `registerAsync`, **be careful about injecting request-scoped providers**
|
|
178
|
+
(directly or indirectly) into the options factory.
|
|
179
|
+
|
|
180
|
+
**The core rule**
|
|
181
|
+
|
|
182
|
+
In NestJS, provider scope is *contagious*:
|
|
183
|
+
|
|
184
|
+
> If a provider depends on a request-scoped provider, it must also become request-scoped.
|
|
185
|
+
|
|
186
|
+
This implies:
|
|
187
|
+
|
|
188
|
+
- If **any token in `registerAsync.inject` is request-scoped**
|
|
189
|
+
- Then the internal `MODULE_OPTIONS_TOKEN` of `nicot-simple-user` **will also become request-scoped**
|
|
190
|
+
- As a result, **the entire dependency chain of this module may be upgraded to request scope**
|
|
191
|
+
|
|
192
|
+
This can happen *silently*, without any warning.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
**A common real-world example**
|
|
197
|
+
|
|
198
|
+
Consider this pattern:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
SimpleUserModule.registerAsync({
|
|
202
|
+
imports: [SmtpModule],
|
|
203
|
+
inject: [SmtpService],
|
|
204
|
+
useFactory: async (smtp: SmtpService) => ({
|
|
205
|
+
sendCodeGenerator: async (ctx) => {
|
|
206
|
+
// ...
|
|
207
|
+
},
|
|
208
|
+
}),
|
|
209
|
+
})
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
At first glance, `SmtpService` looks harmless.
|
|
213
|
+
|
|
214
|
+
However, in many real projects:
|
|
215
|
+
|
|
216
|
+
- `SmtpService` depends on an email template renderer
|
|
217
|
+
- which depends on an i18n service
|
|
218
|
+
- which uses a ParamResolver or request context
|
|
219
|
+
- which is **request-scoped**
|
|
220
|
+
|
|
221
|
+
Once that happens, **the entire `SimpleUserModule` options provider becomes request-scoped**.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
**Why this is dangerous**
|
|
226
|
+
|
|
227
|
+
`nicot-simple-user` internally integrates with **Aragami** for:
|
|
228
|
+
|
|
229
|
+
- sessions
|
|
230
|
+
- verification code storage
|
|
231
|
+
- cooldown / risk control
|
|
232
|
+
- locks and counters
|
|
233
|
+
|
|
234
|
+
Aragami is designed to be **singleton infrastructure**.
|
|
235
|
+
|
|
236
|
+
If it is accidentally instantiated or resolved through a request-scoped provider chain,
|
|
237
|
+
you may observe:
|
|
238
|
+
|
|
239
|
+
- multiple Aragami runtimes
|
|
240
|
+
- duplicated Redis connections
|
|
241
|
+
- inconsistent lock / cooldown behavior
|
|
242
|
+
- subtle bugs that only appear under concurrency
|
|
243
|
+
|
|
244
|
+
These issues are extremely hard to debug once they occur.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
**Recommended approach: use an existing Aragami instance**
|
|
249
|
+
|
|
250
|
+
To avoid scope pollution, the **recommended and safest approach** is:
|
|
251
|
+
|
|
252
|
+
> **Register Aragami at the application level, and tell `nicot-simple-user` to reuse it.**
|
|
253
|
+
|
|
254
|
+
That is what `useExistingAragami` is for.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
@Module({
|
|
258
|
+
imports: [
|
|
259
|
+
AragamiModule.registerAsync({
|
|
260
|
+
isGlobal: true,
|
|
261
|
+
inject: [ConfigService],
|
|
262
|
+
useFactory: async (config: ConfigService) => ({
|
|
263
|
+
redis: { uri: config.getOrThrow('REDIS_URL') },
|
|
264
|
+
}),
|
|
265
|
+
}),
|
|
266
|
+
|
|
267
|
+
SimpleUserModule.registerAsync({
|
|
268
|
+
useExistingAragami: true,
|
|
269
|
+
|
|
270
|
+
imports: [SmtpModule],
|
|
271
|
+
inject: [SmtpService],
|
|
272
|
+
useFactory: async (smtp: SmtpService) => ({
|
|
273
|
+
sendCodeGenerator: async (ctx) => {
|
|
274
|
+
// ...
|
|
275
|
+
},
|
|
276
|
+
}),
|
|
277
|
+
}),
|
|
278
|
+
],
|
|
279
|
+
})
|
|
280
|
+
export class AppModule {}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
With this setup:
|
|
284
|
+
|
|
285
|
+
- Aragami remains **singleton and global**
|
|
286
|
+
- `nicot-simple-user` does **not** attempt to create or configure Aragami
|
|
287
|
+
- even if `sendCodeGenerator` depends on request-scoped services,
|
|
288
|
+
**Aragami itself is not affected**
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
**Design guideline**
|
|
293
|
+
|
|
294
|
+
- Module options (`register` / `registerAsync`) should be treated as **startup-time configuration**
|
|
295
|
+
- Request-specific data should flow through **method parameters**, such as:
|
|
296
|
+
- `SendCodeDto`
|
|
297
|
+
- request context objects
|
|
298
|
+
- runtime services resolved at request time
|
|
299
|
+
|
|
300
|
+
As a rule of thumb:
|
|
301
|
+
|
|
302
|
+
> If something depends on request context (i18n, tenant, locale, user agent, IP),
|
|
303
|
+
> it should **not** be injected into a module options factory.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
**Summary**
|
|
308
|
+
|
|
309
|
+
- Injecting request-scoped providers into `registerAsync` can silently upgrade the entire module to request scope
|
|
310
|
+
- This can break Aragami’s singleton assumptions
|
|
311
|
+
- **The current best practice is:**
|
|
312
|
+
- register Aragami once at the application level
|
|
313
|
+
- set `useExistingAragami: true` in `nicot-simple-user`
|
|
314
|
+
|
|
315
|
+
This keeps infrastructure stable and avoids extremely subtle scope-related bugs.
|
|
316
|
+
|
|
317
|
+
|
|
173
318
|
---
|
|
174
319
|
|
|
175
320
|
## Request Headers
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { DynamicModule } from '@nestjs/common';
|
|
2
|
-
|
|
2
|
+
import { SimpleUserExtraOptions } from './options';
|
|
3
|
+
export declare function attachAragamiWithBridge(base: DynamicModule, options: SimpleUserExtraOptions): DynamicModule;
|
|
@@ -23,7 +23,9 @@ function deriveAragamiOptions(o) {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
const ARAGAMI_OPTIONS = Symbol('ARAGAMI_OPTIONS');
|
|
26
|
-
function attachAragamiWithBridge(base,
|
|
26
|
+
function attachAragamiWithBridge(base, options) {
|
|
27
|
+
if (options.useExistingAragami)
|
|
28
|
+
return base;
|
|
27
29
|
const baseImports = base.imports ?? [];
|
|
28
30
|
const baseProviders = base.providers ?? [];
|
|
29
31
|
const bridge = {
|
|
@@ -49,7 +51,10 @@ function attachAragamiWithBridge(base, reexport = false) {
|
|
|
49
51
|
useFactory: (aragamiOptions) => aragamiOptions,
|
|
50
52
|
}),
|
|
51
53
|
],
|
|
52
|
-
exports: [
|
|
54
|
+
exports: [
|
|
55
|
+
...(base.exports || []),
|
|
56
|
+
...(options.reexportAragami ? [nestjs_aragami_1.AragamiModule] : []),
|
|
57
|
+
],
|
|
53
58
|
};
|
|
54
59
|
}
|
|
55
60
|
//# sourceMappingURL=aragami-init.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aragami-init.js","sourceRoot":"","sources":["../../src/simple-user/aragami-init.ts"],"names":[],"mappings":";;;;;;;;AAmBA,
|
|
1
|
+
{"version":3,"file":"aragami-init.js","sourceRoot":"","sources":["../../src/simple-user/aragami-init.ts"],"names":[],"mappings":";;;;;;;;AAmBA,0DAwCC;AA3DD,2CAAuD;AAGvD,iCAAuC;AACvC,qDAAwD;AACxD,mDAA+C;AAG/C,IAAM,6BAA6B,GAAnC,MAAM,6BAA6B;CAAG,CAAA;AAAhC,6BAA6B;IADlC,IAAA,eAAM,EAAC,EAAE,CAAC;GACL,6BAA6B,CAAG;AAEtC,SAAS,oBAAoB,CAAC,CAAoB;IAChD,OAAO;QACL,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,CAAC;KAC3B,CAAC;AACJ,CAAC;AAED,MAAM,eAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAElD,SAAgB,uBAAuB,CACrC,IAAmB,EACnB,OAA+B;IAE/B,IAAI,OAAO,CAAC,kBAAkB;QAAE,OAAO,IAAI,CAAC;IAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;IACvC,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;IAE3C,MAAM,MAAM,GAAkB;QAC5B,MAAM,EAAE,6BAA6B;QACrC,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE;YACT,GAAG,aAAa;YAChB,IAAA,sBAAc,EACZ;gBACE,OAAO,EAAE,eAAe;gBACxB,MAAM,EAAE,CAAC,qCAAoB,CAAC;aAC/B,EACD,CAAC,CAAoB,EAAE,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAClD;SACF;QACD,OAAO,EAAE,CAAC,eAAe,CAAC;KAC3B,CAAC;IAEF,OAAO;QACL,GAAG,IAAI;QACP,OAAO,EAAE;YACP,GAAG,WAAW;YACd,MAAM;YACN,8BAAa,CAAC,aAAa,CAAC;gBAC1B,OAAO,EAAE,CAAC,MAAM,CAAC;gBACjB,MAAM,EAAE,CAAC,eAAe,CAAC;gBACzB,UAAU,EAAE,CAAC,cAA8B,EAAE,EAAE,CAAC,cAAc;aAC/D,CAAC;SACH;QACD,OAAO,EAAE;YACP,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;YACvB,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,8BAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACpD;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -20,4 +20,5 @@ __exportStar(require("./simple-user/simple-user.service"), exports);
|
|
|
20
20
|
__exportStar(require("./resolver"), exports);
|
|
21
21
|
__exportStar(require("./simple-user.entity"), exports);
|
|
22
22
|
__exportStar(require("aragami"), exports);
|
|
23
|
+
__exportStar(require("nestjs-aragami"), exports);
|
|
23
24
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/simple-user/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,uDAAqC;AACrC,oEAAkD;AAClD,6CAA2B;AAC3B,uDAAqC;AACrC,0CAAwB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/simple-user/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,uDAAqC;AACrC,oEAAkD;AAClD,6CAA2B;AAC3B,uDAAqC;AACrC,0CAAwB;AACxB,iDAA+B"}
|
|
@@ -30,7 +30,7 @@ let SimpleUserModule = class SimpleUserModule extends module_builder_1.Configura
|
|
|
30
30
|
static register(options) {
|
|
31
31
|
const base = super.register(options);
|
|
32
32
|
patchUserCenterControllerMeWithDynamicModule(base);
|
|
33
|
-
return (0, aragami_init_1.attachAragamiWithBridge)(base, options
|
|
33
|
+
return (0, aragami_init_1.attachAragamiWithBridge)(base, options);
|
|
34
34
|
}
|
|
35
35
|
static registerAsync(options) {
|
|
36
36
|
const base = super.registerAsync(options);
|
|
@@ -44,7 +44,7 @@ let SimpleUserModule = class SimpleUserModule extends module_builder_1.Configura
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
return (0, aragami_init_1.attachAragamiWithBridge)(base, options
|
|
47
|
+
return (0, aragami_init_1.attachAragamiWithBridge)(base, options);
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
exports.SimpleUserModule = SimpleUserModule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simple-user.module.js","sourceRoot":"","sources":["../../src/simple-user/simple-user.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAKwB;AACxB,qDAG0B;AAC1B,iDAAyD;AACzD,2EAAsE;AACtE,qEAAgE;AAChE,2EAAsE;AACtE,+DAA2D;AAC3D,iFAA4E;AAC5E,yCAGoB;AACpB,qCAA0C;AAE1C,qDAAqE;AACrE,iCAAkE;AAUlE,MAAM,4CAA4C,GAAG,CACnD,MAAqB,EACrB,EAAE;IACF,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,EAAE,IAAI,CAC3C,CAAC,CAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,uBAAc,CAClC,CAAC;IACnB,IAAI,cAAc,EAAE,QAAQ,EAAE,CAAC;QAC7B,IAAA,sCAA2B,EAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,yCAAkB,EAAE,kCAAe,EAAE,6CAAoB,CAAC,CAAC;AAgBzE,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,wCAAuB;IAC3D,MAAM,CAAC,QAAQ,CAAC,OAAkC;QAChD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,4CAA4C,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,IAAA,sCAAuB,EAAC,IAAI,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"simple-user.module.js","sourceRoot":"","sources":["../../src/simple-user/simple-user.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAKwB;AACxB,qDAG0B;AAC1B,iDAAyD;AACzD,2EAAsE;AACtE,qEAAgE;AAChE,2EAAsE;AACtE,+DAA2D;AAC3D,iFAA4E;AAC5E,yCAGoB;AACpB,qCAA0C;AAE1C,qDAAqE;AACrE,iCAAkE;AAUlE,MAAM,4CAA4C,GAAG,CACnD,MAAqB,EACrB,EAAE;IACF,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,EAAE,IAAI,CAC3C,CAAC,CAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,uBAAc,CAClC,CAAC;IACnB,IAAI,cAAc,EAAE,QAAQ,EAAE,CAAC;QAC7B,IAAA,sCAA2B,EAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,yCAAkB,EAAE,kCAAe,EAAE,6CAAoB,CAAC,CAAC;AAgBzE,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,wCAAuB;IAC3D,MAAM,CAAC,QAAQ,CAAC,OAAkC;QAChD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,4CAA4C,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,IAAA,sCAAuB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,OAAuC;QAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC1C,4CAA4C,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAE,CAA+B,EAAE,KAAK,IAAI,CAAC,CAAmB,CACxE,CAAC;YACF,IAAA,gCAAwB,EAAC,qCAAoB,EAAE,gBAAgB,CAAC,CAAC;YACjE,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;gBACrC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;oBACrC,IAAA,uBAAe,EAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAA,sCAAuB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;CACF,CAAA;AAvBY,4CAAgB;2BAAhB,gBAAgB;IAd5B,IAAA,eAAM,EAAC;QACN,SAAS,EAAE;YACT,uCAAiB;YACjB,mCAAe;YACf,+BAAoB,CAAC,QAAQ;YAC7B,0CAA+B,CAAC,QAAQ;SACzC;QACD,OAAO,EAAE;YACP,uCAAiB;YACjB,+BAAoB,CAAC,QAAQ;YAC7B,0CAA+B,CAAC,QAAQ;SACzC;QACD,WAAW;KACZ,CAAC;GACW,gBAAgB,CAuB5B"}
|