import { Connect, Plugin } from 'vite'; import * as _supabase_supabase_js from '@supabase/supabase-js'; import { SupabaseClientOptions } from '@supabase/supabase-js'; import * as s from 'jsonv-ts'; import { Connection } from '@supabase/lite'; import * as hono_hono_base from 'hono/hono-base'; import * as hono_utils_http_status from 'hono/utils/http-status'; import * as hono_utils_types from 'hono/utils/types'; import * as hono_types from 'hono/types'; import { Context, MiddlewareHandler } from 'hono'; import { Kysely } from 'kysely'; import { ReadableStream as ReadableStream$1 } from 'node:stream/web'; declare module "jsonv-ts" { interface ISchemaOptions { tags?: string[]; links?: { name: string; link: string; }[]; } } declare const schema: s.ObjectSchema<{ readonly project_id: s.Schema; readonly analytics: s.Schema; readonly api: s.Schema; readonly auth: s.Schema; readonly db: s.Schema; readonly edge_runtime: s.Schema; readonly functions: s.Schema; readonly inbucket: s.Schema; readonly realtime: s.Schema; readonly storage: s.Schema; readonly studio: s.Schema; readonly experimental: s.Schema; }, s.Merge>; type Schema = s.Static; type DefaultSchema = s.StaticCoerced; interface UsersTable { id: string; aud: string; role: string; email: string | null; encrypted_password: string | null; phone: string | null; email_confirmed_at: string | null; confirmed_at: string | null; invited_at: string | null; confirmation_token: string | null; confirmation_sent_at: string | null; recovery_token: string | null; recovery_sent_at: string | null; email_change: string | null; email_change_token_new: string | null; email_change_token_current: string | null; email_change_sent_at: string | null; email_change_confirm_status: number; phone_confirmed_at: string | null; phone_change: string | null; phone_change_token: string | null; phone_change_sent_at: string | null; reauthentication_token: string | null; reauthentication_sent_at: string | null; raw_app_meta_data: string | Record; raw_user_meta_data: string | Record; banned_until: string | null; deleted_at: string | null; is_sso_user: boolean; is_anonymous: boolean; last_sign_in_at: string | null; created_at: string; updated_at: string; } interface SessionsTable { id: string; user_id: string; not_after: string | null; refreshed_at: string | null; user_agent: string | null; ip: string | null; tag: string | null; refresh_token_hmac_key: string | null; refresh_token_counter: number | null; scopes: string | null; created_at: string; updated_at: string; aal: string | null; factor_id: string | null; } interface RefreshTokensTable { id: string; token: string; user_id: string; session_id: string | null; revoked: boolean; parent: string | null; created_at: string; updated_at: string; } interface IdentitiesTable { id: string; provider: string; provider_id: string; user_id: string; identity_data: string | Record; email?: string; last_sign_in_at: string | null; created_at: string; updated_at: string; } interface FlowStateTable { id: string; user_id: string | null; auth_code: string | null; authentication_method: string; code_challenge_method: string | null; code_challenge: string | null; provider_type: string; provider_access_token: string | null; provider_refresh_token: string | null; auth_code_issued_at: string | null; invite_token: string | null; referrer: string | null; oauth_client_state_id: string | null; linking_target_id: string | null; email_optional: boolean; created_at: string; updated_at: string; } type NewFlowState = Pick & Partial>; interface UserResponse { id: string; aud: string; role: string; email: string; phone: string; confirmed_at?: string | null; email_confirmed_at?: string | null; last_sign_in_at?: string | null; app_metadata: Record; user_metadata: Record; identities: IdentityResponse[]; created_at: string; updated_at: string; is_anonymous: boolean; new_email?: string; confirmation_sent_at?: string | null; email_change_sent_at?: string | null; recovery_sent_at?: string | null; } interface SessionResponse { access_token: string; refresh_token: string; token_type: "bearer"; expires_in: number; expires_at: number; user: UserResponse; weak_password?: null; } interface IdentityResponse { identity_id: string; id: string; user_id: string; identity_data: Record; provider: string; last_sign_in_at: string | null; created_at: string; updated_at: string; email?: string; } interface AuthConfig { jwt_secret: string; jwt_expiry?: number; enable_refresh_token_rotation?: boolean; refresh_token_reuse_interval?: number; minimum_password_length?: number; password_required_characters?: string[]; password_requirements?: string; enable_signup?: boolean; sessions?: { timebox?: string; inactivity_timeout?: string; single_per_user?: boolean; }; email?: { enable_signup?: boolean; enable_confirmations?: boolean; double_confirm_changes?: boolean; otp_length?: number; otp_expiry?: number; smtp?: { enabled?: boolean; host?: string; port?: number; user?: string; pass?: string; admin_email?: string; sender_name?: string; }; template?: Partial>; }; enable_confirmations?: boolean; site_url?: string; additional_redirect_urls?: string[]; external?: Record; } type EmailTemplateType = "invite" | "confirmation" | "recovery" | "magic_link" | "email_change"; interface EmailTemplateConfig { subject?: string; content_path?: string; } type Dialect$1 = "postgres" | "sqlite"; /** Bound `Connection#runInTransaction` — see db/Connection.ts for why this * indirection exists (DO storage has no BEGIN/COMMIT over kysely). */ type TransactionRunner = (fn: (trx: Kysely) => Promise) => Promise; declare class AuthRepository { private db; private dialect; private runInTransaction; private schema; constructor(db: Kysely, dialect: Dialect$1, runInTransaction?: TransactionRunner); private bool; /** * Runs `fn` inside a database transaction, handing it a repository bound to * the transaction's executor. All reads/writes performed through that * repository (including this one's other methods) participate in the same * transaction, and are rolled back together if `fn` throws. * * Callers that need existing private helpers (which close over `this.repo`) * to run against the transaction should swap `this.repo` for the duration * of the callback — safe because AuthService/AuthRepository instances are * constructed fresh per request (see server/auth.ts createAuthService). */ transaction(fn: (repo: AuthRepository) => Promise): Promise; private table; private insertInto; private update; private deleteFrom; findUserByEmail(email: string): Promise; findUserById(id: string): Promise; findUserByToken(column: string, token: string): Promise; /** * Atomically consumes a one-time token: the UPDATE only matches a row whose * `column` still holds `token`, so exactly one of two concurrent verifies * for the same OTP can win, and a token rotated/cleared by another request * (resend, a competing verify) no longer matches. Returns false when no row * was updated — callers must treat that as an invalid/consumed token and * mutate nothing further. * * This is the guard that survives on D1, whose `runInTransaction` cannot * group statements (see D1SqliteConnection L131-140): a single conditional * UPDATE with a rowcount check is atomic on every driver. */ claimUserToken(userId: string, column: string, token: string): Promise; createUser(user: Partial & { id: string; email: string | null; }): Promise; updateUser(id: string, updates: Partial): Promise; createSession(session: { id: string; user_id: string; aal?: string; }): Promise; findSessionById(id: string): Promise; updateSessionRefreshedAt(id: string, refreshedAt: string): Promise; deleteSession(id: string): Promise; deleteUserSessions(userId: string, exceptSessionId?: string): Promise; deleteRefreshTokensForSession(sessionId: string): Promise; deleteRefreshTokensForUser(userId: string, exceptSessionId?: string): Promise; createRefreshToken(rt: { token: string; user_id: string; session_id: string; parent?: string | null; }): Promise; findRefreshToken(token: string): Promise; findRefreshTokensBySession(sessionId: string): Promise; revokeRefreshToken(id: string): Promise; revokeSessionRefreshTokens(sessionId: string): Promise; revokeRefreshTokensByIds(ids: string[]): Promise; revokeUserRefreshTokens(userId: string): Promise; createIdentity(identity: { id: string; provider: string; provider_id: string; user_id: string; identity_data: Record; last_sign_in_at?: string | null; }): Promise; findIdentitiesByUserId(userId: string): Promise; updateIdentity(id: string, updates: Partial): Promise; deleteIdentitiesExcept(userId: string, keepId: string): Promise; findIdentityByProviderAndId(provider: string, providerId: string): Promise; findIdentitiesByEmails(emails: string[]): Promise; createFlowState(flow: NewFlowState): Promise; findFlowStateById(id: string): Promise; findFlowStateByAuthCode(authCode: string): Promise; updateFlowState(id: string, updates: Partial): Promise; /** * Atomically claims a PKCE flow_state row for a callback: the UPDATE only * matches (and thus only succeeds for) a row whose user_id is still null, * so exactly one of two concurrent callbacks for the same state can win. * Returns false if the row was already claimed (or no longer exists) — * callers should treat that as a replay (flow_state_already_used). */ claimFlowStateForPkce(id: string, updates: { user_id: string; provider_access_token: string; provider_refresh_token: string; auth_code_issued_at: string; }): Promise; /** * Atomically deletes a flow_state row, returning whether a row was * actually removed. A single DELETE...WHERE id = ? is inherently atomic * (at most one caller can ever delete a given row), so this doubles as the * "claim" step for implicit-flow callbacks and PKCE auth-code redemption: * only the caller that observes `true` may proceed to issue a session. */ /** * Deletes at most {@link FLOW_STATE_CLEANUP_BATCH} flow_state rows created * before `cutoffIso`. Ports the flow_state statement of GoTrue's periodic * cleanup (internal/models/cleanup.go L62): * * delete from "flow_state" where id in ( * select id from "flow_state" where created_at < now() - interval '24 hours' * limit 100 for update skip locked); * * The bound is the point of that statement: cleanup must never turn into an * unbounded delete that blocks the request it is piggybacking on (lite has * no background scheduler, so this runs opportunistically on the /authorize * insert path). A backlog is drained across subsequent /authorize calls. * `for update skip locked` has no sqlite equivalent and is omitted; the * id-in-subquery-with-LIMIT shape works on both dialects. Returns the number * of rows removed. */ deleteFlowStatesCreatedBefore(cutoffIso: string): Promise; deleteFlowState(id: string): Promise; createAuditLogEntry(entry: { id: string; payload?: Record; ip_address?: string; }): Promise; parseUserJson(user: UsersTable): UsersTable; } interface CacheSetOptions { ttl?: number; } interface CacheDriver { get(key: string): Promise; set(key: string, value: string, options?: CacheSetOptions): Promise; delete(key: string): Promise; } interface EmailMessage { to: string; subject: string; text?: string; html?: string; } interface EmailDriver { send(message: EmailMessage): Promise; } interface SmsMessage { to: string; body: string; } interface SmsDriver { send(message: SmsMessage): Promise; } interface AppDrivers { email: EmailDriver; sms: SmsDriver; cache: CacheDriver; } type PartialAppDrivers = Partial; interface Mailer { sendConfirmation(email: string, token: string, otp: string, meta?: MailMeta): Promise; sendRecovery(email: string, token: string, otp: string, meta?: MailMeta): Promise; sendMagicLink(email: string, token: string, otp: string, meta?: MailMeta): Promise; sendEmailChange(email: string, token: string, otp: string, meta?: MailMeta): Promise; sendReauthentication(email: string, otp: string, meta?: MailMeta): Promise; } interface MailMeta { userId?: string; emailActionType?: string; tokenHash?: string; tokenNew?: string; tokenHashNew?: string; redirectTo?: string; /** Current (old) email — used as the `Email` template var for email change. */ currentEmail?: string; /** Pending (new) email — used as the `NewEmail` template var for email change. */ newEmail?: string; data?: string; } declare class AuthService { repo: AuthRepository; private config; private mailer; private jwtExpiry; private minPasswordLength; private passwordRequiredCharacters; private sessionTimeboxSeconds?; private sessionInactivitySeconds?; constructor(repo: AuthRepository, config: AuthConfig, mailer: Mailer); private get otpLength(); private get otpExpirySeconds(); /** * Returns a safe post-verification redirect target: `redirectTo` if allowed, * otherwise `site_url`. Mirrors GoTrue's `IsRedirectURLValid`: * - same scheme + host + port as `site_url` (any path; port ignored for * loopback hosts), or * - a glob match of `additional_redirect_urls` against the full URL * (patterns use `.`/`/` as separators, so `*` does not cross them but * `**` does). */ resolveEmailRedirect(redirectTo?: string | null): string; signUp(email: string | undefined, password: string | undefined, data?: Record): Promise<{ user: UserResponse; session?: SessionResponse; }>; signInWithPassword(email: string | undefined, password: string | undefined): Promise; refreshSession(refreshToken: string | undefined): Promise; private refreshWithRevokedToken; private createRefreshResponse; private assertSessionRefreshable; getUser(userId: string): Promise; updateUser(userId: string, updates: { data?: Record; password?: string; email?: string; }): Promise; signOut(sessionId: string | undefined, scope: string | undefined, userId: string): Promise; signInWithOtp(email: string | undefined, options?: { shouldCreateUser?: boolean; }): Promise; requestMagicLink(email: string | undefined, _security?: Record): Promise; verifyOtp(params: { email?: string; token?: string; token_hash?: string; type: string; }): Promise; /** * The mutating half of {@link verifyOtp}, always run inside a transaction * (`this.repo` is bound to it) — see the comment at the call site. */ private completeVerifyOtp; recover(email: string | undefined): Promise; resend(type: string, email: string | undefined): Promise; reauthenticate(userId: string): Promise; private createSessionForUser; private assertPasswordStrong; private mapUserToResponse; private mapIdentityToResponse; private findUserByTokenAndType; private static readonly SENT_AT_COLUMN; private isTokenExpired; private getTokenColumnsForType; private createAuditLog; /** * Same entry shape as {@link createAuditLog}, for the call sites whose * traits map is not `{provider: ...}` (GoTrue builds the map per call site; * see models.NewAuditLogEntry's `traits map[string]any` argument). */ private createAuditLogWithTraits; getExternalProviderRedirectUrl(query: Record, opts: { refererHeader?: string; defaultRedirectUri: string; }): Promise; loadOAuthFlowState(state: string | undefined): Promise; resolveOAuthRedirectTarget(flowState: FlowStateTable): string; handleExternalProviderCallback(flowState: FlowStateTable, params: Record, opts: { defaultRedirectUri: string; }): Promise<{ type: "pkce" | "implicit"; redirectUrl: string; }>; /** * Tail of the external-provider callback, shared by the account-linking and * invite branches: claims the flow state and either hands back the PKCE * auth code or issues a session in the URL fragment (external.go * L221-286). Runs inside the callback's transaction — `this.repo` is * already bound to it by the caller. */ private issueOAuthCallbackResult; /** * Ports internal/api/external.go's processInvite (L449-514): accepts an * invitation with an external identity. The invite token is the user's * `confirmation_token` (models.FindUserByConfirmationToken), the external * email must match the invited email, and the user is confirmed because * they were able to respond to the invite email. * * Runs inside the callback's transaction (`this.repo` is bound to it). */ private processInvite; exchangePkceCode(authCode: string | undefined, codeVerifier: string | undefined): Promise; private resolveOAuthReferrer; private updateUserMetaDataAndProviders; private buildAppMetaDataProviders; private removeUnconfirmedIdentities; private determineAccountLinking; } type CrossReadableStream = ReadableStream | ReadableStream$1; interface ObjectMetadata { cacheControl: string; contentLength: number; size: number; mimetype: string; lastModified?: Date; eTag: string; contentRange?: string; httpStatusCode?: number; } interface BrowserCacheHeaders { ifModifiedSince?: string; ifNoneMatch?: string; range?: string; } interface ObjectResponse { metadata: ObjectMetadata; httpStatusCode: number; body?: CrossReadableStream | Blob | Buffer; } type StorageAdapterOptions = {}; interface StorageAdapter { driver: Driver; getObject(bucketName: string, key: string, version: string | undefined, headers?: BrowserCacheHeaders): Promise; uploadObject(bucketName: string, key: string, version: string | undefined, body: CrossReadableStream | Buffer | Uint8Array, contentType: string, cacheControl: string): Promise; deleteObject(bucket: string, key: string, version: string | undefined): Promise; deleteObjects(bucket: string, prefixes: string[]): Promise; copyObject(bucket: string, source: string, version: string | undefined, destination: string, destinationVersion: string | undefined): Promise>; headObject(bucket: string, key: string, version: string | undefined): Promise; privateAssetUrl(bucket: string, key: string, version: string | undefined): Promise; } interface TransformOptions { width?: number; height?: number; resize?: "cover" | "contain" | "fill"; format?: "webp" | "png" | "jpeg" | "avif"; quality?: number; } interface TransformResult { body: ReadableStream | Uint8Array; contentType: string; /** Only set when body is a Uint8Array */ contentLength?: number; } interface TransformationAdapterOptions { } interface TransformationAdapter { driver: Driver; /** * Whether this adapter requires the full image buffer upfront. * If false, the service will pass the stream/url through without buffering. * - sharp: true (needs buffer) * - cloudflare: false (transforms via URL subrequest) */ requiresBuffer: boolean; /** * Transform from a buffer. Used when requiresBuffer is true. */ transform(input: Uint8Array, options: TransformOptions): Promise; /** * Transform from a URL or Response. Used when requiresBuffer is false. * Adapters that don't support this should set requiresBuffer=true. */ transformFromUrl?(url: string, options: TransformOptions): Promise; } type Dialect = "postgres" | "sqlite"; interface Bucket { id: string; name: string; owner: string | null; owner_id: string | null; public: boolean; file_size_limit: number | null; allowed_mime_types: string[] | null; created_at: string; updated_at: string; } interface StorageObject { id: string; bucket_id: string; name: string; owner: string | null; owner_id: string | null; metadata: Record; user_metadata: Record; path_tokens: string[]; version: string | null; created_at: string; updated_at: string; last_accessed_at: string; } interface ListObjectsOptions { limit?: number; offset?: number; sortBy?: { column: string; order: "asc" | "desc"; }; search?: string; } declare class StorageRepository { private db; private dialect; private schema; constructor(db: Kysely, dialect: Dialect); private table; private insertInto; private update; private deleteFrom; createBucket(bucket: { id: string; name: string; owner?: string | null; owner_id?: string | null; public?: boolean; file_size_limit?: number | null; allowed_mime_types?: string[]; }): Promise; findBucketById(id: string): Promise; findBucketByName(name: string): Promise; listBuckets(): Promise; updateBucket(id: string, updates: Partial<{ public: boolean; file_size_limit: number | null; allowed_mime_types: string[]; }>): Promise; deleteBucket(id: string): Promise; isBucketEmpty(id: string): Promise; createObject(obj: { id: string; bucket_id: string; name: string; owner?: string | null; owner_id?: string | null; metadata?: Record; user_metadata?: Record; version?: string | null; }): Promise; findObjectById(id: string): Promise; findObjectByPath(bucketId: string, name: string): Promise; listObjects(bucketId: string, prefix?: string, options?: ListObjectsOptions): Promise; updateObject(id: string, updates: Partial<{ name: string; metadata: Record; user_metadata: Record; version: string | null; owner: string | null; owner_id: string | null; }>): Promise; deleteObject(id: string): Promise; deleteObjectsByBucket(bucketId: string): Promise; objectExists(bucketId: string, name: string): Promise; touchObject(id: string): Promise; private parseBucketRow; private parseObjectRow; } interface StorageServiceConfig { jwtSecret: string; fileSizeLimit?: number; buckets?: Record; } interface StorageServiceOptions { autoCreateBuckets?: boolean; } declare class StorageService { private repo; private adapter; private config; private options; private transformationAdapter?; private initialized; constructor(repo: StorageRepository, adapter: StorageAdapter, config: StorageServiceConfig, options?: StorageServiceOptions, transformationAdapter?: TransformationAdapter | undefined); init(): Promise; createBucket(params: { id: string; name: string; public?: boolean; file_size_limit?: number | null; allowed_mime_types?: string[]; owner?: string | null; }): Promise; getBucket(id: string): Promise; listBuckets(): Promise; updateBucket(id: string, updates: { public?: boolean; file_size_limit?: number | null; allowed_mime_types?: string[]; }): Promise; deleteBucket(id: string): Promise; emptyBucket(id: string): Promise; upload(bucketId: string, path: string, body: ReadableStream | Buffer | Uint8Array, options?: { contentType?: string; cacheControl?: string; contentLength?: number; upsert?: boolean; metadata?: Record; owner?: string | null; }): Promise; download(bucketId: string, path: string, options?: { transform?: TransformOptions; }): Promise<{ body: CrossReadableStream | Blob | Buffer | Uint8Array; metadata: ObjectMetadata; }>; update(bucketId: string, path: string, body: ReadableStream | Buffer | Uint8Array, options?: { contentType?: string; cacheControl?: string; contentLength?: number; metadata?: Record; upsert?: boolean; owner?: string | null; }): Promise; remove(bucketId: string, paths: string[]): Promise; list(bucketId: string, prefix?: string, options?: ListObjectsOptions): Promise; move(bucketId: string, fromPath: string, toPath: string): Promise; copy(bucketId: string, fromPath: string, toPath: string): Promise<{ key: string; }>; info(bucketId: string, path: string): Promise; exists(bucketId: string, path: string): Promise; createSignedUrl(bucketId: string, path: string, expiresIn: number): Promise<{ signedUrl: string; }>; createSignedUrls(bucketId: string, paths: string[], expiresIn: number): Promise<{ path: string; signedUrl: string; error: string | null; }[]>; createSignedUploadUrl(bucketId: string, path: string): Promise<{ signedUrl: string; token: string; path: string; }>; verifySignedUrl(token: string): Promise<{ bucket: string; path: string; intent: "download" | "upload"; }>; private signStorageToken; } type HonoContext = { Variables: { app: App; authService: AuthService; storageService: StorageService; userId?: string; sessionId?: string; jwt?: Record; apiKeyType?: "publishable" | "secret"; ignoreAuthorization?: boolean; /** * Set by `adminAuth()` when local admin mode elevated this request to * `service_role`. Observability/tests only — the elevation itself is * carried by `apiKeyType`/`ignoreAuthorization`/`jwt`. */ admin?: boolean; }; }; type ApiKeyType = "publishable" | "secret"; /** Claims are applied verbatim as `request.jwt.claims` — MUST include `role`. */ type ResolvedKey = { type: ApiKeyType; claims: Record; }; type ApiKeyResolver = (key: string, c: Context) => Promise; type ServerOptions = { middlewares?: MiddlewareHandler[]; disableStudio?: boolean; disableFallback?: boolean; /** * Test-only PostgREST mode: execute each request in a transaction and roll it back. */ forceRollback?: boolean; /** * `false` disables apikey enforcement outright. Otherwise a custom * `resolver` can be supplied (the lite-platform seam); when omitted, keys * configured under `config.auth.publishable_key`/`secret_key` are used. */ apiKeys?: false | { resolver?: ApiKeyResolver; }; /** * Local admin mode (default `false`): run *keyless* `/rest/v1` and * `/storage/v1` requests as `service_role`, so a browser studio can do * privileged work without a secret key shipping to the browser. Only * same-origin requests addressed to loopback are elevated. * * Two caveats, both local-dev only: * 1. RLS is not enforced for keyless traffic while this is on. To exercise * policies, send an `apikey`: the publishable key for `anon`, or the * publishable key PLUS `Authorization: Bearer ` for * `authenticated`. Those requests are never elevated. A bearer token on * its own is rejected before RLS is reached (401), since opaque keys are * only sourced from `apikey`. * 2. Localhost trust is not per-request trust. Any page open in the * developer's browser can reach the server; the same-origin and * loopback guards are what keep that from being a data-exfiltration * hole. Never enable outside local development. */ admin?: boolean; }; declare function createServer(app: App, options?: ServerOptions): hono_hono_base.HonoBase; }; }, hono_types.BlankSchema | hono_types.MergeSchemaPath<{ "*": { $options: { input: {}; output: null; outputFormat: "body"; status: 204; }; }; } & { "/signup": { $post: { input: {}; output: { access_token: string; refresh_token: string; token_type: "bearer"; expires_in: number; expires_at: number; user: { id: string; aud: string; role: string; email: string; phone: string; confirmed_at?: string | null | undefined; email_confirmed_at?: string | null | undefined; last_sign_in_at?: string | null | undefined; app_metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; identities: { identity_id: string; id: string; user_id: string; identity_data: { [x: string]: hono_utils_types.JSONValue; }; provider: string; last_sign_in_at: string | null; created_at: string; updated_at: string; email?: string | undefined; }[]; created_at: string; updated_at: string; is_anonymous: boolean; new_email?: string | undefined; confirmation_sent_at?: string | null | undefined; email_change_sent_at?: string | null | undefined; recovery_sent_at?: string | null | undefined; }; weak_password?: null | undefined; }; outputFormat: "json"; status: 200; } | { input: {}; output: { id: string; aud: string; role: string; email: string; phone: string; confirmed_at?: string | null | undefined; email_confirmed_at?: string | null | undefined; last_sign_in_at?: string | null | undefined; app_metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; identities: { identity_id: string; id: string; user_id: string; identity_data: { [x: string]: hono_utils_types.JSONValue; }; provider: string; last_sign_in_at: string | null; created_at: string; updated_at: string; email?: string | undefined; }[]; created_at: string; updated_at: string; is_anonymous: boolean; new_email?: string | undefined; confirmation_sent_at?: string | null | undefined; email_change_sent_at?: string | null | undefined; recovery_sent_at?: string | null | undefined; }; outputFormat: "json"; status: 200; }; }; } & { "/signup": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/token": { $post: { input: {}; output: { access_token: string; refresh_token: string; token_type: "bearer"; expires_in: number; expires_at: number; user: { id: string; aud: string; role: string; email: string; phone: string; confirmed_at?: string | null | undefined; email_confirmed_at?: string | null | undefined; last_sign_in_at?: string | null | undefined; app_metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; identities: { identity_id: string; id: string; user_id: string; identity_data: { [x: string]: hono_utils_types.JSONValue; }; provider: string; last_sign_in_at: string | null; created_at: string; updated_at: string; email?: string | undefined; }[]; created_at: string; updated_at: string; is_anonymous: boolean; new_email?: string | undefined; confirmation_sent_at?: string | null | undefined; email_change_sent_at?: string | null | undefined; recovery_sent_at?: string | null | undefined; }; weak_password?: null | undefined; }; outputFormat: "json"; status: 200; }; }; } & { "/token": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/otp": { $post: { input: {}; output: {}; outputFormat: "json"; status: 200; }; }; } & { "/magiclink": { $post: { input: {}; output: {}; outputFormat: "json"; status: 200; }; }; } & { "/magiclink": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/verify": { $post: { input: {}; output: { access_token: string; refresh_token: string; token_type: "bearer"; expires_in: number; expires_at: number; user: { id: string; aud: string; role: string; email: string; phone: string; confirmed_at?: string | null | undefined; email_confirmed_at?: string | null | undefined; last_sign_in_at?: string | null | undefined; app_metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; identities: { identity_id: string; id: string; user_id: string; identity_data: { [x: string]: hono_utils_types.JSONValue; }; provider: string; last_sign_in_at: string | null; created_at: string; updated_at: string; email?: string | undefined; }[]; created_at: string; updated_at: string; is_anonymous: boolean; new_email?: string | undefined; confirmation_sent_at?: string | null | undefined; email_change_sent_at?: string | null | undefined; recovery_sent_at?: string | null | undefined; }; weak_password?: null | undefined; }; outputFormat: "json"; status: 200; }; }; } & { "/verify": { $get: { input: {}; output: undefined; outputFormat: "redirect"; status: 303; }; }; } & { "/recover": { $post: { input: {}; output: {}; outputFormat: "json"; status: 200; }; }; } & { "/resend": { $post: { input: {}; output: {}; outputFormat: "json"; status: 200; }; }; } & { "/health": { $get: { input: {}; output: { version: string; name: string; description: string; }; outputFormat: "json"; status: 200; }; }; } & { "/health": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/settings": { $get: { input: {}; output: { external: { email: boolean; phone: boolean; anonymous_users: boolean; }; disable_signup: boolean; mailer_autoconfirm: boolean; phone_autoconfirm: boolean; sms_provider: string; saml_enabled: boolean; }; outputFormat: "json"; status: 200; }; }; } & { "/settings": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/.well-known/jwks.json": { $get: { input: {}; output: never; outputFormat: "json"; status: 200; }; }; } & { "/.well-known/openid-configuration": { $get: { input: {}; output: { issuer: string; jwks_uri: string; }; outputFormat: "json"; status: 200; }; }; } & { "/authorize": { $get: { input: {}; output: string; outputFormat: "body"; status: 302; }; }; } & { "/callback": { $get: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/callback": { $post: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/nonexistent": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/logout": { $post: { input: {}; output: null; outputFormat: "body"; status: 204; }; }; } & { "/user": { $get: { input: {}; output: { id: string; aud: string; role: string; email: string; phone: string; confirmed_at?: string | null | undefined; email_confirmed_at?: string | null | undefined; last_sign_in_at?: string | null | undefined; app_metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; identities: { identity_id: string; id: string; user_id: string; identity_data: { [x: string]: hono_utils_types.JSONValue; }; provider: string; last_sign_in_at: string | null; created_at: string; updated_at: string; email?: string | undefined; }[]; created_at: string; updated_at: string; is_anonymous: boolean; new_email?: string | undefined; confirmation_sent_at?: string | null | undefined; email_change_sent_at?: string | null | undefined; recovery_sent_at?: string | null | undefined; }; outputFormat: "json"; status: 200; }; }; } & { "/user": { $put: { input: {}; output: { id: string; aud: string; role: string; email: string; phone: string; confirmed_at?: string | null | undefined; email_confirmed_at?: string | null | undefined; last_sign_in_at?: string | null | undefined; app_metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; identities: { identity_id: string; id: string; user_id: string; identity_data: { [x: string]: hono_utils_types.JSONValue; }; provider: string; last_sign_in_at: string | null; created_at: string; updated_at: string; email?: string | undefined; }[]; created_at: string; updated_at: string; is_anonymous: boolean; new_email?: string | undefined; confirmation_sent_at?: string | null | undefined; email_change_sent_at?: string | null | undefined; recovery_sent_at?: string | null | undefined; }; outputFormat: "json"; status: 200; }; }; } & { "/user": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/reauthenticate": { $get: { input: {}; output: {}; outputFormat: "json"; status: 200; }; }; } & { "/reauthenticate": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; }, "/auth/v1"> | hono_types.MergeSchemaPath<{ "/rpc/:function": { $all: { input: { param: { function: string; }; }; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/:relation": { $all: { input: { param: { relation: string; }; }; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "*": { $all: { input: {}; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; }, "/rest/v1"> | hono_types.MergeSchemaPath | hono_types.MergeSchemaPath<{ "/bucket": { $post: { input: { json: { [x: string]: unknown; public?: boolean | undefined; file_size_limit?: number | undefined; allowed_mime_types?: string[] | undefined; id: string; name: string; }; }; output: { name: string; }; outputFormat: "json"; status: 200; }; }; } & { "/bucket": { $get: { input: {}; output: { id: string; name: string; owner: string | null; owner_id: string | null; public: boolean; file_size_limit: number | null; allowed_mime_types: string[] | null; created_at: string; updated_at: string; }[]; outputFormat: "json"; status: 200; }; }; } & { "/bucket/:id": { $get: { input: { param: { id: string; }; }; output: { id: string; name: string; owner: string | null; owner_id: string | null; public: boolean; file_size_limit: number | null; allowed_mime_types: string[] | null; created_at: string; updated_at: string; }; outputFormat: "json"; status: 200; }; }; } & { "/bucket/:id": { $put: { input: { json: { [x: string]: unknown; public?: boolean | undefined; file_size_limit?: number | undefined; allowed_mime_types?: string[] | undefined; }; } & { param: { id: string; }; }; output: { message: string; }; outputFormat: "json"; status: 200; }; }; } & { "/bucket/:id": { $delete: { input: { param: { id: string; }; }; output: { message: string; }; outputFormat: "json"; status: 200; }; }; } & { "/bucket/:id/empty": { $post: { input: { param: { id: string; }; }; output: { message: string; }; outputFormat: "json"; status: 200; }; }; } & { "/object/list/:bucketId": { $post: { input: { json: { [x: string]: unknown; search?: string | undefined; sortBy?: { [x: string]: unknown; column: string; order: string; } | undefined; limit?: number | undefined; offset?: number | undefined; prefix?: string | undefined; }; } & { param: { bucketId: string; }; }; output: { id: string; bucket_id: string; name: string; owner: string | null; owner_id: string | null; metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; path_tokens: string[]; version: string | null; created_at: string; updated_at: string; last_accessed_at: string; }[]; outputFormat: "json"; status: 200; }; }; } & { "/object/move": { $post: { input: { json: { [x: string]: unknown; bucketId: string; sourceKey: string; destinationKey: string; }; }; output: { message: string; }; outputFormat: "json"; status: 200; }; }; } & { "/object/copy": { $post: { input: { json: { [x: string]: unknown; bucketId: string; sourceKey: string; destinationKey: string; }; }; output: { key: string; }; outputFormat: "json"; status: 200; }; }; } & { "/object/info/:bucketId/*": { $get: { input: { param: { bucketId: string; }; }; output: { id: string; bucket_id: string; name: string; owner: string | null; owner_id: string | null; metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; path_tokens: string[]; version: string | null; created_at: string; updated_at: string; last_accessed_at: string; httpMetadata: { cacheControl: string; contentLength: number; size: number; mimetype: string; lastModified?: string | undefined; eTag: string; contentRange?: string | undefined; httpStatusCode?: number | undefined; }; }; outputFormat: "json"; status: 200; }; }; } & { "/object/sign/:bucketId/*": { $post: { input: { json: { [x: string]: unknown; expiresIn: number; }; } & { param: { bucketId: string; }; }; output: { signedUrl: string; }; outputFormat: "json"; status: 200; }; }; } & { "/object/sign/:bucketId": { $post: { input: { json: { [x: string]: unknown; expiresIn: number; paths: string[]; }; } & { param: { bucketId: string; }; }; output: { path: string; signedUrl: string; error: string | null; }[]; outputFormat: "json"; status: 200; }; }; } & { "/object/upload/sign/:bucketId/*": { $post: { input: { param: { bucketId: string; }; }; output: { signedUrl: string; token: string; path: string; }; outputFormat: "json"; status: 200; }; }; } & { "/object/:bucketId": { $delete: { input: { json: { [x: string]: unknown; prefixes: string[]; }; } & { param: { bucketId: string; }; }; output: { id: string; bucket_id: string; name: string; owner: string | null; owner_id: string | null; metadata: { [x: string]: hono_utils_types.JSONValue; }; user_metadata: { [x: string]: hono_utils_types.JSONValue; }; path_tokens: string[]; version: string | null; created_at: string; updated_at: string; last_accessed_at: string; }[]; outputFormat: "json"; status: 200; }; }; } & { "/object/:bucketId/*": { $post: { input: { param: { bucketId: string; }; }; output: { Key: string; Id: string; }; outputFormat: "json"; status: 200; }; }; } & { "/object/:bucketId/*": { $put: { input: { param: { bucketId: string; }; }; output: { Key: string; Id: string; }; outputFormat: "json"; status: 200; }; }; } & { "/object/:bucketId/*": { $get: { input: { param: { bucketId: string; }; }; output: {}; outputFormat: string; status: hono_utils_http_status.StatusCode; }; }; } & { "/object/:bucketId/*": { $head: { input: { param: { bucketId: string; }; }; output: null; outputFormat: "body"; status: 200; } | { input: { param: { bucketId: string; }; }; output: null; outputFormat: "body"; status: 404; }; }; }, "/">, "/storage/v1"> | hono_types.MergeSchemaPath<{ "/ping": { $get: { input: {}; output: { message: string; }; outputFormat: "json"; status: hono_utils_http_status.ContentfulStatusCode; }; }; } & { "/config": { $get: { input: {}; output: {}; outputFormat: "json"; status: hono_utils_http_status.ContentfulStatusCode; }; }; } & { "/info": { $get: { input: {}; output: { connection: any; config: any; admin: boolean; }; outputFormat: "json"; status: hono_utils_http_status.ContentfulStatusCode; }; }; } & { "/introspect": { $get: { input: {}; output: { tables: { name: string; sql: string; schema: string; type: "table" | "view"; rows: number; engine: string; collation: string; }[]; columns: { table: string; name: string; type: string; nullable: boolean; default_value: string | null; is_primary_key: boolean; schema: string; ordinal_position: number; collation: string; character_maximum_length: string | null; precision: { precision: number | null; scale: number | null; } | null; is_identity: boolean; pg_type?: string | undefined; udt_schema?: string | undefined; is_generated?: boolean | undefined; }[]; indexes: { table: string; name: string; unique: boolean; columns: string[]; schema: string; }[]; foreign_keys: { table: string; column: string; ref_table: string; ref_column: string; on_update: string; on_delete: string; schema: string; ref_schema?: string | undefined; foreign_key_name: string; foreign_key_group?: string | undefined; fk_def: string; is_visible?: boolean | undefined; }[]; primary_keys: { table: string; columns: string[]; schema: string; field_count: number; }[]; views: { name: string; sql: string; schema: string; }[]; check_constraints: { schema: string; table: string; expression: string; name?: string | undefined; column?: string | undefined; }[]; unique_constraints: { schema: string; table: string; name: string; columns: string[]; }[]; comments: { schema: string; table: string; column?: string | undefined; text: string; }[]; custom_types: { schema: string; type: string; kind: "enum" | "composite"; values?: string[] | undefined; fields?: { name: string; type: string; }[] | undefined; }[]; triggers: { table: string; name: string; sql: string; schema: string; }[]; functions?: { schema: string; name: string; arg_names: string[]; arg_types: string[]; arg_defaults: number; has_variadic: boolean; volatility: string; return_type: string; return_is_setof: boolean; return_rows?: number | undefined; return_typtype: string; return_base_type?: string | undefined; has_out_args: boolean; }[] | undefined; partitions?: { name: string; schema: string; parent: string; }[] | undefined; database_name: string; version: string; ddl_dialect?: "postgres" | "sqlite" | undefined; schema_separator?: string | undefined; default_schema?: string | undefined; timezones?: readonly string[] | undefined; }; outputFormat: "json"; status: hono_utils_http_status.ContentfulStatusCode; }; }; }, "/_system">, "/", "*">; type Where = Record; type PolicyCommand = "SELECT" | "INSERT" | "UPDATE" | "DELETE" | "ALL"; type PolicyRole = "anon" | "authenticated" | string; interface PolicyData { name: string; table: string; schema?: string; command: PolicyCommand; permissive: boolean; roles: PolicyRole[]; using?: Where; withCheck?: Where; } declare class Policy { readonly data: PolicyData; constructor(data: PolicyData); appliesTo(cmd: "SELECT" | "INSERT" | "UPDATE" | "DELETE"): boolean; appliesToRole(role: string): boolean; toJSON(): PolicyData; static fromJSON(data: PolicyData): Policy; } interface IAppConfig extends DefaultSchema { connection: Connection | Promise; rls?: { tables: string[]; policies: Policy[]; }; options?: { /** * Disable default config values from being applied. */ defaults?: boolean; server?: ServerOptions; drivers?: PartialAppDrivers; system?: SystemOptions; }; } interface SystemOptions { /** * How `ensureSystemSchema()` reconciles system schemas against config: * `"additive"` (default) only creates missing tables/columns; `"full"` also * drops system tables removed from an enabled module's schema (data-loss * steps require `force`). */ schemaReconciliation?: "additive" | "full"; } interface DefaultAppConfig extends IAppConfig { connection: Connection; options?: { defaults?: true; server?: ServerOptions; drivers?: PartialAppDrivers; system?: SystemOptions; }; } declare class App ? Awaited : Connection : never> { #private; private readonly _connection; private readonly _rls; readonly config: DefaultSchema & Omit; readonly server: ReturnType; /** * Resolved local admin mode, after CLI-flag / config-file precedence. Read * this (never the raw CLI flag) when reporting what the server is doing. */ readonly adminMode: boolean; readonly drivers: AppDrivers; _mailer?: Mailer; _storageAdapter?: StorageAdapter; _transformationAdapter?: TransformationAdapter; constructor({ connection, options, rls, ...config }: Config); get connection(): Conn; /** * Initialize the app. This is called automatically on first request. */ init(): Promise; /** * Provision the enabled system schemas (auth / storage / migration-history) * on the connected database with NO filesystem access — the runtime entry * point for non-CLI consumers (e.g. a lite-platform Durable Object) and the * shared provisioning path for the CLI (LITE-291). Reconciles ONLY the system * schemas, so user-land tables are never touched. The reconciliation mode * comes from `options.system.schemaReconciliation` (default `"additive"`). * * @param opts.force allow data-loss drops in `"full"` mode (else throws * `DataLossError`). */ ensureSystemSchema(opts?: { force?: boolean; }): Promise; isValidConfig(config: Schema | DefaultSchema | IAppConfig): boolean; getClient(options?: SupabaseClientOptions & { apikey?: string; }): _supabase_supabase_js.SupabaseClient[SchemaName] extends { Tables: Record; Insert: Record; Update: Record; Relationships: { foreignKeyName: string; columns: string[]; isOneToOne?: boolean; referencedRelation: string; referencedColumns: string[]; }[]; }>; Views: Record; Insert: Record; Update: Record; Relationships: { foreignKeyName: string; columns: string[]; isOneToOne?: boolean; referencedRelation: string; referencedColumns: string[]; }[]; } | { Row: Record; Relationships: { foreignKeyName: string; columns: string[]; isOneToOne?: boolean; referencedRelation: string; referencedColumns: string[]; }[]; }>; Functions: Record | never; Returns: unknown; SetofOptions?: { isSetofReturn?: boolean | undefined; isOneToOne?: boolean | undefined; isNotNullable?: boolean | undefined; to: string; from: string; }; }>; } ? Omit[SchemaName] : never, any>; isLocalRequest(request: Request): boolean; fetch: (request: Request) => Promise; getInfoJson(): { connection: object; config: Config; }; } declare const DEFAULT_PREFIXES: string[]; declare function honoMiddleware(app: App, prefixes?: string[]): Connect.NextHandleFunction; type SupaliteOptions = { config?: string; migrateOnBoot?: boolean; watchSchema?: boolean; forceSchema?: boolean; initOnBoot?: boolean; prefixes?: string[]; /** * Local admin mode (default `true`): keyless, same-origin, loopback * requests from the dev server run as `service_role`. In practice that * means `/rest/v1` here — admin mode also covers `/storage/v1`, but this * plugin does not mount that prefix unless you add it to `prefixes`. * * See `ServerOptions.admin` for the caveats. Never applied in * `vite preview`, which serves a production build; an explicit value here * also outranks `options.server.admin` in `config.toml`. */ admin?: boolean; }; declare function supalite(options?: SupaliteOptions): Plugin; export { DEFAULT_PREFIXES, type SupaliteOptions, supalite as default, honoMiddleware, supalite };