@technomoron/api-server-base 1.1.0 → 1.1.1

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.txt CHANGED
@@ -27,18 +27,32 @@ All runtime dependencies and `@types/*` packages are bundled with the distributi
27
27
 
28
28
  Quick Start
29
29
  -----------
30
- import { ApiServer, ApiModule, ApiError } from '@technomoron/api-server-base';
30
+ import { ApiServer, ApiModule, ApiError, BaseAuthStorage } from '@technomoron/api-server-base';
31
+
32
+ type DemoUser = { id: string; email: string; password: string };
33
+
34
+ class DemoStorage extends BaseAuthStorage<DemoUser, Omit<DemoUser, 'password'>> {
35
+ private readonly users = new Map<string, DemoUser>([
36
+ ['1', { id: '1', email: 'demo@example.com', password: 'secret' }]
37
+ ]);
31
38
 
32
- class AppServer extends ApiServer {
33
39
  async getUser(uid: unknown) {
34
- return { id: uid, email: 'demo@example.com' };
40
+ return this.users.get(String(uid)) ?? null;
35
41
  }
36
42
 
37
- filterUser(user: any) {
38
- return { id: user.id, email: user.email };
43
+ getUserPasswordHash(user: DemoUser) {
44
+ return user.password;
45
+ }
46
+
47
+ filterUser(user: DemoUser) {
48
+ const { password: _password, ...safe } = user;
49
+ void _password;
50
+ return safe;
39
51
  }
40
52
  }
41
53
 
54
+ class AppServer extends ApiServer {}
55
+
42
56
  class UserModule extends ApiModule<AppServer> {
43
57
  constructor() {
44
58
  super({ namespace: '/users' });
@@ -51,18 +65,19 @@ class UserModule extends ApiModule<AppServer> {
51
65
  path: '/',
52
66
  auth: { type: 'yes', req: 'any' },
53
67
  handler: async ({ server, tokenData }) => {
54
- const user = await server.getUser(tokenData?.uid);
68
+ const storage = server.getAuthStorage();
69
+ const user = tokenData ? await storage.getUser(tokenData.uid) : null;
55
70
  if (!user) {
56
71
  throw new ApiError({ code: 404, message: 'User not found' });
57
72
  }
58
- return [200, server.filterUser(user)];
73
+ return [200, storage.filterUser(user)];
59
74
  },
60
75
  },
61
76
  ];
62
77
  }
63
78
  }
64
79
 
65
- const yourStorageAdapter = new YourStorageAdapter();
80
+ const yourStorageAdapter = new DemoStorage();
66
81
 
67
82
  const server = new AppServer({
68
83
  apiPort: 3101,
@@ -116,8 +131,8 @@ Use getClientIp(req) to obtain the most likely client address, skipping loopback
116
131
 
117
132
  Extending the Base Classes
118
133
  --------------------------
119
- Override getApiKey, getUser, authenticateUser, storeToken, getToken, updateToken, deleteToken, and verifyPassword to integrate with your persistence layer.
120
- Customize filterUser to trim sensitive data before sending it to the client.
134
+ Implement the AuthStorage contract (getUser, verifyPassword, storeToken, updateToken, etc.) to integrate with your persistence layer, then supply it via authStorage().
135
+ Use your storage adapter's filterUser helper to trim sensitive data before returning responses.
121
136
  Provide your own authorize method to enforce role based access control using the ApiAuthClass enum.
122
137
  Create feature modules by extending ApiModule. Use the optional checkConfig hook to validate prerequisites before routes mount.
123
138
 
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiModule = void 0;
4
+ class ApiModule {
5
+ constructor(opts = {}) {
6
+ this.mountpath = '';
7
+ this.namespace = opts.namespace ?? this.constructor.defaultNamespace ?? '';
8
+ }
9
+ checkConfig() {
10
+ return true;
11
+ }
12
+ defineRoutes() {
13
+ return [];
14
+ }
15
+ }
16
+ exports.ApiModule = ApiModule;
17
+ ApiModule.defaultNamespace = '';
@@ -0,0 +1,27 @@
1
+ import type { ApiRequest } from './api-server-base.js';
2
+ export type ApiHandler = (apiReq: ApiRequest) => Promise<[number] | [number, any] | [number, any, string]>;
3
+ export type ApiAuthType = 'none' | 'maybe' | 'yes';
4
+ export type ApiAuthClass = 'any' | 'admin';
5
+ export interface ApiKey {
6
+ uid: unknown;
7
+ }
8
+ export type ApiRoute = {
9
+ method: 'get' | 'post' | 'put' | 'delete';
10
+ path: string;
11
+ handler: ApiHandler;
12
+ auth: {
13
+ type: ApiAuthType;
14
+ req: ApiAuthClass;
15
+ };
16
+ };
17
+ export declare class ApiModule<T> {
18
+ server: T;
19
+ namespace: string;
20
+ mountpath: string;
21
+ static defaultNamespace: string;
22
+ constructor(opts?: {
23
+ namespace?: string;
24
+ });
25
+ checkConfig(): boolean;
26
+ defineRoutes(): ApiRoute[];
27
+ }
@@ -17,20 +17,8 @@ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
17
17
  const multer_1 = __importDefault(require("multer"));
18
18
  const auth_module_js_1 = require("./auth-module.cjs");
19
19
  const auth_storage_js_1 = require("./auth-storage.cjs");
20
- class ApiModule {
21
- constructor(opts = {}) {
22
- this.mountpath = '';
23
- this.namespace = opts.namespace ?? this.constructor.defaultNamespace ?? '';
24
- }
25
- checkConfig() {
26
- return true;
27
- }
28
- defineRoutes() {
29
- return [];
30
- }
31
- }
32
- exports.ApiModule = ApiModule;
33
- ApiModule.defaultNamespace = '';
20
+ var api_module_js_1 = require("./api-module.cjs");
21
+ Object.defineProperty(exports, "ApiModule", { enumerable: true, get: function () { return api_module_js_1.ApiModule; } });
34
22
  function guess_exception_text(error, defMsg = 'Unknown Error') {
35
23
  const msg = [];
36
24
  if (typeof error === 'string' && error.trim() !== '') {
@@ -277,31 +265,16 @@ class ApiServer {
277
265
  void token;
278
266
  return null;
279
267
  }
280
- async getUser(uid) {
281
- return this.storageAdapter.getUser(uid);
282
- }
283
- getUserPasswordHash(user) {
284
- return this.storageAdapter.getUserPasswordHash(user);
285
- }
286
- getUserId(user) {
287
- return this.storageAdapter.getUserId(user);
288
- }
289
268
  async authenticateUser(params) {
290
269
  if (!params?.login || !params?.password) {
291
270
  return false;
292
271
  }
293
- const user = await this.getUser(params.login);
272
+ const user = await this.storageAdapter.getUser(params.login);
294
273
  if (!user) {
295
274
  return false;
296
275
  }
297
276
  const hash = this.storageAdapter.getUserPasswordHash(user);
298
- return this.verifyPassword(params.password, hash);
299
- }
300
- async storeToken(data) {
301
- await this.storageAdapter.storeToken(data);
302
- }
303
- async getToken(query) {
304
- return this.storageAdapter.getToken(query);
277
+ return this.storageAdapter.verifyPassword(params.password, hash);
305
278
  }
306
279
  async updateToken(updates) {
307
280
  if (typeof this.storageAdapter.updateToken !== 'function') {
@@ -315,15 +288,6 @@ class ApiServer {
315
288
  scope: updates.scope
316
289
  });
317
290
  }
318
- async deleteToken(query) {
319
- return this.storageAdapter.deleteToken(query);
320
- }
321
- async verifyPassword(password, hash) {
322
- return this.storageAdapter.verifyPassword(password, hash);
323
- }
324
- filterUser(fullUser) {
325
- return this.storageAdapter.filterUser(fullUser);
326
- }
327
291
  guessExceptionText(error, defMsg = 'Unkown Error') {
328
292
  return guess_exception_text(error, defMsg);
329
293
  }
@@ -6,8 +6,10 @@
6
6
  */
7
7
  import { Application, Request, Response } from 'express';
8
8
  import jwt, { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
9
+ import { ApiModule } from './api-module.js';
10
+ import type { ApiAuthClass, ApiKey } from './api-module.js';
9
11
  import type { AuthProviderModule } from './auth-module.js';
10
- import type { AuthIdentifier, AuthStorage, AuthTokenData, AuthTokenQuery } from './auth-storage.js';
12
+ import type { AuthStorage } from './auth-storage.js';
11
13
  export type { Application, Request, Response, NextFunction, Router } from 'express';
12
14
  export type { Multer } from 'multer';
13
15
  export type { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
@@ -45,32 +47,8 @@ export interface ApiRequest {
45
47
  tokenData?: ApiTokenData | null;
46
48
  token?: string;
47
49
  }
48
- export type ApiHandler = (apiReq: ApiRequest) => Promise<[number] | [number, any] | [number, any, string]>;
49
- export type ApiAuthType = 'none' | 'maybe' | 'yes';
50
- export type ApiAuthClass = 'any' | 'admin';
51
- export interface ApiKey {
52
- uid: unknown;
53
- }
54
- export type ApiRoute = {
55
- method: 'get' | 'post' | 'put' | 'delete';
56
- path: string;
57
- handler: ApiHandler;
58
- auth: {
59
- type: ApiAuthType;
60
- req: ApiAuthClass;
61
- };
62
- };
63
- export declare class ApiModule<T> {
64
- server: T;
65
- namespace: string;
66
- mountpath: string;
67
- static defaultNamespace: string;
68
- constructor(opts?: {
69
- namespace?: string;
70
- });
71
- checkConfig(): boolean;
72
- defineRoutes(): ApiRoute[];
73
- }
50
+ export { ApiModule } from './api-module.js';
51
+ export type { ApiHandler, ApiAuthType, ApiAuthClass, ApiRoute, ApiKey } from './api-module.js';
74
52
  export interface ApiErrorParams {
75
53
  code?: number;
76
54
  message?: any;
@@ -114,26 +92,21 @@ export declare class ApiServer {
114
92
  * @deprecated Use {@link ApiServer.authStorage} instead.
115
93
  */
116
94
  useAuthStorage<UserRow, SafeUser>(storage: AuthStorage<UserRow, SafeUser>): this;
117
- authModule<UserRow, SafeUser>(module: AuthProviderModule<UserRow, SafeUser>): this;
95
+ authModule<UserRow>(module: AuthProviderModule<UserRow>): this;
118
96
  /**
119
97
  * @deprecated Use {@link ApiServer.authModule} instead.
120
98
  */
121
- useAuthModule<UserRow, SafeUser>(module: AuthProviderModule<UserRow, SafeUser>): this;
99
+ useAuthModule<UserRow>(module: AuthProviderModule<UserRow>): this;
122
100
  getAuthStorage(): AuthStorage<any, any>;
123
- getAuthModule(): AuthProviderModule<any, any>;
101
+ getAuthModule(): AuthProviderModule<any>;
124
102
  jwtSign(payload: any, secret: string, expiresInSeconds: number, options?: SignOptions): JwtSignResult;
125
103
  jwtVerify<T>(token: string, secret: string, options?: VerifyOptions): JwtVerifyResult<T>;
126
104
  jwtDecode<T>(token: string, options?: jwt.DecodeOptions): JwtDecodeResult<T>;
127
105
  getApiKey<T = ApiKey>(token: string): Promise<T | null>;
128
- getUser(uid: AuthIdentifier): Promise<unknown>;
129
- getUserPasswordHash(user: unknown): string;
130
- getUserId(user: unknown): AuthIdentifier;
131
106
  authenticateUser(params: {
132
107
  login: string;
133
108
  password: string;
134
109
  }): Promise<boolean>;
135
- storeToken(data: AuthTokenData): Promise<void>;
136
- getToken(query: AuthTokenQuery): Promise<AuthTokenData | null>;
137
110
  updateToken(updates: {
138
111
  accessToken: string;
139
112
  refreshToken: string;
@@ -141,9 +114,6 @@ export declare class ApiServer {
141
114
  clientId?: string;
142
115
  scope?: string[];
143
116
  }): Promise<boolean>;
144
- deleteToken(query: AuthTokenQuery): Promise<number>;
145
- verifyPassword(password: string, hash: string): Promise<boolean>;
146
- filterUser<T = any, U = any>(fullUser: T): U;
147
117
  guessExceptionText(error: any, defMsg?: string): string;
148
118
  protected authorize(apiReq: ApiRequest, requiredClass: ApiAuthClass): Promise<void>;
149
119
  private middlewares;
@@ -1,26 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nullAuthModule = exports.BaseAuthModule = void 0;
4
+ const api_module_js_1 = require("./api-module.cjs");
4
5
  // Handy base that you can extend when wiring a real auth module. Subclasses
5
- // must provide their namespace. Methods throw by default so unimplemented
6
- // hooks fail loudly.
7
- class BaseAuthModule {
8
- constructor() {
6
+ // must supply a namespace via the constructor and implement token issuance.
7
+ class BaseAuthModule extends api_module_js_1.ApiModule {
8
+ constructor(opts) {
9
+ super(opts);
9
10
  this.moduleType = 'auth';
10
11
  }
11
- // Override to mint tokens for the provided user and request context
12
- async issueTokens(apiReq, user, metadata) {
13
- void apiReq;
14
- void user;
15
- void metadata;
16
- throw new Error('Auth module not configured');
17
- }
18
12
  }
19
13
  exports.BaseAuthModule = BaseAuthModule;
20
14
  class NullAuthModule extends BaseAuthModule {
21
15
  constructor() {
22
- super(...arguments);
23
- this.namespace = '__null__';
16
+ super({ namespace: '__null__' });
17
+ }
18
+ async issueTokens(apiReq, user, metadata) {
19
+ void apiReq;
20
+ void user;
21
+ void metadata;
22
+ throw new Error('Auth module not configured. Inject a real auth module before issuing tokens.');
24
23
  }
25
24
  }
26
25
  exports.nullAuthModule = new NullAuthModule();
@@ -1,17 +1,20 @@
1
+ import { ApiModule } from './api-module.js';
1
2
  import type { ApiRequest } from './api-server-base.js';
2
3
  import type { AuthTokenMetadata, AuthTokenPair } from './auth-storage.js';
3
- export interface AuthProviderModule<UserRow, SafeUser> {
4
+ export interface AuthProviderModule<UserRow = unknown> {
4
5
  readonly moduleType: 'auth';
5
6
  readonly namespace: string;
6
7
  issueTokens(apiReq: ApiRequest, user: UserRow, metadata?: AuthTokenMetadata & {
7
8
  expires?: Date;
8
9
  }): Promise<AuthTokenPair>;
9
10
  }
10
- export declare abstract class BaseAuthModule implements AuthProviderModule<unknown, unknown> {
11
+ export declare abstract class BaseAuthModule<UserRow = unknown> extends ApiModule<any> implements AuthProviderModule<UserRow> {
11
12
  readonly moduleType: "auth";
12
- abstract readonly namespace: string;
13
- issueTokens(apiReq: ApiRequest, user: unknown, metadata?: AuthTokenMetadata & {
13
+ protected constructor(opts: {
14
+ namespace: string;
15
+ });
16
+ abstract issueTokens(apiReq: ApiRequest, user: UserRow, metadata?: AuthTokenMetadata & {
14
17
  expires?: Date;
15
18
  }): Promise<AuthTokenPair>;
16
19
  }
17
- export declare const nullAuthModule: AuthProviderModule<unknown, unknown>;
20
+ export declare const nullAuthModule: AuthProviderModule<unknown>;
@@ -3,12 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.BaseAuthModule = exports.nullAuthModule = exports.BaseAuthStorage = exports.nullAuthStorage = exports.ApiError = exports.ApiModule = exports.ApiServer = void 0;
6
+ exports.BaseAuthModule = exports.nullAuthModule = exports.BaseAuthStorage = exports.nullAuthStorage = exports.ApiModule = exports.ApiError = exports.ApiServer = void 0;
7
7
  var api_server_base_js_1 = require("./api-server-base.cjs");
8
8
  Object.defineProperty(exports, "ApiServer", { enumerable: true, get: function () { return __importDefault(api_server_base_js_1).default; } });
9
9
  var api_server_base_js_2 = require("./api-server-base.cjs");
10
- Object.defineProperty(exports, "ApiModule", { enumerable: true, get: function () { return api_server_base_js_2.ApiModule; } });
11
10
  Object.defineProperty(exports, "ApiError", { enumerable: true, get: function () { return api_server_base_js_2.ApiError; } });
11
+ var api_module_js_1 = require("./api-module.cjs");
12
+ Object.defineProperty(exports, "ApiModule", { enumerable: true, get: function () { return api_module_js_1.ApiModule; } });
12
13
  var auth_storage_js_1 = require("./auth-storage.cjs");
13
14
  Object.defineProperty(exports, "nullAuthStorage", { enumerable: true, get: function () { return auth_storage_js_1.nullAuthStorage; } });
14
15
  Object.defineProperty(exports, "BaseAuthStorage", { enumerable: true, get: function () { return auth_storage_js_1.BaseAuthStorage; } });
@@ -1,5 +1,6 @@
1
1
  export { default as ApiServer } from './api-server-base.js';
2
- export { ApiModule, ApiError } from './api-server-base.js';
2
+ export { ApiError } from './api-server-base.js';
3
+ export { ApiModule } from './api-module.js';
3
4
  export type { ApiErrorParams, ApiHandler, ApiKey, ApiServerConf, ApiRequest, ApiRoute, ApiAuthType, ApiAuthClass, ApiTokenData, RequestWithStuff } from './api-server-base.js';
4
5
  export type { AuthIdentifier, AuthTokenMetadata, AuthTokenData, AuthTokenQuery, AuthTokenPair, AuthTokenPayload, PasskeyChallengeParams, PasskeyChallenge, PasskeyVerificationParams, PasskeyVerificationResult, OAuthClient, AuthCodeData, AuthCodeRequest, AuthStorage } from './auth-storage.js';
5
6
  export type { AuthProviderModule } from './auth-module.js';
@@ -0,0 +1,27 @@
1
+ import type { ApiRequest } from './api-server-base.js';
2
+ export type ApiHandler = (apiReq: ApiRequest) => Promise<[number] | [number, any] | [number, any, string]>;
3
+ export type ApiAuthType = 'none' | 'maybe' | 'yes';
4
+ export type ApiAuthClass = 'any' | 'admin';
5
+ export interface ApiKey {
6
+ uid: unknown;
7
+ }
8
+ export type ApiRoute = {
9
+ method: 'get' | 'post' | 'put' | 'delete';
10
+ path: string;
11
+ handler: ApiHandler;
12
+ auth: {
13
+ type: ApiAuthType;
14
+ req: ApiAuthClass;
15
+ };
16
+ };
17
+ export declare class ApiModule<T> {
18
+ server: T;
19
+ namespace: string;
20
+ mountpath: string;
21
+ static defaultNamespace: string;
22
+ constructor(opts?: {
23
+ namespace?: string;
24
+ });
25
+ checkConfig(): boolean;
26
+ defineRoutes(): ApiRoute[];
27
+ }
@@ -0,0 +1,13 @@
1
+ export class ApiModule {
2
+ constructor(opts = {}) {
3
+ this.mountpath = '';
4
+ this.namespace = opts.namespace ?? this.constructor.defaultNamespace ?? '';
5
+ }
6
+ checkConfig() {
7
+ return true;
8
+ }
9
+ defineRoutes() {
10
+ return [];
11
+ }
12
+ }
13
+ ApiModule.defaultNamespace = '';
@@ -6,8 +6,10 @@
6
6
  */
7
7
  import { Application, Request, Response } from 'express';
8
8
  import jwt, { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
9
+ import { ApiModule } from './api-module.js';
10
+ import type { ApiAuthClass, ApiKey } from './api-module.js';
9
11
  import type { AuthProviderModule } from './auth-module.js';
10
- import type { AuthIdentifier, AuthStorage, AuthTokenData, AuthTokenQuery } from './auth-storage.js';
12
+ import type { AuthStorage } from './auth-storage.js';
11
13
  export type { Application, Request, Response, NextFunction, Router } from 'express';
12
14
  export type { Multer } from 'multer';
13
15
  export type { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
@@ -45,32 +47,8 @@ export interface ApiRequest {
45
47
  tokenData?: ApiTokenData | null;
46
48
  token?: string;
47
49
  }
48
- export type ApiHandler = (apiReq: ApiRequest) => Promise<[number] | [number, any] | [number, any, string]>;
49
- export type ApiAuthType = 'none' | 'maybe' | 'yes';
50
- export type ApiAuthClass = 'any' | 'admin';
51
- export interface ApiKey {
52
- uid: unknown;
53
- }
54
- export type ApiRoute = {
55
- method: 'get' | 'post' | 'put' | 'delete';
56
- path: string;
57
- handler: ApiHandler;
58
- auth: {
59
- type: ApiAuthType;
60
- req: ApiAuthClass;
61
- };
62
- };
63
- export declare class ApiModule<T> {
64
- server: T;
65
- namespace: string;
66
- mountpath: string;
67
- static defaultNamespace: string;
68
- constructor(opts?: {
69
- namespace?: string;
70
- });
71
- checkConfig(): boolean;
72
- defineRoutes(): ApiRoute[];
73
- }
50
+ export { ApiModule } from './api-module.js';
51
+ export type { ApiHandler, ApiAuthType, ApiAuthClass, ApiRoute, ApiKey } from './api-module.js';
74
52
  export interface ApiErrorParams {
75
53
  code?: number;
76
54
  message?: any;
@@ -114,26 +92,21 @@ export declare class ApiServer {
114
92
  * @deprecated Use {@link ApiServer.authStorage} instead.
115
93
  */
116
94
  useAuthStorage<UserRow, SafeUser>(storage: AuthStorage<UserRow, SafeUser>): this;
117
- authModule<UserRow, SafeUser>(module: AuthProviderModule<UserRow, SafeUser>): this;
95
+ authModule<UserRow>(module: AuthProviderModule<UserRow>): this;
118
96
  /**
119
97
  * @deprecated Use {@link ApiServer.authModule} instead.
120
98
  */
121
- useAuthModule<UserRow, SafeUser>(module: AuthProviderModule<UserRow, SafeUser>): this;
99
+ useAuthModule<UserRow>(module: AuthProviderModule<UserRow>): this;
122
100
  getAuthStorage(): AuthStorage<any, any>;
123
- getAuthModule(): AuthProviderModule<any, any>;
101
+ getAuthModule(): AuthProviderModule<any>;
124
102
  jwtSign(payload: any, secret: string, expiresInSeconds: number, options?: SignOptions): JwtSignResult;
125
103
  jwtVerify<T>(token: string, secret: string, options?: VerifyOptions): JwtVerifyResult<T>;
126
104
  jwtDecode<T>(token: string, options?: jwt.DecodeOptions): JwtDecodeResult<T>;
127
105
  getApiKey<T = ApiKey>(token: string): Promise<T | null>;
128
- getUser(uid: AuthIdentifier): Promise<unknown>;
129
- getUserPasswordHash(user: unknown): string;
130
- getUserId(user: unknown): AuthIdentifier;
131
106
  authenticateUser(params: {
132
107
  login: string;
133
108
  password: string;
134
109
  }): Promise<boolean>;
135
- storeToken(data: AuthTokenData): Promise<void>;
136
- getToken(query: AuthTokenQuery): Promise<AuthTokenData | null>;
137
110
  updateToken(updates: {
138
111
  accessToken: string;
139
112
  refreshToken: string;
@@ -141,9 +114,6 @@ export declare class ApiServer {
141
114
  clientId?: string;
142
115
  scope?: string[];
143
116
  }): Promise<boolean>;
144
- deleteToken(query: AuthTokenQuery): Promise<number>;
145
- verifyPassword(password: string, hash: string): Promise<boolean>;
146
- filterUser<T = any, U = any>(fullUser: T): U;
147
117
  guessExceptionText(error: any, defMsg?: string): string;
148
118
  protected authorize(apiReq: ApiRequest, requiredClass: ApiAuthClass): Promise<void>;
149
119
  private middlewares;
@@ -11,19 +11,7 @@ import jwt from 'jsonwebtoken';
11
11
  import multer from 'multer';
12
12
  import { nullAuthModule } from './auth-module.js';
13
13
  import { nullAuthStorage } from './auth-storage.js';
14
- export class ApiModule {
15
- constructor(opts = {}) {
16
- this.mountpath = '';
17
- this.namespace = opts.namespace ?? this.constructor.defaultNamespace ?? '';
18
- }
19
- checkConfig() {
20
- return true;
21
- }
22
- defineRoutes() {
23
- return [];
24
- }
25
- }
26
- ApiModule.defaultNamespace = '';
14
+ export { ApiModule } from './api-module.js';
27
15
  function guess_exception_text(error, defMsg = 'Unknown Error') {
28
16
  const msg = [];
29
17
  if (typeof error === 'string' && error.trim() !== '') {
@@ -269,31 +257,16 @@ export class ApiServer {
269
257
  void token;
270
258
  return null;
271
259
  }
272
- async getUser(uid) {
273
- return this.storageAdapter.getUser(uid);
274
- }
275
- getUserPasswordHash(user) {
276
- return this.storageAdapter.getUserPasswordHash(user);
277
- }
278
- getUserId(user) {
279
- return this.storageAdapter.getUserId(user);
280
- }
281
260
  async authenticateUser(params) {
282
261
  if (!params?.login || !params?.password) {
283
262
  return false;
284
263
  }
285
- const user = await this.getUser(params.login);
264
+ const user = await this.storageAdapter.getUser(params.login);
286
265
  if (!user) {
287
266
  return false;
288
267
  }
289
268
  const hash = this.storageAdapter.getUserPasswordHash(user);
290
- return this.verifyPassword(params.password, hash);
291
- }
292
- async storeToken(data) {
293
- await this.storageAdapter.storeToken(data);
294
- }
295
- async getToken(query) {
296
- return this.storageAdapter.getToken(query);
269
+ return this.storageAdapter.verifyPassword(params.password, hash);
297
270
  }
298
271
  async updateToken(updates) {
299
272
  if (typeof this.storageAdapter.updateToken !== 'function') {
@@ -307,15 +280,6 @@ export class ApiServer {
307
280
  scope: updates.scope
308
281
  });
309
282
  }
310
- async deleteToken(query) {
311
- return this.storageAdapter.deleteToken(query);
312
- }
313
- async verifyPassword(password, hash) {
314
- return this.storageAdapter.verifyPassword(password, hash);
315
- }
316
- filterUser(fullUser) {
317
- return this.storageAdapter.filterUser(fullUser);
318
- }
319
283
  guessExceptionText(error, defMsg = 'Unkown Error') {
320
284
  return guess_exception_text(error, defMsg);
321
285
  }
@@ -1,17 +1,20 @@
1
+ import { ApiModule } from './api-module.js';
1
2
  import type { ApiRequest } from './api-server-base.js';
2
3
  import type { AuthTokenMetadata, AuthTokenPair } from './auth-storage.js';
3
- export interface AuthProviderModule<UserRow, SafeUser> {
4
+ export interface AuthProviderModule<UserRow = unknown> {
4
5
  readonly moduleType: 'auth';
5
6
  readonly namespace: string;
6
7
  issueTokens(apiReq: ApiRequest, user: UserRow, metadata?: AuthTokenMetadata & {
7
8
  expires?: Date;
8
9
  }): Promise<AuthTokenPair>;
9
10
  }
10
- export declare abstract class BaseAuthModule implements AuthProviderModule<unknown, unknown> {
11
+ export declare abstract class BaseAuthModule<UserRow = unknown> extends ApiModule<any> implements AuthProviderModule<UserRow> {
11
12
  readonly moduleType: "auth";
12
- abstract readonly namespace: string;
13
- issueTokens(apiReq: ApiRequest, user: unknown, metadata?: AuthTokenMetadata & {
13
+ protected constructor(opts: {
14
+ namespace: string;
15
+ });
16
+ abstract issueTokens(apiReq: ApiRequest, user: UserRow, metadata?: AuthTokenMetadata & {
14
17
  expires?: Date;
15
18
  }): Promise<AuthTokenPair>;
16
19
  }
17
- export declare const nullAuthModule: AuthProviderModule<unknown, unknown>;
20
+ export declare const nullAuthModule: AuthProviderModule<unknown>;
@@ -1,22 +1,21 @@
1
+ import { ApiModule } from './api-module.js';
1
2
  // Handy base that you can extend when wiring a real auth module. Subclasses
2
- // must provide their namespace. Methods throw by default so unimplemented
3
- // hooks fail loudly.
4
- export class BaseAuthModule {
5
- constructor() {
3
+ // must supply a namespace via the constructor and implement token issuance.
4
+ export class BaseAuthModule extends ApiModule {
5
+ constructor(opts) {
6
+ super(opts);
6
7
  this.moduleType = 'auth';
7
8
  }
8
- // Override to mint tokens for the provided user and request context
9
+ }
10
+ class NullAuthModule extends BaseAuthModule {
11
+ constructor() {
12
+ super({ namespace: '__null__' });
13
+ }
9
14
  async issueTokens(apiReq, user, metadata) {
10
15
  void apiReq;
11
16
  void user;
12
17
  void metadata;
13
- throw new Error('Auth module not configured');
14
- }
15
- }
16
- class NullAuthModule extends BaseAuthModule {
17
- constructor() {
18
- super(...arguments);
19
- this.namespace = '__null__';
18
+ throw new Error('Auth module not configured. Inject a real auth module before issuing tokens.');
20
19
  }
21
20
  }
22
21
  export const nullAuthModule = new NullAuthModule();
@@ -1,5 +1,6 @@
1
1
  export { default as ApiServer } from './api-server-base.js';
2
- export { ApiModule, ApiError } from './api-server-base.js';
2
+ export { ApiError } from './api-server-base.js';
3
+ export { ApiModule } from './api-module.js';
3
4
  export type { ApiErrorParams, ApiHandler, ApiKey, ApiServerConf, ApiRequest, ApiRoute, ApiAuthType, ApiAuthClass, ApiTokenData, RequestWithStuff } from './api-server-base.js';
4
5
  export type { AuthIdentifier, AuthTokenMetadata, AuthTokenData, AuthTokenQuery, AuthTokenPair, AuthTokenPayload, PasskeyChallengeParams, PasskeyChallenge, PasskeyVerificationParams, PasskeyVerificationResult, OAuthClient, AuthCodeData, AuthCodeRequest, AuthStorage } from './auth-storage.js';
5
6
  export type { AuthProviderModule } from './auth-module.js';
package/dist/esm/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { default as ApiServer } from './api-server-base.js';
2
- export { ApiModule, ApiError } from './api-server-base.js';
2
+ export { ApiError } from './api-server-base.js';
3
+ export { ApiModule } from './api-module.js';
3
4
  export { nullAuthStorage, BaseAuthStorage } from './auth-storage.js';
4
5
  export { nullAuthModule, BaseAuthModule } from './auth-module.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/api-server-base",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Api Server Skeleton / Base Class",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.cjs",