Skip to content
This repository was archived by the owner on Oct 31, 2026. It is now read-only.

Export the store's functions; a base is never pushed over (0.14.0) - #29

Merged
nicu-chiciuc merged 5 commits into
mainfrom
state-functions
Oct 30, 2026
Merged

nicu-chiciuc merged 5 commits into
mainfrom
state-functions

Conversation

@nicu-chiciuc

@nicu-chiciuc nicu-chiciuc commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

What changes

  • The store's functions are exports: @samebase/alchemy-convex/state/functions (stateFunctions(alchemyState, host), readerFunctions(alchemyState)) and @samebase/alchemy-convex/state/auth.config (authConfig(cloudUrl)). The package's own store app uses them, so a team's base app writes three one-line files and copies nothing.
  • state:host is a new function: "seed" for the store app, "base" for a base app. A store without it is a seed.
  • Convex.state() pushes only over no store or an older seed. An older base fails the run with OutdatedBase.
  • reader:repository accepts only a token of the deployment's own issuer, so a base with other auth providers does not widen who can read.

What does not change

STORE_VERSION stays 4 and state:version still answers a number. No existing function changes, so a consumer on 0.13.0 keeps working, next to a seed or a base. Nothing is pushed to any store on release, and the consumers move when they want to.

An earlier version of this PR raised the number to 5 and changed the reply of state:version. That would have forced every consumer of a team to move at once, and a Renovate preview on Scout or Mail, which have no release delay, could have pushed store 5 and broken the rest.

STORE_VERSION is now a wire contract: it rises only when a function that a released client calls changes or goes away. Each consumer needs the exact number, so only such a change moves every consumer at once. The design note, AGENTS.md, and the version file state this rule.

Verification

  • pnpm run check passes (118 tests); pnpm run build passes attw and publint.
  • On the development deployment gallant-skunk-112 only: the store app answered version 4 and host "seed". A scratch app built from the packed tarball answered 4 and "base", and tsc passed with the Convex codegen tsconfig.
  • On both hosts, a real token of reader:authorize read a probe stack through the issuer check, with the secret removed. A read with no token and a read with a changed token were refused. The deployment is a seed again, with no probe rows.
  • One Codex pass; its findings are folded.

Not measured: the rule of Convex.state() on a real base, which the unit tests cover, and the hub as a base.

🤖 Generated with Claude Code

nicu-chiciuc and others added 5 commits October 30, 2026 04:53
… (store version 5)

src/store/functions.ts (`@samebase/alchemy-convex/state/functions`) builds the
twelve `state:*` functions with `stateFunctions(alchemyState, host)` and the two
`reader:*` functions with `readerFunctions(alchemyState)`, with the validators
and semantics of store version 4. `state:version` answers `{ version, host }`.
src/store/authConfig.ts (`@samebase/alchemy-convex/state/auth.config`) gives
the auth config. The store app of src/store/convex uses the exports as a seed.

The package also exports `./state/_generated/component.js`, the `ComponentApi`
type that the Convex codegen of a mounting app imports, and the modules of
src/store import with `.js` specifiers, so that a base app typechecks them with
the Convex tsconfig.

function_version.json is re-recorded from the development deployment after the
push; the old recording is function_version_1.json, the bare number of an older
store.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A base app serves the store functions next to its own functions, and a push
of the store app would replace them. The run pushes only over no store or a
seed of an older version. A base of an older version fails the run with the
exported OutdatedBase, which names the dependency @samebase/alchemy-convex of
the base app; a newer store fails the run from either host, as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The design note gets the section "The store's functions are exported, and a
base is never pushed over (store version 5)" and the measurements on the
development deployment gallant-skunk-112. README, AGENTS, and CHANGELOG
describe the exports and the rule.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…push, the consequence for 0.13.0

reader:repository accepts only a token of the deployment's own issuer, the one that authorize signs,
so a base that accepts other providers does not widen who can read a repository. The fake CLI push
now installs the store app once for each push, a base too, as a real push does. The changelog says
that a 0.13.0 run fails with "bad store version" after the first 0.14.0 run, and the design note says
when a team pushes its base for the first time and how the base upgrades itself.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
state:version keeps its number and state:host answers the app that serves the store, so 0.14.0
changes no function and a consumer on 0.13.0 keeps working. STORE_VERSION is now a wire contract: it
rises only when a function that a released client calls changes or goes away, because each raise
moves every consumer of a team at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nicu-chiciuc nicu-chiciuc changed the title Export the store's functions; a base is never pushed over (store version 5, 0.14.0) Export the store's functions; a base is never pushed over (0.14.0) Oct 30, 2026
@nicu-chiciuc
nicu-chiciuc merged commit 8a39dad into main Oct 30, 2026
1 check passed
@nicu-chiciuc
nicu-chiciuc deleted the state-functions branch October 30, 2026 08:29
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant