diff --git a/src/.eslintrc.base.json b/.eslintrc.base.json
similarity index 100%
rename from src/.eslintrc.base.json
rename to .eslintrc.base.json
diff --git a/src/.eslintrc.cjs b/.eslintrc.cjs
similarity index 100%
rename from src/.eslintrc.cjs
rename to .eslintrc.cjs
diff --git a/Makefile b/Makefile
index c9ce47f8a..411a98618 100644
--- a/Makefile
+++ b/Makefile
@@ -10,12 +10,17 @@ install:
test:
npm run test
+build:
+ npm run build
+
+dev:
+ npm run build
+
test-containerized:
# https://github.com/microsoft/playwright/issues/26482
# For unsupported distros, use the `test-containerized` target instead of `test`
sh -c ./playwright-docker.sh
-
PRETTIER_VERSION=$(shell cat package.json | jq -r '.devDependencies["prettier"] // .dependencies["prettier"]')
format: .bin/ory
@@ -23,7 +28,6 @@ format: .bin/ory
@echo "Prettier Version: $(PRETTIER_VERSION)"
npx prettier@$$PRETTIER_VERSION --write .
-
licenses: .bin/licenses node_modules # checks open-source licenses
.bin/licenses
diff --git a/examples/nextjs-pages-router/pages/index.tsx b/examples/nextjs-pages-router/pages/index.tsx
index de8ba21e5..675b72bf5 100644
--- a/examples/nextjs-pages-router/pages/index.tsx
+++ b/examples/nextjs-pages-router/pages/index.tsx
@@ -1,9 +1,9 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
-import React from "react";
-import Link from "next/link";
-import {useSession} from "@ory/nextjs/hooks";
+import React from "react"
+import Link from "next/link"
+import { useSession } from "@ory/nextjs/hooks"
export default function Home() {
const session = useSession()
@@ -11,8 +11,8 @@ export default function Home() {
return "Hello: " + session.identity?.traits.email
}
return (
-
- Not authenticated, please log in.
-
+
+ Not authenticated, please log in.
+
)
}
diff --git a/packages/elements-react/src/client/config.ts b/packages/elements-react/src/client/config.ts
new file mode 100644
index 000000000..453a624a5
--- /dev/null
+++ b/packages/elements-react/src/client/config.ts
@@ -0,0 +1,87 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * This function returns the base URL of the Ory SDK as set by environment variables `NEXT_PUBLIC_ORY_SDK_URL` or `ORY_SDK_URL`.
+ */
+export function orySdkUrl() {
+ let baseUrl
+
+ if (process.env["NEXT_PUBLIC_ORY_SDK_URL"]) {
+ baseUrl = process.env["NEXT_PUBLIC_ORY_SDK_URL"]
+ }
+
+ if (process.env["ORY_SDK_URL"]) {
+ baseUrl = process.env["_ORY_SDK_URL"]
+ }
+
+ if (!baseUrl) {
+ throw new Error(
+ "You need to set environment variable `NEXT_PUBLIC_ORY_SDK_URL` or if you don't use Next.js `ORY_SDK_URL` to your Ory Network SDK URL.",
+ )
+ }
+
+ return baseUrl.replace(/\/$/, "")
+}
+
+/**
+ * This function returns whether the current environment is a production environment.
+ */
+export function isProduction() {
+ return (
+ ["production", "prod"].indexOf(
+ process.env["VERCEL_ENV"] || process.env["NODE_ENV"] || "",
+ ) > -1
+ )
+}
+
+/**
+ * This function returns the Ory SDK URL. If the environment is not production, it tries to guess the SDK URL based on the environment variables, assuming
+ * that Ory APIs are proxied through the same domain as the application.
+ *
+ * Currently, this is only tested for Vercel deployments.
+ *
+ * @param options
+ */
+export function guessPotentiallyProxiedOrySdkUrl(options?: {
+ knownProxiedUrl?: string
+}) {
+ if (isProduction()) {
+ // In production, we use the production custom domain
+ return orySdkUrl()
+ }
+
+ if (process.env["VERCEL_ENV"]) {
+ // We are in vercel
+
+ // The domain name of the generated deployment URL. Example: *.vercel.app. The value does not include the protocol scheme https://.
+ //
+ // This is only available for preview deployments on Vercel.
+ if (!isProduction() && process.env["VERCEL_URL"]) {
+ return `https://${process.env["VERCEL_URL"]}`.replace(/\/$/, "")
+ }
+
+ // This is sometimes set by the render server.
+ if (process.env["__NEXT_PRIVATE_ORIGIN"]) {
+ return process.env["__NEXT_PRIVATE_ORIGIN"].replace(/\/$/, "")
+ }
+ }
+
+ // Unable to figure out the SDK URL. Either because we are not using Vercel or because we are on a local machine.
+ // Let's try to use the window location.
+ if (typeof window !== "undefined") {
+ return window.location.origin
+ }
+
+ if (options?.knownProxiedUrl) {
+ return options.knownProxiedUrl
+ }
+
+ // We tried everything. Let's use the SDK URL.
+ const final = orySdkUrl()
+ console.warn(
+ `Unable to determine a suitable SDK URL for setting up the Next.js integration of Ory Elements. Will proceed using default Ory SDK URL "${final}". This is likely not what you want for local development and your authentication and login may not work.`,
+ )
+
+ return final
+}
diff --git a/packages/elements-react/src/client/frontendClient.ts b/packages/elements-react/src/client/frontendClient.ts
index 66cd0bb2f..d540e3767 100644
--- a/packages/elements-react/src/client/frontendClient.ts
+++ b/packages/elements-react/src/client/frontendClient.ts
@@ -1,19 +1,31 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
-
+"use client"
import {
Configuration,
ConfigurationParameters,
FrontendApi,
} from "@ory/client-fetch"
+import { guessPotentiallyProxiedOrySdkUrl } from "./config"
export function frontendClient(
- sdkUrl: string,
- opts: Partial = {},
+ {
+ forceBaseUrl,
+ ...opts
+ }: Partial = {
+ credentials: "include",
+ },
) {
+ const basePath =
+ forceBaseUrl ??
+ guessPotentiallyProxiedOrySdkUrl({
+ knownProxiedUrl: window.location.origin,
+ })
+
const config = new Configuration({
...opts,
- basePath: sdkUrl,
+ basePath: basePath?.replace(/\/$/, ""),
+ credentials: opts.credentials || "include",
headers: {
Accept: "application/json",
...opts.headers,
diff --git a/packages/nextjs/src/hooks/useSession.spec.tsx b/packages/elements-react/src/client/useSession.spec.tsx
similarity index 86%
rename from packages/nextjs/src/hooks/useSession.spec.tsx
rename to packages/elements-react/src/client/useSession.spec.tsx
index d2cefaa4c..78caf9265 100644
--- a/packages/nextjs/src/hooks/useSession.spec.tsx
+++ b/packages/elements-react/src/client/useSession.spec.tsx
@@ -8,10 +8,10 @@ import "@testing-library/jest-dom"
import "@testing-library/jest-dom/jest-globals"
import { act, render, screen, waitFor } from "@testing-library/react"
import { sessionStore, useSession } from "./useSession"
-import {newOryFrontendClient} from "../utils/sdk";
+import { frontendClient } from "./frontendClient"
-jest.mock("./newOryFrontendClient", () => ({
- newOrynewOryFrontendClient: jest.fn(() => ({
+jest.mock("./frontendClient", () => ({
+ frontendClient: jest.fn(() => ({
toSession: jest.fn(),
})),
}))
@@ -49,7 +49,7 @@ describe("useSession", () => {
})
it("fetches and sets session successfully", async () => {
- ;(newOryFrontendClient as jest.Mock).mockReturnValue({
+ ;(frontendClient as jest.Mock).mockReturnValue({
toSession: jest.fn().mockResolvedValue(mockSession),
})
@@ -70,7 +70,7 @@ describe("useSession", () => {
})
it("doesn't refetch session if a session is set", async () => {
- ;(newOryFrontendClient as jest.Mock).mockReturnValue({
+ ;(frontendClient as jest.Mock).mockReturnValue({
toSession: jest.fn().mockResolvedValue(mockSession),
})
@@ -91,7 +91,7 @@ describe("useSession", () => {
// this is fine, because jest is not calling the function
// eslint-disable-next-line @typescript-eslint/unbound-method
- expect(newOryFrontendClient("").toSession).toHaveBeenCalledTimes(1)
+ expect(frontendClient().toSession).toHaveBeenCalledTimes(1)
act(() => {
render()
@@ -99,12 +99,12 @@ describe("useSession", () => {
// this is fine, because jest is not calling the function
// eslint-disable-next-line @typescript-eslint/unbound-method
- expect(newOryFrontendClient("").toSession).toHaveBeenCalledTimes(1)
+ expect(frontendClient().toSession).toHaveBeenCalledTimes(1)
})
it("handles errors during session fetching", async () => {
const errorMessage = "Failed to fetch session"
- ;(newOryFrontendClient as jest.Mock).mockReturnValue({
+ ;(frontendClient as jest.Mock).mockReturnValue({
toSession: jest.fn().mockRejectedValue(new Error(errorMessage)),
})
@@ -123,7 +123,7 @@ describe("useSession", () => {
})
it("does not fetch session if already loading or session is set", async () => {
- ;(newOryFrontendClient as jest.Mock).mockReturnValue({
+ ;(frontendClient as jest.Mock).mockReturnValue({
toSession: jest.fn(),
})
@@ -140,6 +140,6 @@ describe("useSession", () => {
// this is fine, because jest is not calling the function
// eslint-disable-next-line @typescript-eslint/unbound-method
- expect(newOryFrontendClient("").toSession).toHaveBeenCalledTimes(1)
+ expect(frontendClient().toSession).toHaveBeenCalledTimes(1)
})
})
diff --git a/packages/nextjs/src/hooks/useSession.ts b/packages/elements-react/src/client/useSession.ts
similarity index 79%
rename from packages/nextjs/src/hooks/useSession.ts
rename to packages/elements-react/src/client/useSession.ts
index 0d7684033..d65b7de19 100644
--- a/packages/nextjs/src/hooks/useSession.ts
+++ b/packages/elements-react/src/client/useSession.ts
@@ -6,7 +6,7 @@ import { Session } from "@ory/client-fetch"
import { useCallback, useEffect } from "react"
import { create, useStore } from "zustand"
import { subscribeWithSelector } from "zustand/middleware"
-import {guessPotentiallyProxiedOrySdkUrl, newOryFrontendClient} from "../utils/sdk";
+import { frontendClient } from "./frontendClient"
type SessionStore = {
setIsLoading: (loading: boolean) => void
@@ -38,10 +38,13 @@ export const sessionStore = create()(
*
* @returns The current session, error and loading state.
*/
-export const useSession = (config?: { sdk: { url: string } }) => {
+export const useSession = (config: { orySdkUrl?: string } = {}) => {
const store = useStore(sessionStore)
const fetchSession = useCallback(async () => {
+ const client = frontendClient({
+ forceBaseUrl: config.orySdkUrl,
+ })
const { session, isLoading, setSession, setIsLoading, setError } =
sessionStore.getState()
@@ -52,21 +55,19 @@ export const useSession = (config?: { sdk: { url: string } }) => {
setIsLoading(true)
try {
- const sessionData = await newOryFrontendClient(guessPotentiallyProxiedOrySdkUrl({
- knownProxiedUrl: window.location.origin
- })).toSession()
+ const sessionData = await client.toSession()
setSession(sessionData)
} catch (e) {
setError(e instanceof Error ? e.message : "Unknown error occurred")
- if (!config?.sdk.url) {
+ if (!config?.orySdkUrl) {
console.error(
- "Could not fetch session. Make sure you have set the SDK URL in the config.",
+ "Could not fetch session. Make sure you have set your environment variables correctly.",
)
}
} finally {
setIsLoading(false)
}
- }, [config?.sdk.url])
+ }, [config?.orySdkUrl])
useEffect(() => {
void fetchSession()
diff --git a/packages/elements-react/src/theme/default/components/generic/page-header.tsx b/packages/elements-react/src/theme/default/components/generic/page-header.tsx
index 1533cced1..b4d2e9d87 100644
--- a/packages/elements-react/src/theme/default/components/generic/page-header.tsx
+++ b/packages/elements-react/src/theme/default/components/generic/page-header.tsx
@@ -3,7 +3,7 @@
import { OryPageHeaderProps, useComponents } from "@ory/elements-react"
import { UserMenu } from "../ui/user-menu"
-import { useSession } from "@ory/elements-react/client"
+import { useSession } from "../../../../client"
export const DefaultPageHeader = (_props: OryPageHeaderProps) => {
const { Card } = useComponents()
diff --git a/packages/nextjs/src/hooks/index.ts b/packages/nextjs/src/hooks/index.ts
index f7267b954..5e2c58350 100644
--- a/packages/nextjs/src/hooks/index.ts
+++ b/packages/nextjs/src/hooks/index.ts
@@ -1,4 +1,3 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
"use client"
-export { useSession } from "./useSession"
diff --git a/packages/nextjs/src/pages/client.ts b/packages/nextjs/src/pages/client.ts
index ee6b68704..7fb58252d 100644
--- a/packages/nextjs/src/pages/client.ts
+++ b/packages/nextjs/src/pages/client.ts
@@ -9,6 +9,7 @@ export const clientSideFrontendClient = new FrontendApi(
headers: {
Accept: "application/json",
},
+ credentials: "include",
basePath: guessPotentiallyProxiedOrySdkUrl(),
}),
)