@vercel/board 0.18.1 → 0.20.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/dist/{a2-CW8jHGD_.mjs → a2-D__qQpe7.mjs} +37 -6
- package/dist/access.mjs +3 -3
- package/dist/{actors-BOamkEuz.mjs → actors-rPnEQLZu.mjs} +2 -2
- package/dist/{auth-Drg9FiC2.mjs → auth-5nLsx9qB.mjs} +1 -1
- package/dist/{backend-B-SJ7p6p.d.mts → backend-CWmd4UH-.d.mts} +8 -1
- package/dist/backend-a2.d.mts +22 -2
- package/dist/backend-a2.mjs +1 -1
- package/dist/{backend-http-7cNb8nJI.d.mts → backend-http-BfWQfvqB.d.mts} +22 -2
- package/dist/{backend-http-CDDS7MLI.mjs → backend-http-CG5y03UP.mjs} +25 -6
- package/dist/{backend-http-BjH8jMDi.mjs → backend-http-c-VHpUOs.mjs} +19 -6
- 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-DNJQyajS.d.mts → chat-provider-D0k3y8zY.d.mts} +4 -1
- package/dist/{chat-provider-YHy-WbrB.mjs → chat-provider-DnHibqnM.mjs} +4 -1
- package/dist/cli-embedded.d.mts +47 -0
- package/dist/cli-embedded.mjs +64 -0
- package/dist/cli.mjs +73 -1661
- package/dist/{client-BA-J7usH.mjs → client-ClznIBMg.mjs} +2 -0
- package/dist/{conformance-CT5EeHeC.mjs → conformance-DQ9qVzWP.mjs} +47 -6
- package/dist/conformance.d.mts +1 -1
- package/dist/conformance.mjs +1 -1
- package/dist/{engine-D0oBUBEK.mjs → engine-kHfSOXnQ.mjs} +15 -4
- package/dist/{errors-DX3hpwWt.mjs → errors-CQ-fwxM3.mjs} +13 -1
- package/dist/{exports-CwsfgCul.mjs → exports-DqWJ7nzC.mjs} +15 -6
- package/dist/exports-ggfE9jNv.d.mts +4 -0
- package/dist/index-DsMPCv_K.d.mts +11 -0
- package/dist/index.d.mts +4 -4
- package/dist/{index.default-jkA7eFFe.mjs → index.default-C3luVnd-.mjs} +1 -1
- package/dist/index.mjs +6 -6
- package/dist/index.node.d.mts +4 -12
- package/dist/index.node.mjs +4 -4
- package/dist/inspect/app.js +93 -92
- package/dist/inspect/engine.js +4 -4
- package/dist/main-wB-VfTCL.mjs +1744 -0
- package/dist/{middleware-CqaCwucP.mjs → middleware-DUjyQP_a.mjs} +1 -1
- package/dist/{provider-B0b9Qxw4.d.mts → provider-D11Dfda0.d.mts} +91 -22
- package/dist/{provider-B3DpYSDq.mjs → provider-poIkXapd.mjs} +4 -0
- package/dist/{serve-Dpb7zMJ0.mjs → serve-AnApUWOR.mjs} +4 -4
- package/dist/{server-Bj1_ugXd.mjs → server-BqVickb5.mjs} +4 -4
- package/dist/{serving-CNkgUPW1.mjs → serving-B307gppu.mjs} +1 -1
- package/dist/sync-github.d.mts +2 -2
- package/dist/sync-github.mjs +2 -2
- package/dist/sync-kapso.d.mts +2 -2
- package/dist/sync-kapso.mjs +2 -2
- package/dist/sync-linear.d.mts +2 -2
- package/dist/sync-linear.mjs +2 -2
- package/dist/sync-slack.d.mts +11 -2
- package/dist/sync-slack.mjs +57 -17
- package/dist/sync.chat.d.mts +1 -1
- package/dist/sync.chat.mjs +1 -1
- package/dist/sync.d.mts +1 -1
- package/dist/sync.mjs +1 -1
- package/dist/{tokens-DhuzKzAl.mjs → tokens-DUXaXwOj.mjs} +2 -2
- package/dist/{watchers-hash-qlnbKQQ0.mjs → watchers-hash-DYwvkhdX.mjs} +38 -7
- package/docs/01-board/06-watchers.md +7 -0
- package/docs/02-sync/03-slack.md +14 -1
- package/docs/02-sync/06-providers.md +1 -0
- package/docs/04-reference/01-cli.md +55 -3
- package/docs/04-reference/02-board.md +8 -3
- package/docs/04-reference/03-http.md +7 -4
- package/package.json +5 -1
- package/dist/exports-ZsgjzEnM.d.mts +0 -4
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { n as DIRECT_UPLOAD_BYTES_MAX, r as IMPORT_BYTES_MAX, t as ATTACHMENT_BYTES_MAX } from "./files-SniSmeEr.mjs";
|
|
2
2
|
import { _ as RemoteWatcherId, b as actorKind, i as Attachment, x as platformAvatar } from "./schemas-Be08nyfW.mjs";
|
|
3
3
|
import "./external-BV_cUncs.mjs";
|
|
4
|
-
import { f as VERSION, n as compileWatcher, o as METHODS, p as SYNC, r as hasCriteria, t as canonicalWatchers } from "./watchers-hash-
|
|
5
|
-
import { r as duration, t as BoardError } from "./client-
|
|
4
|
+
import { f as VERSION, n as compileWatcher, o as METHODS, p as SYNC, r as hasCriteria, t as canonicalWatchers } from "./watchers-hash-DYwvkhdX.mjs";
|
|
5
|
+
import { r as duration, t as BoardError } from "./client-ClznIBMg.mjs";
|
|
6
6
|
import { n as derivedId, r as isKeyIdOf } from "./ids-C6AYo1bu.mjs";
|
|
7
|
-
import { a as forbidden, c as toErrorResponse, i as duplicateId, r as badRequest, s as notFound, t as HttpError } from "./errors-
|
|
7
|
+
import { a as forbidden, c as toErrorResponse, i as duplicateId, r as badRequest, s as notFound, t as HttpError } from "./errors-CQ-fwxM3.mjs";
|
|
8
8
|
import { t as own } from "./own-OwgPWdmh.mjs";
|
|
9
9
|
import { n as replaceMentions } from "./mentions-CB6ShY4R.mjs";
|
|
10
|
-
import { _ as FULL_ACCESS, i as authenticates, v as authorize } from "./auth-
|
|
11
|
-
import { a as resolveMentions, n as actorSeen } from "./actors-
|
|
12
|
-
import { n as MIDDLEWARE_ACTOR, t as DroppedError } from "./middleware-
|
|
10
|
+
import { _ as FULL_ACCESS, i as authenticates, v as authorize } from "./auth-5nLsx9qB.mjs";
|
|
11
|
+
import { a as resolveMentions, n as actorSeen } from "./actors-rPnEQLZu.mjs";
|
|
12
|
+
import { n as MIDDLEWARE_ACTOR, t as DroppedError } from "./middleware-DUjyQP_a.mjs";
|
|
13
13
|
import { n as syncTarget, r as withEmailMentions } from "./targets-C-wdR5wP.mjs";
|
|
14
14
|
import { t as A2Error } from "./session-clear-wHd5GCpZ-BnKSxReK.mjs";
|
|
15
15
|
import { a as reducer } from "./reducer-CjmvZSAb-D_OSISmj.mjs";
|
|
@@ -714,8 +714,32 @@ function createReads(tables, session, projection) {
|
|
|
714
714
|
});
|
|
715
715
|
waitUntil(catching);
|
|
716
716
|
}
|
|
717
|
+
/**
|
|
718
|
+
* The tables caught up with the whole log once on this instance. Until then, a read by index waits
|
|
719
|
+
* for all of it: tables rebuilt from the log can be far behind, and a message's later events (an
|
|
720
|
+
* edit, a reaction, a reply) come after its own index. Once caught up, each write applies as it lands.
|
|
721
|
+
*/
|
|
722
|
+
let whole = null;
|
|
723
|
+
function caughtUp() {
|
|
724
|
+
whole ??= session.consume(projection).then(() => void 0, (error) => {
|
|
725
|
+
whole = null;
|
|
726
|
+
throw error;
|
|
727
|
+
});
|
|
728
|
+
return whole;
|
|
729
|
+
}
|
|
730
|
+
/** `promise`, unless `signal` aborts first: the caller stops waiting, and what it waits for keeps going. */
|
|
731
|
+
function untilAborted(promise, signal) {
|
|
732
|
+
if (!signal) return promise;
|
|
733
|
+
if (signal.aborted) return Promise.reject(signal.reason);
|
|
734
|
+
return new Promise((resolve, reject) => {
|
|
735
|
+
const abort = () => reject(signal.reason);
|
|
736
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
737
|
+
promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
738
|
+
});
|
|
739
|
+
}
|
|
717
740
|
/** Waits until the tables have applied `index`, or the whole log when it's omitted. */
|
|
718
741
|
async function ensure(index, signal) {
|
|
742
|
+
if (index !== void 0) await untilAborted(caughtUp(), signal);
|
|
719
743
|
if (index !== void 0 && await tables.position() >= index) return;
|
|
720
744
|
await session.consume(projection, {
|
|
721
745
|
...index !== void 0 ? { through: index } : {},
|
|
@@ -3081,6 +3105,7 @@ function build(options, binding) {
|
|
|
3081
3105
|
return { watchers: principal.access.everywhere("manage") ? all : all.filter((found) => found.owner === principal.id) };
|
|
3082
3106
|
},
|
|
3083
3107
|
async register(caller, body) {
|
|
3108
|
+
if (body.path) throw new HttpError(501, "no_wake_by_path", "this board wakes a url, not a path: register `url` instead");
|
|
3084
3109
|
const { principal } = await identityOf(caller);
|
|
3085
3110
|
ownWatchers(principal);
|
|
3086
3111
|
if (!principal.access.anywhere("read")) throw forbidden("this token can't read anywhere, so a watcher it registers would see nothing");
|
|
@@ -3179,6 +3204,12 @@ function build(options, binding) {
|
|
|
3179
3204
|
if (!principal.access.everywhere("manage")) throw forbidden("this token can't read a source: it needs manage in every channel");
|
|
3180
3205
|
return binding.readSource(key, target, limit ?? 50);
|
|
3181
3206
|
},
|
|
3207
|
+
async joinSource(caller, { key, target }) {
|
|
3208
|
+
if (!binding.sync.some((entry) => entry.key === key)) throw notFound(`this board doesn't run sync entry ${key}: join it where its sync runs`, "not_synced_here");
|
|
3209
|
+
const { principal } = await identityOf(caller);
|
|
3210
|
+
if (!principal.access.everywhere("manage")) throw forbidden("this token can't join a source: it needs manage in every channel");
|
|
3211
|
+
return binding.joinSource(key, target);
|
|
3212
|
+
},
|
|
3182
3213
|
async synced(caller, { id }, signal) {
|
|
3183
3214
|
const { principal } = await identityOf(caller);
|
|
3184
3215
|
const message = await reads.message(messageAt(id), signal);
|
package/dist/access.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as compileRules, c as githubActions, h as vercelProject, p as oidc } from "./auth-
|
|
2
|
-
import { i as resolveActor } from "./actors-
|
|
3
|
-
import { t as oidcTokens } from "./tokens-
|
|
1
|
+
import { a as compileRules, c as githubActions, h as vercelProject, p as oidc } from "./auth-5nLsx9qB.mjs";
|
|
2
|
+
import { i as resolveActor } from "./actors-rPnEQLZu.mjs";
|
|
3
|
+
import { t as oidcTokens } from "./tokens-DUXaXwOj.mjs";
|
|
4
4
|
export { compileRules, githubActions, oidc, oidcTokens, resolveActor, vercelProject };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { C as toStorable } from "./schemas-Be08nyfW.mjs";
|
|
2
|
-
import { r as badRequest } from "./errors-
|
|
2
|
+
import { r as badRequest } from "./errors-CQ-fwxM3.mjs";
|
|
3
3
|
import { t as own } from "./own-OwgPWdmh.mjs";
|
|
4
4
|
import { t as extractMentions } from "./mentions-CB6ShY4R.mjs";
|
|
5
|
-
import { y as parseScope } from "./auth-
|
|
5
|
+
import { y as parseScope } from "./auth-5nLsx9qB.mjs";
|
|
6
6
|
//#region src/server/actors.ts
|
|
7
7
|
/** Agents whose avatars the board serves itself. */
|
|
8
8
|
const KNOWN_AGENTS = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as ChannelPath, v as SCOPE_MAX } from "./schemas-Be08nyfW.mjs";
|
|
2
|
-
import { a as forbidden, l as unauthorized } from "./errors-
|
|
2
|
+
import { a as forbidden, l as unauthorized } from "./errors-CQ-fwxM3.mjs";
|
|
3
3
|
//#region src/server/access.ts
|
|
4
4
|
/**
|
|
5
5
|
* What a principal may do in a channel. `read` covers messages, threads,
|
|
@@ -2,7 +2,7 @@ import { t as Access } from "./access-CV96SYgr.mjs";
|
|
|
2
2
|
import { m as RuleFunction, n as AccessRule, r as Authenticate, s as Granted, t as AccessFunction, u as Known } from "./auth-CU56Q2Xh.mjs";
|
|
3
3
|
import { i as Attachment, o as Author, p as Labels } from "./schemas-CWxs3ECJ.mjs";
|
|
4
4
|
import { t as Actor, u as ExternalEvent } from "./folds-CRYY14kc.mjs";
|
|
5
|
-
import { $ as Discovery, Et as PostBody, F as BoardClient,
|
|
5
|
+
import { $ as Discovery, $t as SyncCodeView, Bt as SchedulesQuery, Et as PostBody, F as BoardClient, Gt as SourceJoinBody, It as ScheduleBody, Jt as SourceReadQuery, Nt as RegistrationView, Qt as SyncCodeBody, St as MessagesQuery, Tt as PersonView, Wt as SourceJoin, X as BoardEventView, Yt as SyncAccountBody, Z as ChannelView, _t as MatchView, an as SyncImportBody, bn as UploadStartBody, bt as MessageView, ct as InboxEntry, dn as SyncUnlinkBody, dt as InboxPushBody, en as SyncCopiesQuery, et as EditBody, fn as SyncedView, ft as InboxQuery, gn as ThreadsQuery, gt as LinkedQuery, hn as ThreadsPage, ht as LinkedAccount, in as SyncFindView, jt as RegisterBody, kt as ReactBody, ln as SyncRootsQuery, lt as InboxItem, mn as ThreadView, nt as EventsQuery, ot as IdentityView, p as SyncProvider, pt as LabelBody, q as AckBody, qt as SourceRead, rn as SyncFindQuery, sn as SyncReceiptBody, st as InboxAckBody, tn as SyncCopiesView, tt as EventsPage, un as SyncThreadView, ut as InboxNextQuery, vn as TypingBody, vt as MatchesQuery, xn as UploadTicket, xt as MessagesPage, yt as Me, z as ProfileOption, zt as ScheduleView } from "./provider-D11Dfda0.mjs";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
//#region src/api/protocol.d.ts
|
|
8
8
|
type Input<S extends z.ZodType> = NonNullable<z.output<S>>;
|
|
@@ -186,6 +186,11 @@ type Protocol = {
|
|
|
186
186
|
input: Key & Input<typeof SourceReadQuery>;
|
|
187
187
|
output: SourceRead;
|
|
188
188
|
};
|
|
189
|
+
/** Adds sync entry `key`'s app to a public channel, where that sync runs and opted in: needs `manage` everywhere. */
|
|
190
|
+
joinSource: {
|
|
191
|
+
input: Key & Input<typeof SourceJoinBody>;
|
|
192
|
+
output: SourceJoin;
|
|
193
|
+
};
|
|
189
194
|
/** Where a message's thread is synced, and its copy on each target, from sync's records: needs `read` where it is. */
|
|
190
195
|
synced: {
|
|
191
196
|
input: Id;
|
|
@@ -618,6 +623,8 @@ type BoardBinding = {
|
|
|
618
623
|
* `readSource` answers. 404 `not_synced_here` for an entry it doesn't run.
|
|
619
624
|
*/
|
|
620
625
|
readSource(key: string, target: string, limit: number): Promise<SourceRead>;
|
|
626
|
+
/** Adds sync entry `key`'s app to a channel, where it opted in: what `joinSource` answers. 404 `not_synced_here` likewise. */
|
|
627
|
+
joinSource(key: string, target: string): Promise<SourceJoin>;
|
|
621
628
|
/**
|
|
622
629
|
* The message a platform link names, as each platform this board syncs reads it: the platform,
|
|
623
630
|
* and its own thread and message IDs, the message null for a link to a thread. Any entry of that
|
package/dist/backend-a2.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import { i as Attachment } from "./schemas-CWxs3ECJ.mjs";
|
|
|
2
2
|
import { t as Actor } from "./folds-CRYY14kc.mjs";
|
|
3
3
|
import { l as Reducer, r as ContractEvent } from "./reducer-CYPHsSmd-BQIfozGi.mjs";
|
|
4
4
|
import { a as SessionAppend, c as SessionConsumeOptions, d as SessionSchedule, f as StateOptions, l as SessionConsumeResult, n as A2Server, o as SessionClearOptions, p as SessionCleared, r as Consumer, s as SessionClearResult, t as A2Scheduler, u as SessionDeadLetters } from "./server-qgez0Xny-D5mLfqFQ.mjs";
|
|
5
|
-
import { $ as Discovery,
|
|
6
|
-
import { i as Caller, n as BackendRoute, r as BoardBinding } from "./backend-
|
|
5
|
+
import { $ as Discovery, $t as SyncCodeView, Nt as RegistrationView, Tt as PersonView, Wt as SourceJoin, Z as ChannelView, _t as MatchView, bt as MessageView, ct as InboxEntry, fn as SyncedView, hn as ThreadsPage, ht as LinkedAccount, in as SyncFindView, lt as InboxItem, mn as ThreadView, ot as IdentityView, qt as SourceRead, tn as SyncCopiesView, tt as EventsPage, un as SyncThreadView, xn as UploadTicket, xt as MessagesPage, yt as Me, zt as ScheduleView } from "./provider-D11Dfda0.mjs";
|
|
6
|
+
import { i as Caller, n as BackendRoute, r as BoardBinding } from "./backend-CWmd4UH-.mjs";
|
|
7
7
|
import { n as fsBlob, r as memoryBlob, t as BlobStore } from "./blob-C0J3wbGv.mjs";
|
|
8
8
|
import { t as BoardStore } from "./types-8yq2VnKI.mjs";
|
|
9
9
|
import { z } from "zod";
|
|
@@ -220,7 +220,19 @@ export declare function a2(options?: A2Options): {
|
|
|
220
220
|
watchers: RegistrationView[];
|
|
221
221
|
}>;
|
|
222
222
|
register: (caller: Caller, input: {
|
|
223
|
+
watch: Record<string, {
|
|
224
|
+
tail: string;
|
|
225
|
+
when: "enters" | "matches";
|
|
226
|
+
}>;
|
|
227
|
+
sync?: {
|
|
228
|
+
key: string;
|
|
229
|
+
platform: string;
|
|
230
|
+
signIn: boolean;
|
|
231
|
+
}[] | undefined;
|
|
223
232
|
url?: string | null | undefined;
|
|
233
|
+
path?: null | undefined;
|
|
234
|
+
branch?: null | undefined;
|
|
235
|
+
} | {
|
|
224
236
|
watch: Record<string, {
|
|
225
237
|
tail: string;
|
|
226
238
|
when: "enters" | "matches";
|
|
@@ -230,6 +242,9 @@ export declare function a2(options?: A2Options): {
|
|
|
230
242
|
platform: string;
|
|
231
243
|
signIn: boolean;
|
|
232
244
|
}[] | undefined;
|
|
245
|
+
url?: null | undefined;
|
|
246
|
+
path: string;
|
|
247
|
+
branch?: string | null | undefined;
|
|
233
248
|
}, signal: AbortSignal) => Promise<RegistrationView>;
|
|
234
249
|
matches: (caller: Caller, input: {
|
|
235
250
|
limit?: number | undefined;
|
|
@@ -271,6 +286,11 @@ export declare function a2(options?: A2Options): {
|
|
|
271
286
|
target: string;
|
|
272
287
|
limit?: number | undefined;
|
|
273
288
|
}, signal: AbortSignal) => Promise<SourceRead>;
|
|
289
|
+
joinSource: (caller: Caller, input: {
|
|
290
|
+
key: string;
|
|
291
|
+
} & {
|
|
292
|
+
target: string;
|
|
293
|
+
}, signal: AbortSignal) => Promise<SourceJoin>;
|
|
274
294
|
synced: (caller: Caller, input: {
|
|
275
295
|
id: string;
|
|
276
296
|
}, signal: AbortSignal) => Promise<SyncedView>;
|
package/dist/backend-a2.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as fsBlob, r as memoryBlob, t as a2 } from "./a2-
|
|
1
|
+
import { n as fsBlob, r as memoryBlob, t as a2 } from "./a2-D__qQpe7.mjs";
|
|
2
2
|
export { a2, fsBlob, memoryBlob };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as Attachment } from "./schemas-CWxs3ECJ.mjs";
|
|
2
2
|
import { t as Actor } from "./folds-CRYY14kc.mjs";
|
|
3
|
-
import { $ as Discovery,
|
|
4
|
-
import { i as Caller, n as BackendRoute, r as BoardBinding } from "./backend-
|
|
3
|
+
import { $ as Discovery, $t as SyncCodeView, Nt as RegistrationView, Tt as PersonView, Wt as SourceJoin, Z as ChannelView, _t as MatchView, bt as MessageView, ct as InboxEntry, fn as SyncedView, hn as ThreadsPage, ht as LinkedAccount, in as SyncFindView, lt as InboxItem, mn as ThreadView, ot as IdentityView, qt as SourceRead, tn as SyncCopiesView, tt as EventsPage, un as SyncThreadView, xn as UploadTicket, xt as MessagesPage, yt as Me, z as ProfileOption, zt as ScheduleView } from "./provider-D11Dfda0.mjs";
|
|
4
|
+
import { i as Caller, n as BackendRoute, r as BoardBinding } from "./backend-CWmd4UH-.mjs";
|
|
5
5
|
//#region src/server/backend-http.d.ts
|
|
6
6
|
type HttpOptions = {
|
|
7
7
|
/**
|
|
@@ -194,7 +194,19 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
|
|
|
194
194
|
watchers: RegistrationView[];
|
|
195
195
|
}>;
|
|
196
196
|
register: (caller: Caller, input: {
|
|
197
|
+
watch: Record<string, {
|
|
198
|
+
tail: string;
|
|
199
|
+
when: "enters" | "matches";
|
|
200
|
+
}>;
|
|
201
|
+
sync?: {
|
|
202
|
+
key: string;
|
|
203
|
+
platform: string;
|
|
204
|
+
signIn: boolean;
|
|
205
|
+
}[] | undefined;
|
|
197
206
|
url?: string | null | undefined;
|
|
207
|
+
path?: null | undefined;
|
|
208
|
+
branch?: null | undefined;
|
|
209
|
+
} | {
|
|
198
210
|
watch: Record<string, {
|
|
199
211
|
tail: string;
|
|
200
212
|
when: "enters" | "matches";
|
|
@@ -204,6 +216,9 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
|
|
|
204
216
|
platform: string;
|
|
205
217
|
signIn: boolean;
|
|
206
218
|
}[] | undefined;
|
|
219
|
+
url?: null | undefined;
|
|
220
|
+
path: string;
|
|
221
|
+
branch?: string | null | undefined;
|
|
207
222
|
}, signal: AbortSignal) => Promise<RegistrationView>;
|
|
208
223
|
matches: (caller: Caller, input: {
|
|
209
224
|
limit?: number | undefined;
|
|
@@ -245,6 +260,11 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
|
|
|
245
260
|
target: string;
|
|
246
261
|
limit?: number | undefined;
|
|
247
262
|
}, signal: AbortSignal) => Promise<SourceRead>;
|
|
263
|
+
joinSource: (caller: Caller, input: {
|
|
264
|
+
key: string;
|
|
265
|
+
} & {
|
|
266
|
+
target: string;
|
|
267
|
+
}, signal: AbortSignal) => Promise<SourceJoin>;
|
|
248
268
|
synced: (caller: Caller, input: {
|
|
249
269
|
id: string;
|
|
250
270
|
}, signal: AbortSignal) => Promise<SyncedView>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "./files-SniSmeEr.mjs";
|
|
2
2
|
import "./schemas-Be08nyfW.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { n as createBoardClient, t as BoardError } from "./client-
|
|
3
|
+
import { k as RegisterBody, n as compileWatcher, o as METHODS, q as routes, t as canonicalWatchers } from "./watchers-hash-DYwvkhdX.mjs";
|
|
4
|
+
import { n as createBoardClient, t as BoardError } from "./client-ClznIBMg.mjs";
|
|
5
5
|
import { a as sha256, i as keyId, n as derivedId, t as DERIVED_ID } from "./ids-C6AYo1bu.mjs";
|
|
6
|
-
import { a as forbidden, o as json, t as HttpError } from "./errors-
|
|
6
|
+
import { a as forbidden, o as json, t as HttpError } from "./errors-CQ-fwxM3.mjs";
|
|
7
7
|
//#region src/server/backend-http.ts
|
|
8
8
|
/** A watcher's or client's name is the profile its writes are by. */
|
|
9
9
|
const PROFILE = /^[A-Za-z][A-Za-z0-9-]{0,31}$/;
|
|
@@ -308,6 +308,10 @@ function createHttp(url, options, environment) {
|
|
|
308
308
|
if ("self" in caller && bound().sync.some((entry) => entry.key === input.key)) return bound().readSource(input.key, input.target, input.limit ?? 50);
|
|
309
309
|
return remoteCall("readSource", caller, input, signal);
|
|
310
310
|
},
|
|
311
|
+
async joinSource(caller, input, signal) {
|
|
312
|
+
if ("self" in caller && bound().sync.some((entry) => entry.key === input.key)) return bound().joinSource(input.key, input.target);
|
|
313
|
+
return remoteCall("joinSource", caller, input, signal);
|
|
314
|
+
},
|
|
311
315
|
async synced(caller, input, signal) {
|
|
312
316
|
const { targets } = await remoteCall("synced", caller, input, signal);
|
|
313
317
|
return { targets: await Promise.all(targets.map(async (row) => ({
|
|
@@ -350,17 +354,32 @@ function createHttp(url, options, environment) {
|
|
|
350
354
|
};
|
|
351
355
|
/** Only an https URL can be woken; anything else pulls on its own. */
|
|
352
356
|
const wakeable = (here) => here?.startsWith("https://") ? here : null;
|
|
357
|
+
/**
|
|
358
|
+
* Where the remote wakes this board: on a board that wakes by path, the path on this project,
|
|
359
|
+
* which gets through its Deployment Protection, from production or from a preview of a branch,
|
|
360
|
+
* which it names; anywhere else (off Vercel, development, a custom environment), its URL.
|
|
361
|
+
*/
|
|
362
|
+
async function wakeAt(here) {
|
|
363
|
+
const env = typeof process !== "undefined" && process.env.VERCEL === "1" ? process.env : null;
|
|
364
|
+
const environment = env?.VERCEL_TARGET_ENV || env?.VERCEL_ENV;
|
|
365
|
+
const branch = environment === "preview" ? env?.VERCEL_GIT_COMMIT_REF || null : null;
|
|
366
|
+
if (!here || environment !== "production" && !branch || !(await discovery()).wake_by_path) return { url: here };
|
|
367
|
+
return {
|
|
368
|
+
path: new URL(here).pathname,
|
|
369
|
+
...branch ? { branch } : {}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
353
372
|
let last = null;
|
|
354
373
|
let registering = null;
|
|
355
374
|
/** Registers this board's watchers with the remote, as itself, replacing its last registration. */
|
|
356
375
|
async function register(here) {
|
|
357
376
|
const current = await watchersHash();
|
|
358
377
|
if (last && last.url === here && last.result.hash === current && Date.now() - last.at < REGISTER_EVERY_MS) return last.result;
|
|
359
|
-
registering ??= own.register({
|
|
360
|
-
|
|
378
|
+
registering ??= wakeAt(here).then((where) => own.register({
|
|
379
|
+
...where,
|
|
361
380
|
watch: specs,
|
|
362
381
|
...sync.length > 0 ? { sync } : {}
|
|
363
|
-
}).then((result) => {
|
|
382
|
+
})).then((result) => {
|
|
364
383
|
last = {
|
|
365
384
|
url: here,
|
|
366
385
|
at: Date.now(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as BoardError } from "./client-
|
|
2
|
-
import { t as createHttp } from "./backend-http-
|
|
1
|
+
import { t as BoardError } from "./client-ClznIBMg.mjs";
|
|
2
|
+
import { t as createHttp } from "./backend-http-CG5y03UP.mjs";
|
|
3
3
|
import { execFile } from "node:child_process";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -120,7 +120,15 @@ const expiry = (token) => {
|
|
|
120
120
|
return Date.now() + 3e5;
|
|
121
121
|
}
|
|
122
122
|
};
|
|
123
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Where `audience`'s token is cached: one per board, and with a login the Vercel CLI hands over
|
|
125
|
+
* (`VERCEL_AUTH_TOKEN`), one per login too, since it can be someone else's than `vercel login`'s.
|
|
126
|
+
*/
|
|
127
|
+
const cacheFile = (audience) => {
|
|
128
|
+
const login = process.env.VERCEL_AUTH_TOKEN;
|
|
129
|
+
const key = login ? `${audience}\n${login}` : audience;
|
|
130
|
+
return join(configDir(), "tokens", `${createHash("sha256").update(key).digest("hex").slice(0, 32)}.json`);
|
|
131
|
+
};
|
|
124
132
|
async function readCache(audience) {
|
|
125
133
|
try {
|
|
126
134
|
const cached = JSON.parse(await readFile(cacheFile(audience), "utf8"));
|
|
@@ -137,6 +145,11 @@ async function writeCache(audience, cached) {
|
|
|
137
145
|
await writeFile(cacheFile(audience), JSON.stringify(cached), { mode: 384 });
|
|
138
146
|
}
|
|
139
147
|
/**
|
|
148
|
+
* Your Vercel login: what the Vercel CLI hands a CLI it runs, as `vercel board` (`VERCEL_AUTH_TOKEN`,
|
|
149
|
+
* from its `--token` or its own login), or else what `vercel login` saved.
|
|
150
|
+
*/
|
|
151
|
+
const vercelLogin = () => process.env.VERCEL_AUTH_TOKEN ? Promise.resolve(process.env.VERCEL_AUTH_TOKEN) : getVercelToken();
|
|
152
|
+
/**
|
|
140
153
|
* A person's token: their Vercel CLI login mints a development token for the
|
|
141
154
|
* project the board's host is a deployment of, exchanged so its audience is the
|
|
142
155
|
* board's URL. Cached on disk for its 12-hour life.
|
|
@@ -144,7 +157,7 @@ async function writeCache(audience, cached) {
|
|
|
144
157
|
async function personToken(audience, discovery) {
|
|
145
158
|
const cached = await readCache(audience);
|
|
146
159
|
if (cached && cached.name === void 0) {
|
|
147
|
-
const user = await
|
|
160
|
+
const user = await vercelLogin().then(vercelUser).catch(() => null);
|
|
148
161
|
const filled = {
|
|
149
162
|
...cached,
|
|
150
163
|
name: user?.name ?? null,
|
|
@@ -155,7 +168,7 @@ async function personToken(audience, discovery) {
|
|
|
155
168
|
}
|
|
156
169
|
if (cached) return cached;
|
|
157
170
|
if (!discovery.project_id) throw new BoardError("no_project", `the board at ${discovery.url} doesn't know its Vercel project`, 0);
|
|
158
|
-
const authToken = await
|
|
171
|
+
const authToken = await vercelLogin().catch(() => null);
|
|
159
172
|
const project = await boardProject(audience, discovery, authToken);
|
|
160
173
|
let development;
|
|
161
174
|
try {
|
|
@@ -517,7 +530,7 @@ async function projectBypass(url, host, doFetch) {
|
|
|
517
530
|
const blocked = (why) => new BoardError("protected", `${url} is behind Vercel Deployment Protection, and your Vercel login ${why}, or set VERCEL_AUTOMATION_BYPASS_SECRET (${WHERE})`, 0);
|
|
518
531
|
let api;
|
|
519
532
|
try {
|
|
520
|
-
const token = await
|
|
533
|
+
const token = await vercelLogin();
|
|
521
534
|
api = async (method, path) => {
|
|
522
535
|
const response = await doFetch(`https://api.vercel.com${path}`, {
|
|
523
536
|
method,
|
package/dist/backend-http.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as HttpOptions, t as HttpBackend } from "./backend-http-
|
|
1
|
+
import { n as HttpOptions, t as HttpBackend } from "./backend-http-BfWQfvqB.mjs";
|
|
2
2
|
//#region src/backend-http/index.default.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* The board at `url`, which keeps the log. Outside Node there's no environment to find it or a
|
package/dist/backend-http.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as http } from "./index.default-
|
|
1
|
+
import { t as http } from "./index.default-C3luVnd-.mjs";
|
|
2
2
|
export { http };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as HttpOptions, t as HttpBackend } from "./backend-http-
|
|
1
|
+
import { n as HttpOptions, t as HttpBackend } from "./backend-http-BfWQfvqB.mjs";
|
|
2
2
|
//#region src/backend-http/index.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* The board at `url`, which keeps the log: this board uses it as this deployment. Without a
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as http } from "./backend-http-
|
|
1
|
+
import { t as http } from "./backend-http-c-VHpUOs.mjs";
|
|
2
2
|
export { http };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as ExternalFile, f as ExternalLink, l as ExternalAuthor, t as Actor } from "./folds-CRYY14kc.mjs";
|
|
2
|
-
import { M as SyncRoot, O as ProviderEvent, Wt as
|
|
2
|
+
import { M as SyncRoot, O as ProviderEvent, Wt as SourceJoin, a as ProviderOptions, c as ReceivedEvent, d as ResolvedTarget, i as ProviderFile, n as FileDelivery, o as ProviderPost, p as SyncProvider, qt as SourceRead, r as ProviderDelivery, s as Receive, t as FetchedLink, y as SyncFn } from "./provider-D11Dfda0.mjs";
|
|
3
3
|
import { Adapter, Author, FileUpload, Message, ReactionEvent } from "chat";
|
|
4
4
|
//#region src/sync/types.d.ts
|
|
5
5
|
declare function externalAuthor(platform: string, author: Author): ExternalAuthor;
|
|
@@ -45,6 +45,8 @@ type ChatTransport = Omit<ProviderOptions, 'uploadsFiles'> & {
|
|
|
45
45
|
read?(target: string, options: {
|
|
46
46
|
limit: number;
|
|
47
47
|
}): Promise<SourceRead>;
|
|
48
|
+
/** Adds the app to a channel so `read` can read it. */
|
|
49
|
+
join?(target: string): Promise<SourceJoin>;
|
|
48
50
|
avatar?(message: Message): Promise<string | null>;
|
|
49
51
|
fetchRoot?(thread: string): Promise<Omit<SyncRoot, 'raw'> & {
|
|
50
52
|
raw?: unknown;
|
|
@@ -124,6 +126,7 @@ declare abstract class ChatSyncProvider<E extends ProviderEvent = ProviderEvent>
|
|
|
124
126
|
read(target: string, options: {
|
|
125
127
|
limit: number;
|
|
126
128
|
}): Promise<SourceRead>;
|
|
129
|
+
join(target: string): Promise<SourceJoin>;
|
|
127
130
|
fetchFile(file: ExternalFile): Promise<Uint8Array | null>;
|
|
128
131
|
post(target: string, kind: ResolvedTarget['kind'], { as: _sender, files, ...body }: ProviderPost): Promise<ProviderDelivery>;
|
|
129
132
|
whoAmI(token: string): Promise<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./external-BV_cUncs.mjs";
|
|
2
|
-
import { n as ResolvedTarget, r as SyncProvider } from "./provider-
|
|
2
|
+
import { n as ResolvedTarget, r as SyncProvider } from "./provider-poIkXapd.mjs";
|
|
3
3
|
import { n as userTokensOf } from "./users-yryHKFMo.mjs";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
import { Chat, stringifyMarkdown } from "chat";
|
|
@@ -312,6 +312,9 @@ var ChatSyncProvider = class extends SyncProvider {
|
|
|
312
312
|
async read(target, options) {
|
|
313
313
|
return this.transport.read ? this.transport.read(target, options) : super.read(target, options);
|
|
314
314
|
}
|
|
315
|
+
async join(target) {
|
|
316
|
+
return this.transport.join ? this.transport.join(target) : super.join(target);
|
|
317
|
+
}
|
|
315
318
|
async fetchFile(file) {
|
|
316
319
|
const fetch = (await this.ready()).rehydrateAttachment?.({ ...this.transport.fileToFetch?.(file) ?? file }).fetchData;
|
|
317
320
|
if (!fetch) return null;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import "./provider-D11Dfda0.mjs";
|
|
2
|
+
import { d as Board } from "./backend-CWmd4UH-.mjs";
|
|
3
|
+
import "./index-DsMPCv_K.mjs";
|
|
4
|
+
//#region src/cli/main.d.ts
|
|
5
|
+
/** The command word: the first argument that isn't a flag or a string flag's value. */
|
|
6
|
+
export declare function commandWord(args: string[]): string | undefined;
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/cli/embedded.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* Board's CLI as `appName` names it in help, usage, and errors (`vercel board`). An agent's hook
|
|
11
|
+
* runs it the same way, by that name. `run` takes what follows the name, and answers the exit code:
|
|
12
|
+
* 0 success, 1 error, 2 misuse, 124 when `wait` times out. It never exits the process itself. One `run`
|
|
13
|
+
* at a time: a run's flags are the CLI's while it runs.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createApp(options: {
|
|
16
|
+
appName: string;
|
|
17
|
+
}): {
|
|
18
|
+
run(args: string[]): Promise<number>;
|
|
19
|
+
};
|
|
20
|
+
/** Where a `vb()` command's files come from and go, and what stops it. A command that needs one it lacks says so. */
|
|
21
|
+
export type VbOptions = {
|
|
22
|
+
/** A file's bytes, for `--attach`; null when there's no such file. */
|
|
23
|
+
readFile?: (path: string) => Promise<Uint8Array | null> | PromiseLike<Uint8Array | null>;
|
|
24
|
+
/** Saves a file, for `download`. */
|
|
25
|
+
writeFile?: (path: string, data: Uint8Array) => Promise<void> | PromiseLike<void>;
|
|
26
|
+
/** The text `-` reads, as stdin would hold it. */
|
|
27
|
+
stdin?: string;
|
|
28
|
+
/** Stops `tail` and `wait`, as Ctrl-C does. */
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
/** Commands this caller doesn't run, which answer 2: `['tail', 'wait']` for an agent's tool. */
|
|
31
|
+
refuse?: string[];
|
|
32
|
+
};
|
|
33
|
+
/** What a `vb()` command printed, and its exit code: 0, 1 for an error, 2 for misuse, 124 when `wait` timed out. */
|
|
34
|
+
export type VbResult = {
|
|
35
|
+
code: number;
|
|
36
|
+
stdout: string;
|
|
37
|
+
stderr: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Runs the vb command `argv` (`['read', '42']`, `['reply', '42', 'on it']`) on `board`, in this
|
|
41
|
+
* process, and returns what the CLI would print. `board` already says which board and who, so
|
|
42
|
+
* `--url` and `--handle` don't apply, and the commands about your machine (`link`, `use`, `whoami`,
|
|
43
|
+
* `identity`, `hooks`, `serve`, `inspect`) answer 2. Calls run one at a time, in order, so
|
|
44
|
+
* `tail` and `wait`, which hold the rest until they end, need `options.signal`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function vb(board: Board, argv: string[], options?: VbOptions): Promise<VbResult>;
|
|
47
|
+
//#endregion
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { n as main, r as mainWith, t as commandWord } from "./main-wB-VfTCL.mjs";
|
|
2
|
+
//#region src/cli/embedded.ts
|
|
3
|
+
/**
|
|
4
|
+
* Board's CLI as `appName` names it in help, usage, and errors (`vercel board`). An agent's hook
|
|
5
|
+
* runs it the same way, by that name. `run` takes what follows the name, and answers the exit code:
|
|
6
|
+
* 0 success, 1 error, 2 misuse, 124 when `wait` times out. It never exits the process itself. One `run`
|
|
7
|
+
* at a time: a run's flags are the CLI's while it runs.
|
|
8
|
+
*/
|
|
9
|
+
function createApp(options) {
|
|
10
|
+
return { run: (args) => main(args, {
|
|
11
|
+
name: options.appName,
|
|
12
|
+
command: options.appName,
|
|
13
|
+
commands: {}
|
|
14
|
+
}) };
|
|
15
|
+
}
|
|
16
|
+
const lacking = (what) => async () => {
|
|
17
|
+
throw new Error(`${what}: pass it in vb()'s options`);
|
|
18
|
+
};
|
|
19
|
+
let queue = Promise.resolve();
|
|
20
|
+
/**
|
|
21
|
+
* Runs the vb command `argv` (`['read', '42']`, `['reply', '42', 'on it']`) on `board`, in this
|
|
22
|
+
* process, and returns what the CLI would print. `board` already says which board and who, so
|
|
23
|
+
* `--url` and `--handle` don't apply, and the commands about your machine (`link`, `use`, `whoami`,
|
|
24
|
+
* `identity`, `hooks`, `serve`, `inspect`) answer 2. Calls run one at a time, in order, so
|
|
25
|
+
* `tail` and `wait`, which hold the rest until they end, need `options.signal`.
|
|
26
|
+
*/
|
|
27
|
+
function vb(board, argv, options = {}) {
|
|
28
|
+
const word = commandWord(argv);
|
|
29
|
+
if (word !== void 0 && options.refuse?.includes(word)) return Promise.resolve({
|
|
30
|
+
code: 2,
|
|
31
|
+
stdout: "",
|
|
32
|
+
stderr: `error: ${word} isn't available here\n`
|
|
33
|
+
});
|
|
34
|
+
if ((word === "tail" || word === "wait") && !options.signal) return Promise.resolve({
|
|
35
|
+
code: 2,
|
|
36
|
+
stdout: "",
|
|
37
|
+
stderr: `error: ${word} runs until it's stopped, and vb() runs one call at a time: pass a signal\n`
|
|
38
|
+
});
|
|
39
|
+
const result = queue.then(async () => {
|
|
40
|
+
let stdout = "";
|
|
41
|
+
let stderr = "";
|
|
42
|
+
const decoder = new TextDecoder();
|
|
43
|
+
return {
|
|
44
|
+
code: await mainWith(argv, {
|
|
45
|
+
name: "board",
|
|
46
|
+
commands: {}
|
|
47
|
+
}, {
|
|
48
|
+
board,
|
|
49
|
+
write: (chunk) => void (stdout += typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true })),
|
|
50
|
+
error: (chunk) => void (stderr += chunk),
|
|
51
|
+
readFile: options.readFile ? async (path) => options.readFile(path) : lacking("--attach reads files"),
|
|
52
|
+
writeFile: options.writeFile ? async (path, data) => options.writeFile(path, data) : lacking("download saves files"),
|
|
53
|
+
stdin: options.stdin !== void 0 ? async () => options.stdin : lacking("- reads stdin"),
|
|
54
|
+
...options.signal ? { signal: options.signal } : {}
|
|
55
|
+
}),
|
|
56
|
+
stdout,
|
|
57
|
+
stderr
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
queue = result.catch(() => {});
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { commandWord, createApp, vb };
|