Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/rework-package #239

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
11 changes: 11 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "koajs/koa-body" }],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": []
}
23 changes: 23 additions & 0 deletions .changeset/slimy-cats-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
"koa-body": major
---

chore: introduce `@biomejs/biome` as linter and formatter instead of `prettier`
chore: introduce `@changesets/cli` to automate publish and changelog
chore: introduce GitHub actions for publishing to npm
chore: introduce GitHub actions for preview publish using `pkg-pr-new`
chore: replace `mocha` with `node:test`
chore: updated all dependencies to latest except `formidable` because of https://github.com/node-formidable/formidable/issues/958
chore: updated dev dependency `koa-router` to use `@koa/router` instead
chore: introduce `tshy` and `@arethetypeswrong/cli` to have esm and commonjs exports and verification that types and exports are compatible with different module resolutions (fixes: https://github.com/koajs/koa-body/issues/233)
chore: introduce `pnpm` as package-manager

refactor: use `ctx.request.rawBody` instead of `ctx.request.body[symbolUnparsed]` for unparsed body if `includeUnparsed` is set
refactor: `ctx.request.rawBody` is also set on content-type `text/*` if `includeUnparsed` is set
refactor: if given method is not in `parsedMethods` do not patch koa and node with empty object anymore (fixes: https://github.com/koajs/koa-body/issues/238)
refactor: changed type of `ctx.req.body` and `ctx.request.body` from `any` to `{ [key: string]: unknown } | string`

feat: allow to override formidable `onPart` see https://github.com/node-formidable/formidable#formonpart (fixes: https://github.com/koajs/koa-body/issues/172)

docs: updated README.md to reflect changes
docs: reworked examples to use `typescript`
26 changes: 20 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,33 @@ on:
pull_request:
branches: [master]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [18.x, 20.x, 22.x]

steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
- name: Checkout Repo
uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm i
- run: npm test
cache: "pnpm"

- name: Install Dependencies
run: pnpm install

- name: Build Package
run: pnpm build
44 changes: 44 additions & 0 deletions .github/workflows/preview-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Preview release
on:
pull_request_review:
types: [submitted]
pull_request:
types: [labeled]

jobs:
check:
if: ${{ github.event.review.state == 'approved' || contains(github.event.pull_request.labels.*.name, 'ready-for-preview') }}
runs-on: ubuntu-latest
outputs:
has-permissions: ${{ steps.checkPermissions.outputs.require-result }}
steps:
- name: Check permissions
id: checkPermissions
uses: actions-cool/check-user-permission@v2
with:
require: "write"

publish:
needs: check
if: needs.check.outputs.has-permissions == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: "./.nvmrc"
cache: "pnpm"

- name: Install Dependencies
run: pnpm install

- name: Build Package
run: pnpm build

- run: pnpm dlx pkg-pr-new publish
36 changes: 36 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Release

on:
push:
branches:
- main

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: "./.nvmrc"
cache: "pnpm"

- name: Install Dependencies
run: pnpm install

- name: Create Release Pull Request or Publish to npm
uses: changesets/action@v1
with:
publish: pnpm release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
9 changes: 3 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
.directory
node_modules
npm-debug.log
yarn.lock
package-lock.json
*.tgz
lib/
dist
.idea
.tshy*

6 changes: 0 additions & 6 deletions .mocharc.json

This file was deleted.

1 change: 0 additions & 1 deletion .npmrc

This file was deleted.

1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v22.14.0
1 change: 0 additions & 1 deletion .prettierignore

This file was deleted.

5 changes: 0 additions & 5 deletions .prettierrc.json

This file was deleted.

15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ Request Body: {"name":"test"}%

**For a more comprehensive example, see** `examples/multipart.js`

## Usage with [koa-router](https://github.com/alexmingoia/koa-router)
## Usage with [@koa/router](https://github.com/koajs/router)

It's generally better to only parse the body as needed, if using a router that supports middleware composition, we can inject it only for certain routes.

```js
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
const router = require('@koa/router')();
const { koaBody } = require('koa-body');

router.post('/users', koaBody(), (ctx) => {
Expand Down Expand Up @@ -132,7 +132,7 @@ Request Body: {"declaration":{"attributes":{"version":"1.0"}},"elements":[{"type

## Options

> Options available for `koa-body`. Four custom options, and others are from `raw-body` and `formidable`.
> Options available for `koa-body`. Four custom options, and others are from `co-body` and `formidable`.

- `patchNode` **{Boolean}** Patch request body to Node's `ctx.req`, default `false`
- `patchKoa` **{Boolean}** Patch request body to Koa's `ctx.request`, default `true`
Expand All @@ -145,7 +145,7 @@ Request Body: {"declaration":{"attributes":{"version":"1.0"}},"elements":[{"type
- `text` **{Boolean}** Parse text bodies, such as XML, default `true`
- `json` **{Boolean}** Parse JSON bodies, default `true`
- `jsonStrict` **{Boolean}** Toggles co-body strict mode; if set to true - only parses arrays or objects, default `true`
- `includeUnparsed` **{Boolean}** Toggles co-body returnRawBody option; if set to true, for form encoded and JSON requests the raw, unparsed request body will be attached to `ctx.request.body` using a `Symbol` ([see details](#a-note-about-unparsed-request-bodies)), default `false`
- `includeUnparsed` **{Boolean}** Toggles co-body returnRawBody option; if set to true, for form encoded and JSON requests the raw, unparsed request body will be attached to `ctx.request.rawBody`, default `false`
- `formidable` **{Object}** Options to pass to the formidable multipart parser
- `onError` **{Function}** Custom error handle, if throw an error, you can customize the response - onError(error, context), default will throw
- `parsedMethods` **{String[]}** Declares the HTTP methods where bodies will be parsed, default `['POST', 'PUT', 'PATCH']`. Replaces `strict` option.
Expand All @@ -164,19 +164,20 @@ Uploaded files are accessible via `ctx.request.files`.

## A note about unparsed request bodies

Some applications require cryptographic verification of request bodies, for example webhooks from slack or stripe. The unparsed body can be accessed if `includeUnparsed` is `true` in koa-body's options. When enabled, import the symbol for accessing the request body from `unparsed = require('koa-body/unparsed.js')`, or define your own accessor using `unparsed = Symbol.for('unparsedBody')`. Then the unparsed body is available using `ctx.request.body[unparsed]`.
Some applications require cryptographic verification of request bodies, for example webhooks from slack or stripe. The unparsed body can be accessed if `includeUnparsed` is `true` in koa-body's options. Then the unparsed body is available at `ctx.request.rawBody`. This only works for non `multipart` bodies.

## Some options for formidable

> See [node-formidable](https://github.com/felixge/node-formidable) for a full list of options
> See [node-formidable](https://github.com/node-formidable/formidable) for a full list of options

- `maxFields` **{Integer}** Limits the number of fields that the querystring parser will decode, default `1000`
- `maxFieldsSize` **{Integer}** Limits the amount of memory all fields together (except files) can allocate in bytes. If this value is exceeded, an 'error' event is emitted, default `2mb (2 * 1024 * 1024)`
- `uploadDir` **{String}** Sets the directory for placing file uploads in, default `os.tmpDir()`
- `keepExtensions` **{Boolean}** Files written to `uploadDir` will include the extensions of the original files, default `false`
- `hashAlgorithm` **{String}** If you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`, default `false`
- `multiples` **{Boolean}** Multiple file uploads or no, default `true`
- `onFileBegin` **{Function}** Special callback on file begin. The function is executed directly by formidable. It can be used to rename files before saving them to disk. [See the docs](https://github.com/felixge/node-formidable#filebegin)
- `onFileBegin` **{Function}** Special callback on file begin. The function is executed directly by formidable. It can be used to rename files before saving them to disk. [See the docs](https://github.com/node-formidable/formidable#filebegin)
- `onPart` **{Function}** Overrides the default onPart of formidable. The function can be used to filter out parts based on their mimetype. For more use cases. [See the docs](https://github.com/node-formidable/formidable#formonpart)

## Changelog

Expand Down
32 changes: 32 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
"files": { "ignoreUnknown": false, "ignore": ["dist", "package.json"] },
"formatter": {
"enabled": true,
"useEditorconfig": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 100,
"attributePosition": "auto",
"bracketSpacing": true,
"ignore": ["**/dist"]
},
"organizeImports": { "enabled": true },
"linter": { "enabled": true, "rules": { "recommended": true } },
"javascript": {
"formatter": {
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "all",
"semicolons": "always",
"arrowParentheses": "always",
"bracketSameLine": false,
"quoteStyle": "single",
"attributePosition": "auto",
"bracketSpacing": true
}
}
}
45 changes: 16 additions & 29 deletions examples/koa-router.js → examples/koa-router.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
'use strict';
import Router from '@koa/router';
import Koa from 'koa';
import koaBody from '../src/index.js';

const log = console.log;
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
const koaBody = require('../index');
const router = new Router();
const port = process.env.PORT || 4290;
const host = process.env.HOST || 'http://localhost';

Expand All @@ -13,7 +12,7 @@ const host = process.env.HOST || 'http://localhost';
*/
router.post('/post/users', koaBody(), (ctx) => {
const body = ctx.request.body;
log('body', body);
console.log('body', body);
// => POST body object
ctx.body = JSON.stringify(body, null, 2);
});
Expand All @@ -25,7 +24,7 @@ router.get('/', (ctx) => {
ctx.set('Content-Type', 'text/html');
ctx.body = `
<!doctype html>
<html>
<html lang="en">
<body>
<form action="/post/upload" enctype="multipart/form-data" method="post">
<input type="text" name="username" placeholder="username"><br>
Expand All @@ -44,25 +43,13 @@ router.post(
koaBody({
multipart: true,
formidable: {
uploadDir: __dirname + '/uploads',
uploadDir: `${__dirname}/uploads`,
},
}),
(ctx) => {
const fields = ctx.request.body.fields; // this will be undefined for file uploads
const fields = ctx.request.body;
const files = ctx.request.files;
log('files', JSON.stringify(files, null, 2));
/*{
"requestFields": null,
"requestFiles": {
"source": {
"size": 748831,
"path": "/some-dir/upload_cc1e0c49b97af0b9ef17b7b2f96b307d",
"name": "avatar.png",
"type": "image/png",
"mtime": "2018-07-07T14:16:22.576Z"
}
}
}*/
console.log('files', JSON.stringify(files, null, 2));

// respond with the fields and files for example purposes
ctx.body = JSON.stringify(
Expand All @@ -79,10 +66,10 @@ router.post(
app.use(router.routes());
app.listen(port);

log('Visit %s:%s/ in browser.', host, port);
log();
log('Test with executing this commands:');
log('curl -i %s:%s/post/users -d "user=admin"', host, port);
log('curl -i %s:%s/post/upload -F "source=@%s/avatar.png"', host, port, __dirname);
log();
log('Press CTRL+C to stop...');
console.log('Visit %s:%s/ in browser.', host, port);
console.log();
console.log('Test with executing this commands:');
console.log('curl -i %s:%s/post/users -d "user=admin"', host, port);
console.log('curl -i %s:%s/post/upload -F "source=@%s/avatar.png"', host, port, __dirname);
console.log();
console.log('Press CTRL+C to stop...');
Loading