dauth-md-node 1.0.0 → 2.0.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
@@ -47,7 +47,7 @@ Factory function that returns an Express middleware.
47
47
 
48
48
  1. Extracts the `Authorization` header from the request
49
49
  2. Verifies the JWT locally using the provided `tsk` (Tenant Secret Key)
50
- 3. Fetches the full user object from the DAuth backend (`GET /tenant/:domainName/user`)
50
+ 3. Fetches the full user object from the DAuth backend (`GET /app/:domainName/user`)
51
51
  4. Attaches the user to `req.user`
52
52
  5. Calls `next()` on success
53
53
 
@@ -169,17 +169,17 @@ export const getMyLicenses = async (req: IRequestDauth, res: Response) => {
169
169
  ## Environment Detection
170
170
 
171
171
  - **Development** (`NODE_ENV=development`): Routes API calls to `http://localhost:4012/api/v1`
172
- - **Production**: Routes API calls to `https://<domainName>.dauth.ovh/api/v1`
172
+ - **Production**: Routes API calls to `https://dauth.ovh/api/v1`
173
173
 
174
174
  ## Development
175
175
 
176
176
  ```bash
177
- npm start # Watch mode (tsdx watch)
178
- npm run build # Production build (CJS + ESM)
179
- npm test # Run Jest tests
180
- npm run lint # ESLint via tsdx
181
- npm run size # Check bundle size (10KB budget per entry)
182
- npm run analyze # Bundle size analysis with visualization
177
+ pnpm start # Watch mode (tsdx watch)
178
+ pnpm build # Production build (CJS + ESM)
179
+ pnpm test # Run Jest tests
180
+ pnpm lint # ESLint via tsdx
181
+ pnpm size # Check bundle size (10KB budget per entry)
182
+ pnpm analyze # Bundle size analysis with visualization
183
183
  ```
184
184
 
185
185
  ### Bundle Outputs
@@ -0,0 +1,64 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+
3
+ interface CacheOptions {
4
+ ttlMs: number;
5
+ }
6
+ declare class UserCache {
7
+ private store;
8
+ private ttlMs;
9
+ constructor(options: CacheOptions);
10
+ get(token: string): IDauthUser | undefined;
11
+ set(token: string, user: IDauthUser): void;
12
+ clear(): void;
13
+ private sweep;
14
+ }
15
+
16
+ interface IDauthUser {
17
+ _id: string;
18
+ name: string;
19
+ lastname: string;
20
+ nickname: string;
21
+ email: string;
22
+ isVerified: boolean;
23
+ language: string;
24
+ avatar: {
25
+ id: string;
26
+ url: string;
27
+ };
28
+ role: string;
29
+ telPrefix: string;
30
+ telSuffix: string;
31
+ birthDate?: string;
32
+ country?: string;
33
+ metadata?: Record<string, unknown>;
34
+ createdAt: Date;
35
+ updatedAt: Date;
36
+ lastLogin: Date;
37
+ }
38
+ interface IRequestDauth extends Request {
39
+ user: IDauthUser;
40
+ files: {
41
+ image: {
42
+ path: string;
43
+ };
44
+ avatar: {
45
+ path: string;
46
+ };
47
+ };
48
+ headers: {
49
+ authorization: string;
50
+ };
51
+ }
52
+ interface DauthOptions {
53
+ domainName: string;
54
+ tsk: string;
55
+ cache?: CacheOptions;
56
+ }
57
+ interface TCustomResponse extends Response {
58
+ status(code: number): this;
59
+ send(body?: unknown): this;
60
+ }
61
+
62
+ declare const dauth: ({ domainName, tsk, cache }: DauthOptions) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Promise<void | TCustomResponse>;
63
+
64
+ export { type CacheOptions, type DauthOptions, type IDauthUser, type IRequestDauth, UserCache, dauth };
package/dist/index.d.ts CHANGED
@@ -1,43 +1,64 @@
1
- import { Request, NextFunction, Response as ExpressResponse, Handler } from 'express';
2
- export interface IDauthUser {
3
- _id: string;
4
- name: string;
5
- lastname: string;
6
- nickname: string;
7
- email: string;
8
- isVerified: boolean;
9
- language: string;
10
- avatar: {
11
- id: string;
12
- url: string;
13
- };
14
- role: string;
15
- telPrefix: string;
16
- telSuffix: string;
17
- createdAt: Date;
18
- updatedAt: Date;
19
- lastLogin: Date;
20
- }
21
- export interface IRequestDauth extends Request {
22
- user: IDauthUser;
23
- files: {
24
- image: {
25
- path: string;
26
- };
27
- avatar: {
28
- path: string;
29
- };
30
- };
31
- headers: {
32
- authorization: string;
33
- };
34
- }
35
- interface TCustomResponse extends ExpressResponse {
36
- status(code: number): any;
37
- send(body?: any): any;
38
- }
39
- export declare const dauth: ({ domainName, tsk, }: {
40
- domainName: string;
41
- tsk: string;
42
- }) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Handler | void;
43
- export {};
1
+ import { Request, Response, NextFunction } from 'express';
2
+
3
+ interface CacheOptions {
4
+ ttlMs: number;
5
+ }
6
+ declare class UserCache {
7
+ private store;
8
+ private ttlMs;
9
+ constructor(options: CacheOptions);
10
+ get(token: string): IDauthUser | undefined;
11
+ set(token: string, user: IDauthUser): void;
12
+ clear(): void;
13
+ private sweep;
14
+ }
15
+
16
+ interface IDauthUser {
17
+ _id: string;
18
+ name: string;
19
+ lastname: string;
20
+ nickname: string;
21
+ email: string;
22
+ isVerified: boolean;
23
+ language: string;
24
+ avatar: {
25
+ id: string;
26
+ url: string;
27
+ };
28
+ role: string;
29
+ telPrefix: string;
30
+ telSuffix: string;
31
+ birthDate?: string;
32
+ country?: string;
33
+ metadata?: Record<string, unknown>;
34
+ createdAt: Date;
35
+ updatedAt: Date;
36
+ lastLogin: Date;
37
+ }
38
+ interface IRequestDauth extends Request {
39
+ user: IDauthUser;
40
+ files: {
41
+ image: {
42
+ path: string;
43
+ };
44
+ avatar: {
45
+ path: string;
46
+ };
47
+ };
48
+ headers: {
49
+ authorization: string;
50
+ };
51
+ }
52
+ interface DauthOptions {
53
+ domainName: string;
54
+ tsk: string;
55
+ cache?: CacheOptions;
56
+ }
57
+ interface TCustomResponse extends Response {
58
+ status(code: number): this;
59
+ send(body?: unknown): this;
60
+ }
61
+
62
+ declare const dauth: ({ domainName, tsk, cache }: DauthOptions) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Promise<void | TCustomResponse>;
63
+
64
+ export { type CacheOptions, type DauthOptions, type IDauthUser, type IRequestDauth, UserCache, dauth };
package/dist/index.js CHANGED
@@ -1,8 +1,171 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
29
 
2
- 'use strict'
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ UserCache: () => UserCache,
34
+ dauth: () => dauth
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
3
38
 
4
- if (process.env.NODE_ENV === 'production') {
5
- module.exports = require('./dauth-md-node.cjs.production.min.js')
6
- } else {
7
- module.exports = require('./dauth-md-node.cjs.development.js')
39
+ // src/api/utils/config.ts
40
+ var apiVersion = "v1";
41
+ var serverDomain = "dauth.ovh";
42
+ function getServerBasePath() {
43
+ if (process.env.DAUTH_URL) {
44
+ const base = process.env.DAUTH_URL.replace(/\/+$/, "");
45
+ return `${base}/api/${apiVersion}`;
46
+ }
47
+ const isLocalhost = process.env.NODE_ENV === "development";
48
+ const serverPort = 4012;
49
+ const serverLocalUrl = `http://localhost:${serverPort}/api/${apiVersion}`;
50
+ const serverProdUrl = `https://${serverDomain}/api/${apiVersion}`;
51
+ return isLocalhost ? serverLocalUrl : serverProdUrl;
8
52
  }
53
+
54
+ // src/api/dauth.api.ts
55
+ async function getUser(token, domainName) {
56
+ const response = await fetch(
57
+ `${getServerBasePath()}/app/${domainName}/user`,
58
+ {
59
+ method: "GET",
60
+ headers: {
61
+ Authorization: token,
62
+ "Content-Type": "application/json"
63
+ }
64
+ }
65
+ );
66
+ const data = await response.json();
67
+ return { response: { status: response.status }, data };
68
+ }
69
+
70
+ // src/cache.ts
71
+ var UserCache = class {
72
+ store = /* @__PURE__ */ new Map();
73
+ ttlMs;
74
+ constructor(options) {
75
+ this.ttlMs = options.ttlMs;
76
+ }
77
+ get(token) {
78
+ const entry = this.store.get(token);
79
+ if (!entry) return void 0;
80
+ if (Date.now() > entry.expiresAt) {
81
+ this.store.delete(token);
82
+ return void 0;
83
+ }
84
+ return entry.user;
85
+ }
86
+ set(token, user) {
87
+ if (this.store.size > 1e3) {
88
+ this.sweep();
89
+ }
90
+ this.store.set(token, { user, expiresAt: Date.now() + this.ttlMs });
91
+ }
92
+ clear() {
93
+ this.store.clear();
94
+ }
95
+ sweep() {
96
+ const now = Date.now();
97
+ for (const [key, entry] of this.store) {
98
+ if (now > entry.expiresAt) {
99
+ this.store.delete(key);
100
+ }
101
+ }
102
+ }
103
+ };
104
+
105
+ // src/index.ts
106
+ var dauth = ({ domainName, tsk, cache }) => {
107
+ const userCache = cache ? new UserCache(cache) : null;
108
+ return async (req, res, next) => {
109
+ if (!req.headers.authorization) {
110
+ return res.status(403).send({ status: "token-not-found", message: "Token not found" });
111
+ }
112
+ const token = req.headers.authorization.replace(/['"]+/g, "");
113
+ try {
114
+ import_jsonwebtoken.default.verify(token, tsk);
115
+ } catch (error) {
116
+ const message = error instanceof Error ? error.message : "Token invalid";
117
+ if (message === "jwt expired") {
118
+ return res.status(401).send({ status: "token-expired", message: "jwt expired" });
119
+ }
120
+ if (message === "invalid signature") {
121
+ return res.status(401).send({
122
+ status: "tsk-not-invalid",
123
+ message: "The TSK variable in the backend middleware is not valid"
124
+ });
125
+ }
126
+ return res.status(401).send({ status: "token-invalid", message });
127
+ }
128
+ if (userCache) {
129
+ const cachedUser = userCache.get(token);
130
+ if (cachedUser) {
131
+ req.user = cachedUser;
132
+ return next();
133
+ }
134
+ }
135
+ try {
136
+ const getUserFetch = await getUser(token, domainName);
137
+ if (getUserFetch.response.status === 404) {
138
+ return res.status(404).send({
139
+ status: "user-not-found",
140
+ message: getUserFetch.data.message ?? "User does not exist"
141
+ });
142
+ }
143
+ if (getUserFetch.response.status === 500) {
144
+ return res.status(500).send({
145
+ status: "error",
146
+ message: getUserFetch.data.message ?? "Dauth server error"
147
+ });
148
+ }
149
+ if (getUserFetch.response.status === 200) {
150
+ req.user = getUserFetch.data.user;
151
+ if (userCache) {
152
+ userCache.set(token, req.user);
153
+ }
154
+ return next();
155
+ }
156
+ return res.status(501).send({
157
+ status: "request-error",
158
+ message: getUserFetch.data.message ?? "Dauth server error"
159
+ });
160
+ } catch (error) {
161
+ const message = error instanceof Error ? error.message : "Dauth server error";
162
+ return res.status(500).send({ status: "server-error", message });
163
+ }
164
+ };
165
+ };
166
+ // Annotate the CommonJS export names for ESM import in node:
167
+ 0 && (module.exports = {
168
+ UserCache,
169
+ dauth
170
+ });
171
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/api/utils/config.ts","../src/api/dauth.api.ts","../src/cache.ts"],"sourcesContent":["import { Request, NextFunction, Response as ExpressResponse } from 'express';\nimport jwt from 'jsonwebtoken';\nimport { getUser } from './api/dauth.api';\nimport { UserCache } from './cache';\nimport type { CacheOptions } from './cache';\n\nexport interface IDauthUser {\n _id: string;\n name: string;\n lastname: string;\n nickname: string;\n email: string;\n isVerified: boolean;\n language: string;\n avatar: {\n id: string;\n url: string;\n };\n role: string;\n telPrefix: string;\n telSuffix: string;\n birthDate?: string;\n country?: string;\n metadata?: Record<string, unknown>;\n createdAt: Date;\n updatedAt: Date;\n lastLogin: Date;\n}\n\nexport interface IRequestDauth extends Request {\n user: IDauthUser;\n files: {\n image: { path: string };\n avatar: { path: string };\n };\n headers: {\n authorization: string;\n };\n}\n\nexport interface DauthOptions {\n domainName: string;\n tsk: string;\n cache?: CacheOptions;\n}\n\ninterface TCustomResponse extends ExpressResponse {\n status(code: number): this;\n send(body?: unknown): this;\n}\n\nexport { UserCache };\nexport type { CacheOptions };\n\nexport const dauth = ({ domainName, tsk, cache }: DauthOptions) => {\n const userCache = cache ? new UserCache(cache) : null;\n\n return async (\n req: IRequestDauth,\n res: TCustomResponse,\n next: NextFunction\n ) => {\n if (!req.headers.authorization) {\n return res\n .status(403)\n .send({ status: 'token-not-found', message: 'Token not found' });\n }\n\n const token = req.headers.authorization.replace(/['\"]+/g, '');\n\n try {\n jwt.verify(token, tsk);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Token invalid';\n\n if (message === 'jwt expired') {\n return res\n .status(401)\n .send({ status: 'token-expired', message: 'jwt expired' });\n }\n if (message === 'invalid signature') {\n return res.status(401).send({\n status: 'tsk-not-invalid',\n message:\n 'The TSK variable in the backend middleware is not valid',\n });\n }\n return res\n .status(401)\n .send({ status: 'token-invalid', message });\n }\n\n if (userCache) {\n const cachedUser = userCache.get(token);\n if (cachedUser) {\n req.user = cachedUser;\n return next();\n }\n }\n\n try {\n const getUserFetch = await getUser(token, domainName);\n\n if (getUserFetch.response.status === 404) {\n return res.status(404).send({\n status: 'user-not-found',\n message: getUserFetch.data.message ?? 'User does not exist',\n });\n }\n if (getUserFetch.response.status === 500) {\n return res.status(500).send({\n status: 'error',\n message: getUserFetch.data.message ?? 'Dauth server error',\n });\n }\n if (getUserFetch.response.status === 200) {\n req.user = getUserFetch.data.user;\n if (userCache) {\n userCache.set(token, req.user);\n }\n return next();\n }\n return res.status(501).send({\n status: 'request-error',\n message: getUserFetch.data.message ?? 'Dauth server error',\n });\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Dauth server error';\n return res\n .status(500)\n .send({ status: 'server-error', message });\n }\n };\n};\n","export const apiVersion = 'v1';\nexport const serverDomain = 'dauth.ovh';\n\nexport function getServerBasePath(): string {\n if (process.env.DAUTH_URL) {\n const base = process.env.DAUTH_URL.replace(/\\/+$/, '');\n return `${base}/api/${apiVersion}`;\n }\n\n const isLocalhost = process.env.NODE_ENV === 'development';\n const serverPort = 4012;\n const serverLocalUrl = `http://localhost:${serverPort}/api/${apiVersion}`;\n const serverProdUrl = `https://${serverDomain}/api/${apiVersion}`;\n return isLocalhost ? serverLocalUrl : serverProdUrl;\n}\n","import { getServerBasePath } from './utils/config';\n\ninterface GetUserResponse {\n response: { status: number };\n data: { user?: any; message?: string };\n}\n\nexport async function getUser(\n token: string,\n domainName: string\n): Promise<GetUserResponse> {\n const response = await fetch(\n `${getServerBasePath()}/app/${domainName}/user`,\n {\n method: 'GET',\n headers: {\n Authorization: token,\n 'Content-Type': 'application/json',\n },\n }\n );\n const data = (await response.json()) as GetUserResponse['data'];\n return { response: { status: response.status }, data };\n}\n","import { IDauthUser } from './index';\n\ninterface CacheEntry {\n user: IDauthUser;\n expiresAt: number;\n}\n\nexport interface CacheOptions {\n ttlMs: number;\n}\n\nexport class UserCache {\n private store = new Map<string, CacheEntry>();\n private ttlMs: number;\n\n constructor(options: CacheOptions) {\n this.ttlMs = options.ttlMs;\n }\n\n get(token: string): IDauthUser | undefined {\n const entry = this.store.get(token);\n if (!entry) return undefined;\n\n if (Date.now() > entry.expiresAt) {\n this.store.delete(token);\n return undefined;\n }\n\n return entry.user;\n }\n\n set(token: string, user: IDauthUser): void {\n if (this.store.size > 1000) {\n this.sweep();\n }\n this.store.set(token, { user, expiresAt: Date.now() + this.ttlMs });\n }\n\n clear(): void {\n this.store.clear();\n }\n\n private sweep(): void {\n const now = Date.now();\n for (const [key, entry] of this.store) {\n if (now > entry.expiresAt) {\n this.store.delete(key);\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAAgB;;;ACDT,IAAM,aAAa;AACnB,IAAM,eAAe;AAErB,SAAS,oBAA4B;AAC1C,MAAI,QAAQ,IAAI,WAAW;AACzB,UAAM,OAAO,QAAQ,IAAI,UAAU,QAAQ,QAAQ,EAAE;AACrD,WAAO,GAAG,IAAI,QAAQ,UAAU;AAAA,EAClC;AAEA,QAAM,cAAc,QAAQ,IAAI,aAAa;AAC7C,QAAM,aAAa;AACnB,QAAM,iBAAiB,oBAAoB,UAAU,QAAQ,UAAU;AACvE,QAAM,gBAAgB,WAAW,YAAY,QAAQ,UAAU;AAC/D,SAAO,cAAc,iBAAiB;AACxC;;;ACPA,eAAsB,QACpB,OACA,YAC0B;AAC1B,QAAM,WAAW,MAAM;AAAA,IACrB,GAAG,kBAAkB,CAAC,QAAQ,UAAU;AAAA,IACxC;AAAA,MACE,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe;AAAA,QACf,gBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,EAAE,UAAU,EAAE,QAAQ,SAAS,OAAO,GAAG,KAAK;AACvD;;;ACZO,IAAM,YAAN,MAAgB;AAAA,EACb,QAAQ,oBAAI,IAAwB;AAAA,EACpC;AAAA,EAER,YAAY,SAAuB;AACjC,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAEA,IAAI,OAAuC;AACzC,UAAM,QAAQ,KAAK,MAAM,IAAI,KAAK;AAClC,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI,KAAK,IAAI,IAAI,MAAM,WAAW;AAChC,WAAK,MAAM,OAAO,KAAK;AACvB,aAAO;AAAA,IACT;AAEA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,OAAe,MAAwB;AACzC,QAAI,KAAK,MAAM,OAAO,KAAM;AAC1B,WAAK,MAAM;AAAA,IACb;AACA,SAAK,MAAM,IAAI,OAAO,EAAE,MAAM,WAAW,KAAK,IAAI,IAAI,KAAK,MAAM,CAAC;AAAA,EACpE;AAAA,EAEA,QAAc;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA,EAEQ,QAAc;AACpB,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,OAAO;AACrC,UAAI,MAAM,MAAM,WAAW;AACzB,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;;;AHIO,IAAM,QAAQ,CAAC,EAAE,YAAY,KAAK,MAAM,MAAoB;AACjE,QAAM,YAAY,QAAQ,IAAI,UAAU,KAAK,IAAI;AAEjD,SAAO,OACL,KACA,KACA,SACG;AACH,QAAI,CAAC,IAAI,QAAQ,eAAe;AAC9B,aAAO,IACJ,OAAO,GAAG,EACV,KAAK,EAAE,QAAQ,mBAAmB,SAAS,kBAAkB,CAAC;AAAA,IACnE;AAEA,UAAM,QAAQ,IAAI,QAAQ,cAAc,QAAQ,UAAU,EAAE;AAE5D,QAAI;AACF,0BAAAA,QAAI,OAAO,OAAO,GAAG;AAAA,IACvB,SAAS,OAAO;AACd,YAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAE3C,UAAI,YAAY,eAAe;AAC7B,eAAO,IACJ,OAAO,GAAG,EACV,KAAK,EAAE,QAAQ,iBAAiB,SAAS,cAAc,CAAC;AAAA,MAC7D;AACA,UAAI,YAAY,qBAAqB;AACnC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,QAAQ;AAAA,UACR,SACE;AAAA,QACJ,CAAC;AAAA,MACH;AACA,aAAO,IACJ,OAAO,GAAG,EACV,KAAK,EAAE,QAAQ,iBAAiB,QAAQ,CAAC;AAAA,IAC9C;AAEA,QAAI,WAAW;AACb,YAAM,aAAa,UAAU,IAAI,KAAK;AACtC,UAAI,YAAY;AACd,YAAI,OAAO;AACX,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAEA,QAAI;AACF,YAAM,eAAe,MAAM,QAAQ,OAAO,UAAU;AAEpD,UAAI,aAAa,SAAS,WAAW,KAAK;AACxC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,QAAQ;AAAA,UACR,SAAS,aAAa,KAAK,WAAW;AAAA,QACxC,CAAC;AAAA,MACH;AACA,UAAI,aAAa,SAAS,WAAW,KAAK;AACxC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,QAAQ;AAAA,UACR,SAAS,aAAa,KAAK,WAAW;AAAA,QACxC,CAAC;AAAA,MACH;AACA,UAAI,aAAa,SAAS,WAAW,KAAK;AACxC,YAAI,OAAO,aAAa,KAAK;AAC7B,YAAI,WAAW;AACb,oBAAU,IAAI,OAAO,IAAI,IAAI;AAAA,QAC/B;AACA,eAAO,KAAK;AAAA,MACd;AACA,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QAC1B,QAAQ;AAAA,QACR,SAAS,aAAa,KAAK,WAAW;AAAA,MACxC,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,aAAO,IACJ,OAAO,GAAG,EACV,KAAK,EAAE,QAAQ,gBAAgB,QAAQ,CAAC;AAAA,IAC7C;AAAA,EACF;AACF;","names":["jwt"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,135 @@
1
+ // src/index.ts
2
+ import jwt from "jsonwebtoken";
3
+
4
+ // src/api/utils/config.ts
5
+ var apiVersion = "v1";
6
+ var serverDomain = "dauth.ovh";
7
+ function getServerBasePath() {
8
+ if (process.env.DAUTH_URL) {
9
+ const base = process.env.DAUTH_URL.replace(/\/+$/, "");
10
+ return `${base}/api/${apiVersion}`;
11
+ }
12
+ const isLocalhost = process.env.NODE_ENV === "development";
13
+ const serverPort = 4012;
14
+ const serverLocalUrl = `http://localhost:${serverPort}/api/${apiVersion}`;
15
+ const serverProdUrl = `https://${serverDomain}/api/${apiVersion}`;
16
+ return isLocalhost ? serverLocalUrl : serverProdUrl;
17
+ }
18
+
19
+ // src/api/dauth.api.ts
20
+ async function getUser(token, domainName) {
21
+ const response = await fetch(
22
+ `${getServerBasePath()}/app/${domainName}/user`,
23
+ {
24
+ method: "GET",
25
+ headers: {
26
+ Authorization: token,
27
+ "Content-Type": "application/json"
28
+ }
29
+ }
30
+ );
31
+ const data = await response.json();
32
+ return { response: { status: response.status }, data };
33
+ }
34
+
35
+ // src/cache.ts
36
+ var UserCache = class {
37
+ store = /* @__PURE__ */ new Map();
38
+ ttlMs;
39
+ constructor(options) {
40
+ this.ttlMs = options.ttlMs;
41
+ }
42
+ get(token) {
43
+ const entry = this.store.get(token);
44
+ if (!entry) return void 0;
45
+ if (Date.now() > entry.expiresAt) {
46
+ this.store.delete(token);
47
+ return void 0;
48
+ }
49
+ return entry.user;
50
+ }
51
+ set(token, user) {
52
+ if (this.store.size > 1e3) {
53
+ this.sweep();
54
+ }
55
+ this.store.set(token, { user, expiresAt: Date.now() + this.ttlMs });
56
+ }
57
+ clear() {
58
+ this.store.clear();
59
+ }
60
+ sweep() {
61
+ const now = Date.now();
62
+ for (const [key, entry] of this.store) {
63
+ if (now > entry.expiresAt) {
64
+ this.store.delete(key);
65
+ }
66
+ }
67
+ }
68
+ };
69
+
70
+ // src/index.ts
71
+ var dauth = ({ domainName, tsk, cache }) => {
72
+ const userCache = cache ? new UserCache(cache) : null;
73
+ return async (req, res, next) => {
74
+ if (!req.headers.authorization) {
75
+ return res.status(403).send({ status: "token-not-found", message: "Token not found" });
76
+ }
77
+ const token = req.headers.authorization.replace(/['"]+/g, "");
78
+ try {
79
+ jwt.verify(token, tsk);
80
+ } catch (error) {
81
+ const message = error instanceof Error ? error.message : "Token invalid";
82
+ if (message === "jwt expired") {
83
+ return res.status(401).send({ status: "token-expired", message: "jwt expired" });
84
+ }
85
+ if (message === "invalid signature") {
86
+ return res.status(401).send({
87
+ status: "tsk-not-invalid",
88
+ message: "The TSK variable in the backend middleware is not valid"
89
+ });
90
+ }
91
+ return res.status(401).send({ status: "token-invalid", message });
92
+ }
93
+ if (userCache) {
94
+ const cachedUser = userCache.get(token);
95
+ if (cachedUser) {
96
+ req.user = cachedUser;
97
+ return next();
98
+ }
99
+ }
100
+ try {
101
+ const getUserFetch = await getUser(token, domainName);
102
+ if (getUserFetch.response.status === 404) {
103
+ return res.status(404).send({
104
+ status: "user-not-found",
105
+ message: getUserFetch.data.message ?? "User does not exist"
106
+ });
107
+ }
108
+ if (getUserFetch.response.status === 500) {
109
+ return res.status(500).send({
110
+ status: "error",
111
+ message: getUserFetch.data.message ?? "Dauth server error"
112
+ });
113
+ }
114
+ if (getUserFetch.response.status === 200) {
115
+ req.user = getUserFetch.data.user;
116
+ if (userCache) {
117
+ userCache.set(token, req.user);
118
+ }
119
+ return next();
120
+ }
121
+ return res.status(501).send({
122
+ status: "request-error",
123
+ message: getUserFetch.data.message ?? "Dauth server error"
124
+ });
125
+ } catch (error) {
126
+ const message = error instanceof Error ? error.message : "Dauth server error";
127
+ return res.status(500).send({ status: "server-error", message });
128
+ }
129
+ };
130
+ };
131
+ export {
132
+ UserCache,
133
+ dauth
134
+ };
135
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/api/utils/config.ts","../src/api/dauth.api.ts","../src/cache.ts"],"sourcesContent":["import { Request, NextFunction, Response as ExpressResponse } from 'express';\nimport jwt from 'jsonwebtoken';\nimport { getUser } from './api/dauth.api';\nimport { UserCache } from './cache';\nimport type { CacheOptions } from './cache';\n\nexport interface IDauthUser {\n _id: string;\n name: string;\n lastname: string;\n nickname: string;\n email: string;\n isVerified: boolean;\n language: string;\n avatar: {\n id: string;\n url: string;\n };\n role: string;\n telPrefix: string;\n telSuffix: string;\n birthDate?: string;\n country?: string;\n metadata?: Record<string, unknown>;\n createdAt: Date;\n updatedAt: Date;\n lastLogin: Date;\n}\n\nexport interface IRequestDauth extends Request {\n user: IDauthUser;\n files: {\n image: { path: string };\n avatar: { path: string };\n };\n headers: {\n authorization: string;\n };\n}\n\nexport interface DauthOptions {\n domainName: string;\n tsk: string;\n cache?: CacheOptions;\n}\n\ninterface TCustomResponse extends ExpressResponse {\n status(code: number): this;\n send(body?: unknown): this;\n}\n\nexport { UserCache };\nexport type { CacheOptions };\n\nexport const dauth = ({ domainName, tsk, cache }: DauthOptions) => {\n const userCache = cache ? new UserCache(cache) : null;\n\n return async (\n req: IRequestDauth,\n res: TCustomResponse,\n next: NextFunction\n ) => {\n if (!req.headers.authorization) {\n return res\n .status(403)\n .send({ status: 'token-not-found', message: 'Token not found' });\n }\n\n const token = req.headers.authorization.replace(/['\"]+/g, '');\n\n try {\n jwt.verify(token, tsk);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Token invalid';\n\n if (message === 'jwt expired') {\n return res\n .status(401)\n .send({ status: 'token-expired', message: 'jwt expired' });\n }\n if (message === 'invalid signature') {\n return res.status(401).send({\n status: 'tsk-not-invalid',\n message:\n 'The TSK variable in the backend middleware is not valid',\n });\n }\n return res\n .status(401)\n .send({ status: 'token-invalid', message });\n }\n\n if (userCache) {\n const cachedUser = userCache.get(token);\n if (cachedUser) {\n req.user = cachedUser;\n return next();\n }\n }\n\n try {\n const getUserFetch = await getUser(token, domainName);\n\n if (getUserFetch.response.status === 404) {\n return res.status(404).send({\n status: 'user-not-found',\n message: getUserFetch.data.message ?? 'User does not exist',\n });\n }\n if (getUserFetch.response.status === 500) {\n return res.status(500).send({\n status: 'error',\n message: getUserFetch.data.message ?? 'Dauth server error',\n });\n }\n if (getUserFetch.response.status === 200) {\n req.user = getUserFetch.data.user;\n if (userCache) {\n userCache.set(token, req.user);\n }\n return next();\n }\n return res.status(501).send({\n status: 'request-error',\n message: getUserFetch.data.message ?? 'Dauth server error',\n });\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Dauth server error';\n return res\n .status(500)\n .send({ status: 'server-error', message });\n }\n };\n};\n","export const apiVersion = 'v1';\nexport const serverDomain = 'dauth.ovh';\n\nexport function getServerBasePath(): string {\n if (process.env.DAUTH_URL) {\n const base = process.env.DAUTH_URL.replace(/\\/+$/, '');\n return `${base}/api/${apiVersion}`;\n }\n\n const isLocalhost = process.env.NODE_ENV === 'development';\n const serverPort = 4012;\n const serverLocalUrl = `http://localhost:${serverPort}/api/${apiVersion}`;\n const serverProdUrl = `https://${serverDomain}/api/${apiVersion}`;\n return isLocalhost ? serverLocalUrl : serverProdUrl;\n}\n","import { getServerBasePath } from './utils/config';\n\ninterface GetUserResponse {\n response: { status: number };\n data: { user?: any; message?: string };\n}\n\nexport async function getUser(\n token: string,\n domainName: string\n): Promise<GetUserResponse> {\n const response = await fetch(\n `${getServerBasePath()}/app/${domainName}/user`,\n {\n method: 'GET',\n headers: {\n Authorization: token,\n 'Content-Type': 'application/json',\n },\n }\n );\n const data = (await response.json()) as GetUserResponse['data'];\n return { response: { status: response.status }, data };\n}\n","import { IDauthUser } from './index';\n\ninterface CacheEntry {\n user: IDauthUser;\n expiresAt: number;\n}\n\nexport interface CacheOptions {\n ttlMs: number;\n}\n\nexport class UserCache {\n private store = new Map<string, CacheEntry>();\n private ttlMs: number;\n\n constructor(options: CacheOptions) {\n this.ttlMs = options.ttlMs;\n }\n\n get(token: string): IDauthUser | undefined {\n const entry = this.store.get(token);\n if (!entry) return undefined;\n\n if (Date.now() > entry.expiresAt) {\n this.store.delete(token);\n return undefined;\n }\n\n return entry.user;\n }\n\n set(token: string, user: IDauthUser): void {\n if (this.store.size > 1000) {\n this.sweep();\n }\n this.store.set(token, { user, expiresAt: Date.now() + this.ttlMs });\n }\n\n clear(): void {\n this.store.clear();\n }\n\n private sweep(): void {\n const now = Date.now();\n for (const [key, entry] of this.store) {\n if (now > entry.expiresAt) {\n this.store.delete(key);\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,63 +1,67 @@
1
1
  {
2
- "version": "1.0.0",
2
+ "name": "dauth-md-node",
3
+ "version": "2.0.0",
3
4
  "license": "MIT",
5
+ "author": "David T. Pizarro Frick",
4
6
  "main": "dist/index.js",
7
+ "module": "dist/index.mjs",
5
8
  "typings": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
6
16
  "files": [
7
17
  "dist",
8
18
  "src"
9
19
  ],
10
20
  "engines": {
11
- "node": ">=10"
21
+ "node": ">=18"
12
22
  },
13
23
  "scripts": {
14
- "start": "tsdx watch",
15
- "build": "tsdx build",
16
- "test": "tsdx test",
17
- "lint": "tsdx lint",
24
+ "start": "tsup --watch",
25
+ "build": "tsup",
26
+ "test": "vitest run",
27
+ "typecheck": "tsc --noEmit",
18
28
  "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
19
- "prepare": "tsdx build",
29
+ "prepare": "tsup",
20
30
  "size": "size-limit",
21
31
  "analyze": "size-limit --why"
22
32
  },
23
- "husky": {
24
- "hooks": {
25
- "pre-commit": "tsdx lint"
26
- }
27
- },
28
33
  "prettier": {
29
34
  "printWidth": 80,
30
35
  "semi": true,
31
36
  "singleQuote": true,
32
37
  "trailingComma": "es5"
33
38
  },
34
- "name": "dauth-md-node",
35
- "author": "David T. Pizarro Frick",
36
- "module": "dist/dauth-md-node.esm.js",
39
+ "packageManager": "pnpm@10.30.3",
37
40
  "size-limit": [
38
41
  {
39
- "path": "dist/dauth-md-node.cjs.production.min.js",
42
+ "path": "dist/index.js",
40
43
  "limit": "10 KB"
41
44
  },
42
45
  {
43
- "path": "dist/dauth-md-node.esm.js",
46
+ "path": "dist/index.mjs",
44
47
  "limit": "10 KB"
45
48
  }
46
49
  ],
50
+ "peerDependencies": {
51
+ "express": "^4.18.0 || ^5.0.0"
52
+ },
53
+ "dependencies": {
54
+ "jsonwebtoken": "^9.0.2"
55
+ },
47
56
  "devDependencies": {
48
- "@size-limit/preset-small-lib": "^11.0.2",
57
+ "@size-limit/file": "^11.0.2",
49
58
  "@types/express": "^4.17.21",
50
59
  "@types/jsonwebtoken": "^9.0.5",
51
- "@types/node-fetch": "^2.6.11",
60
+ "@types/node": "~22.9.4",
52
61
  "husky": "^9.0.11",
53
62
  "size-limit": "^11.0.2",
54
- "tsdx": "^0.14.1",
55
- "tslib": "^2.6.2",
56
- "typescript": "^3.9.10"
57
- },
58
- "dependencies": {
59
- "express": "^4.18.2",
60
- "jsonwebtoken": "^9.0.2",
61
- "node-fetch": "^2.6.1"
63
+ "tsup": "~8.5.0",
64
+ "typescript": "~5.9.3",
65
+ "vitest": "~3.1.0"
62
66
  }
63
67
  }