@vercel/board 0.0.0 → 0.16.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 (126) hide show
  1. package/README.md +180 -0
  2. package/dist/a2-C41hD8SF.mjs +3045 -0
  3. package/dist/a2-D24cvwpN.d.mts +3359 -0
  4. package/dist/access-CJU2-vaa.mjs +226 -0
  5. package/dist/access-CV96SYgr.d.mts +32 -0
  6. package/dist/access.d.mts +30 -0
  7. package/dist/access.mjs +4 -0
  8. package/dist/actors-DjMeZpnU.mjs +224 -0
  9. package/dist/attempts-Bxp9KgPf.mjs +919 -0
  10. package/dist/auth-COzc09sn.mjs +276 -0
  11. package/dist/auth-CU56Q2Xh.d.mts +204 -0
  12. package/dist/backend-a2/blob-vercel.d.mts +8 -0
  13. package/dist/backend-a2/blob-vercel.mjs +81 -0
  14. package/dist/backend-a2/contract.d.mts +18 -0
  15. package/dist/backend-a2/contract.mjs +5 -0
  16. package/dist/backend-a2/scheduler-local.d.mts +11 -0
  17. package/dist/backend-a2/scheduler-local.mjs +2 -0
  18. package/dist/backend-a2/scheduler-qstash.d.mts +2 -0
  19. package/dist/backend-a2/scheduler-qstash.mjs +2 -0
  20. package/dist/backend-a2/scheduler-vercel.d.mts +2 -0
  21. package/dist/backend-a2/scheduler-vercel.mjs +2 -0
  22. package/dist/backend-a2/store-memory.d.mts +11 -0
  23. package/dist/backend-a2/store-memory.mjs +19 -0
  24. package/dist/backend-a2/store-postgres.d.mts +38 -0
  25. package/dist/backend-a2/store-postgres.mjs +110 -0
  26. package/dist/backend-a2/store-redis-http.d.mts +17 -0
  27. package/dist/backend-a2/store-redis-http.mjs +32 -0
  28. package/dist/backend-a2/store-redis.d.mts +23 -0
  29. package/dist/backend-a2/store-redis.mjs +39 -0
  30. package/dist/backend-a2/store-sqlite.d.mts +12 -0
  31. package/dist/backend-a2/store-sqlite.mjs +31 -0
  32. package/dist/backend-a2.d.mts +4 -0
  33. package/dist/backend-a2.mjs +2 -0
  34. package/dist/backend-http-0roEmjl0.mjs +613 -0
  35. package/dist/backend-http-BVRno-ca.mjs +469 -0
  36. package/dist/backend-http-Bid7RIpC.d.mts +630 -0
  37. package/dist/backend-http.d.mts +10 -0
  38. package/dist/backend-http.mjs +2 -0
  39. package/dist/backend-http.node.d.mts +10 -0
  40. package/dist/backend-http.node.mjs +2 -0
  41. package/dist/blob-C0J3wbGv.d.mts +39 -0
  42. package/dist/bots-CGkO76qH.mjs +67 -0
  43. package/dist/chat-provider-XCnQlxq6.d.mts +140 -0
  44. package/dist/chat-provider-jFSeyNmB.mjs +389 -0
  45. package/dist/cli.d.mts +1 -0
  46. package/dist/cli.mjs +2252 -0
  47. package/dist/client-DGDPaN7U.mjs +380 -0
  48. package/dist/conformance-DRR23YNy.mjs +512 -0
  49. package/dist/conformance.d.mts +30 -0
  50. package/dist/conformance.mjs +2 -0
  51. package/dist/contract-CuJmlrhw.mjs +566 -0
  52. package/dist/emoji-CTLpvH-A.mjs +445 -0
  53. package/dist/engine-Bir5s8ts.mjs +1449 -0
  54. package/dist/errors-DX3hpwWt.mjs +64 -0
  55. package/dist/exports-DLiE7fLY.d.mts +4 -0
  56. package/dist/exports-Dvc1o52I.mjs +1285 -0
  57. package/dist/files-SniSmeEr.mjs +47 -0
  58. package/dist/index.d.mts +13 -0
  59. package/dist/index.default-Bkg77Pxn.mjs +12 -0
  60. package/dist/index.mjs +19 -0
  61. package/dist/index.node.d.mts +14 -0
  62. package/dist/index.node.mjs +5 -0
  63. package/dist/inspect/app.js +416 -0
  64. package/dist/inspect/engine.js +5 -0
  65. package/dist/local-Cr_dSjvs.mjs +44 -0
  66. package/dist/own-OwgPWdmh.mjs +15 -0
  67. package/dist/project-CFiArraX.mjs +124 -0
  68. package/dist/provider-BGjz-mDa.d.mts +2473 -0
  69. package/dist/provider-CuewcDNZ.mjs +205 -0
  70. package/dist/redis-tables-B35vv4CZ.mjs +842 -0
  71. package/dist/reducers-B_vUGQRp.d.mts +1172 -0
  72. package/dist/reducers-mUPFuFJV.mjs +293 -0
  73. package/dist/schemas-Be08nyfW.mjs +74 -0
  74. package/dist/schemas-CWxs3ECJ.d.mts +50 -0
  75. package/dist/serve-BsOOc-6_.mjs +170 -0
  76. package/dist/server-jwPY7_wi.mjs +17 -0
  77. package/dist/serving-BNbzc96L.mjs +2 -0
  78. package/dist/sql-DbiEnqM0.mjs +571 -0
  79. package/dist/sqlite-db-Cbj03vmp.mjs +70 -0
  80. package/dist/sync-github.d.mts +473 -0
  81. package/dist/sync-github.mjs +603 -0
  82. package/dist/sync-kapso.d.mts +175 -0
  83. package/dist/sync-kapso.mjs +86 -0
  84. package/dist/sync-slack.d.mts +364 -0
  85. package/dist/sync-slack.mjs +728 -0
  86. package/dist/sync.chat.d.mts +2 -0
  87. package/dist/sync.chat.mjs +2 -0
  88. package/dist/sync.d.mts +3 -0
  89. package/dist/sync.mjs +4 -0
  90. package/dist/targets-yM5JBUgr.mjs +94 -0
  91. package/dist/tokens-DKLn5P9B.mjs +256 -0
  92. package/dist/types-BHCjTZdB.d.mts +104 -0
  93. package/dist/users-Dls7_ANV.mjs +42 -0
  94. package/dist/watch-spec-W0c7ypHJ.mjs +787 -0
  95. package/dist/watchers-hash-CLjsa6od.mjs +225 -0
  96. package/docs/01-board/01-mounting.md +506 -0
  97. package/docs/01-board/02-database.md +258 -0
  98. package/docs/01-board/03-identity.md +264 -0
  99. package/docs/01-board/04-messages.md +192 -0
  100. package/docs/01-board/05-reading.md +177 -0
  101. package/docs/01-board/06-watchers.md +249 -0
  102. package/docs/01-board/07-schedules.md +133 -0
  103. package/docs/01-board/08-middleware.md +139 -0
  104. package/docs/01-board/09-access.md +501 -0
  105. package/docs/01-quickstart.md +196 -0
  106. package/docs/02-sync/01-overview.md +290 -0
  107. package/docs/02-sync/02-callbacks.md +265 -0
  108. package/docs/02-sync/03-slack.md +248 -0
  109. package/docs/02-sync/04-github.md +201 -0
  110. package/docs/02-sync/05-whatsapp.md +148 -0
  111. package/docs/02-sync/06-providers.md +228 -0
  112. package/docs/03-guides/01-coding-agents.md +226 -0
  113. package/docs/03-guides/02-inspector.md +104 -0
  114. package/docs/03-guides/03-ci.md +251 -0
  115. package/docs/03-guides/04-triage.md +233 -0
  116. package/docs/03-guides/05-agent-factory.md +142 -0
  117. package/docs/04-reference/01-cli.md +606 -0
  118. package/docs/04-reference/02-board.md +579 -0
  119. package/docs/04-reference/03-http.md +489 -0
  120. package/docs/04-reference/04-log.md +250 -0
  121. package/docs/04-reference/05-conformance.md +97 -0
  122. package/docs/index.md +186 -0
  123. package/package.json +168 -1
  124. package/sql/postgres/board.sql +145 -0
  125. package/sql/postgres/notifications.sql +24 -0
  126. package/sql/postgres/schema.sql +451 -0
package/package.json CHANGED
@@ -1 +1,168 @@
1
- {"name":"@vercel/board","version":"0.0.0"}
1
+ {
2
+ "name": "@vercel/board",
3
+ "version": "0.16.0",
4
+ "description": "A message board you mount in one route: one durable log, verified authors, live tail, and two-way sync.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=22.18"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "docs",
13
+ "sql",
14
+ "README.md"
15
+ ],
16
+ "bin": {
17
+ "board": "./dist/cli.mjs",
18
+ "vb": "./dist/cli.mjs"
19
+ },
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.mts",
23
+ "node": "./dist/index.node.mjs",
24
+ "default": "./dist/index.mjs"
25
+ },
26
+ "./access": {
27
+ "types": "./dist/access.d.mts",
28
+ "default": "./dist/access.mjs"
29
+ },
30
+ "./conformance": {
31
+ "types": "./dist/conformance.d.mts",
32
+ "default": "./dist/conformance.mjs"
33
+ },
34
+ "./backend-a2": {
35
+ "types": "./dist/backend-a2.d.mts",
36
+ "default": "./dist/backend-a2.mjs"
37
+ },
38
+ "./backend-a2/contract": {
39
+ "types": "./dist/backend-a2/contract.d.mts",
40
+ "default": "./dist/backend-a2/contract.mjs"
41
+ },
42
+ "./backend-a2/blob-vercel": {
43
+ "types": "./dist/backend-a2/blob-vercel.d.mts",
44
+ "default": "./dist/backend-a2/blob-vercel.mjs"
45
+ },
46
+ "./backend-a2/store-postgres": {
47
+ "types": "./dist/backend-a2/store-postgres.d.mts",
48
+ "default": "./dist/backend-a2/store-postgres.mjs"
49
+ },
50
+ "./backend-a2/store-redis": {
51
+ "types": "./dist/backend-a2/store-redis.d.mts",
52
+ "default": "./dist/backend-a2/store-redis.mjs"
53
+ },
54
+ "./backend-a2/store-redis-http": {
55
+ "types": "./dist/backend-a2/store-redis-http.d.mts",
56
+ "default": "./dist/backend-a2/store-redis-http.mjs"
57
+ },
58
+ "./backend-a2/store-sqlite": {
59
+ "types": "./dist/backend-a2/store-sqlite.d.mts",
60
+ "default": "./dist/backend-a2/store-sqlite.mjs"
61
+ },
62
+ "./backend-a2/store-memory": {
63
+ "types": "./dist/backend-a2/store-memory.d.mts",
64
+ "default": "./dist/backend-a2/store-memory.mjs"
65
+ },
66
+ "./backend-a2/scheduler-vercel": {
67
+ "types": "./dist/backend-a2/scheduler-vercel.d.mts",
68
+ "default": "./dist/backend-a2/scheduler-vercel.mjs"
69
+ },
70
+ "./backend-a2/scheduler-qstash": {
71
+ "types": "./dist/backend-a2/scheduler-qstash.d.mts",
72
+ "default": "./dist/backend-a2/scheduler-qstash.mjs"
73
+ },
74
+ "./backend-a2/scheduler-local": {
75
+ "types": "./dist/backend-a2/scheduler-local.d.mts",
76
+ "default": "./dist/backend-a2/scheduler-local.mjs"
77
+ },
78
+ "./backend-http": {
79
+ "types": "./dist/backend-http.d.mts",
80
+ "node": "./dist/backend-http.node.mjs",
81
+ "default": "./dist/backend-http.mjs"
82
+ },
83
+ "./sync": {
84
+ "types": "./dist/sync.d.mts",
85
+ "default": "./dist/sync.mjs"
86
+ },
87
+ "./sync/chat": {
88
+ "types": "./dist/sync.chat.d.mts",
89
+ "default": "./dist/sync.chat.mjs"
90
+ },
91
+ "./sync-slack": {
92
+ "types": "./dist/sync-slack.d.mts",
93
+ "default": "./dist/sync-slack.mjs"
94
+ },
95
+ "./sync-github": {
96
+ "types": "./dist/sync-github.d.mts",
97
+ "default": "./dist/sync-github.mjs"
98
+ },
99
+ "./sync-kapso": {
100
+ "types": "./dist/sync-kapso.d.mts",
101
+ "default": "./dist/sync-kapso.mjs"
102
+ },
103
+ "./package.json": "./package.json"
104
+ },
105
+ "dependencies": {
106
+ "@chat-adapter/github": "^4.41.1",
107
+ "@chat-adapter/slack": "^4.41.1",
108
+ "@vercel/connect": "^2.3.4",
109
+ "@vercel/oidc": "^3.8.9",
110
+ "chat": "^4.41.1",
111
+ "experimental-a2": "0.22.0",
112
+ "jose": "^6.2.12",
113
+ "zod": "^4.6.5"
114
+ },
115
+ "peerDependencies": {
116
+ "@upstash/qstash": "^2.11.0",
117
+ "@vercel/blob": "^2.8.0",
118
+ "@vercel/queue": "*",
119
+ "ioredis": "^5.4.0",
120
+ "pg": "^8.11.0"
121
+ },
122
+ "devDependencies": {
123
+ "@base-ui/react": "^1.8.0",
124
+ "@chat-adapter/tests": "^4.41.1",
125
+ "@electric-sql/pglite": "0.3.15",
126
+ "@kapso/chat-adapter": "^0.1.1",
127
+ "@types/node": "^26.6.3",
128
+ "@types/pg": "8.15.5",
129
+ "@types/react": "^19.3.0",
130
+ "@types/react-dom": "^19.3.0",
131
+ "@vercel/blob": "^2.8.0",
132
+ "ai": "^7.0.130",
133
+ "ioredis": "5.11.1",
134
+ "lucide-react": "^1.49.0",
135
+ "pg": "^8.16.3",
136
+ "react": "^19.3.0",
137
+ "react-dom": "^19.3.0",
138
+ "react-markdown": "^10.1.0",
139
+ "remark-breaks": "^4.0.0",
140
+ "remark-gfm": "^4.0.1",
141
+ "tsdown": "^0.23.0",
142
+ "typescript": "^7.0.2",
143
+ "vitest": "^5.0.3"
144
+ },
145
+ "peerDependenciesMeta": {
146
+ "@upstash/qstash": {
147
+ "optional": true
148
+ },
149
+ "@vercel/blob": {
150
+ "optional": true
151
+ },
152
+ "@vercel/queue": {
153
+ "optional": true
154
+ },
155
+ "ioredis": {
156
+ "optional": true
157
+ },
158
+ "pg": {
159
+ "optional": true
160
+ }
161
+ },
162
+ "scripts": {
163
+ "build": "tsdown && node scripts/schema.ts",
164
+ "typecheck": "tsc --noEmit",
165
+ "test": "vitest run",
166
+ "pretest": "tsdown --log-level warn"
167
+ }
168
+ }
@@ -0,0 +1,145 @@
1
+ -- board's tables, which live next to A2's. schema.sql holds both: apply that.
2
+
3
+ create table if not exists board_positions (
4
+ consumer text primary key,
5
+ log_index bigint not null
6
+ );
7
+ --> statement-breakpoint
8
+ create table if not exists board_messages (
9
+ id bigint primary key,
10
+ event_id text not null unique,
11
+ channel text not null,
12
+ re bigint,
13
+ by_actor text not null,
14
+ by_principal text not null,
15
+ by_profile text,
16
+ from_key text,
17
+ no_sync boolean not null,
18
+ text_lower text not null,
19
+ deleted boolean not null,
20
+ created_at bigint not null,
21
+ replies integer not null default 0,
22
+ at bigint,
23
+ data text not null
24
+ );
25
+ --> statement-breakpoint
26
+ create index if not exists board_messages_channel on board_messages (channel, id);
27
+ --> statement-breakpoint
28
+ create index if not exists board_messages_re on board_messages (re, id);
29
+ --> statement-breakpoint
30
+ create index if not exists board_messages_by_actor on board_messages (by_actor, id);
31
+ --> statement-breakpoint
32
+ create index if not exists board_messages_by_principal on board_messages (by_principal, id);
33
+ --> statement-breakpoint
34
+ create index if not exists board_threads_at on board_messages (at) where re is null;
35
+ --> statement-breakpoint
36
+ create index if not exists board_threads_channel on board_messages (channel, at) where re is null;
37
+ --> statement-breakpoint
38
+ create table if not exists board_versions (
39
+ log_index bigint primary key,
40
+ message_id bigint not null,
41
+ data text not null
42
+ );
43
+ --> statement-breakpoint
44
+ create index if not exists board_versions_message on board_versions (message_id, log_index);
45
+ --> statement-breakpoint
46
+ create table if not exists board_terms (
47
+ message_id bigint not null,
48
+ term text not null,
49
+ value text not null,
50
+ primary key (message_id, term, value)
51
+ );
52
+ --> statement-breakpoint
53
+ create index if not exists board_terms_term on board_terms (term, value, message_id);
54
+ --> statement-breakpoint
55
+ create table if not exists board_sync_threads (
56
+ thread text primary key,
57
+ data text not null
58
+ );
59
+ --> statement-breakpoint
60
+ create table if not exists board_external_threads (
61
+ external text primary key,
62
+ thread text not null
63
+ );
64
+ --> statement-breakpoint
65
+ create table if not exists board_copies (
66
+ message_id bigint not null,
67
+ target text not null,
68
+ data text not null,
69
+ primary key (message_id, target)
70
+ );
71
+ --> statement-breakpoint
72
+ create table if not exists board_external_messages (
73
+ key text primary key,
74
+ message_id bigint not null
75
+ );
76
+ --> statement-breakpoint
77
+ create index if not exists board_messages_recent on board_messages (by_principal, created_at) where re is null;
78
+ --> statement-breakpoint
79
+ drop function if exists board_apply(text, bigint, boolean, jsonb, jsonb, jsonb);
80
+ --> statement-breakpoint
81
+ create or replace function board_apply(
82
+ apply_consumer text,
83
+ apply_index bigint,
84
+ apply_next boolean,
85
+ apply_message jsonb,
86
+ apply_terms jsonb,
87
+ apply_summary jsonb,
88
+ apply_sync jsonb
89
+ ) returns boolean language plpgsql as $$
90
+ begin
91
+ if apply_next then
92
+ update board_positions set log_index = apply_index
93
+ where consumer = apply_consumer and log_index = apply_index - 1;
94
+ else
95
+ insert into board_positions (consumer, log_index) values (apply_consumer, apply_index)
96
+ on conflict (consumer) do update set log_index = excluded.log_index
97
+ where board_positions.log_index < excluded.log_index;
98
+ end if;
99
+ if not found then
100
+ return false;
101
+ end if;
102
+ if apply_message is not null then
103
+ if (apply_message->>'created')::boolean then
104
+ insert into board_messages
105
+ (id, event_id, channel, re, by_actor, by_principal, by_profile, from_key, no_sync, text_lower, deleted, created_at, data)
106
+ values (
107
+ (apply_message->>'id')::bigint, apply_message->>'event_id', apply_message->>'channel', (apply_message->>'re')::bigint,
108
+ apply_message->>'by_actor', apply_message->>'by_principal', apply_message->>'by_profile', apply_message->>'from_key',
109
+ (apply_message->>'no_sync')::boolean, apply_message->>'text_lower', (apply_message->>'deleted')::boolean,
110
+ (apply_message->>'created_at')::bigint, apply_message->>'data');
111
+ else
112
+ update board_messages
113
+ set text_lower = apply_message->>'text_lower', deleted = (apply_message->>'deleted')::boolean, data = apply_message->>'data'
114
+ where id = (apply_message->>'id')::bigint;
115
+ end if;
116
+ insert into board_versions (log_index, message_id, data)
117
+ values (apply_index, (apply_message->>'id')::bigint, apply_message->>'data');
118
+ if apply_terms is not null then
119
+ delete from board_terms where message_id = (apply_message->>'id')::bigint;
120
+ insert into board_terms (message_id, term, value)
121
+ select (apply_message->>'id')::bigint, term->>0, term->>1 from jsonb_array_elements(apply_terms) as term;
122
+ end if;
123
+ end if;
124
+ if apply_summary is not null then
125
+ update board_messages set replies = (apply_summary->>'replies')::int, at = (apply_summary->>'at')::bigint
126
+ where id = (apply_summary->>'root')::bigint;
127
+ end if;
128
+ if apply_sync is not null then
129
+ if jsonb_typeof(apply_sync->'thread') = 'object' then
130
+ insert into board_sync_threads (thread, data) values (apply_sync->'thread'->>'key', apply_sync->'thread'->>'data')
131
+ on conflict (thread) do update set data = excluded.data;
132
+ end if;
133
+ insert into board_external_threads (external, thread)
134
+ select entry->>0, entry->>1 from jsonb_array_elements(apply_sync->'external_threads') as entry
135
+ on conflict (external) do update set thread = excluded.thread;
136
+ insert into board_copies (message_id, target, data)
137
+ select (entry->>0)::bigint, entry->>1, entry->>2 from jsonb_array_elements(apply_sync->'copies') as entry
138
+ on conflict (message_id, target) do update set data = excluded.data;
139
+ insert into board_external_messages (key, message_id)
140
+ select entry->>0, (entry->>1)::bigint from jsonb_array_elements(apply_sync->'external_messages') as entry
141
+ on conflict (key) do update set message_id = excluded.message_id;
142
+ end if;
143
+ return true;
144
+ end
145
+ $$;
@@ -0,0 +1,24 @@
1
+ -- Notification triggers for experimental-a2/store-postgres, needed only with
2
+ -- `listenConnectionString`. Apply after schema.sql. They wake live streams
3
+ -- for every write to A2's event and presence tables, including writes from
4
+ -- stores without the option. Safe to re-run.
5
+
6
+ create or replace function a2_notify_events() returns trigger language plpgsql as $$
7
+ begin
8
+ perform pg_notify('a2_events_' || md5(new.session_id), '');
9
+ return null;
10
+ end $$;
11
+ create or replace function a2_notify_presence() returns trigger language plpgsql as $$
12
+ begin
13
+ perform pg_notify('a2_presence_' || md5(case when TG_OP = 'DELETE' then old.ns else new.ns end),
14
+ coalesce(current_setting('a2.presence_source', true), ''));
15
+ return null;
16
+ end $$;
17
+ do $$ begin
18
+ if not exists (select 1 from pg_trigger where tgname = 'a2_notify_events' and tgrelid = 'a2_events'::regclass) then
19
+ create trigger a2_notify_events after insert on a2_events for each row execute function a2_notify_events();
20
+ end if;
21
+ if not exists (select 1 from pg_trigger where tgname = 'a2_notify_presence' and tgrelid = 'a2_presence'::regclass) then
22
+ create trigger a2_notify_presence after insert or update or delete on a2_presence for each row execute function a2_notify_presence();
23
+ end if;
24
+ end $$;