spectrum-ts 0.6.1 → 0.7.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-XZTTLPHE.js → chunk-6URE4AYH.js} +136 -24
- package/dist/{chunk-UZWRB3FZ.js → chunk-GX3JCGSD.js} +70 -1
- package/dist/index.d.ts +30 -4
- package/dist/index.js +5 -5
- package/dist/providers/imessage/index.d.ts +1 -1
- package/dist/providers/imessage/index.js +20 -19
- package/dist/providers/terminal/index.d.ts +1 -1
- package/dist/providers/terminal/index.js +3 -4
- package/dist/providers/whatsapp-business/index.d.ts +9 -8
- package/dist/providers/whatsapp-business/index.js +267 -22
- package/dist/{types-DZMHfgYQ.d.ts → types-B5tTx5hc.d.ts} +2 -2
- package/package.json +1 -1
- package/dist/chunk-HXM64ENV.js +0 -67
|
@@ -16,7 +16,78 @@ var resolveContents = (items) => Promise.all(
|
|
|
16
16
|
items.map((c) => typeof c === "string" ? text(c).build() : c.build())
|
|
17
17
|
);
|
|
18
18
|
|
|
19
|
+
// src/utils/errors.ts
|
|
20
|
+
var composeMessage = (opts) => {
|
|
21
|
+
const platform = opts.platform ?? "platform";
|
|
22
|
+
const subject = opts.kind === "content" ? `content type "${opts.contentType ?? "unknown"}"` : `action "${opts.action ?? "unknown"}"`;
|
|
23
|
+
const detail = opts.detail ? `: ${opts.detail}` : "";
|
|
24
|
+
return `${platform} does not support ${subject}${detail}`;
|
|
25
|
+
};
|
|
26
|
+
var UnsupportedError = class _UnsupportedError extends Error {
|
|
27
|
+
kind;
|
|
28
|
+
platform;
|
|
29
|
+
contentType;
|
|
30
|
+
action;
|
|
31
|
+
detail;
|
|
32
|
+
constructor(opts) {
|
|
33
|
+
super(composeMessage(opts));
|
|
34
|
+
this.name = "UnsupportedError";
|
|
35
|
+
this.kind = opts.kind;
|
|
36
|
+
this.platform = opts.platform;
|
|
37
|
+
this.contentType = opts.contentType;
|
|
38
|
+
this.action = opts.action;
|
|
39
|
+
this.detail = opts.detail;
|
|
40
|
+
}
|
|
41
|
+
static content(contentType, platform, detail) {
|
|
42
|
+
return new _UnsupportedError({
|
|
43
|
+
kind: "content",
|
|
44
|
+
contentType,
|
|
45
|
+
platform,
|
|
46
|
+
detail
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
static action(action, platform, detail) {
|
|
50
|
+
return new _UnsupportedError({ kind: "action", action, platform, detail });
|
|
51
|
+
}
|
|
52
|
+
withPlatform(platform) {
|
|
53
|
+
if (this.platform) {
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
return new _UnsupportedError({
|
|
57
|
+
kind: this.kind,
|
|
58
|
+
platform,
|
|
59
|
+
contentType: this.contentType,
|
|
60
|
+
action: this.action,
|
|
61
|
+
detail: this.detail
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
19
66
|
// src/platform/build.ts
|
|
67
|
+
var ANSI_YELLOW = "\x1B[33m";
|
|
68
|
+
var ANSI_RESET = "\x1B[0m";
|
|
69
|
+
var supportsAnsiColor = () => {
|
|
70
|
+
if (typeof process === "undefined") {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (process.env.NO_COLOR) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const force = process.env.FORCE_COLOR;
|
|
77
|
+
if (force !== void 0) {
|
|
78
|
+
return force !== "" && force !== "0" && force !== "false";
|
|
79
|
+
}
|
|
80
|
+
return Boolean(process.stderr?.isTTY);
|
|
81
|
+
};
|
|
82
|
+
var warnUnsupported = (err, fallbackPlatform) => {
|
|
83
|
+
const platform = err.platform ?? fallbackPlatform;
|
|
84
|
+
const subject = err.kind === "content" ? `content type "${err.contentType ?? "unknown"}"` : `action "${err.action ?? "unknown"}"`;
|
|
85
|
+
const detail = err.detail ? `: ${err.detail}` : "";
|
|
86
|
+
const body = `[spectrum-ts] ${platform} does not support ${subject}${detail}; skipping.`;
|
|
87
|
+
console.warn(
|
|
88
|
+
supportsAnsiColor() ? `${ANSI_YELLOW}${body}${ANSI_RESET}` : body
|
|
89
|
+
);
|
|
90
|
+
};
|
|
20
91
|
function buildSpace(params) {
|
|
21
92
|
const { spaceRef, extras, typingCtx, definition, client, config } = params;
|
|
22
93
|
let space;
|
|
@@ -24,10 +95,19 @@ function buildSpace(params) {
|
|
|
24
95
|
const resolved = await resolveContents(content);
|
|
25
96
|
const results = [];
|
|
26
97
|
for (const item of resolved) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
98
|
+
let sendResult;
|
|
99
|
+
try {
|
|
100
|
+
sendResult = await definition.actions.send({
|
|
101
|
+
...typingCtx,
|
|
102
|
+
content: item
|
|
103
|
+
});
|
|
104
|
+
} catch (err) {
|
|
105
|
+
if (err instanceof UnsupportedError) {
|
|
106
|
+
warnUnsupported(err, definition.name);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
31
111
|
if (!sendResult?.id) {
|
|
32
112
|
throw new Error(
|
|
33
113
|
`Platform "${definition.name}" send did not return a message id`
|
|
@@ -49,7 +129,10 @@ function buildSpace(params) {
|
|
|
49
129
|
})
|
|
50
130
|
);
|
|
51
131
|
}
|
|
52
|
-
|
|
132
|
+
if (content.length === 1) {
|
|
133
|
+
return results[0];
|
|
134
|
+
}
|
|
135
|
+
return results;
|
|
53
136
|
}
|
|
54
137
|
space = {
|
|
55
138
|
...extras,
|
|
@@ -80,6 +163,10 @@ function buildMessage(params) {
|
|
|
80
163
|
const { definition, client, config, spaceRef, space } = params;
|
|
81
164
|
const react = async (reaction) => {
|
|
82
165
|
if (!definition.actions.reactToMessage) {
|
|
166
|
+
warnUnsupported(
|
|
167
|
+
UnsupportedError.action("react", definition.name),
|
|
168
|
+
definition.name
|
|
169
|
+
);
|
|
83
170
|
return;
|
|
84
171
|
}
|
|
85
172
|
await definition.actions.reactToMessage({
|
|
@@ -92,20 +179,31 @@ function buildMessage(params) {
|
|
|
92
179
|
};
|
|
93
180
|
async function reply(...content) {
|
|
94
181
|
if (!definition.actions.replyToMessage) {
|
|
95
|
-
|
|
96
|
-
|
|
182
|
+
warnUnsupported(
|
|
183
|
+
UnsupportedError.action("reply", definition.name),
|
|
184
|
+
definition.name
|
|
97
185
|
);
|
|
186
|
+
return content.length === 1 ? void 0 : [];
|
|
98
187
|
}
|
|
99
188
|
const resolved = await resolveContents(content);
|
|
100
189
|
const results = [];
|
|
101
190
|
for (const item of resolved) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
191
|
+
let sendResult;
|
|
192
|
+
try {
|
|
193
|
+
sendResult = await definition.actions.replyToMessage({
|
|
194
|
+
space: spaceRef,
|
|
195
|
+
messageId: params.id,
|
|
196
|
+
content: item,
|
|
197
|
+
client,
|
|
198
|
+
config
|
|
199
|
+
});
|
|
200
|
+
} catch (err) {
|
|
201
|
+
if (err instanceof UnsupportedError) {
|
|
202
|
+
warnUnsupported(err, definition.name);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
109
207
|
if (!sendResult?.id) {
|
|
110
208
|
throw new Error(
|
|
111
209
|
`Platform "${definition.name}" reply did not return a message id`
|
|
@@ -127,7 +225,10 @@ function buildMessage(params) {
|
|
|
127
225
|
})
|
|
128
226
|
);
|
|
129
227
|
}
|
|
130
|
-
|
|
228
|
+
if (content.length === 1) {
|
|
229
|
+
return results[0];
|
|
230
|
+
}
|
|
231
|
+
return results;
|
|
131
232
|
}
|
|
132
233
|
const senderWithPlatform = params.sender === void 0 ? void 0 : { ...params.sender, __platform: definition.name };
|
|
133
234
|
if (params.direction === "outbound") {
|
|
@@ -141,21 +242,31 @@ function buildMessage(params) {
|
|
|
141
242
|
reply,
|
|
142
243
|
edit: async (newContent) => {
|
|
143
244
|
if (!definition.actions.editMessage) {
|
|
144
|
-
|
|
145
|
-
|
|
245
|
+
warnUnsupported(
|
|
246
|
+
UnsupportedError.action("edit", definition.name),
|
|
247
|
+
definition.name
|
|
146
248
|
);
|
|
249
|
+
return;
|
|
147
250
|
}
|
|
148
251
|
const [resolved] = await resolveContents([newContent]);
|
|
149
252
|
if (!resolved) {
|
|
150
253
|
return;
|
|
151
254
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
255
|
+
try {
|
|
256
|
+
await definition.actions.editMessage({
|
|
257
|
+
space: spaceRef,
|
|
258
|
+
messageId: params.id,
|
|
259
|
+
content: resolved,
|
|
260
|
+
client,
|
|
261
|
+
config
|
|
262
|
+
});
|
|
263
|
+
} catch (err) {
|
|
264
|
+
if (err instanceof UnsupportedError) {
|
|
265
|
+
warnUnsupported(err, definition.name);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
throw err;
|
|
269
|
+
}
|
|
159
270
|
},
|
|
160
271
|
sender: senderWithPlatform,
|
|
161
272
|
space,
|
|
@@ -335,6 +446,7 @@ export {
|
|
|
335
446
|
asText,
|
|
336
447
|
text,
|
|
337
448
|
resolveContents,
|
|
449
|
+
UnsupportedError,
|
|
338
450
|
buildSpace,
|
|
339
451
|
buildMessage,
|
|
340
452
|
definePlatform
|
|
@@ -607,6 +607,73 @@ function mergeStreams(streams) {
|
|
|
607
607
|
});
|
|
608
608
|
}
|
|
609
609
|
|
|
610
|
+
// src/utils/cloud.ts
|
|
611
|
+
var SPECTRUM_CLOUD_URL = `https://${process.env.SPECTRUM_CLOUD_URL ?? "spectrum.photon.codes"}`;
|
|
612
|
+
var SpectrumCloudError = class extends Error {
|
|
613
|
+
status;
|
|
614
|
+
code;
|
|
615
|
+
constructor(status, code, message) {
|
|
616
|
+
super(message);
|
|
617
|
+
this.name = "SpectrumCloudError";
|
|
618
|
+
this.status = status;
|
|
619
|
+
this.code = code;
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
var request = async (path, init) => {
|
|
623
|
+
const response = await fetch(`${SPECTRUM_CLOUD_URL}${path}`, init);
|
|
624
|
+
if (!response.ok) {
|
|
625
|
+
const body = await response.text().catch(() => "");
|
|
626
|
+
try {
|
|
627
|
+
const parsed = JSON.parse(body);
|
|
628
|
+
throw new SpectrumCloudError(
|
|
629
|
+
response.status,
|
|
630
|
+
parsed.code,
|
|
631
|
+
parsed.message
|
|
632
|
+
);
|
|
633
|
+
} catch (error) {
|
|
634
|
+
if (error instanceof SpectrumCloudError) {
|
|
635
|
+
throw error;
|
|
636
|
+
}
|
|
637
|
+
throw new SpectrumCloudError(
|
|
638
|
+
response.status,
|
|
639
|
+
"UNKNOWN",
|
|
640
|
+
body || response.statusText
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
const json = await response.json();
|
|
645
|
+
if (!json.succeed) {
|
|
646
|
+
throw new SpectrumCloudError(
|
|
647
|
+
response.status,
|
|
648
|
+
"UNKNOWN",
|
|
649
|
+
"Server returned succeed=false"
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
return json.data;
|
|
653
|
+
};
|
|
654
|
+
var basicAuth = (projectId, projectSecret) => `Basic ${btoa(`${projectId}:${projectSecret}`)}`;
|
|
655
|
+
var cloud = {
|
|
656
|
+
getSubscription: (projectId) => request(`/projects/${projectId}/billing/subscription`),
|
|
657
|
+
issueImessageTokens: (projectId, projectSecret) => request(`/projects/${projectId}/imessage/tokens`, {
|
|
658
|
+
method: "POST",
|
|
659
|
+
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
660
|
+
}),
|
|
661
|
+
getImessageInfo: (projectId) => request(`/projects/${projectId}/imessage/`),
|
|
662
|
+
issueWhatsappBusinessTokens: (projectId, projectSecret) => request(`/projects/${projectId}/whatsapp-business/tokens`, {
|
|
663
|
+
method: "POST",
|
|
664
|
+
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
665
|
+
}),
|
|
666
|
+
getPlatforms: (projectId) => request(`/projects/${projectId}/platforms/`),
|
|
667
|
+
togglePlatform: (projectId, projectSecret, platform, enabled) => request(`/projects/${projectId}/platforms/`, {
|
|
668
|
+
method: "PATCH",
|
|
669
|
+
headers: {
|
|
670
|
+
Authorization: basicAuth(projectId, projectSecret),
|
|
671
|
+
"Content-Type": "application/json"
|
|
672
|
+
},
|
|
673
|
+
body: JSON.stringify({ platform, enabled })
|
|
674
|
+
})
|
|
675
|
+
};
|
|
676
|
+
|
|
610
677
|
export {
|
|
611
678
|
readSchema,
|
|
612
679
|
streamSchema,
|
|
@@ -620,5 +687,7 @@ export {
|
|
|
620
687
|
asCustom,
|
|
621
688
|
custom,
|
|
622
689
|
stream,
|
|
623
|
-
mergeStreams
|
|
690
|
+
mergeStreams,
|
|
691
|
+
SpectrumCloudError,
|
|
692
|
+
cloud
|
|
624
693
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ContentBuilder, U as User, a as ContentInput, b as Content, P as ProviderMessage, c as PlatformDef, d as Platform, e as PlatformProviderConfig, S as SpectrumLike, f as CustomEventStreams, g as Space, I as InboundMessage, O as OutboundMessage } from './types-
|
|
2
|
-
export { A as AnyPlatformDef, E as EventProducer, M as Message, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage } from './types-
|
|
1
|
+
import { C as ContentBuilder, U as User, a as ContentInput, b as Content, P as ProviderMessage, c as PlatformDef, d as Platform, e as PlatformProviderConfig, S as SpectrumLike, f as CustomEventStreams, g as Space, I as InboundMessage, O as OutboundMessage } from './types-B5tTx5hc.js';
|
|
2
|
+
export { A as AnyPlatformDef, E as EventProducer, M as Message, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage } from './types-B5tTx5hc.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-DGy4geUK.js';
|
|
@@ -163,7 +163,7 @@ declare function definePlatform<_Name extends string, _ConfigSchema extends z__d
|
|
|
163
163
|
type SpectrumInstance<Providers extends PlatformProviderConfig[] = PlatformProviderConfig[]> = SpectrumLike<Providers> & CustomEventStreams<Providers> & {
|
|
164
164
|
readonly messages: AsyncIterable<[Space, InboundMessage]>;
|
|
165
165
|
stop(): Promise<void>;
|
|
166
|
-
send(space: Space, content: ContentInput): Promise<OutboundMessage>;
|
|
166
|
+
send(space: Space, content: ContentInput): Promise<OutboundMessage | undefined>;
|
|
167
167
|
send(space: Space, ...content: [ContentInput, ContentInput, ...ContentInput[]]): Promise<OutboundMessage[]>;
|
|
168
168
|
edit(message: OutboundMessage, newContent: ContentInput): Promise<void>;
|
|
169
169
|
responding<T>(space: Space, fn: () => T | Promise<T>): Promise<T>;
|
|
@@ -202,6 +202,11 @@ type PlatformsData = Record<CloudPlatform, PlatformStatus>;
|
|
|
202
202
|
interface ImessageInfoData {
|
|
203
203
|
type: "shared" | "dedicated";
|
|
204
204
|
}
|
|
205
|
+
interface WhatsappBusinessTokenData {
|
|
206
|
+
auth: Record<string, string>;
|
|
207
|
+
expiresIn: number;
|
|
208
|
+
numbers: Record<string, string | null>;
|
|
209
|
+
}
|
|
205
210
|
declare class SpectrumCloudError extends Error {
|
|
206
211
|
readonly status: number;
|
|
207
212
|
readonly code: string;
|
|
@@ -211,11 +216,32 @@ declare const cloud: {
|
|
|
211
216
|
getSubscription: (projectId: string) => Promise<SubscriptionData>;
|
|
212
217
|
issueImessageTokens: (projectId: string, projectSecret: string) => Promise<TokenData>;
|
|
213
218
|
getImessageInfo: (projectId: string) => Promise<ImessageInfoData>;
|
|
219
|
+
issueWhatsappBusinessTokens: (projectId: string, projectSecret: string) => Promise<WhatsappBusinessTokenData>;
|
|
214
220
|
getPlatforms: (projectId: string) => Promise<PlatformsData>;
|
|
215
221
|
togglePlatform: (projectId: string, projectSecret: string, platform: CloudPlatform, enabled: boolean) => Promise<PlatformsData>;
|
|
216
222
|
};
|
|
217
223
|
|
|
224
|
+
type UnsupportedKind = "content" | "action";
|
|
225
|
+
interface UnsupportedErrorOptions {
|
|
226
|
+
action?: string;
|
|
227
|
+
contentType?: string;
|
|
228
|
+
detail?: string;
|
|
229
|
+
kind: UnsupportedKind;
|
|
230
|
+
platform?: string;
|
|
231
|
+
}
|
|
232
|
+
declare class UnsupportedError extends Error {
|
|
233
|
+
readonly kind: UnsupportedKind;
|
|
234
|
+
readonly platform?: string;
|
|
235
|
+
readonly contentType?: string;
|
|
236
|
+
readonly action?: string;
|
|
237
|
+
readonly detail?: string;
|
|
238
|
+
constructor(opts: UnsupportedErrorOptions);
|
|
239
|
+
static content(contentType: string, platform?: string, detail?: string): UnsupportedError;
|
|
240
|
+
static action(action: string, platform?: string, detail?: string): UnsupportedError;
|
|
241
|
+
withPlatform(platform: string): UnsupportedError;
|
|
242
|
+
}
|
|
243
|
+
|
|
218
244
|
declare const fromVCard: (vcf: string) => ContactInput;
|
|
219
245
|
declare const toVCard: (contact: Contact) => Promise<string>;
|
|
220
246
|
|
|
221
|
-
export { type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, Content, ContentBuilder, ContentInput, type DedicatedTokenData, type ImessageInfoData, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, type SharedTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, User, type Voice, attachment, cloud, contact, custom, definePlatform, fromVCard, resolveContents, text, toVCard, voice };
|
|
247
|
+
export { type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, Content, ContentBuilder, ContentInput, type DedicatedTokenData, type ImessageInfoData, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, type SharedTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, UnsupportedError, type UnsupportedKind, User, type Voice, attachment, cloud, contact, custom, definePlatform, fromVCard, resolveContents, text, toVCard, voice };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SpectrumCloudError,
|
|
3
|
-
cloud
|
|
4
|
-
} from "./chunk-HXM64ENV.js";
|
|
5
|
-
import {
|
|
6
3
|
attachment,
|
|
7
4
|
bufferToStream,
|
|
5
|
+
cloud,
|
|
8
6
|
contact,
|
|
9
7
|
custom,
|
|
10
8
|
fromVCard,
|
|
@@ -13,14 +11,15 @@ import {
|
|
|
13
11
|
stream,
|
|
14
12
|
streamSchema,
|
|
15
13
|
toVCard
|
|
16
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-GX3JCGSD.js";
|
|
17
15
|
import {
|
|
16
|
+
UnsupportedError,
|
|
18
17
|
buildMessage,
|
|
19
18
|
buildSpace,
|
|
20
19
|
definePlatform,
|
|
21
20
|
resolveContents,
|
|
22
21
|
text
|
|
23
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-6URE4AYH.js";
|
|
24
23
|
|
|
25
24
|
// src/content/voice.ts
|
|
26
25
|
import { createReadStream } from "fs";
|
|
@@ -367,6 +366,7 @@ async function Spectrum(options) {
|
|
|
367
366
|
export {
|
|
368
367
|
Spectrum,
|
|
369
368
|
SpectrumCloudError,
|
|
369
|
+
UnsupportedError,
|
|
370
370
|
attachment,
|
|
371
371
|
cloud,
|
|
372
372
|
contact,
|
|
@@ -3,7 +3,7 @@ import { AdvancedIMessage } from '@photon-ai/advanced-imessage';
|
|
|
3
3
|
import { IMessageSDK } from '@photon-ai/imessage-kit';
|
|
4
4
|
import * as z from 'zod';
|
|
5
5
|
import z__default from 'zod';
|
|
6
|
-
import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-
|
|
6
|
+
import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-B5tTx5hc.js';
|
|
7
7
|
import * as zod_v4_core from 'zod/v4/core';
|
|
8
8
|
import 'hotscript';
|
|
9
9
|
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
cloud
|
|
3
|
-
} from "../../chunk-HXM64ENV.js";
|
|
4
1
|
import {
|
|
5
2
|
asAttachment,
|
|
6
3
|
asContact,
|
|
7
4
|
asCustom,
|
|
5
|
+
cloud,
|
|
8
6
|
fromVCard,
|
|
9
7
|
mergeStreams,
|
|
10
8
|
stream,
|
|
11
9
|
toVCard
|
|
12
|
-
} from "../../chunk-
|
|
10
|
+
} from "../../chunk-GX3JCGSD.js";
|
|
13
11
|
import {
|
|
12
|
+
UnsupportedError,
|
|
14
13
|
asText,
|
|
15
14
|
definePlatform
|
|
16
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-6URE4AYH.js";
|
|
17
16
|
|
|
18
17
|
// src/providers/imessage/index.ts
|
|
19
18
|
import { createClient as createClient2, directChat } from "@photon-ai/advanced-imessage";
|
|
@@ -243,9 +242,7 @@ var send = async (client, spaceId, content) => {
|
|
|
243
242
|
return synthSendResult();
|
|
244
243
|
}
|
|
245
244
|
default:
|
|
246
|
-
throw
|
|
247
|
-
`Unsupported iMessage local content type: ${content.type}`
|
|
248
|
-
);
|
|
245
|
+
throw UnsupportedError.content(content.type, "iMessage (local mode)");
|
|
249
246
|
}
|
|
250
247
|
};
|
|
251
248
|
|
|
@@ -380,6 +377,8 @@ var ensureM4a = async (buffer, mimeType) => {
|
|
|
380
377
|
};
|
|
381
378
|
|
|
382
379
|
// src/providers/imessage/remote.ts
|
|
380
|
+
var PLATFORM = "iMessage";
|
|
381
|
+
var unsupportedContent = (type) => UnsupportedError.content(type, PLATFORM);
|
|
383
382
|
var toSendResult = (receipt) => ({
|
|
384
383
|
id: receipt.guid,
|
|
385
384
|
timestamp: /* @__PURE__ */ new Date()
|
|
@@ -537,7 +536,7 @@ var send2 = async (clients, spaceId, content) => {
|
|
|
537
536
|
);
|
|
538
537
|
}
|
|
539
538
|
default:
|
|
540
|
-
throw
|
|
539
|
+
throw unsupportedContent(content.type);
|
|
541
540
|
}
|
|
542
541
|
};
|
|
543
542
|
var replyToMessage = async (clients, spaceId, msgId, content) => {
|
|
@@ -590,12 +589,16 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
|
|
|
590
589
|
);
|
|
591
590
|
}
|
|
592
591
|
default:
|
|
593
|
-
throw
|
|
592
|
+
throw unsupportedContent(content.type);
|
|
594
593
|
}
|
|
595
594
|
};
|
|
596
595
|
var editMessage = async (clients, spaceId, msgId, content) => {
|
|
597
596
|
if (content.type !== "text") {
|
|
598
|
-
throw
|
|
597
|
+
throw UnsupportedError.content(
|
|
598
|
+
content.type,
|
|
599
|
+
PLATFORM,
|
|
600
|
+
"only text content can be edited"
|
|
601
|
+
);
|
|
599
602
|
}
|
|
600
603
|
const remote = clients[0];
|
|
601
604
|
if (!remote) {
|
|
@@ -659,8 +662,10 @@ var imessage = definePlatform("iMessage", {
|
|
|
659
662
|
schema: spaceSchema,
|
|
660
663
|
resolve: async ({ input, client }) => {
|
|
661
664
|
if (isLocal(client)) {
|
|
662
|
-
throw
|
|
663
|
-
"
|
|
665
|
+
throw UnsupportedError.action(
|
|
666
|
+
"createSpace",
|
|
667
|
+
"iMessage (local mode)",
|
|
668
|
+
"local mode only supports replying to existing messages"
|
|
664
669
|
);
|
|
665
670
|
}
|
|
666
671
|
if (input.users.length === 0) {
|
|
@@ -742,17 +747,13 @@ var imessage = definePlatform("iMessage", {
|
|
|
742
747
|
},
|
|
743
748
|
replyToMessage: async ({ space, messageId, content, client }) => {
|
|
744
749
|
if (isLocal(client)) {
|
|
745
|
-
throw
|
|
746
|
-
"iMessage local mode does not support replying to messages"
|
|
747
|
-
);
|
|
750
|
+
throw UnsupportedError.action("reply", "iMessage (local mode)");
|
|
748
751
|
}
|
|
749
752
|
return await replyToMessage(client, space.id, messageId, content);
|
|
750
753
|
},
|
|
751
754
|
editMessage: async ({ space, messageId, content, client }) => {
|
|
752
755
|
if (isLocal(client)) {
|
|
753
|
-
throw
|
|
754
|
-
"iMessage local mode does not support editing messages"
|
|
755
|
-
);
|
|
756
|
+
throw UnsupportedError.action("edit", "iMessage (local mode)");
|
|
756
757
|
}
|
|
757
758
|
await editMessage(client, space.id, messageId, content);
|
|
758
759
|
}
|
|
@@ -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-B5tTx5hc.js';
|
|
2
2
|
import * as node_readline from 'node:readline';
|
|
3
3
|
import z__default from 'zod';
|
|
4
4
|
import 'hotscript';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
UnsupportedError,
|
|
2
3
|
definePlatform
|
|
3
|
-
} from "../../chunk-
|
|
4
|
+
} from "../../chunk-6URE4AYH.js";
|
|
4
5
|
|
|
5
6
|
// src/providers/terminal/index.ts
|
|
6
7
|
import { createInterface } from "readline";
|
|
@@ -50,9 +51,7 @@ var terminal = definePlatform("terminal", {
|
|
|
50
51
|
actions: {
|
|
51
52
|
send: async ({ content }) => {
|
|
52
53
|
if (content.type !== "text") {
|
|
53
|
-
throw
|
|
54
|
-
`Terminal provider only supports text content, got "${content.type}"`
|
|
55
|
-
);
|
|
54
|
+
throw UnsupportedError.content(content.type, "terminal");
|
|
56
55
|
}
|
|
57
56
|
console.log(content.text);
|
|
58
57
|
return { id: crypto.randomUUID(), timestamp: /* @__PURE__ */ new Date() };
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import { M as ManagedStream } from '../../stream-DGy4geUK.js';
|
|
2
|
+
import { WhatsAppClient } from '@photon-ai/whatsapp-business';
|
|
2
3
|
import * as z from 'zod';
|
|
3
4
|
import z__default from 'zod';
|
|
4
|
-
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-B5tTx5hc.js';
|
|
5
6
|
import * as zod_v4_core from 'zod/v4/core';
|
|
6
|
-
import { WhatsAppClient } from '@photon-ai/whatsapp-business';
|
|
7
7
|
import 'hotscript';
|
|
8
8
|
|
|
9
|
+
type WhatsAppClients = WhatsAppClient[];
|
|
9
10
|
declare const userSchema: z__default.ZodObject<{}, z__default.core.$strip>;
|
|
10
11
|
declare const spaceSchema: z__default.ZodObject<{
|
|
11
12
|
id: z__default.ZodString;
|
|
12
13
|
}, z__default.core.$strip>;
|
|
13
14
|
type WhatsAppMessage = SchemaMessage<typeof userSchema, typeof spaceSchema>;
|
|
14
15
|
|
|
15
|
-
declare const whatsappBusiness: Platform<PlatformDef<"WhatsApp Business", z.ZodObject<{
|
|
16
|
+
declare const whatsappBusiness: Platform<PlatformDef<"WhatsApp Business", z.ZodUnion<readonly [z.ZodObject<{
|
|
16
17
|
accessToken: z.ZodString;
|
|
17
|
-
phoneNumberId: z.ZodString;
|
|
18
18
|
appSecret: z.ZodOptional<z.ZodString>;
|
|
19
|
-
|
|
19
|
+
phoneNumberId: z.ZodString;
|
|
20
|
+
}, zod_v4_core.$strip>, z.ZodObject<{}, zod_v4_core.$strict>]>, z.ZodType<object, unknown, zod_v4_core.$ZodTypeInternals<object, unknown>> | undefined, z.ZodObject<{
|
|
20
21
|
id: z.ZodString;
|
|
21
|
-
}, zod_v4_core.$strip>, z.ZodType<object, unknown, zod_v4_core.$ZodTypeInternals<object, unknown>> | undefined,
|
|
22
|
+
}, zod_v4_core.$strip>, z.ZodType<object, unknown, zod_v4_core.$ZodTypeInternals<object, unknown>> | undefined, WhatsAppClients, {
|
|
22
23
|
id: string;
|
|
23
24
|
}, {
|
|
24
25
|
id: string;
|
|
@@ -28,12 +29,12 @@ declare const whatsappBusiness: Platform<PlatformDef<"WhatsApp Business", z.ZodO
|
|
|
28
29
|
id: string;
|
|
29
30
|
}, Record<never, never>>, {
|
|
30
31
|
messages: ({ client }: {
|
|
31
|
-
client:
|
|
32
|
+
client: WhatsAppClients;
|
|
32
33
|
config: {
|
|
33
34
|
accessToken: string;
|
|
34
35
|
phoneNumberId: string;
|
|
35
36
|
appSecret?: string | undefined;
|
|
36
|
-
}
|
|
37
|
+
} | Record<string, never>;
|
|
37
38
|
}) => ManagedStream<WhatsAppMessage>;
|
|
38
39
|
}>> & Readonly<Record<never, never>>;
|
|
39
40
|
|
|
@@ -2,20 +2,242 @@ import {
|
|
|
2
2
|
asAttachment,
|
|
3
3
|
asContact,
|
|
4
4
|
asCustom,
|
|
5
|
+
cloud,
|
|
6
|
+
mergeStreams,
|
|
5
7
|
stream
|
|
6
|
-
} from "../../chunk-
|
|
8
|
+
} from "../../chunk-GX3JCGSD.js";
|
|
7
9
|
import {
|
|
10
|
+
UnsupportedError,
|
|
8
11
|
asText,
|
|
9
12
|
definePlatform
|
|
10
|
-
} from "../../chunk-
|
|
13
|
+
} from "../../chunk-6URE4AYH.js";
|
|
11
14
|
|
|
12
15
|
// src/providers/whatsapp-business/index.ts
|
|
16
|
+
import { createClient as createClient2 } from "@photon-ai/whatsapp-business";
|
|
17
|
+
|
|
18
|
+
// src/providers/whatsapp-business/auth.ts
|
|
13
19
|
import {
|
|
14
|
-
createClient
|
|
20
|
+
createClient,
|
|
21
|
+
TypedEventStream
|
|
15
22
|
} from "@photon-ai/whatsapp-business";
|
|
23
|
+
var RENEWAL_RATIO = 0.8;
|
|
24
|
+
var EXPIRY_BUFFER_MS = 3e4;
|
|
25
|
+
var RETRY_DELAY_MS = 3e4;
|
|
26
|
+
var RESUBSCRIBE_BACKOFF_MS = 500;
|
|
27
|
+
var cloudAuthState = /* @__PURE__ */ new WeakMap();
|
|
28
|
+
async function createCloudClients(projectId, projectSecret) {
|
|
29
|
+
let tokenData = await cloud.issueWhatsappBusinessTokens(
|
|
30
|
+
projectId,
|
|
31
|
+
projectSecret
|
|
32
|
+
);
|
|
33
|
+
let tokenExpiresAt = Date.now() + tokenData.expiresIn * 1e3;
|
|
34
|
+
let disposed = false;
|
|
35
|
+
let renewalTimer;
|
|
36
|
+
const lines = /* @__PURE__ */ new Map();
|
|
37
|
+
const buildRawClient = (phoneNumberId) => {
|
|
38
|
+
const accessToken = tokenData.auth[phoneNumberId];
|
|
39
|
+
if (!accessToken) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`WhatsApp Business line ${phoneNumberId} missing from token response`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return createClient({ accessToken, appSecret: "", phoneNumberId });
|
|
45
|
+
};
|
|
46
|
+
const refreshTokens = async () => {
|
|
47
|
+
tokenData = await cloud.issueWhatsappBusinessTokens(
|
|
48
|
+
projectId,
|
|
49
|
+
projectSecret
|
|
50
|
+
);
|
|
51
|
+
tokenExpiresAt = Date.now() + tokenData.expiresIn * 1e3;
|
|
52
|
+
for (const [phoneNumberId, state] of lines) {
|
|
53
|
+
if (!tokenData.auth[phoneNumberId]) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const old = state.current;
|
|
57
|
+
state.current = buildRawClient(phoneNumberId);
|
|
58
|
+
for (const sub of state.subscriptions) {
|
|
59
|
+
sub.swap();
|
|
60
|
+
}
|
|
61
|
+
await old.close().catch(() => void 0);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const clearRenewalTimer = () => {
|
|
65
|
+
if (renewalTimer !== void 0) {
|
|
66
|
+
clearTimeout(renewalTimer);
|
|
67
|
+
renewalTimer = void 0;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const scheduleRenewal = () => {
|
|
71
|
+
if (disposed) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
clearRenewalTimer();
|
|
75
|
+
const ttlMs = tokenData.expiresIn * 1e3;
|
|
76
|
+
const renewInMs = Math.max(ttlMs * RENEWAL_RATIO, 5e3);
|
|
77
|
+
renewalTimer = setTimeout(async () => {
|
|
78
|
+
try {
|
|
79
|
+
await refreshTokens();
|
|
80
|
+
scheduleRenewal();
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.warn(
|
|
83
|
+
`[spectrum-ts] WhatsApp Business token refresh failed; retrying in ${RETRY_DELAY_MS}ms.`,
|
|
84
|
+
err
|
|
85
|
+
);
|
|
86
|
+
clearRenewalTimer();
|
|
87
|
+
renewalTimer = setTimeout(() => scheduleRenewal(), RETRY_DELAY_MS);
|
|
88
|
+
renewalTimer?.unref?.();
|
|
89
|
+
}
|
|
90
|
+
}, renewInMs);
|
|
91
|
+
renewalTimer?.unref?.();
|
|
92
|
+
};
|
|
93
|
+
const refreshIfNeeded = async () => {
|
|
94
|
+
if (Date.now() < tokenExpiresAt - EXPIRY_BUFFER_MS) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await refreshTokens();
|
|
98
|
+
scheduleRenewal();
|
|
99
|
+
};
|
|
100
|
+
scheduleRenewal();
|
|
101
|
+
const clients = Object.keys(tokenData.auth).map(
|
|
102
|
+
(phoneNumberId) => {
|
|
103
|
+
const state = {
|
|
104
|
+
current: buildRawClient(phoneNumberId),
|
|
105
|
+
subscriptions: /* @__PURE__ */ new Set()
|
|
106
|
+
};
|
|
107
|
+
lines.set(phoneNumberId, state);
|
|
108
|
+
return buildClientProxy(state, refreshIfNeeded);
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
cloudAuthState.set(clients, {
|
|
112
|
+
dispose: async () => {
|
|
113
|
+
disposed = true;
|
|
114
|
+
clearRenewalTimer();
|
|
115
|
+
for (const state of lines.values()) {
|
|
116
|
+
for (const sub of state.subscriptions) {
|
|
117
|
+
sub.close();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
await Promise.allSettled(
|
|
121
|
+
Array.from(lines.values()).map((s) => s.current.close())
|
|
122
|
+
);
|
|
123
|
+
lines.clear();
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return clients;
|
|
127
|
+
}
|
|
128
|
+
async function disposeCloudAuth(clients) {
|
|
129
|
+
const auth = cloudAuthState.get(clients);
|
|
130
|
+
if (!auth) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
await auth.dispose();
|
|
134
|
+
cloudAuthState.delete(clients);
|
|
135
|
+
}
|
|
136
|
+
var buildClientProxy = (state, refresh) => {
|
|
137
|
+
const forwarder = (pick) => new Proxy({}, {
|
|
138
|
+
get: (_, prop) => {
|
|
139
|
+
return async (...args) => {
|
|
140
|
+
await refresh();
|
|
141
|
+
const target = pick(state.current);
|
|
142
|
+
const fn = target[prop];
|
|
143
|
+
return Reflect.apply(fn, pick(state.current), args);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
const events = {
|
|
148
|
+
fetchMissed: async (opts) => {
|
|
149
|
+
await refresh();
|
|
150
|
+
return state.current.events.fetchMissed(opts);
|
|
151
|
+
},
|
|
152
|
+
subscribe: (options) => resubscribableStream(state, options)
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
events,
|
|
156
|
+
media: forwarder((c) => c.media),
|
|
157
|
+
messages: forwarder((c) => c.messages),
|
|
158
|
+
close: async () => {
|
|
159
|
+
for (const sub of state.subscriptions) {
|
|
160
|
+
sub.close();
|
|
161
|
+
}
|
|
162
|
+
await state.current.close();
|
|
163
|
+
},
|
|
164
|
+
[Symbol.asyncDispose]: async () => {
|
|
165
|
+
for (const sub of state.subscriptions) {
|
|
166
|
+
sub.close();
|
|
167
|
+
}
|
|
168
|
+
await state.current.close();
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
var pumpOnce = async (ctx) => {
|
|
173
|
+
const sub = ctx.getCurrent().events.subscribe(ctx.options);
|
|
174
|
+
ctx.setActive(sub);
|
|
175
|
+
try {
|
|
176
|
+
for await (const event of sub) {
|
|
177
|
+
ctx.emit(event);
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
} catch {
|
|
181
|
+
return false;
|
|
182
|
+
} finally {
|
|
183
|
+
ctx.setActive(void 0);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
var resubscribableStream = (state, options) => {
|
|
187
|
+
let closed = false;
|
|
188
|
+
let active;
|
|
189
|
+
const source = stream((emit, end) => {
|
|
190
|
+
const ctx = {
|
|
191
|
+
emit,
|
|
192
|
+
getCurrent: () => state.current,
|
|
193
|
+
options,
|
|
194
|
+
setActive: (s) => {
|
|
195
|
+
active = s;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
(async () => {
|
|
199
|
+
while (!closed) {
|
|
200
|
+
await pumpOnce(ctx);
|
|
201
|
+
if (!closed) {
|
|
202
|
+
await new Promise((r) => setTimeout(r, RESUBSCRIBE_BACKOFF_MS));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
end();
|
|
206
|
+
})();
|
|
207
|
+
return () => {
|
|
208
|
+
closed = true;
|
|
209
|
+
active?.close().catch(() => void 0);
|
|
210
|
+
active = void 0;
|
|
211
|
+
state.subscriptions.delete(subscription);
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
const subscription = {
|
|
215
|
+
close: () => {
|
|
216
|
+
closed = true;
|
|
217
|
+
active?.close().catch(() => void 0);
|
|
218
|
+
},
|
|
219
|
+
swap: () => {
|
|
220
|
+
active?.close().catch(() => void 0);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
state.subscriptions.add(subscription);
|
|
224
|
+
return new TypedEventStream(source, async () => {
|
|
225
|
+
closed = true;
|
|
226
|
+
active?.close().catch(() => void 0);
|
|
227
|
+
state.subscriptions.delete(subscription);
|
|
228
|
+
await source.close();
|
|
229
|
+
});
|
|
230
|
+
};
|
|
16
231
|
|
|
17
232
|
// src/providers/whatsapp-business/messages.ts
|
|
18
233
|
import { extension as mimeExtension } from "mime-types";
|
|
234
|
+
var primary = (clients) => {
|
|
235
|
+
const client = clients[0];
|
|
236
|
+
if (!client) {
|
|
237
|
+
throw new Error("No WhatsApp Business client available");
|
|
238
|
+
}
|
|
239
|
+
return client;
|
|
240
|
+
};
|
|
19
241
|
var toSendResult = (result) => ({
|
|
20
242
|
id: result.messageId
|
|
21
243
|
});
|
|
@@ -291,7 +513,7 @@ var contactToWa = (contact) => {
|
|
|
291
513
|
};
|
|
292
514
|
return card;
|
|
293
515
|
};
|
|
294
|
-
var
|
|
516
|
+
var clientStream = (client) => {
|
|
295
517
|
const eventStream = client.events.subscribe().filter(
|
|
296
518
|
(e) => e.type === "message"
|
|
297
519
|
);
|
|
@@ -311,7 +533,9 @@ var messages = (client) => {
|
|
|
311
533
|
return () => eventStream.close();
|
|
312
534
|
});
|
|
313
535
|
};
|
|
314
|
-
var
|
|
536
|
+
var messages = (clients) => mergeStreams(clients.map(clientStream));
|
|
537
|
+
var send = async (clients, spaceId, content) => {
|
|
538
|
+
const client = primary(clients);
|
|
315
539
|
switch (content.type) {
|
|
316
540
|
case "text":
|
|
317
541
|
return toSendResult(
|
|
@@ -353,16 +577,17 @@ var send = async (client, spaceId, content) => {
|
|
|
353
577
|
);
|
|
354
578
|
}
|
|
355
579
|
default:
|
|
356
|
-
throw
|
|
580
|
+
throw UnsupportedError.content(content.type);
|
|
357
581
|
}
|
|
358
582
|
};
|
|
359
|
-
var reactToMessage = async (
|
|
360
|
-
await
|
|
583
|
+
var reactToMessage = async (clients, spaceId, messageId, reaction) => {
|
|
584
|
+
await primary(clients).messages.send({
|
|
361
585
|
to: spaceId,
|
|
362
586
|
reaction: { messageId, emoji: reaction }
|
|
363
587
|
});
|
|
364
588
|
};
|
|
365
|
-
var replyToMessage = async (
|
|
589
|
+
var replyToMessage = async (clients, spaceId, messageId, content) => {
|
|
590
|
+
const client = primary(clients);
|
|
366
591
|
switch (content.type) {
|
|
367
592
|
case "text":
|
|
368
593
|
return toSendResult(
|
|
@@ -411,17 +636,20 @@ var replyToMessage = async (client, spaceId, messageId, content) => {
|
|
|
411
636
|
);
|
|
412
637
|
}
|
|
413
638
|
default:
|
|
414
|
-
throw
|
|
639
|
+
throw UnsupportedError.content(content.type);
|
|
415
640
|
}
|
|
416
641
|
};
|
|
417
642
|
|
|
418
643
|
// src/providers/whatsapp-business/types.ts
|
|
419
644
|
import z from "zod";
|
|
420
|
-
var
|
|
645
|
+
var directConfig = z.object({
|
|
421
646
|
accessToken: z.string().min(1),
|
|
422
|
-
|
|
423
|
-
|
|
647
|
+
appSecret: z.string().optional(),
|
|
648
|
+
phoneNumberId: z.string().min(1)
|
|
424
649
|
});
|
|
650
|
+
var cloudConfig = z.object({}).strict();
|
|
651
|
+
var configSchema = z.union([directConfig, cloudConfig]);
|
|
652
|
+
var isCloudConfig = (config) => !("accessToken" in config);
|
|
425
653
|
var userSchema = z.object({});
|
|
426
654
|
var spaceSchema = z.object({
|
|
427
655
|
id: z.string()
|
|
@@ -440,8 +668,10 @@ var whatsappBusiness = definePlatform("WhatsApp Business", {
|
|
|
440
668
|
throw new Error("WhatsApp space creation requires at least one user");
|
|
441
669
|
}
|
|
442
670
|
if (input.users.length > 1) {
|
|
443
|
-
throw
|
|
444
|
-
"
|
|
671
|
+
throw UnsupportedError.action(
|
|
672
|
+
"createSpace",
|
|
673
|
+
"WhatsApp Business",
|
|
674
|
+
"only 1:1 conversations are supported"
|
|
445
675
|
);
|
|
446
676
|
}
|
|
447
677
|
const user = input.users[0];
|
|
@@ -452,15 +682,30 @@ var whatsappBusiness = definePlatform("WhatsApp Business", {
|
|
|
452
682
|
}
|
|
453
683
|
},
|
|
454
684
|
lifecycle: {
|
|
455
|
-
createClient: async ({
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
685
|
+
createClient: async ({
|
|
686
|
+
config,
|
|
687
|
+
projectId,
|
|
688
|
+
projectSecret
|
|
689
|
+
}) => {
|
|
690
|
+
if (!isCloudConfig(config)) {
|
|
691
|
+
return [
|
|
692
|
+
createClient2({
|
|
693
|
+
accessToken: config.accessToken,
|
|
694
|
+
appSecret: config.appSecret ?? "",
|
|
695
|
+
phoneNumberId: config.phoneNumberId
|
|
696
|
+
})
|
|
697
|
+
];
|
|
698
|
+
}
|
|
699
|
+
if (!(projectId && projectSecret)) {
|
|
700
|
+
throw new Error(
|
|
701
|
+
"WhatsApp Business cloud mode requires projectId and projectSecret. Either pass credentials to Spectrum(), or provide direct credentials: whatsappBusiness.config({ accessToken, phoneNumberId })"
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
return await createCloudClients(projectId, projectSecret);
|
|
461
705
|
},
|
|
462
706
|
destroyClient: async ({ client }) => {
|
|
463
|
-
await client
|
|
707
|
+
await disposeCloudAuth(client);
|
|
708
|
+
await Promise.all(client.map((c) => c.close()));
|
|
464
709
|
}
|
|
465
710
|
},
|
|
466
711
|
events: {
|
|
@@ -95,7 +95,7 @@ interface Space<_Def = unknown> {
|
|
|
95
95
|
edit(message: OutboundMessage, newContent: ContentInput): Promise<void>;
|
|
96
96
|
readonly id: string;
|
|
97
97
|
responding<T>(fn: () => T | Promise<T>): Promise<T>;
|
|
98
|
-
send(content: ContentInput): Promise<OutboundMessage>;
|
|
98
|
+
send(content: ContentInput): Promise<OutboundMessage | undefined>;
|
|
99
99
|
send(...content: [ContentInput, ContentInput, ...ContentInput[]]): Promise<OutboundMessage[]>;
|
|
100
100
|
startTyping(): Promise<void>;
|
|
101
101
|
stopTyping(): Promise<void>;
|
|
@@ -106,7 +106,7 @@ interface BaseMessage<TPlatform extends string = string, TSender extends User =
|
|
|
106
106
|
readonly id: string;
|
|
107
107
|
platform: TPlatform;
|
|
108
108
|
react(reaction: string): Promise<void>;
|
|
109
|
-
reply(content: ContentInput): Promise<OutboundMessage<TPlatform, TSender, TSpace
|
|
109
|
+
reply(content: ContentInput): Promise<OutboundMessage<TPlatform, TSender, TSpace> | undefined>;
|
|
110
110
|
reply(...content: [ContentInput, ContentInput, ...ContentInput[]]): Promise<OutboundMessage<TPlatform, TSender, TSpace>[]>;
|
|
111
111
|
space: TSpace;
|
|
112
112
|
timestamp: Date;
|
package/package.json
CHANGED
package/dist/chunk-HXM64ENV.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// src/utils/cloud.ts
|
|
2
|
-
var SPECTRUM_CLOUD_URL = `https://${process.env.SPECTRUM_CLOUD_URL ?? "spectrum.photon.codes"}`;
|
|
3
|
-
var SpectrumCloudError = class extends Error {
|
|
4
|
-
status;
|
|
5
|
-
code;
|
|
6
|
-
constructor(status, code, message) {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = "SpectrumCloudError";
|
|
9
|
-
this.status = status;
|
|
10
|
-
this.code = code;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
var request = async (path, init) => {
|
|
14
|
-
const response = await fetch(`${SPECTRUM_CLOUD_URL}${path}`, init);
|
|
15
|
-
if (!response.ok) {
|
|
16
|
-
const body = await response.text().catch(() => "");
|
|
17
|
-
try {
|
|
18
|
-
const parsed = JSON.parse(body);
|
|
19
|
-
throw new SpectrumCloudError(
|
|
20
|
-
response.status,
|
|
21
|
-
parsed.code,
|
|
22
|
-
parsed.message
|
|
23
|
-
);
|
|
24
|
-
} catch (error) {
|
|
25
|
-
if (error instanceof SpectrumCloudError) {
|
|
26
|
-
throw error;
|
|
27
|
-
}
|
|
28
|
-
throw new SpectrumCloudError(
|
|
29
|
-
response.status,
|
|
30
|
-
"UNKNOWN",
|
|
31
|
-
body || response.statusText
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
const json = await response.json();
|
|
36
|
-
if (!json.succeed) {
|
|
37
|
-
throw new SpectrumCloudError(
|
|
38
|
-
response.status,
|
|
39
|
-
"UNKNOWN",
|
|
40
|
-
"Server returned succeed=false"
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
return json.data;
|
|
44
|
-
};
|
|
45
|
-
var basicAuth = (projectId, projectSecret) => `Basic ${btoa(`${projectId}:${projectSecret}`)}`;
|
|
46
|
-
var cloud = {
|
|
47
|
-
getSubscription: (projectId) => request(`/projects/${projectId}/billing/subscription`),
|
|
48
|
-
issueImessageTokens: (projectId, projectSecret) => request(`/projects/${projectId}/imessage/tokens`, {
|
|
49
|
-
method: "POST",
|
|
50
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
51
|
-
}),
|
|
52
|
-
getImessageInfo: (projectId) => request(`/projects/${projectId}/imessage/`),
|
|
53
|
-
getPlatforms: (projectId) => request(`/projects/${projectId}/platforms/`),
|
|
54
|
-
togglePlatform: (projectId, projectSecret, platform, enabled) => request(`/projects/${projectId}/platforms/`, {
|
|
55
|
-
method: "PATCH",
|
|
56
|
-
headers: {
|
|
57
|
-
Authorization: basicAuth(projectId, projectSecret),
|
|
58
|
-
"Content-Type": "application/json"
|
|
59
|
-
},
|
|
60
|
-
body: JSON.stringify({ platform, enabled })
|
|
61
|
-
})
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export {
|
|
65
|
-
SpectrumCloudError,
|
|
66
|
-
cloud
|
|
67
|
-
};
|