@argentic/chest-sdk 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +381 -35
- package/client/index.ts +10 -5
- package/client/src/api.ts +81 -0
- package/client/src/errors.ts +14 -3
- package/client/src/events.ts +228 -0
- package/client/src/files.ts +93 -88
- package/client/src/member.ts +40 -17
- package/client/src/members.ts +167 -0
- package/client/src/notifications.ts +148 -0
- package/client/src/testing.ts +417 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/src/api.d.ts +9 -0
- package/dist/src/api.d.ts.map +1 -0
- package/dist/src/api.js +88 -0
- package/dist/src/api.js.map +1 -0
- package/dist/src/errors.d.ts +3 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +13 -3
- package/dist/src/errors.js.map +1 -1
- package/dist/src/events.d.ts +56 -0
- package/dist/src/events.d.ts.map +1 -0
- package/dist/src/events.js +193 -0
- package/dist/src/events.js.map +1 -0
- package/dist/src/files.d.ts +17 -1
- package/dist/src/files.d.ts.map +1 -1
- package/dist/src/files.js +95 -92
- package/dist/src/files.js.map +1 -1
- package/dist/src/member.d.ts +6 -3
- package/dist/src/member.d.ts.map +1 -1
- package/dist/src/member.js +22 -11
- package/dist/src/member.js.map +1 -1
- package/dist/src/members.d.ts +34 -0
- package/dist/src/members.d.ts.map +1 -0
- package/dist/src/members.js +146 -0
- package/dist/src/members.js.map +1 -0
- package/dist/src/notifications.d.ts +25 -0
- package/dist/src/notifications.d.ts.map +1 -0
- package/dist/src/notifications.js +121 -0
- package/dist/src/notifications.js.map +1 -0
- package/dist/src/testing.d.ts +70 -0
- package/dist/src/testing.d.ts.map +1 -0
- package/dist/src/testing.js +419 -0
- package/dist/src/testing.js.map +1 -0
- package/package.json +28 -4
package/dist/src/member.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
// The grammars of the identifiers the Chest mints: a tool may check with them
|
|
3
|
+
// the identifiers it stores.
|
|
4
|
+
export const memberIdPattern = /^mbr_[a-z2-7]{26}$/u;
|
|
5
|
+
export const groupIdPattern = /^grp_[a-z2-7]{26}$/u;
|
|
2
6
|
// The key of the assertions is HMAC-SHA256 of this label under the text of
|
|
3
|
-
// CHEST_TOKEN, exactly as the Chest derives it (chest/toolfront).
|
|
4
|
-
|
|
7
|
+
// CHEST_TOKEN, exactly as the Chest derives it (chest/toolfront). Its version
|
|
8
|
+
// is the shape of the claims: an assertion of another shape is refused. This
|
|
9
|
+
// module stands alone (node:* only), so that it can be copied by itself.
|
|
10
|
+
const label = "Chest-Member v2";
|
|
11
|
+
// The claims every assertion carries; email only for a tool that holds
|
|
12
|
+
// members.email.
|
|
13
|
+
const claims = ["iss", "aud", "iat", "exp", "sub", "given_name", "family_name", "name", "picture", "role", "admin", "builder", "groups"];
|
|
5
14
|
// Clocks of the Chest and of the container may differ by this much, in seconds.
|
|
6
15
|
const skew = 5;
|
|
7
16
|
// An assertion is a few hundred bytes; anything longer is not one.
|
|
8
17
|
const maxLength = 8192;
|
|
9
18
|
const compact = /^([A-Za-z0-9_-]+)\.([A-Za-z0-9_-]+)\.([A-Za-z0-9_-]+)$/u;
|
|
10
|
-
const claims = ["iss", "aud", "iat", "exp", "sub", "given_name", "family_name", "name", "email", "picture", "role", "admin", "builder"];
|
|
11
19
|
function assertionOf(request) {
|
|
12
20
|
const headers = request.headers;
|
|
13
21
|
// A Web Request joins repeated headers with ", ", which no assertion
|
|
@@ -26,10 +34,11 @@ function json(part) {
|
|
|
26
34
|
}
|
|
27
35
|
// member returns who the Chest says is making this request, or null when the
|
|
28
36
|
// request carries no valid assertion — absent, malformed, signed with another
|
|
29
|
-
// key, for another tool, expired or not yet valid —, or
|
|
30
|
-
// CHEST_TOOL is missing. It never throws for what a
|
|
31
|
-
// Chest's front reaches the tool; the signature is a
|
|
32
|
-
// tool still decides what a member may do with its
|
|
37
|
+
// key or for another shape, for another tool, expired or not yet valid —, or
|
|
38
|
+
// when CHEST_TOKEN or CHEST_TOOL is missing. It never throws for what a
|
|
39
|
+
// request carries. Only the Chest's front reaches the tool; the signature is a
|
|
40
|
+
// second defence, and the tool still decides what a member may do with its
|
|
41
|
+
// own rules.
|
|
33
42
|
export function member(request) {
|
|
34
43
|
const token = process.env["CHEST_TOKEN"];
|
|
35
44
|
const tool = process.env["CHEST_TOOL"];
|
|
@@ -51,16 +60,18 @@ export function member(request) {
|
|
|
51
60
|
const payload = json(encodedPayload);
|
|
52
61
|
if (!payload || !claims.every(name => Object.hasOwn(payload, name)))
|
|
53
62
|
return null;
|
|
54
|
-
const { iss, aud, iat, exp, sub, given_name, family_name, name, email, picture, role, admin, builder } = payload;
|
|
55
|
-
if (typeof iss !== "string" || iss === "" || aud !== tool || typeof sub !== "string" || sub
|
|
63
|
+
const { iss, aud, iat, exp, sub, given_name, family_name, name, email, picture, role, admin, builder, groups } = payload;
|
|
64
|
+
if (typeof iss !== "string" || iss === "" || aud !== tool || typeof sub !== "string" || !memberIdPattern.test(sub))
|
|
56
65
|
return null;
|
|
57
66
|
if (typeof iat !== "number" || !Number.isSafeInteger(iat) || typeof exp !== "number" || !Number.isSafeInteger(exp) || exp <= iat)
|
|
58
67
|
return null;
|
|
59
68
|
const now = Math.floor(Date.now() / 1000);
|
|
60
69
|
if (iat > now + skew || exp <= now - skew)
|
|
61
70
|
return null;
|
|
62
|
-
if (typeof given_name !== "string" || typeof family_name !== "string" || typeof name !== "string" || typeof
|
|
71
|
+
if (typeof given_name !== "string" || typeof family_name !== "string" || typeof name !== "string" || typeof picture !== "string" || typeof role !== "string" || typeof admin !== "boolean" || typeof builder !== "boolean")
|
|
63
72
|
return null;
|
|
64
|
-
|
|
73
|
+
if (!Array.isArray(groups) || groups.length > 16 || !groups.every(g => typeof g === "string" && groupIdPattern.test(g)) || (email !== undefined && typeof email !== "string"))
|
|
74
|
+
return null;
|
|
75
|
+
return { id: sub, firstName: given_name, lastName: family_name, name, photo: picture === "" ? null : picture, role: role === "" ? null : role, isAdmin: admin, isBuilder: builder, groups: [...groups], ...(email === undefined ? {} : { email }) };
|
|
65
76
|
}
|
|
66
77
|
//# sourceMappingURL=member.js.map
|
package/dist/src/member.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"member.js","sourceRoot":"","sources":["../../client/src/member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"member.js","sourceRoot":"","sources":["../../client/src/member.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Member } from "./member.js";
|
|
2
|
+
export type MemberPage = {
|
|
3
|
+
members: Member[];
|
|
4
|
+
next: string | null;
|
|
5
|
+
};
|
|
6
|
+
export type FormerMember = {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string | null;
|
|
9
|
+
status: "former" | "erased";
|
|
10
|
+
};
|
|
11
|
+
export type Lookup = {
|
|
12
|
+
members: Member[];
|
|
13
|
+
former: FormerMember[];
|
|
14
|
+
unknown: string[];
|
|
15
|
+
};
|
|
16
|
+
export type Group = {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
members: string[];
|
|
20
|
+
};
|
|
21
|
+
export declare function list(options?: {
|
|
22
|
+
after?: string;
|
|
23
|
+
limit?: number;
|
|
24
|
+
q?: string;
|
|
25
|
+
role?: string;
|
|
26
|
+
group?: string;
|
|
27
|
+
}): Promise<MemberPage>;
|
|
28
|
+
export declare function get(id: string): Promise<Member | null>;
|
|
29
|
+
export declare function forget(): void;
|
|
30
|
+
export declare function lookup(ids: Iterable<string>): Promise<Lookup>;
|
|
31
|
+
export declare const groups: {
|
|
32
|
+
list(): Promise<Group[]>;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=members.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../../client/src/members.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmC,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAoB3E,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAIpE,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAAE,CAAC;AAG5F,MAAM,MAAM,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEtF,MAAM,MAAM,KAAK,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA2BpE,wBAAsB,IAAI,CAAC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAkB3I;AAID,wBAAsB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ5D;AASD,wBAAgB,MAAM,IAAI,IAAI,CAE7B;AAYD,wBAAsB,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCnE;AAID,eAAO,MAAM,MAAM;IACX,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;CAW/B,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { ask, json, refusal } from "./api.js";
|
|
2
|
+
import { ChestError, Unavailable } from "./errors.js";
|
|
3
|
+
import { groupIdPattern, memberIdPattern } from "./member.js";
|
|
4
|
+
const maxLimit = 500;
|
|
5
|
+
const lookupBatch = 200;
|
|
6
|
+
const cacheTime = 60_000;
|
|
7
|
+
const cacheSize = 5000;
|
|
8
|
+
function checkId(id) {
|
|
9
|
+
if (typeof id !== "string" || !memberIdPattern.test(id))
|
|
10
|
+
throw new ChestError("invalid_id", 400, "invalid member identifier");
|
|
11
|
+
return id;
|
|
12
|
+
}
|
|
13
|
+
const text = (value, max) => typeof value === "string" && value.length <= max;
|
|
14
|
+
// shown reads a member as the Chest answers it; anything else is not the
|
|
15
|
+
// Chest's answer.
|
|
16
|
+
function shown(value) {
|
|
17
|
+
const m = value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
18
|
+
if (!m || typeof m["id"] !== "string" || !memberIdPattern.test(m["id"]) || !text(m["first_name"], 256) || !text(m["last_name"], 256) || !text(m["name"], 520) || !(m["photo"] === null || text(m["photo"], 200)) || !(m["role"] === null || text(m["role"], 48)) || typeof m["admin"] !== "boolean" || typeof m["builder"] !== "boolean" || !Array.isArray(m["groups"]) || m["groups"].length > 16 || !m["groups"].every(g => typeof g === "string" && groupIdPattern.test(g)) || !(m["email"] === undefined || text(m["email"], 254)))
|
|
19
|
+
throw new Unavailable();
|
|
20
|
+
return { id: m["id"], firstName: m["first_name"], lastName: m["last_name"], name: m["name"], photo: m["photo"], role: m["role"], isAdmin: m["admin"], isBuilder: m["builder"], groups: [...m["groups"]], ...(m["email"] === undefined ? {} : { email: m["email"] }) };
|
|
21
|
+
}
|
|
22
|
+
// list says the members who have the tool, by name then identifier, limit
|
|
23
|
+
// at a time (100 by default, 500 at most), after the cursor of the previous
|
|
24
|
+
// page. q finds the start of a first name, a last name or a name (and of an
|
|
25
|
+
// address with members.email), whatever its case and accents; role and group
|
|
26
|
+
// keep the members of that role, or of that group.
|
|
27
|
+
export async function list(options = {}) {
|
|
28
|
+
const query = new URLSearchParams();
|
|
29
|
+
if (options.after !== undefined)
|
|
30
|
+
query.set("after", options.after);
|
|
31
|
+
if (options.limit !== undefined) {
|
|
32
|
+
if (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > maxLimit)
|
|
33
|
+
throw new ChestError("invalid_query", 400, "limit is 1 to 500");
|
|
34
|
+
query.set("limit", String(options.limit));
|
|
35
|
+
}
|
|
36
|
+
if (options.q !== undefined && options.q !== "")
|
|
37
|
+
query.set("q", options.q);
|
|
38
|
+
if (options.role !== undefined)
|
|
39
|
+
query.set("role", options.role);
|
|
40
|
+
if (options.group !== undefined) {
|
|
41
|
+
if (!groupIdPattern.test(options.group))
|
|
42
|
+
throw new ChestError("invalid_query", 400, "invalid group identifier");
|
|
43
|
+
query.set("group", options.group);
|
|
44
|
+
}
|
|
45
|
+
const response = await ask("members", "GET", "/members" + (query.size ? "?" + query.toString() : ""));
|
|
46
|
+
if (response.status !== 200)
|
|
47
|
+
throw await refusal(response, "members");
|
|
48
|
+
const page = (await json(response));
|
|
49
|
+
if (!page || !Array.isArray(page.members) || page.members.length > maxLimit || !(page.next === null || text(page.next, 1024)))
|
|
50
|
+
throw new Unavailable();
|
|
51
|
+
return { members: page.members.map(shown), next: page.next };
|
|
52
|
+
}
|
|
53
|
+
// get is the member of that identifier, or null when the tool does not know
|
|
54
|
+
// them: never a member, a former one, or one without access.
|
|
55
|
+
export async function get(id) {
|
|
56
|
+
const response = await ask("members", "GET", "/members/" + checkId(id));
|
|
57
|
+
if (response.status === 404) {
|
|
58
|
+
await response.body?.cancel();
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (response.status !== 200)
|
|
62
|
+
throw await refusal(response, "members");
|
|
63
|
+
return shown(await json(response));
|
|
64
|
+
}
|
|
65
|
+
const known = new Map();
|
|
66
|
+
// forget empties what lookup keeps: the next lookup asks the Chest again.
|
|
67
|
+
export function forget() {
|
|
68
|
+
known.clear();
|
|
69
|
+
}
|
|
70
|
+
function keep(id, answer) {
|
|
71
|
+
known.delete(id);
|
|
72
|
+
known.set(id, { ...answer, at: Date.now() });
|
|
73
|
+
while (known.size > cacheSize)
|
|
74
|
+
known.delete(known.keys().next().value);
|
|
75
|
+
}
|
|
76
|
+
// lookup resolves identifiers, each once, in the order given: the members
|
|
77
|
+
// who have the tool, the former members who had it, and the identifiers it
|
|
78
|
+
// does not know. Any number of them: the SDK asks 200 at a time, and keeps
|
|
79
|
+
// each answer a minute.
|
|
80
|
+
export async function lookup(ids) {
|
|
81
|
+
const wanted = [...new Set([...ids].map(checkId))];
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
const missing = wanted.filter(id => {
|
|
84
|
+
const k = known.get(id);
|
|
85
|
+
return !k || now - k.at >= cacheTime;
|
|
86
|
+
});
|
|
87
|
+
for (let i = 0; i < missing.length; i += lookupBatch) {
|
|
88
|
+
const batch = missing.slice(i, i + lookupBatch);
|
|
89
|
+
const response = await ask("members", "POST", "/members/lookup", { body: JSON.stringify({ ids: batch }), type: "application/json" });
|
|
90
|
+
if (response.status !== 200)
|
|
91
|
+
throw await refusal(response, "members");
|
|
92
|
+
const answer = (await json(response));
|
|
93
|
+
if (!answer || !Array.isArray(answer.members) || !Array.isArray(answer.former) || !Array.isArray(answer.unknown))
|
|
94
|
+
throw new Unavailable();
|
|
95
|
+
const told = new Set();
|
|
96
|
+
for (const m of answer.members.map(shown)) {
|
|
97
|
+
keep(m.id, { member: m });
|
|
98
|
+
told.add(m.id);
|
|
99
|
+
}
|
|
100
|
+
for (const value of answer.former) {
|
|
101
|
+
const f = value;
|
|
102
|
+
if (!f || typeof f.id !== "string" || !memberIdPattern.test(f.id) || !(f.status === "former" ? f.name === undefined || text(f.name, 520) : f.status === "erased" && f.name === undefined))
|
|
103
|
+
throw new Unavailable();
|
|
104
|
+
keep(f.id, { former: { id: f.id, name: f.name ?? null, status: f.status } });
|
|
105
|
+
told.add(f.id);
|
|
106
|
+
}
|
|
107
|
+
for (const id of answer.unknown) {
|
|
108
|
+
if (typeof id !== "string" || !memberIdPattern.test(id))
|
|
109
|
+
throw new Unavailable();
|
|
110
|
+
keep(id, { unknown: true });
|
|
111
|
+
told.add(id);
|
|
112
|
+
}
|
|
113
|
+
if (batch.some(id => !told.has(id)))
|
|
114
|
+
throw new Unavailable();
|
|
115
|
+
}
|
|
116
|
+
const result = { members: [], former: [], unknown: [] };
|
|
117
|
+
for (const id of wanted) {
|
|
118
|
+
const k = known.get(id);
|
|
119
|
+
if (k && "member" in k)
|
|
120
|
+
result.members.push(k.member);
|
|
121
|
+
else if (k && "former" in k)
|
|
122
|
+
result.former.push(k.former);
|
|
123
|
+
else
|
|
124
|
+
result.unknown.push(id);
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
// groups are the groups of the Chest that give the tool, each with the
|
|
129
|
+
// identifiers of its members; nothing of the others.
|
|
130
|
+
export const groups = {
|
|
131
|
+
async list() {
|
|
132
|
+
const response = await ask("members", "GET", "/groups");
|
|
133
|
+
if (response.status !== 200)
|
|
134
|
+
throw await refusal(response, "members");
|
|
135
|
+
const answer = (await json(response));
|
|
136
|
+
if (!answer || !Array.isArray(answer.groups) || answer.groups.length > 16)
|
|
137
|
+
throw new Unavailable();
|
|
138
|
+
return answer.groups.map(value => {
|
|
139
|
+
const g = value;
|
|
140
|
+
if (!g || typeof g.id !== "string" || !groupIdPattern.test(g.id) || !text(g.name, 256) || !Array.isArray(g.members) || g.members.length > 128 || !g.members.every(m => typeof m === "string" && memberIdPattern.test(m)))
|
|
141
|
+
throw new Unavailable();
|
|
142
|
+
return { id: g.id, name: g.name, members: [...g.members] };
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=members.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members.js","sourceRoot":"","sources":["../../client/src/members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAe,MAAM,aAAa,CAAC;AA+B3E,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,SAAS,GAAG,MAAM,CAAC;AACzB,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvB,SAAS,OAAO,CAAC,EAAW;IAC1B,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,YAAY,EAAE,GAAG,EAAE,2BAA2B,CAAC,CAAC;IAC9H,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,GAAW,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC;AAEhH,yEAAyE;AACzE,kBAAkB;AAClB,SAAS,KAAK,CAAC,KAAc;IAC3B,MAAM,CAAC,GAAG,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAgC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzH,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QAAE,MAAM,IAAI,WAAW,EAAE,CAAC;IAChiB,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAa,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AACpR,CAAC;AAED,0EAA0E;AAC1E,4EAA4E;AAC5E,4EAA4E;AAC5E,6EAA6E;AAC7E,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAO,GAAkF,EAAE;IACpH,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IACpC,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACnE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,GAAG,QAAQ;YAAE,MAAM,IAAI,UAAU,CAAC,eAAe,EAAE,GAAG,EAAE,mBAAmB,CAAC,CAAC;QACvJ,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,KAAK,EAAE;QAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,eAAe,EAAE,GAAG,EAAE,0BAA0B,CAAC,CAAC;QAChH,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,MAAM,MAAM,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAiD,CAAC;IACpF,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,WAAW,EAAE,CAAC;IACvJ,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AAC/D,CAAC;AAED,4EAA4E;AAC5E,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,EAAU;IAClC,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;IACxE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,MAAM,MAAM,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACtE,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACrC,CAAC;AAMD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAiB,CAAC;AAEvC,0EAA0E;AAC1E,MAAM,UAAU,MAAM;IACpB,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED,SAAS,IAAI,CAAC,EAAU,EAAE,MAAyB;IACjD,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjB,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAW,CAAC,CAAC;IACtD,OAAO,KAAK,CAAC,IAAI,GAAG,SAAS;QAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAe,CAAC,CAAC;AACnF,CAAC;AAED,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,wBAAwB;AACxB,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAqB;IAChD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;QACjC,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxB,OAAO,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,IAAI,SAAS,CAAC;IACvC,CAAC,CAAC,CAAC;IACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACrI,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,MAAM,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAsE,CAAC;QAC3G,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,MAAM,IAAI,WAAW,EAAE,CAAC;QAC1I,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,KAAkE,CAAC;YAC7E,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;gBAAE,MAAM,IAAI,WAAW,EAAE,CAAC;YACnN,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAG,CAAC,CAAC,IAA2B,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAgC,EAAE,EAAE,CAAC,CAAC;YAC/H,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAChC,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,MAAM,IAAI,WAAW,EAAE,CAAC;YACjF,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACf,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAAE,MAAM,IAAI,WAAW,EAAE,CAAC;IAC/D,CAAC;IACD,MAAM,MAAM,GAAW,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAChE,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC;YAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;aACjD,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC;YAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;;YACrD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,uEAAuE;AACvE,qDAAqD;AACrD,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,KAAK,CAAC,IAAI;QACR,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QACxD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,MAAM,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAgC,CAAC;QACrE,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE;YAAE,MAAM,IAAI,WAAW,EAAE,CAAC;QACnG,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YAC/B,MAAM,CAAC,GAAG,KAAmE,CAAC;YAC9E,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAAE,MAAM,IAAI,WAAW,EAAE,CAAC;YAClP,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAa,EAAE,CAAC;QACzE,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type Notice = {
|
|
2
|
+
title: string;
|
|
3
|
+
body?: string;
|
|
4
|
+
path?: string;
|
|
5
|
+
key?: string;
|
|
6
|
+
};
|
|
7
|
+
export type Delivery = {
|
|
8
|
+
delivered: string[];
|
|
9
|
+
skipped: string[];
|
|
10
|
+
};
|
|
11
|
+
export type BadgeCount = {
|
|
12
|
+
memberId: string;
|
|
13
|
+
count: number;
|
|
14
|
+
};
|
|
15
|
+
export type BadgeWrite = {
|
|
16
|
+
set: string[];
|
|
17
|
+
skipped: string[];
|
|
18
|
+
};
|
|
19
|
+
export declare function notify(memberIds: Iterable<string>, notice: Notice): Promise<Delivery>;
|
|
20
|
+
export declare function withdraw(key: string, memberIds?: Iterable<string>): Promise<void>;
|
|
21
|
+
export declare const badge: {
|
|
22
|
+
set(memberId: string, count: number): Promise<boolean>;
|
|
23
|
+
setMany(counts: Iterable<BadgeCount>): Promise<BadgeWrite>;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../client/src/notifications.ts"],"names":[],"mappings":"AA4BA,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAGnF,MAAM,MAAM,QAAQ,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAElE,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAG7D,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAiE9D,wBAAsB,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAU3F;AAKD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvF;AAID,eAAO,MAAM,KAAK;IAGV,GAAG,WAAW,MAAM,SAAS,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOtD,OAAO,SAAS,QAAQ,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;CAajE,CAAC"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ask as chest, json, refusal } from "./api.js";
|
|
2
|
+
import { ChestError, Unavailable } from "./errors.js";
|
|
3
|
+
import { memberIdPattern } from "./member.js";
|
|
4
|
+
// The bounds of a Chest.
|
|
5
|
+
const maxMembers = 500, maxTitle = 80, maxBody = 280, maxPath = 512, maxCount = 9999;
|
|
6
|
+
const keyPattern = /^[a-z0-9._:-]{1,64}$/u;
|
|
7
|
+
// What the Chest removes from a title before keeping it: control characters
|
|
8
|
+
// and the characters that reorder text.
|
|
9
|
+
const removed = /[\p{Cc}\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/gu;
|
|
10
|
+
const ask = (method, path, value) => chest("notifications", method, path, { body: JSON.stringify(value), type: "application/json" });
|
|
11
|
+
// expect lets through the one answer expected; a refusal is what the Chest
|
|
12
|
+
// says, any other success is not the Chest's.
|
|
13
|
+
async function expect(response, status) {
|
|
14
|
+
if (response.status === status)
|
|
15
|
+
return;
|
|
16
|
+
if (response.status < 400) {
|
|
17
|
+
await response.body?.cancel();
|
|
18
|
+
throw new Unavailable();
|
|
19
|
+
}
|
|
20
|
+
throw await refusal(response, "notifications");
|
|
21
|
+
}
|
|
22
|
+
const length = (s) => [...s].length;
|
|
23
|
+
function checkId(id) {
|
|
24
|
+
if (typeof id !== "string" || !memberIdPattern.test(id))
|
|
25
|
+
throw new ChestError("invalid_id", 400, "invalid member identifier");
|
|
26
|
+
return id;
|
|
27
|
+
}
|
|
28
|
+
// checkIds reads 1 to 500 member identifiers, as given.
|
|
29
|
+
function checkIds(ids) {
|
|
30
|
+
const all = [...ids];
|
|
31
|
+
if (all.length < 1 || all.length > maxMembers)
|
|
32
|
+
throw new ChestError("invalid_body", 400, "1 to 500 member identifiers");
|
|
33
|
+
return all.map(checkId);
|
|
34
|
+
}
|
|
35
|
+
function checkKey(key) {
|
|
36
|
+
if (typeof key !== "string" || !keyPattern.test(key))
|
|
37
|
+
throw new ChestError("invalid_key", 400, "a key is 1 to 64 of a-z 0-9 . _ : -");
|
|
38
|
+
return key;
|
|
39
|
+
}
|
|
40
|
+
function checkCount(count) {
|
|
41
|
+
if (typeof count !== "number" || !Number.isInteger(count) || count < 0 || count > maxCount)
|
|
42
|
+
throw new ChestError("invalid_count", 400, "a count is 0 to 9999");
|
|
43
|
+
return count;
|
|
44
|
+
}
|
|
45
|
+
// checkPath accepts /chest, or /chest followed by '/', '?' or '#': printable
|
|
46
|
+
// ASCII but '\', 512 bytes at most, never '//', no '.' or '..' segment
|
|
47
|
+
// (written %2e either).
|
|
48
|
+
function checkPath(path) {
|
|
49
|
+
if (typeof path !== "string" || path.length > maxPath || !/^\/chest([/?#][\x21-\x5b\x5d-\x7e]*)?$/u.test(path) || path.includes("//") || path.split(/[?#]/u)[0].split("/").some(s => /^(\.|%2e){1,2}$/iu.test(s)))
|
|
50
|
+
throw new ChestError("invalid_path", 400, "a path is /chest or under it");
|
|
51
|
+
return path;
|
|
52
|
+
}
|
|
53
|
+
// partition checks an answer that splits the identifiers asked, each once,
|
|
54
|
+
// in their order, between two lists of it; anything else is not the Chest's.
|
|
55
|
+
function partition(answer, first, second, asked) {
|
|
56
|
+
const a = answer !== null && typeof answer === "object" && !Array.isArray(answer) ? answer : null;
|
|
57
|
+
const lists = [a?.[first], a?.[second]];
|
|
58
|
+
if (!lists.every(l => Array.isArray(l) && l.every(id => typeof id === "string")))
|
|
59
|
+
throw new Unavailable();
|
|
60
|
+
const [one, two] = lists;
|
|
61
|
+
const wanted = [...new Set(asked)];
|
|
62
|
+
const inOrder = (l) => l.every((id, i) => wanted.indexOf(id) > (i === 0 ? -1 : wanted.indexOf(l[i - 1])));
|
|
63
|
+
if (one.length + two.length !== wanted.length || !inOrder(one) || !inOrder(two) || one.some(id => two.includes(id)))
|
|
64
|
+
throw new Unavailable();
|
|
65
|
+
return [[...one], [...two]];
|
|
66
|
+
}
|
|
67
|
+
// notify puts one item in the inbox of each member who has the tool, among
|
|
68
|
+
// 1 to 500 identifiers (each counted once). A link to path, on the tool's
|
|
69
|
+
// team host, opens it. With a key, the member's item of that key is replaced:
|
|
70
|
+
// new text, new time, first and unread again.
|
|
71
|
+
export async function notify(memberIds, notice) {
|
|
72
|
+
const members = checkIds(memberIds);
|
|
73
|
+
const { title, body, path, key } = notice;
|
|
74
|
+
if (typeof title !== "string" || length(title) < 1 || length(title) > maxTitle || title.replace(removed, "").trim() === "")
|
|
75
|
+
throw new ChestError("invalid_title", 400, "a title is 1 to 80 characters");
|
|
76
|
+
if (body !== undefined && (typeof body !== "string" || length(body) > maxBody))
|
|
77
|
+
throw new ChestError("invalid_text", 400, "a body is 280 characters at most");
|
|
78
|
+
const command = { members, title, ...(body ? { body } : {}), ...(path !== undefined ? { path: checkPath(path) } : {}), ...(key !== undefined ? { key: checkKey(key) } : {}) };
|
|
79
|
+
const response = await ask("POST", "/notifications", command);
|
|
80
|
+
await expect(response, 200);
|
|
81
|
+
const [delivered, skipped] = partition(await json(response), "delivered", "skipped", members);
|
|
82
|
+
return { delivered, skipped };
|
|
83
|
+
}
|
|
84
|
+
// withdraw removes the items of that key, from every member or from those
|
|
85
|
+
// named (1 to 500): the thing they were about is done. It never says what
|
|
86
|
+
// existed.
|
|
87
|
+
export async function withdraw(key, memberIds) {
|
|
88
|
+
const command = { key: checkKey(key), ...(memberIds !== undefined ? { members: checkIds(memberIds) } : {}) };
|
|
89
|
+
const response = await ask("POST", "/notifications/withdraw", command);
|
|
90
|
+
await expect(response, 204);
|
|
91
|
+
}
|
|
92
|
+
// badge sets the count shown on the tool's tile for a member (0 to 9,999; 0
|
|
93
|
+
// clears it): a state, not an event, so setting it again changes nothing.
|
|
94
|
+
export const badge = {
|
|
95
|
+
// set is true once the member's badge is set, false when they do not have
|
|
96
|
+
// the tool.
|
|
97
|
+
async set(memberId, count) {
|
|
98
|
+
checkId(memberId);
|
|
99
|
+
const response = await ask("PUT", "/badges/" + memberId, { count: checkCount(count) });
|
|
100
|
+
await expect(response, 200);
|
|
101
|
+
return partition(await json(response), "set", "skipped", [memberId])[0].length === 1;
|
|
102
|
+
},
|
|
103
|
+
// setMany sets 1 to 500 badges, a member at most once.
|
|
104
|
+
async setMany(counts) {
|
|
105
|
+
const all = [...counts];
|
|
106
|
+
if (all.length < 1 || all.length > maxMembers)
|
|
107
|
+
throw new ChestError("invalid_body", 400, "1 to 500 badges");
|
|
108
|
+
const badges = all.map(b => {
|
|
109
|
+
if (b === null || typeof b !== "object")
|
|
110
|
+
throw new ChestError("invalid_body", 400, "a badge is {memberId, count}");
|
|
111
|
+
return { member: checkId(b.memberId), count: checkCount(b.count) };
|
|
112
|
+
});
|
|
113
|
+
if (new Set(badges.map(b => b.member)).size !== badges.length)
|
|
114
|
+
throw new ChestError("invalid_body", 400, "a member at most once");
|
|
115
|
+
const response = await ask("PUT", "/badges", { badges });
|
|
116
|
+
await expect(response, 200);
|
|
117
|
+
const [set, skipped] = partition(await json(response), "set", "skipped", badges.map(b => b.member));
|
|
118
|
+
return { set, skipped };
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../client/src/notifications.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type IncomingMessage } from "node:http";
|
|
2
|
+
import type { ChestEvent } from "./events.js";
|
|
3
|
+
import { type Member } from "./member.js";
|
|
4
|
+
export type FakeGroup = {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
members: string[];
|
|
8
|
+
};
|
|
9
|
+
export type FakeFile = {
|
|
10
|
+
data: Uint8Array;
|
|
11
|
+
type: string;
|
|
12
|
+
updated: string;
|
|
13
|
+
};
|
|
14
|
+
export type FakeNotification = {
|
|
15
|
+
member: string;
|
|
16
|
+
title: string;
|
|
17
|
+
body?: string;
|
|
18
|
+
path: string;
|
|
19
|
+
key?: string;
|
|
20
|
+
};
|
|
21
|
+
export type FakeChestOptions = {
|
|
22
|
+
members?: Member[];
|
|
23
|
+
former?: {
|
|
24
|
+
id: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
erased?: boolean;
|
|
27
|
+
}[];
|
|
28
|
+
groups?: FakeGroup[];
|
|
29
|
+
capabilities?: string[];
|
|
30
|
+
receives?: string[];
|
|
31
|
+
files?: Record<string, {
|
|
32
|
+
data: Uint8Array | string;
|
|
33
|
+
type?: string;
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
36
|
+
export type FakeEvent = {
|
|
37
|
+
[K in ChestEvent["type"]]: {
|
|
38
|
+
type: K;
|
|
39
|
+
data: Extract<ChestEvent, {
|
|
40
|
+
type: K;
|
|
41
|
+
}>["data"];
|
|
42
|
+
id?: string;
|
|
43
|
+
occurredAt?: string;
|
|
44
|
+
};
|
|
45
|
+
}[ChestEvent["type"]];
|
|
46
|
+
export type FakeChest = {
|
|
47
|
+
api: string;
|
|
48
|
+
token: string;
|
|
49
|
+
tool: string;
|
|
50
|
+
members: Member[];
|
|
51
|
+
groups: FakeGroup[];
|
|
52
|
+
files: Map<string, FakeFile>;
|
|
53
|
+
notifications: FakeNotification[];
|
|
54
|
+
badges: Map<string, number>;
|
|
55
|
+
acknowledged: string[];
|
|
56
|
+
emit(event: FakeEvent, to: string | ((request: Request) => Response | Promise<Response>)): Promise<number>;
|
|
57
|
+
close(): Promise<void>;
|
|
58
|
+
};
|
|
59
|
+
export declare function signAssertion(member: Member, options?: {
|
|
60
|
+
token?: string;
|
|
61
|
+
tool?: string;
|
|
62
|
+
now?: Date;
|
|
63
|
+
}): string;
|
|
64
|
+
export declare function withMember<R extends Request | IncomingMessage>(request: R, member: Member, options?: {
|
|
65
|
+
token?: string;
|
|
66
|
+
tool?: string;
|
|
67
|
+
now?: Date;
|
|
68
|
+
}): R;
|
|
69
|
+
export declare function fakeChest(options?: FakeChestOptions): Promise<FakeChest>;
|
|
70
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../client/src/testing.ts"],"names":[],"mappings":"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"}
|