@devmoods/express-extras 0.27.0 → 0.28.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/bin/migrate +1 -1
- package/bin/routes +5 -0
- package/dist/auth.js +2 -1
- package/dist/cache.d.ts +4 -1
- package/dist/cache.js +9 -3
- package/dist/cli/migrate.js +3 -0
- package/dist/cli/routes.d.ts +1 -0
- package/dist/cli/routes.js +10 -0
- package/dist/listen.d.ts +18 -10
- package/dist/listen.js +116 -44
- package/dist/logger.d.ts +2 -5
- package/dist/logger.js +6 -2
- package/dist/migrate.js +3 -1
- package/dist/setupTests.js +0 -5
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +7 -0
- package/package.json +16 -22
- package/dist/cli.js +0 -3
- /package/dist/{cli.d.ts → cli/migrate.d.ts} +0 -0
package/bin/migrate
CHANGED
package/bin/routes
ADDED
package/dist/auth.js
CHANGED
|
@@ -142,7 +142,7 @@ export function EmailAndPasswordAuthProvider(options) {
|
|
|
142
142
|
},
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
|
-
export function createAuth({ getUserByToken, filterUser
|
|
145
|
+
export function createAuth({ getUserByToken, filterUser, redis, providers, }) {
|
|
146
146
|
const useCurrentUser = () => useContext('currentUser');
|
|
147
147
|
const setCurrentUser = (user) => setContext('currentUser', user);
|
|
148
148
|
const providerContext = {
|
|
@@ -272,6 +272,7 @@ export function parseAuthorizationHeader(req) {
|
|
|
272
272
|
if (!token) {
|
|
273
273
|
if (type) {
|
|
274
274
|
return type;
|
|
275
|
+
/* c8 ignore next 3 */
|
|
275
276
|
}
|
|
276
277
|
return null;
|
|
277
278
|
}
|
package/dist/cache.d.ts
CHANGED
|
@@ -4,7 +4,10 @@ export interface CacheAdapter {
|
|
|
4
4
|
set(key: string, value: any, expires?: number | null | undefined): Promise<void>;
|
|
5
5
|
clear(key?: string): Promise<void>;
|
|
6
6
|
}
|
|
7
|
-
export
|
|
7
|
+
export interface RedisCacheAdapterOptions {
|
|
8
|
+
keyPrefix?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function createRedisCacheAdapter(redis: RedisClient, options?: RedisCacheAdapterOptions): CacheAdapter;
|
|
8
11
|
export declare function createMemoryCacheAdapter(): CacheAdapter;
|
|
9
12
|
export declare function createCache(adapter: CacheAdapter): {
|
|
10
13
|
set: (key: string, value: any, expires?: number | null | undefined) => Promise<void>;
|
package/dist/cache.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import {} from './redis.js';
|
|
2
|
-
export function createRedisCacheAdapter(redis) {
|
|
2
|
+
export function createRedisCacheAdapter(redis, options = {}) {
|
|
3
|
+
const { keyPrefix = 'cache:' } = options;
|
|
4
|
+
const createKey = (key) => `${keyPrefix}${key}`;
|
|
3
5
|
return {
|
|
4
6
|
async get(key) {
|
|
5
|
-
const value = await redis.get(key);
|
|
7
|
+
const value = await redis.get(createKey(key));
|
|
6
8
|
if (value == null) {
|
|
7
9
|
return null;
|
|
8
10
|
}
|
|
9
11
|
return JSON.parse(value);
|
|
10
12
|
},
|
|
11
13
|
async set(key, value, expires) {
|
|
12
|
-
await redis.set(key, JSON.stringify(value), { PX: expires });
|
|
14
|
+
await redis.set(createKey(key), JSON.stringify(value), { PX: expires });
|
|
13
15
|
},
|
|
14
16
|
async clear(key) {
|
|
15
17
|
if (key) {
|
|
18
|
+
await redis.del(createKey(key));
|
|
19
|
+
}
|
|
20
|
+
const keys = await redis.keys(`${keyPrefix}*`);
|
|
21
|
+
for (const key of keys) {
|
|
16
22
|
await redis.del(key);
|
|
17
23
|
}
|
|
18
24
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createFetch } from '@devmoods/fetch';
|
|
2
|
+
const port = process.env.PORT ?? 3000;
|
|
3
|
+
const fetch = createFetch({
|
|
4
|
+
getRootUrl: () => `http://localhost:${port}`,
|
|
5
|
+
getRequestId: () => 'routes',
|
|
6
|
+
});
|
|
7
|
+
const response = await fetch('/docs');
|
|
8
|
+
for (const route of response.jsonData.routes) {
|
|
9
|
+
process.stdout.write(`${route.method.toLocaleUpperCase().padEnd(5)} ${route.path}\n`);
|
|
10
|
+
}
|
package/dist/listen.d.ts
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
-
import type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import type { Application } from 'express';
|
|
3
|
+
import type { Server } from 'node:http';
|
|
4
|
+
interface StoppableServer extends Server {
|
|
5
|
+
inspect(): Record<string, any>;
|
|
6
|
+
stop(): Promise<boolean>;
|
|
7
|
+
}
|
|
8
|
+
export declare function stoppable(server: Server, grace?: number): StoppableServer;
|
|
9
|
+
interface ExpressServerOptions {
|
|
10
|
+
onShutdown?(): Promise<void> | void;
|
|
11
|
+
healthCheck?(): Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
export declare function createExpressServer(app: Application, options?: ExpressServerOptions): {
|
|
14
|
+
start(): void;
|
|
15
|
+
stop(): Promise<boolean>;
|
|
16
|
+
terminate(): Promise<void>;
|
|
17
|
+
readonly port: number;
|
|
18
|
+
};
|
|
19
|
+
export {};
|
package/dist/listen.js
CHANGED
|
@@ -1,54 +1,126 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { delay } from '@devmoods/fetch';
|
|
2
|
+
import * as http from 'node:http';
|
|
2
3
|
import { getLogger } from './logger.js';
|
|
3
|
-
import {
|
|
4
|
+
import { route } from './middleware.js';
|
|
5
|
+
import { envPort, readEnv } from './utils.js';
|
|
4
6
|
const logger = getLogger('http');
|
|
5
7
|
const READINESS_PERIOD_MS = readEnv.number('READINESS_PERIOD_MS', 0);
|
|
6
8
|
const FORCE_EXIT_TIMEOUT = readEnv.number('FORCE_EXIT_TIMEOUT', 5000);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
export function stoppable(server, grace = Infinity) {
|
|
10
|
+
let stopped = false;
|
|
11
|
+
let gracefully = true;
|
|
12
|
+
const requestsPerSocket = new Map();
|
|
13
|
+
const onConnection = (socket) => {
|
|
14
|
+
requestsPerSocket.set(socket, 0);
|
|
15
|
+
socket.once('close', () => requestsPerSocket.delete(socket));
|
|
16
|
+
};
|
|
17
|
+
const onRequest = (req, res) => {
|
|
18
|
+
requestsPerSocket.set(req.socket, requestsPerSocket.get(req.socket) + 1);
|
|
19
|
+
res.once('finish', () => {
|
|
20
|
+
const pending = requestsPerSocket.get(req.socket) - 1;
|
|
21
|
+
requestsPerSocket.set(req.socket, pending);
|
|
22
|
+
if (stopped && pending === 0) {
|
|
23
|
+
req.socket.end();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
function stop() {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
setImmediate(() => {
|
|
30
|
+
stopped = true;
|
|
31
|
+
if (grace < Infinity) {
|
|
32
|
+
setTimeout(destroyAll, grace).unref();
|
|
33
|
+
}
|
|
34
|
+
server.close((e) => {
|
|
35
|
+
if (e) {
|
|
36
|
+
return reject(e);
|
|
37
|
+
}
|
|
38
|
+
resolve(gracefully);
|
|
39
|
+
});
|
|
40
|
+
for (const [socket, requests] of requestsPerSocket) {
|
|
41
|
+
if (requests === 0) {
|
|
42
|
+
socket.end();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function destroyAll() {
|
|
49
|
+
gracefully = false;
|
|
50
|
+
for (const socket of requestsPerSocket.keys()) {
|
|
51
|
+
socket.end();
|
|
52
|
+
}
|
|
53
|
+
setImmediate(() => {
|
|
54
|
+
for (const socket of requestsPerSocket.keys()) {
|
|
55
|
+
socket.destroy();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
server.on('connection', onConnection);
|
|
60
|
+
server.on('request', onRequest);
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
server.stop = stop;
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
server.inspect = () => {
|
|
65
|
+
return {
|
|
66
|
+
sockets: requestsPerSocket.size,
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
return server;
|
|
70
|
+
}
|
|
71
|
+
export function createExpressServer(app, options = {}) {
|
|
72
|
+
const server = stoppable(http.createServer(app), FORCE_EXIT_TIMEOUT);
|
|
73
|
+
let stopping = false;
|
|
74
|
+
async function onSignal(signal) {
|
|
75
|
+
if (stopping) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
stopping = true;
|
|
79
|
+
try {
|
|
80
|
+
logger.info(`app shutting down due to ${signal}`);
|
|
81
|
+
await delay(READINESS_PERIOD_MS + 1000);
|
|
82
|
+
await server.stop();
|
|
83
|
+
await options.onShutdown?.();
|
|
84
|
+
logger.info('app shut down');
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
logger.error(error, 'error during shutdown');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const signal of ['SIGTERM', 'SIGINT']) {
|
|
93
|
+
process.on(signal, onSignal);
|
|
94
|
+
}
|
|
95
|
+
app.get('/health', route(async () => {
|
|
96
|
+
const timestamp = new Date().toISOString();
|
|
97
|
+
try {
|
|
98
|
+
if (stopping) {
|
|
99
|
+
throw new Error();
|
|
100
|
+
}
|
|
101
|
+
const meta = await options.healthCheck?.();
|
|
102
|
+
return { status: 'ok', meta, timestamp };
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return [503, { status: 'error', timestamp }];
|
|
106
|
+
}
|
|
107
|
+
}));
|
|
108
|
+
return {
|
|
109
|
+
start() {
|
|
110
|
+
const port = app.get('port') ?? envPort(0);
|
|
111
|
+
server.listen(port, () => {
|
|
112
|
+
logger.info('app listening', { port: this.port });
|
|
21
113
|
});
|
|
22
114
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
await options?.onShutdown?.();
|
|
115
|
+
stop() {
|
|
116
|
+
return server.stop();
|
|
26
117
|
},
|
|
27
|
-
|
|
28
|
-
|
|
118
|
+
terminate() {
|
|
119
|
+
return onSignal('SIGTERM');
|
|
29
120
|
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
const meta = await options?.healthCheck?.();
|
|
37
|
-
return {
|
|
38
|
-
meta,
|
|
39
|
-
timestamp: new Date().toISOString(),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
logger.error(error, 'health check failed');
|
|
44
|
-
throw error;
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
verbatim: true,
|
|
121
|
+
get port() {
|
|
122
|
+
// @ts-ignore
|
|
123
|
+
return server.address().port;
|
|
48
124
|
},
|
|
49
|
-
}
|
|
50
|
-
const port = options.port;
|
|
51
|
-
server.listen(port, () => {
|
|
52
|
-
logger.info('app listening', { port });
|
|
53
|
-
});
|
|
125
|
+
};
|
|
54
126
|
}
|
package/dist/logger.d.ts
CHANGED
|
@@ -11,16 +11,13 @@ export interface LoggerOptions {
|
|
|
11
11
|
* Context to attach to each log line
|
|
12
12
|
*/
|
|
13
13
|
getContext?: () => LoggerContext;
|
|
14
|
-
|
|
15
|
-
* Defaults to `process.env.NODE_ENV === 'test'`
|
|
16
|
-
*/
|
|
17
|
-
silent?: () => boolean;
|
|
14
|
+
level?: string;
|
|
18
15
|
output?: Duplex;
|
|
19
16
|
}
|
|
20
17
|
export declare function attachSentryClientToLoggers(sentryClient: CreateSentry['client']): void;
|
|
21
18
|
export declare function setGlobalLoggerContext(getContext: () => LoggerContext): void;
|
|
22
19
|
export type Logger = ReturnType<typeof createLogger>;
|
|
23
|
-
export declare function createLogger({ name, getContext,
|
|
20
|
+
export declare function createLogger({ name, getContext, level, output, }: LoggerOptions): {
|
|
24
21
|
debug(message: string, context?: LoggerContext): void;
|
|
25
22
|
info(message: string, context?: LoggerContext): void;
|
|
26
23
|
warn(message: string, context?: LoggerContext): void;
|
package/dist/logger.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as os from 'node:os';
|
|
2
2
|
import { useRequestId } from './context.js';
|
|
3
|
+
import { readEnv } from './utils.js';
|
|
3
4
|
const LEVELS = {
|
|
4
5
|
TRACE: 10,
|
|
5
6
|
DEBUG: 20,
|
|
@@ -24,14 +25,17 @@ function defaultGetContext() {
|
|
|
24
25
|
..._globalGetContext?.(),
|
|
25
26
|
};
|
|
26
27
|
}
|
|
27
|
-
export function createLogger({ name, getContext,
|
|
28
|
+
export function createLogger({ name, getContext, level = readEnv('LOG_LEVEL', 'INFO'), output = process.stdout, }) {
|
|
28
29
|
if (_loggers.has(name)) {
|
|
29
30
|
throw new Error(`A logger named ${name} already exists`);
|
|
30
31
|
}
|
|
31
32
|
const hostname = os.hostname();
|
|
32
33
|
const pid = process.pid;
|
|
33
34
|
const env = process.env.NODE_ENV;
|
|
34
|
-
const
|
|
35
|
+
const logLevelName = level.toUpperCase();
|
|
36
|
+
const logLevel = logLevelName in LEVELS
|
|
37
|
+
? LEVELS[logLevelName]
|
|
38
|
+
: LEVELS.INFO;
|
|
35
39
|
function getFinalContext(context) {
|
|
36
40
|
return {
|
|
37
41
|
...defaultGetContext(),
|
package/dist/migrate.js
CHANGED
|
@@ -16,7 +16,9 @@ Usage
|
|
|
16
16
|
});
|
|
17
17
|
let exitCode = 0;
|
|
18
18
|
try {
|
|
19
|
-
exitCode = await runCli(cli.input, cli.flags,
|
|
19
|
+
exitCode = await runCli(cli.input, cli.flags,
|
|
20
|
+
/* c8 ignore next 2 */
|
|
21
|
+
() => cli.showHelp());
|
|
20
22
|
}
|
|
21
23
|
catch (error) {
|
|
22
24
|
if (error instanceof CliError) {
|
package/dist/setupTests.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import 'dotenv/config';
|
|
2
2
|
import * as crypto from 'node:crypto';
|
|
3
3
|
// @ts-ignore
|
|
4
|
-
import createFetchMock from 'vitest-fetch-mock';
|
|
5
|
-
import { vi } from 'vitest';
|
|
6
|
-
const fetchMocker = createFetchMock(vi);
|
|
7
|
-
fetchMocker.enableMocks();
|
|
8
|
-
// @ts-ignore
|
|
9
4
|
globalThis.crypto = crypto;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import type { EventEmitter } from 'node:events';
|
|
1
3
|
/**
|
|
2
4
|
* Start a high resolution timer
|
|
3
5
|
*
|
|
@@ -14,4 +16,5 @@ export declare namespace readEnv {
|
|
|
14
16
|
declare function readEnvNumber(key: string, defaultValue: number): number;
|
|
15
17
|
declare function readEnvBoolean(key: string, defaultValue: boolean): boolean;
|
|
16
18
|
export declare const envPort: (defaultPort?: number) => number;
|
|
19
|
+
export declare function waitForEvent(emitter: EventEmitter, event: string): Promise<unknown>;
|
|
17
20
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -25,3 +25,10 @@ function readEnvBoolean(key, defaultValue) {
|
|
|
25
25
|
return ['true', '1', 't'].includes(readEnv(key, `${defaultValue}`).toLowerCase());
|
|
26
26
|
}
|
|
27
27
|
export const envPort = (defaultPort = 3000) => readEnv.number('PORT', defaultPort);
|
|
28
|
+
export async function waitForEvent(emitter, event) {
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
emitter.once(event, (...args) => {
|
|
31
|
+
resolve([args]);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devmoods/express-extras",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Kubernetes-ready utilities for rapid Node.js application development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,17 +24,14 @@
|
|
|
24
24
|
"license": "ISC",
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@devmoods/eslint-config": "^1.2.0",
|
|
27
|
-
"@
|
|
28
|
-
"@types/
|
|
29
|
-
"@types/node": "20.5.3",
|
|
27
|
+
"@types/koa-compose": "^3.2.5",
|
|
28
|
+
"@types/node": "20.5.9",
|
|
30
29
|
"@types/supertest": "^2.0.12",
|
|
31
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
32
|
-
"@typescript-eslint/parser": "^6.
|
|
33
|
-
"@vitest/coverage-v8": "^0.34.
|
|
34
|
-
"@vitest/expect": "^0.34.2",
|
|
35
|
-
"@vitest/runner": "^0.34.3",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
|
31
|
+
"@typescript-eslint/parser": "^6.5.0",
|
|
32
|
+
"@vitest/coverage-v8": "^0.34.3",
|
|
36
33
|
"chalk": "^5.3.0",
|
|
37
|
-
"eslint": "^8.
|
|
34
|
+
"eslint": "^8.48.0",
|
|
38
35
|
"eslint-plugin-jsx-a11y": "^6.7.1",
|
|
39
36
|
"eslint-plugin-prettier": "^5.0.0",
|
|
40
37
|
"eslint-plugin-react": "^7.33.2",
|
|
@@ -42,27 +39,24 @@
|
|
|
42
39
|
"faktory-worker": "^4.5.1",
|
|
43
40
|
"import-sort-cli": "6.0.0",
|
|
44
41
|
"import-sort-style-module": "6.0.0",
|
|
45
|
-
"prettier": "3.0.
|
|
42
|
+
"prettier": "3.0.3",
|
|
46
43
|
"supertest": "6.3.3",
|
|
47
44
|
"ts-node": "10.9.1",
|
|
48
|
-
"typescript": "5.
|
|
49
|
-
"vitest": "^0.34.
|
|
50
|
-
"vitest-fetch-mock": "^0.2.2"
|
|
45
|
+
"typescript": "5.2.2",
|
|
46
|
+
"vitest": "^0.34.3"
|
|
51
47
|
},
|
|
52
48
|
"dependencies": {
|
|
53
49
|
"@devmoods/fetch": "^3.3.0",
|
|
54
|
-
"@
|
|
55
|
-
"@sentry/node": "^7.64.0",
|
|
50
|
+
"@sentry/node": "^7.66.0",
|
|
56
51
|
"@types/bcrypt": "^5.0.0",
|
|
57
52
|
"@types/body-parser": "^1.19.2",
|
|
58
53
|
"@types/cookie-parser": "^1.4.3",
|
|
59
54
|
"@types/express": "^4.17.17",
|
|
60
55
|
"@types/jsonwebtoken": "^9.0.2",
|
|
61
|
-
"@types/koa-compose": "^3.2.5",
|
|
62
56
|
"@types/nodemailer": "^6.4.9",
|
|
63
57
|
"@types/pg": "^8.10.2",
|
|
64
58
|
"@types/superagent": "^4.1.18",
|
|
65
|
-
"@types/uuid": "^9.0.
|
|
59
|
+
"@types/uuid": "^9.0.3",
|
|
66
60
|
"ajv": "^8.12.0",
|
|
67
61
|
"bcrypt": "^5.1.1",
|
|
68
62
|
"body-parser": "^1.20.2",
|
|
@@ -72,11 +66,11 @@
|
|
|
72
66
|
"express": "^4.18.2",
|
|
73
67
|
"express-route-parser": "^1.0.5",
|
|
74
68
|
"helmet": "^7.0.0",
|
|
75
|
-
"jsonwebtoken": "^9.0.
|
|
76
|
-
"meow": "^12.1.
|
|
69
|
+
"jsonwebtoken": "^9.0.2",
|
|
70
|
+
"meow": "^12.1.1",
|
|
77
71
|
"nodemailer": "^6.9.4",
|
|
78
72
|
"pg": "^8.11.3",
|
|
79
|
-
"redis": "^4.6.
|
|
73
|
+
"redis": "^4.6.8",
|
|
80
74
|
"sql-template-strings": "^2.2.2",
|
|
81
75
|
"uuid": "^9.0.0"
|
|
82
76
|
},
|
|
@@ -104,7 +98,7 @@
|
|
|
104
98
|
"start:worker": "ts-node --esm example/worker.ts",
|
|
105
99
|
"clean": "rm -rf dist",
|
|
106
100
|
"lint": "eslint src",
|
|
107
|
-
"test": "
|
|
101
|
+
"test": "./test.sh src",
|
|
108
102
|
"build": "pnpm run clean && tsc --project tsconfig.build.json",
|
|
109
103
|
"prettier": "prettier --write '**/*.{js,css,md,ts,tsx}'",
|
|
110
104
|
"import-sort": "import-sort --write '**/*.{js,jsx,ts,tsx}'",
|
package/dist/cli.js
DELETED
|
File without changes
|