nicot-simple-user 1.0.4 → 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 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
- export declare function attachAragamiWithBridge(base: DynamicModule): DynamicModule;
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) {
49
51
  useFactory: (aragamiOptions) => aragamiOptions,
50
52
  }),
51
53
  ],
52
- exports: [...(base.exports || []), nestjs_aragami_1.AragamiModule],
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,0DAiCC;AApDD,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,CAAC,IAAmB;IACzD,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,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,8BAAa,CAAC;KAClD,CAAC;AACJ,CAAC"}
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"}
@@ -4,3 +4,4 @@ export * from './simple-user/simple-user.service';
4
4
  export * from './resolver';
5
5
  export * from './simple-user.entity';
6
6
  export * from 'aragami';
7
+ export * from 'nestjs-aragami';
@@ -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"}
@@ -8,6 +8,8 @@ export interface SimpleUserExtraOptions {
8
8
  userServiceCrudExtras?: CrudOptions<SimpleUser>;
9
9
  userConnectionName?: string;
10
10
  isGlobal?: boolean;
11
+ reexportAragami?: boolean;
12
+ useExistingAragami?: boolean;
11
13
  }
12
14
  export interface SimpleUserOptions {
13
15
  allowAnonymousUsers?: boolean;
@@ -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);
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);
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,CAAC,CAAC;IACvC,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,CAAC,CAAC;IACvC,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"}
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"}