Skip to content

Commit

Permalink
Lexicon updates for Sync v1.1 (inductive firehose) (#3391)
Browse files Browse the repository at this point in the history
* mark 'blobs' as deprecated (can parse from records blocks)

* add 'prev' CID to record ops

* add inductive changes and #resync event

* updates from recent discussion

* add sync v1.1 account hosting status states (broken, throttled)

* prettier

* updates from discussion

* remove 'data' from #sync message

* add note on 'repo' field about inconsistent name

* codegen

* changeset
  • Loading branch information
bnewbold authored Feb 22, 2025
1 parent 7e3678c commit 6e382f6
Show file tree
Hide file tree
Showing 20 changed files with 558 additions and 82 deletions.
5 changes: 5 additions & 0 deletions .changeset/unlucky-tools-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@atproto/api": patch
---

update sync lexicons for induction firehose
9 changes: 8 additions & 1 deletion lexicons/com/atproto/sync/getRepoStatus.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@
"status": {
"type": "string",
"description": "If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.",
"knownValues": ["takendown", "suspended", "deactivated"]
"knownValues": [
"takendown",
"suspended",
"deleted",
"deactivated",
"desynchronized",
"throttled"
]
},
"rev": {
"type": "string",
Expand Down
9 changes: 8 additions & 1 deletion lexicons/com/atproto/sync/listRepos.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@
"status": {
"type": "string",
"description": "If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.",
"knownValues": ["takendown", "suspended", "deactivated"]
"knownValues": [
"takendown",
"suspended",
"deleted",
"deactivated",
"desynchronized",
"throttled"
]
}
}
}
Expand Down
54 changes: 46 additions & 8 deletions lexicons/com/atproto/sync/subscribeRepos.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"type": "union",
"refs": [
"#commit",
"#sync",
"#identity",
"#account",
"#handle",
Expand Down Expand Up @@ -61,12 +62,12 @@
"rebase": { "type": "boolean", "description": "DEPRECATED -- unused" },
"tooBig": {
"type": "boolean",
"description": "Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data."
"description": "DEPRECATED -- replaced by #sync event and data limits. Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data."
},
"repo": {
"type": "string",
"format": "did",
"description": "The repo this event comes from."
"description": "The repo this event comes from. Note that all other message types name this field 'did'."
},
"commit": {
"type": "cid-link",
Expand All @@ -84,8 +85,8 @@
},
"blocks": {
"type": "bytes",
"description": "CAR file containing relevant blocks, as a diff since the previous repo state.",
"maxLength": 1000000
"description": "CAR file containing relevant blocks, as a diff since the previous repo state. The commit must be included as a block, and the commit block CID must be the first entry in the CAR header 'roots' list.",
"maxLength": 2000000
},
"ops": {
"type": "array",
Expand All @@ -100,12 +101,42 @@
"type": "array",
"items": {
"type": "cid-link",
"description": "List of new blobs (by CID) referenced by records in this commit."
"description": "DEPRECATED -- will soon always be empty. List of new blobs (by CID) referenced by records in this commit."
}
},
"prevData": {
"type": "cid-link",
"description": "EXPERIMENTAL. The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose."
"description": "The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose."
},
"time": {
"type": "string",
"format": "datetime",
"description": "Timestamp of when this message was originally broadcast."
}
}
},
"sync": {
"type": "object",
"description": "Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository.",
"required": ["seq", "did", "blocks", "rev", "time"],
"properties": {
"seq": {
"type": "integer",
"description": "The stream sequence number of this message."
},
"did": {
"type": "string",
"format": "did",
"description": "The account this repo event corresponds to. Must match that in the commit object."
},
"blocks": {
"type": "bytes",
"description": "CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'.",
"maxLength": 10000
},
"rev": {
"type": "string",
"description": "The rev of the commit. This value must match that in the commit object."
},
"time": {
"type": "string",
Expand Down Expand Up @@ -144,7 +175,14 @@
"status": {
"type": "string",
"description": "If active=false, this optional field indicates a reason for why the account is not active.",
"knownValues": ["takendown", "suspended", "deleted", "deactivated"]
"knownValues": [
"takendown",
"suspended",
"deleted",
"deactivated",
"desynchronized",
"throttled"
]
}
}
},
Expand Down Expand Up @@ -211,7 +249,7 @@
},
"prev": {
"type": "cid-link",
"description": "EXPERIMENTAL. For deletes and updates, the CID of the previous record. For creates, undefined."
"description": "For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined."
}
}
}
Expand Down
78 changes: 68 additions & 10 deletions packages/api/src/client/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3517,7 +3517,14 @@ export const schemaDict = {
type: 'string',
description:
'If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.',
knownValues: ['takendown', 'suspended', 'deactivated'],
knownValues: [
'takendown',
'suspended',
'deleted',
'deactivated',
'desynchronized',
'throttled',
],
},
rev: {
type: 'string',
Expand Down Expand Up @@ -3671,7 +3678,14 @@ export const schemaDict = {
type: 'string',
description:
'If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.',
knownValues: ['takendown', 'suspended', 'deactivated'],
knownValues: [
'takendown',
'suspended',
'deleted',
'deactivated',
'desynchronized',
'throttled',
],
},
},
},
Expand Down Expand Up @@ -3810,6 +3824,7 @@ export const schemaDict = {
type: 'union',
refs: [
'lex:com.atproto.sync.subscribeRepos#commit',
'lex:com.atproto.sync.subscribeRepos#sync',
'lex:com.atproto.sync.subscribeRepos#identity',
'lex:com.atproto.sync.subscribeRepos#account',
'lex:com.atproto.sync.subscribeRepos#handle',
Expand Down Expand Up @@ -3860,12 +3875,13 @@ export const schemaDict = {
tooBig: {
type: 'boolean',
description:
'Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data.',
'DEPRECATED -- replaced by #sync event and data limits. Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data.',
},
repo: {
type: 'string',
format: 'did',
description: 'The repo this event comes from.',
description:
"The repo this event comes from. Note that all other message types name this field 'did'.",
},
commit: {
type: 'cid-link',
Expand All @@ -3886,8 +3902,8 @@ export const schemaDict = {
blocks: {
type: 'bytes',
description:
'CAR file containing relevant blocks, as a diff since the previous repo state.',
maxLength: 1000000,
"CAR file containing relevant blocks, as a diff since the previous repo state. The commit must be included as a block, and the commit block CID must be the first entry in the CAR header 'roots' list.",
maxLength: 2000000,
},
ops: {
type: 'array',
Expand All @@ -3904,13 +3920,48 @@ export const schemaDict = {
items: {
type: 'cid-link',
description:
'List of new blobs (by CID) referenced by records in this commit.',
'DEPRECATED -- will soon always be empty. List of new blobs (by CID) referenced by records in this commit.',
},
},
prevData: {
type: 'cid-link',
description:
"EXPERIMENTAL. The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose.",
"The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose.",
},
time: {
type: 'string',
format: 'datetime',
description:
'Timestamp of when this message was originally broadcast.',
},
},
},
sync: {
type: 'object',
description:
'Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository.',
required: ['seq', 'did', 'blocks', 'rev', 'time'],
properties: {
seq: {
type: 'integer',
description: 'The stream sequence number of this message.',
},
did: {
type: 'string',
format: 'did',
description:
'The account this repo event corresponds to. Must match that in the commit object.',
},
blocks: {
type: 'bytes',
description:
"CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'.",
maxLength: 10000,
},
rev: {
type: 'string',
description:
'The rev of the commit. This value must match that in the commit object.',
},
time: {
type: 'string',
Expand Down Expand Up @@ -3971,7 +4022,14 @@ export const schemaDict = {
type: 'string',
description:
'If active=false, this optional field indicates a reason for why the account is not active.',
knownValues: ['takendown', 'suspended', 'deleted', 'deactivated'],
knownValues: [
'takendown',
'suspended',
'deleted',
'deactivated',
'desynchronized',
'throttled',
],
},
},
},
Expand Down Expand Up @@ -4071,7 +4129,7 @@ export const schemaDict = {
prev: {
type: 'cid-link',
description:
'EXPERIMENTAL. For deletes and updates, the CID of the previous record. For creates, undefined.',
'For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined.',
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ export interface OutputSchema {
did: string
active: boolean
/** If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted. */
status?: 'takendown' | 'suspended' | 'deactivated' | (string & {})
status?:
| 'takendown'
| 'suspended'
| 'deleted'
| 'deactivated'
| 'desynchronized'
| 'throttled'
| (string & {})
/** Optional field, the current rev of the repo, if active=true */
rev?: string
}
Expand Down
9 changes: 8 additions & 1 deletion packages/api/src/client/types/com/atproto/sync/listRepos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ export interface Repo {
rev: string
active?: boolean
/** If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted. */
status?: 'takendown' | 'suspended' | 'deactivated' | (string & {})
status?:
| 'takendown'
| 'suspended'
| 'deleted'
| 'deactivated'
| 'desynchronized'
| 'throttled'
| (string & {})
}

const hashRepo = 'repo'
Expand Down
44 changes: 38 additions & 6 deletions packages/api/src/client/types/com/atproto/sync/subscribeRepos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ export interface Commit {
seq: number
/** DEPRECATED -- unused */
rebase: boolean
/** Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data. */
/** DEPRECATED -- replaced by #sync event and data limits. Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data. */
tooBig: boolean
/** The repo this event comes from. */
/** The repo this event comes from. Note that all other message types name this field 'did'. */
repo: string
/** Repo commit object CID. */
commit: CID
/** The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event. */
rev: string
/** The rev of the last emitted commit from this repo (if any). */
since: string | null
/** CAR file containing relevant blocks, as a diff since the previous repo state. */
/** CAR file containing relevant blocks, as a diff since the previous repo state. The commit must be included as a block, and the commit block CID must be the first entry in the CAR header 'roots' list. */
blocks: Uint8Array
ops: RepoOp[]
blobs: CID[]
/** EXPERIMENTAL. The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose. */
/** The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose. */
prevData?: CID
/** Timestamp of when this message was originally broadcast. */
time: string
Expand All @@ -48,6 +48,31 @@ export function validateCommit<V>(v: V) {
return validate<Commit & V>(v, id, hashCommit)
}

/** Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository. */
export interface Sync {
$type?: 'com.atproto.sync.subscribeRepos#sync'
/** The stream sequence number of this message. */
seq: number
/** The account this repo event corresponds to. Must match that in the commit object. */
did: string
/** CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'. */
blocks: Uint8Array
/** The rev of the commit. This value must match that in the commit object. */
rev: string
/** Timestamp of when this message was originally broadcast. */
time: string
}

const hashSync = 'sync'

export function isSync<V>(v: V) {
return is$typed(v, id, hashSync)
}

export function validateSync<V>(v: V) {
return validate<Sync & V>(v, id, hashSync)
}

/** Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache. */
export interface Identity {
$type?: 'com.atproto.sync.subscribeRepos#identity'
Expand Down Expand Up @@ -77,7 +102,14 @@ export interface Account {
/** Indicates that the account has a repository which can be fetched from the host that emitted this event. */
active: boolean
/** If active=false, this optional field indicates a reason for why the account is not active. */
status?: 'takendown' | 'suspended' | 'deleted' | 'deactivated' | (string & {})
status?:
| 'takendown'
| 'suspended'
| 'deleted'
| 'deactivated'
| 'desynchronized'
| 'throttled'
| (string & {})
}

const hashAccount = 'account'
Expand Down Expand Up @@ -169,7 +201,7 @@ export interface RepoOp {
path: string
/** For creates and updates, the new record CID. For deletions, null. */
cid: CID | null
/** EXPERIMENTAL. For deletes and updates, the CID of the previous record. For creates, undefined. */
/** For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined. */
prev?: CID
}

Expand Down
Loading

0 comments on commit 6e382f6

Please sign in to comment.