spectrum-ts 0.9.0 → 0.9.1
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-6ZOLTQDN.js → chunk-HU2EOF3K.js} +41 -11
- package/dist/{chunk-CZIWNTXP.js → chunk-OIXH5S65.js} +5 -3
- package/dist/{chunk-PLJI5FTO.js → chunk-U6WCQVVX.js} +130 -6
- package/dist/index.d.ts +43 -7
- package/dist/index.js +31 -30
- package/dist/providers/imessage/index.d.ts +16 -7
- package/dist/providers/imessage/index.js +338 -53
- package/dist/providers/terminal/index.d.ts +1 -1
- package/dist/providers/terminal/index.js +1 -1
- package/dist/providers/whatsapp-business/index.d.ts +1 -1
- package/dist/providers/whatsapp-business/index.js +11 -6
- package/dist/{types-B8g0pvfg.d.ts → types-D5KhSXLy.d.ts} +27 -2
- package/package.json +1 -1
|
@@ -2,10 +2,38 @@ import {
|
|
|
2
2
|
bufferToStream,
|
|
3
3
|
readSchema,
|
|
4
4
|
streamSchema
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-OIXH5S65.js";
|
|
6
|
+
import {
|
|
7
|
+
resolveContents
|
|
8
|
+
} from "./chunk-U6WCQVVX.js";
|
|
6
9
|
|
|
7
|
-
// src/content/
|
|
10
|
+
// src/content/group.ts
|
|
8
11
|
import z from "zod";
|
|
12
|
+
var isMessage = (v) => typeof v === "object" && v !== null && "id" in v && "content" in v;
|
|
13
|
+
var groupSchema = z.object({
|
|
14
|
+
type: z.literal("group"),
|
|
15
|
+
items: z.array(z.custom(isMessage)).min(2)
|
|
16
|
+
});
|
|
17
|
+
var asGroup = (input) => groupSchema.parse({ type: "group", items: input.items });
|
|
18
|
+
var stubOutboundMessage = (content) => ({ id: "", content });
|
|
19
|
+
function group(...items) {
|
|
20
|
+
return {
|
|
21
|
+
build: async () => {
|
|
22
|
+
const resolved = await resolveContents(items);
|
|
23
|
+
const members = [];
|
|
24
|
+
for (const item of resolved) {
|
|
25
|
+
if (item.type === "group" || item.type === "reaction") {
|
|
26
|
+
throw new Error(`group() cannot contain "${item.type}" items`);
|
|
27
|
+
}
|
|
28
|
+
members.push(stubOutboundMessage(item));
|
|
29
|
+
}
|
|
30
|
+
return asGroup({ items: members });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/content/richlink.ts
|
|
36
|
+
import z2 from "zod";
|
|
9
37
|
|
|
10
38
|
// src/utils/link-metadata.ts
|
|
11
39
|
import ogs from "open-graph-scraper";
|
|
@@ -76,22 +104,22 @@ var fetchImage = async (url) => {
|
|
|
76
104
|
};
|
|
77
105
|
|
|
78
106
|
// src/content/richlink.ts
|
|
79
|
-
var richlinkCoverSchema =
|
|
80
|
-
mimeType:
|
|
107
|
+
var richlinkCoverSchema = z2.object({
|
|
108
|
+
mimeType: z2.string().min(1).optional(),
|
|
81
109
|
read: readSchema,
|
|
82
110
|
stream: streamSchema
|
|
83
111
|
});
|
|
84
|
-
var optionalStringAccessor =
|
|
112
|
+
var optionalStringAccessor = z2.function({
|
|
85
113
|
input: [],
|
|
86
|
-
output:
|
|
114
|
+
output: z2.promise(z2.string().min(1).optional())
|
|
87
115
|
});
|
|
88
|
-
var coverAccessor =
|
|
116
|
+
var coverAccessor = z2.function({
|
|
89
117
|
input: [],
|
|
90
|
-
output:
|
|
118
|
+
output: z2.promise(richlinkCoverSchema.optional())
|
|
91
119
|
});
|
|
92
|
-
var richlinkSchema =
|
|
93
|
-
type:
|
|
94
|
-
url:
|
|
120
|
+
var richlinkSchema = z2.object({
|
|
121
|
+
type: z2.literal("richlink"),
|
|
122
|
+
url: z2.url(),
|
|
95
123
|
title: optionalStringAccessor,
|
|
96
124
|
summary: optionalStringAccessor,
|
|
97
125
|
cover: coverAccessor
|
|
@@ -136,6 +164,8 @@ function richlink(url) {
|
|
|
136
164
|
}
|
|
137
165
|
|
|
138
166
|
export {
|
|
167
|
+
asGroup,
|
|
168
|
+
group,
|
|
139
169
|
asRichlink,
|
|
140
170
|
richlink
|
|
141
171
|
};
|
|
@@ -555,15 +555,17 @@ function custom(raw) {
|
|
|
555
555
|
|
|
556
556
|
// src/content/reaction.ts
|
|
557
557
|
import z5 from "zod";
|
|
558
|
+
var isMessage = (v) => typeof v === "object" && v !== null && "id" in v && "content" in v;
|
|
558
559
|
var reactionSchema = z5.object({
|
|
559
560
|
type: z5.literal("reaction"),
|
|
560
561
|
emoji: z5.string().min(1),
|
|
561
|
-
target: z5.
|
|
562
|
+
target: z5.custom(isMessage, {
|
|
563
|
+
message: "reaction target must be a Message"
|
|
564
|
+
})
|
|
562
565
|
});
|
|
563
566
|
var asReaction = (input) => reactionSchema.parse({ type: "reaction", ...input });
|
|
564
567
|
function reaction(emoji, target) {
|
|
565
|
-
|
|
566
|
-
return { build: async () => asReaction({ emoji, target: targetId }) };
|
|
568
|
+
return { build: async () => asReaction({ emoji, target }) };
|
|
567
569
|
}
|
|
568
570
|
|
|
569
571
|
// src/utils/stream.ts
|
|
@@ -88,6 +88,63 @@ var warnUnsupported = (err, fallbackPlatform) => {
|
|
|
88
88
|
supportsAnsiColor() ? `${ANSI_YELLOW}${body}${ANSI_RESET}` : body
|
|
89
89
|
);
|
|
90
90
|
};
|
|
91
|
+
var providerMessageCoreKeys = /* @__PURE__ */ new Set([
|
|
92
|
+
"content",
|
|
93
|
+
"id",
|
|
94
|
+
"sender",
|
|
95
|
+
"space",
|
|
96
|
+
"timestamp"
|
|
97
|
+
]);
|
|
98
|
+
var extractExtras = (raw, definition) => {
|
|
99
|
+
const entries = Object.entries(raw).filter(
|
|
100
|
+
([key]) => !providerMessageCoreKeys.has(key)
|
|
101
|
+
);
|
|
102
|
+
const extra = Object.fromEntries(entries);
|
|
103
|
+
return definition.message?.schema ? definition.message.schema.parse(extra) : extra;
|
|
104
|
+
};
|
|
105
|
+
function wrapProviderMessage(raw, ctx) {
|
|
106
|
+
const wrappedContent = wrapNestedContent(raw.content, ctx);
|
|
107
|
+
return buildMessage({
|
|
108
|
+
id: raw.id,
|
|
109
|
+
content: wrappedContent,
|
|
110
|
+
sender: raw.sender,
|
|
111
|
+
timestamp: raw.timestamp ?? /* @__PURE__ */ new Date(),
|
|
112
|
+
extras: extractExtras(raw, ctx.definition),
|
|
113
|
+
spaceRef: ctx.spaceRef,
|
|
114
|
+
space: ctx.space,
|
|
115
|
+
definition: ctx.definition,
|
|
116
|
+
client: ctx.client,
|
|
117
|
+
config: ctx.config,
|
|
118
|
+
direction: "inbound"
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
var wrapNestedContent = (content, ctx) => {
|
|
122
|
+
if (content.type === "reaction") {
|
|
123
|
+
const target = content.target;
|
|
124
|
+
if (isRawProviderRecord(target)) {
|
|
125
|
+
return {
|
|
126
|
+
...content,
|
|
127
|
+
target: wrapProviderMessage(target, ctx)
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return content;
|
|
131
|
+
}
|
|
132
|
+
if (content.type === "group") {
|
|
133
|
+
const items = content.items.map((item) => {
|
|
134
|
+
const raw = item;
|
|
135
|
+
return isRawProviderRecord(raw) ? wrapProviderMessage(raw, ctx) : item;
|
|
136
|
+
});
|
|
137
|
+
return { ...content, items };
|
|
138
|
+
}
|
|
139
|
+
return content;
|
|
140
|
+
};
|
|
141
|
+
var isRawProviderRecord = (v) => {
|
|
142
|
+
if (typeof v !== "object" || v === null) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
const record = v;
|
|
146
|
+
return "id" in record && "content" in record && typeof record.react !== "function" && typeof record.reply !== "function";
|
|
147
|
+
};
|
|
91
148
|
function buildSpace(params) {
|
|
92
149
|
const { spaceRef, extras, typingCtx, definition, client, config } = params;
|
|
93
150
|
let space;
|
|
@@ -98,7 +155,7 @@ function buildSpace(params) {
|
|
|
98
155
|
}
|
|
99
156
|
await definition.actions.reactToMessage({
|
|
100
157
|
space: spaceRef,
|
|
101
|
-
|
|
158
|
+
target: item.target,
|
|
102
159
|
reaction: item.emoji,
|
|
103
160
|
client,
|
|
104
161
|
config
|
|
@@ -130,9 +187,31 @@ function buildSpace(params) {
|
|
|
130
187
|
`Platform "${definition.name}" send did not return a message id`
|
|
131
188
|
);
|
|
132
189
|
}
|
|
190
|
+
const outboundContent = item.type === "group" && sendResult.groupMembers ? {
|
|
191
|
+
...item,
|
|
192
|
+
items: item.items.map((stub, idx) => {
|
|
193
|
+
const member = sendResult?.groupMembers?.[idx];
|
|
194
|
+
if (!member?.id) {
|
|
195
|
+
return stub;
|
|
196
|
+
}
|
|
197
|
+
return buildMessage({
|
|
198
|
+
id: member.id,
|
|
199
|
+
content: stub.content,
|
|
200
|
+
sender: member.sender,
|
|
201
|
+
timestamp: member.timestamp ?? /* @__PURE__ */ new Date(),
|
|
202
|
+
extras: {},
|
|
203
|
+
spaceRef,
|
|
204
|
+
space,
|
|
205
|
+
definition,
|
|
206
|
+
client,
|
|
207
|
+
config,
|
|
208
|
+
direction: "outbound"
|
|
209
|
+
});
|
|
210
|
+
})
|
|
211
|
+
} : item;
|
|
133
212
|
return buildMessage({
|
|
134
213
|
id: sendResult.id,
|
|
135
|
-
content:
|
|
214
|
+
content: outboundContent,
|
|
136
215
|
sender: sendResult.sender,
|
|
137
216
|
timestamp: sendResult.timestamp ?? /* @__PURE__ */ new Date(),
|
|
138
217
|
extras: {},
|
|
@@ -162,6 +241,40 @@ function buildSpace(params) {
|
|
|
162
241
|
}
|
|
163
242
|
return results;
|
|
164
243
|
}
|
|
244
|
+
async function getMessageImpl(id) {
|
|
245
|
+
if (!definition.actions.getMessage) {
|
|
246
|
+
warnUnsupported(
|
|
247
|
+
UnsupportedError.action("getMessage", definition.name),
|
|
248
|
+
definition.name
|
|
249
|
+
);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
let raw;
|
|
253
|
+
try {
|
|
254
|
+
raw = await definition.actions.getMessage({
|
|
255
|
+
space: spaceRef,
|
|
256
|
+
messageId: id,
|
|
257
|
+
client,
|
|
258
|
+
config
|
|
259
|
+
});
|
|
260
|
+
} catch (err) {
|
|
261
|
+
if (err instanceof UnsupportedError) {
|
|
262
|
+
warnUnsupported(err, definition.name);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
throw err;
|
|
266
|
+
}
|
|
267
|
+
if (!raw) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
return wrapProviderMessage(raw, {
|
|
271
|
+
client,
|
|
272
|
+
config,
|
|
273
|
+
definition,
|
|
274
|
+
space,
|
|
275
|
+
spaceRef
|
|
276
|
+
});
|
|
277
|
+
}
|
|
165
278
|
space = {
|
|
166
279
|
...extras,
|
|
167
280
|
...spaceRef,
|
|
@@ -169,6 +282,7 @@ function buildSpace(params) {
|
|
|
169
282
|
edit: async (message, newContent) => {
|
|
170
283
|
await message.edit(newContent);
|
|
171
284
|
},
|
|
285
|
+
getMessage: getMessageImpl,
|
|
172
286
|
startTyping: async () => {
|
|
173
287
|
await definition.actions.startTyping?.(typingCtx);
|
|
174
288
|
},
|
|
@@ -189,6 +303,7 @@ function buildSpace(params) {
|
|
|
189
303
|
}
|
|
190
304
|
function buildMessage(params) {
|
|
191
305
|
const { definition, client, config, spaceRef, space } = params;
|
|
306
|
+
let self;
|
|
192
307
|
const react = async (reaction) => {
|
|
193
308
|
if (!definition.actions.reactToMessage) {
|
|
194
309
|
warnUnsupported(
|
|
@@ -197,10 +312,15 @@ function buildMessage(params) {
|
|
|
197
312
|
);
|
|
198
313
|
return;
|
|
199
314
|
}
|
|
315
|
+
if (!self) {
|
|
316
|
+
throw new Error(
|
|
317
|
+
"react() called before message construction completed (internal bug)"
|
|
318
|
+
);
|
|
319
|
+
}
|
|
200
320
|
try {
|
|
201
321
|
await definition.actions.reactToMessage({
|
|
202
322
|
space: spaceRef,
|
|
203
|
-
|
|
323
|
+
target: self,
|
|
204
324
|
reaction,
|
|
205
325
|
client,
|
|
206
326
|
config
|
|
@@ -268,7 +388,7 @@ function buildMessage(params) {
|
|
|
268
388
|
}
|
|
269
389
|
const senderWithPlatform = params.sender === void 0 ? void 0 : { ...params.sender, __platform: definition.name };
|
|
270
390
|
if (params.direction === "outbound") {
|
|
271
|
-
|
|
391
|
+
const outbound = {
|
|
272
392
|
...params.extras,
|
|
273
393
|
id: params.id,
|
|
274
394
|
content: params.content,
|
|
@@ -308,8 +428,10 @@ function buildMessage(params) {
|
|
|
308
428
|
space,
|
|
309
429
|
timestamp: params.timestamp
|
|
310
430
|
};
|
|
431
|
+
self = outbound;
|
|
432
|
+
return outbound;
|
|
311
433
|
}
|
|
312
|
-
|
|
434
|
+
const inbound = {
|
|
313
435
|
...params.extras,
|
|
314
436
|
id: params.id,
|
|
315
437
|
content: params.content,
|
|
@@ -321,6 +443,8 @@ function buildMessage(params) {
|
|
|
321
443
|
space,
|
|
322
444
|
timestamp: params.timestamp
|
|
323
445
|
};
|
|
446
|
+
self = inbound;
|
|
447
|
+
return inbound;
|
|
324
448
|
}
|
|
325
449
|
|
|
326
450
|
// src/platform/define.ts
|
|
@@ -507,7 +631,7 @@ export {
|
|
|
507
631
|
text,
|
|
508
632
|
resolveContents,
|
|
509
633
|
UnsupportedError,
|
|
634
|
+
wrapProviderMessage,
|
|
510
635
|
buildSpace,
|
|
511
|
-
buildMessage,
|
|
512
636
|
definePlatform
|
|
513
637
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ContentBuilder, U as User, M as Message, 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-
|
|
2
|
-
export { A as AnyPlatformDef, E as EventProducer, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage } from './types-
|
|
1
|
+
import { C as ContentBuilder, U as User, M as Message, 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-D5KhSXLy.js';
|
|
2
|
+
export { A as AnyPlatformDef, E as EventProducer, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage } from './types-D5KhSXLy.js';
|
|
3
3
|
import vCard from 'vcf';
|
|
4
4
|
import z__default from 'zod';
|
|
5
5
|
export { M as ManagedStream, m as mergeStreams, s as stream } from './stream-B55k7W8-.js';
|
|
@@ -122,21 +122,39 @@ declare function contact(input: string | ContactInput | vCard): ContentBuilder;
|
|
|
122
122
|
|
|
123
123
|
declare function custom(raw: unknown): ContentBuilder;
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* A `group` bundles multiple messages into one logical unit (e.g. an album
|
|
127
|
+
* of images sent together). Each item is a full `Message` — addressable by
|
|
128
|
+
* id, reactable via `.react()`, replyable via `.reply()`.
|
|
129
|
+
*
|
|
130
|
+
* Groups do not nest, and reactions cannot be group members. Enforced by the
|
|
131
|
+
* `group()` builder; platforms may additionally reject unsupported item
|
|
132
|
+
* content types at send time.
|
|
133
|
+
*/
|
|
134
|
+
declare const groupSchema: z__default.ZodObject<{
|
|
135
|
+
type: z__default.ZodLiteral<"group">;
|
|
136
|
+
items: z__default.ZodArray<z__default.ZodCustom<Message, Message>>;
|
|
137
|
+
}, z__default.core.$strip>;
|
|
138
|
+
type Group = z__default.infer<typeof groupSchema>;
|
|
139
|
+
declare function group(...items: [ContentInput, ContentInput, ...ContentInput[]]): ContentBuilder;
|
|
140
|
+
|
|
125
141
|
declare const reactionSchema: z__default.ZodObject<{
|
|
126
142
|
type: z__default.ZodLiteral<"reaction">;
|
|
127
143
|
emoji: z__default.ZodString;
|
|
128
|
-
target: z__default.
|
|
144
|
+
target: z__default.ZodCustom<Message, Message>;
|
|
129
145
|
}, z__default.core.$strip>;
|
|
130
146
|
type Reaction = z__default.infer<typeof reactionSchema>;
|
|
131
147
|
/**
|
|
132
|
-
* Construct a `reaction` content value
|
|
133
|
-
* a string is treated as the target message id directly.
|
|
148
|
+
* Construct a `reaction` content value targeting the given message.
|
|
134
149
|
*
|
|
135
150
|
* `space.send(reaction(emoji, message))` is sugar for `message.react(emoji)`.
|
|
136
151
|
* Reactions are fire-and-forget — the returned `OutboundMessage` will be
|
|
137
152
|
* `undefined` because platforms do not surface a message id for reactions.
|
|
153
|
+
*
|
|
154
|
+
* To react to a message known only by id, resolve it first via
|
|
155
|
+
* `space.getMessage(id)`.
|
|
138
156
|
*/
|
|
139
|
-
declare function reaction(emoji: string, target: Message
|
|
157
|
+
declare function reaction(emoji: string, target: Message): ContentBuilder;
|
|
140
158
|
|
|
141
159
|
declare const resolveContents: (items: readonly ContentInput[]) => Promise<Content[]>;
|
|
142
160
|
|
|
@@ -2122,14 +2140,32 @@ type SpectrumInstance<Providers extends PlatformProviderConfig[] = PlatformProvi
|
|
|
2122
2140
|
edit(message: OutboundMessage, newContent: ContentInput): Promise<void>;
|
|
2123
2141
|
responding<T>(space: Space, fn: () => T | Promise<T>): Promise<T>;
|
|
2124
2142
|
};
|
|
2143
|
+
/**
|
|
2144
|
+
* Runtime behavior tweaks for a Spectrum instance.
|
|
2145
|
+
*/
|
|
2146
|
+
interface SpectrumOptions {
|
|
2147
|
+
/**
|
|
2148
|
+
* When `true`, inbound `group` messages are never delivered whole. Instead,
|
|
2149
|
+
* each group item is yielded from `spectrum.messages` as its own
|
|
2150
|
+
* `[space, message]` tuple, in order. Items retain their individual
|
|
2151
|
+
* `id`, `sender`, `timestamp`, and `.react()` / `.reply()` methods.
|
|
2152
|
+
*
|
|
2153
|
+
* Does not affect outbound `group(...)` sends or `space.getMessage(id)`.
|
|
2154
|
+
*
|
|
2155
|
+
* @default false
|
|
2156
|
+
*/
|
|
2157
|
+
flattenGroups?: boolean;
|
|
2158
|
+
}
|
|
2125
2159
|
declare function Spectrum<const Providers extends PlatformProviderConfig[]>(options: {
|
|
2126
2160
|
projectId: string;
|
|
2127
2161
|
projectSecret: string;
|
|
2128
2162
|
providers: [...Providers];
|
|
2163
|
+
options?: SpectrumOptions;
|
|
2129
2164
|
} | {
|
|
2130
2165
|
projectId?: never;
|
|
2131
2166
|
projectSecret?: never;
|
|
2132
2167
|
providers: [...Providers];
|
|
2168
|
+
options?: SpectrumOptions;
|
|
2133
2169
|
}): Promise<SpectrumInstance<Providers>>;
|
|
2134
2170
|
|
|
2135
2171
|
type SubscriptionStatus = "active" | "canceled" | "past_due";
|
|
@@ -2198,4 +2234,4 @@ declare class UnsupportedError extends Error {
|
|
|
2198
2234
|
declare const fromVCard: (vcf: string) => ContactInput;
|
|
2199
2235
|
declare const toVCard: (contact: Contact) => Promise<string>;
|
|
2200
2236
|
|
|
2201
|
-
export { type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, Content, ContentBuilder, ContentInput, type DedicatedTokenData, Emoji, type EmojiKey, type ImessageInfoData, Message, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, type Reaction, type Richlink, type SharedTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, UnsupportedError, type UnsupportedKind, User, type Voice, attachment, cloud, contact, custom, definePlatform, fromVCard, reaction, resolveContents, richlink, text, toVCard, voice };
|
|
2237
|
+
export { type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, Content, ContentBuilder, ContentInput, type DedicatedTokenData, Emoji, type EmojiKey, type Group, type ImessageInfoData, Message, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, type Reaction, type Richlink, type SharedTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, UnsupportedError, type UnsupportedKind, User, type Voice, attachment, cloud, contact, custom, definePlatform, fromVCard, group, reaction, resolveContents, richlink, text, toVCard, voice };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
group,
|
|
2
3
|
richlink
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HU2EOF3K.js";
|
|
4
5
|
import {
|
|
5
6
|
SpectrumCloudError,
|
|
6
7
|
attachment,
|
|
@@ -15,15 +16,15 @@ import {
|
|
|
15
16
|
stream,
|
|
16
17
|
streamSchema,
|
|
17
18
|
toVCard
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-OIXH5S65.js";
|
|
19
20
|
import {
|
|
20
21
|
UnsupportedError,
|
|
21
|
-
buildMessage,
|
|
22
22
|
buildSpace,
|
|
23
23
|
definePlatform,
|
|
24
24
|
resolveContents,
|
|
25
|
-
text
|
|
26
|
-
|
|
25
|
+
text,
|
|
26
|
+
wrapProviderMessage
|
|
27
|
+
} from "./chunk-U6WCQVVX.js";
|
|
27
28
|
|
|
28
29
|
// src/content/voice.ts
|
|
29
30
|
import { createReadStream } from "fs";
|
|
@@ -2063,28 +2064,32 @@ var Emoji = { ...GeneratedEmoji, ...aliases };
|
|
|
2063
2064
|
|
|
2064
2065
|
// src/spectrum.ts
|
|
2065
2066
|
import z2 from "zod";
|
|
2066
|
-
var
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
"sender",
|
|
2070
|
-
"space",
|
|
2071
|
-
"timestamp"
|
|
2072
|
-
]);
|
|
2067
|
+
var spectrumOptionsSchema = z2.object({
|
|
2068
|
+
flattenGroups: z2.boolean().optional()
|
|
2069
|
+
}).optional();
|
|
2073
2070
|
var spectrumConfigSchema = z2.union([
|
|
2074
2071
|
z2.object({
|
|
2075
2072
|
projectId: z2.string().min(1),
|
|
2076
2073
|
projectSecret: z2.string().min(1),
|
|
2077
|
-
providers: z2.array(z2.custom())
|
|
2074
|
+
providers: z2.array(z2.custom()),
|
|
2075
|
+
options: spectrumOptionsSchema
|
|
2078
2076
|
}),
|
|
2079
2077
|
z2.object({
|
|
2080
2078
|
projectId: z2.undefined().optional(),
|
|
2081
2079
|
projectSecret: z2.undefined().optional(),
|
|
2082
|
-
providers: z2.array(z2.custom())
|
|
2080
|
+
providers: z2.array(z2.custom()),
|
|
2081
|
+
options: spectrumOptionsSchema
|
|
2083
2082
|
})
|
|
2084
2083
|
]);
|
|
2085
2084
|
async function Spectrum(options) {
|
|
2086
2085
|
spectrumConfigSchema.parse(options);
|
|
2087
|
-
const {
|
|
2086
|
+
const {
|
|
2087
|
+
projectId,
|
|
2088
|
+
projectSecret,
|
|
2089
|
+
providers,
|
|
2090
|
+
options: runtimeOptions
|
|
2091
|
+
} = options;
|
|
2092
|
+
const flattenGroups = runtimeOptions?.flattenGroups ?? false;
|
|
2088
2093
|
const platformStates = /* @__PURE__ */ new Map();
|
|
2089
2094
|
const customEventStreams = /* @__PURE__ */ new Map();
|
|
2090
2095
|
let stopped = false;
|
|
@@ -2132,11 +2137,6 @@ async function Spectrum(options) {
|
|
|
2132
2137
|
});
|
|
2133
2138
|
const bindSend = async function* () {
|
|
2134
2139
|
for await (const msg of raw) {
|
|
2135
|
-
const extraEntries = Object.entries(msg).filter(
|
|
2136
|
-
([key]) => !providerMessageCoreKeys.has(key)
|
|
2137
|
-
);
|
|
2138
|
-
const extra = Object.fromEntries(extraEntries);
|
|
2139
|
-
const parsedExtra = definition.message?.schema ? definition.message.schema.parse(extra) : {};
|
|
2140
2140
|
const spaceRef = {
|
|
2141
2141
|
...msg.space,
|
|
2142
2142
|
__platform: definition.name
|
|
@@ -2150,19 +2150,19 @@ async function Spectrum(options) {
|
|
|
2150
2150
|
client,
|
|
2151
2151
|
config
|
|
2152
2152
|
});
|
|
2153
|
-
const normalizedMessage =
|
|
2154
|
-
id: msg.id,
|
|
2155
|
-
content: msg.content,
|
|
2156
|
-
sender: msg.sender,
|
|
2157
|
-
timestamp: msg.timestamp ?? /* @__PURE__ */ new Date(),
|
|
2158
|
-
extras: parsedExtra,
|
|
2159
|
-
spaceRef,
|
|
2160
|
-
space,
|
|
2161
|
-
definition,
|
|
2153
|
+
const normalizedMessage = wrapProviderMessage(msg, {
|
|
2162
2154
|
client,
|
|
2163
2155
|
config,
|
|
2164
|
-
|
|
2156
|
+
definition,
|
|
2157
|
+
space,
|
|
2158
|
+
spaceRef
|
|
2165
2159
|
});
|
|
2160
|
+
if (flattenGroups && normalizedMessage.content.type === "group") {
|
|
2161
|
+
for (const item of normalizedMessage.content.items) {
|
|
2162
|
+
yield [space, item];
|
|
2163
|
+
}
|
|
2164
|
+
continue;
|
|
2165
|
+
}
|
|
2166
2166
|
yield [space, normalizedMessage];
|
|
2167
2167
|
}
|
|
2168
2168
|
};
|
|
@@ -2310,6 +2310,7 @@ export {
|
|
|
2310
2310
|
custom,
|
|
2311
2311
|
definePlatform,
|
|
2312
2312
|
fromVCard,
|
|
2313
|
+
group,
|
|
2313
2314
|
mergeStreams,
|
|
2314
2315
|
reaction,
|
|
2315
2316
|
resolveContents,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { M as ManagedStream } from '../../stream-B55k7W8-.js';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-D5KhSXLy.js';
|
|
3
|
+
import * as zod_v4_core from 'zod/v4/core';
|
|
4
4
|
import * as z from 'zod';
|
|
5
5
|
import z__default from 'zod';
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
6
|
+
import { AdvancedIMessage } from '@photon-ai/advanced-imessage';
|
|
7
|
+
import { IMessageSDK } from '@photon-ai/imessage-kit';
|
|
8
8
|
import 'hotscript';
|
|
9
9
|
|
|
10
10
|
type IMessageClient = IMessageSDK | AdvancedIMessage[];
|
|
@@ -16,7 +16,10 @@ declare const spaceSchema: z__default.ZodObject<{
|
|
|
16
16
|
group: "group";
|
|
17
17
|
}>;
|
|
18
18
|
}, z__default.core.$strip>;
|
|
19
|
-
type IMessageMessage = SchemaMessage<typeof userSchema, typeof spaceSchema
|
|
19
|
+
type IMessageMessage = SchemaMessage<typeof userSchema, typeof spaceSchema> & {
|
|
20
|
+
partIndex?: number;
|
|
21
|
+
parentId?: string;
|
|
22
|
+
};
|
|
20
23
|
|
|
21
24
|
declare const imessage: Platform<PlatformDef<"iMessage", z.ZodUnion<readonly [z.ZodObject<{
|
|
22
25
|
local: z.ZodLiteral<true>;
|
|
@@ -43,7 +46,10 @@ declare const imessage: Platform<PlatformDef<"iMessage", z.ZodUnion<readonly [z.
|
|
|
43
46
|
} | {
|
|
44
47
|
id: string;
|
|
45
48
|
type: "group";
|
|
46
|
-
},
|
|
49
|
+
}, z.ZodObject<{
|
|
50
|
+
partIndex: z.ZodOptional<z.ZodNumber>;
|
|
51
|
+
parentId: z.ZodOptional<z.ZodString>;
|
|
52
|
+
}, zod_v4_core.$strip>, ProviderMessage<{
|
|
47
53
|
id: string;
|
|
48
54
|
}, {
|
|
49
55
|
id: string;
|
|
@@ -51,7 +57,10 @@ declare const imessage: Platform<PlatformDef<"iMessage", z.ZodUnion<readonly [z.
|
|
|
51
57
|
} | {
|
|
52
58
|
id: string;
|
|
53
59
|
type: "group";
|
|
54
|
-
},
|
|
60
|
+
}, {
|
|
61
|
+
partIndex?: number | undefined;
|
|
62
|
+
parentId?: string | undefined;
|
|
63
|
+
}>, {
|
|
55
64
|
messages: ({ client }: {
|
|
56
65
|
client: IMessageClient;
|
|
57
66
|
config: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
asGroup,
|
|
2
3
|
asRichlink
|
|
3
|
-
} from "../../chunk-
|
|
4
|
+
} from "../../chunk-HU2EOF3K.js";
|
|
4
5
|
import {
|
|
5
6
|
asAttachment,
|
|
6
7
|
asContact,
|
|
@@ -11,12 +12,12 @@ import {
|
|
|
11
12
|
mergeStreams,
|
|
12
13
|
stream,
|
|
13
14
|
toVCard
|
|
14
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-OIXH5S65.js";
|
|
15
16
|
import {
|
|
16
17
|
UnsupportedError,
|
|
17
18
|
asText,
|
|
18
19
|
definePlatform
|
|
19
|
-
} from "../../chunk-
|
|
20
|
+
} from "../../chunk-U6WCQVVX.js";
|
|
20
21
|
|
|
21
22
|
// src/providers/imessage/index.ts
|
|
22
23
|
import { createClient as createClient2, directChat } from "@photon-ai/advanced-imessage";
|
|
@@ -249,6 +250,7 @@ var send = async (client, spaceId, content) => {
|
|
|
249
250
|
throw UnsupportedError.content(content.type, "iMessage (local mode)");
|
|
250
251
|
}
|
|
251
252
|
};
|
|
253
|
+
var getMessage = async (_client, _id) => void 0;
|
|
252
254
|
|
|
253
255
|
// src/providers/imessage/remote.ts
|
|
254
256
|
import {
|
|
@@ -380,10 +382,52 @@ var ensureM4a = async (buffer, mimeType) => {
|
|
|
380
382
|
return transcodeToM4a(buffer);
|
|
381
383
|
};
|
|
382
384
|
|
|
385
|
+
// src/providers/imessage/cache.ts
|
|
386
|
+
var DEFAULT_MAX = 1e3;
|
|
387
|
+
var MessageCache = class {
|
|
388
|
+
map = /* @__PURE__ */ new Map();
|
|
389
|
+
max;
|
|
390
|
+
constructor(max = DEFAULT_MAX) {
|
|
391
|
+
this.max = max;
|
|
392
|
+
}
|
|
393
|
+
get(id) {
|
|
394
|
+
return this.map.get(id);
|
|
395
|
+
}
|
|
396
|
+
set(id, message) {
|
|
397
|
+
if (this.map.has(id)) {
|
|
398
|
+
this.map.delete(id);
|
|
399
|
+
}
|
|
400
|
+
this.map.set(id, message);
|
|
401
|
+
if (this.map.size > this.max) {
|
|
402
|
+
const first = this.map.keys().next().value;
|
|
403
|
+
if (first !== void 0) {
|
|
404
|
+
this.map.delete(first);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
clear() {
|
|
409
|
+
this.map.clear();
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
var caches = /* @__PURE__ */ new WeakMap();
|
|
413
|
+
var getMessageCache = (owner) => {
|
|
414
|
+
let cache = caches.get(owner);
|
|
415
|
+
if (!cache) {
|
|
416
|
+
cache = new MessageCache();
|
|
417
|
+
caches.set(owner, cache);
|
|
418
|
+
}
|
|
419
|
+
return cache;
|
|
420
|
+
};
|
|
421
|
+
|
|
383
422
|
// src/providers/imessage/remote.ts
|
|
384
423
|
var PLATFORM = "iMessage";
|
|
385
424
|
var URL_BALLOON_BUNDLE_ID = "com.apple.messages.URLBalloonProvider";
|
|
386
|
-
var
|
|
425
|
+
var GROUP_ITEM_ALLOWED = /* @__PURE__ */ new Set([
|
|
426
|
+
"attachment",
|
|
427
|
+
"contact",
|
|
428
|
+
"voice"
|
|
429
|
+
]);
|
|
430
|
+
var unsupportedContent = (type, detail) => UnsupportedError.content(type, PLATFORM, detail);
|
|
387
431
|
var toSendResult = (receipt) => ({
|
|
388
432
|
id: receipt.guid,
|
|
389
433
|
timestamp: /* @__PURE__ */ new Date()
|
|
@@ -442,14 +486,19 @@ var getAssociatedMessageType = (message) => {
|
|
|
442
486
|
const fromRaw = raw?.associatedMessageType;
|
|
443
487
|
return typeof fromRaw === "string" ? fromRaw : void 0;
|
|
444
488
|
};
|
|
445
|
-
var
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
489
|
+
var getBalloonBundleId = (message) => {
|
|
490
|
+
const raw = message._raw;
|
|
491
|
+
const id = raw?.balloonBundleId;
|
|
492
|
+
return typeof id === "string" ? id : void 0;
|
|
493
|
+
};
|
|
494
|
+
var resolveChatGuid = (message, hint) => {
|
|
495
|
+
if (hint) {
|
|
496
|
+
return hint;
|
|
497
|
+
}
|
|
498
|
+
const first = message.chatGuids?.[0];
|
|
499
|
+
return first ?? "";
|
|
500
|
+
};
|
|
501
|
+
var resolveSenderId = (message) => message.sender?.address ?? "";
|
|
453
502
|
var toAttachmentContent2 = (client, info) => asAttachment({
|
|
454
503
|
name: info.fileName,
|
|
455
504
|
mimeType: info.mimeType,
|
|
@@ -465,10 +514,87 @@ var toVCardContent2 = async (client, info) => {
|
|
|
465
514
|
return toAttachmentContent2(client, info);
|
|
466
515
|
}
|
|
467
516
|
};
|
|
468
|
-
var
|
|
469
|
-
|
|
470
|
-
const
|
|
471
|
-
return
|
|
517
|
+
var attachmentContent = async (client, info) => isVCardAttachment2(info.mimeType, info.fileName) ? await toVCardContent2(client, info) : toAttachmentContent2(client, info);
|
|
518
|
+
var baseShape = (message, chatGuidHint, timestamp) => {
|
|
519
|
+
const chat = resolveChatGuid(message, chatGuidHint);
|
|
520
|
+
return {
|
|
521
|
+
sender: { id: resolveSenderId(message) },
|
|
522
|
+
space: {
|
|
523
|
+
id: chat,
|
|
524
|
+
type: chat.includes(";+;") ? "group" : "dm"
|
|
525
|
+
},
|
|
526
|
+
timestamp
|
|
527
|
+
};
|
|
528
|
+
};
|
|
529
|
+
var buildAttachmentMessage = async (client, base, info, id, partIndex, parentId) => {
|
|
530
|
+
const content = await attachmentContent(client, info);
|
|
531
|
+
const msg = { ...base, id, content, partIndex };
|
|
532
|
+
if (parentId !== void 0) {
|
|
533
|
+
msg.parentId = parentId;
|
|
534
|
+
}
|
|
535
|
+
return msg;
|
|
536
|
+
};
|
|
537
|
+
var rebuildFromAppleMessage = async (client, message, chatGuidHint) => {
|
|
538
|
+
const messageGuidStr = message.guid;
|
|
539
|
+
const timestamp = message.dateCreated ?? /* @__PURE__ */ new Date();
|
|
540
|
+
const base = baseShape(message, chatGuidHint, timestamp);
|
|
541
|
+
if (message.attachments.length === 1) {
|
|
542
|
+
const info = message.attachments[0];
|
|
543
|
+
if (!info) {
|
|
544
|
+
throw new Error("Unreachable: attachments.length === 1 but no element");
|
|
545
|
+
}
|
|
546
|
+
return buildAttachmentMessage(client, base, info, messageGuidStr, 0);
|
|
547
|
+
}
|
|
548
|
+
if (message.attachments.length > 1) {
|
|
549
|
+
const items = [];
|
|
550
|
+
for (let i = 0; i < message.attachments.length; i++) {
|
|
551
|
+
const info = message.attachments[i];
|
|
552
|
+
if (!info) {
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
items.push(
|
|
556
|
+
await buildAttachmentMessage(
|
|
557
|
+
client,
|
|
558
|
+
base,
|
|
559
|
+
info,
|
|
560
|
+
formatChildId(i, messageGuidStr),
|
|
561
|
+
i,
|
|
562
|
+
messageGuidStr
|
|
563
|
+
)
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
return {
|
|
567
|
+
...base,
|
|
568
|
+
id: messageGuidStr,
|
|
569
|
+
content: asGroup({ items })
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
const text = message.text;
|
|
573
|
+
if (getBalloonBundleId(message) === URL_BALLOON_BUNDLE_ID) {
|
|
574
|
+
const url = text ?? "";
|
|
575
|
+
try {
|
|
576
|
+
return { ...base, id: messageGuidStr, content: asRichlink({ url }) };
|
|
577
|
+
} catch {
|
|
578
|
+
return {
|
|
579
|
+
...base,
|
|
580
|
+
id: messageGuidStr,
|
|
581
|
+
content: url ? asText(url) : asCustom(message)
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return {
|
|
586
|
+
...base,
|
|
587
|
+
id: messageGuidStr,
|
|
588
|
+
content: text ? asText(text) : asCustom(message)
|
|
589
|
+
};
|
|
590
|
+
};
|
|
591
|
+
var cacheMessage = (cache, message) => {
|
|
592
|
+
cache.set(message.id, message);
|
|
593
|
+
if (message.content.type === "group") {
|
|
594
|
+
for (const item of message.content.items) {
|
|
595
|
+
cache.set(item.id, item);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
472
598
|
};
|
|
473
599
|
var toRichlinkMessage = (event, base, id) => {
|
|
474
600
|
const url = event.message.text ?? "";
|
|
@@ -482,8 +608,42 @@ var toRichlinkMessage = (event, base, id) => {
|
|
|
482
608
|
};
|
|
483
609
|
}
|
|
484
610
|
};
|
|
485
|
-
var PART_PREFIX = /^p
|
|
486
|
-
var
|
|
611
|
+
var PART_PREFIX = /^p:(\d+)\//;
|
|
612
|
+
var formatChildId = (partIndex, parentGuid) => `p:${partIndex}/${parentGuid}`;
|
|
613
|
+
var parseTapbackTarget = (target) => {
|
|
614
|
+
const match = target.match(PART_PREFIX);
|
|
615
|
+
const guid = target.replace(PART_PREFIX, "");
|
|
616
|
+
const partIndex = match ? Number(match[1]) : 0;
|
|
617
|
+
return { guid, partIndex };
|
|
618
|
+
};
|
|
619
|
+
var parseChildId = (id) => {
|
|
620
|
+
const match = id.match(PART_PREFIX);
|
|
621
|
+
if (!match) {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
parentGuid: id.replace(PART_PREFIX, ""),
|
|
626
|
+
partIndex: Number(match[1])
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
var resolveReactionTarget = async (client, cache, strippedGuid, partIndex) => {
|
|
630
|
+
let candidate = cache.get(strippedGuid);
|
|
631
|
+
if (!candidate) {
|
|
632
|
+
try {
|
|
633
|
+
const fetched = await client.messages.get(messageGuid(strippedGuid));
|
|
634
|
+
candidate = await rebuildFromAppleMessage(client, fetched);
|
|
635
|
+
cacheMessage(cache, candidate);
|
|
636
|
+
} catch {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (candidate.content.type === "group") {
|
|
641
|
+
const item = candidate.content.items[partIndex];
|
|
642
|
+
return item ?? candidate;
|
|
643
|
+
}
|
|
644
|
+
return candidate;
|
|
645
|
+
};
|
|
646
|
+
var toReactionMessage = async (client, cache, event, base, id, target) => {
|
|
487
647
|
const type = getAssociatedMessageType(event.message);
|
|
488
648
|
if (type && isTapbackRemoval(type)) {
|
|
489
649
|
return [];
|
|
@@ -495,41 +655,89 @@ var toReactionMessage = (event, base, id, target) => {
|
|
|
495
655
|
if (!emoji) {
|
|
496
656
|
return [];
|
|
497
657
|
}
|
|
498
|
-
const
|
|
658
|
+
const { guid: strippedGuid, partIndex } = parseTapbackTarget(target);
|
|
659
|
+
const resolved = await resolveReactionTarget(
|
|
660
|
+
client,
|
|
661
|
+
cache,
|
|
662
|
+
strippedGuid,
|
|
663
|
+
partIndex
|
|
664
|
+
);
|
|
665
|
+
if (!resolved) {
|
|
666
|
+
return [];
|
|
667
|
+
}
|
|
499
668
|
return [
|
|
500
|
-
{
|
|
669
|
+
{
|
|
670
|
+
...base,
|
|
671
|
+
id,
|
|
672
|
+
content: asReaction({ emoji, target: resolved })
|
|
673
|
+
}
|
|
501
674
|
];
|
|
502
675
|
};
|
|
503
|
-
var toMessages2 = async (client, event) => {
|
|
504
|
-
const base =
|
|
676
|
+
var toMessages2 = async (client, cache, event) => {
|
|
677
|
+
const base = baseShape(event.message, event.chatGuid, event.timestamp);
|
|
505
678
|
const messageGuidStr = event.message.guid;
|
|
506
679
|
const assoc = event.message.associatedMessageGuid;
|
|
507
680
|
if (assoc) {
|
|
508
|
-
return toReactionMessage(event, base, messageGuidStr, assoc);
|
|
681
|
+
return toReactionMessage(client, cache, event, base, messageGuidStr, assoc);
|
|
509
682
|
}
|
|
510
683
|
if (getBalloonBundleId(event.message) === URL_BALLOON_BUNDLE_ID) {
|
|
511
|
-
|
|
684
|
+
const msg2 = toRichlinkMessage(event, base, messageGuidStr);
|
|
685
|
+
cacheMessage(cache, msg2);
|
|
686
|
+
return [msg2];
|
|
512
687
|
}
|
|
513
|
-
if (event.message.attachments.length
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
688
|
+
if (event.message.attachments.length === 1) {
|
|
689
|
+
const info = event.message.attachments[0];
|
|
690
|
+
if (!info) {
|
|
691
|
+
throw new Error("Unreachable: attachments.length === 1 but no element");
|
|
692
|
+
}
|
|
693
|
+
const msg2 = await buildAttachmentMessage(
|
|
694
|
+
client,
|
|
695
|
+
base,
|
|
696
|
+
info,
|
|
697
|
+
messageGuidStr,
|
|
698
|
+
0
|
|
520
699
|
);
|
|
700
|
+
cacheMessage(cache, msg2);
|
|
701
|
+
return [msg2];
|
|
521
702
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
{
|
|
703
|
+
if (event.message.attachments.length > 1) {
|
|
704
|
+
const items = [];
|
|
705
|
+
for (let i = 0; i < event.message.attachments.length; i++) {
|
|
706
|
+
const info = event.message.attachments[i];
|
|
707
|
+
if (!info) {
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
items.push(
|
|
711
|
+
await buildAttachmentMessage(
|
|
712
|
+
client,
|
|
713
|
+
base,
|
|
714
|
+
info,
|
|
715
|
+
formatChildId(i, messageGuidStr),
|
|
716
|
+
i,
|
|
717
|
+
messageGuidStr
|
|
718
|
+
)
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
const parent = {
|
|
525
722
|
...base,
|
|
526
723
|
id: messageGuidStr,
|
|
527
|
-
content:
|
|
528
|
-
}
|
|
529
|
-
|
|
724
|
+
content: asGroup({ items })
|
|
725
|
+
};
|
|
726
|
+
cacheMessage(cache, parent);
|
|
727
|
+
return [parent];
|
|
728
|
+
}
|
|
729
|
+
const text = event.message.text;
|
|
730
|
+
const msg = {
|
|
731
|
+
...base,
|
|
732
|
+
id: messageGuidStr,
|
|
733
|
+
content: text ? asText(text) : asCustom(event.message)
|
|
734
|
+
};
|
|
735
|
+
cacheMessage(cache, msg);
|
|
736
|
+
return [msg];
|
|
530
737
|
};
|
|
531
738
|
var clientStream = (client) => {
|
|
532
739
|
const sub = client.messages.subscribe("message.received");
|
|
740
|
+
const cache = getMessageCache(client);
|
|
533
741
|
return stream((emit, end) => {
|
|
534
742
|
const pump = (async () => {
|
|
535
743
|
try {
|
|
@@ -537,7 +745,7 @@ var clientStream = (client) => {
|
|
|
537
745
|
if (event.message.isFromMe) {
|
|
538
746
|
continue;
|
|
539
747
|
}
|
|
540
|
-
for (const message of await toMessages2(client, event)) {
|
|
748
|
+
for (const message of await toMessages2(client, cache, event)) {
|
|
541
749
|
await emit(message);
|
|
542
750
|
}
|
|
543
751
|
}
|
|
@@ -581,12 +789,7 @@ var stopTyping = async (clients, spaceId) => {
|
|
|
581
789
|
}
|
|
582
790
|
await remote.chats.stopTyping(chatGuid(spaceId));
|
|
583
791
|
};
|
|
584
|
-
var
|
|
585
|
-
const remote = clients[0];
|
|
586
|
-
if (!remote) {
|
|
587
|
-
throw new Error("No remote iMessage client available");
|
|
588
|
-
}
|
|
589
|
-
const chat = chatGuid(spaceId);
|
|
792
|
+
var sendSingle = async (remote, chat, content) => {
|
|
590
793
|
switch (content.type) {
|
|
591
794
|
case "text":
|
|
592
795
|
return toSendResult(await remote.messages.send(chat, content.text));
|
|
@@ -601,9 +804,7 @@ var send2 = async (clients, spaceId, content) => {
|
|
|
601
804
|
mimeType: content.mimeType
|
|
602
805
|
});
|
|
603
806
|
return toSendResult(
|
|
604
|
-
await remote.messages.send(chat, "", {
|
|
605
|
-
attachment: attachment.guid
|
|
606
|
-
})
|
|
807
|
+
await remote.messages.send(chat, "", { attachment: attachment.guid })
|
|
607
808
|
);
|
|
608
809
|
}
|
|
609
810
|
case "contact": {
|
|
@@ -631,6 +832,34 @@ var send2 = async (clients, spaceId, content) => {
|
|
|
631
832
|
throw unsupportedContent(content.type);
|
|
632
833
|
}
|
|
633
834
|
};
|
|
835
|
+
var send2 = async (clients, spaceId, content) => {
|
|
836
|
+
const remote = clients[0];
|
|
837
|
+
if (!remote) {
|
|
838
|
+
throw new Error("No remote iMessage client available");
|
|
839
|
+
}
|
|
840
|
+
const chat = chatGuid(spaceId);
|
|
841
|
+
if (content.type === "group") {
|
|
842
|
+
for (const sub of content.items) {
|
|
843
|
+
const itemType = sub.content.type;
|
|
844
|
+
if (!GROUP_ITEM_ALLOWED.has(itemType)) {
|
|
845
|
+
throw unsupportedContent(
|
|
846
|
+
"group",
|
|
847
|
+
`"${itemType}" items are not supported inside a group`
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
const groupMembers = [];
|
|
852
|
+
for (const sub of content.items) {
|
|
853
|
+
groupMembers.push(await sendSingle(remote, chat, sub.content));
|
|
854
|
+
}
|
|
855
|
+
const first = groupMembers[0];
|
|
856
|
+
if (!first) {
|
|
857
|
+
throw new Error("Empty group");
|
|
858
|
+
}
|
|
859
|
+
return { ...first, groupMembers };
|
|
860
|
+
}
|
|
861
|
+
return sendSingle(remote, chat, content);
|
|
862
|
+
};
|
|
634
863
|
var replyToMessage = async (clients, spaceId, msgId, content) => {
|
|
635
864
|
const remote = clients[0];
|
|
636
865
|
if (!remote) {
|
|
@@ -709,18 +938,56 @@ var editMessage = async (clients, spaceId, msgId, content) => {
|
|
|
709
938
|
content.text
|
|
710
939
|
);
|
|
711
940
|
};
|
|
712
|
-
var reactToMessage = async (clients, spaceId,
|
|
941
|
+
var reactToMessage = async (clients, spaceId, target, reaction) => {
|
|
713
942
|
const remote = clients[0];
|
|
714
943
|
if (!remote) {
|
|
715
944
|
return;
|
|
716
945
|
}
|
|
717
946
|
const chat = chatGuid(spaceId);
|
|
718
|
-
const
|
|
947
|
+
const parentGuid = target.parentId ?? target.id;
|
|
948
|
+
const guid = messageGuid(parentGuid);
|
|
949
|
+
const opts = typeof target.partIndex === "number" ? { partIndex: target.partIndex } : void 0;
|
|
719
950
|
const native = EMOJI_TO_TAPBACK[reaction];
|
|
720
951
|
if (native) {
|
|
721
|
-
await remote.messages.react(chat,
|
|
952
|
+
await remote.messages.react(chat, guid, native, opts);
|
|
722
953
|
} else {
|
|
723
|
-
await remote.messages.reactEmoji(chat,
|
|
954
|
+
await remote.messages.reactEmoji(chat, guid, reaction, opts);
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
var getMessage2 = async (clients, spaceId, msgId) => {
|
|
958
|
+
const remote = clients[0];
|
|
959
|
+
if (!remote) {
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
const cache = getMessageCache(remote);
|
|
963
|
+
const cached = cache.get(msgId);
|
|
964
|
+
if (cached) {
|
|
965
|
+
return cached;
|
|
966
|
+
}
|
|
967
|
+
const childRef = parseChildId(msgId);
|
|
968
|
+
if (childRef) {
|
|
969
|
+
try {
|
|
970
|
+
const fetched = await remote.messages.get(
|
|
971
|
+
messageGuid(childRef.parentGuid)
|
|
972
|
+
);
|
|
973
|
+
const parent = await rebuildFromAppleMessage(remote, fetched, spaceId);
|
|
974
|
+
cacheMessage(cache, parent);
|
|
975
|
+
if (parent.content.type !== "group") {
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const items = parent.content.items;
|
|
979
|
+
return items[childRef.partIndex];
|
|
980
|
+
} catch {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
try {
|
|
985
|
+
const fetched = await remote.messages.get(messageGuid(msgId));
|
|
986
|
+
const rebuilt = await rebuildFromAppleMessage(remote, fetched, spaceId);
|
|
987
|
+
cacheMessage(cache, rebuilt);
|
|
988
|
+
return rebuilt;
|
|
989
|
+
} catch {
|
|
990
|
+
return;
|
|
724
991
|
}
|
|
725
992
|
};
|
|
726
993
|
|
|
@@ -741,6 +1008,10 @@ var spaceSchema = z.object({
|
|
|
741
1008
|
id: z.string(),
|
|
742
1009
|
type: z.enum(["dm", "group"])
|
|
743
1010
|
});
|
|
1011
|
+
var messageSchema = z.object({
|
|
1012
|
+
partIndex: z.number().int().nonnegative().optional(),
|
|
1013
|
+
parentId: z.string().optional()
|
|
1014
|
+
});
|
|
744
1015
|
|
|
745
1016
|
// src/providers/imessage/index.ts
|
|
746
1017
|
var imessage = definePlatform("iMessage", {
|
|
@@ -776,6 +1047,9 @@ var imessage = definePlatform("iMessage", {
|
|
|
776
1047
|
return { id: chat.guid, type: "group" };
|
|
777
1048
|
}
|
|
778
1049
|
},
|
|
1050
|
+
message: {
|
|
1051
|
+
schema: messageSchema
|
|
1052
|
+
},
|
|
779
1053
|
lifecycle: {
|
|
780
1054
|
createClient: async ({
|
|
781
1055
|
config,
|
|
@@ -829,11 +1103,16 @@ var imessage = definePlatform("iMessage", {
|
|
|
829
1103
|
}
|
|
830
1104
|
await stopTyping(client, space.id);
|
|
831
1105
|
},
|
|
832
|
-
reactToMessage: async ({ space,
|
|
1106
|
+
reactToMessage: async ({ space, target, reaction, client }) => {
|
|
833
1107
|
if (isLocal(client)) {
|
|
834
1108
|
throw UnsupportedError.action("react", "iMessage (local mode)");
|
|
835
1109
|
}
|
|
836
|
-
await reactToMessage(
|
|
1110
|
+
await reactToMessage(
|
|
1111
|
+
client,
|
|
1112
|
+
space.id,
|
|
1113
|
+
target,
|
|
1114
|
+
reaction
|
|
1115
|
+
);
|
|
837
1116
|
},
|
|
838
1117
|
replyToMessage: async ({ space, messageId, content, client }) => {
|
|
839
1118
|
if (isLocal(client)) {
|
|
@@ -846,6 +1125,12 @@ var imessage = definePlatform("iMessage", {
|
|
|
846
1125
|
throw UnsupportedError.action("edit", "iMessage (local mode)");
|
|
847
1126
|
}
|
|
848
1127
|
await editMessage(client, space.id, messageId, content);
|
|
1128
|
+
},
|
|
1129
|
+
getMessage: async ({ space, messageId, client }) => {
|
|
1130
|
+
if (isLocal(client)) {
|
|
1131
|
+
return getMessage(client, messageId);
|
|
1132
|
+
}
|
|
1133
|
+
return getMessage2(client, space.id, messageId);
|
|
849
1134
|
}
|
|
850
1135
|
}
|
|
851
1136
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-
|
|
1
|
+
import { d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-D5KhSXLy.js';
|
|
2
2
|
import * as node_readline from 'node:readline';
|
|
3
3
|
import z__default from 'zod';
|
|
4
4
|
import 'hotscript';
|
|
@@ -2,7 +2,7 @@ import { M as ManagedStream } from '../../stream-B55k7W8-.js';
|
|
|
2
2
|
import { WhatsAppClient } from '@photon-ai/whatsapp-business';
|
|
3
3
|
import * as z from 'zod';
|
|
4
4
|
import z__default from 'zod';
|
|
5
|
-
import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-
|
|
5
|
+
import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-D5KhSXLy.js';
|
|
6
6
|
import * as zod_v4_core from 'zod/v4/core';
|
|
7
7
|
import 'hotscript';
|
|
8
8
|
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
cloud,
|
|
7
7
|
mergeStreams,
|
|
8
8
|
stream
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-OIXH5S65.js";
|
|
10
10
|
import {
|
|
11
11
|
UnsupportedError,
|
|
12
12
|
asText,
|
|
13
13
|
definePlatform
|
|
14
|
-
} from "../../chunk-
|
|
14
|
+
} from "../../chunk-U6WCQVVX.js";
|
|
15
15
|
|
|
16
16
|
// src/providers/whatsapp-business/index.ts
|
|
17
17
|
import { createClient as createClient2 } from "@photon-ai/whatsapp-business";
|
|
@@ -401,11 +401,16 @@ var mapContent = (client, content) => {
|
|
|
401
401
|
return asCustom({ whatsapp_type: "sticker", ...content.sticker });
|
|
402
402
|
case "location":
|
|
403
403
|
return asCustom({ whatsapp_type: "location", ...content.location });
|
|
404
|
-
case "reaction":
|
|
404
|
+
case "reaction": {
|
|
405
|
+
const stubTarget = {
|
|
406
|
+
id: content.reaction.messageId,
|
|
407
|
+
content: asCustom({ whatsapp_type: "reaction-target", stub: true })
|
|
408
|
+
};
|
|
405
409
|
return asReaction({
|
|
406
410
|
emoji: content.reaction.emoji,
|
|
407
|
-
target:
|
|
411
|
+
target: stubTarget
|
|
408
412
|
});
|
|
413
|
+
}
|
|
409
414
|
case "interactive":
|
|
410
415
|
return asCustom({ whatsapp_type: "interactive", ...content.interactive });
|
|
411
416
|
case "button":
|
|
@@ -723,11 +728,11 @@ var whatsappBusiness = definePlatform("WhatsApp Business", {
|
|
|
723
728
|
send: async ({ space, content, client }) => {
|
|
724
729
|
return await send(client, space.id, content);
|
|
725
730
|
},
|
|
726
|
-
reactToMessage: async ({ space,
|
|
731
|
+
reactToMessage: async ({ space, target, reaction, client }) => {
|
|
727
732
|
await reactToMessage(
|
|
728
733
|
client,
|
|
729
734
|
space.id,
|
|
730
|
-
|
|
735
|
+
target.id,
|
|
731
736
|
reaction
|
|
732
737
|
);
|
|
733
738
|
},
|
|
@@ -91,7 +91,10 @@ declare const contentSchema: z__default.ZodDiscriminatedUnion<[z__default.ZodObj
|
|
|
91
91
|
}, z__default.core.$strip>, z__default.ZodObject<{
|
|
92
92
|
type: z__default.ZodLiteral<"reaction">;
|
|
93
93
|
emoji: z__default.ZodString;
|
|
94
|
-
target: z__default.
|
|
94
|
+
target: z__default.ZodCustom<Message, Message>;
|
|
95
|
+
}, z__default.core.$strip>, z__default.ZodObject<{
|
|
96
|
+
type: z__default.ZodLiteral<"group">;
|
|
97
|
+
items: z__default.ZodArray<z__default.ZodCustom<Message, Message>>;
|
|
95
98
|
}, z__default.core.$strip>], "type">;
|
|
96
99
|
type Content = z__default.infer<typeof contentSchema>;
|
|
97
100
|
interface ContentBuilder {
|
|
@@ -107,6 +110,13 @@ interface User {
|
|
|
107
110
|
interface Space<_Def = unknown> {
|
|
108
111
|
readonly __platform: string;
|
|
109
112
|
edit(message: OutboundMessage, newContent: ContentInput): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Look up a message in this space by its id. Returns `undefined` if the
|
|
115
|
+
* platform has no way to resolve the id (e.g. cache miss with no by-id
|
|
116
|
+
* SDK fallback). Used to materialize a `Message` for APIs that require one,
|
|
117
|
+
* such as `reaction()`.
|
|
118
|
+
*/
|
|
119
|
+
getMessage(id: string): Promise<Message | undefined>;
|
|
110
120
|
readonly id: string;
|
|
111
121
|
responding<T>(fn: () => T | Promise<T>): Promise<T>;
|
|
112
122
|
send(content: ContentInput): Promise<OutboundMessage | undefined>;
|
|
@@ -158,6 +168,14 @@ type ProviderMessage<TSender extends ResolvedUser = ResolvedUser, TSpace extends
|
|
|
158
168
|
timestamp?: Date;
|
|
159
169
|
} & TExtra;
|
|
160
170
|
interface SendResult<TSender extends ResolvedUser = ResolvedUser> {
|
|
171
|
+
/**
|
|
172
|
+
* Per-item send receipts returned when the dispatched content was a
|
|
173
|
+
* `group`. Providers that iterate native sends to emulate a group
|
|
174
|
+
* (e.g. iMessage) populate this so the platform build layer can
|
|
175
|
+
* replace the outbound group's placeholder items with real Messages
|
|
176
|
+
* that carry each item's own id.
|
|
177
|
+
*/
|
|
178
|
+
groupMembers?: SendResult<TSender>[];
|
|
161
179
|
id: string;
|
|
162
180
|
sender?: TSender;
|
|
163
181
|
timestamp?: Date;
|
|
@@ -190,7 +208,7 @@ interface PlatformDef<_Name extends string = string, _ConfigSchema extends z__de
|
|
|
190
208
|
}) => Promise<void>;
|
|
191
209
|
reactToMessage?: (_: {
|
|
192
210
|
space: _ResolvedSpace & SpaceRef;
|
|
193
|
-
|
|
211
|
+
target: _MessageType;
|
|
194
212
|
reaction: string;
|
|
195
213
|
client: _Client;
|
|
196
214
|
config: z__default.infer<_ConfigSchema>;
|
|
@@ -209,6 +227,12 @@ interface PlatformDef<_Name extends string = string, _ConfigSchema extends z__de
|
|
|
209
227
|
client: _Client;
|
|
210
228
|
config: z__default.infer<_ConfigSchema>;
|
|
211
229
|
}) => Promise<void>;
|
|
230
|
+
getMessage?: (_: {
|
|
231
|
+
space: _ResolvedSpace & SpaceRef;
|
|
232
|
+
messageId: string;
|
|
233
|
+
client: _Client;
|
|
234
|
+
config: z__default.infer<_ConfigSchema>;
|
|
235
|
+
}) => Promise<_MessageType | undefined>;
|
|
212
236
|
};
|
|
213
237
|
config: _ConfigSchema;
|
|
214
238
|
events: _Events;
|
|
@@ -259,6 +283,7 @@ interface AnyPlatformDef {
|
|
|
259
283
|
reactToMessage?: (_: any) => Promise<void>;
|
|
260
284
|
replyToMessage?: (_: any) => Promise<SendResult>;
|
|
261
285
|
editMessage?: (_: any) => Promise<void>;
|
|
286
|
+
getMessage?: (_: any) => Promise<any>;
|
|
262
287
|
};
|
|
263
288
|
config: z__default.ZodType<object>;
|
|
264
289
|
events: {
|