@vercel/board 0.16.0 → 0.17.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.
Files changed (127) hide show
  1. package/README.md +27 -27
  2. package/dist/{a2-C41hD8SF.mjs → a2-Bck5x1Kh.mjs} +969 -25
  3. package/dist/access.d.mts +1 -1
  4. package/dist/access.mjs +3 -3
  5. package/dist/{actors-DjMeZpnU.mjs → actors-BOamkEuz.mjs} +3 -73
  6. package/dist/attempts-CLG840Oj.mjs +20 -0
  7. package/dist/{auth-COzc09sn.mjs → auth-Drg9FiC2.mjs} +225 -2
  8. package/dist/backend-B-SJ7p6p.d.mts +680 -0
  9. package/dist/backend-a2/contract.d.mts +873 -2
  10. package/dist/backend-a2/contract.mjs +2 -2
  11. package/dist/backend-a2/scheduler-local.d.mts +1 -1
  12. package/dist/backend-a2/scheduler-local.mjs +1 -1
  13. package/dist/backend-a2/scheduler-qstash.d.mts +78 -1
  14. package/dist/backend-a2/scheduler-qstash.mjs +521 -1
  15. package/dist/backend-a2/scheduler-vercel.d.mts +37 -1
  16. package/dist/backend-a2/scheduler-vercel.mjs +203 -1
  17. package/dist/backend-a2/store-memory.d.mts +2 -2
  18. package/dist/backend-a2/store-memory.mjs +3 -3
  19. package/dist/backend-a2/store-postgres.d.mts +1 -1
  20. package/dist/backend-a2/store-postgres.mjs +2850 -2
  21. package/dist/backend-a2/store-redis-http.d.mts +1 -1
  22. package/dist/backend-a2/store-redis-http.mjs +490 -2
  23. package/dist/backend-a2/store-redis.d.mts +10 -2
  24. package/dist/backend-a2/store-redis.mjs +51 -2
  25. package/dist/backend-a2/store-sqlite.d.mts +1 -1
  26. package/dist/backend-a2/store-sqlite.mjs +3 -3
  27. package/dist/backend-a2.d.mts +2706 -3
  28. package/dist/backend-a2.mjs +1 -1
  29. package/dist/{backend-http-Bid7RIpC.d.mts → backend-http-7cNb8nJI.d.mts} +10 -3
  30. package/dist/{backend-http-0roEmjl0.mjs → backend-http-C5I7Wfdw.mjs} +2 -2
  31. package/dist/{backend-http-BVRno-ca.mjs → backend-http-CuUIACCs.mjs} +32 -3
  32. package/dist/backend-http.d.mts +1 -1
  33. package/dist/backend-http.mjs +1 -1
  34. package/dist/backend-http.node.d.mts +1 -1
  35. package/dist/backend-http.node.mjs +1 -1
  36. package/dist/{chat-provider-XCnQlxq6.d.mts → chat-provider-DNJQyajS.d.mts} +16 -4
  37. package/dist/{chat-provider-jFSeyNmB.mjs → chat-provider-YHy-WbrB.mjs} +15 -9
  38. package/dist/cli.mjs +30 -10
  39. package/dist/{client-DGDPaN7U.mjs → client-BA-J7usH.mjs} +10 -2
  40. package/dist/{conformance-DRR23YNy.mjs → conformance-CT5EeHeC.mjs} +5 -2
  41. package/dist/conformance.d.mts +1 -1
  42. package/dist/conformance.mjs +1 -1
  43. package/dist/{engine-Bir5s8ts.mjs → engine-D0oBUBEK.mjs} +249 -163
  44. package/dist/events-CewD4kw7.mjs +75 -0
  45. package/dist/{exports-Dvc1o52I.mjs → exports-DOdA7KhF.mjs} +35 -32
  46. package/dist/exports-ZsgjzEnM.d.mts +4 -0
  47. package/dist/external-BV_cUncs.mjs +151 -0
  48. package/dist/folds-CRYY14kc.d.mts +534 -0
  49. package/dist/{reducers-mUPFuFJV.mjs → folds-Dyjput8M.mjs} +6 -73
  50. package/dist/ids-C6AYo1bu.mjs +31 -0
  51. package/dist/index.d.mts +4 -4
  52. package/dist/{index.default-Bkg77Pxn.mjs → index.default-n4qKN7EL.mjs} +1 -1
  53. package/dist/index.mjs +5 -5
  54. package/dist/index.node.d.mts +4 -4
  55. package/dist/index.node.mjs +3 -3
  56. package/dist/inspect/app.js +31 -31
  57. package/dist/inspect/engine.js +5 -5
  58. package/dist/internal-CvsrprnU-CRY89I-b.mjs +203 -0
  59. package/dist/{local-Cr_dSjvs.mjs → local-DhkrAqPP.mjs} +1 -1
  60. package/dist/mentions-CB6ShY4R.mjs +72 -0
  61. package/dist/{targets-yM5JBUgr.mjs → middleware-CqaCwucP.mjs} +1 -33
  62. package/dist/platform-B4TnJtWu-CwcTyKg2.mjs +32 -0
  63. package/dist/{project-CFiArraX.mjs → project-DMDST9kl.mjs} +1 -1
  64. package/dist/{provider-BGjz-mDa.d.mts → provider-B0b9Qxw4.d.mts} +170 -40
  65. package/dist/provider-B3DpYSDq.mjs +220 -0
  66. package/dist/redis-tables-DN9PfIDi.mjs +3897 -0
  67. package/dist/reducer-CYPHsSmd-BQIfozGi.d.mts +170 -0
  68. package/dist/reducer-CjmvZSAb-D_OSISmj.mjs +74 -0
  69. package/dist/{contract-CuJmlrhw.mjs → reducers-BFmIXilu.mjs} +260 -287
  70. package/dist/retryable-lazy-DZWmHpii-Bye-W8q7.mjs +19 -0
  71. package/dist/scheduler-task-X1SToDjP-BVoWuInI.mjs +69 -0
  72. package/dist/{serve-BsOOc-6_.mjs → serve-CNYvA4pT.mjs} +5 -5
  73. package/dist/server-DtFrWxi3-Boa6gdWO.mjs +3602 -0
  74. package/dist/server-qgez0Xny-D5mLfqFQ.d.mts +385 -0
  75. package/dist/{server-jwPY7_wi.mjs → server-snYFkITb.mjs} +4 -4
  76. package/dist/{serving-BNbzc96L.mjs → serving-CNkgUPW1.mjs} +1 -1
  77. package/dist/session-clear-wHd5GCpZ-BnKSxReK.mjs +51 -0
  78. package/dist/{sql-DbiEnqM0.mjs → sql-U9WTxrwJ.mjs} +2 -2
  79. package/dist/{sqlite-db-Cbj03vmp.mjs → sqlite-db-Ds4majtT.mjs} +1 -1
  80. package/dist/store-D0MhBvg6-4Z2L0Kqd.d.mts +530 -0
  81. package/dist/store-N8PXxDAS-BWBgzBHp.mjs +5 -0
  82. package/dist/store-codec-DwrWlgQx-CYxGW0aD.mjs +61 -0
  83. package/dist/store-memory-Bas9Uq5C.mjs +872 -0
  84. package/dist/store-memory-ZLiZbH3R.mjs +2 -0
  85. package/dist/store-polling-BZt2Rf3D-BiEM6_HB.mjs +148 -0
  86. package/dist/store-presence-polling-JuAy2Ck2-CYpuK75X.mjs +109 -0
  87. package/dist/store-sqlite-BmwL3pUR.mjs +2 -0
  88. package/dist/store-sqlite-CxxPCcCT.mjs +1053 -0
  89. package/dist/stream-buffer-DrTyiIuo-BKy-vI14.mjs +53 -0
  90. package/dist/sync-github.d.mts +24 -17
  91. package/dist/sync-github.mjs +89 -22
  92. package/dist/sync-kapso.d.mts +15 -13
  93. package/dist/sync-kapso.mjs +17 -14
  94. package/dist/sync-slack.d.mts +12 -17
  95. package/dist/sync-slack.mjs +54 -42
  96. package/dist/sync.chat.d.mts +1 -1
  97. package/dist/sync.chat.mjs +1 -1
  98. package/dist/sync.d.mts +3 -3
  99. package/dist/sync.mjs +5 -4
  100. package/dist/targets-C-wdR5wP.mjs +33 -0
  101. package/dist/{tokens-DKLn5P9B.mjs → tokens-DhuzKzAl.mjs} +1 -1
  102. package/dist/{types-BHCjTZdB.d.mts → types-8yq2VnKI.d.mts} +2 -2
  103. package/dist/{users-Dls7_ANV.mjs → users-yryHKFMo.mjs} +2 -2
  104. package/dist/{watch-spec-W0c7ypHJ.mjs → watchers-hash-DojIuoFg.mjs} +233 -28
  105. package/docs/01-board/01-mounting.md +1 -1
  106. package/docs/02-sync/01-overview.md +69 -47
  107. package/docs/02-sync/02-functions.md +395 -0
  108. package/docs/02-sync/03-slack.md +30 -25
  109. package/docs/02-sync/04-github.md +62 -26
  110. package/docs/02-sync/05-whatsapp.md +23 -19
  111. package/docs/02-sync/06-providers.md +58 -26
  112. package/docs/03-guides/04-triage.md +1 -1
  113. package/docs/04-reference/01-cli.md +26 -6
  114. package/docs/04-reference/02-board.md +18 -5
  115. package/docs/04-reference/03-http.md +5 -2
  116. package/docs/04-reference/05-conformance.md +1 -1
  117. package/docs/index.md +5 -10
  118. package/package.json +22 -6
  119. package/dist/a2-D24cvwpN.d.mts +0 -3359
  120. package/dist/access-CJU2-vaa.mjs +0 -226
  121. package/dist/attempts-Bxp9KgPf.mjs +0 -919
  122. package/dist/exports-DLiE7fLY.d.mts +0 -4
  123. package/dist/provider-CuewcDNZ.mjs +0 -205
  124. package/dist/redis-tables-B35vv4CZ.mjs +0 -842
  125. package/dist/reducers-B_vUGQRp.d.mts +0 -1172
  126. package/dist/watchers-hash-CLjsa6od.mjs +0 -225
  127. package/docs/02-sync/02-callbacks.md +0 -265
@@ -240,12 +240,25 @@ This handle's own post with `id`, as posting it answered, or a 404
240
240
  ### sync
241
241
 
242
242
  ```ts
243
+ sync(id: string): Promise<SyncedView>
243
244
  sync(id: string, target: string): Promise<{ target: string; attached: boolean }>
245
+ linked(url: string): Promise<ThreadView>
244
246
  ```
245
247
 
246
- Attaches the message's thread to an external target and backfills it.
247
- `target` is the normalized target; `attached` is false when the thread was
248
- already synced there. See [Sync](../02-sync/01-overview.md).
248
+ With a target, `sync` attaches the message's thread to an external target and
249
+ backfills it. `target` is the normalized target; `attached` is false when the
250
+ thread was already synced there.
251
+
252
+ With no target, it says where the thread is synced: `{ targets }`, each
253
+ `{ target, key, thread, message, url, undelivered }`, with this message's copy
254
+ there by the platform's ID and the platform's link to it. It needs `read` where
255
+ the message is.
256
+
257
+ `linked(url)` is the thread a platform link names (a Slack permalink, a GitHub
258
+ PR, issue, or comment), as `thread(id)` answers it. The board looks it up in
259
+ what its sync recorded and never asks the platform: a link it didn't sync, or
260
+ to a message you can't read, is 404 `message_not_found`. See
261
+ [Sync](../02-sync/01-overview.md).
249
262
 
250
263
  ### typing
251
264
 
@@ -574,6 +587,6 @@ export async function POST(request: Request) {
574
587
  calls `http()`'s methods, which call that board, whose middleware sees its
575
588
  writes.
576
589
 
577
- Sync callbacks get a client of their own, acting as the platform user who
590
+ Sync functions get a client of their own, acting as the platform user who
578
591
  triggered the event. See [Mounting](../01-board/01-mounting.md),
579
- [Watchers](../01-board/06-watchers.md), and [Callbacks](../02-sync/02-callbacks.md).
592
+ [Watchers](../01-board/06-watchers.md), and [Sync functions](../02-sync/02-functions.md).
@@ -109,6 +109,8 @@ a refused write it can read answers 403. `GET /me` returns the caller's
109
109
  | POST | `/messages/:id/reactions` | `{ emoji, remove? }`. `emoji` is a short name: `eyes`, `thumbs_up` |
110
110
  | POST | `/messages/:id/labels` | `{ set?, unset? }`, at least one |
111
111
  | POST | `/messages/:id/sync` | `{ target }`: attach the thread to an external target and backfill it. Answers `{ target, attached }` |
112
+ | GET | `/messages/:id/sync` | Where the thread is synced: `{ targets }`, each `{ target, key, thread, message, url, undelivered }`, with this message's copy there and the platform's link to it. Needs `read` where it is |
113
+ | GET | `/links` | The thread a platform link names, as `GET /messages/:id` answers it. Query: `url`. From sync's records alone; a link the board didn't sync, or to a message the caller can't read, is 404 `message_not_found` |
112
114
  | POST | `/messages/:id/typing` | `{ status? }`: show typing in the thread's synced platform threads. Answers `{ targets }`. Writes nothing to the log |
113
115
  | POST | `/attachments` | Upload one file. Answers 201 `{ attachment: { id, name, type, size } }`. See [Attachments](#attachments) |
114
116
  | GET | `/attachments/:id` | The file |
@@ -139,8 +141,9 @@ Every board that keeps its own log answers every route here. The sync routes
139
141
  a person calls (`/webhooks/:key`, `/messages/:id/sync`, `/identity/sign-in`,
140
142
  `/identity/signed-in`, and `/identity/unlink`) are `board()`'s, and work on any
141
143
  backend: the ones that need a sync entry answer 404 on a board that doesn't
142
- run it. `/sources/:key/read` and `/messages/:id/typing` are the backend's
143
- methods, which `a2()` answers through the sync `board()` runs beside it. A
144
+ run it. `/sources/:key/read`, `/messages/:id/typing`, `GET /messages/:id/sync`,
145
+ and `/links` are the backend's methods, which `a2()` answers through the sync
146
+ `board()` runs beside it. A
144
147
  board on `http()` answers only wake-ups, webhooks, and its sync's sign-ins,
145
148
  unless it has an `access` of its own: then it serves its callers as its
146
149
  project on the board it uses (see [A board on `http()`](../01-board/09-access.md#a-board-on-http)). There are no
@@ -56,7 +56,7 @@ Then the rest, a group each in the report:
56
56
  | `schedules` | schedules a reply a day out, lists it, and cancels it |
57
57
  | `attachments` | uploads a file, posts it, and downloads it |
58
58
  | `watchers` | registers a tail, pulls the match for a post, and acks it. Skipped when the token already has watchers or a sync registered there, since registering replaces them |
59
- | `sync` | imports a message as a platform user of its own (`conformance:user:<id>`), finds it by its platform IDs, imports it again to the same message, refuses a second root from the same platform thread, records a receipt and reads the copy back, and deletes it. Skipped when the token can't register a sync or `sync` in the channel, or already has watchers or a sync registered |
59
+ | `sync` | imports a message as a platform user of its own (`conformance:user:<id>`), finds it by its platform IDs, imports it again to the same message, refuses a second root from the same platform thread, records a receipt and reads the copy back, lists where the thread is synced with it, answers 404 for a link no sync there knows, and deletes it. Skipped when the token can't register a sync or `sync` in the channel, or already has watchers or a sync registered |
60
60
 
61
61
  Every board answers all of them: see
62
62
  [the whole protocol](./03-http.md#the-whole-protocol). A board may keep no
package/docs/index.md CHANGED
@@ -51,8 +51,8 @@ import { board } from '@vercel/board'
51
51
  import { a2 } from '@vercel/board/backend-a2'
52
52
  import { vercelQueues } from '@vercel/board/backend-a2/scheduler-vercel'
53
53
  import { postgres } from '@vercel/board/backend-a2/store-postgres'
54
- import { slack } from '@vercel/board/sync-slack'
55
- import { github } from '@vercel/board/sync-github'
54
+ import { channels, slack } from '@vercel/board/sync-slack'
55
+ import { github, repos } from '@vercel/board/sync-github'
56
56
 
57
57
  const backend = a2({
58
58
  store: postgres({ connectionString: process.env.DATABASE_URL! }),
@@ -62,14 +62,9 @@ const backend = a2({
62
62
  const team = board({
63
63
  backend,
64
64
  sync: {
65
- slack: slack({
66
- adapter: 'slack/acme', // a Vercel Connect connector
67
- channels: { '#errors-www': 'errors-www', '#prs': 'prs' },
68
- }),
69
- github: github({
70
- adapter: 'github/acme',
71
- repos: { 'acme/www': 'prs' },
72
- }),
65
+ // A Vercel Connect connector, and what each event does.
66
+ slack: slack('slack/acme', channels({ '#errors-www': 'errors-www', '#prs': 'prs' })),
67
+ github: github('github/acme', repos({ 'acme/www': 'prs' })),
73
68
  },
74
69
  })
75
70
  export const GET = team.fetch, POST = team.fetch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/board",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "A message board you mount in one route: one durable log, verified authors, live tail, and two-way sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -103,24 +103,25 @@
103
103
  "./package.json": "./package.json"
104
104
  },
105
105
  "dependencies": {
106
- "@chat-adapter/github": "^4.41.1",
107
- "@chat-adapter/slack": "^4.41.1",
108
- "@vercel/connect": "^2.3.4",
109
106
  "@vercel/oidc": "^3.8.9",
110
- "chat": "^4.41.1",
111
- "experimental-a2": "0.22.0",
112
107
  "jose": "^6.2.12",
113
108
  "zod": "^4.6.5"
114
109
  },
115
110
  "peerDependencies": {
111
+ "@chat-adapter/github": "^4.41.1",
112
+ "@chat-adapter/slack": "^4.41.1",
116
113
  "@upstash/qstash": "^2.11.0",
117
114
  "@vercel/blob": "^2.8.0",
115
+ "@vercel/connect": "^2.3.4",
118
116
  "@vercel/queue": "*",
117
+ "chat": "^4.41.1",
119
118
  "ioredis": "^5.4.0",
120
119
  "pg": "^8.11.0"
121
120
  },
122
121
  "devDependencies": {
123
122
  "@base-ui/react": "^1.8.0",
123
+ "@chat-adapter/github": "^4.41.1",
124
+ "@chat-adapter/slack": "^4.41.1",
124
125
  "@chat-adapter/tests": "^4.41.1",
125
126
  "@electric-sql/pglite": "0.3.15",
126
127
  "@kapso/chat-adapter": "^0.1.1",
@@ -129,7 +130,10 @@
129
130
  "@types/react": "^19.3.0",
130
131
  "@types/react-dom": "^19.3.0",
131
132
  "@vercel/blob": "^2.8.0",
133
+ "@vercel/connect": "^2.3.4",
132
134
  "ai": "^7.0.130",
135
+ "chat": "^4.41.1",
136
+ "experimental-a2": "0.22.0",
133
137
  "ioredis": "5.11.1",
134
138
  "lucide-react": "^1.49.0",
135
139
  "pg": "^8.16.3",
@@ -143,15 +147,27 @@
143
147
  "vitest": "^5.0.3"
144
148
  },
145
149
  "peerDependenciesMeta": {
150
+ "@chat-adapter/github": {
151
+ "optional": true
152
+ },
153
+ "@chat-adapter/slack": {
154
+ "optional": true
155
+ },
146
156
  "@upstash/qstash": {
147
157
  "optional": true
148
158
  },
149
159
  "@vercel/blob": {
150
160
  "optional": true
151
161
  },
162
+ "@vercel/connect": {
163
+ "optional": true
164
+ },
152
165
  "@vercel/queue": {
153
166
  "optional": true
154
167
  },
168
+ "chat": {
169
+ "optional": true
170
+ },
155
171
  "ioredis": {
156
172
  "optional": true
157
173
  },