commits
The indexer scanned all blocks for the first matching $type, so
multi-record commits (e.g. applyWrites with multiple photos) indexed
every op with the same first block's data. Look up each op's specific
block by its CID instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds pdsApplyWrites to proxy batched create/update/delete operations
through com.atproto.repo.applyWrites with local indexing and label rules.
Exposes it as dev.hatk.applyWrites XRPC handler and on XrpcContext.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allows callers to set the app icon badge count via APNs by passing
badge in the PushPayload.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add resolveHandleToDid to db.ts and use it in executeFeed to automatically
resolve handle-based actor params to DIDs before passing to feed handlers.
Also improve APNs HTTP/2 session with connection logging and request timeout handling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, migrateSchema checked ALL collection tables for emptiness on
every startup. Collections with 0 rows (e.g. blocks when nobody has
blocked anyone) would trigger a full resync of all repos on every
restart, creating an infinite loop.
Now we track which tables were just created this startup and only trigger
resync for those genuinely new collections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously hatk intercepted all /.well-known/ routes, causing non-OAuth
paths like apple-app-site-association to 404. Now only the two OAuth
well-known routes are intercepted, letting others fall through to the
framework handler.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add on-commit hook primitive with collection filtering
- Add APNs HTTP/2 push delivery module with JWT auth and token self-cleaning
- Add _push_tokens table and registerToken/unregisterToken XRPC endpoints
- Add PushConfig to defineConfig
- Wire fireOnCommitHooks into indexer flushBuffer (creates) and processMessage (deletes)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Records with bytes fields (e.g. com.germnetwork.declaration) were
silently dropped during indexing because CBOR-decoded Uint8Array
values failed lexicon validation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
refreshPdsSession was using pds_endpoint (the data PDS, e.g.
porcini.us-east.host.bsky.network) for the token endpoint, but
Bluesky-hosted PDS nodes don't serve /oauth/token — the auth
server (bsky.social) does. This caused token refresh to 404,
deleting the session and forcing users to re-login.
Now stores pds_auth_server from the OAuth request into the session
table and uses it for refresh, with fallback to pds_endpoint for
self-hosted PDS where they're the same.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend serverLogin to accept prompt and pds options for account
creation. Update /oauth/login route to pass through prompt and pds
query params. Bump version to 0.0.1-alpha.48.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Accept prompt parameter in handlePar. When prompt=create, treat
login_hint as a PDS hostname, discover auth server via protected
resource metadata, and forward prompt=create to the PDS PAR request.
Handles bare hostnames (localhost:* -> http://, others -> https://).
Add documentation for native app clients and account creation flow.
Bump version to 0.0.1-alpha.47.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FTS5 interprets dots as column filter operators, so a query like
"alice.test" was parsed as "search column 'alice' for 'test'" instead
of matching the handle. Adding dot to the escape regex converts it to
"alice test" which matches correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Vite plugin handles import resolution, dev server, and the callXrpc
bridge. Type generation is done by the hatk CLI, not the plugin.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove hatk new scaffolding command (~600 lines) from CLI
- Point users to vp create github:hatk-dev/hatk-template-starter
- Update quickstart with vp prerequisites and new create flow
- Update CLI docs, scaffold docs, project structure docs
- Add pronunciation to site hero
- Disable memory diagnostics logging
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Listen for #identity events on the relay and update the handle in
_repos for tracked DIDs when it changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The generated callXrpc client handled 401 responses with a redirect to
re-auth for procedures and queries, but the blob upload path was
missing this handler — causing raw errors instead of graceful re-auth.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename hero to hat://k, update tagline
- Remove hatk schema CLI command and docs
- Add createReport to API reference
- Update hooks guide to use ctx. style and hooks/ directory
- Simplify mutations guide to callXrpc only
- Remove experimental SvelteKit features section
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Double-quote all column names in generated DDL, DML, and FTS queries
to avoid SQLite errors when lexicon field names collide with reserved
words (e.g. "index" from app.bsky.feed.post).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The session's pdsEndpoint was derived from pds_auth_server, but for
bsky.social users the auth server (bsky.social) differs from the data
PDS (e.g. leccinum.us-west.host.bsky.network). XRPC proxy calls were
going to the wrong host, causing immediate InvalidToken errors.
Also handle AT Proto PascalCase error codes (InvalidToken, ExpiredToken)
alongside OAuth snake_case (invalid_token) in the DPoP retry logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move inline label definition object to named `labelDefinition` and
`labelLocale` defs so codegen produces reusable TypeScript types.
Adds `locales` array for human-readable label names and descriptions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keeps insertLabels dedup scoped to (src, uri, val) so multiple labelers
can independently label the same content. Adds GROUP BY uri, val to
queryLabelsForUris to collapse duplicates for display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move com.atproto.repo.strongRef, com.atproto.label.defs, and
com.atproto.moderation.defs from inline objects in lexicon-resolve.ts
to src/lexicons/ JSON files. The resolver now loads all built-in
schemas from disk. createReport lexicon references
com.atproto.repo.strongRef instead of a local #strongRef def.
Build now cleans dist/ before compiling to prevent stale artifacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move all 14 inlined dev.hatk.* lexicon definitions from cli.ts into
src/lexicons/dev/hatk/*.json. The hatk new command now copies them
with cpSync instead of writing each one inline. Build step copies
lexicons to dist/ alongside templates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SQLite adapter coerces boolean params to 0/1
- pdsCreateRecord and pdsPutRecord now run label rules after local indexing
- clearLabels() added for hot-reload support in server-init
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users can submit reports via dev.hatk.createReport XRPC endpoint,
selecting from the app's defined labels with optional free-text reason.
Reports are stored in a new _reports table (dialect-aware for SQLite/DuckDB).
Admins see a Reports tab in the admin UI to review, apply labels, or
dismiss reports. Open report count appears on the Overview dashboard.
Also fixes the label scaffold template to use defineLabel from $hatk,
and adds the createReport lexicon to hatk new scaffolding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move inline template strings from cli.ts into separate .tpl files under
src/templates/ for readability and maintainability. Update xrpc template
with $hatk import and typed query results. Include viewer handle in
ScopeMissing and proxy error responses so the generated client can
preserve identity across re-authentication redirects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wraps existing pds-proxy functions so hooks and XRPC handlers can write
records through the PDS with local indexing, without raw SQL. Also adds
awaitBackfill so ensureRepo properly waits for in-flight backfills.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace HydrateContext with BaseContext (no items field, viewer gains handle)
- Feed hydrate signature: (ctx: BaseContext, items: Row<T>[]) => Promise<unknown[]>
- XrpcContext extends BaseContext, removing duplicate field declarations
- Add buildBaseContext and buildXrpcContext factories, eliminating 4 copy-pasted context constructions across xrpc.ts and opengraph.ts
- Tighten db layer: run/runBatch/all params from any[] to unknown[], typed all<T>() generics at every call site
- FeedContext.db.query tightened to unknown[]
- Codegen updated: BaseContext imports/exports, defineFeed overloads
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
searchRecords was returning raw flat rows while all other context methods
(resolve, lookup, getRecords) return shaped Row<T> with .value. Now
search results are reshaped before returning.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract duplicated getRecords logic (fetch by URIs, reshape, return Map)
into a generic getRecordsMap function in db.ts, used by both
HydrateContext and XrpcContext. Adds getRecords to the XrpcContext
interface so XRPC handlers can fetch shaped records by URI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SQLite maps JSON columns to TEXT, so checking col.sqlType === 'JSON'
only worked for DuckDB. This caused reshapeRow and insert operations
to skip JSON parsing/serialization on SQLite.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9 tasks in 5 batches: D1 adapter, Worker entry, Container entry,
build command, integration and docs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Worker + Container architecture with D1, Service Binding RPC
for communication, and hatk build --target cloudflare output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of emitting one log per invalid record during backfill, collect
counts by collection and emit a single validation_skips event per repo.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Assets 404 without /hatk/ base when served from hatk-dev.github.io/hatk/.
Remove this once hatk.dev custom domain is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Deploys VitePress site on pushes to docs/site/** on main.
CNAME configured for hatk.dev custom domain.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Jobs feature doesn't exist yet. Remove generate/destroy job commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every other define* helper is singular (defineFeed, defineQuery,
defineProcedure, defineHook, defineOG). Align labels to match.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite all documentation to reflect generated client helpers, SQLite-only,
SvelteKit remote commands, and login/logout/parseViewer from $hatk/client.
- Rewrite nav structure with new Frontend section
- Landing page with project tree and feature cards
- Getting Started: quickstart, project structure, configuration rewritten
- Guides: feeds, xrpc handlers, auth (new), seeds, labels, opengraph, hooks
- Frontend: 3 new pages (setup, data-loading, mutations)
- API reference: updated with dual auth (DPoP + cookies), callXrpc
- CLI reference: fixed src/ → app/, localhost → 127.0.0.1
- Remove obsolete: oauth.md, api-client.md, frontend.md, deployment.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a custom fetch function is provided (e.g. SvelteKit's fetch),
bypass the server bridge and use relative URLs so the framework can
deduplicate server/client requests. Guards window.location redirects
for safe server-side execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, migrateSchema checked ALL collection tables for emptiness on
every startup. Collections with 0 rows (e.g. blocks when nobody has
blocked anyone) would trigger a full resync of all repos on every
restart, creating an infinite loop.
Now we track which tables were just created this startup and only trigger
resync for those genuinely new collections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add on-commit hook primitive with collection filtering
- Add APNs HTTP/2 push delivery module with JWT auth and token self-cleaning
- Add _push_tokens table and registerToken/unregisterToken XRPC endpoints
- Add PushConfig to defineConfig
- Wire fireOnCommitHooks into indexer flushBuffer (creates) and processMessage (deletes)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
refreshPdsSession was using pds_endpoint (the data PDS, e.g.
porcini.us-east.host.bsky.network) for the token endpoint, but
Bluesky-hosted PDS nodes don't serve /oauth/token — the auth
server (bsky.social) does. This caused token refresh to 404,
deleting the session and forcing users to re-login.
Now stores pds_auth_server from the OAuth request into the session
table and uses it for refresh, with fallback to pds_endpoint for
self-hosted PDS where they're the same.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Accept prompt parameter in handlePar. When prompt=create, treat
login_hint as a PDS hostname, discover auth server via protected
resource metadata, and forward prompt=create to the PDS PAR request.
Handles bare hostnames (localhost:* -> http://, others -> https://).
Add documentation for native app clients and account creation flow.
Bump version to 0.0.1-alpha.47.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove hatk new scaffolding command (~600 lines) from CLI
- Point users to vp create github:hatk-dev/hatk-template-starter
- Update quickstart with vp prerequisites and new create flow
- Update CLI docs, scaffold docs, project structure docs
- Add pronunciation to site hero
- Disable memory diagnostics logging
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename hero to hat://k, update tagline
- Remove hatk schema CLI command and docs
- Add createReport to API reference
- Update hooks guide to use ctx. style and hooks/ directory
- Simplify mutations guide to callXrpc only
- Remove experimental SvelteKit features section
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The session's pdsEndpoint was derived from pds_auth_server, but for
bsky.social users the auth server (bsky.social) differs from the data
PDS (e.g. leccinum.us-west.host.bsky.network). XRPC proxy calls were
going to the wrong host, causing immediate InvalidToken errors.
Also handle AT Proto PascalCase error codes (InvalidToken, ExpiredToken)
alongside OAuth snake_case (invalid_token) in the DPoP retry logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move com.atproto.repo.strongRef, com.atproto.label.defs, and
com.atproto.moderation.defs from inline objects in lexicon-resolve.ts
to src/lexicons/ JSON files. The resolver now loads all built-in
schemas from disk. createReport lexicon references
com.atproto.repo.strongRef instead of a local #strongRef def.
Build now cleans dist/ before compiling to prevent stale artifacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users can submit reports via dev.hatk.createReport XRPC endpoint,
selecting from the app's defined labels with optional free-text reason.
Reports are stored in a new _reports table (dialect-aware for SQLite/DuckDB).
Admins see a Reports tab in the admin UI to review, apply labels, or
dismiss reports. Open report count appears on the Overview dashboard.
Also fixes the label scaffold template to use defineLabel from $hatk,
and adds the createReport lexicon to hatk new scaffolding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move inline template strings from cli.ts into separate .tpl files under
src/templates/ for readability and maintainability. Update xrpc template
with $hatk import and typed query results. Include viewer handle in
ScopeMissing and proxy error responses so the generated client can
preserve identity across re-authentication redirects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace HydrateContext with BaseContext (no items field, viewer gains handle)
- Feed hydrate signature: (ctx: BaseContext, items: Row<T>[]) => Promise<unknown[]>
- XrpcContext extends BaseContext, removing duplicate field declarations
- Add buildBaseContext and buildXrpcContext factories, eliminating 4 copy-pasted context constructions across xrpc.ts and opengraph.ts
- Tighten db layer: run/runBatch/all params from any[] to unknown[], typed all<T>() generics at every call site
- FeedContext.db.query tightened to unknown[]
- Codegen updated: BaseContext imports/exports, defineFeed overloads
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract duplicated getRecords logic (fetch by URIs, reshape, return Map)
into a generic getRecordsMap function in db.ts, used by both
HydrateContext and XrpcContext. Adds getRecords to the XrpcContext
interface so XRPC handlers can fetch shaped records by URI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite all documentation to reflect generated client helpers, SQLite-only,
SvelteKit remote commands, and login/logout/parseViewer from $hatk/client.
- Rewrite nav structure with new Frontend section
- Landing page with project tree and feature cards
- Getting Started: quickstart, project structure, configuration rewritten
- Guides: feeds, xrpc handlers, auth (new), seeds, labels, opengraph, hooks
- Frontend: 3 new pages (setup, data-loading, mutations)
- API reference: updated with dual auth (DPoP + cookies), callXrpc
- CLI reference: fixed src/ → app/, localhost → 127.0.0.1
- Remove obsolete: oauth.md, api-client.md, frontend.md, deployment.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>