@beespoke/micro-server-jwt 0.0.0-stage → 2.0.5
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 +88 -2
- package/dist/JwtPlugin.d.ts +20 -0
- package/dist/TokenGenerator.d.ts +11 -0
- package/dist/authentication.d.ts +7 -0
- package/dist/configuration.d.ts +19 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +165 -0
- package/dist/plugin/index.d.ts +9 -0
- package/dist/plugin/index.js +11 -0
- package/dist/types.d.ts +19 -0
- package/package.json +39 -4
package/README.md
CHANGED
|
@@ -1,3 +1,89 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @beespoke/micro-server-jwt
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
JWT signing, verification, authentication middleware, and a plugin-owned authentication service. Independent of Sequelize. Supports Node 24+ and Bun 1.3.14+.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @beespoke/micro-server @beespoke/micro-server-jwt
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configure protected routes
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { defineConfig } from '@beespoke/micro-server';
|
|
15
|
+
|
|
16
|
+
export default defineConfig({
|
|
17
|
+
plugins: ['@beespoke/micro-server-jwt'],
|
|
18
|
+
pluginOptions: {
|
|
19
|
+
'@beespoke/micro-server-jwt': {
|
|
20
|
+
secret: process.env.JWT_SECRET_KEY!,
|
|
21
|
+
issuer: 'my-api',
|
|
22
|
+
expiresIn: '15m',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
routes: {
|
|
26
|
+
folderName: './routes',
|
|
27
|
+
context: 'api',
|
|
28
|
+
authenticate: '@beespoke/micro-server-jwt',
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Supply a strong signing secret and create the route directory before startup. Core validates that the authentication plugin is enabled before initializing resources. Signing helpers use the active plugin configuration after bootstrap. Optional `refreshSecret` and `refreshExpiresIn` configure refresh tokens; refresh secret falls back to the access secret if omitted.
|
|
34
|
+
|
|
35
|
+
## Start the application
|
|
36
|
+
|
|
37
|
+
Save the configuration as `micro-server.config.ts` next to your application's `package.json`, then create `index.ts`:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { ApplicationServer } from '@beespoke/micro-server';
|
|
41
|
+
|
|
42
|
+
await ApplicationServer.bootstrap();
|
|
43
|
+
for (const signal of ['SIGINT', 'SIGTERM'] as const) {
|
|
44
|
+
process.once(signal, () => {
|
|
45
|
+
void ApplicationServer.close().catch(error => {
|
|
46
|
+
console.error(error);
|
|
47
|
+
process.exitCode = 1;
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Run `bun index.ts` or `node --env-file-if-exists=.env index.ts`. Node requires ESM (`"type": "module"` in package.json). When using Bun, load configuration secrets from the application environment or its `.env` file.
|
|
54
|
+
|
|
55
|
+
## Issue and verify tokens
|
|
56
|
+
|
|
57
|
+
After bootstrap, issue tokens only after application-owned user authentication:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { generate, verify } from '@beespoke/micro-server-jwt';
|
|
61
|
+
|
|
62
|
+
const token = generate({ sub: '123' });
|
|
63
|
+
const payload = verify(token);
|
|
64
|
+
console.log(payload.sub);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Send access tokens as `Authorization: Bearer <token>`. Configured authentication verifies with the trusted signing secret, HS256, and the configured issuer. Missing, invalid, or expired tokens receive HTTP 401. Token-provided keys are never trusted. `decode` reads a payload without verifying it; use `verify` when trust matters. `generateRefreshToken` creates refresh tokens; applications own refresh endpoint policy and token revocation.
|
|
68
|
+
|
|
69
|
+
## Public routes
|
|
70
|
+
|
|
71
|
+
Set `grantPublicAccess = true` on a discovered route class to exempt its entire router. Public routes skip authentication and do not populate a user from an untrusted token. Directory names such as `public` or `dev` do not implicitly exempt routes. All other discovered routes require a valid token with this configuration.
|
|
72
|
+
|
|
73
|
+
The plugin does not implement login endpoints, password validation, account storage, or authorization rules. Manually mounted routes under `configureRoutes` require application-owned authentication middleware. Exported `authenticate`, `getUserFromRequest`, and `validateRequest` helpers are available for explicit use. `AuthenticatedRequest` and `RequestUserType` describe authenticated request data.
|
|
74
|
+
|
|
75
|
+
## Standalone use
|
|
76
|
+
|
|
77
|
+
The root helpers can be used without HTTP core. Explicitly configure `JWT_SECRET_KEY`, `JWT_ISSUER`, and expiry variables before signing/verifying. Refresh helpers additionally use `JWT_SECRET_KEY_REFRESH` and `JWT_EXPIRY_REFRESH`. Plugin mode validates options and restores previous helper configuration on close. Do not depend on standalone fallback secrets.
|
|
78
|
+
|
|
79
|
+
## TypeScript and lifecycle
|
|
80
|
+
|
|
81
|
+
Add this type-only import to an application-owned `plugin-types.d.ts` for configuration autocomplete:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import type {} from '@beespoke/micro-server-jwt/plugin';
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Core validates plugin options before setup and owns cleanup after successful startup or startup failure. Await `ApplicationServer.bootstrap()` before using the configured client, and call `ApplicationServer.close()` during application shutdown. Importing the package does not open a connection. Relative plugin paths resolve from the selected configuration file's directory.
|
|
88
|
+
|
|
89
|
+
The root export can also be used without HTTP core. In that case, explicitly initialize and close the client. The `/plugin` entry is the integration adapter for `@beespoke/micro-server`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { NextFunction, Request, Response } from 'express';
|
|
2
|
+
import type { JwtOptions } from './configuration.js';
|
|
3
|
+
import type { RequestUserType } from './types.js';
|
|
4
|
+
export interface JwtPluginContext {
|
|
5
|
+
provideService<T>(name: string, value: T): void;
|
|
6
|
+
onClose(hook: () => void | Promise<void>): void;
|
|
7
|
+
}
|
|
8
|
+
export interface JwtPlugin {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
setup(context: JwtPluginContext): void;
|
|
11
|
+
}
|
|
12
|
+
export interface JwtService {
|
|
13
|
+
authenticate(req: Request, res: Response, next: NextFunction): void;
|
|
14
|
+
generate(payload: string | Buffer | object): string;
|
|
15
|
+
generateRefreshToken(payload: string | Buffer | object): string;
|
|
16
|
+
verify(token: string): RequestUserType;
|
|
17
|
+
}
|
|
18
|
+
export declare function validateJwtOptions(options: unknown): void;
|
|
19
|
+
/** Inert until setup; services retain their server's keys independently of root helpers. */
|
|
20
|
+
export declare function createJwtPlugin(options?: JwtOptions): JwtPlugin;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Request } from 'express';
|
|
2
|
+
import { RequestUserType } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* generate jwt token from the payload
|
|
5
|
+
* @param payload
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export declare function generate(payload: string | Buffer | object): string;
|
|
9
|
+
export declare function generateRefreshToken(payload: string | Buffer | object): string;
|
|
10
|
+
export declare function verify(token: string, secret?: string): RequestUserType;
|
|
11
|
+
export declare function decode(val: string | Request): RequestUserType;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NextFunction, Request, Response } from 'express';
|
|
2
|
+
/** Relocated from RouterFactory.authenticate; pass true to allow public access. */
|
|
3
|
+
export declare function authenticate(req: Request, res: Response, next: NextFunction, grantPublicAccess?: boolean): void;
|
|
4
|
+
/** Public routes may decode available identity without treating it as verified. */
|
|
5
|
+
export declare function getUserFromRequest(req: Request): void;
|
|
6
|
+
/** Retains the existing JWT / clientSecret verification policy. */
|
|
7
|
+
export declare function validateRequest(req: Request): Boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SignOptions } from 'jsonwebtoken';
|
|
2
|
+
export interface JwtOptions {
|
|
3
|
+
secret?: string;
|
|
4
|
+
expiresIn?: SignOptions['expiresIn'];
|
|
5
|
+
issuer?: string;
|
|
6
|
+
refreshSecret?: string;
|
|
7
|
+
refreshExpiresIn?: SignOptions['expiresIn'];
|
|
8
|
+
}
|
|
9
|
+
export interface JwtConfiguration {
|
|
10
|
+
readonly secret: string;
|
|
11
|
+
readonly expiresIn: SignOptions['expiresIn'];
|
|
12
|
+
readonly issuer: string;
|
|
13
|
+
readonly refreshSecret: string;
|
|
14
|
+
readonly refreshExpiresIn: SignOptions['expiresIn'];
|
|
15
|
+
}
|
|
16
|
+
export declare function configuredJwt(): JwtConfiguration | undefined;
|
|
17
|
+
/** Restore the previous active configuration even when servers close out of order. */
|
|
18
|
+
export declare function configureJwt(configuration: JwtConfiguration): () => void;
|
|
19
|
+
export declare function resolveJwtOptions(options: unknown): JwtConfiguration;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { generate, generateRefreshToken, verify, decode } from './TokenGenerator.js';
|
|
2
|
+
export { authenticate, getUserFromRequest, validateRequest } from './authentication.js';
|
|
3
|
+
export type { RequestUserType, AuthenticatedRequest } from './types.js';
|
|
4
|
+
export { createJwtPlugin, validateJwtOptions } from './JwtPlugin.js';
|
|
5
|
+
export type { JwtService, JwtPlugin, JwtPluginContext } from './JwtPlugin.js';
|
|
6
|
+
export type { JwtOptions } from './configuration.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// src/TokenGenerator.ts
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
|
|
4
|
+
// src/configuration.ts
|
|
5
|
+
var configurations = [];
|
|
6
|
+
function configuredJwt() {
|
|
7
|
+
return configurations[configurations.length - 1];
|
|
8
|
+
}
|
|
9
|
+
function configureJwt(configuration) {
|
|
10
|
+
const entry = { ...configuration };
|
|
11
|
+
configurations.push(entry);
|
|
12
|
+
return () => {
|
|
13
|
+
const index = configurations.indexOf(entry);
|
|
14
|
+
if (index !== -1)
|
|
15
|
+
configurations.splice(index, 1);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function resolveJwtOptions(options) {
|
|
19
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
20
|
+
throw new TypeError("JWT options must be an object");
|
|
21
|
+
}
|
|
22
|
+
const allowed = new Set(["secret", "expiresIn", "issuer", "refreshSecret", "refreshExpiresIn"]);
|
|
23
|
+
for (const key of Object.keys(options)) {
|
|
24
|
+
if (!allowed.has(key))
|
|
25
|
+
throw new TypeError(`Unknown JWT option: ${key}`);
|
|
26
|
+
}
|
|
27
|
+
const value = options;
|
|
28
|
+
for (const field of ["secret", "refreshSecret", "issuer"]) {
|
|
29
|
+
if (value[field] !== undefined && (typeof value[field] !== "string" || !value[field].trim())) {
|
|
30
|
+
throw new TypeError(`JWT ${field} must be a nonempty string`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const secret = value.secret ?? process.env.JWT_SECRET_KEY;
|
|
34
|
+
if (!secret?.trim() || secret === "your-secret-key-here") {
|
|
35
|
+
throw new TypeError("JWT requires a trusted nonempty secret (secret or JWT_SECRET_KEY)");
|
|
36
|
+
}
|
|
37
|
+
const refreshSecret = value.refreshSecret ?? process.env.JWT_SECRET_KEY_REFRESH ?? secret;
|
|
38
|
+
if (!refreshSecret.trim() || refreshSecret === "your-secret-key-here") {
|
|
39
|
+
throw new TypeError("JWT refreshSecret must be a trusted nonempty string");
|
|
40
|
+
}
|
|
41
|
+
const expiresIn = value.expiresIn ?? process.env.JWT_EXPIRY ?? "15m";
|
|
42
|
+
const refreshExpiresIn = value.refreshExpiresIn ?? process.env.JWT_EXPIRY_REFRESH ?? "15m";
|
|
43
|
+
validateExpiry(expiresIn, "expiresIn");
|
|
44
|
+
validateExpiry(refreshExpiresIn, "refreshExpiresIn");
|
|
45
|
+
const issuer = value.issuer ?? process.env.JWT_ISSUER ?? "*.service";
|
|
46
|
+
if (!issuer.trim())
|
|
47
|
+
throw new TypeError("JWT issuer must be a nonempty string");
|
|
48
|
+
return { secret, refreshSecret, expiresIn, refreshExpiresIn, issuer };
|
|
49
|
+
}
|
|
50
|
+
function validateExpiry(value, field) {
|
|
51
|
+
const duration = /^(?:\d+(?:\.\d+)?|\.\d+)\s*(?:milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i;
|
|
52
|
+
if (typeof value === "number" ? Number.isFinite(value) && Number.isInteger(value) && value > 0 : typeof value === "string" && value.length <= 100 && duration.test(value) && parseFloat(value) > 0)
|
|
53
|
+
return;
|
|
54
|
+
throw new TypeError(`JWT ${field} must be a positive number of seconds or a duration string`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/TokenGenerator.ts
|
|
58
|
+
function generate(payload) {
|
|
59
|
+
const configured = configuredJwt();
|
|
60
|
+
const SECRET_KEY = configured?.secret ?? process.env.JWT_SECRET_KEY ?? "your-secret-key-here";
|
|
61
|
+
const EXPIRY = configured?.expiresIn ?? process.env.JWT_EXPIRY ?? "15m";
|
|
62
|
+
const ISSUER = configured?.issuer ?? process.env.JWT_ISSUER ?? "*.service";
|
|
63
|
+
return jwt.sign(payload, SECRET_KEY, { expiresIn: EXPIRY, issuer: ISSUER });
|
|
64
|
+
}
|
|
65
|
+
function generateRefreshToken(payload) {
|
|
66
|
+
const configured = configuredJwt();
|
|
67
|
+
const SECRET_KEY = configured?.refreshSecret ?? process.env.JWT_SECRET_KEY_REFRESH ?? "your-secret-key-here";
|
|
68
|
+
const EXPIRY = configured?.refreshExpiresIn ?? process.env.JWT_EXPIRY_REFRESH ?? "15m";
|
|
69
|
+
const ISSUER = configured?.issuer ?? process.env.JWT_ISSUER ?? "*.service";
|
|
70
|
+
return jwt.sign(payload, SECRET_KEY, { expiresIn: EXPIRY, issuer: ISSUER });
|
|
71
|
+
}
|
|
72
|
+
function verify(token, secret) {
|
|
73
|
+
const configured = configuredJwt();
|
|
74
|
+
const SECRET_KEY = configured?.secret ?? process.env.JWT_SECRET_KEY;
|
|
75
|
+
let decoded = jwt.verify(token, secret || SECRET_KEY, configured ? { issuer: configured.issuer, algorithms: ["HS256"] } : undefined);
|
|
76
|
+
return decoded;
|
|
77
|
+
}
|
|
78
|
+
function decode(val) {
|
|
79
|
+
let token = "";
|
|
80
|
+
if (typeof val !== "string") {
|
|
81
|
+
token = val.headers["access-token"];
|
|
82
|
+
} else {
|
|
83
|
+
token = val;
|
|
84
|
+
}
|
|
85
|
+
let decoded = jwt.decode(token);
|
|
86
|
+
return decoded;
|
|
87
|
+
}
|
|
88
|
+
// src/authentication.ts
|
|
89
|
+
function authenticate(req, res, next, grantPublicAccess = false) {
|
|
90
|
+
try {
|
|
91
|
+
if (grantPublicAccess) {
|
|
92
|
+
if (!configuredJwt())
|
|
93
|
+
getUserFromRequest(req);
|
|
94
|
+
} else if (!validateRequest(req)) {
|
|
95
|
+
res.status(401).send({ success: false, error: 1004, errorMessage: "Unauthorized. Invalid Access Token." });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
next();
|
|
99
|
+
} catch (error) {
|
|
100
|
+
res.status(401).send({ success: false, error: 1005, errorMessage: error.message });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function getUserFromRequest(req) {
|
|
104
|
+
const token = bearerToken(req);
|
|
105
|
+
if (token)
|
|
106
|
+
req.user = decode(token);
|
|
107
|
+
}
|
|
108
|
+
function validateRequest(req) {
|
|
109
|
+
const token = bearerToken(req);
|
|
110
|
+
if (!token)
|
|
111
|
+
return false;
|
|
112
|
+
const configured = configuredJwt();
|
|
113
|
+
const secret = configured ? configured.secret : decode(token)?.clientSecret;
|
|
114
|
+
req.user = verify(token, secret);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
function bearerToken(req) {
|
|
118
|
+
return /^Bearer\s+(\S+)\s*$/i.exec(req.headers.authorization || "")?.[1];
|
|
119
|
+
}
|
|
120
|
+
// src/JwtPlugin.ts
|
|
121
|
+
import jwt2 from "jsonwebtoken";
|
|
122
|
+
function validateJwtOptions(options) {
|
|
123
|
+
resolveJwtOptions(options);
|
|
124
|
+
}
|
|
125
|
+
function createJwtPlugin(options = {}) {
|
|
126
|
+
const configuration = resolveJwtOptions(options);
|
|
127
|
+
const service = {
|
|
128
|
+
generate: (payload) => jwt2.sign(payload, configuration.secret, { expiresIn: configuration.expiresIn, issuer: configuration.issuer }),
|
|
129
|
+
generateRefreshToken: (payload) => jwt2.sign(payload, configuration.refreshSecret, { expiresIn: configuration.refreshExpiresIn, issuer: configuration.issuer }),
|
|
130
|
+
verify: (token) => jwt2.verify(token, configuration.secret, { issuer: configuration.issuer, algorithms: ["HS256"] }),
|
|
131
|
+
authenticate(req, res, next) {
|
|
132
|
+
const token = /^Bearer\s+(\S+)\s*$/i.exec(req.headers.authorization || "")?.[1];
|
|
133
|
+
if (!token) {
|
|
134
|
+
res.status(401).send({ success: false, error: 1004, errorMessage: "Unauthorized. Invalid Access Token." });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
req.user = service.verify(token);
|
|
139
|
+
} catch {
|
|
140
|
+
res.status(401).send({ success: false, error: 1005, errorMessage: "Unauthorized. Invalid Access Token." });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
next();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
return {
|
|
147
|
+
name: "@beespoke/micro-server-jwt",
|
|
148
|
+
setup(context) {
|
|
149
|
+
context.provideService("@beespoke/micro-server-jwt", service);
|
|
150
|
+
const restore = configureJwt(configuration);
|
|
151
|
+
context.onClose(restore);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
export {
|
|
156
|
+
verify,
|
|
157
|
+
validateRequest,
|
|
158
|
+
validateJwtOptions,
|
|
159
|
+
getUserFromRequest,
|
|
160
|
+
generateRefreshToken,
|
|
161
|
+
generate,
|
|
162
|
+
decode,
|
|
163
|
+
createJwtPlugin,
|
|
164
|
+
authenticate
|
|
165
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PluginDefinition } from '@beespoke/micro-server';
|
|
2
|
+
import type { JwtOptions } from '../index.js';
|
|
3
|
+
declare module '@beespoke/micro-server' {
|
|
4
|
+
interface PluginOptionsRegistry {
|
|
5
|
+
'@beespoke/micro-server-jwt': JwtOptions;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
declare const definition: PluginDefinition<JwtOptions>;
|
|
9
|
+
export default definition;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/plugin/index.ts
|
|
2
|
+
import { createJwtPlugin, validateJwtOptions } from "../index.js";
|
|
3
|
+
var definition = {
|
|
4
|
+
name: "@beespoke/micro-server-jwt",
|
|
5
|
+
validate: validateJwtOptions,
|
|
6
|
+
create: createJwtPlugin
|
|
7
|
+
};
|
|
8
|
+
var plugin_default = definition;
|
|
9
|
+
export {
|
|
10
|
+
plugin_default as default
|
|
11
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Request } from 'express';
|
|
2
|
+
/** Authentication payload shape retained independently of Sequelize. */
|
|
3
|
+
export type RequestUserType = {
|
|
4
|
+
id?: number;
|
|
5
|
+
email?: string;
|
|
6
|
+
clientSecret?: string;
|
|
7
|
+
type?: string;
|
|
8
|
+
[claim: string]: any;
|
|
9
|
+
};
|
|
10
|
+
export type AuthenticatedRequest = Request & {
|
|
11
|
+
user?: RequestUserType;
|
|
12
|
+
};
|
|
13
|
+
declare global {
|
|
14
|
+
namespace Express {
|
|
15
|
+
interface Request {
|
|
16
|
+
user?: any;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beespoke/micro-server-jwt",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "2.0.5",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./plugin": {
|
|
13
|
+
"types": "./dist/plugin/index.d.ts",
|
|
14
|
+
"import": "./dist/plugin/index.js",
|
|
15
|
+
"default": "./dist/plugin/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "bun ../../scripts/build-package.ts",
|
|
23
|
+
"test": "bun test tests"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"jsonwebtoken": "8.5.1",
|
|
27
|
+
"@types/jsonwebtoken": "^9.0.6",
|
|
28
|
+
"@types/express": "^4.17.21",
|
|
29
|
+
"@types/node": "^24.0.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@beespoke/micro-server": "^2.0.5"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@beespoke/micro-server": {
|
|
36
|
+
"optional": true
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"author": "CCCI Inc."
|
|
41
|
+
}
|