diff --git a/js/docs/src/content/docs/lex-reference/livestream/place-stream-livestream-update.md b/js/docs/src/content/docs/lex-reference/livestream/place-stream-livestream-update.md
new file mode 100644
index 00000000..430878fa
--- /dev/null
+++ b/js/docs/src/content/docs/lex-reference/livestream/place-stream-livestream-update.md
@@ -0,0 +1,133 @@
+---
+title: place.stream.livestream.update
+description: Reference for the place.stream.livestream.update lexicon
+---
+
+**Lexicon Version:** 1
+
+## Definitions
+
+
+
+### `main`
+
+**Type:** `procedure`
+
+Update livestream metadata on behalf of a streamer. Requires 'livestream.manage'
+permission. Updates a place.stream.livestream record in the streamer's
+repository.
+
+**Parameters:** _(None defined)_
+
+**Input:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| --------------- | -------- | ----- | ---------------------------------------------- | --------------------------------------- |
+| `streamer` | `string` | ✅ | The DID of the streamer. | Format: `did` |
+| `livestreamUri` | `string` | ✅ | The AT-URI of the livestream record to update. | Format: `at-uri` |
+| `title` | `string` | ❌ | New title for the livestream. | Max Length: 1400
Max Graphemes: 140 |
+
+**Output:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| ----- | -------- | ----- | -------------------------------------------- | ---------------- |
+| `uri` | `string` | ✅ | The AT-URI of the updated livestream record. | Format: `at-uri` |
+| `cid` | `string` | ✅ | The CID of the updated livestream record. | Format: `cid` |
+
+**Possible Errors:**
+
+- `Unauthorized`: The request lacks valid authentication credentials.
+- `Forbidden`: The caller does not have permission to update livestream metadata
+ for this streamer.
+- `SessionNotFound`: The streamer's OAuth session could not be found or is
+ invalid.
+- `RecordNotFound`: The specified livestream record does not exist.
+
+---
+
+## Lexicon Source
+
+```json
+{
+ "lexicon": 1,
+ "id": "place.stream.livestream.update",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Update livestream metadata on behalf of a streamer. Requires 'livestream.manage' permission. Updates a place.stream.livestream record in the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "livestreamUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "livestreamUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the livestream record to update."
+ },
+ "title": {
+ "type": "string",
+ "maxLength": 1400,
+ "maxGraphemes": 140,
+ "description": "New title for the livestream."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the updated livestream record."
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "The CID of the updated livestream record."
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to update livestream metadata for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ },
+ {
+ "name": "RecordNotFound",
+ "description": "The specified livestream record does not exist."
+ }
+ ]
+ }
+ }
+}
+```
diff --git a/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-createblock.md b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-createblock.md
new file mode 100644
index 00000000..af6f0219
--- /dev/null
+++ b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-createblock.md
@@ -0,0 +1,126 @@
+---
+title: place.stream.moderation.createBlock
+description: Reference for the place.stream.moderation.createBlock lexicon
+---
+
+**Lexicon Version:** 1
+
+## Definitions
+
+
+
+### `main`
+
+**Type:** `procedure`
+
+Create a block (ban) on behalf of a streamer. Requires 'ban' permission. Creates
+an app.bsky.graph.block record in the streamer's repository.
+
+**Parameters:** _(None defined)_
+
+**Input:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| ---------- | -------- | ----- | --------------------------------------------------------- | --------------- |
+| `streamer` | `string` | ✅ | The DID of the streamer whose chat this block applies to. | Format: `did` |
+| `subject` | `string` | ✅ | The DID of the user being blocked from chat. | Format: `did` |
+| `reason` | `string` | ❌ | Optional reason for the block. | Max Length: 300 |
+
+**Output:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| ----- | -------- | ----- | --------------------------------------- | ---------------- |
+| `uri` | `string` | ✅ | The AT-URI of the created block record. | Format: `at-uri` |
+| `cid` | `string` | ✅ | The CID of the created block record. | Format: `cid` |
+
+**Possible Errors:**
+
+- `Unauthorized`: The request lacks valid authentication credentials.
+- `Forbidden`: The caller does not have permission to create blocks for this
+ streamer.
+- `SessionNotFound`: The streamer's OAuth session could not be found or is
+ invalid.
+
+---
+
+## Lexicon Source
+
+```json
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.createBlock",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Create a block (ban) on behalf of a streamer. Requires 'ban' permission. Creates an app.bsky.graph.block record in the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "subject"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer whose chat this block applies to."
+ },
+ "subject": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the user being blocked from chat."
+ },
+ "reason": {
+ "type": "string",
+ "maxLength": 300,
+ "description": "Optional reason for the block."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the created block record."
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "The CID of the created block record."
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to create blocks for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ }
+ ]
+ }
+ }
+}
+```
diff --git a/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-creategate.md b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-creategate.md
new file mode 100644
index 00000000..e51bd7f7
--- /dev/null
+++ b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-creategate.md
@@ -0,0 +1,121 @@
+---
+title: place.stream.moderation.createGate
+description: Reference for the place.stream.moderation.createGate lexicon
+---
+
+**Lexicon Version:** 1
+
+## Definitions
+
+
+
+### `main`
+
+**Type:** `procedure`
+
+Create a gate (hide message) on behalf of a streamer. Requires 'hide'
+permission. Creates a place.stream.chat.gate record in the streamer's
+repository.
+
+**Parameters:** _(None defined)_
+
+**Input:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| ------------ | -------- | ----- | --------------------------------------- | ---------------- |
+| `streamer` | `string` | ✅ | The DID of the streamer. | Format: `did` |
+| `messageUri` | `string` | ✅ | The AT-URI of the chat message to hide. | Format: `at-uri` |
+
+**Output:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| ----- | -------- | ----- | -------------------------------------- | ---------------- |
+| `uri` | `string` | ✅ | The AT-URI of the created gate record. | Format: `at-uri` |
+| `cid` | `string` | ✅ | The CID of the created gate record. | Format: `cid` |
+
+**Possible Errors:**
+
+- `Unauthorized`: The request lacks valid authentication credentials.
+- `Forbidden`: The caller does not have permission to hide messages for this
+ streamer.
+- `SessionNotFound`: The streamer's OAuth session could not be found or is
+ invalid.
+
+---
+
+## Lexicon Source
+
+```json
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.createGate",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Create a gate (hide message) on behalf of a streamer. Requires 'hide' permission. Creates a place.stream.chat.gate record in the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "messageUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "messageUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the chat message to hide."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the created gate record."
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "The CID of the created gate record."
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to hide messages for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ }
+ ]
+ }
+ }
+}
+```
diff --git a/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-deleteblock.md b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-deleteblock.md
new file mode 100644
index 00000000..7cacecce
--- /dev/null
+++ b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-deleteblock.md
@@ -0,0 +1,103 @@
+---
+title: place.stream.moderation.deleteBlock
+description: Reference for the place.stream.moderation.deleteBlock lexicon
+---
+
+**Lexicon Version:** 1
+
+## Definitions
+
+
+
+### `main`
+
+**Type:** `procedure`
+
+Delete a block (unban) on behalf of a streamer. Requires 'ban' permission.
+Deletes an app.bsky.graph.block record from the streamer's repository.
+
+**Parameters:** _(None defined)_
+
+**Input:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| ---------- | -------- | ----- | ----------------------------------------- | ---------------- |
+| `streamer` | `string` | ✅ | The DID of the streamer. | Format: `did` |
+| `blockUri` | `string` | ✅ | The AT-URI of the block record to delete. | Format: `at-uri` |
+
+**Output:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+_(No properties defined)_ **Possible Errors:**
+
+- `Unauthorized`: The request lacks valid authentication credentials.
+- `Forbidden`: The caller does not have permission to delete blocks for this
+ streamer.
+- `SessionNotFound`: The streamer's OAuth session could not be found or is
+ invalid.
+
+---
+
+## Lexicon Source
+
+```json
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.deleteBlock",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Delete a block (unban) on behalf of a streamer. Requires 'ban' permission. Deletes an app.bsky.graph.block record from the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "blockUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "blockUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the block record to delete."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "properties": {}
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to delete blocks for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ }
+ ]
+ }
+ }
+}
+```
diff --git a/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-deletegate.md b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-deletegate.md
new file mode 100644
index 00000000..5296d543
--- /dev/null
+++ b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-deletegate.md
@@ -0,0 +1,104 @@
+---
+title: place.stream.moderation.deleteGate
+description: Reference for the place.stream.moderation.deleteGate lexicon
+---
+
+**Lexicon Version:** 1
+
+## Definitions
+
+
+
+### `main`
+
+**Type:** `procedure`
+
+Delete a gate (unhide message) on behalf of a streamer. Requires 'hide'
+permission. Deletes a place.stream.chat.gate record from the streamer's
+repository.
+
+**Parameters:** _(None defined)_
+
+**Input:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| ---------- | -------- | ----- | ---------------------------------------- | ---------------- |
+| `streamer` | `string` | ✅ | The DID of the streamer. | Format: `did` |
+| `gateUri` | `string` | ✅ | The AT-URI of the gate record to delete. | Format: `at-uri` |
+
+**Output:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+_(No properties defined)_ **Possible Errors:**
+
+- `Unauthorized`: The request lacks valid authentication credentials.
+- `Forbidden`: The caller does not have permission to unhide messages for this
+ streamer.
+- `SessionNotFound`: The streamer's OAuth session could not be found or is
+ invalid.
+
+---
+
+## Lexicon Source
+
+```json
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.deleteGate",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Delete a gate (unhide message) on behalf of a streamer. Requires 'hide' permission. Deletes a place.stream.chat.gate record from the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "gateUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "gateUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the gate record to delete."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "properties": {}
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to unhide messages for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ }
+ ]
+ }
+ }
+}
+```
diff --git a/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-permission.md b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-permission.md
new file mode 100644
index 00000000..986eafb7
--- /dev/null
+++ b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-permission.md
@@ -0,0 +1,74 @@
+---
+title: place.stream.moderation.permission
+description: Reference for the place.stream.moderation.permission lexicon
+---
+
+**Lexicon Version:** 1
+
+## Definitions
+
+
+
+### `main`
+
+**Type:** `record`
+
+Record granting moderation permissions to a user for this streamer's content.
+
+**Record Key:** `tid`
+
+**Record Properties:**
+
+| Name | Type | Req'd | Description | Constraints |
+| ---------------- | ----------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ |
+| `moderator` | `string` | ✅ | The DID of the user granted moderator permissions. | Format: `did` |
+| `permissions` | Array of `string` | ✅ | Array of permissions granted to this moderator. 'ban' covers blocks/bans (with optional expiration), 'hide' covers message gates, 'livestream.manage' allows updating livestream metadata. | |
+| `createdAt` | `string` | ✅ | Client-declared timestamp when this moderator was added. | Format: `datetime` |
+| `expirationTime` | `string` | ❌ | Optional expiration time for this delegation. If set, the delegation is invalid after this time. | Format: `datetime` |
+
+---
+
+## Lexicon Source
+
+```json
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.permission",
+ "defs": {
+ "main": {
+ "type": "record",
+ "key": "tid",
+ "description": "Record granting moderation permissions to a user for this streamer's content.",
+ "record": {
+ "type": "object",
+ "required": ["moderator", "permissions", "createdAt"],
+ "properties": {
+ "moderator": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the user granted moderator permissions."
+ },
+ "permissions": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": ["ban", "hide", "livestream.manage"]
+ },
+ "description": "Array of permissions granted to this moderator. 'ban' covers blocks/bans (with optional expiration), 'hide' covers message gates, 'livestream.manage' allows updating livestream metadata."
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "datetime",
+ "description": "Client-declared timestamp when this moderator was added."
+ },
+ "expirationTime": {
+ "type": "string",
+ "format": "datetime",
+ "description": "Optional expiration time for this delegation. If set, the delegation is invalid after this time."
+ }
+ }
+ }
+ }
+ }
+}
+```
diff --git a/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-updatelivestream.md b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-updatelivestream.md
new file mode 100644
index 00000000..73441e44
--- /dev/null
+++ b/js/docs/src/content/docs/lex-reference/moderation/place-stream-moderation-updatelivestream.md
@@ -0,0 +1,133 @@
+---
+title: place.stream.moderation.updateLivestream
+description: Reference for the place.stream.moderation.updateLivestream lexicon
+---
+
+**Lexicon Version:** 1
+
+## Definitions
+
+
+
+### `main`
+
+**Type:** `procedure`
+
+Update livestream metadata on behalf of a streamer. Requires 'livestream.manage'
+permission. Updates a place.stream.livestream record in the streamer's
+repository.
+
+**Parameters:** _(None defined)_
+
+**Input:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| --------------- | -------- | ----- | ---------------------------------------------- | --------------------------------------- |
+| `streamer` | `string` | ✅ | The DID of the streamer. | Format: `did` |
+| `livestreamUri` | `string` | ✅ | The AT-URI of the livestream record to update. | Format: `at-uri` |
+| `title` | `string` | ❌ | New title for the livestream. | Max Length: 1400
Max Graphemes: 140 |
+
+**Output:**
+
+- **Encoding:** `application/json`
+- **Schema:**
+
+**Schema Type:** `object`
+
+| Name | Type | Req'd | Description | Constraints |
+| ----- | -------- | ----- | -------------------------------------------- | ---------------- |
+| `uri` | `string` | ✅ | The AT-URI of the updated livestream record. | Format: `at-uri` |
+| `cid` | `string` | ✅ | The CID of the updated livestream record. | Format: `cid` |
+
+**Possible Errors:**
+
+- `Unauthorized`: The request lacks valid authentication credentials.
+- `Forbidden`: The caller does not have permission to update livestream metadata
+ for this streamer.
+- `SessionNotFound`: The streamer's OAuth session could not be found or is
+ invalid.
+- `RecordNotFound`: The specified livestream record does not exist.
+
+---
+
+## Lexicon Source
+
+```json
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.updateLivestream",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Update livestream metadata on behalf of a streamer. Requires 'livestream.manage' permission. Updates a place.stream.livestream record in the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "livestreamUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "livestreamUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the livestream record to update."
+ },
+ "title": {
+ "type": "string",
+ "maxLength": 1400,
+ "maxGraphemes": 140,
+ "description": "New title for the livestream."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the updated livestream record."
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "The CID of the updated livestream record."
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to update livestream metadata for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ },
+ {
+ "name": "RecordNotFound",
+ "description": "The specified livestream record does not exist."
+ }
+ ]
+ }
+ }
+}
+```
diff --git a/js/docs/src/content/docs/lex-reference/openapi.json b/js/docs/src/content/docs/lex-reference/openapi.json
index 4e13d6b6..a24f7d4c 100644
--- a/js/docs/src/content/docs/lex-reference/openapi.json
+++ b/js/docs/src/content/docs/lex-reference/openapi.json
@@ -517,6 +517,420 @@
}
}
},
+ "/xrpc/place.stream.moderation.createBlock": {
+ "post": {
+ "summary": "Create a block (ban) on behalf of a streamer. Requires 'ban' permission. Creates an app.bsky.graph.block record in the streamer's repository.",
+ "operationId": "place.stream.moderation.createBlock",
+ "tags": ["place.stream.moderation"],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "uri": {
+ "type": "string",
+ "description": "The AT-URI of the created block record.",
+ "format": "uri"
+ },
+ "cid": {
+ "type": "string",
+ "description": "The CID of the created block record.",
+ "format": "cid"
+ }
+ },
+ "required": ["uri", "cid"]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": ["error", "message"],
+ "properties": {
+ "error": {
+ "type": "string",
+ "oneOf": [
+ {
+ "const": "Unauthorized"
+ },
+ {
+ "const": "Forbidden"
+ },
+ {
+ "const": "SessionNotFound"
+ }
+ ]
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "description": "The DID of the streamer whose chat this block applies to.",
+ "format": "did"
+ },
+ "subject": {
+ "type": "string",
+ "description": "The DID of the user being blocked from chat.",
+ "format": "did"
+ },
+ "reason": {
+ "type": "string",
+ "description": "Optional reason for the block.",
+ "maxLength": 300
+ }
+ },
+ "required": ["streamer", "subject"]
+ }
+ }
+ }
+ }
+ }
+ },
+ "/xrpc/place.stream.moderation.createGate": {
+ "post": {
+ "summary": "Create a gate (hide message) on behalf of a streamer. Requires 'hide' permission. Creates a place.stream.chat.gate record in the streamer's repository.",
+ "operationId": "place.stream.moderation.createGate",
+ "tags": ["place.stream.moderation"],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "uri": {
+ "type": "string",
+ "description": "The AT-URI of the created gate record.",
+ "format": "uri"
+ },
+ "cid": {
+ "type": "string",
+ "description": "The CID of the created gate record.",
+ "format": "cid"
+ }
+ },
+ "required": ["uri", "cid"]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": ["error", "message"],
+ "properties": {
+ "error": {
+ "type": "string",
+ "oneOf": [
+ {
+ "const": "Unauthorized"
+ },
+ {
+ "const": "Forbidden"
+ },
+ {
+ "const": "SessionNotFound"
+ }
+ ]
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "description": "The DID of the streamer.",
+ "format": "did"
+ },
+ "messageUri": {
+ "type": "string",
+ "description": "The AT-URI of the chat message to hide.",
+ "format": "uri"
+ }
+ },
+ "required": ["streamer", "messageUri"]
+ }
+ }
+ }
+ }
+ }
+ },
+ "/xrpc/place.stream.moderation.deleteBlock": {
+ "post": {
+ "summary": "Delete a block (unban) on behalf of a streamer. Requires 'ban' permission. Deletes an app.bsky.graph.block record from the streamer's repository.",
+ "operationId": "place.stream.moderation.deleteBlock",
+ "tags": ["place.stream.moderation"],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {}
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": ["error", "message"],
+ "properties": {
+ "error": {
+ "type": "string",
+ "oneOf": [
+ {
+ "const": "Unauthorized"
+ },
+ {
+ "const": "Forbidden"
+ },
+ {
+ "const": "SessionNotFound"
+ }
+ ]
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "description": "The DID of the streamer.",
+ "format": "did"
+ },
+ "blockUri": {
+ "type": "string",
+ "description": "The AT-URI of the block record to delete.",
+ "format": "uri"
+ }
+ },
+ "required": ["streamer", "blockUri"]
+ }
+ }
+ }
+ }
+ }
+ },
+ "/xrpc/place.stream.moderation.deleteGate": {
+ "post": {
+ "summary": "Delete a gate (unhide message) on behalf of a streamer. Requires 'hide' permission. Deletes a place.stream.chat.gate record from the streamer's repository.",
+ "operationId": "place.stream.moderation.deleteGate",
+ "tags": ["place.stream.moderation"],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {}
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": ["error", "message"],
+ "properties": {
+ "error": {
+ "type": "string",
+ "oneOf": [
+ {
+ "const": "Unauthorized"
+ },
+ {
+ "const": "Forbidden"
+ },
+ {
+ "const": "SessionNotFound"
+ }
+ ]
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "description": "The DID of the streamer.",
+ "format": "did"
+ },
+ "gateUri": {
+ "type": "string",
+ "description": "The AT-URI of the gate record to delete.",
+ "format": "uri"
+ }
+ },
+ "required": ["streamer", "gateUri"]
+ }
+ }
+ }
+ }
+ }
+ },
+ "/xrpc/place.stream.moderation.updateLivestream": {
+ "post": {
+ "summary": "Update livestream metadata on behalf of a streamer. Requires 'livestream.manage' permission. Updates a place.stream.livestream record in the streamer's repository.",
+ "operationId": "place.stream.moderation.updateLivestream",
+ "tags": ["place.stream.moderation"],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "uri": {
+ "type": "string",
+ "description": "The AT-URI of the updated livestream record.",
+ "format": "uri"
+ },
+ "cid": {
+ "type": "string",
+ "description": "The CID of the updated livestream record.",
+ "format": "cid"
+ }
+ },
+ "required": ["uri", "cid"]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": ["error", "message"],
+ "properties": {
+ "error": {
+ "type": "string",
+ "oneOf": [
+ {
+ "const": "Unauthorized"
+ },
+ {
+ "const": "Forbidden"
+ },
+ {
+ "const": "SessionNotFound"
+ },
+ {
+ "const": "RecordNotFound"
+ }
+ ]
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "description": "The DID of the streamer.",
+ "format": "did"
+ },
+ "livestreamUri": {
+ "type": "string",
+ "description": "The AT-URI of the livestream record to update.",
+ "format": "uri"
+ },
+ "title": {
+ "type": "string",
+ "description": "New title for the livestream.",
+ "maxLength": 1400
+ }
+ },
+ "required": ["streamer", "livestreamUri"]
+ }
+ }
+ }
+ }
+ }
+ },
"/xrpc/place.stream.live.getLiveUsers": {
"get": {
"summary": "Get a list of livestream segments for a user",
diff --git a/lexicons/place/stream/moderation/createBlock.json b/lexicons/place/stream/moderation/createBlock.json
new file mode 100644
index 00000000..69aab27c
--- /dev/null
+++ b/lexicons/place/stream/moderation/createBlock.json
@@ -0,0 +1,67 @@
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.createBlock",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Create a block (ban) on behalf of a streamer. Requires 'ban' permission. Creates an app.bsky.graph.block record in the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "subject"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer whose chat this block applies to."
+ },
+ "subject": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the user being blocked from chat."
+ },
+ "reason": {
+ "type": "string",
+ "maxLength": 300,
+ "description": "Optional reason for the block."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the created block record."
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "The CID of the created block record."
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to create blocks for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ }
+ ]
+ }
+ }
+}
diff --git a/lexicons/place/stream/moderation/createGate.json b/lexicons/place/stream/moderation/createGate.json
new file mode 100644
index 00000000..8f6235ce
--- /dev/null
+++ b/lexicons/place/stream/moderation/createGate.json
@@ -0,0 +1,62 @@
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.createGate",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Create a gate (hide message) on behalf of a streamer. Requires 'hide' permission. Creates a place.stream.chat.gate record in the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "messageUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "messageUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the chat message to hide."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the created gate record."
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "The CID of the created gate record."
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to hide messages for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ }
+ ]
+ }
+ }
+}
diff --git a/lexicons/place/stream/moderation/deleteBlock.json b/lexicons/place/stream/moderation/deleteBlock.json
new file mode 100644
index 00000000..6e5a9498
--- /dev/null
+++ b/lexicons/place/stream/moderation/deleteBlock.json
@@ -0,0 +1,50 @@
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.deleteBlock",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Delete a block (unban) on behalf of a streamer. Requires 'ban' permission. Deletes an app.bsky.graph.block record from the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "blockUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "blockUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the block record to delete."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "properties": {}
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to delete blocks for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ }
+ ]
+ }
+ }
+}
diff --git a/lexicons/place/stream/moderation/deleteGate.json b/lexicons/place/stream/moderation/deleteGate.json
new file mode 100644
index 00000000..6d4bb4b7
--- /dev/null
+++ b/lexicons/place/stream/moderation/deleteGate.json
@@ -0,0 +1,50 @@
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.deleteGate",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Delete a gate (unhide message) on behalf of a streamer. Requires 'hide' permission. Deletes a place.stream.chat.gate record from the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "gateUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "gateUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the gate record to delete."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "properties": {}
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to unhide messages for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ }
+ ]
+ }
+ }
+}
diff --git a/lexicons/place/stream/moderation/permission.json b/lexicons/place/stream/moderation/permission.json
new file mode 100644
index 00000000..ee579693
--- /dev/null
+++ b/lexicons/place/stream/moderation/permission.json
@@ -0,0 +1,40 @@
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.permission",
+ "defs": {
+ "main": {
+ "type": "record",
+ "key": "tid",
+ "description": "Record granting moderation permissions to a user for this streamer's content.",
+ "record": {
+ "type": "object",
+ "required": ["moderator", "permissions", "createdAt"],
+ "properties": {
+ "moderator": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the user granted moderator permissions."
+ },
+ "permissions": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": ["ban", "hide", "livestream.manage"]
+ },
+ "description": "Array of permissions granted to this moderator. 'ban' covers blocks/bans (with optional expiration), 'hide' covers message gates, 'livestream.manage' allows updating livestream metadata."
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "datetime",
+ "description": "Client-declared timestamp when this moderator was added."
+ },
+ "expirationTime": {
+ "type": "string",
+ "format": "datetime",
+ "description": "Optional expiration time for this delegation. If set, the delegation is invalid after this time."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lexicons/place/stream/moderation/updateLivestream.json b/lexicons/place/stream/moderation/updateLivestream.json
new file mode 100644
index 00000000..e0072807
--- /dev/null
+++ b/lexicons/place/stream/moderation/updateLivestream.json
@@ -0,0 +1,72 @@
+{
+ "lexicon": 1,
+ "id": "place.stream.moderation.updateLivestream",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Update livestream metadata on behalf of a streamer. Requires 'livestream.manage' permission. Updates a place.stream.livestream record in the streamer's repository.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["streamer", "livestreamUri"],
+ "properties": {
+ "streamer": {
+ "type": "string",
+ "format": "did",
+ "description": "The DID of the streamer."
+ },
+ "livestreamUri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the livestream record to update."
+ },
+ "title": {
+ "type": "string",
+ "maxLength": 1400,
+ "maxGraphemes": 140,
+ "description": "New title for the livestream."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": {
+ "type": "string",
+ "format": "at-uri",
+ "description": "The AT-URI of the updated livestream record."
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "The CID of the updated livestream record."
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "Unauthorized",
+ "description": "The request lacks valid authentication credentials."
+ },
+ {
+ "name": "Forbidden",
+ "description": "The caller does not have permission to update livestream metadata for this streamer."
+ },
+ {
+ "name": "SessionNotFound",
+ "description": "The streamer's OAuth session could not be found or is invalid."
+ },
+ {
+ "name": "RecordNotFound",
+ "description": "The specified livestream record does not exist."
+ }
+ ]
+ }
+ }
+}
diff --git a/pkg/gen/gen.go b/pkg/gen/gen.go
index 7ec89429..523577ad 100644
--- a/pkg/gen/gen.go
+++ b/pkg/gen/gen.go
@@ -32,6 +32,7 @@ func main() {
streamplace.MetadataDistributionPolicy{},
streamplace.MetadataContentRights{},
streamplace.MetadataContentWarnings{},
+ streamplace.ModerationPermission{},
); err != nil {
panic(err)
}
diff --git a/pkg/streamplace/cbor_gen.go b/pkg/streamplace/cbor_gen.go
index b58bdda8..f23ad443 100644
--- a/pkg/streamplace/cbor_gen.go
+++ b/pkg/streamplace/cbor_gen.go
@@ -4975,3 +4975,298 @@ func (t *MetadataContentWarnings) UnmarshalCBOR(r io.Reader) (err error) {
return nil
}
+func (t *ModerationPermission) MarshalCBOR(w io.Writer) error {
+ if t == nil {
+ _, err := w.Write(cbg.CborNull)
+ return err
+ }
+
+ cw := cbg.NewCborWriter(w)
+ fieldCount := 5
+
+ if t.ExpirationTime == nil {
+ fieldCount--
+ }
+
+ if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil {
+ return err
+ }
+
+ // t.LexiconTypeID (string) (string)
+ if len("$type") > 1000000 {
+ return xerrors.Errorf("Value in field \"$type\" was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string("$type")); err != nil {
+ return err
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("place.stream.moderation.permission"))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string("place.stream.moderation.permission")); err != nil {
+ return err
+ }
+
+ // t.CreatedAt (string) (string)
+ if len("createdAt") > 1000000 {
+ return xerrors.Errorf("Value in field \"createdAt\" was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("createdAt"))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string("createdAt")); err != nil {
+ return err
+ }
+
+ if len(t.CreatedAt) > 1000000 {
+ return xerrors.Errorf("Value in field t.CreatedAt was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.CreatedAt))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string(t.CreatedAt)); err != nil {
+ return err
+ }
+
+ // t.Moderator (string) (string)
+ if len("moderator") > 1000000 {
+ return xerrors.Errorf("Value in field \"moderator\" was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("moderator"))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string("moderator")); err != nil {
+ return err
+ }
+
+ if len(t.Moderator) > 1000000 {
+ return xerrors.Errorf("Value in field t.Moderator was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Moderator))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string(t.Moderator)); err != nil {
+ return err
+ }
+
+ // t.Permissions ([]string) (slice)
+ if len("permissions") > 1000000 {
+ return xerrors.Errorf("Value in field \"permissions\" was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("permissions"))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string("permissions")); err != nil {
+ return err
+ }
+
+ if len(t.Permissions) > 8192 {
+ return xerrors.Errorf("Slice value in field t.Permissions was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Permissions))); err != nil {
+ return err
+ }
+ for _, v := range t.Permissions {
+ if len(v) > 1000000 {
+ return xerrors.Errorf("Value in field v was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string(v)); err != nil {
+ return err
+ }
+
+ }
+
+ // t.ExpirationTime (string) (string)
+ if t.ExpirationTime != nil {
+
+ if len("expirationTime") > 1000000 {
+ return xerrors.Errorf("Value in field \"expirationTime\" was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("expirationTime"))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string("expirationTime")); err != nil {
+ return err
+ }
+
+ if t.ExpirationTime == nil {
+ if _, err := cw.Write(cbg.CborNull); err != nil {
+ return err
+ }
+ } else {
+ if len(*t.ExpirationTime) > 1000000 {
+ return xerrors.Errorf("Value in field t.ExpirationTime was too long")
+ }
+
+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.ExpirationTime))); err != nil {
+ return err
+ }
+ if _, err := cw.WriteString(string(*t.ExpirationTime)); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (t *ModerationPermission) UnmarshalCBOR(r io.Reader) (err error) {
+ *t = ModerationPermission{}
+
+ cr := cbg.NewCborReader(r)
+
+ maj, extra, err := cr.ReadHeader()
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ }()
+
+ if maj != cbg.MajMap {
+ return fmt.Errorf("cbor input should be of type map")
+ }
+
+ if extra > cbg.MaxLength {
+ return fmt.Errorf("ModerationPermission: map struct too large (%d)", extra)
+ }
+
+ n := extra
+
+ nameBuf := make([]byte, 14)
+ for i := uint64(0); i < n; i++ {
+ nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000)
+ if err != nil {
+ return err
+ }
+
+ if !ok {
+ // Field doesn't exist on this type, so ignore it
+ if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil {
+ return err
+ }
+ continue
+ }
+
+ switch string(nameBuf[:nameLen]) {
+ // t.LexiconTypeID (string) (string)
+ case "$type":
+
+ {
+ sval, err := cbg.ReadStringWithMax(cr, 1000000)
+ if err != nil {
+ return err
+ }
+
+ t.LexiconTypeID = string(sval)
+ }
+ // t.CreatedAt (string) (string)
+ case "createdAt":
+
+ {
+ sval, err := cbg.ReadStringWithMax(cr, 1000000)
+ if err != nil {
+ return err
+ }
+
+ t.CreatedAt = string(sval)
+ }
+ // t.Moderator (string) (string)
+ case "moderator":
+
+ {
+ sval, err := cbg.ReadStringWithMax(cr, 1000000)
+ if err != nil {
+ return err
+ }
+
+ t.Moderator = string(sval)
+ }
+ // t.Permissions ([]string) (slice)
+ case "permissions":
+
+ maj, extra, err = cr.ReadHeader()
+ if err != nil {
+ return err
+ }
+
+ if extra > 8192 {
+ return fmt.Errorf("t.Permissions: array too large (%d)", extra)
+ }
+
+ if maj != cbg.MajArray {
+ return fmt.Errorf("expected cbor array")
+ }
+
+ if extra > 0 {
+ t.Permissions = make([]string, extra)
+ }
+
+ for i := 0; i < int(extra); i++ {
+ {
+ var maj byte
+ var extra uint64
+ var err error
+ _ = maj
+ _ = extra
+ _ = err
+
+ {
+ sval, err := cbg.ReadStringWithMax(cr, 1000000)
+ if err != nil {
+ return err
+ }
+
+ t.Permissions[i] = string(sval)
+ }
+
+ }
+ }
+ // t.ExpirationTime (string) (string)
+ case "expirationTime":
+
+ {
+ b, err := cr.ReadByte()
+ if err != nil {
+ return err
+ }
+ if b != cbg.CborNull[0] {
+ if err := cr.UnreadByte(); err != nil {
+ return err
+ }
+
+ sval, err := cbg.ReadStringWithMax(cr, 1000000)
+ if err != nil {
+ return err
+ }
+
+ t.ExpirationTime = (*string)(&sval)
+ }
+ }
+
+ default:
+ // Field doesn't exist on this type, so ignore it
+ if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/pkg/streamplace/moderationcreateBlock.go b/pkg/streamplace/moderationcreateBlock.go
new file mode 100644
index 00000000..9a10af94
--- /dev/null
+++ b/pkg/streamplace/moderationcreateBlock.go
@@ -0,0 +1,39 @@
+// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.
+
+// Lexicon schema: place.stream.moderation.createBlock
+
+package streamplace
+
+import (
+ "context"
+
+ lexutil "github.com/bluesky-social/indigo/lex/util"
+)
+
+// ModerationCreateBlock_Input is the input argument to a place.stream.moderation.createBlock call.
+type ModerationCreateBlock_Input struct {
+ // reason: Optional reason for the block.
+ Reason *string `json:"reason,omitempty" cborgen:"reason,omitempty"`
+ // streamer: The DID of the streamer whose chat this block applies to.
+ Streamer string `json:"streamer" cborgen:"streamer"`
+ // subject: The DID of the user being blocked from chat.
+ Subject string `json:"subject" cborgen:"subject"`
+}
+
+// ModerationCreateBlock_Output is the output of a place.stream.moderation.createBlock call.
+type ModerationCreateBlock_Output struct {
+ // cid: The CID of the created block record.
+ Cid string `json:"cid" cborgen:"cid"`
+ // uri: The AT-URI of the created block record.
+ Uri string `json:"uri" cborgen:"uri"`
+}
+
+// ModerationCreateBlock calls the XRPC method "place.stream.moderation.createBlock".
+func ModerationCreateBlock(ctx context.Context, c lexutil.LexClient, input *ModerationCreateBlock_Input) (*ModerationCreateBlock_Output, error) {
+ var out ModerationCreateBlock_Output
+ if err := c.LexDo(ctx, lexutil.Procedure, "application/json", "place.stream.moderation.createBlock", nil, input, &out); err != nil {
+ return nil, err
+ }
+
+ return &out, nil
+}
diff --git a/pkg/streamplace/moderationcreateGate.go b/pkg/streamplace/moderationcreateGate.go
new file mode 100644
index 00000000..d2cabff4
--- /dev/null
+++ b/pkg/streamplace/moderationcreateGate.go
@@ -0,0 +1,37 @@
+// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.
+
+// Lexicon schema: place.stream.moderation.createGate
+
+package streamplace
+
+import (
+ "context"
+
+ lexutil "github.com/bluesky-social/indigo/lex/util"
+)
+
+// ModerationCreateGate_Input is the input argument to a place.stream.moderation.createGate call.
+type ModerationCreateGate_Input struct {
+ // messageUri: The AT-URI of the chat message to hide.
+ MessageUri string `json:"messageUri" cborgen:"messageUri"`
+ // streamer: The DID of the streamer.
+ Streamer string `json:"streamer" cborgen:"streamer"`
+}
+
+// ModerationCreateGate_Output is the output of a place.stream.moderation.createGate call.
+type ModerationCreateGate_Output struct {
+ // cid: The CID of the created gate record.
+ Cid string `json:"cid" cborgen:"cid"`
+ // uri: The AT-URI of the created gate record.
+ Uri string `json:"uri" cborgen:"uri"`
+}
+
+// ModerationCreateGate calls the XRPC method "place.stream.moderation.createGate".
+func ModerationCreateGate(ctx context.Context, c lexutil.LexClient, input *ModerationCreateGate_Input) (*ModerationCreateGate_Output, error) {
+ var out ModerationCreateGate_Output
+ if err := c.LexDo(ctx, lexutil.Procedure, "application/json", "place.stream.moderation.createGate", nil, input, &out); err != nil {
+ return nil, err
+ }
+
+ return &out, nil
+}
diff --git a/pkg/streamplace/moderationdeleteBlock.go b/pkg/streamplace/moderationdeleteBlock.go
new file mode 100644
index 00000000..184862cb
--- /dev/null
+++ b/pkg/streamplace/moderationdeleteBlock.go
@@ -0,0 +1,33 @@
+// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.
+
+// Lexicon schema: place.stream.moderation.deleteBlock
+
+package streamplace
+
+import (
+ "context"
+
+ lexutil "github.com/bluesky-social/indigo/lex/util"
+)
+
+// ModerationDeleteBlock_Input is the input argument to a place.stream.moderation.deleteBlock call.
+type ModerationDeleteBlock_Input struct {
+ // blockUri: The AT-URI of the block record to delete.
+ BlockUri string `json:"blockUri" cborgen:"blockUri"`
+ // streamer: The DID of the streamer.
+ Streamer string `json:"streamer" cborgen:"streamer"`
+}
+
+// ModerationDeleteBlock_Output is the output of a place.stream.moderation.deleteBlock call.
+type ModerationDeleteBlock_Output struct {
+}
+
+// ModerationDeleteBlock calls the XRPC method "place.stream.moderation.deleteBlock".
+func ModerationDeleteBlock(ctx context.Context, c lexutil.LexClient, input *ModerationDeleteBlock_Input) (*ModerationDeleteBlock_Output, error) {
+ var out ModerationDeleteBlock_Output
+ if err := c.LexDo(ctx, lexutil.Procedure, "application/json", "place.stream.moderation.deleteBlock", nil, input, &out); err != nil {
+ return nil, err
+ }
+
+ return &out, nil
+}
diff --git a/pkg/streamplace/moderationdeleteGate.go b/pkg/streamplace/moderationdeleteGate.go
new file mode 100644
index 00000000..dce20408
--- /dev/null
+++ b/pkg/streamplace/moderationdeleteGate.go
@@ -0,0 +1,33 @@
+// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.
+
+// Lexicon schema: place.stream.moderation.deleteGate
+
+package streamplace
+
+import (
+ "context"
+
+ lexutil "github.com/bluesky-social/indigo/lex/util"
+)
+
+// ModerationDeleteGate_Input is the input argument to a place.stream.moderation.deleteGate call.
+type ModerationDeleteGate_Input struct {
+ // gateUri: The AT-URI of the gate record to delete.
+ GateUri string `json:"gateUri" cborgen:"gateUri"`
+ // streamer: The DID of the streamer.
+ Streamer string `json:"streamer" cborgen:"streamer"`
+}
+
+// ModerationDeleteGate_Output is the output of a place.stream.moderation.deleteGate call.
+type ModerationDeleteGate_Output struct {
+}
+
+// ModerationDeleteGate calls the XRPC method "place.stream.moderation.deleteGate".
+func ModerationDeleteGate(ctx context.Context, c lexutil.LexClient, input *ModerationDeleteGate_Input) (*ModerationDeleteGate_Output, error) {
+ var out ModerationDeleteGate_Output
+ if err := c.LexDo(ctx, lexutil.Procedure, "application/json", "place.stream.moderation.deleteGate", nil, input, &out); err != nil {
+ return nil, err
+ }
+
+ return &out, nil
+}
diff --git a/pkg/streamplace/moderationpermission.go b/pkg/streamplace/moderationpermission.go
new file mode 100644
index 00000000..88c9b8fb
--- /dev/null
+++ b/pkg/streamplace/moderationpermission.go
@@ -0,0 +1,25 @@
+// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.
+
+// Lexicon schema: place.stream.moderation.permission
+
+package streamplace
+
+import (
+ lexutil "github.com/bluesky-social/indigo/lex/util"
+)
+
+func init() {
+ lexutil.RegisterType("place.stream.moderation.permission", &ModerationPermission{})
+}
+
+type ModerationPermission struct {
+ LexiconTypeID string `json:"$type" cborgen:"$type,const=place.stream.moderation.permission"`
+ // createdAt: Client-declared timestamp when this moderator was added.
+ CreatedAt string `json:"createdAt" cborgen:"createdAt"`
+ // expirationTime: Optional expiration time for this delegation. If set, the delegation is invalid after this time.
+ ExpirationTime *string `json:"expirationTime,omitempty" cborgen:"expirationTime,omitempty"`
+ // moderator: The DID of the user granted moderator permissions.
+ Moderator string `json:"moderator" cborgen:"moderator"`
+ // permissions: Array of permissions granted to this moderator. 'ban' covers blocks/bans (with optional expiration), 'hide' covers message gates, 'livestream.manage' allows updating livestream metadata.
+ Permissions []string `json:"permissions" cborgen:"permissions"`
+}
diff --git a/pkg/streamplace/moderationupdateLivestream.go b/pkg/streamplace/moderationupdateLivestream.go
new file mode 100644
index 00000000..e0642dcf
--- /dev/null
+++ b/pkg/streamplace/moderationupdateLivestream.go
@@ -0,0 +1,39 @@
+// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.
+
+// Lexicon schema: place.stream.moderation.updateLivestream
+
+package streamplace
+
+import (
+ "context"
+
+ lexutil "github.com/bluesky-social/indigo/lex/util"
+)
+
+// ModerationUpdateLivestream_Input is the input argument to a place.stream.moderation.updateLivestream call.
+type ModerationUpdateLivestream_Input struct {
+ // livestreamUri: The AT-URI of the livestream record to update.
+ LivestreamUri string `json:"livestreamUri" cborgen:"livestreamUri"`
+ // streamer: The DID of the streamer.
+ Streamer string `json:"streamer" cborgen:"streamer"`
+ // title: New title for the livestream.
+ Title *string `json:"title,omitempty" cborgen:"title,omitempty"`
+}
+
+// ModerationUpdateLivestream_Output is the output of a place.stream.moderation.updateLivestream call.
+type ModerationUpdateLivestream_Output struct {
+ // cid: The CID of the updated livestream record.
+ Cid string `json:"cid" cborgen:"cid"`
+ // uri: The AT-URI of the updated livestream record.
+ Uri string `json:"uri" cborgen:"uri"`
+}
+
+// ModerationUpdateLivestream calls the XRPC method "place.stream.moderation.updateLivestream".
+func ModerationUpdateLivestream(ctx context.Context, c lexutil.LexClient, input *ModerationUpdateLivestream_Input) (*ModerationUpdateLivestream_Output, error) {
+ var out ModerationUpdateLivestream_Output
+ if err := c.LexDo(ctx, lexutil.Procedure, "application/json", "place.stream.moderation.updateLivestream", nil, input, &out); err != nil {
+ return nil, err
+ }
+
+ return &out, nil
+}