Skip to content

Commit

Permalink
feat: add @ory/nextjs package
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-jonas committed Nov 29, 2024
1 parent 6913bca commit 2110d67
Show file tree
Hide file tree
Showing 47 changed files with 3,144 additions and 165 deletions.
18 changes: 18 additions & 0 deletions .github/codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
flag_management:
default_rules: # the rules that will be followed for any flag added, generally
carryforward: true
statuses:
- type: project
target: auto
threshold: 1%
- type: patch
target: 90%
individual_flags: # exceptions to the default rules above, stated flag by flag
- name: @ory/elements-react #fill in your own flag name
paths:
- packages/elements-react #fill in your own path. Note, accepts globs, not regexes
carryforward: true
- name: @ory/nextjs #fill in your own flag name
paths:
- packages/nextjs #fill in your own path. Note, accepts globs, not regexes
carryforward: true
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ jobs:
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
codecov_yml_path: .github/codecov.yml
934 changes: 769 additions & 165 deletions package-lock.json

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions packages/nextjs/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
// "extends": ["../../.eslintrc.base.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/dependency-checks": "error"
}
}
]
}
17 changes: 17 additions & 0 deletions packages/nextjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# nextjs

This library was generated with [Nx](https://nx.dev).

## Building

Run `nx build @ory/nextjs` to build the library.

## Developing

Run `nx dev @ory/nextjs` to watch the source code for changes and continuously
build the library.

## Running unit tests

Run `nx test @ory/nextjs` to execute the unit tests via
[Jest](https://jestjs.io).
15 changes: 15 additions & 0 deletions packages/nextjs/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0

/* eslint-disable */
export default {
displayName: "nextjs",
preset: "../../jest.preset.js",
testEnvironment: "node",
transform: {
"^.+\\.[tj]s$": ["ts-jest", { tsconfig: "<rootDir>/tsconfig.spec.json" }],
},
collectCoverageFrom: ["src/**/*.ts", "src/**/*.js"],
moduleFileExtensions: ["ts", "js", "html"],
coverageDirectory: "../../coverage/packages/nextjs",
}
73 changes: 73 additions & 0 deletions packages/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"name": "@ory/nextjs",
"version": "0.0.1",
"type": "commonjs",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"private": false,
"dependencies": {
"@ory/client-fetch": "^1.15.6",
"cookie": "^1.0.1",
"psl": "^1.10.0",
"set-cookie-parser": "^2.7.1"
},
"devDependencies": {
"@types/cookie": "^0.6.0",
"@types/psl": "^1.1.3",
"@types/set-cookie-parser": "^2.4.10",
"babel-jest": "^29.7.0",
"jest-esm-transformer": "^1.0.0",
"tsup": "8.3.0"
},
"keywords": [
"ory",
"auth",
"react",
"passwordless",
"login",
"user management",
"permissions",
"authentication",
"nextjs",
"vercel",
"app router",
"pages router"
],
"peerDependencies": {
"next": ">=13.1.0",
"react": ">=16.0.0"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./middleware": {
"types": "./dist/middleware/index.d.ts",
"import": "./dist/middleware/index.mjs",
"require": "./dist/middleware/index.js"
},
"./app": {
"types": "./dist/app/index.d.ts",
"import": "./dist/app/index.mjs",
"require": "./dist/app/index.js"
},
"./pages": {
"types": "./dist/pages/index.d.ts",
"import": "./dist/pages/index.mjs",
"require": "./dist/pages/index.js"
}
},
"typesVersions": {
"*": {
"index": [
"./dist/index.d.ts"
],
"middleware": [
"./dist/middleware/index.d.ts"
]
}
}
}
30 changes: 30 additions & 0 deletions packages/nextjs/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@ory/nextjs",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/nextjs/src",
"projectType": "library",
"tags": [],
"targets": {
"build": {
"command": "tsup --clean --dts",
"options": {
"cwd": "packages/nextjs"
}
},
"dev": {
"command": "tsup --watch --dts",
"options": {
"cwd": "packages/nextjs"
}
},
"test": {
"executor": "@nx/jest:jest",
"dependsOn": ["build"],
"options": {
"jestConfig": "packages/nextjs/jest.config.ts",
"coverage": true,
"coverageReporters": ["text", "cobertura"]
}
}
}
}
15 changes: 15 additions & 0 deletions packages/nextjs/src/app/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0

import { Configuration, FrontendApi } from "@ory/client-fetch"

import { orySdkUrl } from "../utils/sdk"

export const serverSideFrontendClient = new FrontendApi(
new Configuration({
headers: {
Accept: "application/json",
},
basePath: orySdkUrl(),
}),
)
64 changes: 64 additions & 0 deletions packages/nextjs/src/app/flow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0

import { redirect, RedirectType } from "next/navigation"
import { FlowType, handleFlowError } from "@ory/client-fetch"

import { getPublicUrl, onRedirect } from "./utils"
import { QueryParams } from "../types"
import { guessPotentiallyProxiedOrySdkUrl } from "../utils/sdk"
import { onValidationError } from "../utils/utils"
import { rewriteJsonResponse } from "../utils/rewrite"
import * as runtime from "@ory/client-fetch/src/runtime"

export async function getFlow<T extends object>(
params: QueryParams | Promise<QueryParams>,
fetchFlowRaw: () => Promise<runtime.ApiResponse<T>>,
flowType: FlowType,
): Promise<T | null | void> {
const p = await params

// Guess our own public url using Next.js helpers. We need the hostname, port, and protocol.
const knownProxiedUrl = await getPublicUrl()

const onRestartFlow = () => {
return redirect(
new URL(
"/self-service/" +
flowType.toString() +
"/browser?" +
params.toString(),
guessPotentiallyProxiedOrySdkUrl({
knownProxiedUrl,
}),
).toString(),
RedirectType.replace,
)
}

if (!p["flow"]) {
onRestartFlow()
return
}

try {
const rawResponse = await fetchFlowRaw()
return await rawResponse
.value()
.then(
(v: T): T =>
rewriteJsonResponse(
v,
guessPotentiallyProxiedOrySdkUrl({ knownProxiedUrl }),
),
)
} catch (error) {
const errorHandler = handleFlowError({
onValidationError,
onRestartFlow,
onRedirect: onRedirect,
})
await errorHandler(error)
return null
}
}
10 changes: 10 additions & 0 deletions packages/nextjs/src/app/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
"use server"

export { getLoginFlow } from "./login"
export { getRegistrationFlow } from "./registration"
export { getRecoveryFlow } from "./recovery"
export { getVerificationFlow } from "./verification"

export type { OryPageParams } from "./utils"
13 changes: 13 additions & 0 deletions packages/nextjs/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
import { PropsWithChildren } from "react"

import "@ory/elements-react/theme/styles.css"

export default async function AuthLayout({ children }: PropsWithChildren) {
return (
<main className="p-4 pb-8 flex items-center justify-center flex-col gap-8 min-h-screen">
{children}
</main>
)
}
53 changes: 53 additions & 0 deletions packages/nextjs/src/app/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
import { FlowType, LoginFlow } from "@ory/client-fetch"

import { initOverrides, QueryParams } from "../types"
import { serverSideFrontendClient } from "./client"
import { getFlow } from "./flow"
import { toFlowParams } from "./utils"

/**
* Use this method in an app router page to fetch an existing login flow or to create a new one. This method works with server-side rendering.
*
* ```
* import { Login } from "@ory/elements-react/theme"
* import { getLoginFlow, OryPageParams } from "@ory/nextjs/app"
* import { enhanceConfig } from "@ory/nextjs"
*
* import config from "@/ory.config"
* import CardHeader from "@/app/auth/login/card-header"
*
* export default async function LoginPage(props: OryPageParams) {
* const flow = await getLoginFlow(props.searchParams)
*
* if (!flow) {
* return null
* }
*
* return (
* <Login
* flow={flow}
* config={enhanceConfig(config)}
* components={{
* Card: {
* Header: CardHeader,
* },
* }}
* />
* )
* }
* ```
*
* @param params The query parameters of the request.
*/
export async function getLoginFlow(
params: QueryParams | Promise<QueryParams>,
): Promise<LoginFlow | null | void> {
const p = await toFlowParams(await params)
return getFlow(
params,
() => serverSideFrontendClient.getLoginFlowRaw(p, initOverrides),
FlowType.Login,
)
}
Loading

0 comments on commit 2110d67

Please sign in to comment.