From 1005c1e292acc85fb6d1f0f26e7887fdb0444a4b Mon Sep 17 00:00:00 2001 From: Zita Szupera Date: Fri, 16 Oct 2026 11:22:45 -0500 Subject: [PATCH] chore: update docs snippet runner after v9 snippets added back to docs --- .claude/skills/docs-sync/SKILL.md | 23 ++++++++++--------- __tests__/docs-snippets/README.md | 7 +++--- .../docs-snippets/sync/docs-sync.test.ts | 5 ++-- __tests__/docs-snippets/sync/parse.ts | 12 ++++++++-- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/.claude/skills/docs-sync/SKILL.md b/.claude/skills/docs-sync/SKILL.md index a167613..8576639 100644 --- a/.claude/skills/docs-sync/SKILL.md +++ b/.claude/skills/docs-sync/SKILL.md @@ -51,17 +51,17 @@ Before the sync check, make sure every server-side snippet on the tested pages h - Pages: every page of the `[chat][node].json` and `[platform][default].json` sidebars (`$DOCS_DIR/_sidebars/`) under `chat/` or `platform/`, the same list as `findSidebarPages` in `sync/parse.ts`. - Fences: every JS fence (`js`, `javascript`, `ts`, `typescript`) labelled `JavaScript` or unlabelled, together with its tab group: the other fences in the same `` block, or the fence alone when it isn't in one. -- Out of scope: `React` and `React Native` fences, `Node.js` fences inside a `` block, and comment-only fences. +- Out of scope: `React` and `React Native` fences, the stream-chat-js@9 fences (`JavaScript (stream-chat-js@9)`, `Node.js (stream-chat-js@9)`), `Node.js` fences inside a `` block, and comment-only fences. List them with a throwaway script in the scratchpad (page, heading, line, the labels in the group, the code). Then classify each group by its tabs first and the prose second: -| Group | Action | -| -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -| A `JavaScript` fence with server-only code (secret, `updateAppSettings`, `createToken`, ...) | Relabel it `Node.js` and rewrite it to the node SDK call (`client.updateApp`, ...). | -| Only client SDKs (`JavaScript` plus Kotlin, Swift, Dart, Unity, Unreal, React, ...) | Client-side: no `Node.js` tab, even when a server equivalent exists. | -| `JavaScript` only (or with non-SDK tabs such as `JSON`) | Add a `Node.js` tab when the node SDK can do the same thing, unless the heading or prose hints "client-side only". See below. | -| Other server SDK tabs (Python, Ruby, PHP, Go, C#, Java) but no `Node.js` | Add a `Node.js` tab. If the others are comment-only notes ("client-side only operation"), add the same note for the Node SDK. | -| A client group, and the page has its own server-side section for it ("Server-Side Usage", "Server Side") | No `Node.js` tab: the server-side section covers it. | +| Group | Action | +| -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| A `JavaScript` fence with server-only code (secret, `updateAppSettings`, `createToken`, ...) | Relabel it `Node.js` and rewrite it to the node SDK call (`client.updateApp`, ...). Relabel its `JavaScript (stream-chat-js@9)` partner, if any, `Node.js (stream-chat-js@9)`, code unchanged. | +| Only client SDKs (`JavaScript` plus Kotlin, Swift, Dart, Unity, Unreal, React, ...) | Client-side: no `Node.js` tab, even when a server equivalent exists. | +| `JavaScript` only (or with non-SDK tabs such as `JSON`) | Add a `Node.js` tab when the node SDK can do the same thing, unless the heading or prose hints "client-side only". See below. | +| Other server SDK tabs (Python, Ruby, PHP, Go, C#, Java) but no `Node.js` | Add a `Node.js` tab. If the others are comment-only notes ("client-side only operation"), add the same note for the Node SDK. | +| A client group, and the page has its own server-side section for it ("Server-Side Usage", "Server Side") | No `Node.js` tab: the server-side section covers it. | JavaScript-only groups are common: JavaScript is usually the first SDK documented, and the other SDKs follow later. Being alone is no hint that the code is client-side. Client APIs used in passing aren't either: translate them to the server side (`client.user?.language` → `user.language` of a user you have; the message from `client.chat.getMessage`). Skip the group only when: @@ -74,6 +74,7 @@ To check what the node SDK can do, read `src/StreamClient.ts`, `src/StreamChatCl - Mirror the `JavaScript` fence: same comments, structure and placeholder literals (`"user-1"`, `"messaging:general"`). - Use the node SDK's shapes and types: `client.chat.*` / `client.feeds.*`, request objects (`filter_conditions`, `preferences: [...]`), `Date` where the types say `Date` (not `.toISOString()`), and `user_id` where the client code acts as the connected user (server-side `queryChannels` with `hidden` / `muted`, drafts, devices need it). +- Don't write a `Node.js (stream-chat-js@9)` fence for it: list the group in the report so the v9 version can be added by hand. - Put it before the group's ``. A fence that isn't in a `` block: wrap it and the new fence in ``. - From `$DOCS_DIR`, run `npx prettier --write ` and `node scripts/tab-lint.mjs ` (it puts the tabs in the canonical order: client SDKs first, then server SDKs). @@ -90,7 +91,7 @@ It runs without network and reports four kinds of failure. Collect them all, gro | Failure | Meaning | | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `snippets without a test region` | A `Node.js` fence on a tested sidebar page (chat Node, platform) has no region: a new snippet, a new page, or a fence whose key changed (see the next row). | -| mislabelled JS fences | A JS fence is unlabelled or has a label other than `JavaScript`, `React`, `React Native` or `Node.js`. | +| mislabelled JS fences | A JS fence is unlabelled or has a label other than `JavaScript`, `React`, `React Native`, `Node.js` or their stream-chat-js@9 versions. | | `no such fence` | A region's key (`docs`, `heading`, `tab`, `index`) matches no fence: the fence was removed, moved, or its heading was renamed. The failure lists the page's fence keys. | | ` differs from :` | The region's code and the fence's code differ. | @@ -104,7 +105,7 @@ Work one docs page at a time. ### Mislabelled fence -Label it `Node.js` for `@stream-io/node-sdk` (server-side) code, `JavaScript` for client code. Code that works on both sides (e.g. a bare filter object) gets `JavaScript`: an unlabelled `js` fence already renders like `label="JavaScript"` (the JavaScript route's own sample, a titled fallback on the Node route), so the page doesn't change. Whether it also needs a `Node.js` tab is decided by the sweep (step 3). Otherwise, `JavaScript`, `React` and `React Native` fences, and `Node.js` fences inside a `` block (reference implementations without the SDK), are out of scope: never test or change them. +Label it `Node.js` for `@stream-io/node-sdk` (server-side) code, `JavaScript` for client code. Code that works on both sides (e.g. a bare filter object) gets `JavaScript`: an unlabelled `js` fence already renders like `label="JavaScript"` (the JavaScript route's own sample, a titled fallback on the Node route), so the page doesn't change. Whether it also needs a `Node.js` tab is decided by the sweep (step 3). Otherwise, `JavaScript`, `React` and `React Native` fences, the stream-chat-js@9 fences (`JavaScript (stream-chat-js@9)`, `Node.js (stream-chat-js@9)`), and `Node.js` fences inside a `` block (reference implementations without the SDK), are out of scope: never test or change them. ### Region differs from its fence (docs changed) @@ -134,7 +135,7 @@ Write a test for it in the page's test file (create the file if the page is new) - Comment-only fences need no region. - A fence that isn't code (e.g. a bare data shape) is a docs bug: rewrite it as code that runs (e.g. reading and logging the fields), and report it. Never remove a `Node.js` fence just because it is a fragment or can't be tested: wrap it, or put it in `it.skip`. - A snippet the test app can't run goes in `it.skip('BLOCKED: ', ...)` so it is still typechecked; report the exact API error. -- **Client-side code in a `Node.js` fence** (needs a connected user or a WebSocket, or a method the node SDK doesn't have: `connectUser`, `channel.watch()`, `client.on(...)`): never test different code from what the fence shows. If the node SDK can do the same thing, make the smallest docs fix that turns the fence into that call (`channel.watch()` → `channel.getOrCreate()`, `user_id` instead of `connectUser`). If it can't (events, WebSocket, local client state), the fence is mislabelled: label it `JavaScript`. Use `it.skip('BLOCKED: client-side code: ...')` only while that decision is open. Report it either way. To check what a server-side endpoint accepts, read the SDK source (`src/StreamClient.ts`, `src/StreamChatClient.ts`, `src/StreamChannel.ts`, `src/gen/`) or the OpenAPI spec (`chat-serverside-api.json` in https://github.com/GetStream/protocol/tree/main/openapi/v2). +- **Client-side code in a `Node.js` fence** (needs a connected user or a WebSocket, or a method the node SDK doesn't have: `connectUser`, `channel.watch()`, `client.on(...)`): never test different code from what the fence shows. If the node SDK can do the same thing, make the smallest docs fix that turns the fence into that call (`channel.watch()` → `channel.getOrCreate()`, `user_id` instead of `connectUser`). If it can't (events, WebSocket, local client state), the fence is mislabelled: label it `JavaScript`. Its `Node.js (stream-chat-js@9)` partner, if any, becomes `JavaScript (stream-chat-js@9)`, code unchanged. Use `it.skip('BLOCKED: client-side code: ...')` only while that decision is open. Report it either way. To check what a server-side endpoint accepts, read the SDK source (`src/StreamClient.ts`, `src/StreamChatClient.ts`, `src/StreamChannel.ts`, `src/gen/`) or the OpenAPI spec (`chat-serverside-api.json` in https://github.com/GetStream/protocol/tree/main/openapi/v2). - **Push and webhooks**: don't test that notifications or webhook events arrive; assert the response or read the setting back (`getApp()`, `listPushProviders()`, ...). Never touch or use the test app's own push provider (see "Test app" in `AGENTS.md`): only use providers the test creates with `uniqueId` names. Snippets that need real credentials run in `describe.skipIf(!hasFirebaseCredentials)` (`helpers/push.ts`); the README's "Push credentials" section has the details. - **App-level side effects** (app settings, built-in channel types, grants, webhook URLs, push config, ...): read the original value first and restore it with `cleanup.add(...)`, or the file fails with `DRIFT`. diff --git a/__tests__/docs-snippets/README.md b/__tests__/docs-snippets/README.md index 6ce1c11..3d75411 100644 --- a/__tests__/docs-snippets/README.md +++ b/__tests__/docs-snippets/README.md @@ -4,7 +4,8 @@ Typed tests that run the server-side Node.js snippets of the chat docs (the page `getstream.io/content/docs/_sidebars/[chat][node].json`) and of the platform docs (the pages of `getstream.io/content/docs/_sidebars/[platform][default].json`) against a real Stream app. Only fences labelled `Node.js` are in scope (docs fences must always have a label): they are fixed when they are -wrong. `JavaScript`, `React` and `React Native` fences (client-side code) and `Node.js` fences inside a `` block (reference +wrong. `JavaScript`, `React` and `React Native` fences (client-side code), the stream-chat-js@9 fences (`JavaScript (stream-chat-js@9)`, +`Node.js (stream-chat-js@9)`) and `Node.js` fences inside a `` block (reference implementations without the SDK) are out of scope and are neither tested nor changed. ```sh @@ -80,8 +81,8 @@ await channel.getOrCreate({ data: { created_by_id: creatorId } }); - `index` is 1-based among fences with the same heading text and tab (default 1). - **COPY**: `name="literal"` pairs, applied to the region before comparing (identifier `name` becomes the docs literal). Don't use COPY variables as object keys or shorthand properties. - **Comparison**: both sides are formatted with the same prettier options, so quote style and line wrapping don't matter, but any code or comment change does. -- **Coverage** (checked first): every `Node.js` fence (`js`/`javascript`/`ts`/`typescript`) on the pages of the chat Node sidebar and the platform sidebar (`content/docs/_sidebars/[chat][node].json`, `[platform][default].json`), whether or not the page has tests yet, must have a region (inside `it.skip` if it can't run). `JavaScript` / `React` / `React Native` fences and comment-only fences are ignored. -- **Labels**: every JS fence on those pages must be labelled `JavaScript`, `React`, `React Native` or `Node.js`; unlabelled or otherwise labelled JS fences fail. +- **Coverage** (checked first): every `Node.js` fence (`js`/`javascript`/`ts`/`typescript`) on the pages of the chat Node sidebar and the platform sidebar (`content/docs/_sidebars/[chat][node].json`, `[platform][default].json`), whether or not the page has tests yet, must have a region (inside `it.skip` if it can't run). `JavaScript` / `React` / `React Native` / stream-chat-js@9 fences and comment-only fences are ignored. +- **Labels**: every JS fence on those pages must be labelled `JavaScript`, `React`, `React Native`, `Node.js`, `JavaScript (stream-chat-js@9)` or `Node.js (stream-chat-js@9)`; unlabelled or otherwise labelled JS fences fail. - **Excluded pages**: `EXCLUDED_PAGES` in `sync/parse.ts` lists sidebar pages that are deliberately not validated, with a reason. Both checks skip them. - **`DOCS_SYNC_WRITE= yarn test:docs:sync`** writes the regions of that page into the docs fences (docs prettier style). Use it to apply a fix to the docs. `DOCS_SYNC_WRITE=1` writes all pages. - **`DOCS_DIR`** points at another docs checkout (default: `../getstream.io/content/docs` next to this repo). The check is skipped if the directory doesn't exist. diff --git a/__tests__/docs-snippets/sync/docs-sync.test.ts b/__tests__/docs-snippets/sync/docs-sync.test.ts index 865bec8..ef58fd0 100644 --- a/__tests__/docs-snippets/sync/docs-sync.test.ts +++ b/__tests__/docs-snippets/sync/docs-sync.test.ts @@ -21,7 +21,8 @@ import type { DocsFence, TestRegion } from './parse'; // `yarn test:docs:sync`, in this order: // 1. Every `Node.js` fence (except comment-only fences) on the pages of the chat Node // sidebar and the platform sidebar has a test region. `JavaScript`, `React` and -// `React Native` (client-side) fences, and fences inside a +// `React Native` (client-side) fences, the stream-chat-js@9 fences +// (`JavaScript (stream-chat-js@9)`, `Node.js (stream-chat-js@9)`), and fences inside a // `` block, are out of scope. // 2. Every JS fence on those pages is labelled with one of `ALLOWED_JS_LABELS`. // 3. Every marked test region points at an existing fence and matches it (after @@ -97,7 +98,7 @@ describe.skipIf(!hasDocs)(`docs sync (${DOCS_DIR})`, () => { ); expect( mislabelled, - `JS fences need label="${ALLOWED_JS_LABELS.join('" or label="')}" (client-side code or @stream-io/node-sdk code)`, + `JS fences need label="${ALLOWED_JS_LABELS.join('" or label="')}" (client-side code, @stream-io/node-sdk code, or their stream-chat-js@9 versions)`, ).toEqual([]); }); diff --git a/__tests__/docs-snippets/sync/parse.ts b/__tests__/docs-snippets/sync/parse.ts index 834356c..337cc6c 100644 --- a/__tests__/docs-snippets/sync/parse.ts +++ b/__tests__/docs-snippets/sync/parse.ts @@ -55,8 +55,16 @@ const JS_LANGS = new Set(['js', 'javascript', 'ts', 'typescript']); export const JS_TAB = 'JavaScript'; /** The tested tab (`@stream-io/node-sdk` code). */ export const NODE_TAB = 'Node.js'; -/** Out of scope too: client-side React / React Native SDK code. */ -const OUT_OF_SCOPE_TABS = ['React', 'React Native']; +/** + * Out of scope too: client-side React / React Native SDK code, and the stream-chat-js@9 + * versions shown next to `JavaScript` (client-side) and `Node.js` (server-side). + */ +const OUT_OF_SCOPE_TABS = [ + 'React', + 'React Native', + 'JavaScript (stream-chat-js@9)', + 'Node.js (stream-chat-js@9)', +]; /** * Opens a block of reference implementations that don't use the SDK (platform pages). * Its `Node.js` fences are out of scope.