You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(pds): align lexicon validation with reference PDS (#160)
* feat(pds): tighten lexicon validation to match reference PDS
Honor the `validate` flag, return `validationStatus`, validate rkeys
against schema `keySchema`, reject legacy blob refs, and broaden the
bundled schema set. Move authoritative rkey allocation into the DO
with a collision-retry loop so worker-isolate clockid collisions
can't surface as 500s. Translate client-supplied rkey collisions to
409 and intra-batch duplicates to 400.
* test(pds): generate TID-format rkeys in e2e helpers
Now that the validator enforces the schema's keySchema (e.g. tidString
for app.bsky.feed.post), uniqueRkey() must return a valid TID.
Lexicon validation now matches the reference PDS more closely:
6
+
7
+
-`createRecord`, `putRecord`, and `applyWrites` honor the `validate` flag from the request body. `true` requires a known schema, `false` skips schema validation, `undefined` validates known schemas optimistically.
8
+
- Responses include `validationStatus` (`"valid"` for known, `"unknown"` for unknown collections; omitted when `validate: false`). Per-write `validationStatus` is returned in `applyWrites` results.
9
+
- The record's `$type` is filled in from `collection` when missing and rejected on mismatch.
10
+
- Generic record-key shape (`isRecordKey`) is enforced for any provided rkey, regardless of `validate` flag — closes a hole where empty-string and path-traversal-style rkeys could reach the repo.
11
+
- Schema-specific record keys are validated against the schema's `keySchema` for known collections (e.g. `app.bsky.feed.post` requires a TID, `app.bsky.actor.profile` requires `self`).
12
+
- Legacy `{ cid, mimeType }` blob refs are rejected.
13
+
- Bundled schema set broadened to include `com.atproto.lexicon.schema`, `app.bsky.actor.status`, `app.bsky.notification.declaration`, and `chat.bsky.actor.declaration`.
14
+
- The Durable Object is now the authoritative rkey allocator: when the client doesn't supply an rkey, the worker validates against a candidate (so restrictive `keySchema`s still reject early) and the DO picks the final rkey against its MST state, with a small retry loop to defeat any worker-isolate clockid collisions.
15
+
- Client-supplied rkey collisions return `409 RecordAlreadyExists` instead of a generic 500.
16
+
- Intra-batch duplicate rkeys in `applyWrites` return `400 InvalidRequest` (distinguished from the 409 above).
17
+
- Missing rkey for `applyWrites#update`/`#delete` returns `400 InvalidRequest`.
18
+
- Non-boolean `validate` flag values return `400 InvalidRequest`.
0 commit comments