@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,226 @@
|
|
|
1
|
+
import { c as ChannelPath, v as SCOPE_MAX } from "./schemas-DBmUO6pr.mjs";
|
|
2
|
+
import { a as forbidden } from "./errors-C_5rB8Iz.mjs";
|
|
3
|
+
//#region src/server/access.ts
|
|
4
|
+
/**
|
|
5
|
+
* What a principal may do in a channel. `read` covers messages, threads,
|
|
6
|
+
* `/events`, and schedules; `post` starts threads and edits your own messages;
|
|
7
|
+
* `manage` is the board's own bookkeeping (inbox, sources).
|
|
8
|
+
*/
|
|
9
|
+
const PERMISSIONS = [
|
|
10
|
+
"read",
|
|
11
|
+
"post",
|
|
12
|
+
"react",
|
|
13
|
+
"label",
|
|
14
|
+
"sync",
|
|
15
|
+
"manage"
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* One hop of implication, kept as data like Vercel's git broker
|
|
19
|
+
* (`ACTION_IMPLICATIONS`). Each verb that addresses a message by ID implies
|
|
20
|
+
* `read`, so none of them is a blind existence oracle. `post` implies nothing:
|
|
21
|
+
* write-only is `['post']`.
|
|
22
|
+
*/
|
|
23
|
+
const IMPLIES = {
|
|
24
|
+
read: [],
|
|
25
|
+
post: [],
|
|
26
|
+
react: ["read"],
|
|
27
|
+
label: ["read"],
|
|
28
|
+
sync: ["read"],
|
|
29
|
+
manage: [
|
|
30
|
+
"read",
|
|
31
|
+
"post",
|
|
32
|
+
"react",
|
|
33
|
+
"label",
|
|
34
|
+
"sync"
|
|
35
|
+
]
|
|
36
|
+
};
|
|
37
|
+
const ORDER = new Map(PERMISSIONS.map((permission, index) => [permission, index]));
|
|
38
|
+
const SHAPE = "write *, a channel, or a channel and its subtree (feedback/)";
|
|
39
|
+
/** A pattern's parts; any other `*` throws, and says what to type instead. */
|
|
40
|
+
function parsePattern(pattern) {
|
|
41
|
+
if (pattern === "*") return { kind: "all" };
|
|
42
|
+
if (pattern.includes("*")) {
|
|
43
|
+
const before = pattern.slice(0, pattern.indexOf("*")).replace(/\/+$/, "");
|
|
44
|
+
const hint = before === "" ? "write * for every channel" : ChannelPath.safeParse(before).success ? `write ${before}/ for ${before} and its subtree` : SHAPE;
|
|
45
|
+
throw new Error(`invalid channel pattern ${pattern}: ${hint}`);
|
|
46
|
+
}
|
|
47
|
+
const subtree = pattern.endsWith("/");
|
|
48
|
+
const path = subtree ? pattern.slice(0, -1) : pattern;
|
|
49
|
+
if (!ChannelPath.safeParse(path).success) throw new Error(`invalid channel pattern ${pattern || "(empty)"}: ${SHAPE}`);
|
|
50
|
+
return subtree ? {
|
|
51
|
+
kind: "subtree",
|
|
52
|
+
path
|
|
53
|
+
} : {
|
|
54
|
+
kind: "exact",
|
|
55
|
+
path
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const key = (pattern) => pattern.kind === "all" ? "*" : pattern.kind === "subtree" ? `${pattern.path}/` : pattern.path;
|
|
59
|
+
/** A grant with its implications, closed: `['label']` is `read` and `label`. */
|
|
60
|
+
function expand(grant) {
|
|
61
|
+
const out = /* @__PURE__ */ new Set();
|
|
62
|
+
const add = (permission) => {
|
|
63
|
+
if (!ORDER.has(permission)) throw new Error(`unknown permission ${String(permission)}: use ${PERMISSIONS.join(", ")}`);
|
|
64
|
+
if (out.has(permission)) return;
|
|
65
|
+
out.add(permission);
|
|
66
|
+
for (const implied of IMPLIES[permission]) add(implied);
|
|
67
|
+
};
|
|
68
|
+
for (const permission of grant === "all" ? PERMISSIONS : grant) add(permission);
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
const NOTHING = /* @__PURE__ */ new Set();
|
|
72
|
+
function compile(entries) {
|
|
73
|
+
let all = null;
|
|
74
|
+
const exact = /* @__PURE__ */ new Map();
|
|
75
|
+
const subtrees = [];
|
|
76
|
+
for (const [pattern, permissions] of entries) if (pattern.kind === "all") all = permissions;
|
|
77
|
+
else if (pattern.kind === "exact") exact.set(pattern.path, permissions);
|
|
78
|
+
else subtrees.push([pattern.path, permissions]);
|
|
79
|
+
subtrees.sort((a, b) => b[0].length - a[0].length);
|
|
80
|
+
return {
|
|
81
|
+
all,
|
|
82
|
+
exact,
|
|
83
|
+
subtrees
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const under = (channel, path) => channel === path || channel.startsWith(`${path}/`);
|
|
87
|
+
/** What the most specific pattern covering `channel` gives; with `subtreeOnly`, ignoring an exact rule for it. */
|
|
88
|
+
function resolve(rules, channel, subtreeOnly = false) {
|
|
89
|
+
if (!subtreeOnly) {
|
|
90
|
+
const exact = rules.exact.get(channel);
|
|
91
|
+
if (exact) return exact;
|
|
92
|
+
}
|
|
93
|
+
for (const [path, permissions] of rules.subtrees) if (under(channel, path)) return permissions;
|
|
94
|
+
return rules.all ?? NOTHING;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* What `rules` gives every channel `pattern` governs where nothing more
|
|
98
|
+
* specific does. The patterns matching one channel form a chain, so that's one
|
|
99
|
+
* answer: an exact channel resolves as itself, a subtree as whatever covers the
|
|
100
|
+
* subtree's root, ignoring an exact rule for the root.
|
|
101
|
+
*/
|
|
102
|
+
const at = (rules, pattern) => pattern.kind === "all" ? rules.all ?? NOTHING : resolve(rules, pattern.path, pattern.kind === "subtree");
|
|
103
|
+
const equal = (a, b) => a.size === b.size && [...a].every((permission) => b.has(permission));
|
|
104
|
+
/** The answer of the pattern next less specific than `pattern` in `rules`. */
|
|
105
|
+
function parent(rules, pattern) {
|
|
106
|
+
if (pattern.kind === "exact") return resolve(rules, pattern.path, true);
|
|
107
|
+
if (pattern.kind === "subtree") {
|
|
108
|
+
for (const [path, permissions] of rules.subtrees) if (path !== pattern.path && under(pattern.path, path)) return permissions;
|
|
109
|
+
}
|
|
110
|
+
return rules.all ?? NOTHING;
|
|
111
|
+
}
|
|
112
|
+
/** Drops rules that say what their parent says, and an empty `*`, so equal access has one summary. */
|
|
113
|
+
function canonical(entries) {
|
|
114
|
+
const rules = compile(entries);
|
|
115
|
+
return compile(entries.filter(([pattern, permissions]) => pattern.kind === "all" ? permissions.size > 0 : !equal(permissions, parent(rules, pattern))));
|
|
116
|
+
}
|
|
117
|
+
function entriesOf(can) {
|
|
118
|
+
if (can === "all" || Array.isArray(can)) return [[{ kind: "all" }, expand(can)]];
|
|
119
|
+
return Object.entries(can).map(([pattern, grant]) => [parsePattern(pattern), expand(grant)]);
|
|
120
|
+
}
|
|
121
|
+
const entriesIn = (rules) => [
|
|
122
|
+
...rules.all ? [[{ kind: "all" }, rules.all]] : [],
|
|
123
|
+
...rules.subtrees.map(([path, permissions]) => [{
|
|
124
|
+
kind: "subtree",
|
|
125
|
+
path
|
|
126
|
+
}, permissions]),
|
|
127
|
+
...[...rules.exact].map(([path, permissions]) => [{
|
|
128
|
+
kind: "exact",
|
|
129
|
+
path
|
|
130
|
+
}, permissions])
|
|
131
|
+
];
|
|
132
|
+
const RULES = Symbol("board.access");
|
|
133
|
+
const isAccess = (value) => typeof value === "object" && RULES in value;
|
|
134
|
+
function fromRules(rules) {
|
|
135
|
+
const entries = entriesIn(rules);
|
|
136
|
+
const everywhere = (permission) => (rules.all?.has(permission) ?? false) && entries.every(([, permissions]) => permissions.has(permission));
|
|
137
|
+
const readable = /* @__PURE__ */ new Map();
|
|
138
|
+
return {
|
|
139
|
+
[RULES]: rules,
|
|
140
|
+
can: (permission, channel) => resolve(rules, channel).has(permission),
|
|
141
|
+
readable(channel) {
|
|
142
|
+
let found = readable.get(channel);
|
|
143
|
+
if (found === void 0) readable.set(channel, found = resolve(rules, channel).has("read"));
|
|
144
|
+
return found;
|
|
145
|
+
},
|
|
146
|
+
readsAll: everywhere("read"),
|
|
147
|
+
everywhere,
|
|
148
|
+
anywhere: (permission) => entries.some(([, permissions]) => permissions.has(permission)),
|
|
149
|
+
narrow(scope) {
|
|
150
|
+
const other = isAccess(scope) ? scope[RULES] : canonical(entriesOf(scope));
|
|
151
|
+
const patterns = /* @__PURE__ */ new Map([["*", { kind: "all" }]]);
|
|
152
|
+
for (const [pattern] of [...entries, ...entriesIn(other)]) patterns.set(key(pattern), pattern);
|
|
153
|
+
return fromRules(canonical([...patterns.values()].map((pattern) => {
|
|
154
|
+
const theirs = at(other, pattern);
|
|
155
|
+
return [pattern, new Set([...at(rules, pattern)].filter((permission) => theirs.has(permission)))];
|
|
156
|
+
})));
|
|
157
|
+
},
|
|
158
|
+
summary() {
|
|
159
|
+
const named = entries.map(([pattern, permissions]) => [key(pattern), permissions]);
|
|
160
|
+
named.sort(([a], [b]) => a === "*" ? -1 : b === "*" ? 1 : a.localeCompare(b));
|
|
161
|
+
const out = {};
|
|
162
|
+
for (const [name, permissions] of named) out[name] = [...permissions].sort((a, b) => ORDER.get(a) - ORDER.get(b));
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/** Access from config: `'all'`, a list for every channel, or a map from pattern to grant. Throws on a bad pattern or permission. */
|
|
168
|
+
function compileAccess(can) {
|
|
169
|
+
return fromRules(canonical(entriesOf(can)));
|
|
170
|
+
}
|
|
171
|
+
const FULL_ACCESS = compileAccess("all");
|
|
172
|
+
/**
|
|
173
|
+
* `x-board-scope`: `dev/=read,post,react,label;ci/=read`. Each entry is a
|
|
174
|
+
* pattern and its permissions (or `all`). It's meant for a proxy that holds the
|
|
175
|
+
* credential, like Pi's sandbox: the board intersects it with the principal's
|
|
176
|
+
* access, so it can only narrow, and a caller holding its own token gains
|
|
177
|
+
* nothing by sending it.
|
|
178
|
+
*/
|
|
179
|
+
function parseScope(header) {
|
|
180
|
+
if (header.length > 4e3) throw new Error(`x-board-scope is longer than ${SCOPE_MAX} characters`);
|
|
181
|
+
const out = {};
|
|
182
|
+
const entries = header.split(";").map((entry) => entry.trim());
|
|
183
|
+
if (entries.every((entry) => entry === "")) throw new Error("x-board-scope is empty: write pattern=permissions, like dev/=read,post");
|
|
184
|
+
for (const entry of entries) {
|
|
185
|
+
if (entry === "") continue;
|
|
186
|
+
const split = entry.indexOf("=");
|
|
187
|
+
if (split < 0) throw new Error(`x-board-scope entry ${entry} needs =: write pattern=permissions, like dev/=read,post`);
|
|
188
|
+
const pattern = entry.slice(0, split).trim();
|
|
189
|
+
const list = entry.slice(split + 1).trim();
|
|
190
|
+
if (Object.hasOwn(out, pattern)) throw new Error(`x-board-scope lists ${pattern} twice`);
|
|
191
|
+
parsePattern(pattern);
|
|
192
|
+
const permissions = list === "" ? [] : list.split(",").map((permission) => permission.trim());
|
|
193
|
+
if (permissions.length === 1 && permissions[0] === "all") {
|
|
194
|
+
out[pattern] = "all";
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
for (const permission of permissions) if (!ORDER.has(permission)) throw new Error(`x-board-scope: unknown permission ${permission || "(empty)"}: use ${PERMISSIONS.join(", ")}, or all`);
|
|
198
|
+
out[pattern] = permissions;
|
|
199
|
+
}
|
|
200
|
+
return out;
|
|
201
|
+
}
|
|
202
|
+
const PHRASE = {
|
|
203
|
+
read: (channel) => `read ${channel}`,
|
|
204
|
+
post: (channel) => `post in ${channel}`,
|
|
205
|
+
react: (channel) => `react in ${channel}`,
|
|
206
|
+
label: (channel) => `label in ${channel}`,
|
|
207
|
+
sync: (channel) => `sync in ${channel}`,
|
|
208
|
+
manage: (channel) => `manage ${channel}`
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* A proof that `access` allows `permission` in `channel`, or a 403 naming what's
|
|
212
|
+
* missing: `this token can't label in dev`. Pass the channel the board looked
|
|
213
|
+
* up, never one the request named. What the caller can't read should answer as
|
|
214
|
+
* if it didn't exist: pass that error as `hidden`, and it's thrown instead
|
|
215
|
+
* whenever `channel` isn't readable.
|
|
216
|
+
*/
|
|
217
|
+
function authorize(access, permission, channel, hidden) {
|
|
218
|
+
if (hidden && !access.readable(channel)) throw hidden();
|
|
219
|
+
if (!access.can(permission, channel)) throw forbidden(`this token can't ${PHRASE[permission](channel)}`);
|
|
220
|
+
return Object.freeze({
|
|
221
|
+
permission,
|
|
222
|
+
channel
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
//#endregion
|
|
226
|
+
export { parseScope as i, authorize as n, compileAccess as r, FULL_ACCESS as t };
|
package/dist/access.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as Grant, i as ChannelPattern, n as AccessSummary, o as Permission, r as Can, t as Access } from "./access-CV96SYgr.mjs";
|
|
2
2
|
import { _ as oidc, a as CallerRequest, c as HostPrincipal, d as OidcTokensOptions, f as Principal, g as githubActions, h as compileRules, i as AuthenticateContext, l as IssuerConfig, m as RuleFunction, n as AccessRule, o as Claims, p as PrincipalKind, r as Authenticate, t as AccessFunction, u as Known, v as vercelProject } from "./auth-CU56Q2Xh.mjs";
|
|
3
|
-
import { C as Author, t as Actor } from "./folds-
|
|
3
|
+
import { C as Author, t as Actor } from "./folds-8wRRXjAt.mjs";
|
|
4
4
|
//#region src/server/tokens.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* The OIDC tokens made out to this board: a request's bearer token, from Vercel (people and
|
package/dist/access.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { t as oidcTokens } from "./tokens-
|
|
1
|
+
import { i as resolveActor } from "./actors-xPiamLWk.mjs";
|
|
2
|
+
import { a as compileRules, c as githubActions, h as vercelProject, p as oidc } from "./auth-BPinwfN0.mjs";
|
|
3
|
+
import { t as oidcTokens } from "./tokens-C5_yGRlL.mjs";
|
|
4
4
|
export { compileRules, githubActions, oidc, oidcTokens, resolveActor, vercelProject };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { C as toStorable } from "./schemas-
|
|
2
|
-
import { r as badRequest } from "./errors-
|
|
1
|
+
import { C as toStorable } from "./schemas-DBmUO6pr.mjs";
|
|
2
|
+
import { r as badRequest } from "./errors-C_5rB8Iz.mjs";
|
|
3
3
|
import { t as own } from "./own-OwgPWdmh.mjs";
|
|
4
4
|
import { t as extractMentions } from "./mentions-CB6ShY4R.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { i as parseScope } from "./access-CQ39gqEV.mjs";
|
|
6
6
|
//#region src/server/actors.ts
|
|
7
7
|
/** Agents whose avatars the board serves itself. */
|
|
8
8
|
const KNOWN_AGENTS = [
|
|
@@ -1,228 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
//#region src/server/access.ts
|
|
4
|
-
/**
|
|
5
|
-
* What a principal may do in a channel. `read` covers messages, threads,
|
|
6
|
-
* `/events`, and schedules; `post` starts threads and edits your own messages;
|
|
7
|
-
* `manage` is the board's own bookkeeping (inbox, sources).
|
|
8
|
-
*/
|
|
9
|
-
const PERMISSIONS = [
|
|
10
|
-
"read",
|
|
11
|
-
"post",
|
|
12
|
-
"react",
|
|
13
|
-
"label",
|
|
14
|
-
"sync",
|
|
15
|
-
"manage"
|
|
16
|
-
];
|
|
17
|
-
/**
|
|
18
|
-
* One hop of implication, kept as data like Vercel's git broker
|
|
19
|
-
* (`ACTION_IMPLICATIONS`). Each verb that addresses a message by ID implies
|
|
20
|
-
* `read`, so none of them is a blind existence oracle. `post` implies nothing:
|
|
21
|
-
* write-only is `['post']`.
|
|
22
|
-
*/
|
|
23
|
-
const IMPLIES = {
|
|
24
|
-
read: [],
|
|
25
|
-
post: [],
|
|
26
|
-
react: ["read"],
|
|
27
|
-
label: ["read"],
|
|
28
|
-
sync: ["read"],
|
|
29
|
-
manage: [
|
|
30
|
-
"read",
|
|
31
|
-
"post",
|
|
32
|
-
"react",
|
|
33
|
-
"label",
|
|
34
|
-
"sync"
|
|
35
|
-
]
|
|
36
|
-
};
|
|
37
|
-
const ORDER = new Map(PERMISSIONS.map((permission, index) => [permission, index]));
|
|
38
|
-
const SHAPE = "write *, a channel, or a channel and its subtree (feedback/)";
|
|
39
|
-
/** A pattern's parts; any other `*` throws, and says what to type instead. */
|
|
40
|
-
function parsePattern(pattern) {
|
|
41
|
-
if (pattern === "*") return { kind: "all" };
|
|
42
|
-
if (pattern.includes("*")) {
|
|
43
|
-
const before = pattern.slice(0, pattern.indexOf("*")).replace(/\/+$/, "");
|
|
44
|
-
const hint = before === "" ? "write * for every channel" : ChannelPath.safeParse(before).success ? `write ${before}/ for ${before} and its subtree` : SHAPE;
|
|
45
|
-
throw new Error(`invalid channel pattern ${pattern}: ${hint}`);
|
|
46
|
-
}
|
|
47
|
-
const subtree = pattern.endsWith("/");
|
|
48
|
-
const path = subtree ? pattern.slice(0, -1) : pattern;
|
|
49
|
-
if (!ChannelPath.safeParse(path).success) throw new Error(`invalid channel pattern ${pattern || "(empty)"}: ${SHAPE}`);
|
|
50
|
-
return subtree ? {
|
|
51
|
-
kind: "subtree",
|
|
52
|
-
path
|
|
53
|
-
} : {
|
|
54
|
-
kind: "exact",
|
|
55
|
-
path
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
const key = (pattern) => pattern.kind === "all" ? "*" : pattern.kind === "subtree" ? `${pattern.path}/` : pattern.path;
|
|
59
|
-
/** A grant with its implications, closed: `['label']` is `read` and `label`. */
|
|
60
|
-
function expand(grant) {
|
|
61
|
-
const out = /* @__PURE__ */ new Set();
|
|
62
|
-
const add = (permission) => {
|
|
63
|
-
if (!ORDER.has(permission)) throw new Error(`unknown permission ${String(permission)}: use ${PERMISSIONS.join(", ")}`);
|
|
64
|
-
if (out.has(permission)) return;
|
|
65
|
-
out.add(permission);
|
|
66
|
-
for (const implied of IMPLIES[permission]) add(implied);
|
|
67
|
-
};
|
|
68
|
-
for (const permission of grant === "all" ? PERMISSIONS : grant) add(permission);
|
|
69
|
-
return out;
|
|
70
|
-
}
|
|
71
|
-
const NOTHING = /* @__PURE__ */ new Set();
|
|
72
|
-
function compile(entries) {
|
|
73
|
-
let all = null;
|
|
74
|
-
const exact = /* @__PURE__ */ new Map();
|
|
75
|
-
const subtrees = [];
|
|
76
|
-
for (const [pattern, permissions] of entries) if (pattern.kind === "all") all = permissions;
|
|
77
|
-
else if (pattern.kind === "exact") exact.set(pattern.path, permissions);
|
|
78
|
-
else subtrees.push([pattern.path, permissions]);
|
|
79
|
-
subtrees.sort((a, b) => b[0].length - a[0].length);
|
|
80
|
-
return {
|
|
81
|
-
all,
|
|
82
|
-
exact,
|
|
83
|
-
subtrees
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
const under = (channel, path) => channel === path || channel.startsWith(`${path}/`);
|
|
87
|
-
/** What the most specific pattern covering `channel` gives; with `subtreeOnly`, ignoring an exact rule for it. */
|
|
88
|
-
function resolve(rules, channel, subtreeOnly = false) {
|
|
89
|
-
if (!subtreeOnly) {
|
|
90
|
-
const exact = rules.exact.get(channel);
|
|
91
|
-
if (exact) return exact;
|
|
92
|
-
}
|
|
93
|
-
for (const [path, permissions] of rules.subtrees) if (under(channel, path)) return permissions;
|
|
94
|
-
return rules.all ?? NOTHING;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* What `rules` gives every channel `pattern` governs where nothing more
|
|
98
|
-
* specific does. The patterns matching one channel form a chain, so that's one
|
|
99
|
-
* answer: an exact channel resolves as itself, a subtree as whatever covers the
|
|
100
|
-
* subtree's root, ignoring an exact rule for the root.
|
|
101
|
-
*/
|
|
102
|
-
const at = (rules, pattern) => pattern.kind === "all" ? rules.all ?? NOTHING : resolve(rules, pattern.path, pattern.kind === "subtree");
|
|
103
|
-
const equal = (a, b) => a.size === b.size && [...a].every((permission) => b.has(permission));
|
|
104
|
-
/** The answer of the pattern next less specific than `pattern` in `rules`. */
|
|
105
|
-
function parent(rules, pattern) {
|
|
106
|
-
if (pattern.kind === "exact") return resolve(rules, pattern.path, true);
|
|
107
|
-
if (pattern.kind === "subtree") {
|
|
108
|
-
for (const [path, permissions] of rules.subtrees) if (path !== pattern.path && under(pattern.path, path)) return permissions;
|
|
109
|
-
}
|
|
110
|
-
return rules.all ?? NOTHING;
|
|
111
|
-
}
|
|
112
|
-
/** Drops rules that say what their parent says, and an empty `*`, so equal access has one summary. */
|
|
113
|
-
function canonical(entries) {
|
|
114
|
-
const rules = compile(entries);
|
|
115
|
-
return compile(entries.filter(([pattern, permissions]) => pattern.kind === "all" ? permissions.size > 0 : !equal(permissions, parent(rules, pattern))));
|
|
116
|
-
}
|
|
117
|
-
function entriesOf(can) {
|
|
118
|
-
if (can === "all" || Array.isArray(can)) return [[{ kind: "all" }, expand(can)]];
|
|
119
|
-
return Object.entries(can).map(([pattern, grant]) => [parsePattern(pattern), expand(grant)]);
|
|
120
|
-
}
|
|
121
|
-
const entriesIn = (rules) => [
|
|
122
|
-
...rules.all ? [[{ kind: "all" }, rules.all]] : [],
|
|
123
|
-
...rules.subtrees.map(([path, permissions]) => [{
|
|
124
|
-
kind: "subtree",
|
|
125
|
-
path
|
|
126
|
-
}, permissions]),
|
|
127
|
-
...[...rules.exact].map(([path, permissions]) => [{
|
|
128
|
-
kind: "exact",
|
|
129
|
-
path
|
|
130
|
-
}, permissions])
|
|
131
|
-
];
|
|
132
|
-
const RULES = Symbol("board.access");
|
|
133
|
-
const isAccess = (value) => typeof value === "object" && RULES in value;
|
|
134
|
-
function fromRules(rules) {
|
|
135
|
-
const entries = entriesIn(rules);
|
|
136
|
-
const everywhere = (permission) => (rules.all?.has(permission) ?? false) && entries.every(([, permissions]) => permissions.has(permission));
|
|
137
|
-
const readable = /* @__PURE__ */ new Map();
|
|
138
|
-
return {
|
|
139
|
-
[RULES]: rules,
|
|
140
|
-
can: (permission, channel) => resolve(rules, channel).has(permission),
|
|
141
|
-
readable(channel) {
|
|
142
|
-
let found = readable.get(channel);
|
|
143
|
-
if (found === void 0) readable.set(channel, found = resolve(rules, channel).has("read"));
|
|
144
|
-
return found;
|
|
145
|
-
},
|
|
146
|
-
readsAll: everywhere("read"),
|
|
147
|
-
everywhere,
|
|
148
|
-
anywhere: (permission) => entries.some(([, permissions]) => permissions.has(permission)),
|
|
149
|
-
narrow(scope) {
|
|
150
|
-
const other = isAccess(scope) ? scope[RULES] : canonical(entriesOf(scope));
|
|
151
|
-
const patterns = /* @__PURE__ */ new Map([["*", { kind: "all" }]]);
|
|
152
|
-
for (const [pattern] of [...entries, ...entriesIn(other)]) patterns.set(key(pattern), pattern);
|
|
153
|
-
return fromRules(canonical([...patterns.values()].map((pattern) => {
|
|
154
|
-
const theirs = at(other, pattern);
|
|
155
|
-
return [pattern, new Set([...at(rules, pattern)].filter((permission) => theirs.has(permission)))];
|
|
156
|
-
})));
|
|
157
|
-
},
|
|
158
|
-
summary() {
|
|
159
|
-
const named = entries.map(([pattern, permissions]) => [key(pattern), permissions]);
|
|
160
|
-
named.sort(([a], [b]) => a === "*" ? -1 : b === "*" ? 1 : a.localeCompare(b));
|
|
161
|
-
const out = {};
|
|
162
|
-
for (const [name, permissions] of named) out[name] = [...permissions].sort((a, b) => ORDER.get(a) - ORDER.get(b));
|
|
163
|
-
return out;
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
/** Access from config: `'all'`, a list for every channel, or a map from pattern to grant. Throws on a bad pattern or permission. */
|
|
168
|
-
function compileAccess(can) {
|
|
169
|
-
return fromRules(canonical(entriesOf(can)));
|
|
170
|
-
}
|
|
171
|
-
const FULL_ACCESS = compileAccess("all");
|
|
172
|
-
/**
|
|
173
|
-
* `x-board-scope`: `dev/=read,post,react,label;ci/=read`. Each entry is a
|
|
174
|
-
* pattern and its permissions (or `all`). It's meant for a proxy that holds the
|
|
175
|
-
* credential, like Pi's sandbox: the board intersects it with the principal's
|
|
176
|
-
* access, so it can only narrow, and a caller holding its own token gains
|
|
177
|
-
* nothing by sending it.
|
|
178
|
-
*/
|
|
179
|
-
function parseScope(header) {
|
|
180
|
-
if (header.length > 4e3) throw new Error(`x-board-scope is longer than ${SCOPE_MAX} characters`);
|
|
181
|
-
const out = {};
|
|
182
|
-
const entries = header.split(";").map((entry) => entry.trim());
|
|
183
|
-
if (entries.every((entry) => entry === "")) throw new Error("x-board-scope is empty: write pattern=permissions, like dev/=read,post");
|
|
184
|
-
for (const entry of entries) {
|
|
185
|
-
if (entry === "") continue;
|
|
186
|
-
const split = entry.indexOf("=");
|
|
187
|
-
if (split < 0) throw new Error(`x-board-scope entry ${entry} needs =: write pattern=permissions, like dev/=read,post`);
|
|
188
|
-
const pattern = entry.slice(0, split).trim();
|
|
189
|
-
const list = entry.slice(split + 1).trim();
|
|
190
|
-
if (Object.hasOwn(out, pattern)) throw new Error(`x-board-scope lists ${pattern} twice`);
|
|
191
|
-
parsePattern(pattern);
|
|
192
|
-
const permissions = list === "" ? [] : list.split(",").map((permission) => permission.trim());
|
|
193
|
-
if (permissions.length === 1 && permissions[0] === "all") {
|
|
194
|
-
out[pattern] = "all";
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
for (const permission of permissions) if (!ORDER.has(permission)) throw new Error(`x-board-scope: unknown permission ${permission || "(empty)"}: use ${PERMISSIONS.join(", ")}, or all`);
|
|
198
|
-
out[pattern] = permissions;
|
|
199
|
-
}
|
|
200
|
-
return out;
|
|
201
|
-
}
|
|
202
|
-
const PHRASE = {
|
|
203
|
-
read: (channel) => `read ${channel}`,
|
|
204
|
-
post: (channel) => `post in ${channel}`,
|
|
205
|
-
react: (channel) => `react in ${channel}`,
|
|
206
|
-
label: (channel) => `label in ${channel}`,
|
|
207
|
-
sync: (channel) => `sync in ${channel}`,
|
|
208
|
-
manage: (channel) => `manage ${channel}`
|
|
209
|
-
};
|
|
210
|
-
/**
|
|
211
|
-
* A proof that `access` allows `permission` in `channel`, or a 403 naming what's
|
|
212
|
-
* missing: `this token can't label in dev`. Pass the channel the board looked
|
|
213
|
-
* up, never one the request named. What the caller can't read should answer as
|
|
214
|
-
* if it didn't exist: pass that error as `hidden`, and it's thrown instead
|
|
215
|
-
* whenever `channel` isn't readable.
|
|
216
|
-
*/
|
|
217
|
-
function authorize(access, permission, channel, hidden) {
|
|
218
|
-
if (hidden && !access.readable(channel)) throw hidden();
|
|
219
|
-
if (!access.can(permission, channel)) throw forbidden(`this token can't ${PHRASE[permission](channel)}`);
|
|
220
|
-
return Object.freeze({
|
|
221
|
-
permission,
|
|
222
|
-
channel
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
//#endregion
|
|
1
|
+
import { a as forbidden, l as unauthorized } from "./errors-C_5rB8Iz.mjs";
|
|
2
|
+
import { i as parseScope, r as compileAccess, t as FULL_ACCESS } from "./access-CQ39gqEV.mjs";
|
|
226
3
|
//#region src/server/auth.ts
|
|
227
4
|
/**
|
|
228
5
|
* Principal IDs a board authenticates: its people, deployments, workflows, and its own code. No
|
|
@@ -496,4 +273,4 @@ function hostPrincipal(value) {
|
|
|
496
273
|
};
|
|
497
274
|
}
|
|
498
275
|
//#endregion
|
|
499
|
-
export {
|
|
276
|
+
export { compileRules as a, githubActions as c, issuersOf as d, markVerified as f, verifiesTokens as g, vercelProject as h, authenticates as i, hostPrincipal as l, trustedIssuers as m, TOKENS as n, createAuthority as o, oidc as p, VERCEL_ISSUER as r, fromTokens as s, GITHUB_ISSUER as t, issuerName as u };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as Labels, C as Author, D as Handle, E as Emoji, M as MessageId, N as MessageText, O as LabelKey, S as AttachmentId, T as ChannelPath, _ as BoardEvents, b as ActorKind, g as BoardEvent, h as BOARD_SESSION, i as ChannelsState, j as MESSAGE_TEXT_MAX, k as LabelValue, l as ExternalAuthor, m as Origin, n as ActorsState, o as Message, r as Channel, s as MessagesState, t as Actor, v as ATTACHMENTS_PER_MESSAGE_MAX, w as CHANNEL_PATH_MAX, x as Attachment, y as ActorId } from "../folds-
|
|
2
|
-
import { l as Reducer, n as Contract } from "../reducer-CYPHsSmd-
|
|
1
|
+
import { A as Labels, C as Author, D as Handle, E as Emoji, M as MessageId, N as MessageText, O as LabelKey, S as AttachmentId, T as ChannelPath, _ as BoardEvents, b as ActorKind, g as BoardEvent, h as BOARD_SESSION, i as ChannelsState, j as MESSAGE_TEXT_MAX, k as LabelValue, l as ExternalAuthor, m as Origin, n as ActorsState, o as Message, r as Channel, s as MessagesState, t as Actor, v as ATTACHMENTS_PER_MESSAGE_MAX, w as CHANNEL_PATH_MAX, x as Attachment, y as ActorId } from "../folds-8wRRXjAt.mjs";
|
|
2
|
+
import { l as Reducer, n as Contract } from "../reducer-CYPHsSmd-BXjGiptm.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/contract/files.d.ts
|
|
5
5
|
/** Under Vercel Functions' 4.5 MB request body limit, so an upload fits in one request. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as DIRECT_UPLOAD_BYTES_MAX, r as IMPORT_BYTES_MAX, t as ATTACHMENT_BYTES_MAX } from "../files-SniSmeEr.mjs";
|
|
2
|
-
import { a as AttachmentId, c as ChannelPath, d as LabelKey, f as LabelValue, g as MessageText, h as MessageId, i as Attachment, l as Emoji, m as MESSAGE_TEXT_MAX, n as ActorId, o as Author, p as Labels, r as ActorKind, s as CHANNEL_PATH_MAX, t as ATTACHMENTS_PER_MESSAGE_MAX, u as Handle } from "../schemas-
|
|
3
|
-
import { o as Origin } from "../external-
|
|
4
|
-
import { _ as BOARD_SESSION, i as messagesReducer, l as boardContract, n as channelsReducer, t as actorsReducer } from "../reducers-
|
|
2
|
+
import { a as AttachmentId, c as ChannelPath, d as LabelKey, f as LabelValue, g as MessageText, h as MessageId, i as Attachment, l as Emoji, m as MESSAGE_TEXT_MAX, n as ActorId, o as Author, p as Labels, r as ActorKind, s as CHANNEL_PATH_MAX, t as ATTACHMENTS_PER_MESSAGE_MAX, u as Handle } from "../schemas-DBmUO6pr.mjs";
|
|
3
|
+
import { o as Origin } from "../external-D3p5T57R.mjs";
|
|
4
|
+
import { _ as BOARD_SESSION, i as messagesReducer, l as boardContract, n as channelsReducer, t as actorsReducer } from "../reducers-8jqLewgw.mjs";
|
|
5
5
|
export { ATTACHMENTS_PER_MESSAGE_MAX, ATTACHMENT_BYTES_MAX, ActorId, ActorKind, Attachment, AttachmentId, Author, BOARD_SESSION, CHANNEL_PATH_MAX, ChannelPath, DIRECT_UPLOAD_BYTES_MAX, Emoji, Handle, IMPORT_BYTES_MAX, LabelKey, LabelValue, Labels, MESSAGE_TEXT_MAX, MessageId, MessageText, Origin, actorsReducer, boardContract, channelsReducer, messagesReducer };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as A2Scheduler } from "../server-
|
|
1
|
+
import { t as A2Scheduler } from "../server-B9gu0qi1-DI1WvcVK.mjs";
|
|
2
2
|
//#region src/scheduler/local.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* A scheduler in this process (`@vercel/board/backend-a2/scheduler-local`): each task runs at its time on
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as localScheduler } from "../local-
|
|
1
|
+
import { t as localScheduler } from "../local-C76Fy5ad.mjs";
|
|
2
2
|
export { localScheduler };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as Clock } from "../store-
|
|
2
|
-
import { i as SchedulerTask, t as A2Scheduler } from "../server-
|
|
3
|
-
//#region ../../node_modules/.pnpm/experimental-a2@0.
|
|
1
|
+
import { n as Clock } from "../store-DEzcHZOA-B-5vhxef.mjs";
|
|
2
|
+
import { i as SchedulerTask, t as A2Scheduler } from "../server-B9gu0qi1-DI1WvcVK.mjs";
|
|
3
|
+
//#region ../../node_modules/.pnpm/experimental-a2@0.24.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__b1e2c243a963f2620a5d202817417c26/node_modules/experimental-a2/dist/scheduler-qstash.d.ts
|
|
4
4
|
//#region src/scheduler-qstash.d.ts
|
|
5
5
|
type QStashStoreOutage = {
|
|
6
6
|
version: 1;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { t as A2Error } from "../session-clear-
|
|
2
|
-
import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "../server-
|
|
3
|
-
import { _ as serverInternals, l as assertSchedulerTargets, t as DRAIN_TIMINGS, u as classifySchedulerSendFailure } from "../internal-CvsrprnU-
|
|
4
|
-
import { n as platformVercelOidcToken } from "../platform-B4TnJtWu-
|
|
5
|
-
import { t as retryableLazy } from "../retryable-lazy-DZWmHpii-
|
|
6
|
-
import { n as SYSTEM_CLOCK } from "../store-N8PXxDAS-
|
|
7
|
-
import { t as normalizeSchedulerTask } from "../scheduler-task-X1SToDjP-
|
|
8
|
-
//#region ../../node_modules/.pnpm/experimental-a2@0.
|
|
1
|
+
import { t as A2Error } from "../session-clear-XJYpmUpg-2q8l_FJR.mjs";
|
|
2
|
+
import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "../server-DX7mM6nm-D7N_7bug.mjs";
|
|
3
|
+
import { _ as serverInternals, l as assertSchedulerTargets, t as DRAIN_TIMINGS, u as classifySchedulerSendFailure } from "../internal-CvsrprnU-zZMpDiRY.mjs";
|
|
4
|
+
import { n as platformVercelOidcToken } from "../platform-B4TnJtWu-Do3agKr5.mjs";
|
|
5
|
+
import { t as retryableLazy } from "../retryable-lazy-DZWmHpii-DpTc5PIP.mjs";
|
|
6
|
+
import { n as SYSTEM_CLOCK } from "../store-N8PXxDAS-DWWgv-Vz.mjs";
|
|
7
|
+
import { t as normalizeSchedulerTask } from "../scheduler-task-X1SToDjP-D2Il2rln.mjs";
|
|
8
|
+
//#region ../../node_modules/.pnpm/experimental-a2@0.24.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__b1e2c243a963f2620a5d202817417c26/node_modules/experimental-a2/dist/scheduler-qstash.js
|
|
9
9
|
/**
|
|
10
10
|
* experimental-a2/scheduler-qstash — HTTP scheduler over Upstash QStash.
|
|
11
11
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as Clock } from "../store-
|
|
2
|
-
import { i as SchedulerTask, t as A2Scheduler } from "../server-
|
|
3
|
-
//#region ../../node_modules/.pnpm/experimental-a2@0.
|
|
1
|
+
import { n as Clock } from "../store-DEzcHZOA-B-5vhxef.mjs";
|
|
2
|
+
import { i as SchedulerTask, t as A2Scheduler } from "../server-B9gu0qi1-DI1WvcVK.mjs";
|
|
3
|
+
//#region ../../node_modules/.pnpm/experimental-a2@0.24.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__b1e2c243a963f2620a5d202817417c26/node_modules/experimental-a2/dist/scheduler-vercel.d.ts
|
|
4
4
|
type QueueDeliveryMetadata = {
|
|
5
5
|
messageId: string;
|
|
6
6
|
deliveryCount: number;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "../server-
|
|
2
|
-
import { _ as serverInternals, l as assertSchedulerTargets, t as DRAIN_TIMINGS, u as classifySchedulerSendFailure } from "../internal-CvsrprnU-
|
|
3
|
-
import { t as retryableLazy } from "../retryable-lazy-DZWmHpii-
|
|
4
|
-
import { n as SYSTEM_CLOCK } from "../store-N8PXxDAS-
|
|
5
|
-
import { t as normalizeSchedulerTask } from "../scheduler-task-X1SToDjP-
|
|
1
|
+
import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "../server-DX7mM6nm-D7N_7bug.mjs";
|
|
2
|
+
import { _ as serverInternals, l as assertSchedulerTargets, t as DRAIN_TIMINGS, u as classifySchedulerSendFailure } from "../internal-CvsrprnU-zZMpDiRY.mjs";
|
|
3
|
+
import { t as retryableLazy } from "../retryable-lazy-DZWmHpii-DpTc5PIP.mjs";
|
|
4
|
+
import { n as SYSTEM_CLOCK } from "../store-N8PXxDAS-DWWgv-Vz.mjs";
|
|
5
|
+
import { t as normalizeSchedulerTask } from "../scheduler-task-X1SToDjP-D2Il2rln.mjs";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
|
-
//#region ../../node_modules/.pnpm/experimental-a2@0.
|
|
7
|
+
//#region ../../node_modules/.pnpm/experimental-a2@0.24.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__b1e2c243a963f2620a5d202817417c26/node_modules/experimental-a2/dist/scheduler-vercel.js
|
|
8
8
|
/**
|
|
9
9
|
* experimental-a2/scheduler-vercel — queue-backed scheduler over Vercel Queues.
|
|
10
10
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as Clock } from "../store-
|
|
2
|
-
import { t as BoardStore } from "../types-
|
|
1
|
+
import { n as Clock } from "../store-DEzcHZOA-B-5vhxef.mjs";
|
|
2
|
+
import { t as BoardStore } from "../types-shZmGZ-q.mjs";
|
|
3
3
|
//#region src/store/memory.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* A board that lives in memory, for tests: its log in A2's memory store, its
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { r as sqlTables } from "../sql-
|
|
2
|
-
import { t as sqliteDb } from "../sqlite-db-
|
|
3
|
-
import { t as memory$1 } from "../store-memory-
|
|
1
|
+
import { r as sqlTables } from "../sql-Bj0fk6dn.mjs";
|
|
2
|
+
import { t as sqliteDb } from "../sqlite-db-Dc8G78XV.mjs";
|
|
3
|
+
import { t as memory$1 } from "../store-memory-B0PkVSuQ.mjs";
|
|
4
4
|
//#region src/store/memory.ts
|
|
5
5
|
/**
|
|
6
6
|
* A board that lives in memory, for tests: its log in A2's memory store, its
|