spectrum-ts 0.4.0 → 0.6.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.
@@ -0,0 +1,341 @@
1
+ // src/content/text.ts
2
+ import z from "zod";
3
+ var textSchema = z.object({
4
+ type: z.literal("text"),
5
+ text: z.string().nonempty()
6
+ });
7
+ var asText = (text2) => textSchema.parse({ type: "text", text: text2 });
8
+ function text(text2) {
9
+ return {
10
+ build: async () => asText(text2)
11
+ };
12
+ }
13
+
14
+ // src/content/resolve.ts
15
+ var resolveContents = (items) => Promise.all(
16
+ items.map((c) => typeof c === "string" ? text(c).build() : c.build())
17
+ );
18
+
19
+ // src/platform/build.ts
20
+ function buildSpace(params) {
21
+ const { spaceRef, extras, typingCtx, definition, client, config } = params;
22
+ let space;
23
+ async function sendImpl(...content) {
24
+ const resolved = await resolveContents(content);
25
+ const results = [];
26
+ for (const item of resolved) {
27
+ const sendResult = await definition.actions.send({
28
+ ...typingCtx,
29
+ content: item
30
+ });
31
+ if (!sendResult?.id) {
32
+ throw new Error(
33
+ `Platform "${definition.name}" send did not return a message id`
34
+ );
35
+ }
36
+ results.push(
37
+ buildMessage({
38
+ id: sendResult.id,
39
+ content: item,
40
+ sender: sendResult.sender,
41
+ timestamp: sendResult.timestamp ?? /* @__PURE__ */ new Date(),
42
+ extras: {},
43
+ spaceRef,
44
+ space,
45
+ definition,
46
+ client,
47
+ config,
48
+ direction: "outbound"
49
+ })
50
+ );
51
+ }
52
+ return content.length === 1 && results[0] ? results[0] : results;
53
+ }
54
+ space = {
55
+ ...extras,
56
+ ...spaceRef,
57
+ send: sendImpl,
58
+ edit: async (message, newContent) => {
59
+ await message.edit(newContent);
60
+ },
61
+ startTyping: async () => {
62
+ await definition.actions.startTyping?.(typingCtx);
63
+ },
64
+ stopTyping: async () => {
65
+ await definition.actions.stopTyping?.(typingCtx);
66
+ },
67
+ responding: async (fn) => {
68
+ await definition.actions.startTyping?.(typingCtx);
69
+ try {
70
+ return await fn();
71
+ } finally {
72
+ await definition.actions.stopTyping?.(typingCtx).catch(() => {
73
+ });
74
+ }
75
+ }
76
+ };
77
+ return space;
78
+ }
79
+ function buildMessage(params) {
80
+ const { definition, client, config, spaceRef, space } = params;
81
+ const react = async (reaction) => {
82
+ if (!definition.actions.reactToMessage) {
83
+ return;
84
+ }
85
+ await definition.actions.reactToMessage({
86
+ space: spaceRef,
87
+ messageId: params.id,
88
+ reaction,
89
+ client,
90
+ config
91
+ });
92
+ };
93
+ async function reply(...content) {
94
+ if (!definition.actions.replyToMessage) {
95
+ throw new Error(
96
+ `Platform "${definition.name}" does not support replying to messages`
97
+ );
98
+ }
99
+ const resolved = await resolveContents(content);
100
+ const results = [];
101
+ for (const item of resolved) {
102
+ const sendResult = await definition.actions.replyToMessage({
103
+ space: spaceRef,
104
+ messageId: params.id,
105
+ content: item,
106
+ client,
107
+ config
108
+ });
109
+ if (!sendResult?.id) {
110
+ throw new Error(
111
+ `Platform "${definition.name}" reply did not return a message id`
112
+ );
113
+ }
114
+ results.push(
115
+ buildMessage({
116
+ id: sendResult.id,
117
+ content: item,
118
+ sender: sendResult.sender,
119
+ timestamp: sendResult.timestamp ?? /* @__PURE__ */ new Date(),
120
+ extras: {},
121
+ spaceRef,
122
+ space,
123
+ definition,
124
+ client,
125
+ config,
126
+ direction: "outbound"
127
+ })
128
+ );
129
+ }
130
+ return content.length === 1 && results[0] ? results[0] : results;
131
+ }
132
+ const senderWithPlatform = params.sender === void 0 ? void 0 : { ...params.sender, __platform: definition.name };
133
+ if (params.direction === "outbound") {
134
+ return {
135
+ ...params.extras,
136
+ id: params.id,
137
+ content: params.content,
138
+ direction: "outbound",
139
+ platform: definition.name,
140
+ react,
141
+ reply,
142
+ edit: async (newContent) => {
143
+ if (!definition.actions.editMessage) {
144
+ throw new Error(
145
+ `Platform "${definition.name}" does not support editing messages`
146
+ );
147
+ }
148
+ const [resolved] = await resolveContents([newContent]);
149
+ if (!resolved) {
150
+ return;
151
+ }
152
+ await definition.actions.editMessage({
153
+ space: spaceRef,
154
+ messageId: params.id,
155
+ content: resolved,
156
+ client,
157
+ config
158
+ });
159
+ },
160
+ sender: senderWithPlatform,
161
+ space,
162
+ timestamp: params.timestamp
163
+ };
164
+ }
165
+ return {
166
+ ...params.extras,
167
+ id: params.id,
168
+ content: params.content,
169
+ direction: "inbound",
170
+ platform: definition.name,
171
+ react,
172
+ reply,
173
+ sender: senderWithPlatform,
174
+ space,
175
+ timestamp: params.timestamp
176
+ };
177
+ }
178
+
179
+ // src/platform/define.ts
180
+ function createPlatformInstance(def, runtime) {
181
+ const isPlatformUser = (value) => {
182
+ return typeof value === "object" && value !== null && "__platform" in value && value.__platform === def.name;
183
+ };
184
+ const normalizeSpaceArgs = (args) => {
185
+ if (args.length === 0) {
186
+ return { users: [], params: void 0 };
187
+ }
188
+ const [first, ...rest] = args;
189
+ if (Array.isArray(first)) {
190
+ return {
191
+ users: first,
192
+ params: rest[0]
193
+ };
194
+ }
195
+ if (!isPlatformUser(first)) {
196
+ return {
197
+ users: [],
198
+ params: first
199
+ };
200
+ }
201
+ const last = args.at(-1);
202
+ if (last !== void 0 && !isPlatformUser(last)) {
203
+ return {
204
+ users: args.slice(0, -1),
205
+ params: last
206
+ };
207
+ }
208
+ return {
209
+ users: args,
210
+ params: void 0
211
+ };
212
+ };
213
+ const base = {
214
+ async user(userID) {
215
+ const resolved = await def.user.resolve({
216
+ input: { userID },
217
+ client: runtime.client,
218
+ config: runtime.config
219
+ });
220
+ return {
221
+ ...resolved,
222
+ __platform: def.name
223
+ };
224
+ },
225
+ async space(...args) {
226
+ const { users, params } = normalizeSpaceArgs(args);
227
+ let parsedParams = params;
228
+ if (params !== void 0 && def.space.params) {
229
+ parsedParams = def.space.params.parse(params);
230
+ }
231
+ const resolved = await def.space.resolve({
232
+ input: { users, params: parsedParams },
233
+ client: runtime.client,
234
+ config: runtime.config
235
+ });
236
+ const parsedSpace = def.space.schema ? def.space.schema.parse(resolved) : resolved;
237
+ const spaceRef = {
238
+ id: parsedSpace.id,
239
+ __platform: def.name
240
+ };
241
+ const typingCtx = {
242
+ space: spaceRef,
243
+ client: runtime.client,
244
+ config: runtime.config
245
+ };
246
+ return buildSpace({
247
+ spaceRef,
248
+ extras: parsedSpace,
249
+ typingCtx,
250
+ definition: def,
251
+ client: runtime.client,
252
+ config: runtime.config
253
+ });
254
+ }
255
+ };
256
+ const eventProperties = {};
257
+ for (const eventName of Object.keys(def.events)) {
258
+ if (eventName === "messages") {
259
+ continue;
260
+ }
261
+ const producer = def.events[eventName];
262
+ if (producer) {
263
+ eventProperties[eventName] = producer({
264
+ client: runtime.client,
265
+ config: runtime.config
266
+ });
267
+ }
268
+ }
269
+ return Object.assign(base, eventProperties);
270
+ }
271
+ function definePlatform(name, def) {
272
+ const fullDef = { name, ...def };
273
+ const platformCache = /* @__PURE__ */ new WeakMap();
274
+ const narrowSpectrum = (spectrum) => {
275
+ const cached = platformCache.get(spectrum);
276
+ if (cached) {
277
+ return cached;
278
+ }
279
+ const runtime = spectrum.__internal.platforms.get(name);
280
+ if (!runtime) {
281
+ throw new Error(`Platform "${name}" is not registered`);
282
+ }
283
+ const instance = createPlatformInstance(
284
+ fullDef,
285
+ runtime
286
+ );
287
+ platformCache.set(spectrum, instance);
288
+ return instance;
289
+ };
290
+ const narrowSpace = (input) => {
291
+ if (input.__platform !== name) {
292
+ throw new Error(
293
+ `Expected space from "${name}", got "${input.__platform}"`
294
+ );
295
+ }
296
+ return input;
297
+ };
298
+ const narrowMessage = (input) => {
299
+ if (input.platform !== name) {
300
+ throw new Error(
301
+ `Expected message from "${name}", got "${input.platform}"`
302
+ );
303
+ }
304
+ return input;
305
+ };
306
+ const narrower = ((input) => {
307
+ if ("__providers" in input && "__internal" in input) {
308
+ return narrowSpectrum(input);
309
+ }
310
+ if ("__platform" in input && "send" in input) {
311
+ return narrowSpace(input);
312
+ }
313
+ if ("platform" in input && "sender" in input && "space" in input) {
314
+ return narrowMessage(input);
315
+ }
316
+ throw new Error("Invalid input to platform narrowing function");
317
+ });
318
+ narrower.config = (config) => {
319
+ const resolvedConfig = config ?? {};
320
+ return {
321
+ __tag: "PlatformProviderConfig",
322
+ __def: void 0,
323
+ __name: name,
324
+ config: resolvedConfig,
325
+ __definition: fullDef
326
+ };
327
+ };
328
+ if (def.static) {
329
+ Object.assign(narrower, def.static);
330
+ }
331
+ return narrower;
332
+ }
333
+
334
+ export {
335
+ asText,
336
+ text,
337
+ resolveContents,
338
+ buildSpace,
339
+ buildMessage,
340
+ definePlatform
341
+ };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { C as ContentBuilder, a as ContentInput, b as Content, P as ProviderMessage, c as PlatformDef, d as Platform, e as PlatformProviderConfig, S as SpectrumLike, f as CustomEventStreams, g as Space, M as Message } from './types-BdWMydUJ.js';
2
- export { A as AnyPlatformDef, E as EventProducer, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage, U as User } from './types-BdWMydUJ.js';
1
+ import { C as ContentBuilder, U as User, a as ContentInput, b as Content, P as ProviderMessage, c as PlatformDef, d as Platform, e as PlatformProviderConfig, S as SpectrumLike, f as CustomEventStreams, g as Space, I as InboundMessage, O as OutboundMessage } from './types-DZMHfgYQ.js';
2
+ export { A as AnyPlatformDef, E as EventProducer, M as Message, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage } from './types-DZMHfgYQ.js';
3
+ import vCard from 'vcf';
3
4
  import z__default from 'zod';
4
5
  export { M as ManagedStream, m as mergeStreams, s as stream } from './stream-DGy4geUK.js';
5
6
  import 'hotscript';
@@ -9,12 +10,138 @@ declare function attachment(input: string | Buffer, options?: {
9
10
  name?: string;
10
11
  }): ContentBuilder;
11
12
 
13
+ declare const nameSchema: z__default.ZodObject<{
14
+ formatted: z__default.ZodOptional<z__default.ZodString>;
15
+ first: z__default.ZodOptional<z__default.ZodString>;
16
+ last: z__default.ZodOptional<z__default.ZodString>;
17
+ middle: z__default.ZodOptional<z__default.ZodString>;
18
+ prefix: z__default.ZodOptional<z__default.ZodString>;
19
+ suffix: z__default.ZodOptional<z__default.ZodString>;
20
+ }, z__default.core.$strip>;
21
+ declare const phoneSchema: z__default.ZodObject<{
22
+ value: z__default.ZodString;
23
+ type: z__default.ZodOptional<z__default.ZodEnum<{
24
+ mobile: "mobile";
25
+ home: "home";
26
+ work: "work";
27
+ other: "other";
28
+ }>>;
29
+ }, z__default.core.$strip>;
30
+ declare const emailSchema: z__default.ZodObject<{
31
+ value: z__default.ZodString;
32
+ type: z__default.ZodOptional<z__default.ZodEnum<{
33
+ home: "home";
34
+ work: "work";
35
+ other: "other";
36
+ }>>;
37
+ }, z__default.core.$strip>;
38
+ declare const addressSchema: z__default.ZodObject<{
39
+ street: z__default.ZodOptional<z__default.ZodString>;
40
+ city: z__default.ZodOptional<z__default.ZodString>;
41
+ region: z__default.ZodOptional<z__default.ZodString>;
42
+ postalCode: z__default.ZodOptional<z__default.ZodString>;
43
+ country: z__default.ZodOptional<z__default.ZodString>;
44
+ type: z__default.ZodOptional<z__default.ZodEnum<{
45
+ home: "home";
46
+ work: "work";
47
+ other: "other";
48
+ }>>;
49
+ }, z__default.core.$strip>;
50
+ declare const orgSchema: z__default.ZodObject<{
51
+ name: z__default.ZodOptional<z__default.ZodString>;
52
+ title: z__default.ZodOptional<z__default.ZodString>;
53
+ department: z__default.ZodOptional<z__default.ZodString>;
54
+ }, z__default.core.$strip>;
55
+ declare const contactSchema: z__default.ZodObject<{
56
+ type: z__default.ZodLiteral<"contact">;
57
+ user: z__default.ZodOptional<z__default.ZodObject<{
58
+ __platform: z__default.ZodString;
59
+ id: z__default.ZodString;
60
+ }, z__default.core.$strip>>;
61
+ name: z__default.ZodOptional<z__default.ZodObject<{
62
+ formatted: z__default.ZodOptional<z__default.ZodString>;
63
+ first: z__default.ZodOptional<z__default.ZodString>;
64
+ last: z__default.ZodOptional<z__default.ZodString>;
65
+ middle: z__default.ZodOptional<z__default.ZodString>;
66
+ prefix: z__default.ZodOptional<z__default.ZodString>;
67
+ suffix: z__default.ZodOptional<z__default.ZodString>;
68
+ }, z__default.core.$strip>>;
69
+ phones: z__default.ZodOptional<z__default.ZodArray<z__default.ZodObject<{
70
+ value: z__default.ZodString;
71
+ type: z__default.ZodOptional<z__default.ZodEnum<{
72
+ mobile: "mobile";
73
+ home: "home";
74
+ work: "work";
75
+ other: "other";
76
+ }>>;
77
+ }, z__default.core.$strip>>>;
78
+ emails: z__default.ZodOptional<z__default.ZodArray<z__default.ZodObject<{
79
+ value: z__default.ZodString;
80
+ type: z__default.ZodOptional<z__default.ZodEnum<{
81
+ home: "home";
82
+ work: "work";
83
+ other: "other";
84
+ }>>;
85
+ }, z__default.core.$strip>>>;
86
+ addresses: z__default.ZodOptional<z__default.ZodArray<z__default.ZodObject<{
87
+ street: z__default.ZodOptional<z__default.ZodString>;
88
+ city: z__default.ZodOptional<z__default.ZodString>;
89
+ region: z__default.ZodOptional<z__default.ZodString>;
90
+ postalCode: z__default.ZodOptional<z__default.ZodString>;
91
+ country: z__default.ZodOptional<z__default.ZodString>;
92
+ type: z__default.ZodOptional<z__default.ZodEnum<{
93
+ home: "home";
94
+ work: "work";
95
+ other: "other";
96
+ }>>;
97
+ }, z__default.core.$strip>>>;
98
+ org: z__default.ZodOptional<z__default.ZodObject<{
99
+ name: z__default.ZodOptional<z__default.ZodString>;
100
+ title: z__default.ZodOptional<z__default.ZodString>;
101
+ department: z__default.ZodOptional<z__default.ZodString>;
102
+ }, z__default.core.$strip>>;
103
+ urls: z__default.ZodOptional<z__default.ZodArray<z__default.ZodString>>;
104
+ birthday: z__default.ZodOptional<z__default.ZodString>;
105
+ note: z__default.ZodOptional<z__default.ZodString>;
106
+ photo: z__default.ZodOptional<z__default.ZodObject<{
107
+ mimeType: z__default.ZodString;
108
+ read: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
109
+ }, z__default.core.$strip>>;
110
+ raw: z__default.ZodOptional<z__default.ZodUnknown>;
111
+ }, z__default.core.$strip>;
112
+ type Contact = z__default.infer<typeof contactSchema>;
113
+ type ContactName = z__default.infer<typeof nameSchema>;
114
+ type ContactPhone = z__default.infer<typeof phoneSchema>;
115
+ type ContactEmail = z__default.infer<typeof emailSchema>;
116
+ type ContactAddress = z__default.infer<typeof addressSchema>;
117
+ type ContactOrg = z__default.infer<typeof orgSchema>;
118
+ type ContactInput = Omit<Contact, "type">;
119
+ type ContactDetails = Omit<ContactInput, "user">;
120
+ declare function contact(user: User, details?: ContactDetails): ContentBuilder;
121
+ declare function contact(input: string | ContactInput | vCard): ContentBuilder;
122
+
12
123
  declare function custom(raw: unknown): ContentBuilder;
13
124
 
14
125
  declare const resolveContents: (items: readonly ContentInput[]) => Promise<Content[]>;
15
126
 
16
127
  declare function text(text: string): ContentBuilder;
17
128
 
129
+ declare const voiceSchema: z__default.ZodObject<{
130
+ type: z__default.ZodLiteral<"voice">;
131
+ name: z__default.ZodOptional<z__default.ZodString>;
132
+ mimeType: z__default.ZodString;
133
+ duration: z__default.ZodOptional<z__default.ZodNumber>;
134
+ size: z__default.ZodOptional<z__default.ZodNumber>;
135
+ read: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
136
+ stream: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
137
+ }, z__default.core.$strip>;
138
+ type Voice = z__default.infer<typeof voiceSchema>;
139
+ declare function voice(input: string | Buffer, options?: {
140
+ mimeType?: string;
141
+ name?: string;
142
+ duration?: number;
143
+ }): ContentBuilder;
144
+
18
145
  declare function definePlatform<_Name extends string, _ConfigSchema extends z__default.ZodType<object>, _UserSchema extends z__default.ZodType<object> | undefined, _SpaceSchema extends z__default.ZodType<object> | undefined, _SpaceParamsSchema extends z__default.ZodType<object> | undefined, _Client, _ResolvedUser extends {
19
146
  id: string;
20
147
  }, _ResolvedSpace extends {
@@ -34,9 +161,11 @@ declare function definePlatform<_Name extends string, _ConfigSchema extends z__d
34
161
  }): Platform<PlatformDef<_Name, _ConfigSchema, _UserSchema, _SpaceSchema, _SpaceParamsSchema, _Client, _ResolvedUser, _ResolvedSpace, _MessageSchema, _MessageType, _Events>> & Readonly<_Static>;
35
162
 
36
163
  type SpectrumInstance<Providers extends PlatformProviderConfig[] = PlatformProviderConfig[]> = SpectrumLike<Providers> & CustomEventStreams<Providers> & {
37
- readonly messages: AsyncIterable<[Space, Message]>;
164
+ readonly messages: AsyncIterable<[Space, InboundMessage]>;
38
165
  stop(): Promise<void>;
39
- send(space: Space, ...content: [ContentInput, ...ContentInput[]]): Promise<void>;
166
+ send(space: Space, content: ContentInput): Promise<OutboundMessage>;
167
+ send(space: Space, ...content: [ContentInput, ContentInput, ...ContentInput[]]): Promise<OutboundMessage[]>;
168
+ edit(message: OutboundMessage, newContent: ContentInput): Promise<void>;
40
169
  responding<T>(space: Space, fn: () => T | Promise<T>): Promise<T>;
41
170
  };
42
171
  declare function Spectrum<const Providers extends PlatformProviderConfig[]>(options: {
@@ -86,4 +215,7 @@ declare const cloud: {
86
215
  togglePlatform: (projectId: string, projectSecret: string, platform: CloudPlatform, enabled: boolean) => Promise<PlatformsData>;
87
216
  };
88
217
 
89
- export { type CloudPlatform, Content, ContentBuilder, ContentInput, type DedicatedTokenData, type ImessageInfoData, Message, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, type SharedTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, attachment, cloud, custom, definePlatform, resolveContents, text };
218
+ declare const fromVCard: (vcf: string) => ContactInput;
219
+ declare const toVCard: (contact: Contact) => Promise<string>;
220
+
221
+ export { type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, Content, ContentBuilder, ContentInput, type DedicatedTokenData, type ImessageInfoData, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, type SharedTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, User, type Voice, attachment, cloud, contact, custom, definePlatform, fromVCard, resolveContents, text, toVCard, voice };