Skip to content

Commit 6f72e1d

Browse files
committed
chore: switch to pnpm
1 parent f2c524f commit 6f72e1d

11 files changed

Lines changed: 4611 additions & 7301 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@ jobs:
1616
CI: true
1717
name: Test and lint
1818
steps:
19-
- uses: actions/checkout@v4
19+
- uses: actions/checkout@v6
20+
- uses: pnpm/action-setup@v6
2021
- name: Setup node
21-
uses: actions/setup-node@v4
22+
uses: actions/setup-node@v6
2223
with:
23-
node-version: 20.x
24-
- name: npm install
25-
run: npm i
24+
node-version: 24
25+
registry-url: https://registry.npmjs.org
26+
cache: pnpm
27+
- name: pnpm install
28+
run: pnpm i
2629
- name: build
27-
run: npm run build
30+
run: pnpm build
2831
- name: Unittesting
29-
run: npm run test
32+
run: pnpm test
3033
- name: Linting
31-
run: npm run lint
34+
run: pnpm lint

.github/workflows/publish.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
needs: docker
3333
runs-on: ubuntu-latest
3434
steps:
35-
- uses: actions/checkout@v4
35+
- uses: actions/checkout@v6
3636
- name: Update repo description
3737
uses: peter-evans/dockerhub-description@v4
3838
with:

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pnpm lint

Dockerfile

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
1-
FROM node:20-alpine AS build
1+
FROM node:24-alpine AS build
22

3-
RUN npm -g install npm@10
3+
ENV PNPM_HOME="/pnpm"
4+
ENV PATH="$PNPM_HOME:$PATH"
5+
RUN corepack enable
46

57
COPY bin bin/
68
COPY lib lib/
7-
COPY package-lock.json .
9+
COPY pnpm-lock.yaml .
810
COPY package.json .
911
COPY rollup.config.ts .
1012
COPY tsconfig.json .
1113

12-
RUN npm ci
13-
RUN npm run build
14+
RUN pnpm install --frozen-lockfile
15+
RUN pnpm build
1416

1517
FROM node:20-alpine
1618
EXPOSE 8001
1719

1820
WORKDIR /home/node/app
1921

22+
ENV PNPM_HOME="/pnpm"
23+
ENV PATH="$PNPM_HOME:$PATH"
24+
RUN corepack enable
25+
2026
RUN apk add --no-cache tini
21-
RUN npm -g install npm@10
2227

2328
COPY --from=build dist dist/
2429
COPY public public/
2530
COPY views views/
2631
COPY README.md README.md
27-
COPY package-lock.json .
32+
COPY pnpm-lock.yaml .
2833
COPY package.json .
2934

30-
RUN npm ci --omit=dev --ignore-scripts
35+
RUN pnpm install --frozen-lockfile --prod --ignore-scripts
3136

3237
ENTRYPOINT ["tini"]
3338
CMD ["node", "dist/dynamodb-admin.js"]

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ server.on('listening', () => {
7979

8080
## Development
8181

82-
Run `npm run build` and then `DYNAMO_ENDPOINT=http://localhost:8000 npm run start` to start dynamodb-admin.
82+
Run `pnpm build` and then `DYNAMO_ENDPOINT=http://localhost:8000 pnpm start` to start dynamodb-admin.
8383

84-
You can set up a build watcher in a separate terminal using `npm run build:watch` which will re-compile the code on change and cause the dynamodb-admin instance to restart.
84+
You can set up a build watcher in a separate terminal using `pnpm build:watch` which will re-compile the code on change and cause the dynamodb-admin instance to restart.
8585

8686
## See also
8787

lib/routes.ts

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,38 @@ import { listAllTables } from './actions/listAllTables';
1212
import asyncMiddleware from './utils/asyncMiddleware';
1313
import type { DynamoApiController } from './dynamoDbApi';
1414

15+
type TableNameParams = { TableName: string };
16+
type TableItemParams = { TableName: string; key: string };
17+
18+
type TableDefinitionInput = {
19+
TableName: string;
20+
HashAttributeName: string;
21+
HashAttributeType: ScalarAttributeType;
22+
RangeAttributeName?: string;
23+
RangeAttributeType?: ScalarAttributeType;
24+
ReadCapacityUnits: number;
25+
WriteCapacityUnits: number;
26+
};
27+
28+
type SecondaryIndexesInput = Omit<TableDefinitionInput, 'TableName'> & {
29+
IndexName: string;
30+
IndexType: 'global' | 'local';
31+
};
32+
33+
type GetItemQuery = { hash?: string; range?: string };
34+
35+
type TableScanQuery = { pageNum?: string };
36+
37+
type ItemsQuery = {
38+
filters?: string;
39+
startKey?: string;
40+
prevKey?: string;
41+
pageNum?: string;
42+
pageSize?: string;
43+
queryableSelection?: string;
44+
operationType?: string;
45+
};
46+
1547
const DEFAULT_THEME = process.env.DEFAULT_THEME || 'light';
1648

1749
export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath = ''): void {
@@ -46,21 +78,6 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
4678
res.render('create-table', {});
4779
});
4880

49-
type TableDefinitionInput = {
50-
TableName: string;
51-
HashAttributeName: string;
52-
HashAttributeType: ScalarAttributeType;
53-
RangeAttributeName?: string;
54-
RangeAttributeType?: ScalarAttributeType;
55-
ReadCapacityUnits: number;
56-
WriteCapacityUnits: number;
57-
};
58-
59-
type SecondaryIndexesInput = Omit<TableDefinitionInput, 'TableName'> & {
60-
IndexName: string;
61-
IndexType: 'global' | 'local';
62-
};
63-
6481
router.post(
6582
'/create-table',
6683
bodyParser.json({ limit: '500kb' }),
@@ -193,22 +210,21 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
193210
res.send('Tables purged');
194211
}));
195212

196-
router.delete('/tables/:TableName', asyncMiddleware(async(req, res) => {
213+
router.delete('/tables/:TableName', asyncMiddleware<TableNameParams>(async(req, res) => {
197214
const { TableName } = req.params;
198215
await ddbApi.deleteTable({ TableName });
199216
res.status(204).end();
200217
}));
201218

202-
router.delete('/tables/:TableName/all', asyncMiddleware(async(req, res) => {
219+
router.delete('/tables/:TableName/all', asyncMiddleware<TableNameParams>(async(req, res) => {
203220
const { TableName } = req.params;
204221
await purgeTable(TableName, ddbApi);
205222
res.status(200).end();
206223
}));
207224

208-
router.get('/tables/:TableName/get', asyncMiddleware(async(req, res) => {
225+
router.get('/tables/:TableName/get', asyncMiddleware<TableNameParams, any, any, GetItemQuery>(async(req, res) => {
209226
const { TableName } = req.params;
210-
const hash = req.query.hash as string;
211-
const range = req.query.range as string;
227+
const { hash, range } = req.query;
212228
if (hash) {
213229
if (range) {
214230
res.redirect(`${basePath}/tables/${encodeURIComponent(TableName)}/items/${encodeURIComponent(hash)},${encodeURIComponent(range)}`);
@@ -228,10 +244,10 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
228244
});
229245
}));
230246

231-
router.get('/tables/:TableName', asyncMiddleware(async(req, res) => {
232-
const TableName = req.params.TableName;
247+
router.get('/tables/:TableName', asyncMiddleware<TableNameParams, any, any, TableScanQuery>(async(req, res) => {
248+
const { TableName } = req.params;
233249
req.query = pickBy(req.query);
234-
const pageNum = typeof req.query.pageNum === 'string' ? Number.parseInt(req.query.pageNum) : 1;
250+
const pageNum = req.query.pageNum ? Number.parseInt(req.query.pageNum) : 1;
235251

236252
const description = await ddbApi.describeTable({ TableName });
237253
const data = {
@@ -255,13 +271,13 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
255271
res.render('scan', data);
256272
}));
257273

258-
router.get('/tables/:TableName/items', asyncMiddleware(async(req, res) => {
274+
router.get('/tables/:TableName/items', asyncMiddleware<TableNameParams, any, any, ItemsQuery>(async(req, res) => {
259275
const { TableName } = req.params;
260276
req.query = pickBy(req.query);
261-
const filters = typeof req.query.filters === 'string' ? JSON.parse(req.query.filters) : {};
262-
const ExclusiveStartKey = typeof req.query.startKey === 'string' ? JSON.parse(req.query.startKey) : {};
263-
const pageNum = typeof req.query.pageNum === 'string' ? parseInt(req.query.pageNum) : 1;
264-
const queryableSelection = typeof req.query.queryableSelection === 'string' ? req.query.queryableSelection : 'table';
277+
const filters = req.query.filters ? JSON.parse(req.query.filters) : {};
278+
const ExclusiveStartKey = req.query.startKey ? JSON.parse(req.query.startKey) : {};
279+
const pageNum = req.query.pageNum ? parseInt(req.query.pageNum) : 1;
280+
const queryableSelection = req.query.queryableSelection ?? 'table';
265281
const operationType: 'scan' | 'query' = req.query.operationType === 'query' ? 'query' : 'scan';
266282
let indexBeingUsed = null;
267283

@@ -323,7 +339,7 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
323339
KeyConditionExpression: KeyConditionExpression.length ? KeyConditionExpression.join(' AND ') : undefined,
324340
IndexName: queryableSelection !== 'table' ? queryableSelection : undefined,
325341
};
326-
const pageSize = typeof req.query.pageSize === 'string' ? Number.parseInt(req.query.pageSize) : 25;
342+
const pageSize = req.query.pageSize ? Number.parseInt(req.query.pageSize) : 25;
327343

328344
const results = await getPage(ddbApi, tableDescription.KeySchema!, TableName, params, pageSize, operationType);
329345
const { pageItems, nextKey } = results;
@@ -343,10 +359,10 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
343359
const data = {
344360
query: req.query,
345361
pageNum,
346-
prevKey: encodeURIComponent(typeof req.query.prevKey === 'string' ? req.query.prevKey : ''),
347-
startKey: encodeURIComponent(typeof req.query.startKey === 'string' ? req.query.startKey : ''),
362+
prevKey: encodeURIComponent(req.query.prevKey ?? ''),
363+
startKey: encodeURIComponent(req.query.startKey ?? ''),
348364
nextKey: nextKey ? encodeURIComponent(JSON.stringify(nextKey)) : null,
349-
filterQueryString: encodeURIComponent(typeof req.query.filters === 'string' ? req.query.filters : ''),
365+
filterQueryString: encodeURIComponent(req.query.filters ?? ''),
350366
Table: tableDescription,
351367
Items: pageItems,
352368
uniqueKeys,
@@ -355,7 +371,7 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
355371
res.json(data);
356372
}));
357373

358-
router.get('/tables/:TableName/meta', asyncMiddleware(async(req, res) => {
374+
router.get('/tables/:TableName/meta', asyncMiddleware<TableNameParams>(async(req, res) => {
359375
const { TableName } = req.params;
360376
const [tableDescription, items] = await Promise.all([
361377
ddbApi.describeTable({ TableName }),
@@ -368,7 +384,7 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
368384
res.render('meta', data);
369385
}));
370386

371-
router.delete('/tables/:TableName/items/:key', asyncMiddleware(async(req, res) => {
387+
router.delete('/tables/:TableName/items/:key', asyncMiddleware<TableItemParams>(async(req, res) => {
372388
const { TableName } = req.params;
373389
const tableDescription = await ddbApi.describeTable({ TableName });
374390
await ddbApi.deleteItem({
@@ -378,7 +394,7 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
378394
res.status(204).end();
379395
}));
380396

381-
router.get('/tables/:TableName/add-item', asyncMiddleware(async(req, res) => {
397+
router.get('/tables/:TableName/add-item', asyncMiddleware<TableNameParams>(async(req, res) => {
382398
const { TableName } = req.params;
383399
const tableDescription = await ddbApi.describeTable({ TableName });
384400
const Item: Record<string, string | number> = {};
@@ -400,7 +416,7 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
400416
});
401417
}));
402418

403-
router.get('/tables/:TableName/items/:key', asyncMiddleware(async(req, res) => {
419+
router.get('/tables/:TableName/items/:key', asyncMiddleware<TableItemParams>(async(req, res) => {
404420
const { TableName } = req.params;
405421
const tableDescription = await ddbApi.describeTable({ TableName });
406422
const params = {
@@ -421,7 +437,7 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
421437
});
422438
}));
423439

424-
router.put('/tables/:TableName/add-item', bodyParser.json({ limit: '500kb' }), asyncMiddleware(async(req, res) => {
440+
router.put('/tables/:TableName/add-item', bodyParser.json({ limit: '500kb' }), asyncMiddleware<TableNameParams>(async(req, res) => {
425441
const { TableName } = req.params;
426442
const tableDescription = await ddbApi.describeTable({ TableName });
427443
await ddbApi.putItem({ TableName, Item: req.body });
@@ -435,7 +451,7 @@ export function setupRoutes(app: Express, ddbApi: DynamoApiController, basePath
435451
return;
436452
}));
437453

438-
router.put('/tables/:TableName/items/:key', bodyParser.json({ limit: '500kb' }), asyncMiddleware(async(req, res) => {
454+
router.put('/tables/:TableName/items/:key', bodyParser.json({ limit: '500kb' }), asyncMiddleware<TableItemParams>(async(req, res) => {
439455
const { TableName } = req.params;
440456
const tableDescription = await ddbApi.describeTable({ TableName });
441457
await ddbApi.putItem({ TableName, Item: req.body });

lib/utils/asyncMiddleware.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import type { RequestHandler } from 'express';
22

3-
export default function(endpointHandlerFunction: RequestHandler): RequestHandler {
3+
export default function asyncMiddleware<
4+
P extends Record<string, string> = Record<string, string>,
5+
ResBody = any,
6+
ReqBody = any,
7+
ReqQuery extends Record<string, string | string[] | undefined> = Record<string, string | string[] | undefined>,
8+
>(handler: RequestHandler<P, ResBody, ReqBody, ReqQuery>): RequestHandler {
49
return function(req, res, next) {
5-
Promise.resolve(endpointHandlerFunction(req, res, next)).catch(next);
10+
Promise.resolve(handler(req as Parameters<typeof handler>[0], res, next)).catch(next);
611
};
712
}

0 commit comments

Comments
 (0)