spectrum-ts 0.6.1 → 0.8.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-4O6MQC5Z.js} +161 -25
- package/dist/chunk-H5XYVRHM.js +141 -0
- package/dist/{chunk-UZWRB3FZ.js → chunk-ZNUORCLB.js} +77 -6
- package/dist/index.d.ts +45 -5
- package/dist/index.js +20 -13
- package/dist/providers/imessage/index.d.ts +2 -2
- package/dist/providers/imessage/index.js +62 -23
- 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 +10 -9
- package/dist/providers/whatsapp-business/index.js +274 -25
- package/dist/{stream-DGy4geUK.d.ts → stream-B55k7W8-.d.ts} +1 -1
- package/dist/{types-DZMHfgYQ.d.ts → types-DLrsDzV-.d.ts} +15 -4
- package/package.json +2 -1
- package/dist/chunk-HXM64ENV.js +0 -67
|
@@ -2,20 +2,243 @@ import {
|
|
|
2
2
|
asAttachment,
|
|
3
3
|
asContact,
|
|
4
4
|
asCustom,
|
|
5
|
+
cloud,
|
|
6
|
+
mergeStreams,
|
|
5
7
|
stream
|
|
6
|
-
} from "../../chunk-
|
|
8
|
+
} from "../../chunk-ZNUORCLB.js";
|
|
7
9
|
import {
|
|
10
|
+
UnsupportedError,
|
|
8
11
|
asText,
|
|
9
12
|
definePlatform
|
|
10
|
-
} from "../../chunk-
|
|
13
|
+
} from "../../chunk-4O6MQC5Z.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
|
+
await 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
|
+
const pump = (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 async () => {
|
|
208
|
+
closed = true;
|
|
209
|
+
active?.close().catch(() => void 0);
|
|
210
|
+
active = void 0;
|
|
211
|
+
state.subscriptions.delete(subscription);
|
|
212
|
+
await pump;
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
const subscription = {
|
|
216
|
+
close: () => {
|
|
217
|
+
closed = true;
|
|
218
|
+
active?.close().catch(() => void 0);
|
|
219
|
+
},
|
|
220
|
+
swap: () => {
|
|
221
|
+
active?.close().catch(() => void 0);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
state.subscriptions.add(subscription);
|
|
225
|
+
return new TypedEventStream(source, async () => {
|
|
226
|
+
closed = true;
|
|
227
|
+
active?.close().catch(() => void 0);
|
|
228
|
+
state.subscriptions.delete(subscription);
|
|
229
|
+
await source.close();
|
|
230
|
+
});
|
|
231
|
+
};
|
|
16
232
|
|
|
17
233
|
// src/providers/whatsapp-business/messages.ts
|
|
18
234
|
import { extension as mimeExtension } from "mime-types";
|
|
235
|
+
var primary = (clients) => {
|
|
236
|
+
const client = clients[0];
|
|
237
|
+
if (!client) {
|
|
238
|
+
throw new Error("No WhatsApp Business client available");
|
|
239
|
+
}
|
|
240
|
+
return client;
|
|
241
|
+
};
|
|
19
242
|
var toSendResult = (result) => ({
|
|
20
243
|
id: result.messageId
|
|
21
244
|
});
|
|
@@ -291,16 +514,16 @@ var contactToWa = (contact) => {
|
|
|
291
514
|
};
|
|
292
515
|
return card;
|
|
293
516
|
};
|
|
294
|
-
var
|
|
517
|
+
var clientStream = (client) => {
|
|
295
518
|
const eventStream = client.events.subscribe().filter(
|
|
296
519
|
(e) => e.type === "message"
|
|
297
520
|
);
|
|
298
521
|
return stream((emit, end) => {
|
|
299
|
-
(async () => {
|
|
522
|
+
const pump = (async () => {
|
|
300
523
|
try {
|
|
301
524
|
for await (const event of eventStream) {
|
|
302
525
|
for (const m of toMessages(client, event.message)) {
|
|
303
|
-
emit(m);
|
|
526
|
+
await emit(m);
|
|
304
527
|
}
|
|
305
528
|
}
|
|
306
529
|
end();
|
|
@@ -308,10 +531,15 @@ var messages = (client) => {
|
|
|
308
531
|
end(e);
|
|
309
532
|
}
|
|
310
533
|
})();
|
|
311
|
-
return () =>
|
|
534
|
+
return async () => {
|
|
535
|
+
await eventStream.close();
|
|
536
|
+
await pump;
|
|
537
|
+
};
|
|
312
538
|
});
|
|
313
539
|
};
|
|
314
|
-
var
|
|
540
|
+
var messages = (clients) => mergeStreams(clients.map(clientStream));
|
|
541
|
+
var send = async (clients, spaceId, content) => {
|
|
542
|
+
const client = primary(clients);
|
|
315
543
|
switch (content.type) {
|
|
316
544
|
case "text":
|
|
317
545
|
return toSendResult(
|
|
@@ -353,16 +581,17 @@ var send = async (client, spaceId, content) => {
|
|
|
353
581
|
);
|
|
354
582
|
}
|
|
355
583
|
default:
|
|
356
|
-
throw
|
|
584
|
+
throw UnsupportedError.content(content.type);
|
|
357
585
|
}
|
|
358
586
|
};
|
|
359
|
-
var reactToMessage = async (
|
|
360
|
-
await
|
|
587
|
+
var reactToMessage = async (clients, spaceId, messageId, reaction) => {
|
|
588
|
+
await primary(clients).messages.send({
|
|
361
589
|
to: spaceId,
|
|
362
590
|
reaction: { messageId, emoji: reaction }
|
|
363
591
|
});
|
|
364
592
|
};
|
|
365
|
-
var replyToMessage = async (
|
|
593
|
+
var replyToMessage = async (clients, spaceId, messageId, content) => {
|
|
594
|
+
const client = primary(clients);
|
|
366
595
|
switch (content.type) {
|
|
367
596
|
case "text":
|
|
368
597
|
return toSendResult(
|
|
@@ -411,17 +640,20 @@ var replyToMessage = async (client, spaceId, messageId, content) => {
|
|
|
411
640
|
);
|
|
412
641
|
}
|
|
413
642
|
default:
|
|
414
|
-
throw
|
|
643
|
+
throw UnsupportedError.content(content.type);
|
|
415
644
|
}
|
|
416
645
|
};
|
|
417
646
|
|
|
418
647
|
// src/providers/whatsapp-business/types.ts
|
|
419
648
|
import z from "zod";
|
|
420
|
-
var
|
|
649
|
+
var directConfig = z.object({
|
|
421
650
|
accessToken: z.string().min(1),
|
|
422
|
-
|
|
423
|
-
|
|
651
|
+
appSecret: z.string().optional(),
|
|
652
|
+
phoneNumberId: z.string().min(1)
|
|
424
653
|
});
|
|
654
|
+
var cloudConfig = z.object({}).strict();
|
|
655
|
+
var configSchema = z.union([directConfig, cloudConfig]);
|
|
656
|
+
var isCloudConfig = (config) => !("accessToken" in config);
|
|
425
657
|
var userSchema = z.object({});
|
|
426
658
|
var spaceSchema = z.object({
|
|
427
659
|
id: z.string()
|
|
@@ -440,8 +672,10 @@ var whatsappBusiness = definePlatform("WhatsApp Business", {
|
|
|
440
672
|
throw new Error("WhatsApp space creation requires at least one user");
|
|
441
673
|
}
|
|
442
674
|
if (input.users.length > 1) {
|
|
443
|
-
throw
|
|
444
|
-
"
|
|
675
|
+
throw UnsupportedError.action(
|
|
676
|
+
"createSpace",
|
|
677
|
+
"WhatsApp Business",
|
|
678
|
+
"only 1:1 conversations are supported"
|
|
445
679
|
);
|
|
446
680
|
}
|
|
447
681
|
const user = input.users[0];
|
|
@@ -452,15 +686,30 @@ var whatsappBusiness = definePlatform("WhatsApp Business", {
|
|
|
452
686
|
}
|
|
453
687
|
},
|
|
454
688
|
lifecycle: {
|
|
455
|
-
createClient: async ({
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
689
|
+
createClient: async ({
|
|
690
|
+
config,
|
|
691
|
+
projectId,
|
|
692
|
+
projectSecret
|
|
693
|
+
}) => {
|
|
694
|
+
if (!isCloudConfig(config)) {
|
|
695
|
+
return [
|
|
696
|
+
createClient2({
|
|
697
|
+
accessToken: config.accessToken,
|
|
698
|
+
appSecret: config.appSecret ?? "",
|
|
699
|
+
phoneNumberId: config.phoneNumberId
|
|
700
|
+
})
|
|
701
|
+
];
|
|
702
|
+
}
|
|
703
|
+
if (!(projectId && projectSecret)) {
|
|
704
|
+
throw new Error(
|
|
705
|
+
"WhatsApp Business cloud mode requires projectId and projectSecret. Either pass credentials to Spectrum(), or provide direct credentials: whatsappBusiness.config({ accessToken, phoneNumberId })"
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
return await createCloudClients(projectId, projectSecret);
|
|
461
709
|
},
|
|
462
710
|
destroyClient: async ({ client }) => {
|
|
463
|
-
await client
|
|
711
|
+
await disposeCloudAuth(client);
|
|
712
|
+
await Promise.all(client.map((c) => c.close()));
|
|
464
713
|
}
|
|
465
714
|
},
|
|
466
715
|
events: {
|
|
@@ -2,7 +2,7 @@ interface ManagedStream<T> extends AsyncIterable<T> {
|
|
|
2
2
|
close(): Promise<void>;
|
|
3
3
|
}
|
|
4
4
|
type StreamCleanup = void | (() => void | Promise<void>);
|
|
5
|
-
declare function stream<T>(setup: (emit: (value: T) => void
|
|
5
|
+
declare function stream<T>(setup: (emit: (value: T) => Promise<void>, end: (error?: unknown) => void) => StreamCleanup | Promise<StreamCleanup>): ManagedStream<T>;
|
|
6
6
|
declare function mergeStreams<T>(streams: readonly ManagedStream<T>[]): ManagedStream<T>;
|
|
7
7
|
|
|
8
8
|
export { type ManagedStream as M, mergeStreams as m, stream as s };
|
|
@@ -78,6 +78,16 @@ declare const contentSchema: z__default.ZodDiscriminatedUnion<[z__default.ZodObj
|
|
|
78
78
|
size: z__default.ZodOptional<z__default.ZodNumber>;
|
|
79
79
|
read: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
|
|
80
80
|
stream: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
|
|
81
|
+
}, z__default.core.$strip>, z__default.ZodObject<{
|
|
82
|
+
type: z__default.ZodLiteral<"richlink">;
|
|
83
|
+
url: z__default.ZodURL;
|
|
84
|
+
title: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodOptional<z__default.ZodString>>>;
|
|
85
|
+
summary: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodOptional<z__default.ZodString>>>;
|
|
86
|
+
cover: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodOptional<z__default.ZodObject<{
|
|
87
|
+
mimeType: z__default.ZodOptional<z__default.ZodString>;
|
|
88
|
+
read: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
|
|
89
|
+
stream: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
|
|
90
|
+
}, z__default.core.$strip>>>>;
|
|
81
91
|
}, z__default.core.$strip>], "type">;
|
|
82
92
|
type Content = z__default.infer<typeof contentSchema>;
|
|
83
93
|
interface ContentBuilder {
|
|
@@ -95,7 +105,7 @@ interface Space<_Def = unknown> {
|
|
|
95
105
|
edit(message: OutboundMessage, newContent: ContentInput): Promise<void>;
|
|
96
106
|
readonly id: string;
|
|
97
107
|
responding<T>(fn: () => T | Promise<T>): Promise<T>;
|
|
98
|
-
send(content: ContentInput): Promise<OutboundMessage>;
|
|
108
|
+
send(content: ContentInput): Promise<OutboundMessage | undefined>;
|
|
99
109
|
send(...content: [ContentInput, ContentInput, ...ContentInput[]]): Promise<OutboundMessage[]>;
|
|
100
110
|
startTyping(): Promise<void>;
|
|
101
111
|
stopTyping(): Promise<void>;
|
|
@@ -106,7 +116,7 @@ interface BaseMessage<TPlatform extends string = string, TSender extends User =
|
|
|
106
116
|
readonly id: string;
|
|
107
117
|
platform: TPlatform;
|
|
108
118
|
react(reaction: string): Promise<void>;
|
|
109
|
-
reply(content: ContentInput): Promise<OutboundMessage<TPlatform, TSender, TSpace
|
|
119
|
+
reply(content: ContentInput): Promise<OutboundMessage<TPlatform, TSender, TSpace> | undefined>;
|
|
110
120
|
reply(...content: [ContentInput, ContentInput, ...ContentInput[]]): Promise<OutboundMessage<TPlatform, TSender, TSpace>[]>;
|
|
111
121
|
space: TSpace;
|
|
112
122
|
timestamp: Date;
|
|
@@ -310,12 +320,13 @@ type SpaceShapeOf<Def extends AnyPlatformDef> = [SchemaSpaceOf<Def>] extends [
|
|
|
310
320
|
never
|
|
311
321
|
] ? ResolvedSpaceOf<Def> : SchemaSpaceOf<Def>;
|
|
312
322
|
type SpaceParamsInputOf<Def extends AnyPlatformDef> = InputSchema<Def["space"]["params"]>;
|
|
323
|
+
type SpaceUserLike<Def extends AnyPlatformDef> = PlatformUser<Def> | string;
|
|
313
324
|
type SpaceArrayArgs<Def extends AnyPlatformDef> = [
|
|
314
325
|
SpaceParamsInputOf<Def>
|
|
315
|
-
] extends [never] ? [users:
|
|
326
|
+
] extends [never] ? [users: SpaceUserLike<Def>[]] : [users: SpaceUserLike<Def>[]] | [users: SpaceUserLike<Def>[], params: SpaceParamsInputOf<Def>] | [params: SpaceParamsInputOf<Def>];
|
|
316
327
|
type SpaceVarargArgs<Def extends AnyPlatformDef> = [
|
|
317
328
|
SpaceParamsInputOf<Def>
|
|
318
|
-
] extends [never] ?
|
|
329
|
+
] extends [never] ? SpaceUserLike<Def>[] : SpaceUserLike<Def>[] | [...SpaceUserLike<Def>[], SpaceParamsInputOf<Def>];
|
|
319
330
|
type SpaceArgs<Def extends AnyPlatformDef> = SpaceArrayArgs<Def> | SpaceVarargArgs<Def>;
|
|
320
331
|
type PlatformSpace<Def extends AnyPlatformDef> = Omit<SpaceShapeOf<Def>, keyof Space> & Space;
|
|
321
332
|
type PlatformMessage<Def extends AnyPlatformDef> = Omit<SchemaInfer<Def["message"]>, keyof Message> & Message<Def["name"], PlatformUser<Def>, PlatformSpace<Def>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spectrum-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"@repeaterjs/repeater": "^3.0.6",
|
|
26
26
|
"better-grpc": "^0.3.2",
|
|
27
27
|
"mime-types": "^3.0.1",
|
|
28
|
+
"open-graph-scraper": "^6.11.0",
|
|
28
29
|
"type-fest": "^5.4.1",
|
|
29
30
|
"vcf": "^2.1.2",
|
|
30
31
|
"zod": "^4.2.1"
|
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
|
-
};
|