Skip to content

Commit 0ff6b3f

Browse files
docs(nest): add JSDocs (#5034)
The Nest-way is rather different than other things. So, when reviewing, take that into account. Closes GH-4957.
1 parent 18a2700 commit 0ff6b3f

File tree

1 file changed

+203
-24
lines changed

1 file changed

+203
-24
lines changed

arcjet-nest/index.ts

Lines changed: 203 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,36 @@ type PlainObject = {
9292
[key: string]: unknown;
9393
};
9494

95+
/**
96+
* Configuration for {@linkcode createRemoteClient}.
97+
*/
9598
export type RemoteClientOptions = {
99+
/**
100+
* Base URI for HTTP requests to Decide API (optional).
101+
*
102+
* Defaults to the environment variable `ARCJET_BASE_URL` (if that value
103+
* is known and allowed) and the standard production API otherwise.
104+
*/
96105
baseUrl?: string;
106+
107+
/**
108+
* Timeout in milliseconds for the Decide API (optional).
109+
*
110+
* Defaults to `500` in production and `1000` in development.
111+
*/
97112
timeout?: number;
98113
};
99114

115+
/**
116+
* Create a remote client.
117+
*
118+
* @param options
119+
* Configuration (optional).
120+
* @returns
121+
* Client.
122+
*/
100123
export function createRemoteClient(options?: RemoteClientOptions) {
101-
// The base URL for the Arcjet API. Will default to the standard production
102-
// API unless environment variable `ARCJET_BASE_URL` is set.
103124
const url = options?.baseUrl ?? baseUrl(process.env);
104-
105-
// The timeout for the Arcjet API in milliseconds. This is set to a low value
106-
// in production so calls fail open.
107125
const timeout = options?.timeout ?? (isDevelopment(process.env) ? 1000 : 500);
108126

109127
// Transport is the HTTP client that the client uses to make requests.
@@ -126,21 +144,83 @@ type EventHandlerLike = (
126144
listener: (...args: any[]) => void,
127145
) => void;
128146

129-
// Interface of fields that the Arcjet Nest.js SDK expects on Request objects
147+
/**
148+
* Nest request.
149+
*/
130150
export interface ArcjetNestRequest {
151+
/**
152+
* Headers.
153+
*/
131154
headers?: Record<string, string | string[] | undefined>;
155+
/**
156+
* HTTP method of the request.
157+
*/
132158
method?: string;
159+
/**
160+
* URL.
161+
*/
133162
url?: string;
163+
/**
164+
* Request body.
165+
*/
134166
body?: unknown;
135-
// Will only exist for Fastify
167+
/**
168+
* Request ID.
169+
*
170+
* This field is available on Fastify requests:
171+
* <https://fastify.dev/docs/latest/Reference/Request/#request>.
172+
*/
136173
id?: string;
174+
/**
175+
* IP address of the client.
176+
*/
137177
ip?: string;
178+
/**
179+
* Protocol of the request.
180+
*/
138181
protocol?: string;
182+
/**
183+
* Host of the request.
184+
*/
139185
host?: string;
140-
// Will only exist for Express
186+
/**
187+
* `net.Socket` object associated with the connection.
188+
*
189+
* This field is available on Express requests,
190+
* as those inherit from Node `http.IncomingMessage`.
191+
*
192+
* See <https://nodejs.org/api/http.html#messagesocket>.
193+
*/
141194
socket?: Partial<{ remoteAddress: string; encrypted: boolean }>;
195+
/**
196+
* Add event handlers.
197+
*
198+
* This field is available on Express requests,
199+
* as those inherit from Node `http.IncomingMessage`,
200+
* in turn from `stream.Readable` and `EventEmitter`.
201+
*
202+
* See <https://nodejs.org/api/events.html#emitteroneventname-listener>.
203+
*/
142204
on?: EventHandlerLike;
205+
/**
206+
* Remove event handlers.
207+
*
208+
* This field is available on Express requests,
209+
* as those inherit from Node `http.IncomingMessage`,
210+
* in turn from `stream.Readable` and `EventEmitter`.
211+
*
212+
* See <https://nodejs.org/api/events.html#emitterremovelistenereventname-listener>.
213+
*/
143214
removeListener?: EventHandlerLike;
215+
/**
216+
* Whether the readable stream is readable.
217+
*
218+
* This field is available on Express requests,
219+
* as those inherit from Node `http.IncomingMessage`,
220+
* in turn from `stream.Readable`.
221+
*
222+
* See <https://nodejs.org/api/stream.html#readablereadable>.
223+
*/
144224
readable?: boolean;
145225
}
146226

@@ -158,34 +238,50 @@ function cookiesToString(cookies: string | string[] | undefined): string {
158238
}
159239

160240
/**
161-
* The options used to configure an {@link ArcjetNest} client.
241+
* Configuration for the Nest integration of Arcjet.
242+
*
243+
* @template Rules
244+
* List of rules.
245+
* @template Characteristics
246+
* Characteristics to track a user by.
162247
*/
163248
export type ArcjetOptions<
164249
Rules extends [...Array<Primitive | Product>],
165250
Characteristics extends readonly string[],
166251
> = Simplify<
167252
CoreOptions<Rules, Characteristics> & {
168253
/**
169-
* One or more IP Address of trusted proxies in front of the application.
170-
* These addresses will be excluded when Arcjet detects a public IP address.
254+
* IP addresses and CIDR ranges of trusted load balancers and proxies
255+
* (optional, example: `["100.100.100.100", "100.100.100.0/24"]`).
171256
*/
172257
proxies?: Array<string>;
173258
}
174259
>;
175260

176261
/**
177-
* The ArcjetNest client provides a public `protect()` method to
178-
* make a decision about how a NestJS request should be handled.
262+
* Instance of the Nest integration of Arcjet.
263+
*
264+
* Primarily has a `protect()` method to make a decision about how a Nest request
265+
* should be handled.
266+
*
267+
* @template Props
268+
* Configuration.
179269
*/
180270
export interface ArcjetNest<Props extends PlainObject = {}> {
181271
/**
182-
* Runs a request through the configured protections. The request is
183-
* analyzed and then a decision made on whether to allow, deny, or challenge
184-
* the request.
272+
* Make a decision about how to handle a request.
273+
*
274+
* This will analyze the request locally where possible and otherwise call
275+
* the Arcjet decision API.
185276
*
186-
* @param req - An `IncomingMessage` provided to the request handler.
187-
* @param props - Additonal properties required for running rules against a request.
188-
* @returns An {@link ArcjetDecision} indicating Arcjet's decision about the request.
277+
* @param request
278+
* Details about the {@linkcode ArcjetNestRequest} that Arcjet needs to make a
279+
* decision.
280+
* @param props
281+
* Additional properties required for running rules against a request.
282+
* @returns
283+
* Promise that resolves to an {@linkcode ArcjetDecision} indicating
284+
* Arcjet’s decision about the request.
189285
*/
190286
protect(
191287
request: ArcjetNestRequest,
@@ -195,11 +291,17 @@ export interface ArcjetNest<Props extends PlainObject = {}> {
195291
): Promise<ArcjetDecision>;
196292

197293
/**
198-
* Augments the client with another rule. Useful for varying rules based on
199-
* criteria in your handler—e.g. different rate limit for logged in users.
294+
* Augment the client with another rule.
200295
*
201-
* @param rule The rule to add to this execution.
202-
* @returns An augmented {@link ArcjetNest} client.
296+
* Useful for varying rules based on criteria in your handler such as
297+
* different rate limit for logged in users.
298+
*
299+
* @template Rule
300+
* Type of rule.
301+
* @param rule
302+
* Rule to add to Arcjet.
303+
* @returns
304+
* Arcjet instance augmented with the given rule.
203305
*/
204306
withRule<Rule extends Primitive | Product>(
205307
rule: Rule,
@@ -405,7 +507,13 @@ function arcjet<
405507
return withClient(aj);
406508
}
407509

510+
/**
511+
* Symbol for Arcjet.
512+
*
513+
* Used as a label of providers that should be available in other modules.
514+
*/
408515
export const ARCJET = Symbol("ARCJET");
516+
409517
const ARCJET_OPTIONS = Symbol("ARCJET_OPTIONS");
410518
const ARCJET_WITH_RULES = Symbol("ARCJET_WITH_RULES");
411519

@@ -446,9 +554,22 @@ function requestFromContext(context: ExecutionContext) {
446554
}
447555
}
448556

557+
/**
558+
* Nest guard for the Arcjet Nest integration.
559+
*
560+
* See: <https://docs.nestjs.com/guards>.
561+
*/
449562
let ArcjetGuard = class ArcjetGuard implements CanActivate {
450563
aj: ArcjetNest<WithoutCustomProps>;
451564

565+
/**
566+
* Create a Nest guard for the Arcjet.
567+
*
568+
* @param aj
569+
* Arcjet Nest integration.
570+
* @returns
571+
* Arcjet Nest guard.
572+
*/
452573
constructor(aj: ArcjetNest<WithoutCustomProps>) {
453574
this.aj = aj;
454575
}
@@ -484,12 +605,34 @@ let ArcjetGuard = class ArcjetGuard implements CanActivate {
484605
ArcjetGuard = decorate([param(0, Inject(ARCJET))], ArcjetGuard);
485606
export { ArcjetGuard };
486607

608+
/**
609+
* Create Nest modules for the Arcjet Nest integration.
610+
*
611+
* See: <https://docs.nestjs.com/modules>.
612+
*/
487613
export class ArcjetModule {
614+
/**
615+
* Create a Nest module for the Arcjet Nest integration.
616+
*
617+
* You can pass your API key and any default rules that you want to apply to
618+
* every route.
619+
* This is usually in the `app.module.ts` file.
620+
*
621+
* @param options
622+
* Configuration (required).
623+
* @returns
624+
* Dynamic Nest module.
625+
*/
488626
static forRoot<
489627
const Rules extends (Primitive | Product)[],
490628
const Characteristics extends readonly string[],
491629
>(
492630
options: ArcjetOptions<Rules, Characteristics> & {
631+
/**
632+
* Whether to make the module global-scoped (`boolean`, default: `false`).
633+
*
634+
* Global-scoped modules will be visible in all modules.
635+
*/
493636
isGlobal?: boolean | undefined;
494637
},
495638
): DynamicModule {
@@ -514,13 +657,34 @@ export class ArcjetModule {
514657
exports: [ARCJET],
515658
};
516659
}
660+
661+
/**
662+
* Create a Nest module for the Arcjet Nest integration,
663+
* asynchronously.
664+
*
665+
* You can pass your API key and any default rules that you want to apply to
666+
* every route.
667+
* This is usually in the `app.module.ts` file.
668+
*
669+
* @param options
670+
* Configuration (required).
671+
* @returns
672+
* Dynamic Nest module.
673+
*/
517674
static forRootAsync<
518675
const Rules extends (Primitive | Product)[],
519676
const Characteristics extends readonly string[],
520677
>(
521678
options: ConfigurableModuleAsyncOptions<
522679
ArcjetOptions<Rules, Characteristics>
523-
> & { isGlobal?: boolean | undefined },
680+
> & {
681+
/**
682+
* Whether to make the module global-scoped (`boolean`, default: `false`).
683+
*
684+
* Global-scoped modules will be visible in all modules.
685+
*/
686+
isGlobal?: boolean | undefined;
687+
},
524688
): DynamicModule {
525689
const ArcjetProvider = {
526690
provide: ARCJET,
@@ -582,6 +746,21 @@ export class ArcjetModule {
582746
}
583747
}
584748

749+
/**
750+
* Decorator that binds Arcjet rules to the scope of the controller or method,
751+
* depending on its context.
752+
*
753+
* When `@WithArcjetRules` is used at the controller level,
754+
* the rules will be applied to every handler (method) in the controller.
755+
*
756+
* When `@WithArcjetRules` is used at the individual handler level,
757+
* the rules will apply only to that specific method.
758+
*
759+
* @param rules
760+
* List of rules.
761+
* @returns
762+
* Decorator.
763+
*/
585764
export function WithArcjetRules(rules: Array<Primitive | Product>) {
586765
return SetMetadata(ARCJET_WITH_RULES, rules);
587766
}

0 commit comments

Comments
 (0)