@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
@@ -0,0 +1,175 @@
1
+ import { m as SyncHandler, p as SyncContext, t as EventMapping, u as RenderInput } from "./provider-BGjz-mDa.mjs";
2
+ import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-XCnQlxq6.mjs";
3
+ import { z } from "zod";
4
+ import { Adapter } from "chat";
5
+ //#region src/sync/kapso.d.ts
6
+ export declare const WhatsAppEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
7
+ channel: z.ZodString;
8
+ thread: z.ZodString;
9
+ subthread: z.ZodNullable<z.ZodString>;
10
+ kind: z.ZodLiteral<"message">;
11
+ message: z.ZodString;
12
+ isRoot: z.ZodBoolean;
13
+ text: z.ZodString;
14
+ context: z.ZodNullable<z.ZodString>;
15
+ author: z.ZodObject<{
16
+ id: z.ZodString;
17
+ handle: z.ZodString;
18
+ name: z.ZodString;
19
+ avatar: z.ZodNullable<z.ZodString>;
20
+ isBot: z.ZodBoolean;
21
+ }, z.core.$strip>;
22
+ files: z.ZodOptional<z.ZodArray<z.ZodObject<{
23
+ type: z.ZodEnum<{
24
+ audio: "audio";
25
+ file: "file";
26
+ image: "image";
27
+ video: "video";
28
+ }>;
29
+ name: z.ZodOptional<z.ZodString>;
30
+ mimeType: z.ZodOptional<z.ZodString>;
31
+ size: z.ZodOptional<z.ZodNumber>;
32
+ url: z.ZodOptional<z.ZodString>;
33
+ fetchMetadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
34
+ }, z.core.$strip>>>;
35
+ links: z.ZodOptional<z.ZodArray<z.ZodObject<{
36
+ url: z.ZodString;
37
+ thread: z.ZodString;
38
+ message: z.ZodString;
39
+ snapshot: z.ZodNullable<z.ZodObject<{
40
+ author: z.ZodString;
41
+ text: z.ZodString;
42
+ createdAt: z.ZodNullable<z.ZodString>;
43
+ files: z.ZodArray<z.ZodObject<{
44
+ name: z.ZodString;
45
+ url: z.ZodNullable<z.ZodString>;
46
+ }, z.core.$strip>>;
47
+ }, z.core.$strip>>;
48
+ }, z.core.$strip>>>;
49
+ id: z.ZodString;
50
+ key: z.ZodString;
51
+ raw: z.ZodUnknown;
52
+ platform: z.ZodLiteral<"whatsapp">;
53
+ type: z.ZodLiteral<"message">;
54
+ }, z.core.$strip>, z.ZodObject<{
55
+ channel: z.ZodString;
56
+ thread: z.ZodString;
57
+ subthread: z.ZodNullable<z.ZodString>;
58
+ kind: z.ZodLiteral<"edited">;
59
+ message: z.ZodString;
60
+ text: z.ZodString;
61
+ author: z.ZodObject<{
62
+ id: z.ZodString;
63
+ handle: z.ZodString;
64
+ name: z.ZodString;
65
+ avatar: z.ZodNullable<z.ZodString>;
66
+ isBot: z.ZodBoolean;
67
+ }, z.core.$strip>;
68
+ links: z.ZodOptional<z.ZodArray<z.ZodObject<{
69
+ url: z.ZodString;
70
+ thread: z.ZodString;
71
+ message: z.ZodString;
72
+ snapshot: z.ZodNullable<z.ZodObject<{
73
+ author: z.ZodString;
74
+ text: z.ZodString;
75
+ createdAt: z.ZodNullable<z.ZodString>;
76
+ files: z.ZodArray<z.ZodObject<{
77
+ name: z.ZodString;
78
+ url: z.ZodNullable<z.ZodString>;
79
+ }, z.core.$strip>>;
80
+ }, z.core.$strip>>;
81
+ }, z.core.$strip>>>;
82
+ linksOnly: z.ZodOptional<z.ZodBoolean>;
83
+ id: z.ZodString;
84
+ key: z.ZodString;
85
+ raw: z.ZodUnknown;
86
+ platform: z.ZodLiteral<"whatsapp">;
87
+ type: z.ZodLiteral<"message.edited">;
88
+ }, z.core.$strip>, z.ZodObject<{
89
+ channel: z.ZodString;
90
+ thread: z.ZodString;
91
+ subthread: z.ZodNullable<z.ZodString>;
92
+ kind: z.ZodLiteral<"deleted">;
93
+ message: z.ZodString;
94
+ id: z.ZodString;
95
+ key: z.ZodString;
96
+ raw: z.ZodUnknown;
97
+ platform: z.ZodLiteral<"whatsapp">;
98
+ type: z.ZodLiteral<"message.deleted">;
99
+ }, z.core.$strip>, z.ZodObject<{
100
+ channel: z.ZodString;
101
+ thread: z.ZodString;
102
+ subthread: z.ZodNullable<z.ZodString>;
103
+ kind: z.ZodLiteral<"reaction">;
104
+ message: z.ZodString;
105
+ emoji: z.ZodString;
106
+ added: z.ZodBoolean;
107
+ author: z.ZodObject<{
108
+ id: z.ZodString;
109
+ handle: z.ZodString;
110
+ name: z.ZodString;
111
+ avatar: z.ZodNullable<z.ZodString>;
112
+ isBot: z.ZodBoolean;
113
+ }, z.core.$strip>;
114
+ id: z.ZodString;
115
+ key: z.ZodString;
116
+ raw: z.ZodUnknown;
117
+ platform: z.ZodLiteral<"whatsapp">;
118
+ type: z.ZodEnum<{
119
+ "reaction.added": "reaction.added";
120
+ "reaction.removed": "reaction.removed";
121
+ }>;
122
+ }, z.core.$strip>, z.ZodObject<{
123
+ channel: z.ZodString;
124
+ thread: z.ZodString;
125
+ subthread: z.ZodNullable<z.ZodString>;
126
+ kind: z.ZodLiteral<"lifecycle">;
127
+ type: z.ZodString;
128
+ title: z.ZodString;
129
+ url: z.ZodNullable<z.ZodString>;
130
+ labels: z.ZodRecord<z.ZodString, z.ZodString>;
131
+ unset: z.ZodArray<z.ZodString>;
132
+ owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
133
+ reply: z.ZodNullable<z.ZodString>;
134
+ createRoot: z.ZodBoolean;
135
+ author: z.ZodObject<{
136
+ id: z.ZodString;
137
+ handle: z.ZodString;
138
+ name: z.ZodString;
139
+ avatar: z.ZodNullable<z.ZodString>;
140
+ isBot: z.ZodBoolean;
141
+ }, z.core.$strip>;
142
+ id: z.ZodString;
143
+ key: z.ZodString;
144
+ raw: z.ZodUnknown;
145
+ platform: z.ZodLiteral<"whatsapp">;
146
+ }, z.core.$strip>], "kind">;
147
+ export type WhatsAppEvent = z.infer<typeof WhatsAppEvent>;
148
+ type MarkRead = (input: {
149
+ phoneNumberId: string;
150
+ messageId: string;
151
+ typingIndicator: {
152
+ type: 'text';
153
+ };
154
+ }) => Promise<unknown>;
155
+ export type KapsoHandler = SyncHandler<WhatsAppEvent>;
156
+ export type KapsoOptions = {
157
+ adapter: Adapter;
158
+ render?: (input: RenderInput) => string;
159
+ markRead: MarkRead;
160
+ numbers: Record<string, EventMapping<WhatsAppEvent>>;
161
+ };
162
+ /**
163
+ * Syncs WhatsApp numbers on Kapso with board channels. Keys are phone number
164
+ * IDs (`'16315558151'`); values are a board channel (a two-way mirror) or a
165
+ * callback that handles every incoming event. Each Kapso conversation is a
166
+ * thread. WhatsApp has no threads in a number, so a board thread never starts
167
+ * one: a board root in a mirrored channel stays on the board.
168
+ */
169
+ export declare function kapso(options: KapsoOptions): KapsoProvider;
170
+ export declare class KapsoProvider extends ChatSyncProvider<WhatsAppEvent> {
171
+ constructor(options: KapsoOptions);
172
+ eventId(key: string, input: ChatInput): string;
173
+ event(context: Pick<SyncContext, 'id' | 'key' | 'event' | 'raw'>): WhatsAppEvent;
174
+ }
175
+ //#endregion
@@ -0,0 +1,86 @@
1
+ import { c as eventSchema, s as envelope } from "./provider-CuewcDNZ.mjs";
2
+ import { r as markdownOf, t as ChatSyncProvider } from "./chat-provider-jFSeyNmB.mjs";
3
+ import { z } from "zod";
4
+ //#region src/sync/kapso.ts
5
+ const decode = (id) => id.split(":").map((part) => Buffer.from(part, "base64url").toString("utf8")).join(":");
6
+ const encode = (id) => id.split(":").map((part) => Buffer.from(part, "utf8").toString("base64url")).join(":");
7
+ const WhatsAppEvent = eventSchema("whatsapp", "message");
8
+ /**
9
+ * Syncs WhatsApp numbers on Kapso with board channels. Keys are phone number
10
+ * IDs (`'16315558151'`); values are a board channel (a two-way mirror) or a
11
+ * callback that handles every incoming event. Each Kapso conversation is a
12
+ * thread. WhatsApp has no threads in a number, so a board thread never starts
13
+ * one: a board root in a mirrored channel stays on the board.
14
+ */
15
+ function kapso(options) {
16
+ return new KapsoProvider(options);
17
+ }
18
+ var KapsoProvider = class extends ChatSyncProvider {
19
+ constructor(options) {
20
+ if (typeof options.markRead !== "function") throw new Error("kapso requires a public markRead operation for cross-instance read and typing");
21
+ const fileIds = (raw) => (raw?.responses ?? []).flatMap((response) => response.messages?.[0]?.id ?? []);
22
+ super({
23
+ fileIds,
24
+ render: options.render,
25
+ platform: "whatsapp",
26
+ adapter: options.adapter,
27
+ canStartThreads: false,
28
+ async uploadFiles(thread, files) {
29
+ const sent = await options.adapter.postMessage(thread, {
30
+ markdown: "",
31
+ files
32
+ });
33
+ return {
34
+ message: sent.id,
35
+ files: fileIds(sent.raw)
36
+ };
37
+ },
38
+ refusesFiles: (error) => error?.code === "VALIDATION_ERROR",
39
+ async resolveChannel(key) {
40
+ if (!/^\d+$/.test(key)) throw new Error(`${key} isn't a phone number ID; use the number's ID from Kapso, not the number`);
41
+ return key;
42
+ },
43
+ fromChatId: decode,
44
+ toChatId: encode,
45
+ singleReaction: true,
46
+ async startTyping(thread, latest) {
47
+ if (!latest) return options.adapter.startTyping(thread);
48
+ const [phoneNumberId] = decode(thread.slice(thread.indexOf(":") + 1)).split(":");
49
+ await options.markRead({
50
+ phoneNumberId,
51
+ messageId: latest,
52
+ typingIndicator: { type: "text" }
53
+ });
54
+ },
55
+ groupThread: (thread) => thread,
56
+ isRoot: () => false,
57
+ context: () => null,
58
+ markdown(message) {
59
+ const text = markdownOf(message);
60
+ const transcript = message.raw?.kapso?.transcript?.text;
61
+ return [text, typeof transcript === "string" && transcript.trim() && transcript !== text ? `> ${transcript.trim()}` : null].filter(Boolean).join("\n\n");
62
+ },
63
+ async resolveTarget(target) {
64
+ const parts = target.split(":");
65
+ if (!/^\d+$/.test(parts[0]) || parts.length !== 1 && parts.length !== 3) throw new Error(`invalid Kapso target: ${target}`);
66
+ return {
67
+ target,
68
+ channel: parts[0],
69
+ kind: parts.length === 1 ? "channel" : "thread"
70
+ };
71
+ }
72
+ });
73
+ for (const [key, value] of Object.entries(options.numbers)) this.map(key, value);
74
+ }
75
+ eventId(key, input) {
76
+ if (input.kind !== "reaction") return super.eventId(key, input);
77
+ const reaction = input.reaction;
78
+ const stamp = z.looseObject({ id: z.string().min(1) }).parse(reaction.raw).id;
79
+ return `reaction:${key}:${this.toNative(reaction.threadId)}|${reaction.messageId}|${reaction.rawEmoji}|${reaction.user.userId}|${reaction.added}|${stamp}`;
80
+ }
81
+ event(context) {
82
+ return WhatsAppEvent.parse(envelope(this.platform, context.key, context.event, context.raw, context.id));
83
+ }
84
+ };
85
+ //#endregion
86
+ export { KapsoProvider, WhatsAppEvent, kapso };
@@ -0,0 +1,364 @@
1
+ import { v as ExternalLink } from "./reducers-B_vUGQRp.mjs";
2
+ import { d as ResolvedTarget, g as UserTokens, i as ProviderDelivery, m as SyncHandler, p as SyncContext, s as ProviderPost, t as EventMapping, u as RenderInput, v as withUserTokens } from "./provider-BGjz-mDa.mjs";
3
+ import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-XCnQlxq6.mjs";
4
+ import { z } from "zod";
5
+ import { Adapter } from "chat";
6
+ //#region src/sync/slack.d.ts
7
+ type SlackChannel = {
8
+ id?: string;
9
+ name?: string;
10
+ is_member?: boolean;
11
+ is_private?: boolean;
12
+ is_im?: boolean;
13
+ is_mpim?: boolean;
14
+ is_ext_shared?: boolean;
15
+ };
16
+ export type SlackClient = {
17
+ conversations: {
18
+ list(args: Record<string, unknown>): Promise<{
19
+ channels?: SlackChannel[];
20
+ response_metadata?: {
21
+ next_cursor?: string;
22
+ };
23
+ }>;
24
+ info(args: {
25
+ channel: string;
26
+ }): Promise<{
27
+ channel?: SlackChannel;
28
+ }>;
29
+ join(args: {
30
+ channel: string;
31
+ }): Promise<unknown>;
32
+ /** Reads a linked message or a thread; needs `channels:history` (`groups:history` for private channels). */
33
+ replies?(args: {
34
+ channel: string;
35
+ ts: string;
36
+ oldest?: string;
37
+ latest?: string;
38
+ inclusive?: boolean;
39
+ limit: number;
40
+ }): Promise<{
41
+ messages?: SlackMessage[];
42
+ has_more?: boolean;
43
+ }>;
44
+ /** Reads a channel, newest first, for `vb sources <key> read`; needs `channels:history`. */
45
+ history?(args: {
46
+ channel: string;
47
+ limit: number;
48
+ }): Promise<{
49
+ messages?: SlackMessage[];
50
+ has_more?: boolean;
51
+ }>;
52
+ };
53
+ users?: {
54
+ info(args: {
55
+ user: string;
56
+ }): Promise<{
57
+ user?: SlackUser;
58
+ }>;
59
+ lookupByEmail?(args: {
60
+ email: string;
61
+ }): Promise<{
62
+ user?: SlackUser;
63
+ }>;
64
+ };
65
+ files?: {
66
+ delete(args: {
67
+ file: string;
68
+ }): Promise<unknown>;
69
+ };
70
+ /** Posts an agent's message under its own name; needs `chat:write.customize` for `username` and `icon_url`. */
71
+ chat?: {
72
+ postMessage(args: SlackPost): Promise<{
73
+ ts?: string;
74
+ }>;
75
+ /** A message's link, with the workspace's own host and a reply's `thread_ts`. */
76
+ getPermalink?(args: {
77
+ channel: string;
78
+ message_ts: string;
79
+ }): Promise<{
80
+ permalink?: string;
81
+ }>;
82
+ };
83
+ /** Says which scopes the app has (`response_metadata.scopes`, from Slack's `x-oauth-scopes`). */
84
+ /** Also whose a token is (`user_id`), for a person's own. */
85
+ auth?: {
86
+ test(args?: Record<string, unknown>): Promise<{
87
+ user_id?: string;
88
+ user?: string;
89
+ response_metadata?: {
90
+ scopes?: string[];
91
+ };
92
+ }>;
93
+ };
94
+ };
95
+ type SlackPost = {
96
+ channel: string;
97
+ thread_ts?: string;
98
+ text?: string;
99
+ markdown_text?: string;
100
+ username?: string;
101
+ icon_url?: string;
102
+ unfurl_links?: boolean;
103
+ unfurl_media?: boolean;
104
+ };
105
+ /** The `**name**: ` a message's text opens with, taken out when Slack shows the name as the sender. */
106
+ export declare function withoutLabel(markdown: string, name: string): string;
107
+ /** GitHub's markdown allows inline HTML, which Slack shows as raw tags: as markdown instead, outside code. */
108
+ export declare function withoutHtml(markdown: string): string;
109
+ /**
110
+ * A sender's picture as Slack's `icon_url`: an https image. The board's built-in agent
111
+ * avatars are SVGs, which Slack won't show, so those keep the app's icon.
112
+ */
113
+ export declare function slackIcon(avatar: string | null): string | null;
114
+ type SlackUser = {
115
+ id?: string;
116
+ name?: string;
117
+ real_name?: string;
118
+ is_bot?: boolean;
119
+ profile?: {
120
+ display_name?: string;
121
+ real_name?: string;
122
+ image_72?: string;
123
+ image_48?: string;
124
+ };
125
+ };
126
+ type SlackFile = {
127
+ name?: string;
128
+ title?: string;
129
+ permalink?: string;
130
+ };
131
+ type SlackMessage = {
132
+ ts?: string;
133
+ text?: string;
134
+ user?: string;
135
+ username?: string;
136
+ bot_profile?: {
137
+ name?: string;
138
+ };
139
+ files?: SlackFile[];
140
+ thread_ts?: string;
141
+ reply_count?: number;
142
+ };
143
+ /** What Slack attaches to a message that links another: `is_msg_unfurl` marks a message link's. */
144
+ type SlackAttachment = {
145
+ is_msg_unfurl?: boolean;
146
+ /** A forward's shared message. */
147
+ is_share?: boolean;
148
+ from_url?: string;
149
+ original_url?: string;
150
+ channel_id?: string;
151
+ ts?: string;
152
+ author_id?: string;
153
+ author_name?: string;
154
+ author_subname?: string;
155
+ text?: string;
156
+ files?: SlackFile[];
157
+ };
158
+ /**
159
+ * Every Slack message a message's mrkdwn links to, in order, with the unfurls Slack attached for them,
160
+ * then the messages it forwards: a forward's shared message is only in its `is_share` attachments.
161
+ */
162
+ export declare function slackLinks(key: string, text: string, attachments?: SlackAttachment[], markdown?: (mrkdwn: string) => string): ExternalLink[];
163
+ /**
164
+ * What a forward with no text of its own says: the messages it shares, quoted,
165
+ * so the board (and whoever watches it) reads what was forwarded, not "(no text)".
166
+ */
167
+ export declare function forwardText(links: ExternalLink[]): string;
168
+ /**
169
+ * The name a file goes to Slack under. Slack picks a file's type from its
170
+ * extension, so a text file named `run.log` arrives as a binary download;
171
+ * `run.log.txt` arrives as text it previews. The board keeps the file's own name.
172
+ */
173
+ export declare function slackFileName(filename: string, mimeType?: string): string;
174
+ export declare const SlackEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
175
+ channel: z.ZodString;
176
+ thread: z.ZodString;
177
+ subthread: z.ZodNullable<z.ZodString>;
178
+ kind: z.ZodLiteral<"message">;
179
+ message: z.ZodString;
180
+ isRoot: z.ZodBoolean;
181
+ text: z.ZodString;
182
+ context: z.ZodNullable<z.ZodString>;
183
+ author: z.ZodObject<{
184
+ id: z.ZodString;
185
+ handle: z.ZodString;
186
+ name: z.ZodString;
187
+ avatar: z.ZodNullable<z.ZodString>;
188
+ isBot: z.ZodBoolean;
189
+ }, z.core.$strip>;
190
+ files: z.ZodOptional<z.ZodArray<z.ZodObject<{
191
+ type: z.ZodEnum<{
192
+ audio: "audio";
193
+ file: "file";
194
+ image: "image";
195
+ video: "video";
196
+ }>;
197
+ name: z.ZodOptional<z.ZodString>;
198
+ mimeType: z.ZodOptional<z.ZodString>;
199
+ size: z.ZodOptional<z.ZodNumber>;
200
+ url: z.ZodOptional<z.ZodString>;
201
+ fetchMetadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
202
+ }, z.core.$strip>>>;
203
+ links: z.ZodOptional<z.ZodArray<z.ZodObject<{
204
+ url: z.ZodString;
205
+ thread: z.ZodString;
206
+ message: z.ZodString;
207
+ snapshot: z.ZodNullable<z.ZodObject<{
208
+ author: z.ZodString;
209
+ text: z.ZodString;
210
+ createdAt: z.ZodNullable<z.ZodString>;
211
+ files: z.ZodArray<z.ZodObject<{
212
+ name: z.ZodString;
213
+ url: z.ZodNullable<z.ZodString>;
214
+ }, z.core.$strip>>;
215
+ }, z.core.$strip>>;
216
+ }, z.core.$strip>>>;
217
+ id: z.ZodString;
218
+ key: z.ZodString;
219
+ raw: z.ZodUnknown;
220
+ platform: z.ZodLiteral<"slack">;
221
+ type: z.ZodLiteral<"message">;
222
+ }, z.core.$strip>, z.ZodObject<{
223
+ channel: z.ZodString;
224
+ thread: z.ZodString;
225
+ subthread: z.ZodNullable<z.ZodString>;
226
+ kind: z.ZodLiteral<"edited">;
227
+ message: z.ZodString;
228
+ text: z.ZodString;
229
+ author: z.ZodObject<{
230
+ id: z.ZodString;
231
+ handle: z.ZodString;
232
+ name: z.ZodString;
233
+ avatar: z.ZodNullable<z.ZodString>;
234
+ isBot: z.ZodBoolean;
235
+ }, z.core.$strip>;
236
+ links: z.ZodOptional<z.ZodArray<z.ZodObject<{
237
+ url: z.ZodString;
238
+ thread: z.ZodString;
239
+ message: z.ZodString;
240
+ snapshot: z.ZodNullable<z.ZodObject<{
241
+ author: z.ZodString;
242
+ text: z.ZodString;
243
+ createdAt: z.ZodNullable<z.ZodString>;
244
+ files: z.ZodArray<z.ZodObject<{
245
+ name: z.ZodString;
246
+ url: z.ZodNullable<z.ZodString>;
247
+ }, z.core.$strip>>;
248
+ }, z.core.$strip>>;
249
+ }, z.core.$strip>>>;
250
+ linksOnly: z.ZodOptional<z.ZodBoolean>;
251
+ id: z.ZodString;
252
+ key: z.ZodString;
253
+ raw: z.ZodUnknown;
254
+ platform: z.ZodLiteral<"slack">;
255
+ type: z.ZodLiteral<"message.edited">;
256
+ }, z.core.$strip>, z.ZodObject<{
257
+ channel: z.ZodString;
258
+ thread: z.ZodString;
259
+ subthread: z.ZodNullable<z.ZodString>;
260
+ kind: z.ZodLiteral<"deleted">;
261
+ message: z.ZodString;
262
+ id: z.ZodString;
263
+ key: z.ZodString;
264
+ raw: z.ZodUnknown;
265
+ platform: z.ZodLiteral<"slack">;
266
+ type: z.ZodLiteral<"message.deleted">;
267
+ }, z.core.$strip>, z.ZodObject<{
268
+ channel: z.ZodString;
269
+ thread: z.ZodString;
270
+ subthread: z.ZodNullable<z.ZodString>;
271
+ kind: z.ZodLiteral<"reaction">;
272
+ message: z.ZodString;
273
+ emoji: z.ZodString;
274
+ added: z.ZodBoolean;
275
+ author: z.ZodObject<{
276
+ id: z.ZodString;
277
+ handle: z.ZodString;
278
+ name: z.ZodString;
279
+ avatar: z.ZodNullable<z.ZodString>;
280
+ isBot: z.ZodBoolean;
281
+ }, z.core.$strip>;
282
+ id: z.ZodString;
283
+ key: z.ZodString;
284
+ raw: z.ZodUnknown;
285
+ platform: z.ZodLiteral<"slack">;
286
+ type: z.ZodEnum<{
287
+ "reaction.added": "reaction.added";
288
+ "reaction.removed": "reaction.removed";
289
+ }>;
290
+ }, z.core.$strip>, z.ZodObject<{
291
+ channel: z.ZodString;
292
+ thread: z.ZodString;
293
+ subthread: z.ZodNullable<z.ZodString>;
294
+ kind: z.ZodLiteral<"lifecycle">;
295
+ type: z.ZodString;
296
+ title: z.ZodString;
297
+ url: z.ZodNullable<z.ZodString>;
298
+ labels: z.ZodRecord<z.ZodString, z.ZodString>;
299
+ unset: z.ZodArray<z.ZodString>;
300
+ owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
301
+ reply: z.ZodNullable<z.ZodString>;
302
+ createRoot: z.ZodBoolean;
303
+ author: z.ZodObject<{
304
+ id: z.ZodString;
305
+ handle: z.ZodString;
306
+ name: z.ZodString;
307
+ avatar: z.ZodNullable<z.ZodString>;
308
+ isBot: z.ZodBoolean;
309
+ }, z.core.$strip>;
310
+ id: z.ZodString;
311
+ key: z.ZodString;
312
+ raw: z.ZodUnknown;
313
+ platform: z.ZodLiteral<"slack">;
314
+ }, z.core.$strip>], "kind">;
315
+ export type SlackEvent = z.infer<typeof SlackEvent>;
316
+ export type SlackHandler = SyncHandler<SlackEvent>;
317
+ export type SlackOptions = {
318
+ /**
319
+ * A Vercel Connect connector (`'slack/acme'`): board builds the Slack adapter,
320
+ * its Web API client, and people's sign-in, so messages they write post as them.
321
+ * Or your own Chat SDK adapter, wrapped in `withUserTokens` to post as people.
322
+ */
323
+ adapter: Adapter | string;
324
+ render?: (input: RenderInput) => string;
325
+ /** Not needed with a connector. */
326
+ client?: () => Promise<SlackClient>;
327
+ channels: Record<string, EventMapping<SlackEvent>>;
328
+ };
329
+ /**
330
+ * Syncs Slack channels with board channels. Keys are channels by name
331
+ * (`'#prs'`) or ID (`'C0123ABC'`); values are a board channel (a two-way
332
+ * mirror) or a callback that handles every incoming event. The app joins public
333
+ * channels it isn't in; private ones need an invite.
334
+ */
335
+ export declare function slack(options: SlackOptions): SlackProvider;
336
+ export declare class SlackProvider extends ChatSyncProvider<SlackEvent> {
337
+ private readonly web;
338
+ private customize;
339
+ constructor(given: SlackOptions);
340
+ /**
341
+ * An agent's message goes out under its own name (`clever-lemur via vboard-factory`), and its
342
+ * picture when it has one Slack can show, instead of the app's, with the text's
343
+ * `**name**: ` label dropped. Without `chat:write.customize` it posts as the app, label and all.
344
+ */
345
+ post(target: string, kind: ResolvedTarget['kind'], body: ProviderPost): Promise<ProviderDelivery>;
346
+ /** An edit keeps the label out only where the message went out under the agent's name. */
347
+ edit(thread: string, message: string, body: ProviderPost): Promise<void>;
348
+ private postNamed;
349
+ /** Whether the app may set a message's username and icon (`chat:write.customize`), asked once. */
350
+ private canCustomize;
351
+ /** Whether a message Slack has went out under `name`. */
352
+ private sentAs;
353
+ /**
354
+ * Slack's link to the event's message, from `chat.getPermalink`, so it has the workspace's
355
+ * own host (Enterprise Grid included) and a reply's `thread_ts`. Null for an event without
356
+ * one message to link (a lifecycle event, or a deleted message Slack no longer has); throws
357
+ * when Slack won't say. It reads only the URL: nothing is synced or joined.
358
+ */
359
+ permalink(event: SlackEvent): Promise<string | null>;
360
+ eventId(key: string, input: ChatInput): string;
361
+ event(context: Pick<SyncContext, 'id' | 'key' | 'event' | 'raw'>): SlackEvent;
362
+ }
363
+ //#endregion
364
+ export { type UserTokens, withUserTokens };