Skip to content
Merged
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
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ node_modules
__tests__
*.test.js
dist
benchmarks
benchmarks
e2e
16 changes: 10 additions & 6 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
"extends": ["eslint:recommended", "prettier"],
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
"sourceType": "script"
},
"rules": {},
"globals": {
"expect": true,
"it": true
}
"overrides": [
{
"files": ["src/**/*.js", "__tests__/**/*.mjs"],
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
}
}
]
}
10 changes: 6 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ jobs:

strategy:
matrix:
node-version: [14.x]
# The SWC build toolchain requires Node >= 16.14, so coverage runs on a
# modern LTS. Runtime compatibility across older Node is covered by the
# release workflow's test matrix against the prebuilt dist.
node-version: [20.x]

steps:
- name: Get branch name (merge)
Expand All @@ -28,9 +31,8 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install NPM
run: npm install -g npm@9
- run: npm ci
cache: 'npm'
- run: npm ci --ignore-scripts
- run: npm run test-ci
env:
COVERALLS_SERVICE_NAME: GithubActions
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: 'E2E'

# Dual-package (CJS/ESM) end-to-end validation. Manual only — the Docker/LocalStack layer is
# heavy and these are not fast unit checks, so they never gate PRs.
on:
workflow_dispatch:

jobs:
layer1:
name: 'Layer 1 (Node ${{ matrix.node }})'
runs-on: ubuntu-latest
strategy:
matrix:
node: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci --ignore-scripts
- run: npm run test:e2e

layer2-localstack:
name: 'Layer 2 (LocalStack)'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci --ignore-scripts
- name: Install LocalStack driver deps
working-directory: e2e/localstack
run: npm install --no-audit --no-fund
- name: Run LocalStack e2e
run: npm run test:e2e:localstack
52 changes: 44 additions & 8 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,42 @@ on:
types: [opened, reopened, synchronize]

jobs:
# Build the dual CJS/ESM output once on a modern Node (the SWC toolchain requires
# Node >= 16.14), then share dist/ with the test matrix so older Node versions are
# exercised against the compiled runtime without having to run the build themselves.
build:
name: 'Build'
runs-on: ubuntu-latest
steps:
- name: 'Checkout latest code'
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Build dist (CJS + ESM)
run: npm run build
- name: Type check
run: npm run test:types
- name: Upload dist
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1

test:
name: Node ${{ matrix.node }}
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
node: [14, 16, 18, 20, 22]
name: Node ${{ matrix.node }}
steps:
- name: 'Checkout latest code'
uses: actions/checkout@v4
Expand All @@ -23,9 +53,14 @@ jobs:
- name: Install NPM (if node 14)
run: if [ "${{ matrix.node }}" == "14" ]; then npm install -g npm@9; fi
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test
run: npm ci --ignore-scripts
- name: Download prebuilt dist
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Run tests against prebuilt dist
run: npm run test:prebuilt

lint:
name: 'ESLint'
Expand All @@ -38,10 +73,10 @@ jobs:
- name: Set up node
uses: actions/setup-node@v4
with:
node-version: '16'
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
run: npm ci --ignore-scripts
- name: Run ESLint
run: npm run lint:check

Expand All @@ -56,8 +91,9 @@ jobs:
- name: Set up node
uses: actions/setup-node@v4
with:
node-version: '16'
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
run: npm ci --ignore-scripts
- name: Run Prettier
run: npm run prettier:check
41 changes: 37 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,36 @@ permissions:
contents: read

jobs:
# Build the dual CJS/ESM output once (SWC needs Node >= 16.14), then run the test
# matrix against the prebuilt dist so Node 14-22 runtime compatibility is verified
# without building on the older versions.
build:
name: 'Build'
runs-on: ubuntu-latest
steps:
- name: Checkout latest code
uses: actions/checkout@v4
- name: Set up node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Build dist (CJS + ESM)
run: npm run build
- name: Type check
run: npm run test:types
- name: Upload dist
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1

test:
name: 'Test (Node ${{ matrix.node }})'
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -32,9 +60,14 @@ jobs:
- name: Install NPM (if node 14)
run: if [ "${{ matrix.node }}" == "14" ]; then npm install -g npm@9; fi
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test
run: npm ci --ignore-scripts
- name: Download prebuilt dist
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Run tests against prebuilt dist
run: npm run test:prebuilt

publish:
name: 'Publish to npm'
Expand All @@ -55,7 +88,7 @@ jobs:
# Trusted publishing requires npm >= 11.5.1.
run: npm install -g npm@latest
- name: Install dependencies
run: npm ci
run: npm ci --ignore-scripts
- name: Set version to publish
# package.json ships a 0.0.0-development placeholder; the real version
# comes from the manual input (workflow_dispatch) or the release tag,
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ dump.rdb
# Coverage reports
.nyc_output
coverage

# Build output
dist
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ node_modules
__tests__
*.test.js
dist
benchmarks
benchmarks
e2e
16 changes: 16 additions & 0 deletions .swcrc.cjs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://swc.rs/schema.json",
"jsc": {
"parser": {
"syntax": "ecmascript",
"dynamicImport": true
},
"target": "es2018",
"keepClassNames": true
},
"module": {
"type": "commonjs",
"noInterop": false
},
"sourceMaps": false
}
17 changes: 17 additions & 0 deletions .swcrc.esm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://swc.rs/schema.json",
"jsc": {
"parser": {
"syntax": "ecmascript",
"dynamicImport": true
},
"target": "es2018",
"keepClassNames": true
},
"module": {
"type": "es6",
"strict": false,
"noInterop": false
},
"sourceMaps": false
}
51 changes: 51 additions & 0 deletions __tests__/esm-compat.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use strict';

import createAPI from '../dist/esm/index.js';
import * as utils from '../dist/esm/lib/utils.js';
import prettyPrint from '../dist/esm/lib/prettyPrint.js';
import { ApiError } from '../dist/esm/lib/errors.js';

const event = {
httpMethod: 'GET',
path: '/compat',
headers: {},
multiValueHeaders: {},
};

async function main() {
const createApi = createAPI({ version: 'v1.0' });
createApi.get('/compat', (req, res) => {
res.json({ ok: true, method: req.method });
});

const result = await createApi.run(event, {});

if (typeof createAPI !== 'function') {
throw new Error('Expected default export to be a function');
}

if (typeof utils.escapeHtml !== 'function') {
throw new Error('Expected utils.escapeHtml to be a function');
}

if (typeof prettyPrint !== 'function') {
throw new Error('Expected prettyPrint default export to be a function');
}

if (typeof ApiError !== 'function') {
throw new Error('Expected ApiError export to be a function');
}

if (result.statusCode !== 200) {
throw new Error(`Expected statusCode 200, received ${result.statusCode}`);
}

if (JSON.parse(result.body).ok !== true) {
throw new Error('Expected successful ESM route response');
}
}

main().catch((error) => {
console.error(error);
process.exit(1);
});
Loading
Loading