@technomoron/api-server-base 1.1.5 → 1.1.7

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.
@@ -325,7 +325,7 @@ function fillConfig(config) {
325
325
  accessCookie: config.accessCookie ?? 'dat',
326
326
  refreshCookie: config.refreshCookie ?? 'drt',
327
327
  accessExpiry: config.accessExpiry ?? 60 * 15,
328
- refreshExpiry: config.refreshExpiry ?? 30 * 24 * 60 * 60 * 1000,
328
+ refreshExpiry: config.refreshExpiry ?? 30 * 24 * 60 * 60,
329
329
  authApi: config.authApi ?? false,
330
330
  devMode: config.devMode ?? false,
331
331
  hydrateGetBody: config.hydrateGetBody ?? true,
@@ -335,7 +335,9 @@ function fillConfig(config) {
335
335
  class ApiServer {
336
336
  constructor(config = {}) {
337
337
  this.currReq = null;
338
+ this.apiNotFoundHandler = null;
338
339
  this.config = fillConfig(config);
340
+ this.apiBasePath = this.normalizeApiBasePath(this.config.apiBasePath);
339
341
  this.storageAdapter = auth_storage_js_1.nullAuthStorage;
340
342
  this.moduleAdapter = auth_module_js_1.nullAuthModule;
341
343
  this.app = (0, express_1.default)();
@@ -345,6 +347,7 @@ class ApiServer {
345
347
  }
346
348
  this.middlewares();
347
349
  // addSwaggerUi(this.app);
350
+ this.installApiNotFoundHandler();
348
351
  }
349
352
  authStorage(storage) {
350
353
  this.storageAdapter = storage;
@@ -493,6 +496,56 @@ class ApiServer {
493
496
  };
494
497
  this.app.use((0, cors_1.default)(corsOptions));
495
498
  }
499
+ normalizeApiBasePath(path) {
500
+ if (!path || typeof path !== 'string') {
501
+ return '/api';
502
+ }
503
+ const trimmed = path.trim();
504
+ if (!trimmed) {
505
+ return '/api';
506
+ }
507
+ const withLeadingSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
508
+ if (withLeadingSlash.length === 1) {
509
+ return withLeadingSlash;
510
+ }
511
+ return withLeadingSlash.replace(/\/+$/, '') || '/api';
512
+ }
513
+ installApiNotFoundHandler() {
514
+ if (this.apiNotFoundHandler) {
515
+ return;
516
+ }
517
+ this.apiNotFoundHandler = (req, res) => {
518
+ const payload = {
519
+ code: 404,
520
+ message: this.describeMissingEndpoint(req),
521
+ data: null,
522
+ errors: {}
523
+ };
524
+ res.status(404).json(payload);
525
+ };
526
+ this.app.use(this.apiBasePath, this.apiNotFoundHandler);
527
+ }
528
+ ensureApiNotFoundOrdering() {
529
+ this.installApiNotFoundHandler();
530
+ if (!this.apiNotFoundHandler) {
531
+ return;
532
+ }
533
+ const stack = this.app?._router?.stack;
534
+ if (!stack) {
535
+ return;
536
+ }
537
+ const index = stack.findIndex((layer) => layer.handle === this.apiNotFoundHandler);
538
+ if (index === -1 || index === stack.length - 1) {
539
+ return;
540
+ }
541
+ const [layer] = stack.splice(index, 1);
542
+ stack.push(layer);
543
+ }
544
+ describeMissingEndpoint(req) {
545
+ const method = typeof req.method === 'string' ? req.method.toUpperCase() : 'GET';
546
+ const target = req.originalUrl || req.url || this.apiBasePath;
547
+ return `No such endpoint: ${method} ${target}`;
548
+ }
496
549
  start() {
497
550
  this.app
498
551
  .listen({
@@ -628,18 +681,18 @@ class ApiServer {
628
681
  handle_request(handler, auth) {
629
682
  return async (req, res, next) => {
630
683
  void next;
684
+ const apiReq = {
685
+ server: this,
686
+ req,
687
+ res,
688
+ token: '',
689
+ tokenData: null,
690
+ getClientInfo: () => ensureClientInfo(apiReq),
691
+ getClientIp: () => ensureClientInfo(apiReq).ip,
692
+ getClientIpChain: () => ensureClientInfo(apiReq).ipchain
693
+ };
694
+ this.currReq = apiReq;
631
695
  try {
632
- const apiReq = {
633
- server: this,
634
- req,
635
- res,
636
- token: '',
637
- tokenData: null,
638
- getClientInfo: () => ensureClientInfo(apiReq),
639
- getClientIp: () => ensureClientInfo(apiReq).ip,
640
- getClientIpChain: () => ensureClientInfo(apiReq).ipchain
641
- };
642
- this.currReq = apiReq;
643
696
  if (this.config.hydrateGetBody) {
644
697
  hydrateGetBody(apiReq.req);
645
698
  }
@@ -660,7 +713,11 @@ class ApiServer {
660
713
  throw new ApiError({ code: 500, message: 'Handler result must start with a numeric status code' });
661
714
  }
662
715
  const message = typeof rawMessage === 'string' ? rawMessage : 'Success';
663
- res.status(code).json({ code, message, data });
716
+ const responsePayload = { code, message, data };
717
+ if (this.config.debug) {
718
+ this.dumpResponse(apiReq, responsePayload, code);
719
+ }
720
+ res.status(code).json(responsePayload);
664
721
  }
665
722
  catch (error) {
666
723
  if (error instanceof ApiError || isApiErrorLike(error)) {
@@ -668,20 +725,28 @@ class ApiServer {
668
725
  const normalizedErrors = apiError.errors && typeof apiError.errors === 'object' && !Array.isArray(apiError.errors)
669
726
  ? apiError.errors
670
727
  : {};
671
- res.status(apiError.code).json({
728
+ const errorPayload = {
672
729
  code: apiError.code,
673
730
  message: apiError.message,
674
731
  data: apiError.data ?? null,
675
732
  errors: normalizedErrors
676
- });
733
+ };
734
+ if (this.config.debug) {
735
+ this.dumpResponse(apiReq, errorPayload, apiError.code);
736
+ }
737
+ res.status(apiError.code).json(errorPayload);
677
738
  }
678
739
  else {
679
- res.status(500).json({
740
+ const errorPayload = {
680
741
  code: 500,
681
742
  message: this.guessExceptionText(error),
682
743
  data: null,
683
744
  errors: {}
684
- });
745
+ };
746
+ if (this.config.debug) {
747
+ this.dumpResponse(apiReq, errorPayload, 500);
748
+ }
749
+ res.status(500).json(errorPayload);
685
750
  }
686
751
  }
687
752
  };
@@ -693,7 +758,7 @@ class ApiServer {
693
758
  this.authModule(module);
694
759
  }
695
760
  module.checkConfig();
696
- const base = this.config.apiBasePath ?? '/api';
761
+ const base = this.apiBasePath;
697
762
  const ns = module.namespace;
698
763
  const mountPath = `${base}${ns}`;
699
764
  module.mountpath = mountPath;
@@ -705,6 +770,7 @@ class ApiServer {
705
770
  }
706
771
  });
707
772
  this.app.use(mountPath, router);
773
+ this.ensureApiNotFoundOrdering();
708
774
  return this;
709
775
  }
710
776
  dumpRequest(apiReq) {
@@ -719,6 +785,59 @@ class ApiServer {
719
785
  console.log('Headers:', req.headers);
720
786
  console.log('------------------------');
721
787
  }
788
+ formatDebugValue(value, maxLength = 50, seen = new WeakSet()) {
789
+ if (value === null || value === undefined) {
790
+ return value;
791
+ }
792
+ if (typeof value === 'string') {
793
+ return value.length <= maxLength
794
+ ? value
795
+ : `${value.slice(0, maxLength)}… [truncated ${value.length - maxLength} chars]`;
796
+ }
797
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
798
+ return value;
799
+ }
800
+ if (typeof value === 'symbol') {
801
+ return value.toString();
802
+ }
803
+ if (value instanceof Date) {
804
+ return value.toISOString();
805
+ }
806
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
807
+ return `<Buffer length=${value.length}>`;
808
+ }
809
+ if (typeof value === 'function') {
810
+ return `[Function ${value.name || 'anonymous'}]`;
811
+ }
812
+ if (typeof value === 'object') {
813
+ const obj = value;
814
+ if (seen.has(obj)) {
815
+ return '[Circular]';
816
+ }
817
+ seen.add(obj);
818
+ if (Array.isArray(value)) {
819
+ const arr = value.map((item) => this.formatDebugValue(item, maxLength, seen));
820
+ seen.delete(obj);
821
+ return arr;
822
+ }
823
+ const recordValue = value;
824
+ const entries = Object.entries(recordValue).reduce((acc, [key, val]) => {
825
+ acc[key] = this.formatDebugValue(val, maxLength, seen);
826
+ return acc;
827
+ }, {});
828
+ seen.delete(obj);
829
+ return entries;
830
+ }
831
+ return value;
832
+ }
833
+ dumpResponse(apiReq, payload, status) {
834
+ const url = apiReq.req.originalUrl || apiReq.req.url;
835
+ console.log('--- Outgoing Response! ---');
836
+ console.log('URL:', url);
837
+ console.log('Status:', status);
838
+ console.log('Payload:', this.formatDebugValue(payload));
839
+ console.log('--------------------------');
840
+ }
722
841
  }
723
842
  exports.ApiServer = ApiServer;
724
843
  exports.default = ApiServer;
@@ -9,7 +9,7 @@ import jwt, { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
9
9
  import { ApiModule } from './api-module.js';
10
10
  import type { ApiAuthClass, ApiKey } from './api-module.js';
11
11
  import type { AuthProviderModule } from './auth-module.js';
12
- import type { AuthStorage, AuthTokenData } from './auth-storage.js';
12
+ import type { AuthStorage, AuthTokenData, AuthTokenMetadata } from './auth-storage.js';
13
13
  export type { Application, Request, Response, NextFunction, Router } from 'express';
14
14
  export type { Multer } from 'multer';
15
15
  export type { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
@@ -35,7 +35,7 @@ interface JwtDecodeResult<T> {
35
35
  data?: T;
36
36
  error?: string;
37
37
  }
38
- export interface ApiTokenData extends JwtPayload {
38
+ export interface ApiTokenData extends JwtPayload, AuthTokenMetadata {
39
39
  uid: unknown;
40
40
  iat?: number;
41
41
  exp?: number;
@@ -101,8 +101,10 @@ export declare class ApiServer {
101
101
  app: Application;
102
102
  currReq: ApiRequest | null;
103
103
  readonly config: ApiServerConf;
104
+ private readonly apiBasePath;
104
105
  private storageAdapter;
105
106
  private moduleAdapter;
107
+ private apiNotFoundHandler;
106
108
  constructor(config?: Partial<ApiServerConf>);
107
109
  authStorage<UserRow, SafeUser>(storage: AuthStorage<UserRow, SafeUser>): this;
108
110
  /**
@@ -134,6 +136,10 @@ export declare class ApiServer {
134
136
  guessExceptionText(error: any, defMsg?: string): string;
135
137
  protected authorize(apiReq: ApiRequest, requiredClass: ApiAuthClass): Promise<void>;
136
138
  private middlewares;
139
+ private normalizeApiBasePath;
140
+ private installApiNotFoundHandler;
141
+ private ensureApiNotFoundOrdering;
142
+ private describeMissingEndpoint;
137
143
  start(): this;
138
144
  private verifyJWT;
139
145
  private authenticate;
@@ -144,5 +150,7 @@ export declare class ApiServer {
144
150
  private handle_request;
145
151
  api<T extends ApiModule<any>>(module: T): this;
146
152
  dumpRequest(apiReq: ApiRequest): void;
153
+ private formatDebugValue;
154
+ dumpResponse(apiReq: ApiRequest, payload: unknown, status: number): void;
147
155
  }
148
156
  export default ApiServer;
@@ -9,6 +9,7 @@ export interface AuthTokenMetadata {
9
9
  ip?: string;
10
10
  os?: string;
11
11
  scope?: string | string[];
12
+ loginType?: string;
12
13
  revokeSessions?: 'device' | 'domain' | 'client' | 'user';
13
14
  }
14
15
  export interface AuthTokenData extends AuthTokenMetadata {
@@ -9,7 +9,7 @@ import jwt, { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
9
9
  import { ApiModule } from './api-module.js';
10
10
  import type { ApiAuthClass, ApiKey } from './api-module.js';
11
11
  import type { AuthProviderModule } from './auth-module.js';
12
- import type { AuthStorage, AuthTokenData } from './auth-storage.js';
12
+ import type { AuthStorage, AuthTokenData, AuthTokenMetadata } from './auth-storage.js';
13
13
  export type { Application, Request, Response, NextFunction, Router } from 'express';
14
14
  export type { Multer } from 'multer';
15
15
  export type { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
@@ -35,7 +35,7 @@ interface JwtDecodeResult<T> {
35
35
  data?: T;
36
36
  error?: string;
37
37
  }
38
- export interface ApiTokenData extends JwtPayload {
38
+ export interface ApiTokenData extends JwtPayload, AuthTokenMetadata {
39
39
  uid: unknown;
40
40
  iat?: number;
41
41
  exp?: number;
@@ -101,8 +101,10 @@ export declare class ApiServer {
101
101
  app: Application;
102
102
  currReq: ApiRequest | null;
103
103
  readonly config: ApiServerConf;
104
+ private readonly apiBasePath;
104
105
  private storageAdapter;
105
106
  private moduleAdapter;
107
+ private apiNotFoundHandler;
106
108
  constructor(config?: Partial<ApiServerConf>);
107
109
  authStorage<UserRow, SafeUser>(storage: AuthStorage<UserRow, SafeUser>): this;
108
110
  /**
@@ -134,6 +136,10 @@ export declare class ApiServer {
134
136
  guessExceptionText(error: any, defMsg?: string): string;
135
137
  protected authorize(apiReq: ApiRequest, requiredClass: ApiAuthClass): Promise<void>;
136
138
  private middlewares;
139
+ private normalizeApiBasePath;
140
+ private installApiNotFoundHandler;
141
+ private ensureApiNotFoundOrdering;
142
+ private describeMissingEndpoint;
137
143
  start(): this;
138
144
  private verifyJWT;
139
145
  private authenticate;
@@ -144,5 +150,7 @@ export declare class ApiServer {
144
150
  private handle_request;
145
151
  api<T extends ApiModule<any>>(module: T): this;
146
152
  dumpRequest(apiReq: ApiRequest): void;
153
+ private formatDebugValue;
154
+ dumpResponse(apiReq: ApiRequest, payload: unknown, status: number): void;
147
155
  }
148
156
  export default ApiServer;
@@ -317,7 +317,7 @@ function fillConfig(config) {
317
317
  accessCookie: config.accessCookie ?? 'dat',
318
318
  refreshCookie: config.refreshCookie ?? 'drt',
319
319
  accessExpiry: config.accessExpiry ?? 60 * 15,
320
- refreshExpiry: config.refreshExpiry ?? 30 * 24 * 60 * 60 * 1000,
320
+ refreshExpiry: config.refreshExpiry ?? 30 * 24 * 60 * 60,
321
321
  authApi: config.authApi ?? false,
322
322
  devMode: config.devMode ?? false,
323
323
  hydrateGetBody: config.hydrateGetBody ?? true,
@@ -327,7 +327,9 @@ function fillConfig(config) {
327
327
  export class ApiServer {
328
328
  constructor(config = {}) {
329
329
  this.currReq = null;
330
+ this.apiNotFoundHandler = null;
330
331
  this.config = fillConfig(config);
332
+ this.apiBasePath = this.normalizeApiBasePath(this.config.apiBasePath);
331
333
  this.storageAdapter = nullAuthStorage;
332
334
  this.moduleAdapter = nullAuthModule;
333
335
  this.app = express();
@@ -337,6 +339,7 @@ export class ApiServer {
337
339
  }
338
340
  this.middlewares();
339
341
  // addSwaggerUi(this.app);
342
+ this.installApiNotFoundHandler();
340
343
  }
341
344
  authStorage(storage) {
342
345
  this.storageAdapter = storage;
@@ -485,6 +488,56 @@ export class ApiServer {
485
488
  };
486
489
  this.app.use(cors(corsOptions));
487
490
  }
491
+ normalizeApiBasePath(path) {
492
+ if (!path || typeof path !== 'string') {
493
+ return '/api';
494
+ }
495
+ const trimmed = path.trim();
496
+ if (!trimmed) {
497
+ return '/api';
498
+ }
499
+ const withLeadingSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
500
+ if (withLeadingSlash.length === 1) {
501
+ return withLeadingSlash;
502
+ }
503
+ return withLeadingSlash.replace(/\/+$/, '') || '/api';
504
+ }
505
+ installApiNotFoundHandler() {
506
+ if (this.apiNotFoundHandler) {
507
+ return;
508
+ }
509
+ this.apiNotFoundHandler = (req, res) => {
510
+ const payload = {
511
+ code: 404,
512
+ message: this.describeMissingEndpoint(req),
513
+ data: null,
514
+ errors: {}
515
+ };
516
+ res.status(404).json(payload);
517
+ };
518
+ this.app.use(this.apiBasePath, this.apiNotFoundHandler);
519
+ }
520
+ ensureApiNotFoundOrdering() {
521
+ this.installApiNotFoundHandler();
522
+ if (!this.apiNotFoundHandler) {
523
+ return;
524
+ }
525
+ const stack = this.app?._router?.stack;
526
+ if (!stack) {
527
+ return;
528
+ }
529
+ const index = stack.findIndex((layer) => layer.handle === this.apiNotFoundHandler);
530
+ if (index === -1 || index === stack.length - 1) {
531
+ return;
532
+ }
533
+ const [layer] = stack.splice(index, 1);
534
+ stack.push(layer);
535
+ }
536
+ describeMissingEndpoint(req) {
537
+ const method = typeof req.method === 'string' ? req.method.toUpperCase() : 'GET';
538
+ const target = req.originalUrl || req.url || this.apiBasePath;
539
+ return `No such endpoint: ${method} ${target}`;
540
+ }
488
541
  start() {
489
542
  this.app
490
543
  .listen({
@@ -620,18 +673,18 @@ export class ApiServer {
620
673
  handle_request(handler, auth) {
621
674
  return async (req, res, next) => {
622
675
  void next;
676
+ const apiReq = {
677
+ server: this,
678
+ req,
679
+ res,
680
+ token: '',
681
+ tokenData: null,
682
+ getClientInfo: () => ensureClientInfo(apiReq),
683
+ getClientIp: () => ensureClientInfo(apiReq).ip,
684
+ getClientIpChain: () => ensureClientInfo(apiReq).ipchain
685
+ };
686
+ this.currReq = apiReq;
623
687
  try {
624
- const apiReq = {
625
- server: this,
626
- req,
627
- res,
628
- token: '',
629
- tokenData: null,
630
- getClientInfo: () => ensureClientInfo(apiReq),
631
- getClientIp: () => ensureClientInfo(apiReq).ip,
632
- getClientIpChain: () => ensureClientInfo(apiReq).ipchain
633
- };
634
- this.currReq = apiReq;
635
688
  if (this.config.hydrateGetBody) {
636
689
  hydrateGetBody(apiReq.req);
637
690
  }
@@ -652,7 +705,11 @@ export class ApiServer {
652
705
  throw new ApiError({ code: 500, message: 'Handler result must start with a numeric status code' });
653
706
  }
654
707
  const message = typeof rawMessage === 'string' ? rawMessage : 'Success';
655
- res.status(code).json({ code, message, data });
708
+ const responsePayload = { code, message, data };
709
+ if (this.config.debug) {
710
+ this.dumpResponse(apiReq, responsePayload, code);
711
+ }
712
+ res.status(code).json(responsePayload);
656
713
  }
657
714
  catch (error) {
658
715
  if (error instanceof ApiError || isApiErrorLike(error)) {
@@ -660,20 +717,28 @@ export class ApiServer {
660
717
  const normalizedErrors = apiError.errors && typeof apiError.errors === 'object' && !Array.isArray(apiError.errors)
661
718
  ? apiError.errors
662
719
  : {};
663
- res.status(apiError.code).json({
720
+ const errorPayload = {
664
721
  code: apiError.code,
665
722
  message: apiError.message,
666
723
  data: apiError.data ?? null,
667
724
  errors: normalizedErrors
668
- });
725
+ };
726
+ if (this.config.debug) {
727
+ this.dumpResponse(apiReq, errorPayload, apiError.code);
728
+ }
729
+ res.status(apiError.code).json(errorPayload);
669
730
  }
670
731
  else {
671
- res.status(500).json({
732
+ const errorPayload = {
672
733
  code: 500,
673
734
  message: this.guessExceptionText(error),
674
735
  data: null,
675
736
  errors: {}
676
- });
737
+ };
738
+ if (this.config.debug) {
739
+ this.dumpResponse(apiReq, errorPayload, 500);
740
+ }
741
+ res.status(500).json(errorPayload);
677
742
  }
678
743
  }
679
744
  };
@@ -685,7 +750,7 @@ export class ApiServer {
685
750
  this.authModule(module);
686
751
  }
687
752
  module.checkConfig();
688
- const base = this.config.apiBasePath ?? '/api';
753
+ const base = this.apiBasePath;
689
754
  const ns = module.namespace;
690
755
  const mountPath = `${base}${ns}`;
691
756
  module.mountpath = mountPath;
@@ -697,6 +762,7 @@ export class ApiServer {
697
762
  }
698
763
  });
699
764
  this.app.use(mountPath, router);
765
+ this.ensureApiNotFoundOrdering();
700
766
  return this;
701
767
  }
702
768
  dumpRequest(apiReq) {
@@ -711,5 +777,58 @@ export class ApiServer {
711
777
  console.log('Headers:', req.headers);
712
778
  console.log('------------------------');
713
779
  }
780
+ formatDebugValue(value, maxLength = 50, seen = new WeakSet()) {
781
+ if (value === null || value === undefined) {
782
+ return value;
783
+ }
784
+ if (typeof value === 'string') {
785
+ return value.length <= maxLength
786
+ ? value
787
+ : `${value.slice(0, maxLength)}… [truncated ${value.length - maxLength} chars]`;
788
+ }
789
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
790
+ return value;
791
+ }
792
+ if (typeof value === 'symbol') {
793
+ return value.toString();
794
+ }
795
+ if (value instanceof Date) {
796
+ return value.toISOString();
797
+ }
798
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
799
+ return `<Buffer length=${value.length}>`;
800
+ }
801
+ if (typeof value === 'function') {
802
+ return `[Function ${value.name || 'anonymous'}]`;
803
+ }
804
+ if (typeof value === 'object') {
805
+ const obj = value;
806
+ if (seen.has(obj)) {
807
+ return '[Circular]';
808
+ }
809
+ seen.add(obj);
810
+ if (Array.isArray(value)) {
811
+ const arr = value.map((item) => this.formatDebugValue(item, maxLength, seen));
812
+ seen.delete(obj);
813
+ return arr;
814
+ }
815
+ const recordValue = value;
816
+ const entries = Object.entries(recordValue).reduce((acc, [key, val]) => {
817
+ acc[key] = this.formatDebugValue(val, maxLength, seen);
818
+ return acc;
819
+ }, {});
820
+ seen.delete(obj);
821
+ return entries;
822
+ }
823
+ return value;
824
+ }
825
+ dumpResponse(apiReq, payload, status) {
826
+ const url = apiReq.req.originalUrl || apiReq.req.url;
827
+ console.log('--- Outgoing Response! ---');
828
+ console.log('URL:', url);
829
+ console.log('Status:', status);
830
+ console.log('Payload:', this.formatDebugValue(payload));
831
+ console.log('--------------------------');
832
+ }
714
833
  }
715
834
  export default ApiServer;
@@ -9,6 +9,7 @@ export interface AuthTokenMetadata {
9
9
  ip?: string;
10
10
  os?: string;
11
11
  scope?: string | string[];
12
+ loginType?: string;
12
13
  revokeSessions?: 'device' | 'domain' | 'client' | 'user';
13
14
  }
14
15
  export interface AuthTokenData extends AuthTokenMetadata {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/api-server-base",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Api Server Skeleton / Base Class",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.cjs",