spectrum-ts 0.2.1 → 0.3.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/{chunk-3TBRO2J7.js → chunk-V2PK557T.js} +15 -0
- package/dist/{chunk-LIRM7SBA.js → chunk-XEEDIGVK.js} +28 -5
- package/dist/chunk-ZRSCHSLZ.js +44 -0
- package/dist/index.d.ts +15 -5
- package/dist/index.js +27 -76
- package/dist/providers/imessage/index.d.ts +1 -2
- package/dist/providers/imessage/index.js +34 -33
- package/dist/providers/terminal/index.d.ts +3 -4
- package/dist/providers/terminal/index.js +4 -5
- package/dist/providers/whatsapp-business/index.d.ts +1 -2
- package/dist/providers/whatsapp-business/index.js +37 -71
- package/dist/{types-DQE0dQT4.d.ts → types-DuE2hXuJ.d.ts} +10 -16
- package/package.json +6 -29
- package/src/index.ts +0 -38
- package/src/platform/define.ts +0 -308
- package/src/platform/types.ts +0 -442
- package/src/providers/imessage/auth.ts +0 -115
- package/src/providers/imessage/index.ts +0 -153
- package/src/providers/imessage/local.ts +0 -55
- package/src/providers/imessage/remote.ts +0 -157
- package/src/providers/imessage/types.ts +0 -31
- package/src/providers/terminal/index.ts +0 -66
- package/src/providers/whatsapp-business/index.ts +0 -77
- package/src/providers/whatsapp-business/messages.ts +0 -240
- package/src/providers/whatsapp-business/types.ts +0 -19
- package/src/spectrum.ts +0 -390
- package/src/types/content.ts +0 -85
- package/src/types/message.ts +0 -18
- package/src/types/space.ts +0 -10
- package/src/types/user.ts +0 -4
- package/src/utils/cloud.ts +0 -147
- package/src/utils/stream.ts +0 -71
package/src/platform/types.ts
DELETED
|
@@ -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
|
-
});
|