@iglo.tech/iglo.base 0.0.0-stage → 1.0.1-rc.0

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +18 -0
  3. package/README.md +778 -2
  4. package/dist/iglo-base.es.mjs +4 -0
  5. package/dist/iglo-base.es.mjs.map +34 -0
  6. package/dist/ssr-astro.es.mjs +4 -0
  7. package/dist/ssr-astro.es.mjs.map +12 -0
  8. package/dist/ssr-browser-client.es.mjs +4 -0
  9. package/dist/ssr-browser-client.es.mjs.map +13 -0
  10. package/dist/ssr-browser.es.mjs +4 -0
  11. package/dist/ssr-browser.es.mjs.map +10 -0
  12. package/dist/ssr-next.es.mjs +4 -0
  13. package/dist/ssr-next.es.mjs.map +12 -0
  14. package/dist/ssr-nuxt.es.mjs +4 -0
  15. package/dist/ssr-nuxt.es.mjs.map +12 -0
  16. package/dist/ssr-react-router.es.mjs +4 -0
  17. package/dist/ssr-react-router.es.mjs.map +12 -0
  18. package/dist/ssr-sveltekit.es.mjs +4 -0
  19. package/dist/ssr-sveltekit.es.mjs.map +12 -0
  20. package/dist/ssr.es.mjs +4 -0
  21. package/dist/ssr.es.mjs.map +22 -0
  22. package/dist/types/src/Client.d.ts +233 -0
  23. package/dist/types/src/ClientResponseError.d.ts +22 -0
  24. package/dist/types/src/index.d.ts +18 -0
  25. package/dist/types/src/services/BackupService.d.ts +59 -0
  26. package/dist/types/src/services/BaseService.d.ts +8 -0
  27. package/dist/types/src/services/BatchService.d.ts +56 -0
  28. package/dist/types/src/services/CollectionService.d.ts +47 -0
  29. package/dist/types/src/services/CronService.d.ts +20 -0
  30. package/dist/types/src/services/CrudService.d.ts +85 -0
  31. package/dist/types/src/services/FileService.d.ts +19 -0
  32. package/dist/types/src/services/HealthService.d.ts +16 -0
  33. package/dist/types/src/services/LogService.d.ts +35 -0
  34. package/dist/types/src/services/RealtimeService.d.ts +124 -0
  35. package/dist/types/src/services/RecordService.d.ts +374 -0
  36. package/dist/types/src/services/SQLService.d.ts +21 -0
  37. package/dist/types/src/services/SettingsService.d.ts +46 -0
  38. package/dist/types/src/ssr/adapter.d.ts +133 -0
  39. package/dist/types/src/ssr/astro.d.ts +27 -0
  40. package/dist/types/src/ssr/browser-client.d.ts +100 -0
  41. package/dist/types/src/ssr/browser-token.d.ts +29 -0
  42. package/dist/types/src/ssr/browser.d.ts +1 -0
  43. package/dist/types/src/ssr/cache.d.ts +9 -0
  44. package/dist/types/src/ssr/cookies.d.ts +68 -0
  45. package/dist/types/src/ssr/csrf.d.ts +38 -0
  46. package/dist/types/src/ssr/index.d.ts +12 -0
  47. package/dist/types/src/ssr/next.d.ts +53 -0
  48. package/dist/types/src/ssr/no-store-fetch.d.ts +7 -0
  49. package/dist/types/src/ssr/nuxt.d.ts +41 -0
  50. package/dist/types/src/ssr/oauth2.d.ts +56 -0
  51. package/dist/types/src/ssr/popup.d.ts +14 -0
  52. package/dist/types/src/ssr/react-router.d.ts +53 -0
  53. package/dist/types/src/ssr/renew.d.ts +25 -0
  54. package/dist/types/src/ssr/server-client.d.ts +83 -0
  55. package/dist/types/src/ssr/superuser-client.d.ts +24 -0
  56. package/dist/types/src/ssr/sveltekit.d.ts +44 -0
  57. package/dist/types/src/ssr/types.d.ts +118 -0
  58. package/dist/types/src/stores/AsyncAuthStore.d.ts +52 -0
  59. package/dist/types/src/stores/BaseAuthStore.d.ts +104 -0
  60. package/dist/types/src/stores/LocalAuthStore.d.ts +48 -0
  61. package/dist/types/src/tools/cookie.d.ts +31 -0
  62. package/dist/types/src/tools/dtos.d.ts +122 -0
  63. package/dist/types/src/tools/formdata.d.ts +30 -0
  64. package/dist/types/src/tools/jwt.d.ts +14 -0
  65. package/dist/types/src/tools/legacy.d.ts +2 -0
  66. package/dist/types/src/tools/loose.d.ts +5 -0
  67. package/dist/types/src/tools/options.d.ts +91 -0
  68. package/dist/types/src/tools/refresh.d.ts +3 -0
  69. package/package.json +73 -4
@@ -0,0 +1,133 @@
1
+ import type { SerializeOptions } from "../tools/cookie.js";
2
+ import { type BrowserToken, type CookieAdapter, type CreateServerClientOptions, type ServerClient, type SessionCache, type SuperuserClient } from "./index.js";
3
+ /** The paths the adapter answers. A route set to `false` is not mounted. */
4
+ export interface AdapterRoutes {
5
+ /** `POST`: renews the browser token (`handleBrowserTokenRenew`). */
6
+ renew: string | false;
7
+ /** `POST` with the JSON body `{ "token": ... }`: completes a popup sign-in (`handlePopupHandOff`). */
8
+ popup: string | false;
9
+ /** `GET {oauth2Start}/{provider}`: starts the OAuth2 redirect flow (`startOAuth2`). */
10
+ oauth2Start: string | false;
11
+ /** `GET`: the provider's callback, which completes the flow (`completeOAuth2`). */
12
+ oauth2Callback: string | false;
13
+ }
14
+ export declare const DEFAULT_ROUTES: Readonly<AdapterRoutes>;
15
+ /** The options every adapter takes. The app creates `sessionCache` and `superuser` once. */
16
+ export interface AdapterOptions {
17
+ /** iglo.base's URL as the app server reaches it. */
18
+ url: string;
19
+ /** The session cache, created by the app (`createSessionCache`) and shared by its requests. */
20
+ sessionCache: SessionCache;
21
+ /** Mints browser tokens with `impersonate`. Without it, `readableCookie` must be true. */
22
+ superuser?: SuperuserClient;
23
+ /**
24
+ * The app's public origin, such as `https://app.example.com`. It sets the cookie security and
25
+ * the OAuth2 callback URL. Default: the origin of each request.
26
+ */
27
+ origin?: string;
28
+ /** Overrides the cookie's security (`Secure` and the `__Host-` prefix). */
29
+ secure?: boolean;
30
+ /** The session cookie's base name (default `pb_auth`). */
31
+ cookieName?: string;
32
+ cookieOptions?: Partial<SerializeOptions>;
33
+ /** The fallback without superuser credentials: the session cookie is readable by page scripts. */
34
+ readableCookie?: boolean;
35
+ /**
36
+ * The CSRF guard on state-changing requests that carry the session cookie. `false` turns it
37
+ * off; `allowedOrigins` lists the other origins that may send them.
38
+ */
39
+ csrf?: false | {
40
+ allowedOrigins?: readonly string[];
41
+ };
42
+ /** Lifetime of minted browser tokens in seconds (default 900). */
43
+ browserTokenDuration?: number;
44
+ routes?: Partial<AdapterRoutes>;
45
+ lang?: string;
46
+ clock?: () => number;
47
+ fetch?: CreateServerClientOptions["fetch"];
48
+ }
49
+ export interface ResolvedAdapterOptions extends AdapterOptions {
50
+ routes: AdapterRoutes;
51
+ }
52
+ /**
53
+ * Checks the configuration once, when the app creates its adapter. Without superuser
54
+ * credentials the adapter can only serve pages in fallback mode, so it must say so here.
55
+ *
56
+ * @throws {TypeError} without a superuser client and without `readableCookie: true`
57
+ */
58
+ export declare function resolveAdapterOptions(options: AdapterOptions): ResolvedAdapterOptions;
59
+ /** The app's public origin: the option, or the origin of the request. */
60
+ export declare function appOrigin(request: Request, options: ResolvedAdapterOptions): string;
61
+ /** The session of one request, resumed from its cookies. */
62
+ export interface RequestSession {
63
+ /** The server client for this request only. Never shared across requests. */
64
+ server: ServerClient;
65
+ /**
66
+ * Mints the page's browser token for the signed-in user (`null` when nobody is signed in). A token
67
+ * that is minted marks the request's responses as user data (see `NoStorePolicy`).
68
+ */
69
+ browserToken: () => Promise<BrowserToken | null>;
70
+ }
71
+ /**
72
+ * Whether a request's responses carry user data, and so must not be stored by a cache. The policy
73
+ * is on when the request carries a session cookie (under either name, as `checkCsrf` counts them),
74
+ * and turns on the first time the request writes a cookie or mints a browser token. Every response
75
+ * of an active request gets `SSR_NO_CACHE_HEADERS` (docs/design/13-ssr.md, "Session cookie").
76
+ * Anonymous requests that write nothing keep their responses cacheable.
77
+ */
78
+ export interface NoStorePolicy {
79
+ /** Whether the responses of this request carry the no-cache headers. */
80
+ readonly active: boolean;
81
+ /** A cookie was written or a browser token minted: from now on the responses are user data. */
82
+ markUserData(): void;
83
+ /**
84
+ * The response to send: when the policy is active, it carries the no-cache headers. A response
85
+ * with immutable headers comes back as a copy (see `withMutableHeaders`), so the app sends the
86
+ * returned response.
87
+ */
88
+ apply(response: Response): Response;
89
+ }
90
+ /**
91
+ * The policy of one request. `onActive` runs once, when the policy turns on: at once when the
92
+ * request carries a session cookie, otherwise at the first write or mint. For a framework that
93
+ * sets headers before the handler's response is sent (Nitro) it sets them as they become needed.
94
+ */
95
+ export declare function noStorePolicy(request: Request, options: ResolvedAdapterOptions, onActive?: () => void): NoStorePolicy;
96
+ /**
97
+ * Sets SSR_NO_CACHE_HEADERS, replacing any the app set: a user's response must not be stored with
98
+ * a public `Cache-Control`. The headers must be mutable: see `withMutableHeaders`.
99
+ */
100
+ export declare function setNoStoreHeaders(headers: Headers): void;
101
+ /**
102
+ * The response with headers that can be changed. In Node, the runtime the SSR apps run on, the
103
+ * headers of a `fetch()` response and of `Response.redirect()` are immutable, and so the no-cache
104
+ * headers could not be set on them. Such a response (an endpoint that returns a fetched response
105
+ * unchanged, say) is rebuilt with a copy of its headers, body and status. The copy does not keep
106
+ * `url` or `redirected`, which are read-only. Callers send the response this returns.
107
+ *
108
+ * A network error (`Response.error()`, status 0) cannot be copied: `new Response` rejects status 0.
109
+ * It is returned as it is, and so are its headers.
110
+ */
111
+ export declare function withMutableHeaders(response: Response): Response;
112
+ /**
113
+ * Resumes the session of one request with `createServerClient`. `cookies` is the framework's
114
+ * cookie access, mapped to `{ getAll, setAll, isSecure }`: writes made by the session check
115
+ * (a refresh, a revoked session) go through its `setAll`. Each write and each minted browser token
116
+ * turns `policy` on, so the adapter sets the no-cache headers on the response it returns.
117
+ */
118
+ export declare function resumeSession(cookies: CookieAdapter, request: Request, options: ResolvedAdapterOptions, policy?: NoStorePolicy): Promise<RequestSession>;
119
+ /**
120
+ * The CSRF guard for a request, before the app's handler runs: `undefined` lets it through, and
121
+ * a response is the ready 403. It only looks at requests that carry the session cookie, so
122
+ * the guard never rejects a sign-in form or a public page (see `checkCsrf`).
123
+ */
124
+ export declare function csrfRejection(request: Request, options: ResolvedAdapterOptions): Response | undefined;
125
+ /** A `302` to `location` that carries the cookies and headers queued by `cookies`. */
126
+ export declare function redirectWithCookies(location: string, cookies: {
127
+ applyToResponse(r: Response): Response;
128
+ }): Response;
129
+ /**
130
+ * The adapter's routes. Returns the route's response, or `undefined` when the request is not for
131
+ * one of them (the app then handles it). The renew and popup routes run their own origin checks.
132
+ */
133
+ export declare function handleRoute(request: Request, options: ResolvedAdapterOptions): Promise<Response | undefined>;
@@ -0,0 +1,27 @@
1
+ import { type AdapterOptions } from "./adapter.js";
2
+ export interface AstroCookieStore {
3
+ get(name: string): {
4
+ value: string;
5
+ } | undefined;
6
+ set(name: string, value: string, options?: Record<string, unknown>): void;
7
+ delete(name: string, options?: Record<string, unknown>): void;
8
+ }
9
+ export interface AstroContext {
10
+ request: Request;
11
+ url: URL;
12
+ cookies: AstroCookieStore;
13
+ locals: object;
14
+ }
15
+ export interface AstroAuth {
16
+ /**
17
+ * An Astro middleware (`export const onRequest = auth.onRequest`). Sets `context.locals.pb` and
18
+ * `context.locals.pbBrowserToken`, answers the adapter routes and the CSRF guard, else returns
19
+ * `next()`.
20
+ */
21
+ onRequest(context: AstroContext, next: () => Promise<Response>): Promise<Response>;
22
+ }
23
+ /**
24
+ * Creates the Astro auth. Throws a `TypeError` without a superuser client and without
25
+ * `readableCookie: true` (see `resolveAdapterOptions`).
26
+ */
27
+ export declare function createAstroAuth(options: AdapterOptions): AstroAuth;
@@ -0,0 +1,100 @@
1
+ import Client from "../Client.js";
2
+ import { type AuthRecord } from "../stores/BaseAuthStore.js";
3
+ import type { Loose } from "../tools/loose.js";
4
+ import type { SendOptions } from "../tools/options.js";
5
+ import type { FetchFunction } from "./no-store-fetch.js";
6
+ /** The timers the client uses. Injected by tests, which run without sleeping. */
7
+ export interface BrowserTimers {
8
+ setTimeout: (callback: () => void, ms: number) => unknown;
9
+ clearTimeout: (handle: unknown) => void;
10
+ }
11
+ export interface CreateBrowserClientOptions {
12
+ url: string;
13
+ /** The browser token from the page (`mintBrowserToken`). Without it, the readable cookie is read. */
14
+ token?: string;
15
+ /** The user record that goes with `token`. Dropped when its id is not the token's. */
16
+ record?: AuthRecord;
17
+ /**
18
+ * The server's clock when `token` was minted (`BrowserToken.serverTime`, in milliseconds). The
19
+ * client measures its own clock against it. Without it the offset is learned from the first
20
+ * renewal, so pass it whenever the page has it.
21
+ */
22
+ serverTime?: number;
23
+ /** The adapter route that renews the token (`handleBrowserTokenRenew`). Without it, no renewal. */
24
+ renewUrl?: string;
25
+ /** The adapter route that completes a popup sign-in (`handlePopupHandOff`). */
26
+ handOffUrl?: string;
27
+ /** The session cookie's base name, for reading the readable cookie (default `pb_auth`). */
28
+ cookieName?: string;
29
+ clock?: () => number;
30
+ timers?: BrowserTimers;
31
+ fetch?: FetchFunction;
32
+ lang?: string;
33
+ }
34
+ /**
35
+ * The SDK client for a page. It holds a short browser token, renews it before it expires,
36
+ * keeps its realtime subscriptions authorized as the signed-in user changes, and hands a popup
37
+ * token off to the server. Create it with `createBrowserClient`.
38
+ */
39
+ export declare class BrowserClient extends Client {
40
+ private readonly _options;
41
+ private readonly _clock;
42
+ private readonly _timers;
43
+ private _timer;
44
+ private _retries;
45
+ private _renewing;
46
+ private _disposed;
47
+ private _offsetMs;
48
+ private _lastRenewedAt;
49
+ private _realtimeIdentity;
50
+ constructor(options: CreateBrowserClientOptions);
51
+ /** Sends with the injected fetch (if any) unless the request names its own. */
52
+ send<T = Loose>(path: string, options: SendOptions): Promise<T>;
53
+ /**
54
+ * Renews the browser token now, through the renew route. Parallel callers, and the timers,
55
+ * share one request. A 401 clears the auth store. A network error or 5xx keeps the token and
56
+ * retries with a bounded backoff until it expires.
57
+ *
58
+ * @throws {ClientResponseError} when the request fails (status 0 for a network error), or
59
+ * when no `renewUrl` is set
60
+ */
61
+ renew(): Promise<void>;
62
+ /**
63
+ * After `authWithOAuth2()` in a popup: posts the popup's token to the hand-off route, which
64
+ * writes the HttpOnly session cookie, then renews the token. The long-lived popup token is
65
+ * replaced in page memory by the short minted one. On any failure the popup token is cleared
66
+ * from the store rather than kept.
67
+ *
68
+ * @throws {ClientResponseError} when the hand-off or the renewal is refused or fails
69
+ */
70
+ handOff(): Promise<void>;
71
+ /** Stops the renewal timers. The client keeps working; it just stops renewing. */
72
+ dispose(): void;
73
+ private _postHandOff;
74
+ private _fetch;
75
+ /** The current token's expiry in the server's clock, in milliseconds. */
76
+ private _expiresAt;
77
+ /** This device's clock, moved onto iglo.base's clock. */
78
+ private _serverNow;
79
+ private _authChanged;
80
+ private _schedule;
81
+ /**
82
+ * After a network error or a 5xx: retries with a bounded backoff. Once the retries are used up,
83
+ * or no further retry fits before the token ends, the store is cleared at the token's expiry.
84
+ */
85
+ private _retryLaterIfSame;
86
+ private _retryLater;
87
+ private _renewOnce;
88
+ /**
89
+ * Sets a timer. A delay above `setTimeout`'s maximum is waited for in steps: the timer is
90
+ * re-armed when it fires, so no delay is ever cut to 1 ms.
91
+ */
92
+ private _setTimer;
93
+ private _cancelTimer;
94
+ }
95
+ /**
96
+ * Creates the browser client for a page. Pass the token, its record and `serverTime` from
97
+ * `mintBrowserToken`, which the page gets at render, and the renew route's URL. Without a token,
98
+ * the readable session cookie (fallback mode) is read.
99
+ */
100
+ export declare function createBrowserClient(options: CreateBrowserClientOptions): BrowserClient;
@@ -0,0 +1,29 @@
1
+ import type { ServerClient } from "./server-client.js";
2
+ import type { SuperuserClient } from "./superuser-client.js";
3
+ import type { BrowserToken, MintBrowserTokenOptions } from "./types.js";
4
+ /** The lifetime of a browser token when the app does not set one (15 minutes). */
5
+ export declare const DEFAULT_BROWSER_TOKEN_DURATION_SEC = 900;
6
+ /**
7
+ * What a page needs for its browser client, for the user the server client resumed: a token
8
+ * from the superuser client's `impersonate` (a non-refreshable one, 15 minutes by default), the
9
+ * server's clock at minting (`serverTime`), and the server client's validated record. The session
10
+ * token never leaves the server.
11
+ *
12
+ * The result is per-user: the response that carries it must be `Cache-Control: no-store` and
13
+ * private (`SSR_NO_CACHE_HEADERS`, from `@iglo.tech/iglo.base/ssr`), or a shared cache can hand one user's
14
+ * token to another. The renew route already answers with those headers.
15
+ *
16
+ * Returns `null` when nobody is signed in. Without a superuser client, the server client must
17
+ * be in fallback mode (`readableCookie`): the page then gets the session token, which the session
18
+ * cookie already exposes to page JavaScript.
19
+ *
20
+ * Errors from `impersonate` reach the caller as `ClientResponseError`, with the server's status.
21
+ * They mean different things, and the caller decides what each means for the session
22
+ * (`handleBrowserTokenRenew` does): `404` means the user is gone, while `401` (the superuser token
23
+ * is missing, expired or revoked) and `403` (it is not a superuser's) mean the superuser
24
+ * credentials were refused, which says nothing about the user's session.
25
+ *
26
+ * @throws {TypeError} without a superuser client on a server client that is not in fallback mode
27
+ * @throws {ClientResponseError} when `impersonate` fails (see above)
28
+ */
29
+ export declare function mintBrowserToken(server: ServerClient, superuser: SuperuserClient | undefined, options?: MintBrowserTokenOptions): Promise<BrowserToken | null>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { SessionCache, SessionCacheOptions } from "./types.js";
2
+ export declare const DEFAULT_TTL_MS: number;
3
+ export declare const DEFAULT_MAX_ENTRIES = 10000;
4
+ export declare function hashToken(token: string): Promise<string>;
5
+ /**
6
+ * Creates the per-process session cache. Pass one instance to every `createServerClient`
7
+ * of the process; it is never a module global.
8
+ */
9
+ export declare function createSessionCache(options?: SessionCacheOptions): SessionCache;
@@ -0,0 +1,68 @@
1
+ import { type AuthRecord } from "../stores/BaseAuthStore.js";
2
+ import { type SerializeOptions } from "../tools/cookie.js";
3
+ import type { Cookie, CookieToSet, CookieValueMap, RequestCookieAdapter } from "./types.js";
4
+ export declare const SSR_NO_CACHE_HEADERS: Readonly<Record<string, string>>;
5
+ export declare const DEFAULT_COOKIE_KEY = "pb_auth";
6
+ /** The temporary cookie of the OAuth2 redirect flow (docs/design/13-ssr.md, "OAuth2"). */
7
+ export declare const OAUTH2_COOKIE_KEY = "pb_oauth2";
8
+ export declare const OAUTH2_COOKIE_MAX_AGE_SEC = 600;
9
+ export declare function isLocalhost(hostname: string): boolean;
10
+ export declare function isHttpLocalUrl(urlStr: string): boolean;
11
+ export declare function normalizeCookies(raw: Cookie[] | CookieValueMap | undefined | null): Cookie[];
12
+ /** The name a cookie is written under: `__Host-` prefixed on secure origins, plain otherwise. */
13
+ export declare function cookieWireName(baseName: string, secure: boolean): string;
14
+ /**
15
+ * The cookie the SDK reads, by the one name it is written under for `secure` (see
16
+ * `cookieWireName`). On a secure origin the plain name is never read: a sibling subdomain can set
17
+ * a cookie for the parent domain under any name, but only the host itself can set a `__Host-` one.
18
+ */
19
+ export declare function findCookie(cookies: Cookie[], baseName: string, secure: boolean): Cookie | undefined;
20
+ /**
21
+ * Whether a session cookie is present under either name. The CSRF guard does not know how the
22
+ * app named its cookie (`secure` may come from the app's settings), so both names count: the
23
+ * guard checks more requests, never fewer. Reading a value is still `findCookie`'s job.
24
+ */
25
+ export declare function hasSessionCookieName(cookies: Cookie[], baseName: string): boolean;
26
+ /**
27
+ * The record that belongs to a token, or null: a record for another user is dropped, since a
28
+ * cookie can be edited by its user. Shared by the server and the browser client.
29
+ */
30
+ export declare function recordForToken(token: string, record: AuthRecord): AuthRecord;
31
+ export declare function safeDecode(value: string): string;
32
+ /**
33
+ * Reads the token and user record from a session cookie value. Adapters may hand over
34
+ * the value decoded (the request adapter does) or as sent by the browser (Next.js does),
35
+ * so the raw text is tried first and the percent-decoded text second, each decoded once.
36
+ */
37
+ export declare function parseSessionValue(raw: string): {
38
+ token: string;
39
+ record: AuthRecord;
40
+ } | undefined;
41
+ export declare function formatSessionCookieValue(wireName: string, token: string, record: AuthRecord, options?: SerializeOptions): string;
42
+ export interface CookieSettings {
43
+ cookieName?: string;
44
+ secure?: boolean;
45
+ cookieOptions?: Partial<SerializeOptions>;
46
+ /** Fallback mode: the session cookie is written without `HttpOnly` (docs/design/13-ssr.md). */
47
+ readable?: boolean;
48
+ }
49
+ /** `cookieOptions.secure` overrides the flag; the default is secure (`__Host-`). */
50
+ export declare function isSecureSession(settings: CookieSettings): boolean;
51
+ export declare function buildSessionCookieToSet(token: string, record: AuthRecord, options: CookieSettings & {
52
+ nowSeconds?: number;
53
+ exp?: number;
54
+ }): CookieToSet;
55
+ /** Expiring cookies for a session end. */
56
+ export declare function buildClearedSessionCookies(settings: CookieSettings): CookieToSet[];
57
+ /**
58
+ * The temporary OAuth2 cookie: HttpOnly, `SameSite=Lax` (the provider's redirect is a top-level
59
+ * GET), `Path=/`, `Max-Age` 600 and the same `Secure`/`__Host-` rule as the session cookie.
60
+ * The app's `cookieOptions` are not applied (apart from `secure`), so an app cannot make the
61
+ * cookie unreachable from the provider's redirect.
62
+ */
63
+ export declare function buildOAuth2CookieToSet(value: string, settings: CookieSettings): CookieToSet;
64
+ /** Expiring cookies for the temporary OAuth2 cookie, written with the same name rule. */
65
+ export declare function buildClearedOAuth2Cookies(settings: CookieSettings): CookieToSet[];
66
+ export declare function createRequestCookieAdapter(request: Request, options?: {
67
+ secure?: boolean;
68
+ }): RequestCookieAdapter;
@@ -0,0 +1,38 @@
1
+ export interface CsrfOptions {
2
+ /**
3
+ * Origins besides the request's own that may send state-changing requests, for example
4
+ * `https://www.example.com` when the app is served under two origins. Each entry must be an
5
+ * origin: a scheme, a host and an optional port, with no path.
6
+ */
7
+ allowedOrigins?: readonly string[];
8
+ /** The session cookie's base name (default `pb_auth`). */
9
+ cookieName?: string;
10
+ }
11
+ export type OriginCheck = {
12
+ ok: true;
13
+ } | {
14
+ ok: false;
15
+ reason: "missing-origin" | "foreign-origin";
16
+ };
17
+ export type CsrfResult = {
18
+ ok: true;
19
+ } | {
20
+ ok: false;
21
+ reason: "missing-origin" | "foreign-origin";
22
+ response: Response;
23
+ };
24
+ /**
25
+ * Whether the request comes from its own origin or an allowed one. `Origin` decides; `Referer`
26
+ * is read only when `Origin` is absent. A request with neither, or with an `Origin` the browser
27
+ * sent as `null`, is rejected. The request's own origin comes from its URL: behind a proxy that
28
+ * changes the public origin, list the public origin in `allowedOrigins`.
29
+ */
30
+ export declare function checkOrigin(request: Request, allowedOrigins?: readonly string[]): OriginCheck;
31
+ /**
32
+ * The CSRF guard for an adapter's request handler, called before the handler runs. It rejects
33
+ * `POST`, `PUT`, `PATCH` and `DELETE` requests that carry the session cookie unless their origin
34
+ * passes `checkOrigin`. Requests without the session cookie (under either name), and `GET`, `HEAD`
35
+ * and `OPTIONS`, pass. A rejection carries a ready 403 `Response`. Frameworks with their own check
36
+ * (Next.js Server Actions) may skip this.
37
+ */
38
+ export declare function checkCsrf(request: Request, options?: CsrfOptions): CsrfResult;
@@ -0,0 +1,12 @@
1
+ export { ServerClient, createServerClient } from "./server-client.js";
2
+ export { SuperuserClient, createSuperuserClient } from "./superuser-client.js";
3
+ export { createSessionCache, DEFAULT_TTL_MS, DEFAULT_MAX_ENTRIES } from "./cache.js";
4
+ export { createRequestCookieAdapter, SSR_NO_CACHE_HEADERS, DEFAULT_COOKIE_KEY, } from "./cookies.js";
5
+ export { OAuth2Error, type OAuth2ErrorKind } from "./oauth2.js";
6
+ export { checkCsrf, checkOrigin } from "./csrf.js";
7
+ export { handlePopupHandOff } from "./popup.js";
8
+ export { mintBrowserToken, DEFAULT_BROWSER_TOKEN_DURATION_SEC } from "./browser-token.js";
9
+ export { handleBrowserTokenRenew, type BrowserTokenRenewOptions } from "./renew.js";
10
+ export type { Cookie, CookieToSet, CookieAdapter, SessionCache, SessionCacheEntry, SessionCacheOptions, CreateServerClientOptions, CreateSuperuserClientOptions, RequestCookieAdapter, StartOAuth2Options, CompleteOAuth2Result, BrowserToken, MintBrowserTokenOptions, } from "./types.js";
11
+ export type { CsrfOptions, CsrfResult, OriginCheck } from "./csrf.js";
12
+ export type { PopupHandOffOptions } from "./popup.js";
@@ -0,0 +1,53 @@
1
+ import { type AdapterOptions, type RequestSession } from "./adapter.js";
2
+ import type { SerializeOptions } from "../tools/cookie.js";
3
+ /**
4
+ * What `cookies()` from `next/headers` returns, typed structurally. Values are the raw text the
5
+ * browser sent. `set` is missing from the read-only store type, and it throws at runtime inside
6
+ * Server Components; the adapter swallows that and keeps the refreshed session in memory.
7
+ */
8
+ export interface NextCookieStore {
9
+ getAll(): Array<{
10
+ name: string;
11
+ value: string;
12
+ }>;
13
+ set?(name: string, value: string, options?: SerializeOptions): unknown;
14
+ }
15
+ export interface NextAuthOptions extends AdapterOptions {
16
+ /** NextResponse.next, supplied by the app: `next: (init) => NextResponse.next(init)`. The adapter cannot import next/server. */
17
+ next: (init: {
18
+ request: {
19
+ headers: Headers;
20
+ };
21
+ }) => Response;
22
+ }
23
+ export interface NextAuth {
24
+ /**
25
+ * middleware.ts: answers the CSRF guard and the adapter routes, and otherwise resumes the session.
26
+ * The pass-through response gets the cookies the session wrote, and the request it forwards gets
27
+ * the same cookies in its `Cookie` header, so Server Components read the refreshed session.
28
+ */
29
+ middleware(request: Request): Promise<Response>;
30
+ /**
31
+ * Server Components, route handlers and server actions: resumes the session from the cookie
32
+ * store the middleware prepared. Cookie writes are attempted and swallowed (a read-only store
33
+ * throws); a refresh made here updates memory only.
34
+ */
35
+ serverSession(input: {
36
+ cookies: NextCookieStore;
37
+ headers?: {
38
+ get(name: string): string | null;
39
+ };
40
+ }): Promise<RequestSession>;
41
+ }
42
+ /**
43
+ * The Next.js App Router adapter. The options carry the app's session cache and superuser client,
44
+ * which it creates once; nothing here keeps state between requests.
45
+ *
46
+ * It runs on the Node.js runtime only: Next.js 16 `proxy.ts` always does, and Next.js 15.5
47
+ * `middleware.ts` does with `export const runtime = "nodejs"`. The Edge runtime is not supported.
48
+ * On Edge the package's browser condition resolves to a stub, so the import fails at build time
49
+ * or the app answers every request with the stub's error (docs/design/13-ssr.md, "Runtime").
50
+ *
51
+ * @throws {TypeError} without a superuser client and without `readableCookie: true`
52
+ */
53
+ export declare function createNextAuth(options: NextAuthOptions): NextAuth;
@@ -0,0 +1,7 @@
1
+ export type FetchFunction = (url: RequestInfo | URL, config?: RequestInit) => Promise<Response>;
2
+ /**
3
+ * Wraps the fetch that sends a server client's requests. It runs after `beforeSend`, so an
4
+ * app that replaces the send options cannot drop `cache: "no-store"` (Next.js would cache
5
+ * the response in its data cache otherwise).
6
+ */
7
+ export declare function noStoreFetch(inner: FetchFunction | undefined, onResponse?: (response: Response) => void): FetchFunction;
@@ -0,0 +1,41 @@
1
+ import { type AdapterOptions } from "./adapter.js";
2
+ /** The options of a cookie write, in the shape h3's `setCookie` takes. */
3
+ export interface NuxtCookieOptions {
4
+ path: string;
5
+ httpOnly?: boolean;
6
+ sameSite?: boolean | "lax" | "strict" | "none";
7
+ secure?: boolean;
8
+ maxAge?: number;
9
+ expires?: Date;
10
+ domain?: string;
11
+ }
12
+ /** The parts of Nitro's event the middleware uses (see the file header for the mapping). */
13
+ export interface NuxtEvent {
14
+ /** The request method. */
15
+ method: string;
16
+ /** The request target: the path and query, as h3's `event.path` has them. */
17
+ path: string;
18
+ /** The request headers, as Node has them (`event.node.req.headers`). */
19
+ headers: Record<string, string | string[] | undefined>;
20
+ /** Nitro's per-request context: the middleware sets `pb` and `pbBrowserToken` on it. */
21
+ context: Record<string, unknown>;
22
+ /** Reads the request body as JSON. Only the popup route calls it. */
23
+ readBody?: () => Promise<unknown>;
24
+ /** Writes a cookie on the response (h3's `setCookie`). */
25
+ setCookie(name: string, value: string, options: NuxtCookieOptions): void;
26
+ /** Sets a header on the response (h3's `setResponseHeader`). */
27
+ setHeader(name: string, value: string): void;
28
+ }
29
+ export interface NuxtAuth {
30
+ /**
31
+ * A Nitro server middleware: sets `event.context.pb` and `event.context.pbBrowserToken`, answers
32
+ * the adapter routes and the CSRF guard, else lets the request continue. Returns a `Response`
33
+ * to answer the request, or `undefined` to continue.
34
+ */
35
+ middleware(event: NuxtEvent): Promise<Response | undefined>;
36
+ }
37
+ /**
38
+ * Creates the Nuxt auth. Throws a `TypeError` without a superuser client and without
39
+ * `readableCookie: true` (see `resolveAdapterOptions`).
40
+ */
41
+ export declare function createNuxtAuth(options: AdapterOptions): NuxtAuth;
@@ -0,0 +1,56 @@
1
+ /** The temporary cookie's lifetime, as its `Max-Age` (see `buildOAuth2CookieToSet`). */
2
+ export declare const OAUTH2_STATE_TTL_MS: number;
3
+ export declare const DEFAULT_OAUTH2_COLLECTION = "users";
4
+ export type OAuth2ErrorKind = "invalid-callback" | "unknown-provider" | "unsupported-provider" | "no-cookie-writer" | "missing-cookie" | "expired" | "state-mismatch" | "provider-error" | "missing-code";
5
+ /**
6
+ * A failure of the OAuth2 redirect flow that the SDK detects itself. A failure the server
7
+ * reports is its `ClientResponseError`, unchanged.
8
+ */
9
+ export declare class OAuth2Error extends Error {
10
+ readonly kind: OAuth2ErrorKind;
11
+ /** The provider's `error` parameter (`provider-error` only). */
12
+ readonly providerError?: string;
13
+ constructor(kind: OAuth2ErrorKind, message: string, providerError?: string);
14
+ }
15
+ /** What the temporary cookie carries from `startOAuth2` to `completeOAuth2`. */
16
+ export interface OAuth2Pending {
17
+ state: string;
18
+ codeVerifier: string;
19
+ provider: string;
20
+ collection: string;
21
+ /** The callback URL sent to the provider; the server must get the same one. */
22
+ redirectURL: string;
23
+ redirectTo: string;
24
+ /** Expiry, in epoch milliseconds. */
25
+ exp: number;
26
+ }
27
+ /**
28
+ * A same-origin path for `redirectTo`, or `/`. Only a path that starts with one slash is kept:
29
+ * no `//host`, no backslash (browsers read `/\host` as `//host`), no control characters, no
30
+ * scheme, and nothing that resolves to another origin.
31
+ */
32
+ export declare function safeRedirectPath(value: unknown): string;
33
+ /** Equal strings compare in time that depends only on their length (the state is public). */
34
+ export declare function constantTimeEqual(a: string, b: string): boolean;
35
+ /**
36
+ * The callback URL the provider redirects to. It is registered with the provider, so it must
37
+ * be an absolute http(s) URL; a query or fragment would not match the registration.
38
+ */
39
+ export declare function validateCallbackUrl(callbackUrl: string): string;
40
+ /**
41
+ * Reads the temporary cookie's value. Adapters may hand it over decoded or as the browser sent
42
+ * it, so the raw text is tried first and the percent-decoded text second (as the session cookie).
43
+ * Anything malformed is `undefined`, which the caller treats as a missing cookie.
44
+ */
45
+ export declare function parseOAuth2Cookie(raw: string): OAuth2Pending | undefined;
46
+ /** The provider's authorization URL with the callback as its `redirect_uri`. */
47
+ export declare function withRedirectUri(authURL: string, callbackUrl: string): string;
48
+ /**
49
+ * Whether the provider returns to the callback as a GET with `code`, `state` and `error` in the
50
+ * query string. Upstream asks Apple for `response_mode=form_post`, so Apple returns with a
51
+ * cross-site POST whose form body this flow does not read, and whose `SameSite=Lax` cookie the
52
+ * browser does not send. Only `response_mode=query`, or no `response_mode`, passes; any other
53
+ * mode is refused. The URL may be relative: upstream returns `?client_id=...` for a provider with
54
+ * no authorization endpoint, and the caller appends `redirect_uri` to it.
55
+ */
56
+ export declare function returnsToQueryString(authURL: string): boolean;
@@ -0,0 +1,14 @@
1
+ import type { CreateServerClientOptions } from "./types.js";
2
+ export interface PopupHandOffOptions extends Omit<CreateServerClientOptions, "cookies" | "request" | "origin"> {
3
+ /** Origins besides the request's own that may post the token (see `checkOrigin`). */
4
+ allowedOrigins?: readonly string[];
5
+ }
6
+ /**
7
+ * The adapter route that completes a popup sign-in. It accepts `POST` with the JSON body
8
+ * `{ "token": "..." }` from the same origin (always checked, with or without a session cookie),
9
+ * and checks the token with one `auth-refresh`. On success the HttpOnly session cookie is written
10
+ * from the refreshed token and record, and the response carries the record only: the token stays
11
+ * in the cookie. The posted token is the only input trusted; nothing else the browser sends is.
12
+ * A revoked token gets 401 and sets no cookie.
13
+ */
14
+ export declare function handlePopupHandOff(request: Request, { allowedOrigins, ...options }: PopupHandOffOptions): Promise<Response>;