UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

252 lines 9.79 kB
import { Alepha, Atom, KIND, Primitive, Static, TSchema } from "alepha"; import { SecretProvider } from "alepha/crypto"; import { DateTimeProvider, DurationLike } from "alepha/datetime"; //#region ../../src/server/cookies/services/CookieParser.d.ts declare class CookieParser { parseRequestCookies(header: string): Record<string, string>; serializeResponseCookies(cookies: Record<string, Cookie | null>, isHttps: boolean): string[]; cookieToString(name: string, cookie: Cookie, isHttps?: boolean): string; } //#endregion //#region ../../src/server/cookies/providers/ServerCookiesProvider.d.ts declare class ServerCookiesProvider { protected readonly alepha: Alepha; protected readonly log: import("alepha/logger").Logger; protected readonly cookieParser: CookieParser; protected readonly dateTimeProvider: DateTimeProvider; protected readonly secretProvider: SecretProvider; protected readonly ALGORITHM = "aes-256-gcm"; protected readonly IV_LENGTH = 16; protected readonly AUTH_TAG_LENGTH = 16; protected readonly SIGNATURE_LENGTH = 32; readonly onRequest: import("alepha").HookPrimitive<"server:onRequest">; readonly onAction: import("alepha").HookPrimitive<"action:onRequest">; readonly onSend: import("alepha").HookPrimitive<"server:onSend">; protected getCookiesFromContext(cookies?: Cookies): Cookies; /** * Namespaces a cookie name with the app's `APP_NAME` (lowercased) so that * two Alepha apps sharing a cookie jar do not collide. * * Cookies are scoped by host + path only — never by port — so two apps on * `localhost:3000` and `localhost:4000` would otherwise both read/write a * cookie literally named `tokens` and silently clobber each other (and, * because each encrypts with its own `APP_SECRET`, the foreign cookie fails * to decrypt and gets deleted, logging the user out). * * When `APP_NAME` is unset the name is returned unchanged, so existing * single-app deployments keep their current cookie names. Same convention as * the `APP_NAME` prefix used by R2 storage and server-timing. * * Pass `prefix = false` to skip the namespace entirely — used for * `persist: "cookie"` atoms, whose browser-side counterpart cannot see * `APP_NAME` and therefore always uses the bare name. See * `CookiePrimitiveOptions.prefix`. */ protected prefixName(name: string, prefix?: boolean): string; getCookie<T extends TSchema>(name: string, options: CookiePrimitiveOptions<T>, contextCookies?: Cookies): Static<T> | undefined; setCookie<T extends TSchema>(name: string, options: CookiePrimitiveOptions<T>, data: Static<T>, contextCookies?: Cookies): void; deleteCookie<T extends TSchema>(name: string, contextCookies?: Cookies, prefix?: boolean): void; protected encrypt(text: string): string; protected decrypt(encryptedText: string): string; /** * Derives a 32-byte key from APP_SECRET via SHA-256. * Accepts any string length — no padding or truncation needed. */ protected deriveKey(): Buffer; protected sign(data: string): string; } //#endregion //#region ../../src/server/cookies/primitives/$cookie.d.ts /** * Declares a type-safe, configurable HTTP cookie. * This primitive provides methods to get, set, and delete the cookie * within the server request/response cycle. */ declare const $cookie: { <T extends TSchema>(options: CookiePrimitiveOptions<T>, extendedOptions?: Omit<CookiePrimitiveOptions<T>, "schema">): AbstractCookiePrimitive<T>; [KIND]: typeof CookiePrimitive; }; interface CookiePrimitiveOptions<T extends TSchema> { /** * The schema for the cookie's value, used for validation and type safety. */ schema: T; /** * The name of the cookie. */ name?: string; /** * The cookie's path. Defaults to "/". */ path?: string; /** * Time-to-live for the cookie. Maps to `Max-Age`. */ ttl?: DurationLike; /** * If true, the cookie is only sent over HTTPS. Defaults to true in production. */ secure?: boolean; /** * If true, the cookie cannot be accessed by client-side scripts. */ httpOnly?: boolean; /** * SameSite policy for the cookie. Defaults to "lax". */ sameSite?: "strict" | "lax" | "none"; /** * The domain for the cookie. */ domain?: string; /** * If true, the cookie value will be compressed using zlib. */ compress?: boolean; /** * If true, the cookie value will be encrypted. Requires `COOKIE_SECRET` env var. */ encrypt?: boolean; /** * If true, the cookie will be signed to prevent tampering. Requires `COOKIE_SECRET` env var. */ sign?: boolean; /** * Optional key to link this cookie to an Atom, enabling automatic synchronization between the cookie and the Atom's state. */ key?: string; /** * Internal escape hatch: when explicitly set to `false`, the server skips * the `APP_NAME` cookie-name namespace applied by * `ServerCookiesProvider.prefixName()`. * * Used by `AtomCookiePersistence` so the cookie name the server * reads/writes for a `persist: "cookie"` atom matches the bare name its * browser variant uses — `APP_NAME` is not reachable client-side (not * baked into the client bundle, not part of SSR hydration), so the * browser can only ever use the bare atom key. * * Application code declaring `$cookie(...)` directly should leave this * unset — it defaults to `true` (prefixed), matching every other cookie. */ prefix?: boolean; } interface AbstractCookiePrimitive<T extends TSchema> { readonly name: string; readonly options: CookiePrimitiveOptions<T>; set(value: Static<T>, options?: { cookies?: Cookies; ttl?: DurationLike; }): void; get(options?: { cookies?: Cookies; }): Static<T> | undefined; del(options?: { cookies?: Cookies; }): void; } declare class CookiePrimitive<T extends TSchema> extends Primitive<CookiePrimitiveOptions<T>> implements AbstractCookiePrimitive<T> { protected readonly serverCookiesProvider: ServerCookiesProvider; protected onInit(): void; get schema(): T; get name(): string; /** * Sets the cookie with the given value in the current request's response. */ set(value: Static<T>, options?: { cookies?: Cookies; ttl?: DurationLike; }): void; /** * Gets the cookie value from the current request. Returns undefined if not found or invalid. */ get(options?: { cookies?: Cookies; }): Static<T> | undefined; /** * Deletes the cookie in the current request's response. */ del(options?: { cookies?: Cookies; }): void; } interface Cookies { req: Record<string, string>; res: Record<string, Cookie | null>; } interface Cookie { value: string; path?: string; maxAge?: number; secure?: boolean; httpOnly?: boolean; sameSite?: "strict" | "lax" | "none"; domain?: string; } //#endregion //#region ../../src/server/cookies/providers/AtomCookiePersistence.d.ts /** * Binds every atom declared with `persist: "cookie"` to an HTTP cookie. * * - `server:onRequest` — seeds the request-scoped state from the cookie, so * SSR renders with the persisted value. * - `state:mutate` — writes the new value back as a Set-Cookie header. * - `state:register` — an atom registering lazily *during* a request (first * touched by an SSR render, after `server:onRequest` already ran) reads * its cookie right away, so that render still sees the persisted value. * * Atoms are resolved from the `StateManager` registry * (`alepha.store.listAtoms()`) on every request and every mutation, never * from a map built up from `state:register` events. That event fires exactly * once per atom and is never replayed, while `$module.register()` registers * `atoms[]` BEFORE it wires `imports[]` and injects `services[]` — so the * documented `$module({ atoms, imports: [AlephaServerCookies], services })` * shape registers every atom before this provider exists. An event-sourced * map would stay empty forever there, making `persist: "cookie"` a silent * no-op in both directions. Reading the registry on demand is * order-independent. * * The cookie is named after the atom key, lives 365 days, SameSite=lax, * path "/". For custom cookie options (encryption, signing, custom TTL), * declare an explicit `$cookie({ key: atom.key, ... })` binding instead. */ declare class AtomCookiePersistence { protected readonly alepha: Alepha; protected readonly log: import("alepha/logger").Logger; protected readonly serverCookies: ServerCookiesProvider; protected readonly onRequest: import("alepha").HookPrimitive<"server:onRequest">; protected readonly onRegister: import("alepha").HookPrimitive<"state:register">; protected readonly onMutate: import("alepha").HookPrimitive<"state:mutate">; /** * Every registered atom declared with `persist: "cookie"`, read live from * the state manager's registry. */ protected cookieAtoms(): Array<Atom<any, any>>; protected read(atom: Atom<any, any>, cookies?: Cookies): void; protected cookieOptions(atom: Atom<any, any>): { schema: any; path: string; sameSite: "lax"; ttl: DurationLike; prefix: boolean; }; } //#endregion //#region ../../src/server/cookies/index.d.ts declare module "alepha/server" { interface ServerRequest { cookies: Cookies; } } /** * Server and browser-safe cookie handling. * * **Features:** * - Cookie management on server and browser * * @module alepha.server.cookies */ declare const AlephaServerCookies: import("alepha").Service<import("alepha").Module>; //#endregion export { $cookie, AbstractCookiePrimitive, AlephaServerCookies, AtomCookiePersistence, Cookie, CookiePrimitive, CookiePrimitiveOptions, Cookies, ServerCookiesProvider }; //# sourceMappingURL=index.d.ts.map