@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.
- package/README.md +27 -27
- package/dist/{a2-C41hD8SF.mjs → a2-Bck5x1Kh.mjs} +969 -25
- package/dist/access.d.mts +1 -1
- package/dist/access.mjs +3 -3
- package/dist/{actors-DjMeZpnU.mjs → actors-BOamkEuz.mjs} +3 -73
- package/dist/attempts-CLG840Oj.mjs +20 -0
- package/dist/{auth-COzc09sn.mjs → auth-Drg9FiC2.mjs} +225 -2
- package/dist/backend-B-SJ7p6p.d.mts +680 -0
- package/dist/backend-a2/contract.d.mts +873 -2
- package/dist/backend-a2/contract.mjs +2 -2
- package/dist/backend-a2/scheduler-local.d.mts +1 -1
- package/dist/backend-a2/scheduler-local.mjs +1 -1
- package/dist/backend-a2/scheduler-qstash.d.mts +78 -1
- package/dist/backend-a2/scheduler-qstash.mjs +521 -1
- package/dist/backend-a2/scheduler-vercel.d.mts +37 -1
- package/dist/backend-a2/scheduler-vercel.mjs +203 -1
- package/dist/backend-a2/store-memory.d.mts +2 -2
- package/dist/backend-a2/store-memory.mjs +3 -3
- package/dist/backend-a2/store-postgres.d.mts +1 -1
- package/dist/backend-a2/store-postgres.mjs +2850 -2
- package/dist/backend-a2/store-redis-http.d.mts +1 -1
- package/dist/backend-a2/store-redis-http.mjs +490 -2
- package/dist/backend-a2/store-redis.d.mts +10 -2
- package/dist/backend-a2/store-redis.mjs +51 -2
- package/dist/backend-a2/store-sqlite.d.mts +1 -1
- package/dist/backend-a2/store-sqlite.mjs +3 -3
- package/dist/backend-a2.d.mts +2706 -3
- package/dist/backend-a2.mjs +1 -1
- package/dist/{backend-http-Bid7RIpC.d.mts → backend-http-7cNb8nJI.d.mts} +10 -3
- package/dist/{backend-http-0roEmjl0.mjs → backend-http-C5I7Wfdw.mjs} +2 -2
- package/dist/{backend-http-BVRno-ca.mjs → backend-http-CuUIACCs.mjs} +32 -3
- 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/{chat-provider-XCnQlxq6.d.mts → chat-provider-DNJQyajS.d.mts} +16 -4
- package/dist/{chat-provider-jFSeyNmB.mjs → chat-provider-YHy-WbrB.mjs} +15 -9
- package/dist/cli.mjs +30 -10
- package/dist/{client-DGDPaN7U.mjs → client-BA-J7usH.mjs} +10 -2
- package/dist/{conformance-DRR23YNy.mjs → conformance-CT5EeHeC.mjs} +5 -2
- package/dist/conformance.d.mts +1 -1
- package/dist/conformance.mjs +1 -1
- package/dist/{engine-Bir5s8ts.mjs → engine-D0oBUBEK.mjs} +249 -163
- package/dist/events-CewD4kw7.mjs +75 -0
- package/dist/{exports-Dvc1o52I.mjs → exports-DOdA7KhF.mjs} +35 -32
- package/dist/exports-ZsgjzEnM.d.mts +4 -0
- package/dist/external-BV_cUncs.mjs +151 -0
- package/dist/folds-CRYY14kc.d.mts +534 -0
- package/dist/{reducers-mUPFuFJV.mjs → folds-Dyjput8M.mjs} +6 -73
- package/dist/ids-C6AYo1bu.mjs +31 -0
- package/dist/index.d.mts +4 -4
- package/dist/{index.default-Bkg77Pxn.mjs → index.default-n4qKN7EL.mjs} +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.node.d.mts +4 -4
- package/dist/index.node.mjs +3 -3
- package/dist/inspect/app.js +31 -31
- package/dist/inspect/engine.js +5 -5
- package/dist/internal-CvsrprnU-CRY89I-b.mjs +203 -0
- package/dist/{local-Cr_dSjvs.mjs → local-DhkrAqPP.mjs} +1 -1
- package/dist/mentions-CB6ShY4R.mjs +72 -0
- package/dist/{targets-yM5JBUgr.mjs → middleware-CqaCwucP.mjs} +1 -33
- package/dist/platform-B4TnJtWu-CwcTyKg2.mjs +32 -0
- package/dist/{project-CFiArraX.mjs → project-DMDST9kl.mjs} +1 -1
- package/dist/{provider-BGjz-mDa.d.mts → provider-B0b9Qxw4.d.mts} +170 -40
- package/dist/provider-B3DpYSDq.mjs +220 -0
- package/dist/redis-tables-DN9PfIDi.mjs +3897 -0
- package/dist/reducer-CYPHsSmd-BQIfozGi.d.mts +170 -0
- package/dist/reducer-CjmvZSAb-D_OSISmj.mjs +74 -0
- package/dist/{contract-CuJmlrhw.mjs → reducers-BFmIXilu.mjs} +260 -287
- package/dist/retryable-lazy-DZWmHpii-Bye-W8q7.mjs +19 -0
- package/dist/scheduler-task-X1SToDjP-BVoWuInI.mjs +69 -0
- package/dist/{serve-BsOOc-6_.mjs → serve-CNYvA4pT.mjs} +5 -5
- package/dist/server-DtFrWxi3-Boa6gdWO.mjs +3602 -0
- package/dist/server-qgez0Xny-D5mLfqFQ.d.mts +385 -0
- package/dist/{server-jwPY7_wi.mjs → server-snYFkITb.mjs} +4 -4
- package/dist/{serving-BNbzc96L.mjs → serving-CNkgUPW1.mjs} +1 -1
- package/dist/session-clear-wHd5GCpZ-BnKSxReK.mjs +51 -0
- package/dist/{sql-DbiEnqM0.mjs → sql-U9WTxrwJ.mjs} +2 -2
- package/dist/{sqlite-db-Cbj03vmp.mjs → sqlite-db-Ds4majtT.mjs} +1 -1
- package/dist/store-D0MhBvg6-4Z2L0Kqd.d.mts +530 -0
- package/dist/store-N8PXxDAS-BWBgzBHp.mjs +5 -0
- package/dist/store-codec-DwrWlgQx-CYxGW0aD.mjs +61 -0
- package/dist/store-memory-Bas9Uq5C.mjs +872 -0
- package/dist/store-memory-ZLiZbH3R.mjs +2 -0
- package/dist/store-polling-BZt2Rf3D-BiEM6_HB.mjs +148 -0
- package/dist/store-presence-polling-JuAy2Ck2-CYpuK75X.mjs +109 -0
- package/dist/store-sqlite-BmwL3pUR.mjs +2 -0
- package/dist/store-sqlite-CxxPCcCT.mjs +1053 -0
- package/dist/stream-buffer-DrTyiIuo-BKy-vI14.mjs +53 -0
- package/dist/sync-github.d.mts +24 -17
- package/dist/sync-github.mjs +89 -22
- package/dist/sync-kapso.d.mts +15 -13
- package/dist/sync-kapso.mjs +17 -14
- package/dist/sync-slack.d.mts +12 -17
- package/dist/sync-slack.mjs +54 -42
- package/dist/sync.chat.d.mts +1 -1
- package/dist/sync.chat.mjs +1 -1
- package/dist/sync.d.mts +3 -3
- package/dist/sync.mjs +5 -4
- package/dist/targets-C-wdR5wP.mjs +33 -0
- package/dist/{tokens-DKLn5P9B.mjs → tokens-DhuzKzAl.mjs} +1 -1
- package/dist/{types-BHCjTZdB.d.mts → types-8yq2VnKI.d.mts} +2 -2
- package/dist/{users-Dls7_ANV.mjs → users-yryHKFMo.mjs} +2 -2
- package/dist/{watch-spec-W0c7ypHJ.mjs → watchers-hash-DojIuoFg.mjs} +233 -28
- package/docs/01-board/01-mounting.md +1 -1
- package/docs/02-sync/01-overview.md +69 -47
- package/docs/02-sync/02-functions.md +395 -0
- package/docs/02-sync/03-slack.md +30 -25
- package/docs/02-sync/04-github.md +62 -26
- package/docs/02-sync/05-whatsapp.md +23 -19
- package/docs/02-sync/06-providers.md +58 -26
- package/docs/03-guides/04-triage.md +1 -1
- package/docs/04-reference/01-cli.md +26 -6
- package/docs/04-reference/02-board.md +18 -5
- package/docs/04-reference/03-http.md +5 -2
- package/docs/04-reference/05-conformance.md +1 -1
- package/docs/index.md +5 -10
- package/package.json +22 -6
- package/dist/a2-D24cvwpN.d.mts +0 -3359
- package/dist/access-CJU2-vaa.mjs +0 -226
- package/dist/attempts-Bxp9KgPf.mjs +0 -919
- package/dist/exports-DLiE7fLY.d.mts +0 -4
- package/dist/provider-CuewcDNZ.mjs +0 -205
- package/dist/redis-tables-B35vv4CZ.mjs +0 -842
- package/dist/reducers-B_vUGQRp.d.mts +0 -1172
- package/dist/watchers-hash-CLjsa6od.mjs +0 -225
- package/docs/02-sync/02-callbacks.md +0 -265
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { i as PRESENCE_TIMINGS } from "./internal-CvsrprnU-CRY89I-b.mjs";
|
|
2
|
+
//#region ../../node_modules/.pnpm/experimental-a2@0.22.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__52060f00b21aecfab049c27fa3abd2f9/node_modules/experimental-a2/dist/stream-buffer-DrTyiIuo.js
|
|
3
|
+
const key = ({ participant, field }) => JSON.stringify([participant, field]);
|
|
4
|
+
function presenceTombstones() {
|
|
5
|
+
const stamps = /* @__PURE__ */ new Map();
|
|
6
|
+
const prune = () => {
|
|
7
|
+
const cutoff = Date.now() - PRESENCE_TIMINGS.tombstoneMs;
|
|
8
|
+
for (const [id, stamp] of stamps) {
|
|
9
|
+
if (stamp.keptAtMs > cutoff) return;
|
|
10
|
+
stamps.delete(id);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
outranks(write) {
|
|
15
|
+
if (stamps.size === 0) return false;
|
|
16
|
+
prune();
|
|
17
|
+
const stamp = stamps.get(key(write));
|
|
18
|
+
return stamp !== void 0 && stamp.atMs > write.at.getTime();
|
|
19
|
+
},
|
|
20
|
+
keep(deletion) {
|
|
21
|
+
prune();
|
|
22
|
+
const id = key(deletion);
|
|
23
|
+
stamps.delete(id);
|
|
24
|
+
stamps.set(id, {
|
|
25
|
+
atMs: deletion.at.getTime(),
|
|
26
|
+
keptAtMs: Date.now()
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
drop(field) {
|
|
30
|
+
if (stamps.size > 0) stamps.delete(key(field));
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const isSerializedEvent = (event) => "payloadJson" in event;
|
|
35
|
+
const parseSerializedEvent = (event) => ({
|
|
36
|
+
id: event.id,
|
|
37
|
+
type: event.type,
|
|
38
|
+
payload: JSON.parse(event.payloadJson),
|
|
39
|
+
index: event.index,
|
|
40
|
+
sessionId: event.sessionId,
|
|
41
|
+
createdAt: new Date(event.createdAtMs)
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* The next event a stream iterator already holds, removed without
|
|
45
|
+
* awaiting its `next()`, which then continues after it; `undefined` when
|
|
46
|
+
* it holds none. Call only while no `next()` is pending. The SSE encoder
|
|
47
|
+
* writes these with the event `next()` just returned, so a buffered
|
|
48
|
+
* backlog leaves in few writes.
|
|
49
|
+
*/
|
|
50
|
+
const bufferedEvents = /* @__PURE__ */ new WeakMap();
|
|
51
|
+
const takeBuffered = (iterator) => bufferedEvents.get(iterator)?.();
|
|
52
|
+
//#endregion
|
|
53
|
+
export { takeBuffered as a, presenceTombstones as i, isSerializedEvent as n, parseSerializedEvent as r, bufferedEvents as t };
|
package/dist/sync-github.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
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-B0b9Qxw4.mjs";
|
|
2
|
+
import { n as ChatSyncProvider } from "./chat-provider-DNJQyajS.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { Adapter } from "chat";
|
|
5
5
|
//#region src/sync/github.d.ts
|
|
@@ -314,6 +314,7 @@ export declare const GitHubEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
314
314
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
315
315
|
reply: z.ZodNullable<z.ZodString>;
|
|
316
316
|
createRoot: z.ZodBoolean;
|
|
317
|
+
retitled: z.ZodOptional<z.ZodBoolean>;
|
|
317
318
|
author: z.ZodObject<{
|
|
318
319
|
id: z.ZodString;
|
|
319
320
|
handle: z.ZodString;
|
|
@@ -324,7 +325,7 @@ export declare const GitHubEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
324
325
|
id: z.ZodString;
|
|
325
326
|
key: z.ZodString;
|
|
326
327
|
platform: z.ZodLiteral<"github">;
|
|
327
|
-
type: z.ZodLiteral<"pr.assigned" | "pr.closed" | "pr.draft" | "pr.labeled" | "pr.opened" | "pr.ready" | "pr.reopened" | "pr.unassigned" | "pr.unlabeled" | "review.dismissed" | "review.submitted">;
|
|
328
|
+
type: z.ZodLiteral<"pr.assigned" | "pr.closed" | "pr.draft" | "pr.edited" | "pr.labeled" | "pr.opened" | "pr.ready" | "pr.reopened" | "pr.unassigned" | "pr.unlabeled" | "review.dismissed" | "review.submitted">;
|
|
328
329
|
subject: z.ZodObject<{
|
|
329
330
|
repo: z.ZodString;
|
|
330
331
|
number: z.ZodNumber;
|
|
@@ -373,6 +374,7 @@ export declare const GitHubEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
373
374
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
374
375
|
reply: z.ZodNullable<z.ZodString>;
|
|
375
376
|
createRoot: z.ZodBoolean;
|
|
377
|
+
retitled: z.ZodOptional<z.ZodBoolean>;
|
|
376
378
|
author: z.ZodObject<{
|
|
377
379
|
id: z.ZodString;
|
|
378
380
|
handle: z.ZodString;
|
|
@@ -383,7 +385,7 @@ export declare const GitHubEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
383
385
|
id: z.ZodString;
|
|
384
386
|
key: z.ZodString;
|
|
385
387
|
platform: z.ZodLiteral<"github">;
|
|
386
|
-
type: z.ZodLiteral<"issue.assigned" | "issue.closed" | "issue.labeled" | "issue.opened" | "issue.reopened" | "issue.unassigned" | "issue.unlabeled">;
|
|
388
|
+
type: z.ZodLiteral<"issue.assigned" | "issue.closed" | "issue.edited" | "issue.labeled" | "issue.opened" | "issue.reopened" | "issue.unassigned" | "issue.unlabeled">;
|
|
387
389
|
subject: z.ZodObject<{
|
|
388
390
|
repo: z.ZodString;
|
|
389
391
|
number: z.ZodNumber;
|
|
@@ -422,10 +424,9 @@ export declare const GitHubEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
422
424
|
}, z.core.$loose>;
|
|
423
425
|
}, z.core.$strip>)[]], "type">;
|
|
424
426
|
export type GitHubEvent = z.infer<typeof GitHubEvent>;
|
|
425
|
-
export type
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
issues?: EventMapping<GitHubEvent>;
|
|
427
|
+
export type GitHubRepo = SyncUnit<GitHubEvent> | {
|
|
428
|
+
pulls?: SyncUnit<GitHubEvent>;
|
|
429
|
+
issues?: SyncUnit<GitHubEvent>;
|
|
429
430
|
};
|
|
430
431
|
export type GitHubOptions = {
|
|
431
432
|
/**
|
|
@@ -439,19 +440,25 @@ export type GitHubOptions = {
|
|
|
439
440
|
* board looks it up from the installation token; set it to skip that call.
|
|
440
441
|
*/
|
|
441
442
|
botUserId?: number;
|
|
442
|
-
render?: (input: RenderInput) => string;
|
|
443
|
-
repos: Record<string, GitHubRepo>;
|
|
444
443
|
};
|
|
445
444
|
/**
|
|
446
|
-
* Syncs GitHub
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
445
|
+
* Syncs GitHub with the board: `app` is a Vercel Connect connector
|
|
446
|
+
* (`'github/acme'`) or the options, and `sync` is what each event does, both
|
|
447
|
+
* ways, like `repos({ 'acme/www': 'prs' })`. A board thread never opens an
|
|
448
|
+
* issue: GitHub threads start on GitHub.
|
|
450
449
|
*/
|
|
451
|
-
export declare function github(
|
|
450
|
+
export declare function github(app: string | GitHubOptions, sync: SyncFn<GitHubEvent>): GitHubProvider;
|
|
451
|
+
/**
|
|
452
|
+
* Routes each event by its repo. Keys are repos (`'owner/repo'`); values are a board channel
|
|
453
|
+
* that PRs and issues are imported `into`, a sync function, or `{ pulls, issues }` to route
|
|
454
|
+
* each its own way. A string imports and sends nothing back: what's said on the board stays
|
|
455
|
+
* there unless a function delivers it. A thread the board syncs in another repo keeps
|
|
456
|
+
* importing.
|
|
457
|
+
*/
|
|
458
|
+
export declare function repos(map: Record<string, GitHubRepo>): SyncFn<GitHubEvent>;
|
|
452
459
|
export declare class GitHubProvider extends ChatSyncProvider<GitHubEvent> {
|
|
453
460
|
private readonly body;
|
|
454
|
-
constructor(given: GitHubOptions);
|
|
461
|
+
constructor(given: GitHubOptions, sync: SyncFn<GitHubEvent>);
|
|
455
462
|
whoAmI(token: string): Promise<{
|
|
456
463
|
id: string;
|
|
457
464
|
handle: string;
|
|
@@ -467,7 +474,7 @@ export declare class GitHubProvider extends ChatSyncProvider<GitHubEvent> {
|
|
|
467
474
|
* (`root:<event>` or `lifecycle:<event>`), so its reactions go on the PR or issue.
|
|
468
475
|
*/
|
|
469
476
|
react(thread: string, message: string, emoji: string, added: boolean): Promise<void>;
|
|
470
|
-
event(context:
|
|
477
|
+
event(context: SyncContext): GitHubEvent;
|
|
471
478
|
}
|
|
472
479
|
//#endregion
|
|
473
480
|
export { type UserTokens, withUserTokens };
|
package/dist/sync-github.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { c as
|
|
2
|
-
import {
|
|
3
|
-
import { r as
|
|
1
|
+
import { c as into, d as withRoutes } from "./provider-B3DpYSDq.mjs";
|
|
2
|
+
import { i as eventSchema, r as envelope } from "./events-CewD4kw7.mjs";
|
|
3
|
+
import { r as withUserTokens, t as connectUserTokens } from "./users-yryHKFMo.mjs";
|
|
4
|
+
import { r as markdownOf, t as ChatSyncProvider } from "./chat-provider-YHy-WbrB.mjs";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
import { connectGitHubAdapter } from "@vercel/connect/chat";
|
|
6
7
|
import { createGitHubAdapter } from "@chat-adapter/github";
|
|
@@ -85,6 +86,20 @@ function lifecycle(name, body) {
|
|
|
85
86
|
createRoot: true
|
|
86
87
|
}
|
|
87
88
|
};
|
|
89
|
+
case "edited":
|
|
90
|
+
if (!body.changes?.title) return null;
|
|
91
|
+
return {
|
|
92
|
+
number: pr.number,
|
|
93
|
+
user: sender ?? {},
|
|
94
|
+
lifecycle: {
|
|
95
|
+
...base,
|
|
96
|
+
type: "pr.edited",
|
|
97
|
+
labels: {},
|
|
98
|
+
reply: null,
|
|
99
|
+
createRoot: false,
|
|
100
|
+
retitled: true
|
|
101
|
+
}
|
|
102
|
+
};
|
|
88
103
|
case "ready_for_review": return {
|
|
89
104
|
number: pr.number,
|
|
90
105
|
user: sender ?? {},
|
|
@@ -207,6 +222,18 @@ function lifecycle(name, body) {
|
|
|
207
222
|
createRoot: true
|
|
208
223
|
}
|
|
209
224
|
};
|
|
225
|
+
if (action === "edited" && body.changes?.title) return {
|
|
226
|
+
number: issue.number,
|
|
227
|
+
user: sender ?? {},
|
|
228
|
+
lifecycle: {
|
|
229
|
+
...base,
|
|
230
|
+
type: "issue.edited",
|
|
231
|
+
labels: {},
|
|
232
|
+
reply: null,
|
|
233
|
+
createRoot: false,
|
|
234
|
+
retitled: true
|
|
235
|
+
}
|
|
236
|
+
};
|
|
210
237
|
if (action === "closed") return {
|
|
211
238
|
number: issue.number,
|
|
212
239
|
user: sender ?? {},
|
|
@@ -257,6 +284,7 @@ const GitHubPayload = z.looseObject({
|
|
|
257
284
|
});
|
|
258
285
|
const prTypes = [
|
|
259
286
|
"pr.opened",
|
|
287
|
+
"pr.edited",
|
|
260
288
|
"pr.ready",
|
|
261
289
|
"pr.draft",
|
|
262
290
|
"pr.reopened",
|
|
@@ -270,6 +298,7 @@ const prTypes = [
|
|
|
270
298
|
];
|
|
271
299
|
const issueTypes = [
|
|
272
300
|
"issue.opened",
|
|
301
|
+
"issue.edited",
|
|
273
302
|
"issue.closed",
|
|
274
303
|
"issue.reopened",
|
|
275
304
|
"issue.labeled",
|
|
@@ -330,13 +359,39 @@ async function asPerson(token, method, path, body) {
|
|
|
330
359
|
return response.status === 204 ? null : response.json();
|
|
331
360
|
}
|
|
332
361
|
/**
|
|
333
|
-
* Syncs GitHub
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
362
|
+
* Syncs GitHub with the board: `app` is a Vercel Connect connector
|
|
363
|
+
* (`'github/acme'`) or the options, and `sync` is what each event does, both
|
|
364
|
+
* ways, like `repos({ 'acme/www': 'prs' })`. A board thread never opens an
|
|
365
|
+
* issue: GitHub threads start on GitHub.
|
|
366
|
+
*/
|
|
367
|
+
function github(app, sync) {
|
|
368
|
+
return new GitHubProvider(typeof app === "string" ? { adapter: app } : app, sync);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Routes each event by its repo. Keys are repos (`'owner/repo'`); values are a board channel
|
|
372
|
+
* that PRs and issues are imported `into`, a sync function, or `{ pulls, issues }` to route
|
|
373
|
+
* each its own way. A string imports and sends nothing back: what's said on the board stays
|
|
374
|
+
* there unless a function delivers it. A thread the board syncs in another repo keeps
|
|
375
|
+
* importing.
|
|
337
376
|
*/
|
|
338
|
-
function
|
|
339
|
-
|
|
377
|
+
function repos(map) {
|
|
378
|
+
const unit = (value) => typeof value === "string" ? into(value) : value;
|
|
379
|
+
const routes = /* @__PURE__ */ new Map();
|
|
380
|
+
for (const [repo, value] of Object.entries(map)) {
|
|
381
|
+
const { pulls, issues } = typeof value === "object" ? value : {
|
|
382
|
+
pulls: value,
|
|
383
|
+
issues: value
|
|
384
|
+
};
|
|
385
|
+
const [forPulls, forIssues] = [unit(pulls), unit(issues)];
|
|
386
|
+
if (forPulls) routes.set(`${repo}:pulls`, forPulls);
|
|
387
|
+
if (forIssues) routes.set(`${repo}:issues`, forIssues);
|
|
388
|
+
}
|
|
389
|
+
const fn = async (sync) => {
|
|
390
|
+
const route = sync.channel === null ? void 0 : routes.get(sync.channel);
|
|
391
|
+
if (route) await route(sync);
|
|
392
|
+
else if (sync.direction === "in") await sync.import();
|
|
393
|
+
};
|
|
394
|
+
return withRoutes(fn, async (channel) => routes.has(channel));
|
|
340
395
|
}
|
|
341
396
|
/**
|
|
342
397
|
* A connector's GitHub adapter, finding its own bot user ID. Chat SDK skips detection
|
|
@@ -368,13 +423,12 @@ function fromConnector(connector, botUserId) {
|
|
|
368
423
|
}
|
|
369
424
|
var GitHubProvider = class extends ChatSyncProvider {
|
|
370
425
|
body;
|
|
371
|
-
constructor(given) {
|
|
426
|
+
constructor(given, sync) {
|
|
372
427
|
const options = {
|
|
373
428
|
...given,
|
|
374
429
|
adapter: typeof given.adapter === "string" ? fromConnector(given.adapter, given.botUserId) : given.adapter
|
|
375
430
|
};
|
|
376
431
|
super({
|
|
377
|
-
render: options.render,
|
|
378
432
|
platform: "github",
|
|
379
433
|
adapter: options.adapter,
|
|
380
434
|
canStartThreads: false,
|
|
@@ -383,6 +437,25 @@ var GitHubProvider = class extends ChatSyncProvider {
|
|
|
383
437
|
groupThread: (thread) => thread.replace(/:rc:[^:]+$/, ""),
|
|
384
438
|
channelOf,
|
|
385
439
|
isRoot: () => false,
|
|
440
|
+
locate(url) {
|
|
441
|
+
const match = /^https:\/\/github\.com\/([^/\s]+)\/([^/\s]+)\/(pull|issues)\/(\d+)[^#\s]*(?:#(issuecomment-|discussion_r)(\d+))?$/.exec(url.trim());
|
|
442
|
+
if (!match) return null;
|
|
443
|
+
const [, owner, repo, kind, number, anchor, id] = match;
|
|
444
|
+
const thread = `${owner}/${repo}:${kind === "issues" ? "issue:" : ""}${number}`;
|
|
445
|
+
if (anchor === "discussion_r" && kind !== "pull") return null;
|
|
446
|
+
return {
|
|
447
|
+
thread,
|
|
448
|
+
message: anchor ? id : null
|
|
449
|
+
};
|
|
450
|
+
},
|
|
451
|
+
async url(thread, message) {
|
|
452
|
+
const match = /^([^/]+)\/([^:]+):(issue:)?(\d+)(:rc:\d+)?$/.exec(thread);
|
|
453
|
+
if (!match) return null;
|
|
454
|
+
const [, owner, repo, issue, number, review] = match;
|
|
455
|
+
const page = `https://github.com/${owner}/${repo}/${issue ? "issues" : "pull"}/${number}`;
|
|
456
|
+
if (!/^\d+$/.test(message)) return page;
|
|
457
|
+
return `${page}#${review ? "discussion_r" : "issuecomment-"}${message}`;
|
|
458
|
+
},
|
|
386
459
|
async fetchRoot(thread) {
|
|
387
460
|
const match = /^([^/]+)\/([^:]+):(issue:)?(\d+)$/.exec(thread);
|
|
388
461
|
if (!match) throw new Error(`invalid GitHub thread: ${thread}`);
|
|
@@ -497,7 +570,9 @@ var GitHubProvider = class extends ChatSyncProvider {
|
|
|
497
570
|
}];
|
|
498
571
|
},
|
|
499
572
|
async resolveTarget(target) {
|
|
500
|
-
|
|
573
|
+
const review = /^([^/]+\/[^:]+:\d+):rc:[^:]+$/.exec(target);
|
|
574
|
+
if (review) throw new Error(`a review thread can't be a target; sync its PR, ${review[1]}`);
|
|
575
|
+
if (!/^[^/]+\/[^:]+(?::(?:issue:)?\d+)?$/.test(target)) throw new Error(`invalid GitHub target: ${target}`);
|
|
501
576
|
const at = target.indexOf(":");
|
|
502
577
|
return {
|
|
503
578
|
target,
|
|
@@ -505,7 +580,7 @@ var GitHubProvider = class extends ChatSyncProvider {
|
|
|
505
580
|
kind: at === -1 ? "channel" : "thread"
|
|
506
581
|
};
|
|
507
582
|
}
|
|
508
|
-
});
|
|
583
|
+
}, sync);
|
|
509
584
|
const converter = options.adapter.formatConverter;
|
|
510
585
|
this.body = (post) => {
|
|
511
586
|
try {
|
|
@@ -514,14 +589,6 @@ var GitHubProvider = class extends ChatSyncProvider {
|
|
|
514
589
|
return post.markdown;
|
|
515
590
|
}
|
|
516
591
|
};
|
|
517
|
-
for (const [repo, value] of Object.entries(options.repos)) {
|
|
518
|
-
const { pulls, issues } = typeof value === "object" && !("run" in value) ? value : {
|
|
519
|
-
pulls: value,
|
|
520
|
-
issues: value
|
|
521
|
-
};
|
|
522
|
-
if (pulls) this.map(`${repo}:pulls`, pulls);
|
|
523
|
-
if (issues) this.map(`${repo}:issues`, issues);
|
|
524
|
-
}
|
|
525
592
|
}
|
|
526
593
|
async whoAmI(token) {
|
|
527
594
|
const user = await asPerson(token, "GET", "/user");
|
|
@@ -600,4 +667,4 @@ var GitHubProvider = class extends ChatSyncProvider {
|
|
|
600
667
|
}
|
|
601
668
|
};
|
|
602
669
|
//#endregion
|
|
603
|
-
export { GitHubEvent, GitHubPayload, GitHubProvider, github, withUserTokens };
|
|
670
|
+
export { GitHubEvent, GitHubPayload, GitHubProvider, github, repos, withUserTokens };
|
package/dist/sync-kapso.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-
|
|
1
|
+
import { S as SyncUnit, f as SyncContext, y as SyncFn } from "./provider-B0b9Qxw4.mjs";
|
|
2
|
+
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-DNJQyajS.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { Adapter } from "chat";
|
|
5
5
|
//#region src/sync/kapso.d.ts
|
|
@@ -132,6 +132,7 @@ export declare const WhatsAppEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
132
132
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
133
133
|
reply: z.ZodNullable<z.ZodString>;
|
|
134
134
|
createRoot: z.ZodBoolean;
|
|
135
|
+
retitled: z.ZodOptional<z.ZodBoolean>;
|
|
135
136
|
author: z.ZodObject<{
|
|
136
137
|
id: z.ZodString;
|
|
137
138
|
handle: z.ZodString;
|
|
@@ -152,24 +153,25 @@ type MarkRead = (input: {
|
|
|
152
153
|
type: 'text';
|
|
153
154
|
};
|
|
154
155
|
}) => Promise<unknown>;
|
|
155
|
-
export type KapsoHandler = SyncHandler<WhatsAppEvent>;
|
|
156
156
|
export type KapsoOptions = {
|
|
157
157
|
adapter: Adapter;
|
|
158
|
-
render?: (input: RenderInput) => string;
|
|
159
158
|
markRead: MarkRead;
|
|
160
|
-
numbers: Record<string, EventMapping<WhatsAppEvent>>;
|
|
161
159
|
};
|
|
162
160
|
/**
|
|
163
|
-
* Syncs WhatsApp numbers on Kapso with board
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* thread
|
|
167
|
-
* one: a board root in a mirrored channel stays on the board.
|
|
161
|
+
* Syncs WhatsApp numbers on Kapso with the board: `sync` is what each event
|
|
162
|
+
* does, both ways, like `numbers({ '16315558151': 'support' })`. Each Kapso
|
|
163
|
+
* conversation is a thread. WhatsApp has no threads in a number, so a board
|
|
164
|
+
* thread never starts one: a board root in a mirrored channel stays on the board.
|
|
168
165
|
*/
|
|
169
|
-
export declare function kapso(options: KapsoOptions): KapsoProvider;
|
|
166
|
+
export declare function kapso(options: KapsoOptions, sync: SyncFn<WhatsAppEvent>): KapsoProvider;
|
|
167
|
+
/**
|
|
168
|
+
* Routes each event by its WhatsApp number. Keys are phone number IDs (`'16315558151'`), not
|
|
169
|
+
* the numbers; values are a board channel to `mirror`, or a sync function.
|
|
170
|
+
*/
|
|
171
|
+
export declare const numbers: (map: Record<string, SyncUnit<WhatsAppEvent>>) => SyncFn<WhatsAppEvent>;
|
|
170
172
|
export declare class KapsoProvider extends ChatSyncProvider<WhatsAppEvent> {
|
|
171
|
-
constructor(options: KapsoOptions);
|
|
173
|
+
constructor(options: KapsoOptions, sync: SyncFn<WhatsAppEvent>);
|
|
172
174
|
eventId(key: string, input: ChatInput): string;
|
|
173
|
-
event(context:
|
|
175
|
+
event(context: SyncContext): WhatsAppEvent;
|
|
174
176
|
}
|
|
175
177
|
//#endregion
|
package/dist/sync-kapso.mjs
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { s as channels } from "./provider-B3DpYSDq.mjs";
|
|
2
|
+
import { i as eventSchema, r as envelope } from "./events-CewD4kw7.mjs";
|
|
3
|
+
import { r as markdownOf, t as ChatSyncProvider } from "./chat-provider-YHy-WbrB.mjs";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
//#region src/sync/kapso.ts
|
|
5
6
|
const decode = (id) => id.split(":").map((part) => Buffer.from(part, "base64url").toString("utf8")).join(":");
|
|
6
7
|
const encode = (id) => id.split(":").map((part) => Buffer.from(part, "utf8").toString("base64url")).join(":");
|
|
7
8
|
const WhatsAppEvent = eventSchema("whatsapp", "message");
|
|
8
9
|
/**
|
|
9
|
-
* Syncs WhatsApp numbers on Kapso with board
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* thread
|
|
13
|
-
* one: a board root in a mirrored channel stays on the board.
|
|
10
|
+
* Syncs WhatsApp numbers on Kapso with the board: `sync` is what each event
|
|
11
|
+
* does, both ways, like `numbers({ '16315558151': 'support' })`. Each Kapso
|
|
12
|
+
* conversation is a thread. WhatsApp has no threads in a number, so a board
|
|
13
|
+
* thread never starts one: a board root in a mirrored channel stays on the board.
|
|
14
14
|
*/
|
|
15
|
-
function kapso(options) {
|
|
16
|
-
return new KapsoProvider(options);
|
|
15
|
+
function kapso(options, sync) {
|
|
16
|
+
return new KapsoProvider(options, sync);
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Routes each event by its WhatsApp number. Keys are phone number IDs (`'16315558151'`), not
|
|
20
|
+
* the numbers; values are a board channel to `mirror`, or a sync function.
|
|
21
|
+
*/
|
|
22
|
+
const numbers = (map) => channels(map);
|
|
18
23
|
var KapsoProvider = class extends ChatSyncProvider {
|
|
19
|
-
constructor(options) {
|
|
24
|
+
constructor(options, sync) {
|
|
20
25
|
if (typeof options.markRead !== "function") throw new Error("kapso requires a public markRead operation for cross-instance read and typing");
|
|
21
26
|
const fileIds = (raw) => (raw?.responses ?? []).flatMap((response) => response.messages?.[0]?.id ?? []);
|
|
22
27
|
super({
|
|
23
28
|
fileIds,
|
|
24
|
-
render: options.render,
|
|
25
29
|
platform: "whatsapp",
|
|
26
30
|
adapter: options.adapter,
|
|
27
31
|
canStartThreads: false,
|
|
@@ -69,8 +73,7 @@ var KapsoProvider = class extends ChatSyncProvider {
|
|
|
69
73
|
kind: parts.length === 1 ? "channel" : "thread"
|
|
70
74
|
};
|
|
71
75
|
}
|
|
72
|
-
});
|
|
73
|
-
for (const [key, value] of Object.entries(options.numbers)) this.map(key, value);
|
|
76
|
+
}, sync);
|
|
74
77
|
}
|
|
75
78
|
eventId(key, input) {
|
|
76
79
|
if (input.kind !== "reaction") return super.eventId(key, input);
|
|
@@ -83,4 +86,4 @@ var KapsoProvider = class extends ChatSyncProvider {
|
|
|
83
86
|
}
|
|
84
87
|
};
|
|
85
88
|
//#endregion
|
|
86
|
-
export { KapsoProvider, WhatsAppEvent, kapso };
|
|
89
|
+
export { KapsoProvider, WhatsAppEvent, kapso, numbers };
|
package/dist/sync-slack.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-
|
|
1
|
+
import { f as ExternalLink } from "./folds-CRYY14kc.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-B0b9Qxw4.mjs";
|
|
3
|
+
import { n as ChatSyncProvider, t as ChatInput } from "./chat-provider-DNJQyajS.mjs";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { Adapter } from "chat";
|
|
6
6
|
//#region src/sync/slack.d.ts
|
|
@@ -26,9 +26,6 @@ export type SlackClient = {
|
|
|
26
26
|
}): Promise<{
|
|
27
27
|
channel?: SlackChannel;
|
|
28
28
|
}>;
|
|
29
|
-
join(args: {
|
|
30
|
-
channel: string;
|
|
31
|
-
}): Promise<unknown>;
|
|
32
29
|
/** Reads a linked message or a thread; needs `channels:history` (`groups:history` for private channels). */
|
|
33
30
|
replies?(args: {
|
|
34
31
|
channel: string;
|
|
@@ -300,6 +297,7 @@ export declare const SlackEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
300
297
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
301
298
|
reply: z.ZodNullable<z.ZodString>;
|
|
302
299
|
createRoot: z.ZodBoolean;
|
|
300
|
+
retitled: z.ZodOptional<z.ZodBoolean>;
|
|
303
301
|
author: z.ZodObject<{
|
|
304
302
|
id: z.ZodString;
|
|
305
303
|
handle: z.ZodString;
|
|
@@ -313,7 +311,6 @@ export declare const SlackEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
313
311
|
platform: z.ZodLiteral<"slack">;
|
|
314
312
|
}, z.core.$strip>], "kind">;
|
|
315
313
|
export type SlackEvent = z.infer<typeof SlackEvent>;
|
|
316
|
-
export type SlackHandler = SyncHandler<SlackEvent>;
|
|
317
314
|
export type SlackOptions = {
|
|
318
315
|
/**
|
|
319
316
|
* A Vercel Connect connector (`'slack/acme'`): board builds the Slack adapter,
|
|
@@ -321,22 +318,20 @@ export type SlackOptions = {
|
|
|
321
318
|
* Or your own Chat SDK adapter, wrapped in `withUserTokens` to post as people.
|
|
322
319
|
*/
|
|
323
320
|
adapter: Adapter | string;
|
|
324
|
-
render?: (input: RenderInput) => string;
|
|
325
321
|
/** Not needed with a connector. */
|
|
326
322
|
client?: () => Promise<SlackClient>;
|
|
327
|
-
channels: Record<string, EventMapping<SlackEvent>>;
|
|
328
323
|
};
|
|
329
324
|
/**
|
|
330
|
-
* Syncs Slack
|
|
331
|
-
* (`'
|
|
332
|
-
*
|
|
333
|
-
*
|
|
325
|
+
* Syncs a Slack workspace with the board: `app` is a Vercel Connect connector
|
|
326
|
+
* (`'slack/acme'`) or the options, and `sync` is what each event does, both ways,
|
|
327
|
+
* like `channels({ '#prs': 'prs' })`. Invite the app to each channel it syncs:
|
|
328
|
+
* it never joins one on its own.
|
|
334
329
|
*/
|
|
335
|
-
export declare function slack(
|
|
330
|
+
export declare function slack(app: string | SlackOptions, sync: SyncFn<SlackEvent>): SlackProvider;
|
|
336
331
|
export declare class SlackProvider extends ChatSyncProvider<SlackEvent> {
|
|
337
332
|
private readonly web;
|
|
338
333
|
private customize;
|
|
339
|
-
constructor(given: SlackOptions);
|
|
334
|
+
constructor(given: SlackOptions, sync: SyncFn<SlackEvent>);
|
|
340
335
|
/**
|
|
341
336
|
* An agent's message goes out under its own name (`clever-lemur via vboard-factory`), and its
|
|
342
337
|
* picture when it has one Slack can show, instead of the app's, with the text's
|
|
@@ -358,7 +353,7 @@ export declare class SlackProvider extends ChatSyncProvider<SlackEvent> {
|
|
|
358
353
|
*/
|
|
359
354
|
permalink(event: SlackEvent): Promise<string | null>;
|
|
360
355
|
eventId(key: string, input: ChatInput): string;
|
|
361
|
-
event(context:
|
|
356
|
+
event(context: SyncContext): SlackEvent;
|
|
362
357
|
}
|
|
363
358
|
//#endregion
|
|
364
|
-
export { type UserTokens, withUserTokens };
|
|
359
|
+
export { type UserTokens, channels, withUserTokens };
|