| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
refactor(corsair): record connect requests in corsair_events, drop corsair_connects (#1463) * refactor(corsair): record connect requests in corsair_events, drop corsair_connects Route connect-request writes into the append-only corsair_events log instead of a dedicated corsair_connects table: - record -> append a connect.request event (payload {plugin, connectUrl}) - read -> newest connect.request across the tenant's accounts, within TTL, unless a newer connect.cleared tombstone supersedes it - clear -> append a connect.cleared tombstone (no mutation/delete) Account FK resolved from (tenant, plugin); setup/ensurePluginRows guarantees the account row exists before a link is minted. Removes the CorsairConnect kysely type, orm/schema entries, the REQUIRED_TABLES registration, and the test DDL. The client HTTP contract (/connect/request, /connect/request/clear) is unchanged. * docs: drop corsair_connects, note connect prompts live in corsair_events * fix(connect): per-plugin connect requests, one-at-a-time FIFO readConnectRequest now scans each account's latest connect event with a bounded per-plugin query and returns the oldest live one (FIFO), so a later plugin failure can't shadow an earlier one. A same-timestamp connect.cleared beats a connect.request via a CASE tiebreak, keeping the prompt suppressed. clearConnectRequest takes a plugin arg and tombstones only that plugin; the handler, client, and React provider thread it through. Index corsair_events(account_id, event_type, created_at) so the per-plugin read is an index seek, not a log scan. * fix(connect): monotonic connect-event timestamps so re-request after clear wins Same-ms clear-then-request kept the prompt suppressed because the CASE tiebreak always let connect.cleared win; event_type can't encode append order. Stamp each connect event's created_at with max(now, latest+1) per account for a strict total order, then read newest by created_at alone. * chore(corsair): bump version to 0.1.127 in package.json | 19 天前 | |
feat(connect): Corsair Connect — in-app OAuth flow for end users (#1209) * fix(auth): treat non-expiring tokens as fresh * feat(auth): add ReconnectRequiredError for hub reconnect responses * feat(react): add CorsairProvider and useConnect connect overlay * feat(react): detect connect completion via popup close and postMessage * fix(react): make connect completion detection correct and self-host-safe Ignore status polls from a closed or superseded connection attempt via an attempt-id guard, so a late poll can no longer settle the wrong promise. Drop the postMessage fast-path. The connect success page cannot pin a target origin to an arbitrary customer app, and the status poll plus popup-close watch already detect completion everywhere, including self-hosted and custom connect pages. * feat(connect): record connect-requests and serve them to the client When a tool call raises auth-missing, the binding writes a per-tenant row to corsair_connect_requests with the plugin and its connect link; the management handler exposes it (GET /connect/request, POST /connect/request/clear), tenant-scoped so end-user mode can't read across tenants. Registered in REQUIRED_TABLES so a missing table warns to run migrations instead of 500ing. * feat(react): Corsair Connect provider, boundary, and dialog Wrap the app once in <CorsairProvider>: an auth-missing failure surfaces a connect dialog and resumes the failed work once connected, with no per-call code at the call sites. <CorsairBoundary> covers server-rendered reads; useConnect exposes the proactive connect() and the call() mutation wrapper. Splits a browser bundle so the dialog renders inside any host app. * docs(database): add the corsair_connect_requests table Document the connect-request table across the SQLite, Postgres, Drizzle, and Prisma migrations and the core-tables reference. * fix(react): tenant-scope the connect watch and stop repeat settles The status poll and connect-request clear now use the tenant the link was minted for, so a proactive connect for a non-default tenant no longer watches the default one. A settled attempt bumps its id before running effects, so a slower poll from the same attempt can't refresh the router twice, and unmount tears down the popup, timers, and any waiting promise. PluginIcon resets its source when the domain changes so a reused mark never shows the prior brand. * fix(connect): record reconnect requests under the owning tenant, no-store responses recordConnectRequestBestEffort now keys on the error's own tenantId — the tenant the scoped connectUrl belongs to — and falls back to the binding's tenant, so the owner can read its own pending request instead of it landing under `default`. The connect-request GET is served Cache-Control: no-store so a shared cache can't hand one tenant's connect link to another browser. * build(corsair): clean dist with a portable command rm -rf isn't available under cmd.exe, so the pre-tsup clean broke Windows builds. Use node's fs.rmSync, which runs on every platform. * fix(react): end the connect attempt when the popup is blocked window.open returns null when the browser blocks the popup; the watcher then never settles because there is no window to observe, so connect() hung. Guard it — end the attempt so the promise resolves and the caller can retry. Also correct the call() contract docs: it retries whenever a connect-request is pending (the server records that across the RSC boundary where the typed error is lost), so it is documented for connect-gated or retry-safe mutations. * fix(react): confirm the connection before treating a closed popup as cancel The success page closes the popup only after the connection persists, but the confirming status poll can outrun the grace window. The grace timeout used to settle cancelled outright, so a slow final poll discarded a real success — connect() resolved false though the account connected. It now runs one authoritative status check when the grace fires and settles on the result. Extracted finishConnected/finishCancelled to share that path with the poll. * docs: document Corsair Connect and rebuild the llms.txt index Add a Corsair Connect section to the React adapter page (CorsairProvider, CorsairBoundary, useConnect, and the React-only caveat), and note the typed AuthMissingError / ReconnectRequiredError under error handling. Rebuild both llms.txt files against the current docs: the index had drifted — the Frameworks, Use cases, Workflows, Management, and LLM-gateway sections were missing and one MCP path (openai-agents) no longer exists. Regenerated from the live nav and page frontmatter, with every link verified to resolve. * feat(connect): error.tsx boundary, dialog redesign, post-connect retry - Replace the inline CorsairBoundary with CorsairErrorBoundary wired for a Next error.tsx — the only boundary that catches a Server Component read throw (a nested client boundary never sees it). - Redesign the overlay: rounded card, drop the plus-corner marks and the blueprint dot-grid, and a Clerk-style "Secured by <mark> Corsair" footer. - call(): retry the resumed action with linear backoff so the first run after connect rides out the credential-propagation window instead of surfacing a one-off auth-missing. * feat(connect): global auto-prompt for unwrapped client calls CorsairProvider listens for unhandled promise rejections and opens the dialog when the reason is a Corsair auth-missing / reconnect error, so a plain client-triggered server action prompts to connect with no `call` wrapper at the call site. Wrapped calls are caught upstream and never reach the listener (no double-prompt); server reads still gate through the error boundary. `call` stays the opt-in for auto-resume. On by default; opt out with captureUnhandled={false}. * style(connect): refine dialog type — hierarchy + readable greys Title carries presence via size + tracking rather than black weight, and secondary labels stay at quiet medium weights. Darken the muted/faint tokens so the greyed text (Not now, roster, footer) reads comfortably instead of too pale. * docs(connect): document the shipped Connect model Rewrite the React Connect guide to what ships: the dialog auto-opens for any client call (global capture, no wrapper), `call` adds resume, server reads gate through an error.tsx re-exporting CorsairErrorBoundary, and `connect` stays the proactive path. Drop the old inline <CorsairBoundary>. * refactor(connect): trim internal exports off the react barrel Drop useCorsair + CorsairContextValue from the public client/react entry — they only serve the in-package error boundary, which imports useCorsair from ./provider directly. Delete the dead connectNonce (written on connect, read nowhere) and its now-unused useState import. * feat(connect): unify connection status into useConnections Rename useConnect -> useConnections and fold this user's connection status into it: connections, isConnected(plugin), loading. The provider now owns the status (one fetch on mount) and refetches after every successful connect, so a proactive button reflects reality and never re-prompts an already-connected plugin — no second hook, no manual refetch. Drop the unused status field. Document PluginConnectionState / ConnectionStatus in core so the states are self-explaining, and export PluginConnectionState. * feat(react): mark provider-opened connect links for auto-forward The Hub connect page auto-forwards a single fresh OAuth link straight to sign-in. Tag the popup the provider opens with forward=1 so only those links skip the connect page; cold links (grid, email, pasted) omit the marker and render the page as before. * chore(corsair): bump to 0.1.125 * fix(react): confirm connection with retries before reading popup-close as cancel * fix(react): coalesce concurrent connect calls so a second doesn't cancel the first * refactor(db): rename corsair_connect_requests table to corsair_connects * fix(react): keep the connect modal centered and scroll a tall card * docs: rename corsair_connect_requests to corsair_connects * fix(react): restore the connect modal to its original centered position * fix(react): anchor the connect modal to the top so it grows downward * fix(react): scope connect coalescing to tenant and cancel a stale grace on reopen * fix(react): let the reactive connect path (null tenant) coalesce with an open flow * fix(connect): scope the reactive connect path to its resolved tenant The connect-request DTO now carries the tenant the server resolved it under, so the reactive path stops passing null and openDialog coalesces on the real tenant. Strict equality then joins a same-tenant concurrent flow and supersedes a different one — fixing both the cancel-same-tenant and join-wrong-tenant cases at the source instead of special-casing null in the coalesce check. * fix(connect): resolve proactive tenant for symmetric coalescing The proactive path passed null while the reactive path passed the server-resolved tenant, so strict equality superseded a same-tenant flow — dropping the reactive read to 'dismissed' or resolving connect() false despite connecting. ConnectLink now returns the tenant it resolved (both builders already default to 'default'), and connect() scopes the flow to it. Both paths always express the tenant the same way, so openDialog never sees null from a live flow and coalescing is exact. * refactor(connect): drop the unneeded row cast in readConnectRequest corsair_connects is registered in the Kysely schema, so selectAll() is already typed — the 'as CorsairConnect | undefined' cast (and its import) were dead. * test(connect): lock the no-double-side-effect and no-hang invariants Provider-level regression tests through a mounted CorsairProvider: call() rethrows without re-running the op when no connect-request is pending (an auth-missing failure records the request only after failing at the auth gate, so nothing to duplicate), and a pending connect() resolves false rather than hanging when the provider unmounts mid-flow. * fix(connect): gate coalescing on flow liveness to stop stranding a caller finishConnected empties the waiters and stops the watch before React commits the success state, so the state ref reads 'connecting' for a beat. A same-tenant openDialog landing in that window joined the already-settled flow and added a waiter that nothing settles again — the caller's promise hung forever. Gate coalescing on the waiter count (the synchronous liveness truth) so a settled flow is never joined. | 21 天前 | |
feat(blog): add SEO metadata and FAQs fields to post schema | 2 个月前 | |
feat(corsair): auth missing link generated by hub | 2 个月前 | |
fix: update combo integration pages on www | 3 小时前 | |
feat(www): integration listing | 3 个月前 | |
feat(www): add blog | 2 个月前 | |
update readme | 4 个月前 | |
fix: update landing page to add integration pages | 19 天前 | |
feat(www): add PostHog web analytics (#844) | 1 个月前 | |
update readme | 4 个月前 | |
fix: update landing page to add integration pages | 19 天前 | |
feat(www): add PostHog web analytics (#844) | 1 个月前 | |
update readme | 4 个月前 | |
feat(www): add blog | 2 个月前 | |
feat(corsair): auth missing link generated by hub | 2 个月前 | |
feat(www): oss integrations tracker | 3 个月前 | |
ci: scope PR Checks to the diff and run the plugin gate first (#1104) * perf(turbo): hash www env vars and tsconfig.base, not the lockfile * ci(deploy): pin Node 24, freeze the lockfile, restore turbo cache * ci: add job timeouts and labeler concurrency * feat(ci): classify PRs into plugin, www, full, and docs lanes * ci: run the plugin gate first and scope PR Checks to the diff * fix(ci): stop shell-interpolating package names and persist CodeQL creds * fix(ci): skip live *.api.test.ts without dropping webhook tests | 28 天前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 19 天前 | ||
| 21 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 3 小时前 | ||
| 3 个月前 | ||
| 2 个月前 | ||
| 4 个月前 | ||
| 19 天前 | ||
| 1 个月前 | ||
| 4 个月前 | ||
| 19 天前 | ||
| 1 个月前 | ||
| 4 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 3 个月前 | ||
| 28 天前 |