Conversation
Foundation for the docs overhaul tracked in CIP-3307: - IA.md: living migration checklist at the repo root (one checkbox per planned page; sections tick off as they land on this branch) - New `v2docs` collection (content/docs) served from the site root via a required catch-all route, alongside the legacy tree (content/stack) at /stack until every section migrates - Frontmatter facet model: Diátaxis `type`, `components`, `audience`, `integration` (category / setup / pairsWith), and review-tracking fields (`verifiedAgainst`, `reviewBy`) - Section scaffold: get-started, integrations (incl. the /integrations/supabase stub the Supabase listing links to), concepts, compare, guides, security, solutions, reference — meta.json + stubs - v2-redirects.mjs: full legacy→v2 map (85/85 pages covered), gated behind ENABLE_V2_REDIRECTS=1 so the preview serves both trees during migration; /quickstart vanity redirect ships ungated - scripts/validate-v2-redirects.ts wired into prebuild: CI fails if a legacy page has no v2 mapping - llms.txt, llms-full.txt, sitemap, and the .mdx raw-markdown mirror now cover both trees Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
…rence/eql Two issues caught by smoke-testing the scaffold: - Stub descriptions containing ":" broke YAML frontmatter parsing (500s across the v2 tree) — descriptions are now quoted. - The AI-citation redirect "/reference/eql" → "/stack/reference/eql" shadowed the v2 /reference/eql page (redirects run before the filesystem); removed since the v2 page now serves that path. Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…t bare root Two fixes from preview review: - The bare domain root (Vercel preview URLs) 404'd because the app lives under the /docs basePath — added a basePath:false redirect / → /docs. In production only /docs/* reaches this app, so previews-only. - The /docs landing was a standalone (home) page disconnected from the v2 nav, with every link pointing at legacy /stack URLs. It's now content/docs/index.mdx rendered inside DocsLayout (sidebar + search), linking the v2 sections. The catch-all became optional ([[...slug]]) and the (home) route group is deleted (recoverable from history; CIP-3327 refines the landing content). - The landing's raw-markdown mirror serves at /docs/index.mdx (its URL is "/", which can't carry the .mdx suffix). Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
Listing "index" explicitly in meta.json pages forced each section's index out as a separate child item with the same title as its folder (clicking "Get started" opened a sub-nav containing another "Get started"). With index unlisted, Fumadocs merges it into the folder row: the folder itself links to the page, and children are only real sub-pages (Integrations → Supabase, not Integrations → Integrations). The root meta.json keeps "index" — at tree root there is no folder row to merge into, so the landing needs its own sidebar item. Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
Folders whose only page is their index still rendered as collapsible sidebar folders with a chevron pointing at nothing. getV2PageTree() now collapses such folders into plain page items (recursively, so guides/* and reference/* leaves flatten too); a section becomes a folder again automatically when its first real sub-page lands. Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
MDX links (markdown and Card hrefs) render through the Link component, which prefixes the /docs basePath — hardcoded /docs/... links rendered as /docs/docs/... and 404'd. Convention (enforce via CIP-3349 lint): internal links in content are always basePath-relative. Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
There was a problem hiding this comment.
Pull request overview
This PR scaffolds the “Docs V2” information architecture by introducing a new content/docs tree served from the site root (under the existing /docs basePath), while keeping the legacy content/stack tree available at /docs/stack during migration. It also adds a gated legacy→v2 redirect map plus CI validation to ensure legacy pages won’t become orphaned when redirects are enabled.
Changes:
- Add a new
v2docscollection +v2sourceloader, plus root catch-all routes/layout for the v2 docs tree. - Introduce a full legacy→v2 redirect map (
v2-redirects.mjs) gated byENABLE_V2_REDIRECTS=1, with a prebuild validation script to enforce coverage. - Scaffold v2 section stubs/meta and update sitemap + LLM surfaces (
llms.txt,llms-full.txt,.mdxraw mirror) to include the v2 tree first.
Reviewed changes
Copilot reviewed 65 out of 65 changed files in this pull request and generated 25 comments.
Show a summary per file
| File | Description |
|---|---|
| v2-redirects.mjs | Adds the full legacy /stack/* → v2 redirect mapping list (flag-gated in Next config). |
| next.config.mjs | Wires in gated v2 redirects, adds preview root redirect, and adds .mdx rewrite for v2 raw mirror; removes old /reference/eql redirect collision. |
| scripts/validate-v2-redirects.ts | Adds CI/prebuild gate to ensure every legacy content/stack page is covered by v2 redirects. |
| package.json | Adds validate-redirects script and runs it during prebuild. |
| source.config.ts | Defines the new v2docs collection and its frontmatter facet schema. |
| src/lib/source.ts | Adds v2source, v2 page tree shaping (flattenEmptyFolders), and broadens getLLMText typing for both trees. |
| src/app/[[...slug]]/layout.tsx | Adds the v2 docs layout (DocsLayout + v2 tree) at the root catch-all segment. |
| src/app/[[...slug]]/page.tsx | Adds the v2 docs page renderer, metadata generation, and markdown mirror URL generation. |
| src/app/llms.mdx/v2/[[...slug]]/route.ts | Adds the v2 raw-markdown mirror route for agent/LLM consumption. |
| src/app/llms.txt/route.ts | Lists v2 pages first, then legacy pages, in llms.txt. |
| src/app/llms-full.txt/route.ts | Emits the concatenated markdown for v2 pages first, then legacy pages. |
| src/app/sitemap.ts | Includes both v2 and legacy pages in sitemap (v2 first). |
| src/app/og/docs/[...slug]/route.tsx | Import ordering tweak only. |
| src/app/api/search/route.ts | Import ordering tweak only. |
| src/app/layout.tsx | Import ordering tweak only. |
| src/app/stack/layout.tsx | Import ordering tweak only. |
| src/app/stack/[[...slug]]/page.tsx | Import ordering tweak only. |
| src/proxy.ts | Import ordering tweak only. |
| src/lib/posthog/provider.tsx | Import ordering tweak only. |
| src/components/icons/supabase.tsx | Fixes missing semicolon in return statement. |
| src/app/(home)/page.tsx | Removes the standalone legacy docs landing page implementation. |
| src/app/(home)/layout.tsx | Removes the legacy home layout wrapper. |
| IA.md | Adds the migration checklist + branch workflow rules for the v2 overhaul. |
| content/docs/meta.json | Adds v2 root meta defining top-level section ordering. |
| content/docs/index.mdx | Adds the v2 docs landing page content (Cards + LLM surface links). |
| content/docs/get-started/meta.json | Adds v2 “Get started” section meta. |
| content/docs/get-started/index.mdx | Adds v2 “Get started” stub page. |
| content/docs/integrations/meta.json | Adds v2 “Integrations” section meta. |
| content/docs/integrations/index.mdx | Adds v2 “Integrations” stub page. |
| content/docs/integrations/supabase/meta.json | Adds v2 Supabase integration meta (custom icon). |
| content/docs/integrations/supabase/index.mdx | Adds v2 Supabase stub page with facet example. |
| content/docs/concepts/meta.json | Adds v2 “Concepts” section meta. |
| content/docs/concepts/index.mdx | Adds v2 “Concepts” stub page. |
| content/docs/compare/meta.json | Adds v2 “Comparisons” section meta. |
| content/docs/compare/index.mdx | Adds v2 “Comparisons” stub page. |
| content/docs/guides/meta.json | Adds v2 “Guides” section meta. |
| content/docs/guides/index.mdx | Adds v2 “Guides” stub page. |
| content/docs/guides/development/meta.json | Adds v2 “Development” guides meta. |
| content/docs/guides/development/index.mdx | Adds v2 “Development” stub page. |
| content/docs/guides/migration/meta.json | Adds v2 “Data migration” guides meta. |
| content/docs/guides/migration/index.mdx | Adds v2 “Data migration” stub page. |
| content/docs/guides/deployment/meta.json | Adds v2 “Deployment” guides meta. |
| content/docs/guides/deployment/index.mdx | Adds v2 “Deployment” stub page. |
| content/docs/guides/troubleshooting/meta.json | Adds v2 “Troubleshooting” guides meta. |
| content/docs/guides/troubleshooting/index.mdx | Adds v2 “Troubleshooting” stub page. |
| content/docs/security/meta.json | Adds v2 “Architecture & security” section meta. |
| content/docs/security/index.mdx | Adds v2 “Architecture & security” stub page. |
| content/docs/security/compliance/meta.json | Adds v2 “Compliance” meta under security. |
| content/docs/security/compliance/index.mdx | Adds v2 “Compliance” stub page. |
| content/docs/solutions/meta.json | Adds v2 “Solutions” section meta. |
| content/docs/solutions/index.mdx | Adds v2 “Solutions” stub page. |
| content/docs/reference/meta.json | Adds v2 “Reference” section meta. |
| content/docs/reference/index.mdx | Adds v2 “Reference” stub page. |
| content/docs/reference/eql/meta.json | Adds v2 “EQL” reference meta. |
| content/docs/reference/eql/index.mdx | Adds v2 “EQL” stub page. |
| content/docs/reference/stack/meta.json | Adds v2 “Stack SDK” reference meta. |
| content/docs/reference/stack/index.mdx | Adds v2 “Stack SDK” stub page. |
| content/docs/reference/proxy/meta.json | Adds v2 “Proxy” reference meta. |
| content/docs/reference/proxy/index.mdx | Adds v2 “Proxy” stub page. |
| content/docs/reference/cli/meta.json | Adds v2 “CLI” reference meta. |
| content/docs/reference/cli/index.mdx | Adds v2 “CLI” stub page. |
| content/docs/reference/auth/meta.json | Adds v2 “Auth” reference meta. |
| content/docs/reference/auth/index.mdx | Adds v2 “Auth” stub page. |
| content/docs/reference/workspace/meta.json | Adds v2 “Workspace & account” reference meta. |
| content/docs/reference/workspace/index.mdx | Adds v2 “Workspace & account” stub page. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <Card title="Integrations" href="/docs/integrations" description="Platforms, ORMs, frameworks, auth providers, and runtimes." /> | ||
| <Card title="Concepts" href="/docs/concepts" description="How searchable encryption, key management, and identity-aware encryption work." /> | ||
| <Card title="Guides" href="/docs/guides" description="Development workflow, data migration, deployment, and troubleshooting." /> | ||
| <Card title="Architecture & security" href="/docs/security" description="Trust model, components, availability, audit, and compliance — for security review." /> | ||
| <Card title="Solutions" href="/docs/solutions" description="PII protection, HIPAA, AI/RAG, data residency, and provable access." /> |
| <Card title="Guides" href="/docs/guides" description="Development workflow, data migration, deployment, and troubleshooting." /> | ||
| <Card title="Architecture & security" href="/docs/security" description="Trust model, components, availability, audit, and compliance — for security review." /> | ||
| <Card title="Solutions" href="/docs/solutions" description="PII protection, HIPAA, AI/RAG, data residency, and provable access." /> | ||
| <Card title="Reference" href="/docs/reference" description="EQL, the Stack SDK, Auth, the CLI, and Proxy — precise API documentation." /> |
| - **Moving a page = ** move the file into `content/docs`, update its facets, | ||
| fix inbound links, confirm its `v2-redirects.mjs` entry, tick it here. |
Seven pages replacing the v2-era EQL reference, written against the eql_v3 branch of cipherstash/encrypt-query-language (3.0.0): - index: what EQL is, the v3 domain-variant model, install (single SQL script, idempotent), dbdev, Docker, migration/runtime permission split, managed-Postgres rationale - types: 10 scalar families × variants matrix; bool storage-only; _ord/_ord_ore twins; index terms per variant - operators: per-variant support matrix, typed-operand rule, no-LIKE, fail-loud blockers, query shapes, function-form equivalents - indexes: functional indexes on term extractors, engagement requirements, sort-key form for index-streamed ORDER BY, EXPLAIN checklist, large-table build guidance - json: ste_vec model, per-node-type terms (hm XOR oc), containment + GIN, field access, path queries, blocked native jsonb operators - functions: comparisons, extractors, min/max only (no SUM/AVG), version() - payload-format: v/i/c envelope (wire version still v:2), hm/ob/bf term keys, sv document shape, annotated examples (absorbs the legacy CipherCell page) Cross-page consistency verified against the shipped SQL: equality on _ord variants compares ORE terms (no hm in _ord payloads), and bare ORDER BY is correct but extractor-form sort keys stream from the index. Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
| { | ||
| source: "/stack/quickstart", | ||
| destination: "/get-started/quickstart", | ||
| permanent: true, |
There was a problem hiding this comment.
We shouldn't make these permanent for now.
There was a problem hiding this comment.
Done in d0ccd7e — all 71 entries flipped to permanent: false, with a header note to revisit as part of CIP-3335 once the map has soaked post-merge.
EQL is an abstraction over SQL the way Tailwind is over CSS — the docs now follow the same shape: Install → Core concepts → type categories → Indexes → query patterns, increasing in complexity. Each type-category page is the complete reference for its types (variants, payload shape, operators/functions, example queries on one page). - index: trimmed to the Install page - core-concepts (new): the canonical home for shared mechanics — variant model, payload anatomy (v/i/c envelope + hm/ob/bf terms, absorbs payload-format/CipherCell), typed-operand rule, fail-loud blockers, ORE-equality on _ord, term-leakage pointer - numbers-and-dates, text, booleans (new) + json (reworked): category pages; text owns the no-LIKE treatment; json absorbs the sv payload shape; booleans framed as "every type has a storage-only variant — for bool it's the only one" - filtering, sorting, grouping-and-aggregates, joins (new): cross-type query patterns; joins headlines the same-keyset constraint - deleted: types.mdx, operators.mdx, functions.mdx, payload-format.mdx (content redistributed; URLs never shipped publicly, no redirect debt) - Anti-drift rule recorded in IA.md: mechanics live ONLY in core-concepts; category/query pages link, never restate - meta.json: flat URLs with ---Types---/---Indexes---/---Queries--- sidebar separators; legacy redirect map retargeted (queries → filtering, cipher-cell → core-concepts) Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
…load v:3 Review feedback on the EQL section: - Variant tables: generic form first, then full enumeration of every concrete domain name (Tailwind-style); capability column made concise; "index term carried" column dropped — term internals live in core-concepts' payload anatomy - SEM specifiers documented as a concept in core-concepts: a trailing mechanism suffix (_ord_ore) pins WHICH searchable-encryption mechanism implements a capability; _ord tracks the default (currently ORE). Replaces the "twins" framing. Each orderable type page lists its specifiers under an "SEM specifiers" heading, noting the OPE specifier arriving for all orderable types (incl. text) in the v3 release - Payload `v` field documented as the EQL version (3) per team decision 2026-07-02; all payload examples updated from v:2 Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
…perators and Functions Review feedback: - Dates & times split out of Numbers — same traits, distinct semantics; each page's examples now match its domain (payroll vs audit-event time windows / retention cutoffs / newest-first) - CREATE TABLE examples get an explicit "Example" sub-heading + lead-in - Operators and Functions are separate sections on every type page — operators as the per-variant support matrix, functions as the form-equivalents table (+ MIN/MAX, which only exist as functions) - IA.md: split reflected; query-performance follow-up added (CIP-3351 — the v3 branch already folded the v2 perf guide into database-indexes.md, which our indexes page absorbed) Claude-Session: https://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P
- indexes.mdx: cast query-shape example params to their EQL domain types, consistent with the typed-operand rule - numbers/dates-and-times/text: the fail-loud note now scopes to operators — ORDER BY on a variant without an ordering term doesn't raise, it silently returns a meaningless order (links Sorting)
- v2-redirects.mjs: all entries permanent: false while the IA settles (per review); flip to permanent post-merge soak (CIP-3335) - IA.md: fix unmatched bold around 'Moving a page' - add placeholder pages for /concepts/searchable-encryption (CIP-3333) and /guides/troubleshooting/query-performance (CIP-3351) so the EQL reference's forward links resolve instead of 404ing
# Conflicts: # v2-redirects.mjs
|
Review comments addressed in d0ccd7e:
|
Docs V2: EQL v3 reference section, Tailwind-shaped (CIP-3326)
Replace Shiki's default GitHub themes with two custom themes (light + dark) built from the site palette: the lime-green brand accent for keywords, warm neutrals for text and comments, and teal / gold / amber supporting hues tuned to the near-black and off-white grounds the docs already use. Shiki already runs in dual-theme mode, so this is purely a themes swap in rehypeCodeOptions — the copy button, line highlighting, diff/focus transformers, and Fira Code font are unchanged, and every code block picks it up.
Match the marketing site: H2 and below now render in Geist Sans (loaded via next/font/google), while H1 keeps its Fira Code monospace treatment. Body text and code are unchanged.
-0.02em reads too tight on the smaller Geist Sans headings; H2-H3 keep it.
docs: brand styling — CipherStash code theme + Geist Sans headings
Backport the code syntax palette settled on the marketing site (js-suite #572): rose keywords, purple functions, aqua types, lime strings, a lighter yellow for numbers, and a neutral grey for comments. The dark theme takes those exact values; the light theme uses darkened, readable variants of the same hues so both modes share one hue assignment.
docs: retune the code theme to match the marketing site
…hapes EQL #423 added `eql_v3.grouped_value`, the aggregate that lets a query project an encrypted column while grouping by that column's equality term. Documenting it exposed two wrong claims on the grouping page: that `GROUP BY email` and `SELECT DISTINCT email` work in natural form, and that grouping compares equality terms. Neither is true — an encrypted column is a domain over jsonb with no custom operator class, so Postgres compares the raw (randomised) ciphertext and never collapses two encryptions of the same value. - Group on `eql_v3.eq_term(col)` for correctness first, planner economics second; drop the "raise work_mem if an ORM forces the raw form" advice, which rescued the performance of a query that was already returning wrong answers. - New `grouped_value` section: the 42803 rejection it fixes, the shape that fixes it, and its semantics (first non-null per group, all-NULL group is NULL, parallel safe, returns its input unchanged). - Deduplication is `DISTINCT ON (eql_v3.eq_term(col)) col` with the matching leading ORDER BY. Plain DISTINCT is not supported; `DISTINCT ON` has no projection restriction, so `grouped_value` is not involved there. - Same correction to the Indexes page's GROUP BY section, and grouped_value in the MIN/MAX and JSON-leaf examples. grouped_value landed after eql-3.0.2, so the page carries a version callout (with the 3.0.x join-back workaround) and the drift check gets an UNRELEASED allowlist — reported on every run, and deleted when EQL_RELEASE_TAG is bumped to a release whose manifest covers it.
…rsion note - Restore the `GROUP BY` and `DISTINCT` heading, and fold deduplication back under it: one section for how both operators must be written, with the `grouped_value` projection following as its own section. - Add a `BadExample` component (rustdoc `compile_fail` styling: red frame, explicit label, verbatim error) so a broken example can't be mistaken for a working one while skimming, and use it for the two broken shapes here — the natural `GROUP BY` / `DISTINCT` forms, and the bare column under GROUP BY. - Drop the unreleased-version callout.
Documenting U-011 (the empty-bloom fuzzy-match guard, shipped in 3.0.3) meant moving EQL_RELEASE_TAG off 3.0.0, and the strict drift check then reported what the pin had been hiding: 3.0.1 renamed the whole encrypted-JSON surface and replaced the text match operator, and the hand-written pages still taught the 3.0.0 spelling of both. Every customer on a released 3.0.x has been reading docs whose text-match and JSON examples raise. Text fuzzy match (U-008, U-011): - `@>` / `<@` and `eql_v3.contains` / `contained_by` on text_match, text_search and text_search_ore are now `@@` / `eql_v3.matches`; the old spellings raise, and the pages say so. - Document the empty-needle guard as a LIKE truth table: a sub-floor search term (no trigrams, `bf: []`) used to match every row and now matches only empty-bloom values. - Note the one regression it carries: `matches` is non-STRICT and names the needle twice, so a needle from an uncorrelated subquery stops inlining and loses the GIN index. Bind parameters and literals are unaffected. Encrypted JSON (U-007, U-010): - eql_v3_json → eql_v3_json_search, eql_v3_jsonb_entry → eql_v3_json_entry, query_jsonb → query_json; the bare eql_v3_json is now storage-only. - Field equality is value-selector containment, not `=` on an extracted leaf (which raises). `eq_term` on an entry is a deprecated alias for `ope_term` and is not an exact equality term — so JSON leaves can no longer be grouped by equality at all, which the grouping page now states outright. - Wire format: document-level key header `h`, no root `c`, selector-derived nonces, sentinel value entries, `hm` retired. - `jsonb_array_elements_text` was removed; entry ciphertext is not independently decryptable. Tooling: - The fragment generator keyed the match card off a `match` capability the 3.0.1 catalog no longer emits (text_match now reports `["storage"]` with `supportedOperators: ["@@"]`), so the text function catalog silently lost its match entry. It now keys off the operator and renders `eql_v3.matches`. - Drift check: exempt lines that name a symbol in order to say it is gone, so a rename note can name the old symbol — the same line-local exemption validate-content-api.ts makes. - Two more manifest blind spots, both verified present in the 3.0.3 install SQL: `eql_v3.grouped_value` (hand-written CREATE AGGREGATE; the catalog only contributes the 60 generated min/max aggregates) and `public.eql_v3_json` (created in a DO block, like the query-operand domains). Generated artifacts (functions.mdx, the partials, eql-version.ts, the stack EQL API page) are left alone: prebuild regenerates them from the pinned release, and the committed copies are placeholders — the stack one still says EQL 2.3.0-pre.3.
EQL 3.0.3's ope_term brief contains "= / <> are blocked". Doxygen comments
are written for a plain-text renderer, so bare SQL operators are normal in
them — but the generator dropped them into functions.mdx verbatim, where MDX
read `<>` as an unclosed JSX fragment and failed the build on the generated
content file rather than at the source.
Escape `<` and `{` in every prose string the manifest supplies (brief,
description, param and return descriptions), skipping inline-code spans so
the descriptions that already write `<>` in backticks keep rendering as code.
Reports whether a newer EQL release exists for the pinned minor, and with --apply rewrites the pin. The companion workflow calls this on a schedule and opens a PR, so a new EQL release surfaces as a reviewable PR instead of something someone has to remember to check. It deliberately does NOT float the pin. The drift check validates every schema-qualified symbol in the hand-written pages against the pinned release's manifest and FAILS THE BUILD on a mismatch, so an auto-following pin would turn an unrelated PR red with no commit of its author's to explain it — which is what eql-3.0.0-alpha.4 did when it replaced eql_v3.ore_cllw. Scope is the pinned minor, and even that goes through review: EQL patch releases are not additive-only ahead of Stack 1.0. Between 3.0.0 and 3.0.1 — a patch — eql_v3.contains went 15 occurrences to 0, eql_v3.matches 0 to 15, and eql_v3_json_search 0 to 162. A newer minor or major is reported but never proposed, since those carry migration work beyond a pin change. Prereleases and the sibling tags cut by the same release (eql-bindings-v3.0.3, @cipherstash/eql@3.0.3) are excluded by matching eql-X.Y.Z exactly and honouring the API's prerelease flag. Note the release bodies claim "Preview (prerelease)" on stable releases; that text is stale boilerplate and contradicts the flag, so the flag is what this trusts. Claude-Session: https://claude.ai/code/session_01NkuQNMvw9BpB4BWWeKtfV8
docs: add an EQL pin resolver so patch bumps stop relying on memory
…aying `any`
The generated Stack API reference documents 13 types as `any` and gives
AuthStrategy the wrong description entirely. Both come from one missing
compiler option.
@cipherstash/protect-ffi's `exports` map routes the `node` condition to
lib/index.d.cts (the real type surface) and everything else to
`default: ./dist/wasm/protect_ffi.js`, which ships no `types`. TypeScript
therefore falls through to the sibling dist/wasm/protect_ffi.d.ts — raw
wasm-bindgen output — where none of the hand-written types exist.
`moduleResolution: "bundler"` does not imply the `node` condition;
packages/stack/tsconfig.json adds `customConditions: ["node"]`, which is why
the stack team never sees this. But typedoc.tsconfig.json extends stack's ROOT
tsconfig, which does not set it. Set it on the generated config.
Confirmed with a minimal repro against protect-ffi 0.30.0 (the version stack
1.0.0-rc.4 pins exactly): `moduleResolution: bundler` alone yields
"has no exported member 'ProtectError'. Did you mean 'encryptQuery'?"; adding
customConditions typechecks clean.
Also turns error checking back on. It was disabled to tolerate this, on the
theory that the references were "unresolved even though the source is correct"
and TypeDoc would still emit accurate signatures. It does not — an unresolved
import becomes `any` in the output, so the workaround converted a loud failure
into a silently wrong reference. With the condition fixed the surface
typechecks with 0 errors, so the next resolution break fails the build instead.
Generating with and without the fix, back to back against the same stack tag,
changes 23 pages. Representative:
EncryptionError.code any -> ProtectErrorCode
EncryptQueryOperation.execute() Promise<Result<any, ...>>
-> Promise<Result<EncryptedQueryResult, ...>>
encryptQuery plaintext param any -> Plaintext | null | undefined
AuthStrategy description the module's blurb -> the type's own docs
Claude-Session: https://claude.ai/code/session_01NkuQNMvw9BpB4BWWeKtfV8
docs: resolve protect-ffi's real types so the Stack reference stops saying `any`
EQL 3.0.4 ships the manifest-extraction fixes from cipherstash/encrypt-query-language#427, so `eql_v3.grouped_value` and `public.eql_v3_json` now resolve from the catalog and no longer need drift-check exemptions. Verified against the released manifest: grouped_value(jsonb) and lints() present, 53 domains (was 52) including public.eql_v3_json, and the `match` capability restored to text_match and both text_search variants. Only `eql_v3.query_text_eq` stays on the allowlist — the 40 scalar query-operand domains created in a `DO ... EXECUTE` block are a separate gap that 3.0.4 does not address. Removing the other two means a regression in either now fails the drift check instead of staying quiet. Also always stamp the pinned tag as the manifest's version rather than only substituting when it reads "DEV". EQL's release workflow derives that field from a tag input that can arrive empty, in which case json.sh falls back to "DEV" — which 3.0.4 shipped, and which would otherwise render as "EQL DEV" in the banner on every reference page. The existing guard already covered that case; this extends it to warn when a manifest is stamped with a DIFFERENT release, which would be a packaging mix-up worth seeing rather than a cosmetic default worth silencing. bun run build passes: drift check clean against 3.0.4, 1990 functions, banner reads EQL 3.0.4. Claude-Session: https://claude.ai/code/session_01NkuQNMvw9BpB4BWWeKtfV8
Brings main's four commits onto v2 so #37 (v2 -> main) is mergeable again. Everything main has that v2 lacks is a README URL fix and a Next bump; there is no content divergence. One conflict, in package.json: main bumped next 16.2.3 -> 16.2.6 (dependabot #18) while v2 added mermaid to the same dependency block. Kept both — v2's mermaid and main's newer next. Also regenerates bun.lock, which main's bump never touched: its package.json asked for next 16.2.6 while its lockfile still pinned 16.2.3, so `bun install --frozen-lockfile` failed on main. It passes here. `bun run build` is green end to end on the merge: EQL drift check clean, mermaid diagrams parse, all 188 legacy redirects covered, 706 pages compiled. Claude-Session: https://claude.ai/code/session_01NkuQNMvw9BpB4BWWeKtfV8
docs: EQL 3.0.4 — grouped_value, @@ fuzzy match, and the encrypted-JSON surface
chore: merge main into v2 (unblocks #37)
… API gate Three changes, all about the docs telling the truth about the SDK. 1. Add @cipherstash/stack-supabase to the TypeDoc entry points. Stack 1.0 split the Supabase adapter into its own package, and the entry points were never updated, so NOTHING in it reached the generated reference — encryptedSupabaseV3, the query builder, and the EQL-version constraints on its encrypted operators were all absent. 19 pages now generate (763 total, up from 706), including the constraint that free-text and JSON operators are "unavailable with EQL 3.0.2+" because PostgREST cannot express the required eql_v3.query_* cast. That is now published automatically instead of relying on someone reading the source. 2. Resolve a workspace package's subpath imports to source. stack-supabase imports its sibling by package name (@cipherstash/stack, /schema, /adapter-kit, ...), which resolves through that package's exports map to ./dist — and the clone is never built, so all 42 imports were TS2307 and every cross-package type would have documented as `any`. Derive the tsconfig `paths` from the sibling's own exports map, rewriting ./dist/x.js to ./packages/<pkg>/src/x.ts, rather than hardcoding twelve subpaths that would rot the next time Stack adds one. Two of them are not guessable (`/types` -> types-public.ts, `/v3` -> encryption/v3.ts), which is the argument for deriving rather than transcribing. 3. Say what the content API gate actually checks. It printed "no deprecated or non-existent API found in documentation" while the Supabase page taught `.contains()` for encrypted free-text, which raises. It is a denylist of 7 patterns, not verification, so it now reports the rule count and files scanned and states the limitation outright. Deliberately NOT adding the version-diff denylist discussed: `contains()` was repurposed rather than removed, so it is present in every tag and no symbol-presence or signature diff fires on it. Catching that class needs the examples typechecked against the SDK; the header now records that. Also removes CLAUDE.md's "Required Skills" section. All six skills it mandated (encryption, secrets, drizzle, supabase, dynamodb, update-docs) do not exist, and its validation checklist was stale too — `switcher` appears in 0 files and the "Good to know" callout in 1, versus <Callout> in 37. Its accurate items are already covered by the Frontmatter, Code Blocks, and Formatting sections above. Claude-Session: https://claude.ai/code/session_01NkuQNMvw9BpB4BWWeKtfV8
docs: generate the stack-supabase reference, and stop overstating the API gate
Long-lived integration branch for the docs V2 overhaul, tracked in CIP-3307. Opened as a draft — it merges only when the migration completes (CIP-3335); section work stacks as PRs targeting this branch, and this PR's Vercel preview is the staging site for the whole overhaul.
What's in the scaffold (CIP-3325)
IA.md— living migration checklist at the repo root: one checkbox per planned page, ticked as sections land, with the branch's working rules (how to move a page, redirect flag, URL conventions)v2docscollection (content/docs) served from the site root (/docs/get-started/…,/docs/integrations/supabase, …) via a required catch-all route. The legacy tree still serves at/docs/stack/*— both trees coexist until every section migrates, then the legacy tree is deletedtype,components,audience,integration(category / setup / pairsWith), and review-tracking fields (verifiedAgainst,reviewBy)/docs/integrations/supabase(the Supabase listing's link target)v2-redirects.mjs— full legacy→v2 map (85/85 pages covered), gated behindENABLE_V2_REDIRECTS=1so previews serve both trees during migration; the flag flips on at merge.bun run validate-redirectsis wired into prebuild: a legacy page without a mapping fails CI/docs/quickstartvanity redirect (ungated — no legacy traffic on that path).mdxraw-markdown mirror all cover the v2 tree (listed first)/reference/eql → /stack/reference/eql— its source collided with (and shadowed) the v2 page at that pathHow to review the preview
/docs/get-started,/docs/integrations/supabase,/docs/security/compliance,/docs/reference/eql(stubs for now)/docs/stack/quickstartetc..mdxto any v2 page URL;/docs/llms.txtMerge checklist (CIP-3335, end of migration)
ENABLE_V2_REDIRECTS=1set for productioncontent/stack,/stackroutes, and the legacy loader deletedhttps://claude.ai/code/session_01ACPpFPHvKtrV48nbEYuv7P