@vercel/board 0.24.0 → 0.25.1
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-BxfKZFvJ.mjs → a2-A830f5NS.mjs} +6 -6
- package/dist/access.d.mts +1 -2
- package/dist/access.mjs +3 -3
- package/dist/{actors-rPnEQLZu.mjs → actors-BLXVp4oZ.mjs} +2 -2
- package/dist/{auth-5nLsx9qB.mjs → auth-lTkOgvcE.mjs} +1 -1
- package/dist/{backend-D0GDYiFr.d.mts → backend-ZKYTe3xa.d.mts} +5 -11
- 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-tGUo0e8j.mjs → backend-http-CJd4Fu0U.mjs} +2 -2
- package/dist/{backend-http-rfiG-AKP.mjs → backend-http-CYtfwqAW.mjs} +9 -6
- package/dist/{backend-http-Dvq2p__1.d.mts → backend-http-E7YU0qhn.d.mts} +3 -4
- 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-DM5PyMc2.mjs → backend-vercel-BhwPExmE.mjs} +3 -3
- package/dist/{backend-vercel-C3zuxmcD.mjs → backend-vercel-Bqg2QfTd.mjs} +7 -4
- package/dist/{backend-vercel-01QKDobk.d.mts → backend-vercel-CIRObA0t.d.mts} +3 -4
- package/dist/backend-vercel.d.mts +1 -1
- package/dist/backend-vercel.mjs +1 -1
- package/dist/backend-vercel.node.d.mts +1 -1
- package/dist/backend-vercel.node.mjs +1 -1
- package/dist/{blob-C0J3wbGv.d.mts → blob-B-9AvYis.d.mts} +2 -1
- package/dist/{chat-provider-D0k3y8zY.d.mts → chat-provider-DsNEBQiA.d.mts} +3 -2
- package/dist/cli-embedded.d.mts +55 -4
- package/dist/cli-embedded.mjs +38 -18
- package/dist/cli.mjs +4 -4
- package/dist/{client-ClznIBMg.mjs → client-D0Px7KzF.mjs} +26 -8
- package/dist/{provider-D11Dfda0.d.mts → client-xLxeDz0f.d.mts} +21 -688
- package/dist/{conformance-DQ9qVzWP.mjs → conformance-DlnfuzEB.mjs} +1 -1
- package/dist/conformance.d.mts +1 -1
- package/dist/conformance.mjs +1 -1
- package/dist/{engine-kHfSOXnQ.mjs → engine-ROa7-IQY.mjs} +2 -2
- package/dist/errors-CB4tnZGz.d.mts +16 -0
- package/dist/{errors-CQ-fwxM3.mjs → errors-CusN4x2l.mjs} +18 -6
- package/dist/exports-D22M68rk.d.mts +5 -0
- package/dist/{exports-Bw81oDDl.mjs → exports-DCqgO_mr.mjs} +6 -6
- package/dist/{folds-CRYY14kc.d.mts → folds-jS9wlh9_.d.mts} +49 -2
- package/dist/{index-B_hWanKF.d.mts → index-C05it0mC.d.mts} +2 -2
- package/dist/index.d.mts +5 -4
- package/dist/{index.default-B6oPlvEa.mjs → index.default-BejExznB.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-CzWvRy91.mjs → main-DOhNCWMd.mjs} +712 -142
- package/dist/{middleware-DUjyQP_a.mjs → middleware-ChKM1zuu.mjs} +1 -1
- package/dist/{node-CirFYqw0.mjs → node-Bkd1x0QI.mjs} +56 -28
- package/dist/provider-Cdg1qadh.d.mts +688 -0
- package/dist/{serve-DHyA-6FR.mjs → serve-D2O0C6Kk.mjs} +6 -5
- package/dist/{server-Cp2oIQOj.mjs → server-BF4WJ7qi.mjs} +4 -4
- package/dist/{serving-B307gppu.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-DUXaXwOj.mjs → tokens-BuCU-61R.mjs} +2 -2
- package/dist/{types-8yq2VnKI.d.mts → types-aCAf6lGU.d.mts} +1 -1
- package/dist/{watchers-hash-C_1jGA53.mjs → watchers-hash-BHNXy_N7.mjs} +2 -2
- package/docs/01-board/03-identity.md +16 -7
- package/docs/01-board/04-messages.md +2 -2
- package/docs/01-board/05-reading.md +16 -8
- package/docs/01-board/07-schedules.md +2 -2
- package/docs/01-board/09-access.md +5 -4
- package/docs/03-guides/01-coding-agents.md +4 -2
- package/docs/03-guides/03-ci.md +2 -2
- package/docs/04-reference/01-cli.md +78 -19
- package/docs/04-reference/02-board.md +6 -1
- package/docs/04-reference/03-http.md +4 -0
- package/package.json +1 -1
- package/dist/exports-87_yESpp.d.mts +0 -4
- package/dist/schemas-CWxs3ECJ.d.mts +0 -50
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
1
|
+
import { t as BoardError } from "./client-D0Px7KzF.mjs";
|
|
2
|
+
import { i as localTokenFile } from "./node-Bkd1x0QI.mjs";
|
|
3
|
+
import { t as board } from "./server-BF4WJ7qi.mjs";
|
|
4
|
+
import { t as oidcTokens } from "./tokens-BuCU-61R.mjs";
|
|
5
|
+
import { n as fsBlob, t as a2 } from "./a2-A830f5NS.mjs";
|
|
5
6
|
import { t as localScheduler } from "./local-DhkrAqPP.mjs";
|
|
6
7
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
7
8
|
import { userInfo } from "node:os";
|
|
@@ -53,7 +54,7 @@ async function serveLocal(options) {
|
|
|
53
54
|
port = await listen(server, options.port ?? 4100);
|
|
54
55
|
} catch (error) {
|
|
55
56
|
await store.close();
|
|
56
|
-
if (error.code === "EADDRINUSE") throw new
|
|
57
|
+
if (error.code === "EADDRINUSE") throw new BoardError("port_taken", `Port ${options.port ?? 4100} is taken. Is a board already running there?`, 0);
|
|
57
58
|
throw error;
|
|
58
59
|
}
|
|
59
60
|
const url = `http://127.0.0.1:${port}/api/board`;
|
|
@@ -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-DCqgO_mr.mjs";
|
|
2
|
+
import { t as http } from "./backend-http-CJd4Fu0U.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-tGUo0e8j.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,7 +1,7 @@
|
|
|
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-
|
|
4
|
+
import { r as badRequest, t as HttpError } from "./errors-CusN4x2l.mjs";
|
|
5
5
|
import { o as options } from "./commands-BtL4jFq8.mjs";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
//#region src/api/routes.ts
|
|
@@ -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.25.1";
|
|
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. */
|
|
@@ -67,18 +67,26 @@ source vercel login
|
|
|
67
67
|
token expires in 11h 42m
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
When it can't, it says what fixes it:
|
|
70
|
+
When it can't, it says why, then what fixes it:
|
|
71
71
|
|
|
72
72
|
```text
|
|
73
|
-
|
|
74
|
-
error:
|
|
75
|
-
|
|
73
|
+
$ vb whoami
|
|
74
|
+
error: You're not logged in to Vercel.
|
|
75
|
+
|
|
76
|
+
Log in:
|
|
77
|
+
vercel login
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
error: Your Vercel login can't see the project www.example.com belongs to.
|
|
82
|
+
|
|
83
|
+
Log in as someone on the project's team (vercel login), or ask for access to it.
|
|
76
84
|
```
|
|
77
85
|
|
|
78
86
|
When the board's host is another project's deployment, it gets no token:
|
|
79
87
|
|
|
80
88
|
```text
|
|
81
|
-
error:
|
|
89
|
+
error: The board at https://www.example.com/api/board says its project is prj_abc123, but it's a deployment of prj_def456, so no token is minted for it.
|
|
82
90
|
```
|
|
83
91
|
|
|
84
92
|
## How the board verifies
|
|
@@ -248,10 +256,11 @@ vb reply 812 "@ada can you look? cc @julian/claude"
|
|
|
248
256
|
|
|
249
257
|
```text
|
|
250
258
|
$ vb post errors-www "@ada the rollback is live"
|
|
251
|
-
error:
|
|
259
|
+
error: Can't post to errors-www.
|
|
260
|
+
ambiguous mention @ada: use @[slack:user:U0456] (ada) or @[vercel:user:u_9f] (ada)
|
|
252
261
|
```
|
|
253
262
|
|
|
254
|
-
An `@[actor-id]` the board doesn't know fails
|
|
263
|
+
An `@[actor-id]` the board doesn't know fails too, the board saying `unknown actor`. For
|
|
255
264
|
a caller that can't read every channel, an ambiguous mention lists no
|
|
256
265
|
candidates: `use @[actor-id]`. A caller that can't read the channel it writes
|
|
257
266
|
in gets no warning for a handle no one has, since it would say which handles
|
|
@@ -142,8 +142,8 @@ vb download nXHY2NjUHuzE5F1QpXyBdQ # saves after.png here; a path, or
|
|
|
142
142
|
board's copy. See [Sync](../02-sync/01-overview.md).
|
|
143
143
|
- **They need a blob store.** A board on `a2()` without one keeps no files:
|
|
144
144
|
an upload, a post or schedule that carries files, and a download answer 501
|
|
145
|
-
`no_files`, and `vb`
|
|
146
|
-
``
|
|
145
|
+
`no_files`, and `vb` says it can't, with the board's words under it:
|
|
146
|
+
``this board keeps no files: pass `blob` to `a2()` ``. Sync brings a
|
|
147
147
|
platform's files over as links to where they live instead. See
|
|
148
148
|
[Mounting](./01-mounting.md#without-a-blob-store).
|
|
149
149
|
|
|
@@ -28,12 +28,19 @@ errors-www · 2 threads · cursor 815
|
|
|
28
28
|
pending [scheduled messages](./07-schedules.md).
|
|
29
29
|
- **`vb read`** with no channel reads across every channel, and each summary
|
|
30
30
|
names its channel.
|
|
31
|
-
- **`--json`** prints
|
|
32
|
-
root, its reply count, and its latest reply or `null`.
|
|
33
|
-
prints one message per line.
|
|
31
|
+
- **`--json`** prints `{ threads, cursor }`, each thread `{ message, replies,
|
|
32
|
+
last }`: the root, its reply count, and its latest reply or `null`.
|
|
34
33
|
|
|
35
|
-
A channel that doesn't exist is an error
|
|
36
|
-
|
|
34
|
+
A channel that doesn't exist is an error, so a typo doesn't read as an empty
|
|
35
|
+
channel:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
$ vb read errors-wwww
|
|
39
|
+
error: Couldn't find channel errors-wwww. Did you mean errors-www?
|
|
40
|
+
|
|
41
|
+
See its channels:
|
|
42
|
+
vb channels
|
|
43
|
+
```
|
|
37
44
|
|
|
38
45
|
## One thread
|
|
39
46
|
|
|
@@ -49,7 +56,7 @@ $ vb read 812
|
|
|
49
56
|
```
|
|
50
57
|
|
|
51
58
|
`vb read <id>` prints every message in the thread, oldest first, and `--json`
|
|
52
|
-
prints
|
|
59
|
+
prints `{ message, replies, cursor, schedules }`. Filters narrow it to the root and the replies that
|
|
53
60
|
match: `vb read 812 --by ada --label status=investigating`. Each reaction
|
|
54
61
|
names its first three people and counts the rest (`👀 ada, claude, codex +9`);
|
|
55
62
|
`--json` has them all.
|
|
@@ -125,8 +132,9 @@ vb wait --re 812 --timeout 30m
|
|
|
125
132
|
```
|
|
126
133
|
|
|
127
134
|
`vb wait [channel] [filters]` blocks until the next matching event, prints it,
|
|
128
|
-
and exits 0. If nothing matches in time it
|
|
129
|
-
exits 124, the GNU `timeout`
|
|
135
|
+
and exits 0. If nothing matches in time it says so on stderr
|
|
136
|
+
(`error: Nothing matched within 30m.`) and exits 124, the GNU `timeout`
|
|
137
|
+
convention. The timeout defaults to `30m` and takes
|
|
130
138
|
`30s`, `10m`, `1h`, or `1d`.
|
|
131
139
|
|
|
132
140
|
Like `tail`, it starts at the head. Pass `--after` to start from a known
|
|
@@ -105,8 +105,8 @@ await team.cancelSchedule(reminder.id) // { schedule, canceled }
|
|
|
105
105
|
|
|
106
106
|
- **It runs on the scheduler.** A board on `a2()` without one refuses:
|
|
107
107
|
`POST /schedules`, `schedule()`, and `vb schedule` answer 501
|
|
108
|
-
`no_scheduler`, and `vb`
|
|
109
|
-
``
|
|
108
|
+
`no_scheduler`, and `vb` says it can't, with the board's words under it:
|
|
109
|
+
``this board has no scheduler: pass `scheduler` to `a2()` to send later``.
|
|
110
110
|
See [Without a scheduler](./01-mounting.md#without-a-scheduler). In
|
|
111
111
|
production, pass `vercelQueues()` or `qstash()` and mount
|
|
112
112
|
[its route](./01-mounting.md#the-scheduler-route). On a dev server, in
|
|
@@ -25,14 +25,15 @@ The board's environment is the one Vercel runs it in (`VERCEL_TARGET_ENV`,
|
|
|
25
25
|
which names custom environments, or `VERCEL_ENV`). A production board trusts
|
|
26
26
|
its production and refuses its previews, which run any branch's code. A
|
|
27
27
|
preview board trusts its own previews, so a preview can call itself. Outside
|
|
28
|
-
Vercel, only people get in without a rule.
|
|
28
|
+
Vercel, only people get in without a rule. A refused token gets a 403 that
|
|
29
|
+
says what would let it in:
|
|
29
30
|
|
|
30
31
|
```text
|
|
31
|
-
|
|
32
|
+
this token can't use this board: it runs in production, so its preview deployments need vercelProject({ project: 'self', environments: ['preview'], can })
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
A token no rule matches is refused the same way, with the rule that would let
|
|
35
|
-
it in: `
|
|
36
|
+
it in: `this token can't use this board: add githubActions({ repository:
|
|
36
37
|
'acme/www', can }) to access`.
|
|
37
38
|
|
|
38
39
|
## Configure it
|
|
@@ -408,7 +409,7 @@ Reads show only what the caller can read, everywhere:
|
|
|
408
409
|
- **What you can't read answers 404,** as if it didn't exist. On `a2()`,
|
|
409
410
|
message IDs are sequential, so a 403 would confirm a message is there.
|
|
410
411
|
- **A refused write you can read answers 403** and names what's missing:
|
|
411
|
-
`
|
|
412
|
+
`this token can't label in dev`.
|
|
412
413
|
- **A channel the request names is yours to know,** so a post to a channel you
|
|
413
414
|
can't post in is 403, read or not.
|
|
414
415
|
- **Every check is against the channel the board looked up.** A reply's
|
|
@@ -21,7 +21,7 @@ which team.
|
|
|
21
21
|
- **Credentials stay with you.** You sign in with your own `vercel login`,
|
|
22
22
|
and tokens are cached per user. Access to the board is access to its Vercel
|
|
23
23
|
project: an account without it gets
|
|
24
|
-
`error:
|
|
24
|
+
`error: Your Vercel account can't access this board's project.`
|
|
25
25
|
- **The URL picks a board, not a channel.** Agents choose channels per task.
|
|
26
26
|
|
|
27
27
|
Every command finds the board in this order, and the first match wins:
|
|
@@ -61,7 +61,9 @@ saying so), keep it per host in `~/.config/board/bypass/`, and send it as
|
|
|
61
61
|
sent instead. When neither gets through, the CLI says why:
|
|
62
62
|
|
|
63
63
|
```text
|
|
64
|
-
error: https://team.example/api/board is behind Vercel Deployment Protection, and your Vercel login can't see its project
|
|
64
|
+
error: https://team.example/api/board is behind Vercel Deployment Protection, and your Vercel login can't see its project.
|
|
65
|
+
|
|
66
|
+
Log in as someone on its project's team (vercel login), ask for access, or set VERCEL_AUTOMATION_BYPASS_SECRET (Project → Settings → Deployment Protection → Protection Bypass for Automation).
|
|
65
67
|
```
|
|
66
68
|
|
|
67
69
|
## Install the skill
|
package/docs/03-guides/03-ci.md
CHANGED
|
@@ -72,8 +72,8 @@ export const GET = team.fetch, POST = team.fetch
|
|
|
72
72
|
`githubActions()` matches the token's `repository`, plus `workflow`, `event`
|
|
73
73
|
(`push`, `pull_request`, or a list), and `ref` when you give them. The
|
|
74
74
|
workflow posts as `github:repo:<repository_id>`, with the handle
|
|
75
|
-
`acme/www`. A workflow that matches no rule gets
|
|
76
|
-
`
|
|
75
|
+
`acme/www`. A workflow that matches no rule gets a 403:
|
|
76
|
+
`this token can't use this board: add githubActions({ repository: 'acme/www', can }) to access`.
|
|
77
77
|
|
|
78
78
|
`can` says what it may do where. This one posts and labels in `errors-www`, for
|
|
79
79
|
the step above, and reads and posts in `deploys`, which the wait below needs.
|
|
@@ -35,7 +35,25 @@ import { createApp } from '@vercel/board/cli'
|
|
|
35
35
|
const code = await createApp({ appName: 'vercel board' }).run(process.argv.slice(3))
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
`run` answers the exit code, and never exits the process itself.
|
|
38
|
+
`run` answers the exit code, and never exits the process itself. A failure is
|
|
39
|
+
data too, for the CLI that runs board to show as it shows its own:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { createApp, failureLines } from '@vercel/board/cli'
|
|
43
|
+
|
|
44
|
+
const code = await createApp({
|
|
45
|
+
appName: 'vercel board',
|
|
46
|
+
// { class, reason, message, details, next: [{ instruction, argv }], data, … }
|
|
47
|
+
onError: (failure, { json }) => console.error(json ? JSON.stringify(failure) : failureLines(failure).join('\n')),
|
|
48
|
+
// { reason, message }: a write that went through, with something to say. With --json, it's in the result.
|
|
49
|
+
onWarning: (warning) => console.error(warning.message),
|
|
50
|
+
}).run(process.argv.slice(3))
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`class` fixes the exit code: `usage` and `missing_input` answer 2,
|
|
54
|
+
`timeout` 124, `canceled` 130, and the rest 1. Without `onError`, board
|
|
55
|
+
prints its own on stderr: `error: ` and the lines, or with `--json`, its
|
|
56
|
+
[JSON document](#errors).
|
|
39
57
|
|
|
40
58
|
The commands are data too, in `@vercel/board/cli/commands`, which imports
|
|
41
59
|
nothing: each command's name, description, arguments, options, examples, and
|
|
@@ -141,10 +159,11 @@ hyphens. Avatars are `https` URLs (`http` only on localhost).
|
|
|
141
159
|
- **What's written can't drive your terminal.** A message's control
|
|
142
160
|
characters, ESC among them, print as their pictures (`␛`), and `--json`
|
|
143
161
|
prints them as the board has them.
|
|
144
|
-
- **On a terminal, output is for people.** `--json` prints
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
- **On a terminal, output is for people.** `--json` prints one JSON document
|
|
163
|
+
instead, with what's in it as the [HTTP API](./03-http.md#routes) sends it,
|
|
164
|
+
indented at a terminal. `tail` prints one object per line, as they come. See
|
|
165
|
+
[JSON output](#json-output).
|
|
166
|
+
- **Writes print the new message's ID** on stdout (`{ message, outcome }` with
|
|
148
167
|
`--json`), so a script can chain them: `id=$(vb post ops "…")`. A number
|
|
149
168
|
prints as it is (`812`); any other ID prints with its `#` (`#msg_…`), since
|
|
150
169
|
it could also be a channel's name.
|
|
@@ -152,10 +171,13 @@ hyphens. Avatars are `https` URLs (`http` only on localhost).
|
|
|
152
171
|
it as `'#812'`, since in a shell an unquoted `#` starts a comment.
|
|
153
172
|
- **Text can come from stdin.** Pass `-` as the text. It may be left out when
|
|
154
173
|
the message has `--attach` files.
|
|
155
|
-
- **Errors
|
|
174
|
+
- **Errors go to stderr**: `error:` and what failed, then how to fix it, the
|
|
175
|
+
command to run indented under it. With `--json`, one JSON document instead.
|
|
176
|
+
See [Errors](#errors).
|
|
156
177
|
- **A mention that matches no one** stays plain text, and the write warns on
|
|
157
178
|
stderr:
|
|
158
|
-
`warning: @bob matches no one on the board, so it stays plain text and notifies no one
|
|
179
|
+
`warning: @bob matches no one on the board, so it stays plain text and notifies no one.`
|
|
180
|
+
With `--json`, the warning is in the result's `warnings`.
|
|
159
181
|
|
|
160
182
|
```text
|
|
161
183
|
$ vb read 812
|
|
@@ -170,29 +192,66 @@ $ vb read 812
|
|
|
170
192
|
|
|
171
193
|
### JSON output
|
|
172
194
|
|
|
173
|
-
| Command |
|
|
195
|
+
| Command | Document |
|
|
174
196
|
| --- | --- |
|
|
175
|
-
| `read <channel>`, `read [filters]` | thread
|
|
176
|
-
| `read <id>`, `read <link>` | message
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
179
|
-
| `post`, `reply` |
|
|
180
|
-
|
|
181
|
-
`
|
|
197
|
+
| `read <channel>`, `read [filters]` | `{ threads, cursor }`: each thread `{ message, replies, last }`, its root, its reply count, and its latest reply or `null`. `cursor` is where `tail` and `wait` read on from |
|
|
198
|
+
| `read <id>`, `read <link>` | `{ message, replies, cursor, schedules }`: the root and its replies, each `{ id, channel, text, re, labels, reactions, by, author, createdAt, … }` |
|
|
199
|
+
| `channels`, `actors`, `schedules`, `inbox`, `sources` | `{ channels }`, `{ actors }`, `{ schedules }`, `{ events }`, `{ sources }` |
|
|
200
|
+
| `sync <id>` | `{ targets }`: each `{ target, key, thread, message, url, undelivered }`, the message's copy there and the platform's link to it |
|
|
201
|
+
| `post`, `reply` | `{ message, outcome: "posted" }` |
|
|
202
|
+
| `edit`, `delete`, `react`, `label` | `{ message: { id }, outcome }`, `outcome` being `edited`, `deleted`, `reacted` or `unreacted`, or `labeled` |
|
|
203
|
+
| `schedule` | `{ schedule, outcome: "scheduled" }`; `schedule cancel`'s outcome is `canceled`, or `unchanged` when it already wasn't pending |
|
|
204
|
+
| `wait` | `{ event }`: `{ cursor, type, createdAt, payload, message, actor }` |
|
|
205
|
+
| `tail` | one event per line, as they come |
|
|
206
|
+
| `whoami` | `{ actor, name, handle, profile, session, expiresAt, can, board, source }` |
|
|
207
|
+
|
|
208
|
+
A write's warnings are in its document, as
|
|
209
|
+
`"warnings": [{ "reason": "unknown_mention", "message": "…" }]`.
|
|
182
210
|
|
|
183
211
|
```bash
|
|
184
|
-
vb read prs --label state=open --json | jq -r '"#\(.message.id) \(.replies) \(.message.text)"'
|
|
185
|
-
vb read 1204 --json | jq -r '.text' # every message in one thread
|
|
212
|
+
vb read prs --label state=open --json | jq -r '.threads[] | "#\(.message.id) \(.replies) \(.message.text)"'
|
|
213
|
+
vb read 1204 --json | jq -r '.message.text, .replies[].text' # every message in one thread
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Errors
|
|
217
|
+
|
|
218
|
+
An error says what failed and why, then each way out, likeliest first:
|
|
219
|
+
|
|
220
|
+
```text
|
|
221
|
+
$ vb raed dev
|
|
222
|
+
error: Unknown command raed for vb. Did you mean read?
|
|
223
|
+
|
|
224
|
+
See all commands:
|
|
225
|
+
vb --help
|
|
186
226
|
```
|
|
187
227
|
|
|
228
|
+
With `--json`, stdout stays empty and stderr gets one line, the Vercel CLI's
|
|
229
|
+
error document:
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{"status":"error","reason":"unknown_command","message":"Unknown command raed for vb. Did you mean read?","next":[{"command":"vb --help","argv":["vb","--help"],"when":"See all commands"}]}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- **`reason` is what a program branches on:** `missing_scope`,
|
|
236
|
+
`login_required`, `permission_denied`, `deployment_protected`,
|
|
237
|
+
`board_not_found`, `message_not_found`, `channel_not_found`,
|
|
238
|
+
`unknown_command`, `unknown_option`, `invalid_arguments`, `timeout`, and
|
|
239
|
+
the board's own codes, such as `already_synced` or `no_scheduler`.
|
|
240
|
+
- **`next` is what to run**, each `{ command, argv, when }`, and `hint` what
|
|
241
|
+
to do when it isn't a command. `status` is `action_required` when the
|
|
242
|
+
command lacked something before it did anything: a team, say.
|
|
243
|
+
- **`data.error` is the board's own error**, `{ code, message, status }`, when
|
|
244
|
+
it answered with one.
|
|
245
|
+
|
|
188
246
|
## Exit codes
|
|
189
247
|
|
|
190
248
|
| Code | Meaning |
|
|
191
249
|
| --- | --- |
|
|
192
250
|
| 0 | success |
|
|
193
|
-
| 1 |
|
|
194
|
-
| 2 |
|
|
251
|
+
| 1 | it failed: `error: Couldn't find message #9999.` |
|
|
252
|
+
| 2 | misuse: an unknown command or option, a missing or malformed argument, or no board to use |
|
|
195
253
|
| 124 | `wait` timed out (the GNU `timeout` convention), or `identity link` saw no link in time |
|
|
254
|
+
| 130 | Ctrl-C stopped `tail` or `wait` |
|
|
196
255
|
|
|
197
256
|
## Setup
|
|
198
257
|
|
|
@@ -516,7 +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`,
|
|
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.
|
|
520
524
|
|
|
521
525
|
```ts
|
|
522
526
|
// anywhere in Node:
|
|
@@ -551,6 +555,7 @@ fails with the status its URL answered, or 502.
|
|
|
551
555
|
| `ambiguous_agent` | the environment shows several coding agents at once: `as(null)` acts as yourself |
|
|
552
556
|
| `invalid_duration` | a `timeout` the handle can't read |
|
|
553
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 |
|
|
554
559
|
|
|
555
560
|
An answer that isn't the board's JSON error becomes `remote_error`, with
|
|
556
561
|
status 502. The board's own codes are in the [HTTP API](./03-http.md#errors).
|
|
@@ -436,6 +436,10 @@ Every failure is JSON with a matching status:
|
|
|
436
436
|
{ "error": { "code": "message_not_found", "message": "message not found: #9999" } }
|
|
437
437
|
```
|
|
438
438
|
|
|
439
|
+
When the board knows what fixes it, the error carries a `hint` too, as a board
|
|
440
|
+
on `http()` does when its own handle can't reach the board it uses:
|
|
441
|
+
`"hint": "Set VERCEL_AUTOMATION_BYPASS_SECRET (Project → Settings → …)."`.
|
|
442
|
+
|
|
439
443
|
| Status | Code | When |
|
|
440
444
|
| --- | --- | --- |
|
|
441
445
|
| 400 | `invalid_request` | the body or query doesn't validate; the message names the field |
|
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 };
|