@wxn0brp/falcon-frame 0.0.6 → 0.0.8

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.
@@ -0,0 +1,7 @@
1
+ import { Plugin } from "../plugins.js";
2
+ interface Opts {
3
+ accessControlAllowMethods?: boolean;
4
+ accessControlAllowHeaders?: boolean;
5
+ }
6
+ export declare function createCORSPlugin(allowedOrigins: string[], opts?: Opts): Plugin;
7
+ export {};
@@ -0,0 +1,33 @@
1
+ function setHeader(res, opts) {
2
+ if (opts.accessControlAllowMethods)
3
+ res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
4
+ if (opts.accessControlAllowHeaders)
5
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
6
+ }
7
+ export function createCORSPlugin(allowedOrigins, opts = {}) {
8
+ opts = {
9
+ accessControlAllowMethods: true,
10
+ accessControlAllowHeaders: true,
11
+ ...opts,
12
+ };
13
+ return {
14
+ id: "cors",
15
+ process: (req, res, next) => {
16
+ if (allowedOrigins.includes("*")) {
17
+ res.setHeader("Access-Control-Allow-Origin", "*");
18
+ setHeader(res, opts);
19
+ return next();
20
+ }
21
+ const origin = req.headers.origin;
22
+ if (origin && allowedOrigins.includes(origin)) {
23
+ res.setHeader("Access-Control-Allow-Origin", origin);
24
+ setHeader(res, opts);
25
+ }
26
+ if (req.method === "OPTIONS") {
27
+ res.statusCode = 204;
28
+ return res.end();
29
+ }
30
+ next();
31
+ },
32
+ };
33
+ }
@@ -0,0 +1,2 @@
1
+ import { Plugin } from "../plugins.js";
2
+ export declare function createRateLimiterPlugin(maxRequests: number, windowMs: number): Plugin;
@@ -0,0 +1,23 @@
1
+ export function createRateLimiterPlugin(maxRequests, windowMs) {
2
+ const rateLimitMap = new Map();
3
+ return {
4
+ id: "rateLimiter",
5
+ process: (req, res, next) => {
6
+ const ip = req.socket.remoteAddress ?? "unknown";
7
+ const now = Date.now();
8
+ const record = rateLimitMap.get(ip);
9
+ if (!record || now - record.lastRequest > windowMs) {
10
+ rateLimitMap.set(ip, { count: 1, lastRequest: now });
11
+ return next();
12
+ }
13
+ if (record.count >= maxRequests) {
14
+ res.statusCode = 429;
15
+ return res.end("Too Many Requests");
16
+ }
17
+ record.count++;
18
+ record.lastRequest = now;
19
+ rateLimitMap.set(ip, record);
20
+ next();
21
+ },
22
+ };
23
+ }
package/dist/plugins.d.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  import { RouteHandler } from "./types.js";
2
- type PluginId = string;
3
- interface Plugin {
2
+ export type PluginId = string;
3
+ export interface Plugin {
4
4
  id: PluginId;
5
5
  process: RouteHandler;
6
6
  priority?: number;
7
7
  }
8
+ export interface PluginOptions {
9
+ before?: PluginId | PluginId[];
10
+ after?: PluginId | PluginId[];
11
+ optional?: boolean;
12
+ }
8
13
  export declare class PluginSystem {
9
14
  private plugins;
10
15
  private executionOrder;
@@ -13,10 +18,7 @@ export declare class PluginSystem {
13
18
  * @param plugin - Plugin to register
14
19
  * @param options - Options for positioning plugins
15
20
  */
16
- register(plugin: Plugin, options?: {
17
- before?: PluginId;
18
- after?: PluginId;
19
- }): void;
21
+ register(plugin: Plugin, options?: PluginOptions): void;
20
22
  /**
21
23
  * Updates the execution order of plugins
22
24
  * @param pluginId - ID of the plugin to position
@@ -40,4 +42,3 @@ export declare class PluginSystem {
40
42
  */
41
43
  getPluginsInOrder(): Plugin[];
42
44
  }
43
- export {};
package/dist/plugins.js CHANGED
@@ -21,25 +21,37 @@ export class PluginSystem {
21
21
  * @param options - Options for positioning
22
22
  */
23
23
  updateExecutionOrder(pluginId, options) {
24
- if (!this.executionOrder.includes(pluginId)) {
25
- if (options?.before) {
26
- const index = this.executionOrder.indexOf(options.before);
27
- if (index === -1) {
28
- throw new Error(`Plugin '${options.before}' not found`);
29
- }
30
- this.executionOrder.splice(index, 0, pluginId);
31
- }
32
- else if (options?.after) {
33
- const index = this.executionOrder.indexOf(options.after);
34
- if (index === -1) {
35
- throw new Error(`Plugin '${options.after}' not found`);
36
- }
37
- this.executionOrder.splice(index + 1, 0, pluginId);
24
+ if (this.executionOrder.includes(pluginId))
25
+ return;
26
+ const resolveTarget = (target) => {
27
+ if (!target)
28
+ return null;
29
+ const list = Array.isArray(target) ? target : [target];
30
+ return list.find(id => this.executionOrder.includes(id)) || null;
31
+ };
32
+ const beforeTarget = resolveTarget(options?.before);
33
+ const afterTarget = resolveTarget(options?.after);
34
+ if (beforeTarget) {
35
+ const index = this.executionOrder.indexOf(beforeTarget);
36
+ this.executionOrder.splice(index, 0, pluginId);
37
+ }
38
+ else if (afterTarget) {
39
+ const index = this.executionOrder.indexOf(afterTarget);
40
+ this.executionOrder.splice(index + 1, 0, pluginId);
41
+ }
42
+ else if (options?.before || options?.after) {
43
+ if (options.optional) {
44
+ this.executionOrder.push(pluginId); // fallback: add to the end
38
45
  }
39
46
  else {
40
- this.executionOrder.push(pluginId);
47
+ throw new Error(`Plugin dependency not found for '${pluginId}': ` +
48
+ `before=${JSON.stringify(options?.before)}, ` +
49
+ `after=${JSON.stringify(options?.after)}`);
41
50
  }
42
51
  }
52
+ else {
53
+ this.executionOrder.push(pluginId);
54
+ }
43
55
  }
44
56
  /**
45
57
  * Returns a RouteHandler that executes all registered plugins in the correct order
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxn0brp/falcon-frame",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "author": "wxn0brP",