@atlasauth/nextjs 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/matcher.d.ts +15 -0
- package/dist/matcher.js +24 -0
- package/dist/matcher.js.map +1 -1
- package/dist/server.d.ts +80 -0
- package/dist/server.js +216 -0
- package/dist/server.js.map +1 -0
- package/package.json +23 -3
package/dist/matcher.d.ts
CHANGED
|
@@ -21,6 +21,21 @@
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function matchesPattern(pathname: string, pattern: string): boolean;
|
|
23
23
|
export declare function matchesAny(pathname: string, patterns: readonly string[]): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* §10.1 Clerk-parity `createRouteMatcher(patterns)` — the idiom integrators write
|
|
26
|
+
* at the top of `middleware.ts` (`const isProtected = createRouteMatcher(['/dashboard(.*)'])`).
|
|
27
|
+
* Returns a predicate over anything carrying a pathname: a Next `NextRequest`
|
|
28
|
+
* (`req.nextUrl.pathname`), a plain `{ nextUrl }` / `{ url }`, or a bare path
|
|
29
|
+
* string. Uses the SAME `(.*)`-only pattern engine as the middleware, so a
|
|
30
|
+
* matcher written here and the middleware's own routing agree exactly (no second
|
|
31
|
+
* dialect, no customer regex in the auth path).
|
|
32
|
+
*/
|
|
33
|
+
export declare function createRouteMatcher(patterns: readonly string[]): (input: string | {
|
|
34
|
+
nextUrl?: {
|
|
35
|
+
pathname?: string;
|
|
36
|
+
};
|
|
37
|
+
url?: string;
|
|
38
|
+
}) => boolean;
|
|
24
39
|
export declare function isStaticAsset(pathname: string): boolean;
|
|
25
40
|
export interface MiddlewareConfig {
|
|
26
41
|
/** Routes reachable without a session. Everything else requires one. */
|
package/dist/matcher.js
CHANGED
|
@@ -16,6 +16,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
16
16
|
exports.DEFAULT_SIGN_IN_URL = void 0;
|
|
17
17
|
exports.matchesPattern = matchesPattern;
|
|
18
18
|
exports.matchesAny = matchesAny;
|
|
19
|
+
exports.createRouteMatcher = createRouteMatcher;
|
|
19
20
|
exports.isStaticAsset = isStaticAsset;
|
|
20
21
|
exports.decideRoute = decideRoute;
|
|
21
22
|
exports.safeRedirect = safeRedirect;
|
|
@@ -40,6 +41,29 @@ function matchesPattern(pathname, pattern) {
|
|
|
40
41
|
function matchesAny(pathname, patterns) {
|
|
41
42
|
return patterns.some((pattern) => matchesPattern(pathname, pattern));
|
|
42
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* §10.1 Clerk-parity `createRouteMatcher(patterns)` — the idiom integrators write
|
|
46
|
+
* at the top of `middleware.ts` (`const isProtected = createRouteMatcher(['/dashboard(.*)'])`).
|
|
47
|
+
* Returns a predicate over anything carrying a pathname: a Next `NextRequest`
|
|
48
|
+
* (`req.nextUrl.pathname`), a plain `{ nextUrl }` / `{ url }`, or a bare path
|
|
49
|
+
* string. Uses the SAME `(.*)`-only pattern engine as the middleware, so a
|
|
50
|
+
* matcher written here and the middleware's own routing agree exactly (no second
|
|
51
|
+
* dialect, no customer regex in the auth path).
|
|
52
|
+
*/
|
|
53
|
+
function createRouteMatcher(patterns) {
|
|
54
|
+
return (input) => {
|
|
55
|
+
let pathname;
|
|
56
|
+
if (typeof input === 'string') {
|
|
57
|
+
// Accept a full URL or a bare path.
|
|
58
|
+
pathname = input.startsWith('http') ? new URL(input).pathname : input;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
pathname =
|
|
62
|
+
input.nextUrl?.pathname ?? (input.url ? new URL(input.url, 'http://x').pathname : '');
|
|
63
|
+
}
|
|
64
|
+
return matchesAny(pathname, patterns);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
43
67
|
/**
|
|
44
68
|
* Paths that are never auth decisions.
|
|
45
69
|
*
|
package/dist/matcher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matcher.js","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AAUH,wCASC;AAED,gCAEC;AAWD,sCAKC;AA4BD,kCA4BC;AASD,oCAiBC;
|
|
1
|
+
{"version":3,"file":"matcher.js","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@atlasauth/nextjs/server` — the pre-bound, zero-argument App-Router helpers.
|
|
3
|
+
*
|
|
4
|
+
* §Q7 gap: the base entry ships FACTORIES (`createAuthHelper`,
|
|
5
|
+
* `createCurrentUserHelper`) that the integrator wires once and then feeds an
|
|
6
|
+
* `EdgeRequest` on every call. Clerk instead ships `auth()` / `currentUser()`
|
|
7
|
+
* that read the ambient request from `next/headers` with no argument and read
|
|
8
|
+
* their config from the environment. This subpath adds exactly that ergonomic
|
|
9
|
+
* ON TOP of the existing core — it reuses `resolveAuth` + `AtlasBackend` through
|
|
10
|
+
* the very same factories, so JWT verification is defined in exactly one place.
|
|
11
|
+
*
|
|
12
|
+
* It lives in its own entry precisely because it imports `next/headers`: keeping
|
|
13
|
+
* it out of `index.ts` means `@atlasauth/nextjs` (middleware + matcher) still
|
|
14
|
+
* builds and runs with no `next` installed. `next` is only an OPTIONAL peer.
|
|
15
|
+
*/
|
|
16
|
+
import { type AtlasClient, type AtlasClientConfig } from '@atlasauth/backend';
|
|
17
|
+
import { createAuthHelper, type AtlasMiddlewareOptions, type CurrentUser, type EdgeRequest } from './middleware';
|
|
18
|
+
type Env = Record<string, string | undefined>;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the edge-verification config from the environment, mirroring how Clerk
|
|
21
|
+
* reads `CLERK_*` / `NEXT_PUBLIC_CLERK_*`. Server-only names win over their
|
|
22
|
+
* `NEXT_PUBLIC_` fallbacks. Throws with an actionable message when a required
|
|
23
|
+
* value is absent, because a silently-misconfigured verifier fails every request
|
|
24
|
+
* anyway — better a clear error at the first call than a mystery sign-out loop.
|
|
25
|
+
*/
|
|
26
|
+
export declare function configFromEnv(env?: Env): AtlasMiddlewareOptions;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the Backend-API (secret-key) config from the environment, for
|
|
29
|
+
* {@link atlasClient}. The secret key is server-only by definition — there is no
|
|
30
|
+
* `NEXT_PUBLIC_` fallback for it, and there must never be one.
|
|
31
|
+
*/
|
|
32
|
+
export declare function backendConfigFromEnv(env?: Env): AtlasClientConfig;
|
|
33
|
+
/**
|
|
34
|
+
* `clerkClient()`-equivalent: a configured `@atlasauth/backend` management client
|
|
35
|
+
* built from `ATLAS_SECRET_KEY` (+ optional `ATLAS_API_URL`). Overrides win over
|
|
36
|
+
* the environment, for tests and multi-instance setups.
|
|
37
|
+
*/
|
|
38
|
+
export declare function atlasClient(overrides?: Partial<AtlasClientConfig>): AtlasClient;
|
|
39
|
+
/** The subset of Next's cookie store {@link buildEdgeRequest} reads. */
|
|
40
|
+
export interface CookieStoreLike {
|
|
41
|
+
getAll(): ReadonlyArray<{
|
|
42
|
+
name: string;
|
|
43
|
+
value: string;
|
|
44
|
+
}>;
|
|
45
|
+
get?(name: string): {
|
|
46
|
+
value: string;
|
|
47
|
+
} | undefined;
|
|
48
|
+
}
|
|
49
|
+
/** The subset of Next's header store {@link buildEdgeRequest} reads. */
|
|
50
|
+
export interface HeaderStoreLike {
|
|
51
|
+
get(name: string): string | null | undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build an `EdgeRequest`-shaped object from a cookie store + a header store, the
|
|
55
|
+
* bridge between `next/headers` and the existing `resolveAuth` core. Pure and
|
|
56
|
+
* injectable: the ambient `auth()` feeds it the real Next stores, and tests feed
|
|
57
|
+
* it fakes — no request context required. `resolveAuth` reads only the
|
|
58
|
+
* `authorization` and `cookie` headers, so those are what we synthesize; the
|
|
59
|
+
* cookie header is reconstructed from the cookie store (which reflects any
|
|
60
|
+
* in-request mutations), falling back to the raw `cookie` header.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildEdgeRequest(cookieStore: CookieStoreLike, headerStore: HeaderStoreLike): EdgeRequest;
|
|
63
|
+
/** What the pre-bound `auth()` resolves to — the same state + `has`/`protect` the
|
|
64
|
+
* factory helper returns. */
|
|
65
|
+
export type ServerAuth = Awaited<ReturnType<ReturnType<typeof createAuthHelper>>>;
|
|
66
|
+
/**
|
|
67
|
+
* Clerk-parity `auth()` — no arguments. Reads cookies/headers from the ambient
|
|
68
|
+
* `next/headers` request, verifies the session at the edge via the shared core,
|
|
69
|
+
* and returns the same `AuthState & { has, protect }`. Config comes from the
|
|
70
|
+
* environment (see {@link configFromEnv}). Signed-out is a plain state, not a
|
|
71
|
+
* throw — call `.protect()` where anonymous access is a bug.
|
|
72
|
+
*/
|
|
73
|
+
export declare function auth(): Promise<ServerAuth>;
|
|
74
|
+
/**
|
|
75
|
+
* Clerk-parity `currentUser()` — no arguments. The signed-in user's profile from
|
|
76
|
+
* the verified session claims (no round-trip), or `null` when signed out.
|
|
77
|
+
*/
|
|
78
|
+
export declare function currentUser(): Promise<CurrentUser | null>;
|
|
79
|
+
export type { AtlasClient, AtlasClientConfig } from '@atlasauth/backend';
|
|
80
|
+
export type { AuthState, CurrentUser, EdgeRequest } from './middleware';
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.configFromEnv = configFromEnv;
|
|
37
|
+
exports.backendConfigFromEnv = backendConfigFromEnv;
|
|
38
|
+
exports.atlasClient = atlasClient;
|
|
39
|
+
exports.buildEdgeRequest = buildEdgeRequest;
|
|
40
|
+
exports.auth = auth;
|
|
41
|
+
exports.currentUser = currentUser;
|
|
42
|
+
/**
|
|
43
|
+
* `@atlasauth/nextjs/server` — the pre-bound, zero-argument App-Router helpers.
|
|
44
|
+
*
|
|
45
|
+
* §Q7 gap: the base entry ships FACTORIES (`createAuthHelper`,
|
|
46
|
+
* `createCurrentUserHelper`) that the integrator wires once and then feeds an
|
|
47
|
+
* `EdgeRequest` on every call. Clerk instead ships `auth()` / `currentUser()`
|
|
48
|
+
* that read the ambient request from `next/headers` with no argument and read
|
|
49
|
+
* their config from the environment. This subpath adds exactly that ergonomic
|
|
50
|
+
* ON TOP of the existing core — it reuses `resolveAuth` + `AtlasBackend` through
|
|
51
|
+
* the very same factories, so JWT verification is defined in exactly one place.
|
|
52
|
+
*
|
|
53
|
+
* It lives in its own entry precisely because it imports `next/headers`: keeping
|
|
54
|
+
* it out of `index.ts` means `@atlasauth/nextjs` (middleware + matcher) still
|
|
55
|
+
* builds and runs with no `next` installed. `next` is only an OPTIONAL peer.
|
|
56
|
+
*/
|
|
57
|
+
const backend_1 = require("@atlasauth/backend");
|
|
58
|
+
const middleware_1 = require("./middleware");
|
|
59
|
+
/** Read `process.env` without requiring `process` to be typed (no @types/node). */
|
|
60
|
+
function readEnv() {
|
|
61
|
+
return globalThis.process?.env ?? {};
|
|
62
|
+
}
|
|
63
|
+
/** First non-empty env var among `names`. */
|
|
64
|
+
function pick(env, ...names) {
|
|
65
|
+
for (const name of names) {
|
|
66
|
+
const value = env[name];
|
|
67
|
+
if (value !== undefined && value !== '')
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the edge-verification config from the environment, mirroring how Clerk
|
|
74
|
+
* reads `CLERK_*` / `NEXT_PUBLIC_CLERK_*`. Server-only names win over their
|
|
75
|
+
* `NEXT_PUBLIC_` fallbacks. Throws with an actionable message when a required
|
|
76
|
+
* value is absent, because a silently-misconfigured verifier fails every request
|
|
77
|
+
* anyway — better a clear error at the first call than a mystery sign-out loop.
|
|
78
|
+
*/
|
|
79
|
+
function configFromEnv(env = readEnv()) {
|
|
80
|
+
const jwksUrl = pick(env, 'ATLAS_JWKS_URL', 'NEXT_PUBLIC_ATLAS_JWKS_URL');
|
|
81
|
+
const issuer = pick(env, 'ATLAS_ISSUER', 'NEXT_PUBLIC_ATLAS_ISSUER');
|
|
82
|
+
if (!jwksUrl) {
|
|
83
|
+
throw new Error('@atlasauth/nextjs/server: missing ATLAS_JWKS_URL (or NEXT_PUBLIC_ATLAS_JWKS_URL).');
|
|
84
|
+
}
|
|
85
|
+
if (!issuer) {
|
|
86
|
+
throw new Error('@atlasauth/nextjs/server: missing ATLAS_ISSUER (or NEXT_PUBLIC_ATLAS_ISSUER).');
|
|
87
|
+
}
|
|
88
|
+
const authorizedPartiesRaw = pick(env, 'ATLAS_AUTHORIZED_PARTIES', 'NEXT_PUBLIC_ATLAS_AUTHORIZED_PARTIES');
|
|
89
|
+
const authorizedParties = authorizedPartiesRaw
|
|
90
|
+
? authorizedPartiesRaw
|
|
91
|
+
.split(',')
|
|
92
|
+
.map((part) => part.trim())
|
|
93
|
+
.filter(Boolean)
|
|
94
|
+
: undefined;
|
|
95
|
+
const publishableKey = pick(env, 'ATLAS_PUBLISHABLE_KEY', 'NEXT_PUBLIC_ATLAS_PUBLISHABLE_KEY');
|
|
96
|
+
return { jwksUrl, issuer, authorizedParties, publishableKey };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Resolve the Backend-API (secret-key) config from the environment, for
|
|
100
|
+
* {@link atlasClient}. The secret key is server-only by definition — there is no
|
|
101
|
+
* `NEXT_PUBLIC_` fallback for it, and there must never be one.
|
|
102
|
+
*/
|
|
103
|
+
function backendConfigFromEnv(env = readEnv()) {
|
|
104
|
+
const secretKey = pick(env, 'ATLAS_SECRET_KEY');
|
|
105
|
+
if (!secretKey) {
|
|
106
|
+
throw new Error('@atlasauth/nextjs/server: missing ATLAS_SECRET_KEY.');
|
|
107
|
+
}
|
|
108
|
+
const apiUrl = pick(env, 'ATLAS_API_URL', 'NEXT_PUBLIC_ATLAS_API_URL');
|
|
109
|
+
return { secretKey, apiUrl };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* `clerkClient()`-equivalent: a configured `@atlasauth/backend` management client
|
|
113
|
+
* built from `ATLAS_SECRET_KEY` (+ optional `ATLAS_API_URL`). Overrides win over
|
|
114
|
+
* the environment, for tests and multi-instance setups.
|
|
115
|
+
*/
|
|
116
|
+
function atlasClient(overrides = {}) {
|
|
117
|
+
const env = readEnv();
|
|
118
|
+
// Resolve from the environment leniently so an explicit override can supply
|
|
119
|
+
// the secret key on its own; `createAtlasClient` still throws if none is found
|
|
120
|
+
// from either source.
|
|
121
|
+
return (0, backend_1.createAtlasClient)({
|
|
122
|
+
secretKey: overrides.secretKey ?? pick(env, 'ATLAS_SECRET_KEY') ?? '',
|
|
123
|
+
apiUrl: overrides.apiUrl ?? pick(env, 'ATLAS_API_URL', 'NEXT_PUBLIC_ATLAS_API_URL'),
|
|
124
|
+
fetch: overrides.fetch,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Build an `EdgeRequest`-shaped object from a cookie store + a header store, the
|
|
129
|
+
* bridge between `next/headers` and the existing `resolveAuth` core. Pure and
|
|
130
|
+
* injectable: the ambient `auth()` feeds it the real Next stores, and tests feed
|
|
131
|
+
* it fakes — no request context required. `resolveAuth` reads only the
|
|
132
|
+
* `authorization` and `cookie` headers, so those are what we synthesize; the
|
|
133
|
+
* cookie header is reconstructed from the cookie store (which reflects any
|
|
134
|
+
* in-request mutations), falling back to the raw `cookie` header.
|
|
135
|
+
*/
|
|
136
|
+
function buildEdgeRequest(cookieStore, headerStore) {
|
|
137
|
+
const reconstructed = cookieStore
|
|
138
|
+
.getAll()
|
|
139
|
+
.map(({ name, value }) => `${name}=${value}`)
|
|
140
|
+
.join('; ');
|
|
141
|
+
const cookieHeader = reconstructed.length > 0 ? reconstructed : (headerStore.get('cookie') ?? null);
|
|
142
|
+
const authorization = headerStore.get('authorization') ?? null;
|
|
143
|
+
return {
|
|
144
|
+
nextUrl: { pathname: '' },
|
|
145
|
+
headers: {
|
|
146
|
+
get(name) {
|
|
147
|
+
const key = name.toLowerCase();
|
|
148
|
+
if (key === 'cookie')
|
|
149
|
+
return cookieHeader;
|
|
150
|
+
if (key === 'authorization')
|
|
151
|
+
return authorization;
|
|
152
|
+
return headerStore.get(name) ?? null;
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Read the ambient request from `next/headers` and shape it for the core.
|
|
159
|
+
* Imported dynamically so merely importing this module never touches
|
|
160
|
+
* `next/headers` (which throws outside a request scope) — the module loads only
|
|
161
|
+
* when `auth()`/`currentUser()` actually run inside a server component, route
|
|
162
|
+
* handler, or Server Action.
|
|
163
|
+
*/
|
|
164
|
+
async function edgeRequestFromContext() {
|
|
165
|
+
const { cookies, headers } = await Promise.resolve().then(() => __importStar(require('next/headers')));
|
|
166
|
+
const cookieStore = await cookies();
|
|
167
|
+
const headerStore = await headers();
|
|
168
|
+
return buildEdgeRequest(cookieStore, headerStore);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Memoize the factory-built helpers by their resolved config so the in-process
|
|
172
|
+
* JWKS cache inside `AtlasBackend` stays warm across calls — rebuilding a fresh
|
|
173
|
+
* backend per `auth()` would throw that cache away and re-fetch the JWKS on
|
|
174
|
+
* every render, defeating the whole point of edge-local verification.
|
|
175
|
+
*/
|
|
176
|
+
function cacheKey(options) {
|
|
177
|
+
return [options.jwksUrl, options.issuer, (options.authorizedParties ?? []).join(',')].join('\n');
|
|
178
|
+
}
|
|
179
|
+
let authHelperCache;
|
|
180
|
+
function getAuthHelper() {
|
|
181
|
+
const options = configFromEnv();
|
|
182
|
+
const key = cacheKey(options);
|
|
183
|
+
if (!authHelperCache || authHelperCache.key !== key) {
|
|
184
|
+
authHelperCache = { key, fn: (0, middleware_1.createAuthHelper)(options) };
|
|
185
|
+
}
|
|
186
|
+
return authHelperCache.fn;
|
|
187
|
+
}
|
|
188
|
+
let currentUserHelperCache;
|
|
189
|
+
function getCurrentUserHelper() {
|
|
190
|
+
const options = configFromEnv();
|
|
191
|
+
const key = cacheKey(options);
|
|
192
|
+
if (!currentUserHelperCache || currentUserHelperCache.key !== key) {
|
|
193
|
+
currentUserHelperCache = { key, fn: (0, middleware_1.createCurrentUserHelper)(options) };
|
|
194
|
+
}
|
|
195
|
+
return currentUserHelperCache.fn;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Clerk-parity `auth()` — no arguments. Reads cookies/headers from the ambient
|
|
199
|
+
* `next/headers` request, verifies the session at the edge via the shared core,
|
|
200
|
+
* and returns the same `AuthState & { has, protect }`. Config comes from the
|
|
201
|
+
* environment (see {@link configFromEnv}). Signed-out is a plain state, not a
|
|
202
|
+
* throw — call `.protect()` where anonymous access is a bug.
|
|
203
|
+
*/
|
|
204
|
+
async function auth() {
|
|
205
|
+
const helper = getAuthHelper();
|
|
206
|
+
return helper(await edgeRequestFromContext());
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Clerk-parity `currentUser()` — no arguments. The signed-in user's profile from
|
|
210
|
+
* the verified session claims (no round-trip), or `null` when signed out.
|
|
211
|
+
*/
|
|
212
|
+
async function currentUser() {
|
|
213
|
+
const helper = getCurrentUserHelper();
|
|
214
|
+
return helper(await edgeRequestFromContext());
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/nextjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./server": {
|
|
12
|
+
"types": "./dist/server.d.ts",
|
|
13
|
+
"default": "./dist/server.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
6
17
|
"dependencies": {
|
|
7
|
-
"@atlasauth/backend": "0.1.
|
|
18
|
+
"@atlasauth/backend": "0.1.2"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"next": ">=13.4"
|
|
22
|
+
},
|
|
23
|
+
"peerDependenciesMeta": {
|
|
24
|
+
"next": {
|
|
25
|
+
"optional": true
|
|
26
|
+
}
|
|
8
27
|
},
|
|
9
28
|
"devDependencies": {
|
|
10
29
|
"typescript": "^5.6.3",
|
|
11
30
|
"vitest": "^2.1.4",
|
|
12
|
-
"jose": "^5.9.6"
|
|
31
|
+
"jose": "^5.9.6",
|
|
32
|
+
"next": "^15.0.0"
|
|
13
33
|
},
|
|
14
34
|
"publishConfig": {
|
|
15
35
|
"access": "public"
|