@vercel/board 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{a2-CQ3WcqMv.mjs → a2-Qzj0kCWU.mjs} +6 -6
- package/dist/access.d.mts +1 -2
- package/dist/access.mjs +3 -3
- package/dist/{actors-CDDhhFNY.mjs → actors-BLXVp4oZ.mjs} +2 -2
- package/dist/{auth-BwWH3Twu.mjs → auth-lTkOgvcE.mjs} +1 -1
- package/dist/{backend-DmXjVnil.d.mts → backend-ZKYTe3xa.d.mts} +5 -15
- package/dist/backend-a2/blob-vercel.d.mts +1 -1
- package/dist/backend-a2/contract.d.mts +1 -2
- package/dist/backend-a2/store-memory.d.mts +1 -1
- package/dist/backend-a2/store-postgres.d.mts +1 -1
- package/dist/backend-a2/store-redis-http.d.mts +1 -1
- package/dist/backend-a2/store-redis.d.mts +1 -1
- package/dist/backend-a2/store-sqlite.d.mts +1 -1
- package/dist/backend-a2.d.mts +5 -6
- package/dist/backend-a2.mjs +1 -1
- package/dist/{backend-http-BJ7AdK0c.mjs → backend-http-BB0Gld6Q.mjs} +8 -5
- package/dist/{backend-http-BsP0Xq9e.d.mts → backend-http-E7YU0qhn.d.mts} +3 -4
- package/dist/{backend-http-Cs-UKpYp.mjs → backend-http-F0W6e36G.mjs} +2 -2
- package/dist/backend-http.d.mts +1 -1
- package/dist/backend-http.mjs +1 -1
- package/dist/backend-http.node.d.mts +1 -1
- package/dist/backend-http.node.mjs +1 -1
- package/dist/{backend-vercel-CED673bx.d.mts → backend-vercel-CIRObA0t.d.mts} +3 -4
- package/dist/{backend-vercel-CG2SYa03.mjs → backend-vercel-CtB46vMQ.mjs} +3 -3
- package/dist/{backend-vercel-B0Q0K0O5.mjs → backend-vercel-DUWIcFi9.mjs} +24 -8
- package/dist/backend-vercel.d.mts +1 -1
- package/dist/backend-vercel.mjs +1 -1
- package/dist/backend-vercel.node.d.mts +6 -1
- package/dist/backend-vercel.node.mjs +2 -2
- package/dist/{blob-C0J3wbGv.d.mts → blob-B-9AvYis.d.mts} +2 -1
- package/dist/{chat-provider-6eYkL2ef.d.mts → chat-provider-DsNEBQiA.d.mts} +3 -2
- package/dist/cli-commands.d.mts +1 -1
- package/dist/cli-commands.mjs +1 -1
- package/dist/cli-embedded.d.mts +7 -3
- package/dist/cli-embedded.mjs +8 -4
- package/dist/cli.mjs +4 -4
- package/dist/{client-BY-BCggB.mjs → client-D0Px7KzF.mjs} +16 -4
- package/dist/{provider-C_sj4-GL.d.mts → client-xLxeDz0f.d.mts} +13 -689
- package/dist/{commands-D0wXq6CY.d.mts → commands-D6gvrOh3.d.mts} +4 -4
- package/dist/{commands-BtL4jFq8.mjs → commands-nEG47RM_.mjs} +7 -7
- package/dist/{conformance-BZ53bxrG.mjs → conformance-DlnfuzEB.mjs} +1 -1
- package/dist/conformance.d.mts +1 -1
- package/dist/conformance.mjs +1 -1
- package/dist/{engine-SeaJ_CIY.mjs → engine-ROa7-IQY.mjs} +2 -2
- package/dist/errors-CB4tnZGz.d.mts +16 -0
- package/dist/{errors-Bven0k29.mjs → errors-CusN4x2l.mjs} +14 -6
- package/dist/exports-D22M68rk.d.mts +5 -0
- package/dist/{exports-ByvYtxFT.mjs → exports-NFjBgIT2.mjs} +6 -6
- package/dist/{folds-CRYY14kc.d.mts → folds-jS9wlh9_.d.mts} +49 -2
- package/dist/{index-k2LfZxl-.d.mts → index-C05it0mC.d.mts} +2 -2
- package/dist/index.d.mts +5 -4
- package/dist/{index.default-DmfhBZZi.mjs → index.default-Boe7x-mK.mjs} +1 -1
- package/dist/index.mjs +6 -6
- package/dist/index.node.d.mts +5 -4
- package/dist/index.node.mjs +4 -4
- package/dist/inspect/app.js +108 -108
- package/dist/{main-BNkywL2P.mjs → main-BuahKR16.mjs} +84 -69
- package/dist/{middleware-B0J7QBq7.mjs → middleware-ChKM1zuu.mjs} +1 -1
- package/dist/{node-C51_xzCb.mjs → node-Ybi9E6bO.mjs} +104 -46
- package/dist/provider-Cdg1qadh.d.mts +688 -0
- package/dist/{serve-DYQ64Q5R.mjs → serve-BbHEQk_Y.mjs} +5 -5
- package/dist/{server-BgK1sgj7.mjs → server-Bphio_82.mjs} +4 -4
- package/dist/{serving-rXQcEgTO.mjs → serving-CvOWEym2.mjs} +1 -1
- package/dist/sync-github.d.mts +2 -2
- package/dist/sync-kapso.d.mts +2 -2
- package/dist/sync-linear.d.mts +2 -2
- package/dist/sync-slack.d.mts +3 -3
- package/dist/sync.chat.d.mts +1 -1
- package/dist/sync.d.mts +2 -2
- package/dist/{tokens-U-XRlEfq.mjs → tokens-BuCU-61R.mjs} +2 -2
- package/dist/{types-8yq2VnKI.d.mts → types-aCAf6lGU.d.mts} +1 -1
- package/dist/{watchers-hash-C4CJg7K1.mjs → watchers-hash-BfDPW95j.mjs} +5 -5
- package/docs/01-board/04-messages.md +1 -1
- package/docs/01-board/05-reading.md +2 -2
- package/docs/01-board/06-watchers.md +3 -3
- package/docs/02-sync/01-overview.md +2 -2
- package/docs/03-guides/03-ci.md +2 -2
- package/docs/03-guides/04-triage.md +5 -5
- package/docs/04-reference/01-cli.md +9 -4
- package/docs/04-reference/02-board.md +6 -2
- package/docs/index.md +2 -2
- package/package.json +1 -1
- package/dist/exports-CPrIkpz3.d.mts +0 -4
- package/dist/schemas-CWxs3ECJ.d.mts +0 -50
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as createBoard } from "./exports-
|
|
2
|
-
import { t as http } from "./backend-http-
|
|
1
|
+
import { t as createBoard } from "./exports-NFjBgIT2.mjs";
|
|
2
|
+
import { t as http } from "./backend-http-F0W6e36G.mjs";
|
|
3
3
|
//#region src/server/index.ts
|
|
4
4
|
/**
|
|
5
5
|
* The handle on a board. With a `backend`, the board lives there: `a2()` keeps it in this
|
|
@@ -9,8 +9,8 @@ import { t as http } from "./backend-http-Cs-UKpYp.mjs";
|
|
|
9
9
|
function board(options = {}) {
|
|
10
10
|
return createBoard(options, {
|
|
11
11
|
http: () => http(),
|
|
12
|
-
sync: () => import("./engine-
|
|
13
|
-
serving: () => import("./serving-
|
|
12
|
+
sync: () => import("./engine-ROa7-IQY.mjs"),
|
|
13
|
+
serving: () => import("./serving-CvOWEym2.mjs")
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
16
|
//#endregion
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as ownTeamId, n as discoveryIdentity, r as ownProjectId, t as oidcTokens } from "./tokens-
|
|
1
|
+
import { i as ownTeamId, n as discoveryIdentity, r as ownProjectId, t as oidcTokens } from "./tokens-BuCU-61R.mjs";
|
|
2
2
|
export { discoveryIdentity, oidcTokens, ownProjectId, ownTeamId };
|
package/dist/sync-github.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SyncUnit, _ as withUserTokens, d as ResolvedTarget, f as SyncContext, h as UserTokens, o as ProviderPost, r as ProviderDelivery, y as SyncFn } from "./provider-
|
|
2
|
-
import { n as ChatSyncProvider } from "./chat-provider-
|
|
1
|
+
import { S as SyncUnit, _ as withUserTokens, d as ResolvedTarget, f as SyncContext, h as UserTokens, o as ProviderPost, r as ProviderDelivery, y as SyncFn } from "./provider-Cdg1qadh.mjs";
|
|
2
|
+
import { n as ChatSyncProvider } from "./chat-provider-DsNEBQiA.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { Adapter } from "chat";
|
|
5
5
|
//#region src/sync/github.d.ts
|
package/dist/sync-kapso.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SyncUnit, f as SyncContext, y as SyncFn } from "./provider-
|
|
2
|
-
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-
|
|
1
|
+
import { S as SyncUnit, f as SyncContext, y as SyncFn } from "./provider-Cdg1qadh.mjs";
|
|
2
|
+
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-DsNEBQiA.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { Adapter } from "chat";
|
|
5
5
|
//#region src/sync/kapso.d.ts
|
package/dist/sync-linear.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SyncUnit, c as ReceivedEvent, d as ResolvedTarget, f as SyncContext, o as ProviderPost, r as ProviderDelivery, y as SyncFn } from "./provider-
|
|
2
|
-
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-
|
|
1
|
+
import { S as SyncUnit, c as ReceivedEvent, d as ResolvedTarget, f as SyncContext, o as ProviderPost, r as ProviderDelivery, y as SyncFn } from "./provider-Cdg1qadh.mjs";
|
|
2
|
+
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-DsNEBQiA.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { Adapter } from "chat";
|
|
5
5
|
//#region src/sync/linear.d.ts
|
package/dist/sync-slack.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { f as ExternalLink } from "./folds-
|
|
2
|
-
import { C as channels, _ as withUserTokens, d as ResolvedTarget, f as SyncContext, h as UserTokens, o as ProviderPost, r as ProviderDelivery, y as SyncFn } from "./provider-
|
|
3
|
-
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-
|
|
1
|
+
import { f as ExternalLink } from "./folds-jS9wlh9_.mjs";
|
|
2
|
+
import { C as channels, _ as withUserTokens, d as ResolvedTarget, f as SyncContext, h as UserTokens, o as ProviderPost, r as ProviderDelivery, y as SyncFn } from "./provider-Cdg1qadh.mjs";
|
|
3
|
+
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-DsNEBQiA.mjs";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { Adapter } from "chat";
|
|
6
6
|
//#region src/sync/slack.d.ts
|
package/dist/sync.chat.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as externalAuthor, n as ChatSyncProvider, r as ChatTransport, t as ChatInput } from "./chat-provider-
|
|
1
|
+
import { i as externalAuthor, n as ChatSyncProvider, r as ChatTransport, t as ChatInput } from "./chat-provider-DsNEBQiA.mjs";
|
|
2
2
|
export { ChatInput, ChatSyncProvider, ChatTransport, externalAuthor };
|
package/dist/sync.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { d as ExternalFile, l as ExternalAuthor, u as ExternalEvent } from "./folds-
|
|
2
|
-
import { A as SyncOverrides, C as channels, D as EventBase, E as render, M as SyncRoot, N as envelope, O as ProviderEvent, P as eventSchema, S as SyncUnit, T as mirror, _ as withUserTokens, a as ProviderOptions, b as SyncIn, c as ReceivedEvent, d as ResolvedTarget, f as SyncContext, g as connectUserTokens, h as UserTokens, i as ProviderFile, j as SyncResult, k as RootOverride, l as RenderInput, m as UnreadableError, n as FileDelivery, o as ProviderPost, p as SyncProvider, r as ProviderDelivery, s as Receive, u as Renderer, v as Sync, w as into, x as SyncOut, y as SyncFn } from "./provider-
|
|
1
|
+
import { d as ExternalFile, l as ExternalAuthor, u as ExternalEvent } from "./folds-jS9wlh9_.mjs";
|
|
2
|
+
import { A as SyncOverrides, C as channels, D as EventBase, E as render, M as SyncRoot, N as envelope, O as ProviderEvent, P as eventSchema, S as SyncUnit, T as mirror, _ as withUserTokens, a as ProviderOptions, b as SyncIn, c as ReceivedEvent, d as ResolvedTarget, f as SyncContext, g as connectUserTokens, h as UserTokens, i as ProviderFile, j as SyncResult, k as RootOverride, l as RenderInput, m as UnreadableError, n as FileDelivery, o as ProviderPost, p as SyncProvider, r as ProviderDelivery, s as Receive, u as Renderer, v as Sync, w as into, x as SyncOut, y as SyncFn } from "./provider-Cdg1qadh.mjs";
|
|
3
3
|
export { EventBase, type ExternalAuthor, ExternalEvent, type ExternalFile, type FileDelivery, type ProviderDelivery, type ProviderEvent, type ProviderFile, type ProviderOptions, type ProviderPost, type Receive, ReceivedEvent, type RenderInput, type Renderer, ResolvedTarget, type RootOverride, type Sync, type SyncContext, type SyncFn, type SyncIn, type SyncOut, SyncOverrides, SyncProvider, type SyncResult, type SyncRoot, type SyncUnit, UnreadableError, type UserTokens, channels, connectUserTokens, envelope, eventSchema, into, mirror, render, withUserTokens };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { l as unauthorized } from "./errors-
|
|
2
|
-
import { f as markVerified, m as trustedIssuers, n as TOKENS, r as VERCEL_ISSUER, u as issuerName } from "./auth-
|
|
1
|
+
import { l as unauthorized } from "./errors-CusN4x2l.mjs";
|
|
2
|
+
import { f as markVerified, m as trustedIssuers, n as TOKENS, r as VERCEL_ISSUER, u as issuerName } from "./auth-lTkOgvcE.mjs";
|
|
3
3
|
import { createRemoteJWKSet, decodeJwt, jwtVerify } from "jose";
|
|
4
4
|
//#region src/server/identity.ts
|
|
5
5
|
let fromDisk;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ExternalCopy, c as SyncedThread, g as BoardEvent, o as Message } from "./folds-
|
|
1
|
+
import { a as ExternalCopy, c as SyncedThread, g as BoardEvent, o as Message } from "./folds-jS9wlh9_.mjs";
|
|
2
2
|
import { t as A2Store } from "./store-D0MhBvg6-4Z2L0Kqd.mjs";
|
|
3
3
|
//#region src/store/types.d.ts
|
|
4
4
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as DIRECT_UPLOAD_BYTES_MAX, t as ATTACHMENT_BYTES_MAX } from "./files-SniSmeEr.mjs";
|
|
2
2
|
import { S as storable, a as AttachmentId, c as ChannelPath, d as LabelKey, g as MessageText, l as Emoji, m as MESSAGE_TEXT_MAX, n as ActorId, p as Labels, x as platformAvatar } from "./schemas-Be08nyfW.mjs";
|
|
3
3
|
import { a as Link, i as ExternalTarget, n as ExternalEvent, o as Origin, t as ExternalAuthor } from "./external-BV_cUncs.mjs";
|
|
4
|
-
import { r as badRequest, t as HttpError } from "./errors-
|
|
5
|
-
import { o as options } from "./commands-
|
|
4
|
+
import { r as badRequest, t as HttpError } from "./errors-CusN4x2l.mjs";
|
|
5
|
+
import { o as options } from "./commands-nEG47RM_.mjs";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
//#region src/api/routes.ts
|
|
8
8
|
/**
|
|
@@ -662,7 +662,7 @@ const routes = {
|
|
|
662
662
|
const SYNC = "@sync";
|
|
663
663
|
//#endregion
|
|
664
664
|
//#region src/version.ts
|
|
665
|
-
const VERSION = "0.
|
|
665
|
+
const VERSION = "0.26.0";
|
|
666
666
|
//#endregion
|
|
667
667
|
//#region src/server/routing.ts
|
|
668
668
|
/** board()'s own routes: the files it serves, and sync's, which run where board() does. */
|
|
@@ -865,7 +865,7 @@ const FILTER_FLAGS = {
|
|
|
865
865
|
by: options.by,
|
|
866
866
|
mentions: options.mentions,
|
|
867
867
|
label: options.label,
|
|
868
|
-
|
|
868
|
+
source: options.source,
|
|
869
869
|
text: options.text
|
|
870
870
|
};
|
|
871
871
|
/** `--mentions` alone means mentions of me; `--mentions @ada`, mentions of ada. */
|
|
@@ -961,7 +961,7 @@ function parseWatchTail(expression) {
|
|
|
961
961
|
...values.by ? { by: values.by.replace(/^@/, "") } : {},
|
|
962
962
|
...values.mentions ? { mentions: values.mentions.replace(/^@/, "") } : {},
|
|
963
963
|
...values.label?.length ? { label: values.label } : {},
|
|
964
|
-
...values.
|
|
964
|
+
...values.source ? { from: values.source } : {},
|
|
965
965
|
...values.text ? { text: values.text } : {}
|
|
966
966
|
});
|
|
967
967
|
if (!parsed.success) {
|
|
@@ -164,7 +164,7 @@ await team.reply('812', { text: 'fixed, see after', attachments: [shot] })
|
|
|
164
164
|
A retry shouldn't post twice. Give a post or reply an ID of your own:
|
|
165
165
|
|
|
166
166
|
```bash
|
|
167
|
-
vb post deploys "a1b2c3 is live" --
|
|
167
|
+
vb post deploys "a1b2c3 is live" --idempotency-key deploy-a1b2c3
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
The same ID with the same write returns the message it already posted. The same
|
|
@@ -75,14 +75,14 @@ read includes it.
|
|
|
75
75
|
| `--re <id>` | the thread rooted at `<id>`: the root and its replies |
|
|
76
76
|
| `--by <handle>` | messages by that actor: a handle without the `@`, or an exact actor ID |
|
|
77
77
|
| `--mentions` | messages that mention you; `--mentions @ada` for someone else |
|
|
78
|
-
| `--
|
|
78
|
+
| `--source <source>` | where it was written: a sync key (`slack`, `github`), or `board` |
|
|
79
79
|
| `--label <key>` | messages with that label; `key=value`, or `key=a\|b` for either |
|
|
80
80
|
| `--text <words>` | text containing the words, case-insensitive (a substring, not search) |
|
|
81
81
|
| `--after <id>` | messages after that message ID or cursor; for `read`, threads with activity after it |
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
vb read prs --label state=open # what's pending
|
|
85
|
-
vb read issues --label tag.bug --
|
|
85
|
+
vb read issues --label tag.bug --source github
|
|
86
86
|
vb read --mentions # everywhere I'm mentioned
|
|
87
87
|
vb read errors-www --by ada --text ENOTFOUND
|
|
88
88
|
```
|
|
@@ -21,7 +21,7 @@ const team = board({
|
|
|
21
21
|
// sync as in Sync
|
|
22
22
|
watch: {
|
|
23
23
|
triage: {
|
|
24
|
-
tail: 'firehose --
|
|
24
|
+
tail: 'firehose --source slack',
|
|
25
25
|
run: async ({ event, board }) => {
|
|
26
26
|
if (event.type === 'message.posted' && event.message?.re === null)
|
|
27
27
|
await board.reply(event.message.id, 'Thanks! Tracking it.') // synced to the Slack thread
|
|
@@ -37,13 +37,13 @@ export const { scheduler } = backend
|
|
|
37
37
|
would print, exactly as `vb tail --json` prints it. Try it in a terminal first:
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
vb tail firehose --
|
|
40
|
+
vb tail firehose --source slack --json
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
## The expression
|
|
44
44
|
|
|
45
45
|
A channel (or `prefix/` for a subtree) and the shared
|
|
46
|
-
[filters](./05-reading.md#filters): `--re`, `--by`, `--mentions`, `--
|
|
46
|
+
[filters](./05-reading.md#filters): `--re`, `--by`, `--mentions`, `--source`,
|
|
47
47
|
`--label`, `--text`, and `--all`.
|
|
48
48
|
|
|
49
49
|
- **Positions aren't filters.** A watcher starts at the head when it's deployed
|
|
@@ -95,7 +95,7 @@ see [Sync functions](./02-functions.md).
|
|
|
95
95
|
|
|
96
96
|
**Entry keys** (`slack`, `github`, or `acme` for a second Slack workspace) are
|
|
97
97
|
names you choose; the adapter decides the platform. The key appears in external
|
|
98
|
-
IDs (`acme:C0999XYZ:1727.9`), in sync targets, in `--
|
|
98
|
+
IDs (`acme:C0999XYZ:1727.9`), in sync targets, in `--source` filters, and in the
|
|
99
99
|
webhook path (`/webhooks/acme`).
|
|
100
100
|
|
|
101
101
|
**Map keys** are the platform's names or IDs: `'#prs'` or `'C0123ABC'` for
|
|
@@ -303,7 +303,7 @@ written to the log. It needs `post` and `read` in the thread's channel.
|
|
|
303
303
|
vb sources # the board's sync entries and their platforms
|
|
304
304
|
vb inbox slack # raw platform events, newest first: did Slack send it?
|
|
305
305
|
vb inbox slack '#errors-www' --limit 5
|
|
306
|
-
vb tail --
|
|
306
|
+
vb tail --source slack --all # board events from Slack, delivery receipts included
|
|
307
307
|
```
|
|
308
308
|
|
|
309
309
|
`vb inbox` needs `sync` in every channel for the board's own inbox, and every
|
package/docs/03-guides/03-ci.md
CHANGED
|
@@ -24,7 +24,7 @@ jobs:
|
|
|
24
24
|
- uses: actions/checkout@v4
|
|
25
25
|
# your deploy steps…
|
|
26
26
|
- if: failure()
|
|
27
|
-
run: npx -y @vercel/board post errors-www "deploy failed on $SHA" --label source=ci --
|
|
27
|
+
run: npx -y @vercel/board post errors-www "deploy failed on $SHA" --label source=ci --idempotency-key "deploy-$SHA"
|
|
28
28
|
env:
|
|
29
29
|
BOARD_URL: https://team.example/api/board
|
|
30
30
|
SHA: ${{ github.sha }}
|
|
@@ -34,7 +34,7 @@ jobs:
|
|
|
34
34
|
whose audience is the board's URL, so it's good for that board and nothing
|
|
35
35
|
else. Without `id-token: write`, GitHub gives the job no token, so the CLI
|
|
36
36
|
falls through to a `vercel login` the runner doesn't have, and fails.
|
|
37
|
-
- **`--
|
|
37
|
+
- **`--idempotency-key` makes a retried step post once.** The same ID with the same write
|
|
38
38
|
returns the message already posted.
|
|
39
39
|
- **The post is an ordinary thread.** If `errors-www` mirrors a Slack channel,
|
|
40
40
|
it lands there, and a reply in Slack reaches the board.
|
|
@@ -18,10 +18,10 @@ messages.
|
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
# in a terminal:
|
|
21
|
-
vb tail firehose --
|
|
21
|
+
vb tail firehose --source slack --json
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
`tail` prints one line of JSON per event, live, until Ctrl-C. `--
|
|
24
|
+
`tail` prints one line of JSON per event, live, until Ctrl-C. `--source slack`
|
|
25
25
|
keeps messages that came from Slack. Each line carries the event and the
|
|
26
26
|
message it concerns, as it is after the event:
|
|
27
27
|
|
|
@@ -38,7 +38,7 @@ report is a `message.posted` whose message has `re: null`: a thread root.
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
# triage.sh: runs until you stop it
|
|
41
|
-
vb tail firehose --
|
|
41
|
+
vb tail firehose --source slack --json | while read -r event; do
|
|
42
42
|
[ "$(jq -r '.type' <<<"$event")" = "message.posted" ] || continue
|
|
43
43
|
[ "$(jq -r '.message.re' <<<"$event")" = "null" ] || continue
|
|
44
44
|
id=$(jq -r '.message.id' <<<"$event")
|
|
@@ -63,7 +63,7 @@ prints it, and exits, so each turn handles one event. Every event carries a
|
|
|
63
63
|
```bash
|
|
64
64
|
# triage-turn.sh: one event per run
|
|
65
65
|
last=$(cat .triage-cursor 2>/dev/null)
|
|
66
|
-
next=$(vb wait firehose --
|
|
66
|
+
next=$(vb wait firehose --source slack ${last:+--after "$last"} --json --timeout 1h) || exit 0
|
|
67
67
|
jq -r '.cursor' <<<"$next" > .triage-cursor
|
|
68
68
|
|
|
69
69
|
[ "$(jq -r '.type' <<<"$next")" = "message.posted" ] || exit 0
|
|
@@ -117,7 +117,7 @@ const team = board({
|
|
|
117
117
|
// sync: { slack: slack('slack/acme', channels({ '#firehose': 'firehose' })) },
|
|
118
118
|
watch: {
|
|
119
119
|
triage: {
|
|
120
|
-
tail: 'firehose --
|
|
120
|
+
tail: 'firehose --source slack',
|
|
121
121
|
run: async ({ event, board }) => {
|
|
122
122
|
const message = event.message
|
|
123
123
|
if (event.type !== 'message.posted' || !message || message.re !== null) return
|
|
@@ -47,6 +47,11 @@ const code = await createApp({
|
|
|
47
47
|
onError: (failure, { json }) => console.error(json ? JSON.stringify(failure) : failureLines(failure).join('\n')),
|
|
48
48
|
// { reason, message }: a write that went through, with something to say. With --json, it's in the result.
|
|
49
49
|
onWarning: (warning) => console.error(warning.message),
|
|
50
|
+
// Your Vercel login, and the team whose board to use when --scope names none, as this CLI
|
|
51
|
+
// resolves its own: asked for only when a request needs them. Help, a typo, or misuse never asks.
|
|
52
|
+
// A login that throws fails the request: board never falls back to `vercel login`'s.
|
|
53
|
+
login: async () => process.env.VERCEL_AUTH_TOKEN!,
|
|
54
|
+
team: async () => process.env.VERCEL_ORG_ID ?? null,
|
|
50
55
|
}).run(process.argv.slice(3))
|
|
51
56
|
```
|
|
52
57
|
|
|
@@ -485,7 +490,7 @@ schedules that reply in that thread. `--all` adds done and canceled ones.
|
|
|
485
490
|
### post
|
|
486
491
|
|
|
487
492
|
```text
|
|
488
|
-
vb post <channel|id> ["<text>"] [--label k=v]... [--attach <file>]... [--sync <target>]... [--no-sync] [--
|
|
493
|
+
vb post <channel|id> ["<text>"] [--label k=v]... [--attach <file>]... [--sync <target>]... [--no-sync] [--idempotency-key <key>]
|
|
489
494
|
```
|
|
490
495
|
|
|
491
496
|
Starts a thread. The channel is created by its first post. Given a message ID
|
|
@@ -499,7 +504,7 @@ for new threads only.
|
|
|
499
504
|
| `--attach <file>` | uploads a file (at most 4 MB, or 100 MB on a board whose blob store takes direct uploads; 10 per message) and attaches it. Every file is checked before any uploads. A board that keeps no files refuses: ``error: this board keeps no files: pass `blob` to `a2()` `` |
|
|
500
505
|
| `--sync <target>` | also starts or joins a thread there: `slack:#incidents`, `github:owner/repo:12`; new threads only |
|
|
501
506
|
| `--no-sync` | keeps the message on the board: it reaches none of the channel's mirrored channels |
|
|
502
|
-
| `--
|
|
507
|
+
| `--idempotency-key <key>` | the same key never posts twice, so a retried step posts once |
|
|
503
508
|
|
|
504
509
|
`--sync` and `--no-sync` together are a usage error. See
|
|
505
510
|
[Messages](../01-board/04-messages.md) and
|
|
@@ -508,7 +513,7 @@ for new threads only.
|
|
|
508
513
|
### reply
|
|
509
514
|
|
|
510
515
|
```text
|
|
511
|
-
vb reply <id> ["<text>"] [--attach <file>]... [--no-sync] [--
|
|
516
|
+
vb reply <id> ["<text>"] [--attach <file>]... [--no-sync] [--idempotency-key <key>]
|
|
512
517
|
```
|
|
513
518
|
|
|
514
519
|
Replies in a thread. `<id>` may be any message in it: the board stores the
|
|
@@ -739,7 +744,7 @@ of them must match.
|
|
|
739
744
|
| `--by <handle>` | messages by an actor, by handle or exact actor ID. A person's handle covers their agents (`julian/claude`) and linked accounts |
|
|
740
745
|
| `--mentions` | messages that mention you |
|
|
741
746
|
| `--mentions @handle` | messages that mention that actor |
|
|
742
|
-
| `--
|
|
747
|
+
| `--source <source>` | where a message came from: a sync key (`slack`, `github`), or `board` for messages written on the board |
|
|
743
748
|
| `--label <key>` | messages with the label, any value |
|
|
744
749
|
| `--label <key>=<value>` | that value; `state=open\|draft` means either |
|
|
745
750
|
| `--text <words>` | a case-insensitive substring of the text (1 to 200 characters), not search |
|
|
@@ -516,8 +516,11 @@ which only the handle reaches. A handle on `http()` finds the board it uses in
|
|
|
516
516
|
## Errors
|
|
517
517
|
|
|
518
518
|
A failed request throws a `BoardError` with the board's `code`, its
|
|
519
|
-
`message`, the HTTP `status`, and, when
|
|
520
|
-
|
|
519
|
+
`message`, the HTTP `status`, and, when there's one, a `hint` for what fixes
|
|
520
|
+
it (`Run vercel login.`). `origin` says who said so: `handle` for what the
|
|
521
|
+
handle raised itself, such as no Vercel login, and `board` for a board's
|
|
522
|
+
answer, whose message and hint are its own words whatever code it names, so
|
|
523
|
+
trust them as you'd trust that board.
|
|
521
524
|
|
|
522
525
|
```ts
|
|
523
526
|
// anywhere in Node:
|
|
@@ -552,6 +555,7 @@ fails with the status its URL answered, or 502.
|
|
|
552
555
|
| `ambiguous_agent` | the environment shows several coding agents at once: `as(null)` acts as yourself |
|
|
553
556
|
| `invalid_duration` | a `timeout` the handle can't read |
|
|
554
557
|
| `too_many_redirects` | the board's URL redirects more than 20 times |
|
|
558
|
+
| `redirected` | the board's URL redirects to another origin, where none of its credentials follow, and Deployment Protection there turns it away: use the URL it redirects to |
|
|
555
559
|
|
|
556
560
|
An answer that isn't the board's JSON error becomes `remote_error`, with
|
|
557
561
|
status 502. The board's own codes are in the [HTTP API](./03-http.md#errors).
|
package/docs/index.md
CHANGED
|
@@ -110,7 +110,7 @@ const team = board({
|
|
|
110
110
|
// sync as above
|
|
111
111
|
watch: {
|
|
112
112
|
triage: {
|
|
113
|
-
tail: 'errors-www --
|
|
113
|
+
tail: 'errors-www --source slack',
|
|
114
114
|
run: async ({ event, board }) => {
|
|
115
115
|
if (event.type !== 'message.posted' || event.message?.re !== null) return
|
|
116
116
|
// the reply reaches the Slack thread too:
|
|
@@ -124,7 +124,7 @@ export const { scheduler } = backend
|
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
A watcher is a `vb tail` the board runs for you. Try the expression in a
|
|
127
|
-
terminal first (`vb tail errors-www --
|
|
127
|
+
terminal first (`vb tail errors-www --source slack --json`); `run` gets exactly
|
|
128
128
|
those events, durably, with retries and nothing kept open. See
|
|
129
129
|
[Watchers](./01-board/06-watchers.md).
|
|
130
130
|
|
package/package.json
CHANGED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
//#region src/contract/schemas.d.ts
|
|
3
|
-
declare const CHANNEL_PATH_MAX = 80;
|
|
4
|
-
declare const MESSAGE_TEXT_MAX = 10000;
|
|
5
|
-
declare const ATTACHMENTS_PER_MESSAGE_MAX = 10;
|
|
6
|
-
/** `errors-www`, `www/production`: lowercase segments joined by `/`. */
|
|
7
|
-
declare const ChannelPath: z.ZodString;
|
|
8
|
-
declare const MessageText: z.ZodString;
|
|
9
|
-
/** A message is named by the log index of its `message.posted` event. */
|
|
10
|
-
declare const MessageId: z.ZodNumber;
|
|
11
|
-
declare const LabelKey: z.ZodString;
|
|
12
|
-
declare const LabelValue: z.ZodString;
|
|
13
|
-
declare const Labels: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
14
|
-
/** Normalized short names, as Chat SDK names them: `eyes`, `check`, `thumbs_up`. */
|
|
15
|
-
declare const Emoji: z.ZodString;
|
|
16
|
-
/** `vercel:user:u_abc123`, or `vercel:user:u_abc123+claude` for a profile. */
|
|
17
|
-
declare const ActorId: z.ZodString;
|
|
18
|
-
/** What an actor is: a `person`, an `agent` acting for a principal (`--as claude`), a deployment, a workflow, or a platform user (`external`). */
|
|
19
|
-
declare const ActorKind: z.ZodEnum<{
|
|
20
|
-
agent: "agent";
|
|
21
|
-
deployment: "deployment";
|
|
22
|
-
external: "external";
|
|
23
|
-
person: "person";
|
|
24
|
-
workflow: "workflow";
|
|
25
|
-
}>;
|
|
26
|
-
declare const Handle: z.ZodString;
|
|
27
|
-
declare const Author: z.ZodObject<{
|
|
28
|
-
actor: z.ZodString;
|
|
29
|
-
principal: z.ZodString;
|
|
30
|
-
profile: z.ZodNullable<z.ZodString>;
|
|
31
|
-
session: z.ZodNullable<z.ZodString>;
|
|
32
|
-
}, z.core.$strip>;
|
|
33
|
-
/** 128 random bits, base64url: an attachment is named by an ID nobody can guess. */
|
|
34
|
-
declare const AttachmentId: z.ZodString;
|
|
35
|
-
/** A file on a message. The board records `type` and `size` from what it stored, never from the request. */
|
|
36
|
-
declare const Attachment: z.ZodObject<{
|
|
37
|
-
id: z.ZodString;
|
|
38
|
-
name: z.ZodString;
|
|
39
|
-
type: z.ZodString;
|
|
40
|
-
size: z.ZodNumber;
|
|
41
|
-
}, z.core.$strip>;
|
|
42
|
-
type ChannelPath = z.infer<typeof ChannelPath>;
|
|
43
|
-
type MessageId = z.infer<typeof MessageId>;
|
|
44
|
-
type Labels = z.infer<typeof Labels>;
|
|
45
|
-
type ActorId = z.infer<typeof ActorId>;
|
|
46
|
-
type ActorKind = z.infer<typeof ActorKind>;
|
|
47
|
-
type Author = z.infer<typeof Author>;
|
|
48
|
-
type Attachment = z.infer<typeof Attachment>;
|
|
49
|
-
//#endregion
|
|
50
|
-
export { AttachmentId as a, ChannelPath as c, LabelKey as d, LabelValue as f, MessageText as g, MessageId as h, Attachment as i, Emoji as l, MESSAGE_TEXT_MAX as m, ActorId as n, Author as o, Labels as p, ActorKind as r, CHANNEL_PATH_MAX as s, ATTACHMENTS_PER_MESSAGE_MAX as t, Handle as u };
|