spectrum-ts 0.2.2 → 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.
@@ -1,442 +0,0 @@
1
- import type { Fn, Pipe, Tuples } from "hotscript";
2
- import type z from "zod";
3
- import type { Content } from "../types/content";
4
- import type { Message } from "../types/message";
5
- import type { Space } from "../types/space";
6
- import type { User } from "../types/user";
7
-
8
- type ResolvedSpace = Pick<Space, "id">;
9
- type SpaceRef = Pick<Space, "id" | "__platform">;
10
- type ResolvedUser = Pick<User, "id">;
11
- type AwaitedReturn<T> = T extends (...args: never[]) => Promise<infer R>
12
- ? R
13
- : never;
14
- type SchemaInfer<T> = T extends { schema?: infer S extends z.ZodType<object> }
15
- ? z.infer<S>
16
- : Record<never, never>;
17
- type InferSchema<TSchema> =
18
- TSchema extends z.ZodType<object> ? z.infer<TSchema> : Record<never, never>;
19
- type InferOptionalSchema<TSchema> =
20
- TSchema extends z.ZodType<object> ? z.infer<TSchema> : never;
21
-
22
- type InputSchema<TSchema> =
23
- TSchema extends z.ZodType<object> ? z.input<TSchema> : never;
24
-
25
- // ---------------------------------------------------------------------------
26
- // Event system types
27
- // ---------------------------------------------------------------------------
28
-
29
- export type EventProducer<
30
- TPayload = unknown,
31
- TClient = unknown,
32
- TConfig = unknown,
33
- > = (ctx: { client: TClient; config: TConfig }) => AsyncIterable<TPayload>;
34
-
35
- export type ProviderMessage<
36
- TSender extends ResolvedUser = ResolvedUser,
37
- TSpace extends ResolvedSpace = ResolvedSpace,
38
- TExtra extends object = Record<never, never>,
39
- > = {
40
- id: string;
41
- content: Content[];
42
- sender: TSender;
43
- space: TSpace;
44
- timestamp?: Date;
45
- } & TExtra;
46
-
47
- type MergeSchema<
48
- TSchema extends z.ZodType | undefined,
49
- TBase extends object,
50
- > = TSchema extends z.ZodType
51
- ? string extends keyof z.infer<TSchema>
52
- ? TBase
53
- : Omit<z.infer<TSchema>, keyof TBase> & TBase
54
- : TBase;
55
-
56
- export type SchemaMessage<
57
- TUserSchema extends z.ZodType | undefined = undefined,
58
- TSpaceSchema extends z.ZodType | undefined = undefined,
59
- > = ProviderMessage<
60
- MergeSchema<TUserSchema, ResolvedUser>,
61
- MergeSchema<TSpaceSchema, ResolvedSpace>
62
- >;
63
-
64
- type InferEventPayload<T> = T extends (ctx: never) => AsyncIterable<infer P>
65
- ? P
66
- : never;
67
-
68
- // ---------------------------------------------------------------------------
69
- // Reserved names — event names that would collide with SpectrumInstance methods
70
- // ---------------------------------------------------------------------------
71
-
72
- type ReservedNames = "stop" | "send" | "__internal" | "__providers";
73
-
74
- // ---------------------------------------------------------------------------
75
- // PlatformDef — the full definition of a platform adapter
76
- // ---------------------------------------------------------------------------
77
-
78
- export interface PlatformDef<
79
- _Name extends string = string,
80
- _ConfigSchema extends z.ZodType<object> = z.ZodType<object>,
81
- _UserSchema extends z.ZodType<object> | undefined = undefined,
82
- _SpaceSchema extends z.ZodType<object> | undefined = undefined,
83
- _SpaceParamsSchema extends z.ZodType<object> | undefined = undefined,
84
- _Client = unknown,
85
- _ResolvedUser extends ResolvedUser = ResolvedUser,
86
- _ResolvedSpace extends ResolvedSpace = ResolvedSpace,
87
- _MessageSchema extends z.ZodType<object> | undefined = undefined,
88
- _MessageType extends ProviderMessage<
89
- _ResolvedUser,
90
- _ResolvedSpace,
91
- InferSchema<_MessageSchema>
92
- > = ProviderMessage<
93
- _ResolvedUser,
94
- _ResolvedSpace,
95
- InferSchema<_MessageSchema>
96
- >,
97
- _Events extends {
98
- messages: EventProducer<_MessageType, _Client, z.infer<_ConfigSchema>>;
99
- } = {
100
- messages: EventProducer<_MessageType, _Client, z.infer<_ConfigSchema>>;
101
- },
102
- > {
103
- actions: {
104
- send: (_: {
105
- space: _ResolvedSpace & SpaceRef;
106
- content: Content[];
107
- client: _Client;
108
- config: z.infer<_ConfigSchema>;
109
- }) => Promise<void>;
110
- startTyping?: (_: {
111
- space: _ResolvedSpace & SpaceRef;
112
- client: _Client;
113
- config: z.infer<_ConfigSchema>;
114
- }) => Promise<void>;
115
- stopTyping?: (_: {
116
- space: _ResolvedSpace & SpaceRef;
117
- client: _Client;
118
- config: z.infer<_ConfigSchema>;
119
- }) => Promise<void>;
120
- reactToMessage?: (_: {
121
- space: _ResolvedSpace & SpaceRef;
122
- messageId: string;
123
- reaction: string;
124
- client: _Client;
125
- config: z.infer<_ConfigSchema>;
126
- }) => Promise<void>;
127
- replyToMessage?: (_: {
128
- space: _ResolvedSpace & SpaceRef;
129
- messageId: string;
130
- content: Content[];
131
- client: _Client;
132
- config: z.infer<_ConfigSchema>;
133
- }) => Promise<void>;
134
- };
135
-
136
- config: _ConfigSchema;
137
-
138
- events: _Events;
139
-
140
- lifecycle: {
141
- createClient: (ctx: {
142
- config: z.infer<_ConfigSchema>;
143
- projectId: string | undefined;
144
- projectSecret: string | undefined;
145
- }) => Promise<_Client>;
146
- destroyClient: (ctx: { client: _Client }) => Promise<void>;
147
- };
148
-
149
- message?: {
150
- schema?: _MessageSchema;
151
- };
152
- name: _Name;
153
-
154
- space: {
155
- schema?: _SpaceSchema;
156
- params?: _SpaceParamsSchema;
157
- resolve: (_: {
158
- input: {
159
- users: (_ResolvedUser & { __platform: _Name })[];
160
- params?: _SpaceParamsSchema extends z.ZodType<object>
161
- ? z.infer<_SpaceParamsSchema>
162
- : undefined;
163
- };
164
- client: _Client;
165
- config: z.infer<_ConfigSchema>;
166
- }) => Promise<_ResolvedSpace>;
167
- };
168
-
169
- user: {
170
- schema?: _UserSchema;
171
- resolve: (_: {
172
- input: { userID: string };
173
- client: _Client;
174
- config: z.infer<_ConfigSchema>;
175
- }) => Promise<_ResolvedUser>;
176
- };
177
- }
178
-
179
- // ---------------------------------------------------------------------------
180
- // AnyPlatformDef — structural wildcard for erasure contexts
181
- // ---------------------------------------------------------------------------
182
-
183
- export interface AnyPlatformDef {
184
- actions: {
185
- // biome-ignore lint/suspicious/noExplicitAny: wildcard action
186
- send: (_: any) => Promise<void>;
187
- // biome-ignore lint/suspicious/noExplicitAny: wildcard action
188
- startTyping?: (_: any) => Promise<void>;
189
- // biome-ignore lint/suspicious/noExplicitAny: wildcard action
190
- stopTyping?: (_: any) => Promise<void>;
191
- // biome-ignore lint/suspicious/noExplicitAny: wildcard action
192
- reactToMessage?: (_: any) => Promise<void>;
193
- // biome-ignore lint/suspicious/noExplicitAny: wildcard action
194
- replyToMessage?: (_: any) => Promise<void>;
195
- };
196
- config: z.ZodType<object>;
197
- events: {
198
- // biome-ignore lint/suspicious/noExplicitAny: wildcard event
199
- messages: (ctx: any) => AsyncIterable<any>;
200
- // biome-ignore lint/suspicious/noExplicitAny: wildcard event
201
- [key: string]: (ctx: any) => AsyncIterable<any>;
202
- };
203
- lifecycle: {
204
- // biome-ignore lint/suspicious/noExplicitAny: wildcard lifecycle
205
- createClient: (ctx: any) => Promise<any>;
206
- // biome-ignore lint/suspicious/noExplicitAny: wildcard lifecycle
207
- destroyClient: (ctx: any) => Promise<void>;
208
- };
209
- message?: { schema?: z.ZodType<object> };
210
- name: string;
211
- space: {
212
- schema?: z.ZodType<object>;
213
- params?: z.ZodType<object>;
214
- // biome-ignore lint/suspicious/noExplicitAny: wildcard resolver
215
- resolve: (_: any) => Promise<any>;
216
- };
217
- user: {
218
- schema?: z.ZodType<object>;
219
- // biome-ignore lint/suspicious/noExplicitAny: wildcard resolver
220
- resolve: (_: any) => Promise<any>;
221
- };
222
- }
223
-
224
- // ---------------------------------------------------------------------------
225
- // PlatformProviderConfig — carries platform def type through providers array
226
- // ---------------------------------------------------------------------------
227
-
228
- export interface PlatformProviderConfig<
229
- Def extends AnyPlatformDef = AnyPlatformDef,
230
- > {
231
- readonly __def: Def;
232
- readonly __definition: AnyPlatformDef;
233
- readonly __name: Def["name"];
234
- readonly __tag: "PlatformProviderConfig";
235
- readonly config: unknown;
236
- }
237
-
238
- // ---------------------------------------------------------------------------
239
- // HotScript Fn's for type-level provider operations
240
- // ---------------------------------------------------------------------------
241
-
242
- interface MatchesPlatformName<Name extends string> extends Fn {
243
- return: this["arg0"] extends PlatformProviderConfig<infer Def>
244
- ? Def["name"] extends Name
245
- ? true
246
- : false
247
- : false;
248
- }
249
-
250
- interface ExtractDef extends Fn {
251
- return: this["arg0"] extends PlatformProviderConfig<infer Def> ? Def : never;
252
- }
253
-
254
- interface ExtractDefByName<Name extends string> extends Fn {
255
- return: this["arg0"] extends { name: Name } ? true : false;
256
- }
257
-
258
- // ---------------------------------------------------------------------------
259
- // HotScript Fn's for custom event operations
260
- // ---------------------------------------------------------------------------
261
-
262
- interface ExtractCustomEventNames extends Fn {
263
- return: this["arg0"] extends AnyPlatformDef
264
- ? Exclude<keyof this["arg0"]["events"], "messages" | symbol | number>
265
- : never;
266
- }
267
-
268
- interface ToCustomEventVariant<EventName extends string> extends Fn {
269
- return: this["arg0"] extends PlatformProviderConfig<infer Def>
270
- ? EventName extends keyof Def["events"]
271
- ? InferEventPayload<Def["events"][EventName]> & { platform: Def["name"] }
272
- : never
273
- : never;
274
- }
275
-
276
- // ---------------------------------------------------------------------------
277
- // HasProvider — check if a platform name exists in providers tuple
278
- // ---------------------------------------------------------------------------
279
-
280
- export type HasProvider<
281
- Providers extends PlatformProviderConfig[],
282
- Name extends string,
283
- > = Pipe<Providers, [Tuples.Some<MatchesPlatformName<Name>>]>;
284
-
285
- // ---------------------------------------------------------------------------
286
- // ExtractProviderDef — pull a platform's def from the providers tuple
287
- // ---------------------------------------------------------------------------
288
-
289
- export type ExtractProviderDef<
290
- Providers extends PlatformProviderConfig[],
291
- Name extends string,
292
- > = Pipe<
293
- Providers,
294
- [Tuples.Map<ExtractDef>, Tuples.Find<ExtractDefByName<Name>>]
295
- >;
296
-
297
- // ---------------------------------------------------------------------------
298
- // AllCustomEventNames — union of all non-messages event names across providers
299
- // ---------------------------------------------------------------------------
300
-
301
- type AllCustomEventNames<Providers extends PlatformProviderConfig[]> = Pipe<
302
- Providers,
303
- [Tuples.Map<ExtractDef>, Tuples.Map<ExtractCustomEventNames>, Tuples.ToUnion]
304
- >;
305
-
306
- // ---------------------------------------------------------------------------
307
- // UnifiedCustomEvent — for a given event name, union of payloads across providers
308
- // ---------------------------------------------------------------------------
309
-
310
- type UnifiedCustomEvent<
311
- Providers extends PlatformProviderConfig[],
312
- EventName extends string,
313
- > = Pipe<
314
- Providers,
315
- [Tuples.Map<ToCustomEventVariant<EventName>>, Tuples.ToUnion]
316
- >;
317
-
318
- // ---------------------------------------------------------------------------
319
- // CustomEventStreams — mapped type producing async iterables for each custom event
320
- // ---------------------------------------------------------------------------
321
-
322
- export type CustomEventStreams<Providers extends PlatformProviderConfig[]> = {
323
- [K in Exclude<AllCustomEventNames<Providers>, ReservedNames> &
324
- string]: AsyncIterable<UnifiedCustomEvent<Providers, K>>;
325
- };
326
-
327
- // ---------------------------------------------------------------------------
328
- // Platform-specific Space, Message, and User types
329
- // ---------------------------------------------------------------------------
330
-
331
- type ResolvedSpaceOf<Def extends AnyPlatformDef> = AwaitedReturn<
332
- Def["space"]["resolve"]
333
- >;
334
- type SchemaSpaceOf<Def extends AnyPlatformDef> = InferOptionalSchema<
335
- Def["space"]["schema"]
336
- >;
337
-
338
- type ResolvedUserOf<Def extends AnyPlatformDef> = AwaitedReturn<
339
- Def["user"]["resolve"]
340
- >;
341
-
342
- type SpaceShapeOf<Def extends AnyPlatformDef> = [SchemaSpaceOf<Def>] extends [
343
- never,
344
- ]
345
- ? ResolvedSpaceOf<Def>
346
- : SchemaSpaceOf<Def>;
347
-
348
- type SpaceParamsInputOf<Def extends AnyPlatformDef> = InputSchema<
349
- Def["space"]["params"]
350
- >;
351
-
352
- type SpaceArrayArgs<Def extends AnyPlatformDef> = [
353
- SpaceParamsInputOf<Def>,
354
- ] extends [never]
355
- ? [users: PlatformUser<Def>[]]
356
- :
357
- | [users: PlatformUser<Def>[]]
358
- | [users: PlatformUser<Def>[], params: SpaceParamsInputOf<Def>]
359
- | [params: SpaceParamsInputOf<Def>];
360
-
361
- type SpaceVarargArgs<Def extends AnyPlatformDef> = [
362
- SpaceParamsInputOf<Def>,
363
- ] extends [never]
364
- ? PlatformUser<Def>[]
365
- : PlatformUser<Def>[] | [...PlatformUser<Def>[], SpaceParamsInputOf<Def>];
366
-
367
- type SpaceArgs<Def extends AnyPlatformDef> =
368
- | SpaceArrayArgs<Def>
369
- | SpaceVarargArgs<Def>;
370
-
371
- export type PlatformSpace<Def extends AnyPlatformDef> = Omit<
372
- SpaceShapeOf<Def>,
373
- keyof Space
374
- > &
375
- Space;
376
-
377
- export type PlatformMessage<Def extends AnyPlatformDef> = Omit<
378
- SchemaInfer<Def["message"]>,
379
- keyof Message
380
- > &
381
- Message<Def["name"], PlatformUser<Def>, PlatformSpace<Def>>;
382
-
383
- export type PlatformUser<Def extends AnyPlatformDef> = Omit<
384
- ResolvedUserOf<Def>,
385
- keyof User
386
- > &
387
- User;
388
-
389
- // ---------------------------------------------------------------------------
390
- // PlatformInstance — returned from imessage(spectrum)
391
- // ---------------------------------------------------------------------------
392
-
393
- export type PlatformInstance<Def extends AnyPlatformDef> = {
394
- space(...args: SpaceArgs<Def>): Promise<PlatformSpace<Def>>;
395
- user(userID: string): Promise<PlatformUser<Def>>;
396
- } & {
397
- [K in Exclude<
398
- keyof Def["events"],
399
- "messages" | symbol | number
400
- > as K extends ReservedNames ? never : K]: AsyncIterable<
401
- InferEventPayload<Def["events"][K]>
402
- >;
403
- };
404
-
405
- // ---------------------------------------------------------------------------
406
- // SpectrumLike — minimal interface for platform narrowing
407
- // ---------------------------------------------------------------------------
408
-
409
- export interface SpectrumLike<
410
- Providers extends PlatformProviderConfig[] = PlatformProviderConfig[],
411
- > {
412
- readonly __internal: {
413
- platforms: Map<
414
- string,
415
- { client: unknown; config: unknown; definition: AnyPlatformDef }
416
- >;
417
- };
418
- readonly __providers: Providers;
419
- }
420
-
421
- // ---------------------------------------------------------------------------
422
- // Platform — the callable returned by definePlatform()
423
- // ---------------------------------------------------------------------------
424
-
425
- export interface Platform<Def extends AnyPlatformDef> {
426
- config(
427
- ...args: Record<string, never> extends z.input<Def["config"]>
428
- ? [config?: z.input<Def["config"]>]
429
- : [config: z.input<Def["config"]>]
430
- ): PlatformProviderConfig<Def>;
431
- <Providers extends PlatformProviderConfig[]>(
432
- spectrum: SpectrumLike<Providers>
433
- ): HasProvider<Providers, Def["name"]> extends true
434
- ? PlatformInstance<Def>
435
- : never;
436
-
437
- (space: Space): PlatformSpace<Def>;
438
-
439
- (message: Message): PlatformMessage<Def>;
440
- }
441
-
442
- export type { Message } from "../types/message";
@@ -1,115 +0,0 @@
1
- import {
2
- type AdvancedIMessage,
3
- createClient,
4
- } from "@photon-ai/advanced-imessage";
5
- import {
6
- cloud,
7
- type DedicatedTokenData,
8
- type SharedTokenData,
9
- } from "../../utils/cloud";
10
-
11
- const RENEWAL_RATIO = 0.8;
12
- const EXPIRY_BUFFER_MS = 30_000;
13
- const RETRY_DELAY_MS = 30_000;
14
-
15
- interface CloudAuth {
16
- dispose: () => void;
17
- }
18
-
19
- const cloudAuthState = new WeakMap<AdvancedIMessage[], CloudAuth>();
20
-
21
- export async function createCloudClients(
22
- projectId: string,
23
- projectSecret: string
24
- ): Promise<AdvancedIMessage[]> {
25
- let tokenData = await cloud.issueImessageTokens(projectId, projectSecret);
26
- let tokenExpiresAt = Date.now() + tokenData.expiresIn * 1000;
27
- let disposed = false;
28
- let renewalTimer: ReturnType<typeof setTimeout> | undefined;
29
-
30
- const scheduleRenewal = () => {
31
- if (disposed) {
32
- return;
33
- }
34
- const ttlMs = tokenData.expiresIn * 1000;
35
- const renewInMs = Math.max(ttlMs * RENEWAL_RATIO, 5000);
36
-
37
- renewalTimer = setTimeout(async () => {
38
- try {
39
- tokenData = await cloud.issueImessageTokens(projectId, projectSecret);
40
- tokenExpiresAt = Date.now() + tokenData.expiresIn * 1000;
41
- scheduleRenewal();
42
- } catch {
43
- renewalTimer = setTimeout(() => scheduleRenewal(), RETRY_DELAY_MS);
44
- renewalTimer?.unref?.();
45
- }
46
- }, renewInMs);
47
- renewalTimer?.unref?.();
48
- };
49
-
50
- scheduleRenewal();
51
-
52
- const refreshIfNeeded = async (): Promise<void> => {
53
- if (Date.now() < tokenExpiresAt - EXPIRY_BUFFER_MS) {
54
- return;
55
- }
56
- tokenData = await cloud.issueImessageTokens(projectId, projectSecret);
57
- tokenExpiresAt = Date.now() + tokenData.expiresIn * 1000;
58
- scheduleRenewal();
59
- };
60
-
61
- const buildClients = (): AdvancedIMessage[] => {
62
- if (tokenData.type === "shared") {
63
- const address =
64
- process.env.SPECTRUM_IMESSAGE_ADDRESS ??
65
- "imessage.spectrum.photon.codes:443";
66
-
67
- return [
68
- createClient({
69
- address,
70
- tls: true,
71
- token: async () => {
72
- await refreshIfNeeded();
73
- return (tokenData as SharedTokenData).token;
74
- },
75
- }),
76
- ];
77
- }
78
-
79
- return Object.entries(tokenData.auth).map(([instanceId, token]) =>
80
- createClient({
81
- address: `${instanceId}.imsg.photon.codes:443`,
82
- tls: true,
83
- token: async () => {
84
- await refreshIfNeeded();
85
- const data = tokenData as DedicatedTokenData;
86
- return data.auth[instanceId] ?? token;
87
- },
88
- })
89
- );
90
- };
91
-
92
- const clients = buildClients();
93
-
94
- cloudAuthState.set(clients, {
95
- dispose: () => {
96
- disposed = true;
97
- if (renewalTimer !== undefined) {
98
- clearTimeout(renewalTimer);
99
- renewalTimer = undefined;
100
- }
101
- },
102
- });
103
-
104
- return clients;
105
- }
106
-
107
- export async function disposeCloudAuth(
108
- clients: AdvancedIMessage[]
109
- ): Promise<void> {
110
- const auth = cloudAuthState.get(clients);
111
- if (auth) {
112
- auth.dispose();
113
- cloudAuthState.delete(clients);
114
- }
115
- }
@@ -1,153 +0,0 @@
1
- import { createClient, directChat } from "@photon-ai/advanced-imessage";
2
- import { IMessageSDK } from "@photon-ai/imessage-kit";
3
- import { definePlatform } from "../../platform/define";
4
- import { createCloudClients, disposeCloudAuth } from "./auth";
5
- import { messages as localMessages, send as localSend } from "./local";
6
- import {
7
- messages as remoteMessages,
8
- reactToMessage as remoteReactToMessage,
9
- replyToMessage as remoteReplyToMessage,
10
- send as remoteSend,
11
- startTyping as remoteStartTyping,
12
- stopTyping as remoteStopTyping,
13
- } from "./remote";
14
- import {
15
- configSchema,
16
- type IMessageClient,
17
- isLocal,
18
- spaceSchema,
19
- } from "./types";
20
-
21
- export const imessage = definePlatform("iMessage", {
22
- config: configSchema,
23
-
24
- static: {
25
- tapbacks: {
26
- love: "love",
27
- like: "like",
28
- dislike: "dislike",
29
- laugh: "laugh",
30
- emphasize: "emphasize",
31
- question: "question",
32
- } as const,
33
- },
34
-
35
- user: {
36
- resolve: async ({ input }) => ({ id: input.userID }),
37
- },
38
-
39
- space: {
40
- schema: spaceSchema,
41
- resolve: async ({ input, client }) => {
42
- if (isLocal(client)) {
43
- throw new Error(
44
- "Space creation is not supported in local mode. Local mode only supports replying to messages."
45
- );
46
- }
47
-
48
- if (input.users.length === 0) {
49
- throw new Error("iMessage space creation requires at least one user");
50
- }
51
-
52
- const addresses = input.users.map((u) => u.id);
53
-
54
- if (input.users.length === 1) {
55
- return {
56
- id: directChat(addresses[0] ?? "") as string,
57
- type: "dm" as const,
58
- };
59
- }
60
-
61
- const remote = client[0];
62
- if (!remote) {
63
- throw new Error("No remote iMessage client available");
64
- }
65
-
66
- const { chat } = await remote.chats.create(addresses);
67
- return { id: chat.guid as string, type: "group" as const };
68
- },
69
- },
70
-
71
- lifecycle: {
72
- createClient: async ({
73
- config,
74
- projectId,
75
- projectSecret,
76
- }): Promise<IMessageClient> => {
77
- if (config.local) {
78
- return new IMessageSDK();
79
- }
80
-
81
- if (config.clients) {
82
- const entries = Array.isArray(config.clients)
83
- ? config.clients
84
- : [config.clients];
85
- return entries.map((e) =>
86
- createClient({ address: e.address, tls: true, token: e.token })
87
- );
88
- }
89
-
90
- if (!(projectId && projectSecret)) {
91
- throw new Error(
92
- "iMessage requires projectId and projectSecret. " +
93
- "Either pass credentials to Spectrum(), use local mode: imessage.config({ local: true }), " +
94
- "or provide explicit client config: imessage.config({ clients: [...] })"
95
- );
96
- }
97
-
98
- return await createCloudClients(projectId, projectSecret);
99
- },
100
-
101
- destroyClient: async ({ client }: { client: IMessageClient }) => {
102
- if (isLocal(client)) {
103
- await client.close();
104
- return;
105
- }
106
- await disposeCloudAuth(client);
107
- await Promise.all(client.map((c) => c.close()));
108
- },
109
- },
110
-
111
- events: {
112
- messages: ({ client }) =>
113
- isLocal(client) ? localMessages(client) : remoteMessages(client),
114
- },
115
-
116
- actions: {
117
- send: async ({ space, content, client }) => {
118
- for (const item of content) {
119
- if (isLocal(client)) {
120
- await localSend(client, space.id, item);
121
- } else {
122
- await remoteSend(client, space.id, item);
123
- }
124
- }
125
- },
126
- startTyping: async ({ space, client }) => {
127
- if (isLocal(client)) {
128
- return;
129
- }
130
- await remoteStartTyping(client, space.id);
131
- },
132
- stopTyping: async ({ space, client }) => {
133
- if (isLocal(client)) {
134
- return;
135
- }
136
- await remoteStopTyping(client, space.id);
137
- },
138
- reactToMessage: async ({ space, messageId, reaction, client }) => {
139
- if (isLocal(client)) {
140
- return;
141
- }
142
- await remoteReactToMessage(client, space.id, messageId, reaction);
143
- },
144
- replyToMessage: async ({ space, messageId, content, client }) => {
145
- if (isLocal(client)) {
146
- return;
147
- }
148
- for (const item of content) {
149
- await remoteReplyToMessage(client, space.id, messageId, item);
150
- }
151
- },
152
- },
153
- });