Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into phated/decision-ttl
Browse files Browse the repository at this point in the history
  • Loading branch information
blaine-arcjet committed Dec 14, 2023
2 parents c3e6b10 + f822c9f commit de890b4
Show file tree
Hide file tree
Showing 29 changed files with 543 additions and 124 deletions.
13 changes: 6 additions & 7 deletions analyze/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@arcjet/analyze",
"version": "1.0.0-alpha.3",
"version": "1.0.0-alpha.4",
"description": "Arcjet local analysis engine",
"license": "Apache-2.0",
"homepage": "https://arcjet.com",
Expand All @@ -10,8 +10,7 @@
"directory": "analyze"
},
"engines": {
"node": ">=18",
"npm": ">=10"
"node": ">=18"
},
"type": "module",
"main": "./index.js",
Expand All @@ -36,12 +35,12 @@
"./wasm/arcjet_analyze_js_req_bg.js"
],
"dependencies": {
"@arcjet/logger": "1.0.0-alpha.3"
"@arcjet/logger": "1.0.0-alpha.4"
},
"devDependencies": {
"@arcjet/eslint-config": "1.0.0-alpha.3",
"@arcjet/rollup-config": "1.0.0-alpha.3",
"@arcjet/tsconfig": "1.0.0-alpha.3",
"@arcjet/eslint-config": "1.0.0-alpha.4",
"@arcjet/rollup-config": "1.0.0-alpha.4",
"@arcjet/tsconfig": "1.0.0-alpha.4",
"@jest/globals": "29.7.0",
"@rollup/wasm-node": "4.8.0",
"@types/node": "18.18.0",
Expand Down
65 changes: 51 additions & 14 deletions arcjet-next/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Interceptor } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web";
import type { NextApiResponse } from "next";
import {
NextFetchEvent,
NextMiddleware,
NextRequest,
type NextFetchEvent,
type NextMiddleware,
type NextRequest,
NextResponse,
} from "next/server.js";
import type { NextMiddlewareResult } from "next/dist/server/web/types.js";
import arcjet, {
ArcjetDecision,
ArcjetOptions,
Expand All @@ -22,7 +24,6 @@ import arcjet, {
createRemoteClient,
} from "arcjet";
import findIP from "@arcjet/ip";
import { NextMiddlewareResult } from "next/dist/server/web/types.js";

// Re-export all named exports from the generic SDK
export * from "arcjet";
Expand Down Expand Up @@ -236,6 +237,30 @@ export function createMiddleware<const Rules extends (Primitive | Product)[]>(
};
}

function isNextApiResponse(val: unknown): val is NextApiResponse {
if (val === null) {
return false;
}

if (typeof val !== "object") {
return false;
}

if (!("status" in val)) {
return false;
}

if (!("json" in val)) {
return false;
}

if (typeof val.status !== "function" || typeof val.json !== "function") {
return false;
}

return true;
}

/**
* Wraps a Next.js page route, edge middleware, or an API route running on the
* Edge Runtime.
Expand All @@ -258,19 +283,31 @@ export function withArcjet<Args extends [ArcjetNextRequest, ...unknown[]], Res>(
) {
return async (...args: Args) => {
const request = args[0];
const response = args[1];
const decision = await arcjet.protect(request);
if (decision.isDenied()) {
// TODO(#222): Content type negotiation using `Accept` header
if (decision.reason.isRateLimit()) {
return NextResponse.json(
{ code: 429, message: "Too Many Requests" },
{ status: 429 },
);
if (isNextApiResponse(response)) {
// TODO(#222): Content type negotiation using `Accept` header
if (decision.reason.isRateLimit()) {
return response
.status(429)
.json({ code: 429, message: "Too Many Requests" });
} else {
return response.status(403).json({ code: 403, message: "Forbidden" });
}
} else {
return NextResponse.json(
{ code: 403, message: "Forbidden" },
{ status: 403 },
);
// TODO(#222): Content type negotiation using `Accept` header
if (decision.reason.isRateLimit()) {
return NextResponse.json(
{ code: 429, message: "Too Many Requests" },
{ status: 429 },
);
} else {
return NextResponse.json(
{ code: 403, message: "Forbidden" },
{ status: 403 },
);
}
}
} else {
return handler(...args);
Expand Down
15 changes: 7 additions & 8 deletions arcjet-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@arcjet/next",
"version": "1.0.0-alpha.3",
"version": "1.0.0-alpha.4",
"description": "Arcjet SDK for the Next.js framework",
"license": "Apache-2.0",
"homepage": "https://arcjet.com",
Expand All @@ -10,8 +10,7 @@
"directory": "arcjet-next"
},
"engines": {
"node": ">=18",
"npm": ">=10"
"node": ">=18"
},
"type": "module",
"main": "./index.js",
Expand All @@ -32,15 +31,15 @@
"test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests"
},
"dependencies": {
"@arcjet/ip": "1.0.0-alpha.3",
"@arcjet/ip": "1.0.0-alpha.4",
"@connectrpc/connect-web": "1.1.4",
"arcjet": "1.0.0-alpha.3",
"arcjet": "1.0.0-alpha.4",
"next": "14.0.4"
},
"devDependencies": {
"@arcjet/eslint-config": "1.0.0-alpha.3",
"@arcjet/rollup-config": "1.0.0-alpha.3",
"@arcjet/tsconfig": "1.0.0-alpha.3",
"@arcjet/eslint-config": "1.0.0-alpha.4",
"@arcjet/rollup-config": "1.0.0-alpha.4",
"@arcjet/tsconfig": "1.0.0-alpha.4",
"@jest/globals": "29.7.0",
"@types/node": "18.18.0",
"@rollup/wasm-node": "4.8.0",
Expand Down
17 changes: 8 additions & 9 deletions arcjet/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arcjet",
"version": "1.0.0-alpha.3",
"version": "1.0.0-alpha.4",
"description": "Arcjet TypeScript and JavaScript SDK core",
"license": "Apache-2.0",
"homepage": "https://arcjet.com",
Expand All @@ -10,8 +10,7 @@
"directory": "arcjet"
},
"engines": {
"node": ">=18",
"npm": ">=10"
"node": ">=18"
},
"type": "module",
"main": "./index.js",
Expand All @@ -32,14 +31,14 @@
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
},
"dependencies": {
"@arcjet/analyze": "1.0.0-alpha.3",
"@arcjet/logger": "1.0.0-alpha.3",
"@arcjet/protocol": "1.0.0-alpha.3"
"@arcjet/analyze": "1.0.0-alpha.4",
"@arcjet/logger": "1.0.0-alpha.4",
"@arcjet/protocol": "1.0.0-alpha.4"
},
"devDependencies": {
"@arcjet/eslint-config": "1.0.0-alpha.3",
"@arcjet/rollup-config": "1.0.0-alpha.3",
"@arcjet/tsconfig": "1.0.0-alpha.3",
"@arcjet/eslint-config": "1.0.0-alpha.4",
"@arcjet/rollup-config": "1.0.0-alpha.4",
"@arcjet/tsconfig": "1.0.0-alpha.4",
"@edge-runtime/jest-environment": "2.3.7",
"@jest/globals": "29.7.0",
"@rollup/wasm-node": "4.8.0",
Expand Down
5 changes: 2 additions & 3 deletions eslint-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@arcjet/eslint-config",
"version": "1.0.0-alpha.3",
"version": "1.0.0-alpha.4",
"description": "Custom eslint config for Arcjet projects",
"license": "Apache-2.0",
"homepage": "https://arcjet.com",
Expand All @@ -10,8 +10,7 @@
"directory": "eslint-config"
},
"engines": {
"node": ">=18",
"npm": ">=10"
"node": ">=18"
},
"type": "commonjs",
"main": "./index.js",
Expand Down
3 changes: 3 additions & 0 deletions examples/nextjs-14-pages-wrap/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
36 changes: 36 additions & 0 deletions examples/nextjs-14-pages-wrap/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
29 changes: 29 additions & 0 deletions examples/nextjs-14-pages-wrap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<a href="https://arcjet.com" target="_arcjet-home">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://arcjet.com/arcjet-logo-minimal-dark-mark-all.svg">
<img src="https://arcjet.com/arcjet-logo-minimal-light-mark-all.svg" alt="Arcjet Logo" height="128" width="auto">
</picture>
</a>

# Using `withArcjet` with Next.js 14 and the Pages Router

This example shows how to use `withArcjet` in a Next.js [API
Route](https://nextjs.org/docs/pages/building-your-application/routing/api-routes).

## How to use

1. From the root of the project, install the dependencies.

```bash
npm ci
```

2. Enter this directory and start the dev server.

```bash
cd examples/nextjs-14-pages-wrap
npm run dev
```

3. Visit `http://localhost:3000/api/arcjet`.
4. Refresh the page to trigger the rate limit.
6 changes: 6 additions & 0 deletions examples/nextjs-14-pages-wrap/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}

module.exports = nextConfig
28 changes: 28 additions & 0 deletions examples/nextjs-14-pages-wrap/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "nextjs-14-pages-wrap",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@arcjet/next": "*",
"react": "^18",
"react-dom": "^18",
"next": "14.0.4"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"eslint": "^8",
"eslint-config-next": "14.0.4"
}
}
6 changes: 6 additions & 0 deletions examples/nextjs-14-pages-wrap/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import '@/styles/globals.css'
import type { AppProps } from 'next/app'

export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
13 changes: 13 additions & 0 deletions examples/nextjs-14-pages-wrap/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
28 changes: 28 additions & 0 deletions examples/nextjs-14-pages-wrap/pages/api/arcjet-edge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import arcjet, { rateLimit, withArcjet } from "@arcjet/next";
import { NextRequest, NextResponse } from "next/server";

export const config = {
runtime: "edge",
};

const aj = arcjet({
// mark
key: "ajkey_yourkey",
rules: [
rateLimit({
mode: "LIVE",
// Limiting by ip.src is the default if not specified
//characteristics: ["ip.src"],
window: "1m",
max: 1,
timeout: "10m",
}),
],
});

export default withArcjet(aj, async function handler(req: NextRequest) {
return NextResponse.json({
message: "Hello world",
});
});
Loading

0 comments on commit de890b4

Please sign in to comment.