From 560d133d5aca4976790d34214d3d75473ab309ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Tue, 19 May 2026 04:03:38 +0100 Subject: [PATCH 1/5] feat(server): passkey (WebAuthn) auth + auth-config flags for local-mode routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two additions on top of the local-first refactor (#902): 1. @better-auth/passkey plugin enabled in auth/index.tsx ------------------------------------------------------- The operator signs up once with email+password, then can enroll a passkey (Touch ID / Face ID / hardware key) for biometric sign-in. The plugin's default `requireSession: true` for registration is kept — this PR adds the sign-in side; post-signup enrollment UI is a small follow-up. Codex review caught two subtle bugs: - `origin: resolveBaseUrl({ request })` would freeze the WebAuthn origin onto the first request that constructed the cached BA instance — request from localhost could poison passkey for a subsequent Tailscale request. Now `origin: null` (plugin reads the request Origin header at verification time). - `rpID: new URL(resolveBaseUrl({ request })).hostname` had the same freezing problem. Now derived from `PUBLIC_WEB_URL` env (stable per deployment), defaults to "localhost" for local-mode. Migration db/migrations/20260519000000_passkey_table.sql creates the `passkey` table with the schema @better-auth/passkey's adapter expects: publicKey, credentialID, counter, deviceType, backedUp, transports, aaguid. FK userId → user(id) ON DELETE CASCADE. 2. /api/auth-config extended with passkey + singleUserMode + hasUser -------------------------------------------------------------------- SPA currently reads auth-config to gate visible providers (magic-link, social, email-password). After #902 it also needs to know: - `passkey: true` — plugin is always wired, so the SPA can render the Sign-in-with-passkey button unconditionally. - `singleUserMode: env.LOBU_SINGLE_USER === '1'` — drives the SPA's copy + routing for local-first installs. - `hasUser`: SELECT EXISTS(SELECT 1 FROM "user" WHERE id <> 'bootstrap-user') — when singleUserMode + !hasUser, SPA forces /sign-up; when +hasUser, forces /sign-in. Filters out the legacy bootstrap-user row so an install that still has it pre-#902 isn't mis-routed. Submodule bump -------------- packages/owletto → feat/passkey-client (lobu-ai/owletto#8c6c283): - authClient wires passkeyClient(). - login.tsx renders the Sign-in-with-passkey button + checks result.error (third codex finding: BA client returns failure as result.error, not via throw). - login.tsx auto-toggles authIntent based on singleUserMode + hasUser. Verified: - `make typecheck` clean. - `bun test packages/server/src/__tests__/unit` — 201 pass, 0 fail. - Codex reviewed; 3 findings (origin freeze, rpID freeze, result.error not inspected) all fixed before push. Not in this PR (deferred): - Post-signup passkey enrollment prompt — operator needs to sign up with password first, then go to /settings to add a passkey. A one-click "enrol now?" after first sign-up is a follow-up. - Passkey-only signup (no password at all) — requires the plugin's custom `resolveUser` callback + a user-create hook. Bigger lift. --- bun.lock | 18 +++++----- .../20260519000000_passkey_table.sql | 32 +++++++++++++++++ packages/owletto | 2 +- packages/server/package.json | 1 + packages/server/src/auth/config.ts | 33 ++++++++++++++++- packages/server/src/auth/index.tsx | 36 +++++++++++++++++++ 6 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 db/migrations/20260519000000_passkey_table.sql diff --git a/bun.lock b/bun.lock index 515aacf2f..4931af79b 100644 --- a/bun.lock +++ b/bun.lock @@ -17,7 +17,7 @@ }, "packages/agent-worker": { "name": "@lobu/worker", - "version": "7.0.0", + "version": "7.2.0", "bin": { "lobu-worker": "./dist/index.js", }, @@ -44,7 +44,7 @@ }, "packages/cli": { "name": "@lobu/cli", - "version": "7.0.0", + "version": "7.2.0", "bin": { "lobu": "bin/lobu.js", }, @@ -126,7 +126,7 @@ }, "packages/connector-sdk": { "name": "@lobu/connector-sdk", - "version": "7.0.0", + "version": "7.2.0", "dependencies": { "@lobu/core": "workspace:*", "@sinclair/typebox": "^0.34.41", @@ -147,7 +147,7 @@ }, "packages/connector-worker": { "name": "@lobu/connector-worker", - "version": "7.0.0", + "version": "7.2.0", "bin": { "connector-worker": "./dist/bin.js", }, @@ -170,7 +170,7 @@ }, "packages/connectors": { "name": "@lobu/connectors", - "version": "7.0.0", + "version": "7.2.0", "dependencies": { "@lobu/connector-sdk": "workspace:*", "baileys": "7.0.0-rc.9", @@ -184,7 +184,7 @@ }, "packages/core": { "name": "@lobu/core", - "version": "7.0.0", + "version": "7.2.0", "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.57.0", @@ -203,7 +203,7 @@ }, "packages/embeddings": { "name": "@lobu/embeddings", - "version": "7.0.0", + "version": "7.2.0", "dependencies": { "@hono/node-server": "^1.13.7", "@xenova/transformers": "^2.17.2", @@ -234,7 +234,7 @@ }, "packages/openclaw-plugin": { "name": "@lobu/openclaw-plugin", - "version": "7.0.0", + "version": "7.2.0", "devDependencies": { "@types/node": "^20.10.0", "postgres": "^3.4.7", @@ -247,6 +247,7 @@ "version": "1.6.0", "dependencies": { "@assistant-ui/react": "^0.14.0", + "@better-auth/passkey": "^1.6.9", "@codemirror/autocomplete": "^6.20.0", "@codemirror/commands": "^6.10.2", "@codemirror/lang-json": "^6.0.2", @@ -320,6 +321,7 @@ "@anthropic-ai/sdk": "^0.90.0", "@aws-sdk/client-bedrock": "^3.1028.0", "@aws-sdk/client-secrets-manager": "^3.1028.0", + "@better-auth/passkey": "^1.6.9", "@chat-adapter/discord": "4.26.0", "@chat-adapter/gchat": "4.26.0", "@chat-adapter/slack": "4.26.0", diff --git a/db/migrations/20260519000000_passkey_table.sql b/db/migrations/20260519000000_passkey_table.sql new file mode 100644 index 000000000..67fa2a253 --- /dev/null +++ b/db/migrations/20260519000000_passkey_table.sql @@ -0,0 +1,32 @@ +-- migrate:up + +-- Adds the `passkey` table required by @better-auth/passkey. Each row is a +-- WebAuthn credential: bound to a user, identified by `credential_id` (the +-- credential's external id the browser reports), with `public_key` used to +-- verify subsequent authentication assertions. `counter` is the WebAuthn +-- signCount used to detect cloned authenticators. +-- +-- Stored separately from `account` because account.providerId is unique-per- +-- user-per-provider, but a user can have many passkeys (one per +-- device/browser). + +CREATE TABLE IF NOT EXISTS "passkey" ( + id TEXT PRIMARY KEY, + name TEXT, + "publicKey" TEXT NOT NULL, + "userId" TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + "credentialID" TEXT NOT NULL, + counter BIGINT NOT NULL DEFAULT 0, + "deviceType" TEXT NOT NULL, + "backedUp" BOOLEAN NOT NULL DEFAULT FALSE, + transports TEXT, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(), + aaguid TEXT +); + +CREATE INDEX IF NOT EXISTS passkey_user_id_idx ON "passkey"("userId"); +CREATE INDEX IF NOT EXISTS passkey_credential_id_idx ON "passkey"("credentialID"); + +-- migrate:down + +DROP TABLE IF EXISTS "passkey"; diff --git a/packages/owletto b/packages/owletto index 0275737be..8c6c283da 160000 --- a/packages/owletto +++ b/packages/owletto @@ -1 +1 @@ -Subproject commit 0275737be28ba12011d3e23b5e35acbbbb928c04 +Subproject commit 8c6c283dacb5f755ab044629af00d2b014fb8632 diff --git a/packages/server/package.json b/packages/server/package.json index 7978c37ef..03251c6a6 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -47,6 +47,7 @@ "@sinclair/typebox": "^0.34.41", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", + "@better-auth/passkey": "^1.6.9", "better-auth": "^1.4.10", "chat": "^4.26.0", "commander": "^14.0.1", diff --git a/packages/server/src/auth/config.ts b/packages/server/src/auth/config.ts index e86c26f31..81b1d8b49 100644 --- a/packages/server/src/auth/config.ts +++ b/packages/server/src/auth/config.ts @@ -9,6 +9,15 @@ interface AuthConfig { magicLink: boolean; phone: boolean; emailPassword: boolean; + passkey: boolean; + // True iff this deployment runs in single-user mode (LOBU_SINGLE_USER=1). + // The SPA branches signup/sign-in copy on this — "Set up your local install" + // vs "Sign up for Lobu" — and skips affordances that don't apply. + singleUserMode: boolean; + // True iff at least one (non-legacy-bootstrap) user already exists. The SPA + // routes `/` → /sign-up when this is false in single-user mode, so the + // operator lands on the right page on first launch without typing a URL. + hasUser: boolean; } type TokenEndpointAuthMethod = 'client_secret_post' | 'client_secret_basic' | 'none'; @@ -400,6 +409,28 @@ export async function getAuthConfig( const hasProviderAuthEnabled = Object.values(social).some(Boolean) || phone; const emailPassword = hasValue(env.BETTER_AUTH_SECRET) || (!isProduction && !hasProviderAuthEnabled); + // Passkey plugin is always wired (auth/index.tsx) — the gateway can verify + // WebAuthn ceremonies regardless of env config. + const passkey = true; + const singleUserMode = env.LOBU_SINGLE_USER === '1'; + // Filter out the legacy bootstrap-user (pre-PR #902) — it doesn't count as + // "the install has a user." Real users include anyone signed up via the web + // UI after that PR. + let hasUser = false; + try { + const sql = getDb(); + const rows = (await sql` + SELECT EXISTS( + SELECT 1 FROM "user" WHERE id <> 'bootstrap-user' + ) AS has_user + `) as unknown as Array<{ has_user: boolean }>; + hasUser = !!rows[0]?.has_user; + } catch { + // If the DB isn't reachable (very early boot / migrations still running), + // fail closed: treat as "no user yet" so the SPA shows /sign-up. Worst + // case is one extra page transition when the operator clicks something. + hasUser = false; + } - return { social, magicLink, phone, emailPassword }; + return { social, magicLink, phone, emailPassword, passkey, singleUserMode, hasUser }; } diff --git a/packages/server/src/auth/index.tsx b/packages/server/src/auth/index.tsx index 1752c9204..e0d59341e 100644 --- a/packages/server/src/auth/index.tsx +++ b/packages/server/src/auth/index.tsx @@ -1,4 +1,5 @@ import { createHash } from "node:crypto"; +import { passkey } from "@better-auth/passkey"; import { APIError, betterAuth } from "better-auth"; import { magicLink, organization, phoneNumber } from "better-auth/plugins"; import { bearer } from "better-auth/plugins/bearer"; @@ -513,6 +514,41 @@ export async function createAuth(env: Env, request?: Request) { otpLength: 6, expiresIn: 60 * 5, // 5 minutes }), + // WebAuthn / passkey support. Especially useful in local-mode + // (LOBU_SINGLE_USER=1) where Touch ID / Face ID is a much cleaner + // auth than "remember the password you typed at /sign-up." Default + // `requireSession: true` for registration means the operator + // signs up with email+password first, then enrolls a passkey from + // settings (or a post-signup prompt). Sign-in then offers + // "Sign in with passkey" as a one-tap biometric option. + // + // rpID = the hostname WebAuthn binds the credential to. Pulled + // from PUBLIC_WEB_URL (env), NOT from resolveBaseUrl(request) — + // resolveBaseUrl reflects the request that happened to construct + // this BA instance, and createAuth() is cached for 60s, so a + // request from one host could freeze the rpID for the next host's + // request. PUBLIC_WEB_URL is stable per-deployment. + // + // origin defaults to the request Origin header — handled by the + // plugin itself when we pass `null`. That keeps WebAuthn-side + // origin verification accurate for Vite dev (SPA on a different + // port than the API) and prod. + passkey({ + rpID: (() => { + const publicWebUrl = process.env.PUBLIC_WEB_URL?.trim(); + if (publicWebUrl) { + try { + const host = new URL(publicWebUrl).hostname; + if (host) return host; + } catch { + /* fallthrough to default */ + } + } + return "localhost"; + })(), + rpName: "Lobu", + origin: null, + }), ], databaseHooks: { From f8f41d65c865fbadafe37fbd03816eb3730fda69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Tue, 19 May 2026 04:12:10 +0100 Subject: [PATCH 2/5] fix: passkey schema snapshot + cli runtime dep CI catches: 1. db/schema.sql must match `dbmate up` output (Schema snapshot drift check). My branch added a migration that creates the `passkey` table but forgot to regenerate db/schema.sql. 2. CLI declares the runtime deps the embedded server bundle pulls at start (dev.test.ts 'CLI package declares runtime deps'). Adding @better-auth/passkey to packages/server/* needs the matching entry in packages/cli/package.json so `lobu run` can resolve it. Hand-edited db/schema.sql to insert only the four passkey blocks (CREATE TABLE, PK, two INDEXes, FK) at the alphabetically correct positions. Avoided a full `make db-schema` regen because my local Postgres has postgis enabled (not in CI's pg16 image) so a full regen would also add postgis extension + geo_lookup function rows that shouldn't be in the snapshot. --- bun.lock | 1 + db/schema.sql | 44 +++++++++++++++++++++++++++++++++++++++ packages/cli/package.json | 1 + 3 files changed, 46 insertions(+) diff --git a/bun.lock b/bun.lock index 4931af79b..72a5560d0 100644 --- a/bun.lock +++ b/bun.lock @@ -52,6 +52,7 @@ "@anthropic-ai/sdk": "^0.90.0", "@aws-sdk/client-bedrock": "^3.1028.0", "@aws-sdk/client-secrets-manager": "^3.1028.0", + "@better-auth/passkey": "^1.6.9", "@chat-adapter/discord": "4.26.0", "@chat-adapter/gchat": "4.26.0", "@chat-adapter/slack": "4.26.0", diff --git a/db/schema.sql b/db/schema.sql index e35b66671..07960fa80 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -1517,6 +1517,24 @@ CREATE SEQUENCE public.personal_access_tokens_id_seq ALTER SEQUENCE public.personal_access_tokens_id_seq OWNED BY public.personal_access_tokens.id; +-- +-- Name: passkey; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.passkey ( + id text NOT NULL, + name text, + "publicKey" text NOT NULL, + "userId" text NOT NULL, + "credentialID" text NOT NULL, + counter bigint DEFAULT 0 NOT NULL, + "deviceType" text NOT NULL, + "backedUp" boolean DEFAULT false NOT NULL, + transports text, + "createdAt" timestamp with time zone DEFAULT now() NOT NULL, + aaguid text +); + -- -- Name: rate_limits; Type: TABLE; Schema: public; Owner: - -- @@ -2722,6 +2740,13 @@ ALTER TABLE ONLY public.personal_access_tokens ALTER TABLE ONLY public.personal_access_tokens ADD CONSTRAINT personal_access_tokens_token_hash_key UNIQUE (token_hash); +-- +-- Name: passkey passkey_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.passkey + ADD CONSTRAINT passkey_pkey PRIMARY KEY (id); + -- -- Name: rate_limits rate_limits_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -4144,6 +4169,18 @@ CREATE INDEX personal_access_tokens_token_prefix_idx ON public.personal_access_t CREATE INDEX personal_access_tokens_user_id_idx ON public.personal_access_tokens USING btree (user_id); +-- +-- Name: passkey_credential_id_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX passkey_credential_id_idx ON public.passkey USING btree ("credentialID"); + +-- +-- Name: passkey_user_id_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX passkey_user_id_idx ON public.passkey USING btree ("userId"); + -- -- Name: rate_limits_expires_at_idx; Type: INDEX; Schema: public; Owner: - -- @@ -4930,6 +4967,13 @@ ALTER TABLE ONLY public.runs ALTER TABLE ONLY public.runs ADD CONSTRAINT runs_feed_id_fkey FOREIGN KEY (feed_id) REFERENCES public.feeds(id) ON DELETE SET NULL; +-- +-- Name: passkey passkey_userId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.passkey + ADD CONSTRAINT "passkey_userId_fkey" FOREIGN KEY ("userId") REFERENCES public."user"(id) ON DELETE CASCADE; + -- -- Name: runs runs_organization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- diff --git a/packages/cli/package.json b/packages/cli/package.json index f8f241b6b..2317abbae 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -61,6 +61,7 @@ "@sinclair/typebox": "^0.34.41", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", + "@better-auth/passkey": "^1.6.9", "better-auth": "^1.4.10", "chalk": "^5.3.0", "chat": "^4.26.0", From dcabd5dda158d22c964b858f08af2fbd1d171671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Tue, 19 May 2026 04:22:32 +0100 Subject: [PATCH 3/5] fix(schema): place passkey blocks alphabetically to match dbmate output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous patch put the passkey table after personal_access_tokens, but 'passkey' < 'pending_interactions' < 'personal_access_tokens' alphabetically — dbmate's pg_dump emits them in alpha order, so CI's schema-drift check flagged the mis-positioning. Re-anchored each block: - TABLE: before pending_interactions - PK CONSTRAINT: before pending_interactions_pkey - INDEXes: before personal_access_tokens_active_idx (after oauth_tokens_*) - FK CONSTRAINT: before pending_interactions_organization_id_fkey --- db/schema.sql | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/db/schema.sql b/db/schema.sql index 07960fa80..120664ccf 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -1453,6 +1453,24 @@ CREATE TABLE public.organization_lobu_links ( updated_at timestamp with time zone DEFAULT now() NOT NULL ); +-- +-- Name: passkey; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.passkey ( + id text NOT NULL, + name text, + "publicKey" text NOT NULL, + "userId" text NOT NULL, + "credentialID" text NOT NULL, + counter bigint DEFAULT 0 NOT NULL, + "deviceType" text NOT NULL, + "backedUp" boolean DEFAULT false NOT NULL, + transports text, + "createdAt" timestamp with time zone DEFAULT now() NOT NULL, + aaguid text +); + -- -- Name: pending_interactions; Type: TABLE; Schema: public; Owner: - -- @@ -2719,6 +2737,13 @@ ALTER TABLE ONLY public.organization ALTER TABLE ONLY public.organization ADD CONSTRAINT organization_slug_key UNIQUE (slug); +-- +-- Name: passkey passkey_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.passkey + ADD CONSTRAINT passkey_pkey PRIMARY KEY (id); + -- -- Name: pending_interactions pending_interactions_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -4139,6 +4164,18 @@ CREATE INDEX oauth_tokens_token_hash_idx ON public.oauth_tokens USING btree (tok CREATE INDEX oauth_tokens_user_id_idx ON public.oauth_tokens USING btree (user_id); +-- +-- Name: passkey_credential_id_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX passkey_credential_id_idx ON public.passkey USING btree ("credentialID"); + +-- +-- Name: passkey_user_id_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX passkey_user_id_idx ON public.passkey USING btree ("userId"); + -- -- Name: personal_access_tokens_active_idx; Type: INDEX; Schema: public; Owner: - -- @@ -4918,6 +4955,13 @@ ALTER TABLE ONLY public.organization_lobu_links ALTER TABLE ONLY public.organization_lobu_links ADD CONSTRAINT organization_lobu_links_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES public.organization(id) ON DELETE CASCADE; +-- +-- Name: passkey passkey_userId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.passkey + ADD CONSTRAINT "passkey_userId_fkey" FOREIGN KEY ("userId") REFERENCES public."user"(id) ON DELETE CASCADE; + -- -- Name: pending_interactions pending_interactions_organization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- From 07a0c5e52863178e1c5eb58398c7560424f4b3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Tue, 19 May 2026 04:23:27 +0100 Subject: [PATCH 4/5] chore(submodule): bump owletto to d5ae2a4 (passkey-client merged) --- packages/owletto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/owletto b/packages/owletto index 8c6c283da..d5ae2a44d 160000 --- a/packages/owletto +++ b/packages/owletto @@ -1 +1 @@ -Subproject commit 8c6c283dacb5f755ab044629af00d2b014fb8632 +Subproject commit d5ae2a44d5e7f19ec6c04f646f2c75fcbfa76949 From d3c7466f7604a5fe2c851301322c8d9d5af18ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Tue, 19 May 2026 04:29:02 +0100 Subject: [PATCH 5/5] fix(schema): rebuild passkey delta against fresh origin/main schema Previous attempts left duplicate passkey blocks: re-patching after git checkout but before merge layered the new blocks on top of the old wrong-position ones. Reset db/schema.sql to origin/main's clean state, then spliced the 4 passkey blocks once at the correct positions (alphabetical: passkey < pending_interactions < personal_access_tokens) + inserted the 20260519000000 row in INSERT INTO schema_migrations. --- db/schema.sql | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/db/schema.sql b/db/schema.sql index b4c1c8682..a8d8a3ccf 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -1627,24 +1627,6 @@ CREATE SEQUENCE public.personal_access_tokens_id_seq ALTER SEQUENCE public.personal_access_tokens_id_seq OWNED BY public.personal_access_tokens.id; --- --- Name: passkey; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.passkey ( - id text NOT NULL, - name text, - "publicKey" text NOT NULL, - "userId" text NOT NULL, - "credentialID" text NOT NULL, - counter bigint DEFAULT 0 NOT NULL, - "deviceType" text NOT NULL, - "backedUp" boolean DEFAULT false NOT NULL, - transports text, - "createdAt" timestamp with time zone DEFAULT now() NOT NULL, - aaguid text -); - -- -- Name: rate_limits; Type: TABLE; Schema: public; Owner: - -- @@ -2913,13 +2895,6 @@ ALTER TABLE ONLY public.personal_access_tokens ALTER TABLE ONLY public.personal_access_tokens ADD CONSTRAINT personal_access_tokens_token_hash_key UNIQUE (token_hash); --- --- Name: passkey passkey_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.passkey - ADD CONSTRAINT passkey_pkey PRIMARY KEY (id); - -- -- Name: rate_limits rate_limits_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -4385,18 +4360,6 @@ CREATE INDEX personal_access_tokens_token_prefix_idx ON public.personal_access_t CREATE INDEX personal_access_tokens_user_id_idx ON public.personal_access_tokens USING btree (user_id); --- --- Name: passkey_credential_id_idx; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX passkey_credential_id_idx ON public.passkey USING btree ("credentialID"); - --- --- Name: passkey_user_id_idx; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX passkey_user_id_idx ON public.passkey USING btree ("userId"); - -- -- Name: rate_limits_expires_at_idx; Type: INDEX; Schema: public; Owner: - -- @@ -5196,13 +5159,6 @@ ALTER TABLE ONLY public.runs ALTER TABLE ONLY public.runs ADD CONSTRAINT runs_feed_id_fkey FOREIGN KEY (feed_id) REFERENCES public.feeds(id) ON DELETE SET NULL; --- --- Name: passkey passkey_userId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.passkey - ADD CONSTRAINT "passkey_userId_fkey" FOREIGN KEY ("userId") REFERENCES public."user"(id) ON DELETE CASCADE; - -- -- Name: runs runs_organization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - --