@loomcycle/bridge-discord 0.2.0 → 0.4.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/events.js ADDED
@@ -0,0 +1,80 @@
1
+ // POST /discord/events: Discord's Webhook Events, served only when the bridge
2
+ // is a loomcycle gate. The one event it acts on is APPLICATION_DEAUTHORIZED:
3
+ // a person removed the app, so the gate tells loomcycle they are gone
4
+ // (RFC FA §3.7c) and loomcycle disables them at once and removes them per the
5
+ // gate's policy.
6
+ //
7
+ // Discord signs these exactly as it signs interactions (Ed25519 over the
8
+ // timestamp header then the raw body, with the application's public key). It
9
+ // wants a 204 with no body within 3 seconds, and redelivers an event that got
10
+ // anything else for up to 10 minutes.
11
+ //
12
+ // Revocation must not fail open: the 204 is sent only once loomcycle has
13
+ // taken the revoke. A failed revoke, or one slower than Discord waits, is
14
+ // answered 503 so Discord delivers it again; a repeated revoke changes
15
+ // nothing (loomcycle answers 204 for a person it has already removed, or
16
+ // never knew).
17
+ import { header } from "@loomcycle/bridge-core";
18
+ import { isSnowflake } from "./config.js";
19
+ import { personSub } from "./identity.js";
20
+ import { verifyInteraction } from "./verify.js";
21
+ export const EVENTS_PATH = "/discord/events";
22
+ /** The outer object's type: Discord's probe when the URL is saved, or an event. */
23
+ export const WebhookType = { PING: 0, EVENT: 1 };
24
+ export const APPLICATION_DEAUTHORIZED = "APPLICATION_DEAUTHORIZED";
25
+ // Discord asks for a Content-Type even on the empty answer.
26
+ const NO_CONTENT = { status: 204, headers: { "content-type": "application/json" } };
27
+ const RETRY_LATER = { status: 503, body: "revoke not applied; retry" };
28
+ /** Inside Discord's 3 seconds, with room for the answer to travel. */
29
+ const REVOKE_TIMEOUT_MS = 2500;
30
+ class RevokeTimeout extends Error {
31
+ }
32
+ export function eventsRoute(deps) {
33
+ return async (req) => {
34
+ // Always verified, BRIDGE_DEV or not: what this route does is revoke.
35
+ const ok = verifyInteraction(deps.key, header(req, "x-signature-ed25519"), header(req, "x-signature-timestamp"), req.body, deps.now());
36
+ if (!ok)
37
+ return { status: 401, body: "unauthorized" };
38
+ let wh;
39
+ try {
40
+ wh = JSON.parse(req.body.toString("utf8"));
41
+ }
42
+ catch {
43
+ return { status: 400, body: "bad request" };
44
+ }
45
+ if (!wh || typeof wh !== "object")
46
+ return { status: 400, body: "bad request" };
47
+ if (wh.type !== WebhookType.EVENT || wh.event?.type !== APPLICATION_DEAUTHORIZED)
48
+ return NO_CONTENT;
49
+ const userId = wh.event.data?.user?.id;
50
+ if (!isSnowflake(userId))
51
+ return NO_CONTENT;
52
+ const subject = deps.gate.subjectOf(personSub(userId));
53
+ deps.forget(subject);
54
+ let timer;
55
+ const timeout = new Promise((_, reject) => {
56
+ timer = setTimeout(() => reject(new RevokeTimeout()), deps.revokeTimeoutMs ?? REVOKE_TIMEOUT_MS);
57
+ });
58
+ const revoke = deps.gate.revoke(subject);
59
+ try {
60
+ await Promise.race([revoke, timeout]);
61
+ }
62
+ catch (err) {
63
+ if (err instanceof RevokeTimeout) {
64
+ // It may still land; the redelivery repeats it either way.
65
+ revoke.catch((late) => deps.log.warn("discord revoke failed", { status: late?.status }));
66
+ deps.log.warn("discord revoke timed out; Discord will redeliver", {});
67
+ }
68
+ else {
69
+ deps.log.warn("discord revoke failed; Discord will redeliver", { status: err?.status });
70
+ }
71
+ return RETRY_LATER;
72
+ }
73
+ finally {
74
+ clearTimeout(timer);
75
+ }
76
+ deps.log.info("discord user removed the app; revoked in loomcycle", { user: userId });
77
+ return NO_CONTENT;
78
+ };
79
+ }
80
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { type DiscordApi } from "./api.js";
2
+ import type { DiscordRef } from "./port.js";
3
+ /** At most this many trusted servers are asked about a person's membership;
4
+ * past it the bridge asserts no groups for people (a channel's own user
5
+ * still gets its server's). */
6
+ export declare const MAX_GROUP_LOOKUPS = 20;
7
+ /** How long a person's looked-up groups are reused. */
8
+ export declare const GROUP_CACHE_MS: number;
9
+ export interface GroupLookupOptions {
10
+ api: Pick<DiscordApi, "guildMember">;
11
+ /** The gate's name: a person is "<gate>:<user id>", a channel "<gate>:conv:<hash>". */
12
+ gate: string;
13
+ trustedGuilds: ReadonlySet<string>;
14
+ now?: () => number;
15
+ }
16
+ export declare class GroupLookup {
17
+ private readonly opts;
18
+ private readonly cache;
19
+ private readonly now;
20
+ constructor(opts: GroupLookupOptions);
21
+ /** groupsFor: a channel's own user is in its server's group. A person (a
22
+ * DM) is in the group of each trusted server they are a member of, and in
23
+ * a group per role they hold there, looked up with the bot token. A lookup
24
+ * that fails, or more trusted servers than are worth asking about, asserts
25
+ * nothing, so loomcycle never removes a group on a guess. Cached per
26
+ * person for a while: a token is asked for rarely, but a restart asks for
27
+ * all of them at once. */
28
+ groupsFor(subject: string, ref: DiscordRef): Promise<string[] | undefined>;
29
+ /** forget drops a person's cached groups (they were revoked). */
30
+ forget(subject: string): void;
31
+ }
package/dist/groups.js ADDED
@@ -0,0 +1,83 @@
1
+ // A gate bridge's groups for a run identity (RFC FA §3.7d): what Discord
2
+ // knows, named as platform groups. loomcycle keeps them as "<gate>:<group>"
3
+ // external groups, which an operator maps (group_map) and binds ACLs to.
4
+ import { DiscordApiError } from "./api.js";
5
+ import { isSnowflake } from "./config.js";
6
+ import { guildGroup, roleGroup } from "./identity.js";
7
+ /** At most this many trusted servers are asked about a person's membership;
8
+ * past it the bridge asserts no groups for people (a channel's own user
9
+ * still gets its server's). */
10
+ export const MAX_GROUP_LOOKUPS = 20;
11
+ /** How long a person's looked-up groups are reused. */
12
+ export const GROUP_CACHE_MS = 10 * 60 * 1000;
13
+ const MAX_CACHED = 10_000;
14
+ /** Discord's JSON error code for a server the bot cannot see. */
15
+ const UNKNOWN_GUILD = 10004;
16
+ export class GroupLookup {
17
+ opts;
18
+ cache = new Map();
19
+ now;
20
+ constructor(opts) {
21
+ this.opts = opts;
22
+ this.now = opts.now ?? Date.now;
23
+ }
24
+ /** groupsFor: a channel's own user is in its server's group. A person (a
25
+ * DM) is in the group of each trusted server they are a member of, and in
26
+ * a group per role they hold there, looked up with the bot token. A lookup
27
+ * that fails, or more trusted servers than are worth asking about, asserts
28
+ * nothing, so loomcycle never removes a group on a guess. Cached per
29
+ * person for a while: a token is asked for rarely, but a restart asks for
30
+ * all of them at once. */
31
+ async groupsFor(subject, ref) {
32
+ const prefix = `${this.opts.gate}:`;
33
+ if (!subject.startsWith(prefix))
34
+ return undefined;
35
+ const sub = subject.slice(prefix.length);
36
+ // A ref stored before 0.3 has no server: assert nothing for it.
37
+ if (sub.startsWith("conv:"))
38
+ return ref.guildId ? [guildGroup(ref.guildId)] : undefined;
39
+ if (!isSnowflake(sub))
40
+ return undefined;
41
+ const trusted = this.opts.trustedGuilds;
42
+ if (trusted.size === 0)
43
+ return [];
44
+ if (trusted.size > MAX_GROUP_LOOKUPS)
45
+ return undefined;
46
+ const now = this.now();
47
+ const hit = this.cache.get(subject);
48
+ if (hit && hit.until > now)
49
+ return hit.groups;
50
+ const out = [];
51
+ for (const guild of [...trusted].sort()) {
52
+ let member;
53
+ try {
54
+ member = await this.opts.api.guildMember(guild, sub);
55
+ }
56
+ catch (err) {
57
+ // Not a member. A server the bot cannot see is also a 404, but says
58
+ // nothing about the person.
59
+ if (err instanceof DiscordApiError && err.status === 404 && err.code !== UNKNOWN_GUILD)
60
+ continue;
61
+ return undefined;
62
+ }
63
+ // A bot is never a person the gate speaks for: no groups for it at all.
64
+ if (member?.user?.bot)
65
+ return undefined;
66
+ out.push(guildGroup(guild));
67
+ const roles = Array.isArray(member?.roles) ? member.roles : [];
68
+ for (const role of roles)
69
+ if (isSnowflake(role))
70
+ out.push(roleGroup(role));
71
+ }
72
+ this.cache.delete(subject);
73
+ this.cache.set(subject, { groups: out, until: now + GROUP_CACHE_MS });
74
+ if (this.cache.size > MAX_CACHED)
75
+ this.cache.delete(this.cache.keys().next().value);
76
+ return out;
77
+ }
78
+ /** forget drops a person's cached groups (they were revoked). */
79
+ forget(subject) {
80
+ this.cache.delete(subject);
81
+ }
82
+ }
83
+ //# sourceMappingURL=groups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.js","sourceRoot":"","sources":["../src/groups.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,27 @@
1
1
  import { type Identified } from "@loomcycle/bridge-core";
2
2
  import { type DiscordConfig } from "./config.js";
3
3
  import { type Interaction } from "./interaction.js";
4
- export type Fences = Pick<DiscordConfig, "applicationId" | "allowedGuilds" | "allowDms" | "trustedGuilds">;
4
+ export type Fences = Pick<DiscordConfig, "applicationId" | "allowedGuilds" | "allowDms" | "trustedGuilds"> & {
5
+ /** The bridge's gate name in loomcycle (RFC FA §3.7d): a person is
6
+ * "<gate>:<user id>", a channel "<gate>:conv:<hash>". Unset for a bridge
7
+ * with a loomcycle token: "discord-<id>" and "discord-conv-<hash>", the
8
+ * subjects a gate's legacy_subject_prefix links to on a first login. */
9
+ gate?: string;
10
+ };
5
11
  /** Where an interaction happened. */
6
12
  export interface Place {
7
13
  channelId: string;
8
14
  /** Absent in a DM. */
9
15
  guildId?: string;
10
16
  }
17
+ /** personSub is the platform id a person is asserted under: loomcycle makes
18
+ * it the subject "<gate>:<id>". */
19
+ export declare function personSub(userId: string): string;
20
+ /** guildGroup names the platform group of a server's members, and roleGroup
21
+ * that of a role's holders. loomcycle keeps them as "<gate>:dc-guild-<id>"
22
+ * external groups, which an operator maps (group_map) and binds ACLs to. */
23
+ export declare function guildGroup(guildId: string): string;
24
+ export declare function roleGroup(roleId: string): string;
11
25
  export declare const NOT_IN_SERVER = "This bot isn't available in this server.";
12
26
  export declare const NOT_IN_DMS = "This bot isn't available in direct messages.";
13
27
  export declare const NOT_HERE = "This bot isn't available here.";
package/dist/identity.js CHANGED
@@ -1,9 +1,23 @@
1
1
  // Who used a command, and where, as the core needs it. The fences (allowed
2
2
  // servers, DMs on or off) are applied here, before anything touches loomcycle.
3
- import { sharedSubject } from "@loomcycle/bridge-core";
3
+ import { gateSharedSubject, sharedSubject } from "@loomcycle/bridge-core";
4
4
  import { isSnowflake } from "./config.js";
5
5
  import { Context } from "./interaction.js";
6
6
  const THREAD_TYPES = new Set([10, 11, 12]);
7
+ /** personSub is the platform id a person is asserted under: loomcycle makes
8
+ * it the subject "<gate>:<id>". */
9
+ export function personSub(userId) {
10
+ return userId;
11
+ }
12
+ /** guildGroup names the platform group of a server's members, and roleGroup
13
+ * that of a role's holders. loomcycle keeps them as "<gate>:dc-guild-<id>"
14
+ * external groups, which an operator maps (group_map) and binds ACLs to. */
15
+ export function guildGroup(guildId) {
16
+ return `dc-guild-${guildId}`;
17
+ }
18
+ export function roleGroup(roleId) {
19
+ return `dc-role-${roleId}`;
20
+ }
7
21
  export const NOT_IN_SERVER = "This bot isn't available in this server.";
8
22
  export const NOT_IN_DMS = "This bot isn't available in direct messages.";
9
23
  export const NOT_HERE = "This bot isn't available here.";
@@ -35,6 +49,7 @@ export function identify(ix, fences) {
35
49
  const user = ix.member?.user ?? ix.user;
36
50
  if (!user || !isSnowflake(user.id))
37
51
  return { ok: false, reason: "no_user" };
52
+ const subject = fences.gate ? `${fences.gate}:${personSub(user.id)}` : `discord-${user.id}`;
38
53
  // Bots cannot use slash commands today; this keeps that true if they ever can.
39
54
  if (user.bot || user.id === fences.applicationId)
40
55
  return { ok: false, reason: "self_or_bot" };
@@ -49,13 +64,13 @@ export function identify(ix, fences) {
49
64
  return { ok: false, reason: "private_channel", notice: NOT_HERE, conversationId };
50
65
  if (!fences.allowDms)
51
66
  return { ok: false, reason: "dms_closed", notice: NOT_IN_DMS, conversationId };
52
- const speaker = { subject: `discord-${user.id}`, name: displayName(ix, user.id), trust: "trusted" };
67
+ const speaker = { subject, name: displayName(ix, user.id), trust: "trusted" };
53
68
  return { ok: true, speaker, scope: "personal", conversationId, runAs: { subject: speaker.subject, name: speaker.name } };
54
69
  }
55
70
  if (!fences.allowedGuilds.has(place.guildId))
56
71
  return { ok: false, reason: "guild_not_allowed", notice: NOT_IN_SERVER, conversationId };
57
72
  const speaker = {
58
- subject: `discord-${user.id}`,
73
+ subject,
59
74
  name: displayName(ix, user.id),
60
75
  trust: fences.trustedGuilds.has(place.guildId) ? "trusted" : "untrusted",
61
76
  };
@@ -68,7 +83,10 @@ export function identify(ix, fences) {
68
83
  speaker,
69
84
  scope: "channel",
70
85
  conversationId,
71
- runAs: { subject: sharedSubject("discord", place.guildId, memoryChannel), name: "Discord channel" },
86
+ runAs: {
87
+ subject: fences.gate ? gateSharedSubject(fences.gate, place.guildId, memoryChannel) : sharedSubject("discord", place.guildId, memoryChannel),
88
+ name: "Discord channel",
89
+ },
72
90
  };
73
91
  }
74
92
  //# sourceMappingURL=identity.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,+EAA+E;AAE/E,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAiC,MAAM,wBAAwB,CAAC;AAEzG,OAAO,EAAE,WAAW,EAAsB,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAoB,MAAM,kBAAkB,CAAC;AAiB7D,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAE3C;oCACoC;AACpC,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;6EAE6E;AAC7E,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,YAAY,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,OAAO,WAAW,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,0CAA0C,CAAC;AACxE,MAAM,CAAC,MAAM,UAAU,GAAG,8CAA8C,CAAC;AACzE,MAAM,CAAC,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AAEzD,gFAAgF;AAChF,MAAM,UAAU,OAAO,CAAC,EAAe;IACrC,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC;IAClD,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,IAAI,EAAE,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IACpD,OAAO,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAY;IAC3C,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,SAAS,EAAE,CAAC;AAC/F,CAAC;AAED;kDACkD;AAClD,SAAS,WAAW,CAAC,EAAe,EAAE,EAAU;IAC9C,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC;IACrC,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,WAAW,IAAI,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAC;IACnE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC;SACtB,OAAO,CAAC,uCAAuC,EAAE,GAAG,CAAC;SACrD,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE;SACN,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChB,OAAO,KAAK,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAe,EAAE,MAAc;IACtD,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC;IACxC,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,EAAE,EAAE,CAAC;IAC5F,+EAA+E;IAC/E,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,aAAa;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAC9F,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IACvD,MAAM,cAAc,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAE/C,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACnB,uEAAuE;QACvE,uEAAuE;QACvE,IAAI,EAAE,CAAC,OAAO,KAAK,OAAO,CAAC,eAAe;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;QAC9H,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;QACrG,MAAM,OAAO,GAAY,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QACvF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;IAC3H,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;IACvI,MAAM,OAAO,GAAY;QACvB,OAAO;QACP,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QAC9B,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;KACzE,CAAC;IACF,yEAAyE;IACzE,2CAA2C;IAC3C,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;IACrC,MAAM,aAAa,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;IACjH,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO;QACP,KAAK,EAAE,SAAS;QAChB,cAAc;QACd,KAAK,EAAE;YACL,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE,aAAa,CAAC;YAC5I,IAAI,EAAE,iBAAiB;SACxB;KACF,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,13 +1,17 @@
1
1
  export { DiscordApi, DiscordApiError, retryAfterMs, USER_AGENT } from "./api.js";
2
- export type { CommandSpec, DiscordApiOptions } from "./api.js";
2
+ export type { CommandSpec, DiscordApiOptions, GuildMember, VoiceMessagePayload } from "./api.js";
3
3
  export { createDiscordBridge, MAX_MESSAGE_CHARS } from "./bridge.js";
4
4
  export type { DiscordBridgeOptions } from "./bridge.js";
5
5
  export { customIdOf, parseCustomId, renderCard, textMessage } from "./cards.js";
6
6
  export type { MessageBody } from "./cards.js";
7
- export { commandSpecs, HELP_TEXT, registerCommands } from "./commands.js";
7
+ export { ASK_BY_VOICE, commandSpecs, DISCORD_VOICE_HELP, HELP_TEXT, helpText, registerCommands, slashHelpText } from "./commands.js";
8
8
  export { DEFAULT_API_BASE_URL, DEFAULT_PORT, loadConfig } from "./config.js";
9
9
  export type { DiscordConfig } from "./config.js";
10
- export { conversationIdOf, identify, placeOf } from "./identity.js";
10
+ export { APPLICATION_DEAUTHORIZED, EVENTS_PATH, eventsRoute, WebhookType } from "./events.js";
11
+ export type { EventDeps, WebhookEvent } from "./events.js";
12
+ export { GROUP_CACHE_MS, GroupLookup, MAX_GROUP_LOOKUPS } from "./groups.js";
13
+ export type { GroupLookupOptions } from "./groups.js";
14
+ export { conversationIdOf, guildGroup, identify, personSub, placeOf, roleGroup } from "./identity.js";
11
15
  export type { Fences, Place } from "./identity.js";
12
16
  export type { Interaction } from "./interaction.js";
13
17
  export { interactionRoute } from "./interactions.js";
@@ -15,3 +19,5 @@ export type { InteractionDeps } from "./interactions.js";
15
19
  export { DiscordPort } from "./port.js";
16
20
  export type { DiscordRef } from "./port.js";
17
21
  export { MAX_SKEW_SECONDS, publicKeyFromHex, verifyInteraction } from "./verify.js";
22
+ export { DEFAULT_MAX_UPLOAD_BYTES, DiscordVoice, IS_VOICE_MESSAGE, NEEDS_VOICE, oggSeconds, OWN_VOICE_ONLY, VOICE_FILENAME, VOICE_HOSTS, VOICE_OFF, voiceOfMessage, voiceUrl, WAVEFORM, } from "./voice.js";
23
+ export type { DiscordVoiceOptions } from "./voice.js";
package/dist/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  export { DiscordApi, DiscordApiError, retryAfterMs, USER_AGENT } from "./api.js";
2
2
  export { createDiscordBridge, MAX_MESSAGE_CHARS } from "./bridge.js";
3
3
  export { customIdOf, parseCustomId, renderCard, textMessage } from "./cards.js";
4
- export { commandSpecs, HELP_TEXT, registerCommands } from "./commands.js";
4
+ export { ASK_BY_VOICE, commandSpecs, DISCORD_VOICE_HELP, HELP_TEXT, helpText, registerCommands, slashHelpText } from "./commands.js";
5
5
  export { DEFAULT_API_BASE_URL, DEFAULT_PORT, loadConfig } from "./config.js";
6
- export { conversationIdOf, identify, placeOf } from "./identity.js";
6
+ export { APPLICATION_DEAUTHORIZED, EVENTS_PATH, eventsRoute, WebhookType } from "./events.js";
7
+ export { GROUP_CACHE_MS, GroupLookup, MAX_GROUP_LOOKUPS } from "./groups.js";
8
+ export { conversationIdOf, guildGroup, identify, personSub, placeOf, roleGroup } from "./identity.js";
7
9
  export { interactionRoute } from "./interactions.js";
8
10
  export { DiscordPort } from "./port.js";
9
11
  export { MAX_SKEW_SECONDS, publicKeyFromHex, verifyInteraction } from "./verify.js";
12
+ export { DEFAULT_MAX_UPLOAD_BYTES, DiscordVoice, IS_VOICE_MESSAGE, NEEDS_VOICE, oggSeconds, OWN_VOICE_ONLY, VOICE_FILENAME, VOICE_HOSTS, VOICE_OFF, voiceOfMessage, voiceUrl, WAVEFORM, } from "./voice.js";
10
13
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEjF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEhF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEjF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEhF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACrI,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE9F,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGtG,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EACL,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,cAAc,EACd,cAAc,EACd,WAAW,EACX,SAAS,EACT,cAAc,EACd,QAAQ,EACR,QAAQ,GACT,MAAM,YAAY,CAAC"}
@@ -10,6 +10,11 @@ export declare const CallbackType: {
10
10
  readonly DEFERRED_UPDATE_MESSAGE: 6;
11
11
  readonly UPDATE_MESSAGE: 7;
12
12
  };
13
+ /** Application command types. */
14
+ export declare const CommandType: {
15
+ readonly CHAT_INPUT: 1;
16
+ readonly MESSAGE: 3;
17
+ };
13
18
  /** Interaction context types: where a command was used. */
14
19
  export declare const Context: {
15
20
  readonly GUILD: 0;
@@ -28,6 +33,19 @@ export interface CommandOption {
28
33
  type?: number;
29
34
  value?: unknown;
30
35
  }
36
+ /** A message as a message command's interaction resolves it. */
37
+ export interface ResolvedMessage {
38
+ id?: string;
39
+ author?: DiscordUser;
40
+ flags?: number;
41
+ attachments?: Array<{
42
+ id?: string;
43
+ url?: string;
44
+ content_type?: string;
45
+ size?: number;
46
+ duration_secs?: number;
47
+ }>;
48
+ }
31
49
  export interface Interaction {
32
50
  id?: string;
33
51
  application_id?: string;
@@ -46,9 +64,20 @@ export interface Interaction {
46
64
  };
47
65
  user?: DiscordUser;
48
66
  context?: number;
67
+ /** The invoking person's client language (en-US, pt-BR, uk). */
68
+ locale?: string;
69
+ /** The largest file the bot may upload here, in bytes. */
70
+ attachment_size_limit?: number;
49
71
  data?: {
50
72
  name?: string;
73
+ /** The command's type (CommandType). */
74
+ type?: number;
51
75
  options?: CommandOption[];
52
76
  custom_id?: string;
77
+ /** A message command's target message. */
78
+ target_id?: string;
79
+ resolved?: {
80
+ messages?: Record<string, ResolvedMessage>;
81
+ };
53
82
  };
54
83
  }
@@ -13,6 +13,8 @@ export const CallbackType = {
13
13
  DEFERRED_UPDATE_MESSAGE: 6,
14
14
  UPDATE_MESSAGE: 7,
15
15
  };
16
+ /** Application command types. */
17
+ export const CommandType = { CHAT_INPUT: 1, MESSAGE: 3 };
16
18
  /** Interaction context types: where a command was used. */
17
19
  export const Context = { GUILD: 0, BOT_DM: 1, PRIVATE_CHANNEL: 2 };
18
20
  export const EPHEMERAL = 1 << 6;
@@ -1 +1 @@
1
- {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../src/interaction.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,6EAA6E;AAC7E,sBAAsB;AAEtB,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,CAAC;IACP,mBAAmB,EAAE,CAAC;IACtB,iBAAiB,EAAE,CAAC;CACZ,CAAC;AAEX,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,CAAC;IACP,2BAA2B,EAAE,CAAC;IAC9B,oCAAoC,EAAE,CAAC;IACvC,uBAAuB,EAAE,CAAC;IAC1B,cAAc,EAAE,CAAC;CACT,CAAC;AAEX,2DAA2D;AAC3D,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAW,CAAC;AAE5E,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../src/interaction.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,6EAA6E;AAC7E,sBAAsB;AAEtB,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,CAAC;IACP,mBAAmB,EAAE,CAAC;IACtB,iBAAiB,EAAE,CAAC;CACZ,CAAC;AAEX,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,CAAC;IACP,2BAA2B,EAAE,CAAC;IAC9B,oCAAoC,EAAE,CAAC;IACvC,uBAAuB,EAAE,CAAC;IAC1B,cAAc,EAAE,CAAC;CACT,CAAC;AAEX,iCAAiC;AACjC,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAW,CAAC;AAElE,2DAA2D;AAC3D,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAW,CAAC;AAE5E,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,CAAC"}
@@ -2,9 +2,11 @@ import { type ConversationRouter, type Logger, type Route } from "@loomcycle/bri
2
2
  import type { KeyObject } from "node:crypto";
3
3
  import type { DiscordApi } from "./api.js";
4
4
  import { type DiscordConfig } from "./config.js";
5
+ import { type Fences } from "./identity.js";
5
6
  import type { DiscordPort, DiscordRef } from "./port.js";
7
+ import { type DiscordVoice } from "./voice.js";
6
8
  export interface InteractionDeps {
7
- cfg: Pick<DiscordConfig, "applicationId" | "allowedGuilds" | "allowDms" | "trustedGuilds" | "dev">;
9
+ cfg: Fences & Pick<DiscordConfig, "dev">;
8
10
  key: KeyObject;
9
11
  port: DiscordPort;
10
12
  api: DiscordApi;
@@ -13,6 +15,12 @@ export interface InteractionDeps {
13
15
  now: () => number;
14
16
  /** How long a button press may take before the bridge acks it and finishes later. */
15
17
  inlineCardMs?: number;
18
+ /** Set with BRIDGE_VOICE=1: Ask by voice is taken. untrusted is
19
+ * BRIDGE_VOICE_UNTRUSTED. */
20
+ voice?: {
21
+ port: DiscordVoice;
22
+ untrusted: boolean;
23
+ };
16
24
  }
17
25
  export declare const NO_LONGER_ACTIVE = "This button is no longer active.";
18
26
  export declare function interactionRoute(deps: InteractionDeps): Route;
@@ -1,12 +1,13 @@
1
1
  // POST /discord/interactions: verify, then answer within Discord's 3 seconds,
2
2
  // then do the work.
3
- import { header } from "@loomcycle/bridge-core";
3
+ import { header, VOICE_TEXT } from "@loomcycle/bridge-core";
4
4
  import { NO_MENTIONS, parseCustomId, renderCard, SUPPRESS_EMBEDS, textMessage } from "./cards.js";
5
- import { HELP_TEXT, MAX_PROMPT_CHARS } from "./commands.js";
5
+ import { ASK_BY_VOICE, MAX_PROMPT_CHARS, slashHelpText } from "./commands.js";
6
6
  import { isSnowflake } from "./config.js";
7
7
  import { identify, NOT_HERE, placeOf } from "./identity.js";
8
- import { CallbackType, EPHEMERAL, InteractionType } from "./interaction.js";
8
+ import { CallbackType, CommandType, EPHEMERAL, InteractionType } from "./interaction.js";
9
9
  import { verifyInteraction } from "./verify.js";
10
+ import { voiceOfMessage, VOICE_OFF } from "./voice.js";
10
11
  /** Interaction tokens are opaque; this keeps one from bending the URL path it is put in. */
11
12
  const TOKEN = /^[A-Za-z0-9._-]{1,1000}$/;
12
13
  /** Longer than the 5-minute signature window, so a replay inside it is refused. */
@@ -47,6 +48,10 @@ function json(body) {
47
48
  function ephemeral(text) {
48
49
  return json({ type: CallbackType.CHANNEL_MESSAGE_WITH_SOURCE, data: { ...textMessage(text), flags: EPHEMERAL | SUPPRESS_EMBEDS } });
49
50
  }
51
+ /** refOf is where replies go, as the conversation store keeps it. */
52
+ function refOf(place) {
53
+ return place.guildId ? { channelId: place.channelId, guildId: place.guildId } : { channelId: place.channelId };
54
+ }
50
55
  function promptOf(ix) {
51
56
  const v = ix.data?.options?.find((o) => o.name === "prompt")?.value;
52
57
  return typeof v === "string" ? v.trim().slice(0, MAX_PROMPT_CHARS) : "";
@@ -54,6 +59,31 @@ function promptOf(ix) {
54
59
  export function interactionRoute(deps) {
55
60
  const seen = new Seen(deps.now);
56
61
  const { cfg, port, log } = deps;
62
+ const help = slashHelpText(deps.voice !== undefined);
63
+ /** voiceCommand takes Ask by voice: the core downloads, transcribes and
64
+ * answers it, after a deferred response like /ask's. */
65
+ const voiceCommand = (ix, id) => {
66
+ if (ix.data?.name !== ASK_BY_VOICE)
67
+ return ephemeral("Unknown command. Try /help.");
68
+ if (!deps.voice)
69
+ return ephemeral(VOICE_OFF);
70
+ // Said here rather than left to the core, which stays quiet in a shared
71
+ // channel: an interaction must be answered.
72
+ if (id.speaker.trust === "untrusted" && !deps.voice.untrusted)
73
+ return ephemeral(VOICE_TEXT.unavailable);
74
+ const found = voiceOfMessage(ix);
75
+ if ("refusal" in found)
76
+ return ephemeral(found.refusal);
77
+ const place = placeOf(ix);
78
+ const ref = refOf(place);
79
+ port.track(ix.id, ix.token, place.channelId, FALLBACK.ask);
80
+ setImmediate(() => {
81
+ deps.router.onVoice(id, ref, found.voice, typeof ix.locale === "string" ? ix.locale : undefined).catch((err) => {
82
+ log.error("voice message failed", { conversation: id.conversationId, error: err?.name });
83
+ });
84
+ });
85
+ return json({ type: CallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE, data: { flags: SUPPRESS_EMBEDS, allowed_mentions: NO_MENTIONS } });
86
+ };
57
87
  const command = (ix) => {
58
88
  const id = identify(ix, cfg);
59
89
  if (!id.ok) {
@@ -61,16 +91,21 @@ export function interactionRoute(deps) {
61
91
  // Every interaction must be answered, so each refused one hears why.
62
92
  return ephemeral(id.notice ?? NOT_HERE);
63
93
  }
94
+ // A spoken reply may follow any turn (/voice on), so every command says
95
+ // how large an upload this channel takes.
96
+ deps.voice?.port.observe(placeOf(ix).channelId, ix.attachment_size_limit);
97
+ if (ix.data?.type === CommandType.MESSAGE)
98
+ return voiceCommand(ix, id);
64
99
  const name = ix.data?.name ?? "";
65
100
  if (name === "help")
66
- return ephemeral(HELP_TEXT);
101
+ return ephemeral(help);
67
102
  const text = name === "ask" ? promptOf(ix) : name === "new" || name === "stop" ? `/${name}` : undefined;
68
103
  if (text === undefined)
69
104
  return ephemeral("Unknown command. Try /help.");
70
105
  if (!text)
71
106
  return ephemeral("Write something after /ask.");
72
107
  const place = placeOf(ix);
73
- const ref = { channelId: place.channelId };
108
+ const ref = refOf(place);
74
109
  port.track(ix.id, ix.token, place.channelId, FALLBACK[name]);
75
110
  // After this response is written: the core's first reply edits the
76
111
  // deferred message, which must exist by then.
@@ -98,7 +133,7 @@ export function interactionRoute(deps) {
98
133
  return ephemeral(id.notice ?? NOT_HERE);
99
134
  }
100
135
  const place = placeOf(ix);
101
- const ref = { channelId: place.channelId };
136
+ const ref = refOf(place);
102
137
  // Its token also carries the agent's next messages in this channel.
103
138
  port.track(ix.id, ix.token, place.channelId);
104
139
  const work = deps.router.onCardAction(id, ref, input).catch((err) => {
@@ -1 +1 @@
1
- {"version":3,"file":"interactions.js","sourceRoot":"","sources":["../src/interactions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"interactions.js","sourceRoot":"","sources":["../src/interactions.ts"],"names":[],"mappings":"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"}