@vercel/board 0.28.0 → 0.30.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-B0_VlbtC.mjs → a2-D_28Pdip.mjs} +197 -259
- package/dist/access-CQ39gqEV.mjs +226 -0
- package/dist/access.d.mts +1 -1
- package/dist/access.mjs +3 -3
- package/dist/{actors-BLXVp4oZ.mjs → actors-xPiamLWk.mjs} +3 -3
- package/dist/{auth-lTkOgvcE.mjs → auth-BPinwfN0.mjs} +3 -226
- package/dist/backend-a2/blob-vercel.d.mts +1 -1
- package/dist/backend-a2/contract.d.mts +2 -2
- package/dist/backend-a2/contract.mjs +3 -3
- 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 +3 -3
- package/dist/backend-a2/scheduler-qstash.mjs +8 -8
- package/dist/backend-a2/scheduler-vercel.d.mts +3 -3
- package/dist/backend-a2/scheduler-vercel.mjs +6 -6
- 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 +34 -15
- package/dist/backend-a2/store-redis-http.d.mts +1 -1
- package/dist/backend-a2/store-redis-http.mjs +6 -6
- package/dist/backend-a2/store-redis.d.mts +2 -2
- package/dist/backend-a2/store-redis.mjs +5 -5
- 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 +20 -7
- package/dist/backend-a2.mjs +2 -1
- package/dist/{backend-http-BvNFrvcY.mjs → backend-http-16SbvnAK.mjs} +2 -2
- package/dist/{backend-http-E7YU0qhn.d.mts → backend-http-3PoBYQoo.d.mts} +15 -3
- package/dist/{backend-http-CfLVYqmj.mjs → backend-http-BPaNYLWj.mjs} +4 -5
- 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/{backend-ZKYTe3xa.d.mts → backend-n3hajfrD.d.mts} +12 -6
- package/dist/{backend-vercel-D87pIp2k.mjs → backend-vercel-C4Kee2-K.mjs} +260 -30
- package/dist/{backend-vercel-DTrDiSk5.mjs → backend-vercel-Kd8nvW5A.mjs} +3 -3
- package/dist/{backend-vercel-CIRObA0t.d.mts → backend-vercel-qznuDxnN.d.mts} +20 -5
- package/dist/backend-vercel.d.mts +1 -1
- package/dist/backend-vercel.mjs +1 -1
- package/dist/backend-vercel.node.d.mts +1 -1
- package/dist/backend-vercel.node.mjs +1 -1
- package/dist/{blob-B-9AvYis.d.mts → blob-CqILvdmr.d.mts} +2 -2
- package/dist/blob-DQK5prXT.mjs +182 -0
- package/dist/{chat-provider-DnHibqnM.mjs → chat-provider-COtsU5jB.mjs} +2 -2
- package/dist/{chat-provider-DsNEBQiA.d.mts → chat-provider-D6jVT4wS.d.mts} +5 -3
- package/dist/cli-commands.d.mts +1 -1
- package/dist/cli-commands.mjs +1 -1
- package/dist/cli-embedded.d.mts +2 -2
- package/dist/cli-embedded.mjs +1 -1
- package/dist/cli.mjs +5 -5
- package/dist/{client-xLxeDz0f.d.mts → client-CjAatpV4.d.mts} +67 -10
- package/dist/{commands-BFookFtn.mjs → commands-B5DHjZKK.mjs} +54 -10
- package/dist/{commands-D6gvrOh3.d.mts → commands-BtH69yqt.d.mts} +17 -0
- package/dist/{conformance-DlnfuzEB.mjs → conformance-C7fwIvmN.mjs} +258 -18
- package/dist/conformance.d.mts +1 -1
- package/dist/conformance.mjs +1 -1
- package/dist/{engine-Bfe6pcXb.mjs → engine-DkdkXQEy.mjs} +21 -13
- package/dist/{errors-CB4tnZGz.d.mts → errors-87TVtXeb.d.mts} +1 -1
- package/dist/{client-D0Px7KzF.mjs → errors-C_5rB8Iz.mjs} +104 -4
- package/dist/{events-CewD4kw7.mjs → events-qf5XG5VQ.mjs} +2 -2
- package/dist/{exports-CCzw2Vdw.mjs → exports-CG0P8Qi4.mjs} +59 -33
- package/dist/exports-CrGA5_yN.d.mts +5 -0
- package/dist/{external-BV_cUncs.mjs → external-D3p5T57R.mjs} +4 -2
- package/dist/{folds-jS9wlh9_.d.mts → folds-8wRRXjAt.d.mts} +4 -0
- package/dist/{folds-Dyjput8M.mjs → folds-DGYkMW19.mjs} +3 -2
- package/dist/{index-C05it0mC.d.mts → index-BygAXP7t.d.mts} +2 -2
- package/dist/index.d.mts +6 -6
- package/dist/{index.default-DmKxH_E6.mjs → index.default-DhkgpfR2.mjs} +1 -1
- package/dist/index.mjs +5 -6
- package/dist/index.node.d.mts +6 -6
- package/dist/index.node.mjs +3 -4
- package/dist/inspect/app.js +29 -29
- package/dist/inspect/engine.js +5 -5
- package/dist/{internal-CvsrprnU-CRY89I-b.mjs → internal-CvsrprnU-zZMpDiRY.mjs} +1 -1
- package/dist/{local-DhkrAqPP.mjs → local-C76Fy5ad.mjs} +1 -1
- package/dist/{main-eci7w-aP.mjs → main-D2s-QBOK.mjs} +76 -26
- package/dist/{middleware-ChKM1zuu.mjs → middleware-DlJQYiwV.mjs} +2 -2
- package/dist/{node-Zd_C-gxP.mjs → node-D8Rtg1su.mjs} +1 -1
- package/dist/{platform-B4TnJtWu-CwcTyKg2.mjs → platform-B4TnJtWu-Do3agKr5.mjs} +1 -1
- package/dist/{project-DMDST9kl.mjs → project-C_2xs57L.mjs} +1 -1
- package/dist/{provider-poIkXapd.mjs → provider-BaVmi4Hi.mjs} +3 -1
- package/dist/{provider-Cdg1qadh.d.mts → provider-Bm46LAdp.d.mts} +9 -2
- package/dist/{redis-tables-DN9PfIDi.mjs → redis-tables-BWJZHUGg.mjs} +41 -25
- package/dist/{reducer-CjmvZSAb-D_OSISmj.mjs → reducer-Bswr11ar-P324o9vn.mjs} +2 -2
- package/dist/{reducer-CYPHsSmd-BQIfozGi.d.mts → reducer-CYPHsSmd-BXjGiptm.d.mts} +1 -1
- package/dist/{reducers-BcmSs4qf.mjs → reducers-8jqLewgw.mjs} +5 -5
- package/dist/{retryable-lazy-DZWmHpii-Bye-W8q7.mjs → retryable-lazy-DZWmHpii-DpTc5PIP.mjs} +1 -1
- package/dist/{scheduler-task-X1SToDjP-BVoWuInI.mjs → scheduler-task-X1SToDjP-D2Il2rln.mjs} +1 -1
- package/dist/{schemas-Be08nyfW.mjs → schemas-DBmUO6pr.mjs} +2 -1
- package/dist/{serve-B09an9DQ.mjs → serve-lPoBDEds.mjs} +7 -6
- package/dist/{server-qgez0Xny-D5mLfqFQ.d.mts → server-B9gu0qi1-DI1WvcVK.d.mts} +10 -4
- package/dist/{server-DTX0prGr.mjs → server-D82a4uMe.mjs} +4 -4
- package/dist/{server-DtFrWxi3-Boa6gdWO.mjs → server-DX7mM6nm-D7N_7bug.mjs} +32 -23
- package/dist/{serving-CvOWEym2.mjs → serving-DKny38LK.mjs} +1 -1
- package/dist/{session-clear-wHd5GCpZ-BnKSxReK.mjs → session-clear-XJYpmUpg-2q8l_FJR.mjs} +14 -2
- package/dist/{sql-U9WTxrwJ.mjs → sql-Bj0fk6dn.mjs} +2 -2
- package/dist/{sqlite-db-Ds4majtT.mjs → sqlite-db-Dc8G78XV.mjs} +1 -1
- package/dist/{store-D0MhBvg6-4Z2L0Kqd.d.mts → store-DEzcHZOA-B-5vhxef.d.mts} +12 -2
- package/dist/store-N8PXxDAS-DWWgv-Vz.mjs +5 -0
- package/dist/{store-codec-DwrWlgQx-CYxGW0aD.mjs → store-codec-pAG2oPgQ-SqDXlPBR.mjs} +4 -4
- package/dist/store-memory-4IBl0Ztu.mjs +2 -0
- package/dist/{store-memory-Bas9Uq5C.mjs → store-memory-B0PkVSuQ.mjs} +14 -7
- package/dist/{store-polling-BZt2Rf3D-BiEM6_HB.mjs → store-polling-BZt2Rf3D-Div-bJ_D.mjs} +2 -2
- package/dist/{store-presence-polling-JuAy2Ck2-CYpuK75X.mjs → store-presence-polling-JuAy2Ck2-Dh-g_KYM.mjs} +3 -3
- package/dist/{store-sqlite-CxxPCcCT.mjs → store-sqlite-D85t3tE7.mjs} +14 -7
- package/dist/store-sqlite-iBTYYKBj.mjs +2 -0
- package/dist/{stream-buffer-DrTyiIuo-BKy-vI14.mjs → stream-buffer-DrTyiIuo-Be10yOBR.mjs} +2 -2
- package/dist/sync-github.d.mts +4 -2
- package/dist/sync-github.mjs +4 -14
- package/dist/sync-kapso.d.mts +3 -2
- package/dist/sync-kapso.mjs +3 -3
- package/dist/sync-linear.d.mts +12 -2
- package/dist/sync-linear.mjs +191 -9
- package/dist/sync-slack.d.mts +41 -5
- package/dist/sync-slack.mjs +70 -11
- package/dist/sync.chat.d.mts +1 -1
- package/dist/sync.chat.mjs +1 -1
- package/dist/sync.d.mts +2 -2
- package/dist/sync.mjs +3 -3
- package/dist/tags-BpFo6q0_.mjs +14 -0
- package/dist/{targets-C-wdR5wP.mjs → targets-Cgjs29T0.mjs} +1 -1
- package/dist/{tokens-BuCU-61R.mjs → tokens-C5_yGRlL.mjs} +2 -2
- package/dist/{types-aCAf6lGU.d.mts → types-shZmGZ-q.d.mts} +2 -2
- package/dist/{watchers-hash-7DJU9b-n.mjs → watchers-hash-B_5b0-ZG.mjs} +50 -19
- package/docs/01-board/04-messages.md +93 -0
- package/docs/01-board/08-middleware.md +5 -2
- package/docs/02-sync/03-slack.md +6 -2
- package/docs/02-sync/07-linear.md +28 -6
- package/docs/04-reference/01-cli.md +27 -12
- package/docs/04-reference/02-board.md +20 -5
- package/docs/04-reference/03-http.md +17 -6
- package/docs/04-reference/05-conformance.md +14 -3
- package/package.json +2 -2
- package/dist/errors-CusN4x2l.mjs +0 -88
- package/dist/exports-D22M68rk.d.mts +0 -5
- package/dist/store-N8PXxDAS-BWBgzBHp.mjs +0 -5
- package/dist/store-memory-ZLiZbH3R.mjs +0 -2
- package/dist/store-sqlite-BmwL3pUR.mjs +0 -2
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { n as DIRECT_UPLOAD_BYTES_MAX, t as ATTACHMENT_BYTES_MAX } from "./files-SniSmeEr.mjs";
|
|
2
|
+
import { i as Attachment } from "./schemas-DBmUO6pr.mjs";
|
|
3
|
+
import { r as badRequest, s as notFound, t as HttpError } from "./errors-C_5rB8Iz.mjs";
|
|
4
|
+
import { randomBytes } from "node:crypto";
|
|
5
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
//#region src/server/blob.ts
|
|
8
|
+
/** Files in memory, for tests: forgets everything when the process ends. */
|
|
9
|
+
function memoryBlob() {
|
|
10
|
+
const files = /* @__PURE__ */ new Map();
|
|
11
|
+
return {
|
|
12
|
+
put: async (key, data, contentType) => void files.set(key, {
|
|
13
|
+
data: data.slice(),
|
|
14
|
+
contentType
|
|
15
|
+
}),
|
|
16
|
+
get: async (key) => files.get(key) ?? null
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Files on disk, for development and `vb serve`: under `dir`, `.a2/attachments` by default. */
|
|
20
|
+
function fsBlob(dir = ".a2/attachments") {
|
|
21
|
+
const path = (key) => join(dir, ...key.split("/"));
|
|
22
|
+
return {
|
|
23
|
+
async put(key, data, contentType) {
|
|
24
|
+
await mkdir(dirname(path(key)), { recursive: true });
|
|
25
|
+
await writeFile(path(key), data);
|
|
26
|
+
await writeFile(`${path(key)}.type`, contentType);
|
|
27
|
+
},
|
|
28
|
+
async get(key) {
|
|
29
|
+
try {
|
|
30
|
+
const [data, contentType] = await Promise.all([readFile(path(key)), readFile(`${path(key)}.type`, "utf8")]);
|
|
31
|
+
return {
|
|
32
|
+
data: new Uint8Array(data),
|
|
33
|
+
contentType
|
|
34
|
+
};
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const dataKey = (id) => `board/attachments/${id}`;
|
|
42
|
+
/** A direct upload the board signed, until it's finished: what it's called, and who may finish it. */
|
|
43
|
+
const ticketKey = (id) => `board/uploads/${id}.json`;
|
|
44
|
+
const metaKey = (id) => `board/attachments/${id}.json`;
|
|
45
|
+
/** `shot.png`, as the board stores a name: no paths, no control characters. */
|
|
46
|
+
function fileName(name) {
|
|
47
|
+
return (name ?? "").split(/[\\/]/).pop().replace(/[\u0000-\u001f\u007f]/g, "").trim().slice(0, 255) || "file";
|
|
48
|
+
}
|
|
49
|
+
/** `image/png`, or `application/octet-stream` when the type isn't one. */
|
|
50
|
+
function mediaType(type) {
|
|
51
|
+
const value = (type ?? "").split(";")[0].trim().toLowerCase();
|
|
52
|
+
return /^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*$/.test(value) && value.length <= 255 ? value : "application/octet-stream";
|
|
53
|
+
}
|
|
54
|
+
/** A board without a blob store keeps no files: every file route says so. */
|
|
55
|
+
const noBlob = () => new HttpError(501, "no_files", "this board keeps no files: pass `blob` to `a2()`");
|
|
56
|
+
/** 128 random bits, base64url, drawn again when they'd start with `-`, which a command line reads as a flag. */
|
|
57
|
+
function attachmentId() {
|
|
58
|
+
for (;;) {
|
|
59
|
+
const id = randomBytes(16).toString("base64url");
|
|
60
|
+
if (!id.startsWith("-")) return id;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Stores an upload under a fresh ID, with its metadata beside it. `uploadedBy`
|
|
65
|
+
* is the principal that sent it, who can read it before any message carries it.
|
|
66
|
+
* `max` is the most it can be: `ATTACHMENT_BYTES_MAX` unless the board's own sync imports it.
|
|
67
|
+
*/
|
|
68
|
+
async function writeUpload(blob, input, max = ATTACHMENT_BYTES_MAX) {
|
|
69
|
+
if (!blob) throw noBlob();
|
|
70
|
+
if (input.data.byteLength === 0) throw badRequest("the file is empty");
|
|
71
|
+
if (input.data.byteLength > max) throw new HttpError(413, "too_large", `attachments are at most ${max / 1024 / 1024} MB`);
|
|
72
|
+
const attachment = {
|
|
73
|
+
id: attachmentId(),
|
|
74
|
+
name: fileName(input.name),
|
|
75
|
+
type: mediaType(input.type),
|
|
76
|
+
size: input.data.byteLength
|
|
77
|
+
};
|
|
78
|
+
await blob.put(dataKey(attachment.id), input.data, attachment.type);
|
|
79
|
+
const meta = input.uploadedBy === void 0 ? attachment : {
|
|
80
|
+
...attachment,
|
|
81
|
+
uploadedBy: input.uploadedBy
|
|
82
|
+
};
|
|
83
|
+
await blob.put(metaKey(attachment.id), new TextEncoder().encode(JSON.stringify(meta)), "application/json");
|
|
84
|
+
return attachment;
|
|
85
|
+
}
|
|
86
|
+
async function bytes(data) {
|
|
87
|
+
return data instanceof Uint8Array ? data : new Uint8Array(await new Response(data).arrayBuffer());
|
|
88
|
+
}
|
|
89
|
+
const attachmentNotFound = (id) => notFound(`no attachment: ${id}`, "attachment_not_found");
|
|
90
|
+
/**
|
|
91
|
+
* An upload's metadata, as the board recorded it, never what a request says,
|
|
92
|
+
* and who uploaded it: null for files the board imported itself, or stored
|
|
93
|
+
* before it recorded that.
|
|
94
|
+
*/
|
|
95
|
+
async function readUpload(blob, id) {
|
|
96
|
+
if (!blob) throw noBlob();
|
|
97
|
+
const found = Attachment.shape.id.safeParse(id).success ? await blob.get(metaKey(id)) : null;
|
|
98
|
+
if (!found) throw attachmentNotFound(id);
|
|
99
|
+
const meta = JSON.parse(new TextDecoder().decode(await bytes(found.data)));
|
|
100
|
+
return {
|
|
101
|
+
attachment: Attachment.parse(meta),
|
|
102
|
+
uploadedBy: typeof meta.uploadedBy === "string" ? meta.uploadedBy : null
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** An attachment's bytes as the store keeps them, a stream or the bytes, for board() to serve. */
|
|
106
|
+
async function attachmentBody(blob, id) {
|
|
107
|
+
if (!blob) throw noBlob();
|
|
108
|
+
const found = await blob.get(dataKey(id));
|
|
109
|
+
if (!found) throw attachmentNotFound(id);
|
|
110
|
+
return found.data;
|
|
111
|
+
}
|
|
112
|
+
/** How long a direct upload's URL takes bytes: long enough for 100 MB on a slow link. */
|
|
113
|
+
const DIRECT_UPLOAD_TTL_MS = 18e5;
|
|
114
|
+
const noDirectUploads = () => new HttpError(501, "no_direct_uploads", `this board's blob store can't take direct uploads, so files are at most ${ATTACHMENT_BYTES_MAX / 1024 / 1024} MB`);
|
|
115
|
+
/**
|
|
116
|
+
* Starts a direct upload: a fresh ID, and a URL in the store to `PUT` its bytes to. The board
|
|
117
|
+
* keeps what the request said the file is until `finishUpload` checks the store has it.
|
|
118
|
+
*/
|
|
119
|
+
async function startUpload(blob, input) {
|
|
120
|
+
if (!blob) throw noBlob();
|
|
121
|
+
if (!blob.uploadUrl || !blob.head) throw noDirectUploads();
|
|
122
|
+
if (input.size > 104857600) throw new HttpError(413, "too_large", `direct uploads are at most ${DIRECT_UPLOAD_BYTES_MAX / 1024 / 1024} MB`);
|
|
123
|
+
const expires = new Date(Date.now() + DIRECT_UPLOAD_TTL_MS);
|
|
124
|
+
const ticket = {
|
|
125
|
+
id: attachmentId(),
|
|
126
|
+
name: fileName(input.name),
|
|
127
|
+
type: mediaType(input.type),
|
|
128
|
+
size: input.size,
|
|
129
|
+
uploadedBy: input.uploadedBy,
|
|
130
|
+
expiresAt: expires.toISOString()
|
|
131
|
+
};
|
|
132
|
+
await blob.put(ticketKey(ticket.id), new TextEncoder().encode(JSON.stringify(ticket)), "application/json");
|
|
133
|
+
const { url, headers } = await blob.uploadUrl(dataKey(ticket.id), {
|
|
134
|
+
contentType: ticket.type,
|
|
135
|
+
maxBytes: ticket.size,
|
|
136
|
+
expiresAt: expires
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
id: ticket.id,
|
|
140
|
+
url,
|
|
141
|
+
headers: {
|
|
142
|
+
...headers,
|
|
143
|
+
"content-type": ticket.type
|
|
144
|
+
},
|
|
145
|
+
expiresAt: ticket.expiresAt
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Finishes a direct upload: once the store has exactly the bytes its start said, the board records
|
|
150
|
+
* the attachment, as `writeUpload` does. Only its uploader may finish it; a second finish answers
|
|
151
|
+
* the same attachment. It never reads the record before writing it: a store with a cache (Vercel
|
|
152
|
+
* Blob's CDN) would keep that miss, and the post that names the file would find nothing.
|
|
153
|
+
*/
|
|
154
|
+
async function finishUpload(blob, id, principal) {
|
|
155
|
+
if (!blob) throw noBlob();
|
|
156
|
+
const found = Attachment.shape.id.safeParse(id).success ? await blob.get(ticketKey(id)) : null;
|
|
157
|
+
const ticket = found ? JSON.parse(new TextDecoder().decode(await bytes(found.data))) : null;
|
|
158
|
+
if (!ticket || ticket.uploadedBy !== principal) throw notFound(`no upload: ${id}`, "upload_not_found");
|
|
159
|
+
if (!blob.head) throw noDirectUploads();
|
|
160
|
+
const stored = await blob.head(dataKey(id));
|
|
161
|
+
if (!stored) throw new HttpError(409, "not_uploaded", `nothing's been uploaded for ${id} yet: PUT the file to its URL first`);
|
|
162
|
+
if (stored.size !== ticket.size) throw badRequest(`the store has ${stored.size} bytes for ${id}, but its upload said ${ticket.size}`, "size_mismatch");
|
|
163
|
+
const attachment = {
|
|
164
|
+
id,
|
|
165
|
+
name: ticket.name,
|
|
166
|
+
type: ticket.type,
|
|
167
|
+
size: stored.size
|
|
168
|
+
};
|
|
169
|
+
try {
|
|
170
|
+
await blob.put(metaKey(id), new TextEncoder().encode(JSON.stringify({
|
|
171
|
+
...attachment,
|
|
172
|
+
uploadedBy: principal
|
|
173
|
+
})), "application/json");
|
|
174
|
+
} catch (error) {
|
|
175
|
+
const done = await blob.get(metaKey(id)).catch(() => null);
|
|
176
|
+
if (!done) throw error;
|
|
177
|
+
return Attachment.parse(JSON.parse(new TextDecoder().decode(await bytes(done.data))));
|
|
178
|
+
}
|
|
179
|
+
return attachment;
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
export { fsBlob as a, readUpload as c, finishUpload as i, startUpload as l, attachmentNotFound as n, mediaType as o, fileName as r, memoryBlob as s, attachmentBody as t, writeUpload as u };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./external-
|
|
2
|
-
import { n as ResolvedTarget, r as SyncProvider } from "./provider-
|
|
1
|
+
import "./external-D3p5T57R.mjs";
|
|
2
|
+
import { n as ResolvedTarget, r as SyncProvider } from "./provider-BaVmi4Hi.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";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { d as ExternalFile, f as ExternalLink, l as ExternalAuthor, t as Actor } from "./folds-
|
|
2
|
-
import {
|
|
3
|
-
import { M as SyncRoot, O as ProviderEvent, a as ProviderOptions, c as ReceivedEvent, d as ResolvedTarget, i as ProviderFile, n as FileDelivery, o as ProviderPost, p as SyncProvider, r as ProviderDelivery, s as Receive, t as FetchedLink, y as SyncFn } from "./provider-
|
|
1
|
+
import { d as ExternalFile, f as ExternalLink, l as ExternalAuthor, t as Actor } from "./folds-8wRRXjAt.mjs";
|
|
2
|
+
import { ft as SourceJoin, ht as SourceRead } from "./client-CjAatpV4.mjs";
|
|
3
|
+
import { M as SyncRoot, O as ProviderEvent, a as ProviderOptions, c as ReceivedEvent, d as ResolvedTarget, i as ProviderFile, n as FileDelivery, o as ProviderPost, p as SyncProvider, r as ProviderDelivery, s as Receive, t as FetchedLink, y as SyncFn } from "./provider-Bm46LAdp.mjs";
|
|
4
4
|
import { Adapter, Author, FileUpload, Message, ReactionEvent } from "chat";
|
|
5
5
|
//#region src/sync/types.d.ts
|
|
6
6
|
declare function externalAuthor(platform: string, author: Author): ExternalAuthor;
|
|
@@ -45,6 +45,7 @@ type ChatTransport = Omit<ProviderOptions, 'uploadsFiles'> & {
|
|
|
45
45
|
/** A channel or thread, read on demand without syncing it. */
|
|
46
46
|
read?(target: string, options: {
|
|
47
47
|
limit: number;
|
|
48
|
+
after: string | null;
|
|
48
49
|
}): Promise<SourceRead>;
|
|
49
50
|
/** Adds the app to a channel so `read` can read it. */
|
|
50
51
|
join?(target: string): Promise<SourceJoin>;
|
|
@@ -126,6 +127,7 @@ declare abstract class ChatSyncProvider<E extends ProviderEvent = ProviderEvent>
|
|
|
126
127
|
url(thread: string, message: string): Promise<string | null>;
|
|
127
128
|
read(target: string, options: {
|
|
128
129
|
limit: number;
|
|
130
|
+
after: string | null;
|
|
129
131
|
}): Promise<SourceRead>;
|
|
130
132
|
join(target: string): Promise<SourceJoin>;
|
|
131
133
|
fetchFile(file: ExternalFile): Promise<Uint8Array | null>;
|
package/dist/cli-commands.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as OptionName, c as globalOptions, d as options, f as usage, i as CliOption, l as groups, n as CliCommand, o as commands, r as CliExample, s as filters, t as CliArgument, u as option } from "./commands-
|
|
1
|
+
import { a as OptionName, c as globalOptions, d as options, f as usage, i as CliOption, l as groups, n as CliCommand, o as commands, r as CliExample, s as filters, t as CliArgument, u as option } from "./commands-BtH69yqt.mjs";
|
|
2
2
|
export { CliArgument, CliCommand, CliExample, CliOption, OptionName, commands, filters, globalOptions, groups, option, options, usage };
|
package/dist/cli-commands.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as option, i as groups, n as filters, o as options, r as globalOptions, s as usage, t as commands } from "./commands-
|
|
1
|
+
import { a as option, i as groups, n as filters, o as options, r as globalOptions, s as usage, t as commands } from "./commands-B5DHjZKK.mjs";
|
|
2
2
|
export { commands, filters, globalOptions, groups, option, options, usage };
|
package/dist/cli-embedded.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as Board } from "./backend-
|
|
2
|
-
import "./index-
|
|
1
|
+
import { d as Board } from "./backend-n3hajfrD.mjs";
|
|
2
|
+
import "./index-BygAXP7t.mjs";
|
|
3
3
|
//#region src/cli/failure.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* What kind of failure it is, which fixes the exit code: 2 for `usage` and `missing_input`, 130
|
package/dist/cli-embedded.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as commandLine, c as failureLines, i as mainWith, l as formatFailure, n as commandWord, o as exitCode, r as main, s as failureDocument, t as Failed } from "./main-
|
|
1
|
+
import { a as commandLine, c as failureLines, i as mainWith, l as formatFailure, n as commandWord, o as exitCode, r as main, s as failureDocument, t as Failed } from "./main-D2s-QBOK.mjs";
|
|
2
2
|
//#region src/cli/embedded.ts
|
|
3
3
|
/**
|
|
4
4
|
* Board's CLI as `appName` names it in help, usage, and errors (`vercel board`). With no board
|
package/dist/cli.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as ATTACHMENT_BYTES_MAX } from "./files-SniSmeEr.mjs";
|
|
3
|
-
import "./schemas-
|
|
4
|
-
import { a as option } from "./commands-
|
|
5
|
-
import { l as projectDir } from "./node-
|
|
6
|
-
import { r as main, u as who } from "./main-
|
|
3
|
+
import "./schemas-DBmUO6pr.mjs";
|
|
4
|
+
import { a as option } from "./commands-B5DHjZKK.mjs";
|
|
5
|
+
import { l as projectDir } from "./node-D8Rtg1su.mjs";
|
|
6
|
+
import { r as main, u as who } from "./main-D2s-QBOK.mjs";
|
|
7
7
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
8
8
|
import { appendFile, readFile } from "node:fs/promises";
|
|
9
9
|
import { join } from "node:path";
|
|
@@ -661,7 +661,7 @@ const local = {
|
|
|
661
661
|
if (args.length > 0) throw usage("serve takes no arguments: pass its port with --port, and its directory with --dir.");
|
|
662
662
|
const port = portFlag();
|
|
663
663
|
const root = projectDir();
|
|
664
|
-
const { localHandle, serveLocal } = await import("./serve-
|
|
664
|
+
const { localHandle, serveLocal } = await import("./serve-lPoBDEds.mjs");
|
|
665
665
|
const handle = flags.handle ?? process.env.BOARD_HANDLE;
|
|
666
666
|
const local = await serveLocal({
|
|
667
667
|
dir: flags.dir ?? join(root, ".board"),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { n as AccessSummary } from "./access-CV96SYgr.mjs";
|
|
2
|
-
import { a as ExternalCopy, g as BoardEvent, o as Message, p as Link, r as Channel, t as Actor, u as ExternalEvent, x as Attachment } from "./folds-
|
|
2
|
+
import { a as ExternalCopy, g as BoardEvent, o as Message, p as Link, r as Channel, t as Actor, u as ExternalEvent, x as Attachment } from "./folds-8wRRXjAt.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/api/routes.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* A message's, schedule's, or cursor's ID: a string clients pass back as they got it, and never
|
|
7
|
-
* parse, compare, or count with. Each backend picks its own; a board on `a2()` writes decimals
|
|
7
|
+
* parse, compare, or count with. Each backend picks its own; a board on `a2()` writes decimals,
|
|
8
|
+
* and `s12` for a schedule.
|
|
8
9
|
*/
|
|
9
10
|
declare const Ref: z.ZodString;
|
|
10
11
|
/** A sync target as the board that syncs it resolved it: a platform channel to start a thread in, or a thread to join. */
|
|
@@ -78,6 +79,7 @@ declare const PostBody: z.ZodObject<{
|
|
|
78
79
|
}, z.core.$strip>]>>>;
|
|
79
80
|
id: z.ZodOptional<z.ZodString>;
|
|
80
81
|
attachments: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
82
|
+
after: z.ZodOptional<z.ZodString>;
|
|
81
83
|
}, z.core.$strip>;
|
|
82
84
|
/**
|
|
83
85
|
* A message to post later, as the caller: once (`in` or `at`), or repeating
|
|
@@ -171,6 +173,7 @@ declare const AckBody: z.ZodObject<{
|
|
|
171
173
|
declare const SourceReadQuery: z.ZodObject<{
|
|
172
174
|
target: z.ZodString;
|
|
173
175
|
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
176
|
+
after: z.ZodOptional<z.ZodString>;
|
|
174
177
|
}, z.core.$strip>;
|
|
175
178
|
/** A channel to add the board's app to, so it can be read on demand: `#name`, an ID, or a link into it. */
|
|
176
179
|
declare const SourceJoinBody: z.ZodObject<{
|
|
@@ -231,6 +234,7 @@ declare const SyncImportBody: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
231
234
|
message: z.ZodNullable<z.ZodString>;
|
|
232
235
|
}, z.core.$strip>>>;
|
|
233
236
|
id: z.ZodOptional<z.ZodString>;
|
|
237
|
+
after: z.ZodOptional<z.ZodString>;
|
|
234
238
|
}, z.core.$strip>, z.ZodObject<{
|
|
235
239
|
author: z.ZodObject<{
|
|
236
240
|
id: z.ZodString;
|
|
@@ -252,6 +256,7 @@ declare const SyncImportBody: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
252
256
|
channel: z.ZodString;
|
|
253
257
|
thread: z.ZodString;
|
|
254
258
|
}, z.core.$strip>>;
|
|
259
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
255
260
|
}, z.core.$strip>, z.ZodObject<{
|
|
256
261
|
author: z.ZodObject<{
|
|
257
262
|
id: z.ZodString;
|
|
@@ -267,6 +272,7 @@ declare const SyncImportBody: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
267
272
|
}, z.core.$strip>>;
|
|
268
273
|
message: z.ZodOptional<z.ZodString>;
|
|
269
274
|
op: z.ZodLiteral<"delete">;
|
|
275
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
270
276
|
}, z.core.$strip>, z.ZodObject<{
|
|
271
277
|
author: z.ZodObject<{
|
|
272
278
|
id: z.ZodString;
|
|
@@ -301,6 +307,7 @@ declare const SyncImportBody: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
301
307
|
op: z.ZodLiteral<"labels">;
|
|
302
308
|
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
303
309
|
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
310
|
+
if: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodString>>>;
|
|
304
311
|
}, z.core.$strip>, z.ZodObject<{
|
|
305
312
|
author: z.ZodObject<{
|
|
306
313
|
id: z.ZodString;
|
|
@@ -495,6 +502,7 @@ declare const InboxPushBody: z.ZodObject<{
|
|
|
495
502
|
type: z.ZodString;
|
|
496
503
|
title: z.ZodString;
|
|
497
504
|
url: z.ZodNullable<z.ZodString>;
|
|
505
|
+
body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
498
506
|
labels: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
499
507
|
unset: z.ZodArray<z.ZodString>;
|
|
500
508
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -551,11 +559,15 @@ declare const SignInQuery: z.ZodObject<{
|
|
|
551
559
|
declare const SyncUnlinkBody: z.ZodObject<{
|
|
552
560
|
account: z.ZodString;
|
|
553
561
|
}, z.core.$strip>;
|
|
554
|
-
/**
|
|
562
|
+
/**
|
|
563
|
+
* A direct upload, before its bytes: what the file will be called, its type, its exact size, and
|
|
564
|
+
* the SHA-256 of its bytes, in base64, for a store that signs its URL for them (Vercel's).
|
|
565
|
+
*/
|
|
555
566
|
declare const UploadStartBody: z.ZodObject<{
|
|
556
567
|
name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
557
568
|
type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
558
569
|
size: z.ZodNumber;
|
|
570
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
559
571
|
}, z.core.$strip>;
|
|
560
572
|
/** Where to send a direct upload's bytes: `PUT` the file to `url` with `headers` (its `content-type` included), before `expiresAt`, then finish it. */
|
|
561
573
|
type UploadTicket = {
|
|
@@ -566,8 +578,11 @@ type UploadTicket = {
|
|
|
566
578
|
};
|
|
567
579
|
declare const EditBody: z.ZodObject<{
|
|
568
580
|
text: z.ZodString;
|
|
581
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
569
582
|
}, z.core.$strip>;
|
|
570
|
-
declare const DeleteBody: z.ZodOptional<z.ZodObject<{
|
|
583
|
+
declare const DeleteBody: z.ZodOptional<z.ZodObject<{
|
|
584
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
585
|
+
}, z.core.$strip>>;
|
|
571
586
|
/** `status`: what Slack shows in place of "Typing…" (WhatsApp and GitHub ignore it). */
|
|
572
587
|
declare const TypingBody: z.ZodOptional<z.ZodObject<{
|
|
573
588
|
status: z.ZodOptional<z.ZodString>;
|
|
@@ -576,9 +591,12 @@ declare const ReactBody: z.ZodObject<{
|
|
|
576
591
|
emoji: z.ZodString;
|
|
577
592
|
remove: z.ZodOptional<z.ZodBoolean>;
|
|
578
593
|
}, z.core.$strip>;
|
|
594
|
+
/** At most this many labels in a label write's `if`. */
|
|
595
|
+
declare const LABEL_CONDITIONS_MAX = 16;
|
|
579
596
|
declare const LabelBody: z.ZodObject<{
|
|
580
597
|
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
581
598
|
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
599
|
+
if: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodString>>>;
|
|
582
600
|
}, z.core.$strip>;
|
|
583
601
|
type FiltersInput = z.input<typeof Filters$1>;
|
|
584
602
|
type SyncImportInput = z.input<typeof SyncImportBody>;
|
|
@@ -653,7 +671,7 @@ type ActorView = Pick<Actor, 'kind' | 'handle' | 'name' | 'avatar'> & {
|
|
|
653
671
|
person?: PersonView;
|
|
654
672
|
};
|
|
655
673
|
/** A message as clients see it: its IDs are refs, and `version` says which of two views of it is newer. */
|
|
656
|
-
type MessageView = Omit<Message, 'id' | 're' | 'replyTo' | 'links' | 'schedule' | 'version'> & {
|
|
674
|
+
type MessageView = Omit<Message, 'id' | 're' | 'replyTo' | 'links' | 'schedule' | 'version' | 'revision'> & {
|
|
657
675
|
id: string;
|
|
658
676
|
/** The thread's root, or null for a root. */
|
|
659
677
|
re: string | null;
|
|
@@ -661,6 +679,11 @@ type MessageView = Omit<Message, 'id' | 're' | 'replyTo' | 'links' | 'schedule'
|
|
|
661
679
|
replyTo: string | null;
|
|
662
680
|
/** Grows with each change to this message: of two views of it, the one with the higher version is newer. */
|
|
663
681
|
version: number;
|
|
682
|
+
/**
|
|
683
|
+
* Changes with each edit and delete, and only then: what an edit or a delete passes as `revision`
|
|
684
|
+
* to change it only if no one has since.
|
|
685
|
+
*/
|
|
686
|
+
revision: number;
|
|
664
687
|
links: LinkView[];
|
|
665
688
|
/** Set when a schedule posted it: the schedule's ID and which send this was, from 0. */
|
|
666
689
|
schedule?: {
|
|
@@ -911,6 +934,8 @@ type SourceRead = {
|
|
|
911
934
|
messages: SourceMessage[];
|
|
912
935
|
/** The platform has more than `limit`: older messages in a channel, later replies in a thread. */
|
|
913
936
|
more: boolean;
|
|
937
|
+
/** Where to pick up, as `after`, when the platform can page past `limit`. */
|
|
938
|
+
next?: string | null;
|
|
914
939
|
};
|
|
915
940
|
/** A channel the board's app joined, or was already in (`joined: false`). */
|
|
916
941
|
type SourceJoin = {
|
|
@@ -1012,6 +1037,7 @@ declare const routes: {
|
|
|
1012
1037
|
}, z.core.$strip>]>>>;
|
|
1013
1038
|
id: z.ZodOptional<z.ZodString>;
|
|
1014
1039
|
attachments: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1040
|
+
after: z.ZodOptional<z.ZodString>;
|
|
1015
1041
|
}, z.core.$strip>;
|
|
1016
1042
|
};
|
|
1017
1043
|
readonly edit: {
|
|
@@ -1019,12 +1045,15 @@ declare const routes: {
|
|
|
1019
1045
|
readonly path: '/messages/:id/edit';
|
|
1020
1046
|
readonly body: z.ZodObject<{
|
|
1021
1047
|
text: z.ZodString;
|
|
1048
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
1022
1049
|
}, z.core.$strip>;
|
|
1023
1050
|
};
|
|
1024
1051
|
readonly delete: {
|
|
1025
1052
|
readonly method: 'POST';
|
|
1026
1053
|
readonly path: '/messages/:id/delete';
|
|
1027
|
-
readonly body: z.ZodOptional<z.ZodObject<{
|
|
1054
|
+
readonly body: z.ZodOptional<z.ZodObject<{
|
|
1055
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
1056
|
+
}, z.core.$strip>>;
|
|
1028
1057
|
};
|
|
1029
1058
|
readonly react: {
|
|
1030
1059
|
readonly method: 'POST';
|
|
@@ -1040,6 +1069,7 @@ declare const routes: {
|
|
|
1040
1069
|
readonly body: z.ZodObject<{
|
|
1041
1070
|
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1042
1071
|
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1072
|
+
if: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodString>>>;
|
|
1043
1073
|
}, z.core.$strip>;
|
|
1044
1074
|
};
|
|
1045
1075
|
/** Attaches the thread to a sync target, recording a `thread` receipt: needs `sync` where the thread is. */
|
|
@@ -1226,6 +1256,7 @@ declare const routes: {
|
|
|
1226
1256
|
type: z.ZodString;
|
|
1227
1257
|
title: z.ZodString;
|
|
1228
1258
|
url: z.ZodNullable<z.ZodString>;
|
|
1259
|
+
body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1229
1260
|
labels: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1230
1261
|
unset: z.ZodArray<z.ZodString>;
|
|
1231
1262
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -1308,6 +1339,7 @@ declare const routes: {
|
|
|
1308
1339
|
message: z.ZodNullable<z.ZodString>;
|
|
1309
1340
|
}, z.core.$strip>>>;
|
|
1310
1341
|
id: z.ZodOptional<z.ZodString>;
|
|
1342
|
+
after: z.ZodOptional<z.ZodString>;
|
|
1311
1343
|
}, z.core.$strip>, z.ZodObject<{
|
|
1312
1344
|
author: z.ZodObject<{
|
|
1313
1345
|
id: z.ZodString;
|
|
@@ -1329,6 +1361,7 @@ declare const routes: {
|
|
|
1329
1361
|
channel: z.ZodString;
|
|
1330
1362
|
thread: z.ZodString;
|
|
1331
1363
|
}, z.core.$strip>>;
|
|
1364
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
1332
1365
|
}, z.core.$strip>, z.ZodObject<{
|
|
1333
1366
|
author: z.ZodObject<{
|
|
1334
1367
|
id: z.ZodString;
|
|
@@ -1344,6 +1377,7 @@ declare const routes: {
|
|
|
1344
1377
|
}, z.core.$strip>>;
|
|
1345
1378
|
message: z.ZodOptional<z.ZodString>;
|
|
1346
1379
|
op: z.ZodLiteral<"delete">;
|
|
1380
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
1347
1381
|
}, z.core.$strip>, z.ZodObject<{
|
|
1348
1382
|
author: z.ZodObject<{
|
|
1349
1383
|
id: z.ZodString;
|
|
@@ -1378,6 +1412,7 @@ declare const routes: {
|
|
|
1378
1412
|
op: z.ZodLiteral<"labels">;
|
|
1379
1413
|
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1380
1414
|
unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1415
|
+
if: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodString>>>;
|
|
1381
1416
|
}, z.core.$strip>, z.ZodObject<{
|
|
1382
1417
|
author: z.ZodObject<{
|
|
1383
1418
|
id: z.ZodString;
|
|
@@ -1535,6 +1570,7 @@ declare const routes: {
|
|
|
1535
1570
|
readonly query: z.ZodObject<{
|
|
1536
1571
|
target: z.ZodString;
|
|
1537
1572
|
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
1573
|
+
after: z.ZodOptional<z.ZodString>;
|
|
1538
1574
|
}, z.core.$strip>;
|
|
1539
1575
|
};
|
|
1540
1576
|
/** Adds the app to a public channel so it can be read, where that sync runs and opted in with `join`. Full access only. */
|
|
@@ -1586,6 +1622,7 @@ declare const routes: {
|
|
|
1586
1622
|
name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1587
1623
|
type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1588
1624
|
size: z.ZodNumber;
|
|
1625
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
1589
1626
|
}, z.core.$strip>;
|
|
1590
1627
|
};
|
|
1591
1628
|
/** After the `PUT`: the board checks what landed in the store and records the attachment. */
|
|
@@ -1760,7 +1797,13 @@ type PostOptions = {
|
|
|
1760
1797
|
/** Files from `upload`, or their IDs. */
|
|
1761
1798
|
attachments?: (Attachment | string)[];
|
|
1762
1799
|
};
|
|
1763
|
-
type ReplyOptions = Omit<PostOptions, 'sync'
|
|
1800
|
+
type ReplyOptions = Omit<PostOptions, 'sync'> & {
|
|
1801
|
+
/**
|
|
1802
|
+
* Posts only while this is the thread's newest message: the ID of the last one you read. If
|
|
1803
|
+
* another has come after it, nothing is posted, and it throws a 409 `newer_message`.
|
|
1804
|
+
*/
|
|
1805
|
+
after?: string;
|
|
1806
|
+
};
|
|
1764
1807
|
/**
|
|
1765
1808
|
* When a scheduled message goes out: once `in` a while or `at` a time, or
|
|
1766
1809
|
* `every` so often (first at `at`, `in`, or one `every` from now), stopping
|
|
@@ -1859,11 +1902,19 @@ declare function createBoardClient(options: ClientOptions): {
|
|
|
1859
1902
|
download: (id: string, opts?: {
|
|
1860
1903
|
signal?: AbortSignal;
|
|
1861
1904
|
}) => Promise<Response>;
|
|
1862
|
-
|
|
1905
|
+
/**
|
|
1906
|
+
* `revision` is the message's as you read it: if it's been edited or deleted since, nothing
|
|
1907
|
+
* changes, and it throws a 409 `revision_conflict`.
|
|
1908
|
+
*/
|
|
1909
|
+
edit: (id: string, text: string, opts?: {
|
|
1910
|
+
revision?: number;
|
|
1911
|
+
}) => Promise<{
|
|
1863
1912
|
ok: true;
|
|
1864
1913
|
unknownMentions?: string[];
|
|
1865
1914
|
}>;
|
|
1866
|
-
delete: (id: string
|
|
1915
|
+
delete: (id: string, opts?: {
|
|
1916
|
+
revision?: number;
|
|
1917
|
+
}) => Promise<{
|
|
1867
1918
|
ok: true;
|
|
1868
1919
|
}>;
|
|
1869
1920
|
/** `emoji` is a short name, `:name:`, or the character itself. */
|
|
@@ -1872,9 +1923,14 @@ declare function createBoardClient(options: ClientOptions): {
|
|
|
1872
1923
|
}) => Promise<{
|
|
1873
1924
|
ok: true;
|
|
1874
1925
|
}>;
|
|
1926
|
+
/**
|
|
1927
|
+
* `if` is what the labels must be now, a value or null for one that mustn't be set: if one
|
|
1928
|
+
* isn't, nothing changes, and it throws a 409 `label_conflict`.
|
|
1929
|
+
*/
|
|
1875
1930
|
label: (id: string, change: {
|
|
1876
1931
|
set?: Record<string, string>;
|
|
1877
1932
|
unset?: string[];
|
|
1933
|
+
if?: Record<string, string | null>;
|
|
1878
1934
|
}) => Promise<{
|
|
1879
1935
|
ok: true;
|
|
1880
1936
|
}>;
|
|
@@ -1930,6 +1986,7 @@ declare function createBoardClient(options: ClientOptions): {
|
|
|
1930
1986
|
*/
|
|
1931
1987
|
readSource: (key: string, target: string, opts?: {
|
|
1932
1988
|
limit?: number;
|
|
1989
|
+
after?: string;
|
|
1933
1990
|
}) => Promise<SourceRead>;
|
|
1934
1991
|
/** Adds the app to a public channel so `readSource` can read it, where the sync opted in with `join`. Full access only. */
|
|
1935
1992
|
joinSource: (key: string, target: string) => Promise<SourceJoin>;
|
|
@@ -2002,4 +2059,4 @@ declare function createBoardClient(options: ClientOptions): {
|
|
|
2002
2059
|
}, opts?: WaitOptions): Promise<BoardEventView | null>;
|
|
2003
2060
|
};
|
|
2004
2061
|
//#endregion
|
|
2005
|
-
export {
|
|
2062
|
+
export { RegisterBody as $, InboxItem as A, SyncReceiptInput as At, MatchesQuery as B, TypingBody as Bt, EventsQuery as C, SyncCopiesView as Ct, IdentityView as D, SyncImportBody as Dt, IdentityUnlinkBody as E, SyncFindView as Et, LabelBody as F, ThreadSummaryView as Ft, MessagesQueryInput as G, MessageView as H, UploadStartBody as Ht, LinkView as I, ThreadView as It, PostBody as J, ParsedFilters as K, LinkedAccount as L, ThreadsPage as Lt, InboxPushBody as M, SyncThreadView as Mt, InboxQuery as N, SyncUnlinkBody as Nt, InboxAckBody as O, SyncImportInput as Ot, LABEL_CONDITIONS_MAX as P, SyncedView as Pt, Ref as Q, LinkedQuery as R, ThreadsQuery as Rt, EventsPage as S, SyncCopiesQuery as St, FiltersInput as T, SyncFindQuery as Tt, MessagesPage as U, UploadTicket as Ut, Me as V, TypingResult as Vt, MessagesQuery as W, routes as Wt, REGISTERED_WATCHERS_MAX as X, PostInput as Y, ReactBody as Z, BoardEventView as _, SyncAccountBody as _t, PostOptions as a, ScheduleBodyOutput as at, Discovery as b, SyncCodeBody as bt, ScheduleOptions as c, SchedulesQuery as ct, WaitOptions as d, SignInQuery as dt, RegisterInput as et, Written as f, SourceJoin as ft, ApiError as g, SourceReadQuery as gt, ActorView as h, SourceRead as ht, Filters as i, ScheduleBody as it, InboxNextQuery as j, SyncRootsQuery as jt, InboxEntry as k, SyncReceiptBody as kt, ScheduleTiming as l, SchedulesQueryInput as lt, AckBody as m, SourceMessage as mt, BoardError as n, ResolvedSyncTarget as nt, ProfileOption as o, ScheduleInput as ot, duration as p, SourceJoinBody as pt, PersonView as q, ErrorOrigin as r, RouteName as rt, ReplyOptions as s, ScheduleView as st, BoardClient as t, RegistrationView as tt, UploadInput as u, SchedulesQueryOutput as ut, ChannelView as v, SyncAccountInput as vt, EventsQueryInput as w, SyncFindInput as wt, EditBody as x, SyncCodeView as xt, DeleteBody as y, SyncBody as yt, MatchView as z, ThreadsQueryInput as zt };
|