@vellumai/cli 0.12.0-staging.1 → 0.12.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.
@@ -1,8 +1,10 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import {
4
+ botProviderForChannel,
4
5
  CHANNEL_BOT_PROVIDER,
5
6
  CHANNEL_IDS,
7
+ channelForBotProvider,
6
8
  isChannelBotProvider,
7
9
  isChannelUserIntegration,
8
10
  isChannelId,
@@ -41,6 +43,35 @@ describe("isChannelId", () => {
41
43
  });
42
44
  });
43
45
 
46
+ describe("botProviderForChannel and channelForBotProvider", () => {
47
+ test("are inverses over every entry of the map", () => {
48
+ for (const [channelId, botProviderKey] of Object.entries(
49
+ CHANNEL_BOT_PROVIDER,
50
+ )) {
51
+ expect(botProviderForChannel(channelId)).toBe(botProviderKey);
52
+ expect(channelForBotProvider(botProviderKey)).toBe(
53
+ channelId as keyof typeof CHANNEL_BOT_PROVIDER,
54
+ );
55
+ }
56
+ });
57
+
58
+ test("answer nothing for a channel without a bot, a person's grant, or an unknown key", () => {
59
+ expect(botProviderForChannel("phone")).toBeUndefined();
60
+ expect(botProviderForChannel("vellum")).toBeUndefined();
61
+ expect(botProviderForChannel("not-a-channel")).toBeUndefined();
62
+ // `slack` is the person's integration standing beside the bot's key.
63
+ expect(channelForBotProvider("slack")).toBeUndefined();
64
+ expect(channelForBotProvider("google")).toBeUndefined();
65
+ });
66
+
67
+ test("never resolve an inherited object property as a channel or a key", () => {
68
+ for (const name of ["constructor", "toString", "__proto__"]) {
69
+ expect(botProviderForChannel(name)).toBeUndefined();
70
+ expect(channelForBotProvider(name)).toBeUndefined();
71
+ }
72
+ });
73
+ });
74
+
44
75
  describe("isChannelUserIntegration", () => {
45
76
  test("names the grant standing beside a bot of the same brand", () => {
46
77
  expect(isChannelUserIntegration("slack")).toBe(true);
@@ -93,9 +93,34 @@ export const CHANNEL_BOT_PROVIDER = {
93
93
  * connected" question, for any provider key.
94
94
  */
95
95
  export function isChannelBotProvider(providerKey: string): boolean {
96
- return (Object.values(CHANNEL_BOT_PROVIDER) as readonly string[]).includes(
97
- providerKey,
98
- );
96
+ return channelForBotProvider(providerKey) !== undefined;
97
+ }
98
+
99
+ /**
100
+ * The provider key holding a channel's bot credential, or `undefined` when
101
+ * the channel has none, or is not a channel at all. Walks the map's own
102
+ * entries, so an inherited object property name is never a channel.
103
+ */
104
+ export function botProviderForChannel(channelId: string): string | undefined {
105
+ return Object.entries(CHANNEL_BOT_PROVIDER).find(
106
+ ([id]) => id === channelId,
107
+ )?.[1];
108
+ }
109
+
110
+ /**
111
+ * The channel whose bot credential a provider key holds, or `undefined` when
112
+ * the key is not a bot's. The inverse of `botProviderForChannel`, for a
113
+ * surface that has only the provider key in hand and needs to speak in the
114
+ * channel's vocabulary.
115
+ */
116
+ export function channelForBotProvider(
117
+ providerKey: string,
118
+ ): keyof typeof CHANNEL_BOT_PROVIDER | undefined {
119
+ return (
120
+ Object.entries(CHANNEL_BOT_PROVIDER) as Array<
121
+ [keyof typeof CHANNEL_BOT_PROVIDER, string]
122
+ >
123
+ ).find(([, key]) => key === providerKey)?.[0];
99
124
  }
100
125
 
101
126
  /**
@@ -1,8 +1,10 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import {
4
+ botProviderForChannel,
4
5
  CHANNEL_BOT_PROVIDER,
5
6
  CHANNEL_IDS,
7
+ channelForBotProvider,
6
8
  isChannelBotProvider,
7
9
  isChannelUserIntegration,
8
10
  isChannelId,
@@ -41,6 +43,35 @@ describe("isChannelId", () => {
41
43
  });
42
44
  });
43
45
 
46
+ describe("botProviderForChannel and channelForBotProvider", () => {
47
+ test("are inverses over every entry of the map", () => {
48
+ for (const [channelId, botProviderKey] of Object.entries(
49
+ CHANNEL_BOT_PROVIDER,
50
+ )) {
51
+ expect(botProviderForChannel(channelId)).toBe(botProviderKey);
52
+ expect(channelForBotProvider(botProviderKey)).toBe(
53
+ channelId as keyof typeof CHANNEL_BOT_PROVIDER,
54
+ );
55
+ }
56
+ });
57
+
58
+ test("answer nothing for a channel without a bot, a person's grant, or an unknown key", () => {
59
+ expect(botProviderForChannel("phone")).toBeUndefined();
60
+ expect(botProviderForChannel("vellum")).toBeUndefined();
61
+ expect(botProviderForChannel("not-a-channel")).toBeUndefined();
62
+ // `slack` is the person's integration standing beside the bot's key.
63
+ expect(channelForBotProvider("slack")).toBeUndefined();
64
+ expect(channelForBotProvider("google")).toBeUndefined();
65
+ });
66
+
67
+ test("never resolve an inherited object property as a channel or a key", () => {
68
+ for (const name of ["constructor", "toString", "__proto__"]) {
69
+ expect(botProviderForChannel(name)).toBeUndefined();
70
+ expect(channelForBotProvider(name)).toBeUndefined();
71
+ }
72
+ });
73
+ });
74
+
44
75
  describe("isChannelUserIntegration", () => {
45
76
  test("names the grant standing beside a bot of the same brand", () => {
46
77
  expect(isChannelUserIntegration("slack")).toBe(true);
@@ -93,9 +93,34 @@ export const CHANNEL_BOT_PROVIDER = {
93
93
  * connected" question, for any provider key.
94
94
  */
95
95
  export function isChannelBotProvider(providerKey: string): boolean {
96
- return (Object.values(CHANNEL_BOT_PROVIDER) as readonly string[]).includes(
97
- providerKey,
98
- );
96
+ return channelForBotProvider(providerKey) !== undefined;
97
+ }
98
+
99
+ /**
100
+ * The provider key holding a channel's bot credential, or `undefined` when
101
+ * the channel has none, or is not a channel at all. Walks the map's own
102
+ * entries, so an inherited object property name is never a channel.
103
+ */
104
+ export function botProviderForChannel(channelId: string): string | undefined {
105
+ return Object.entries(CHANNEL_BOT_PROVIDER).find(
106
+ ([id]) => id === channelId,
107
+ )?.[1];
108
+ }
109
+
110
+ /**
111
+ * The channel whose bot credential a provider key holds, or `undefined` when
112
+ * the key is not a bot's. The inverse of `botProviderForChannel`, for a
113
+ * surface that has only the provider key in hand and needs to speak in the
114
+ * channel's vocabulary.
115
+ */
116
+ export function channelForBotProvider(
117
+ providerKey: string,
118
+ ): keyof typeof CHANNEL_BOT_PROVIDER | undefined {
119
+ return (
120
+ Object.entries(CHANNEL_BOT_PROVIDER) as Array<
121
+ [keyof typeof CHANNEL_BOT_PROVIDER, string]
122
+ >
123
+ ).find(([, key]) => key === providerKey)?.[0];
99
124
  }
100
125
 
101
126
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/cli",
3
- "version": "0.12.0-staging.1",
3
+ "version": "0.12.0",
4
4
  "description": "CLI tools for vellum-assistant",
5
5
  "type": "module",
6
6
  "exports": {