spectrum-ts 1.18.0 → 3.0.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/README.md +11 -1
- package/dist/{attachment-DfWSZS5L.d.ts → attachment-WePAHfcH.d.ts} +1 -1
- package/dist/{authoring-C9uDdZ2F.d.ts → authoring-DDh3muGT.d.ts} +61 -26
- package/dist/authoring.d.ts +3 -3
- package/dist/authoring.js +8 -5
- package/dist/chunk-34FQGGD7.js +34 -0
- package/dist/chunk-3GEJYGZK.js +84 -0
- package/dist/{chunk-MC6ZKFSG.js → chunk-5XEFJBN2.js} +25 -103
- package/dist/{chunk-QGJFZMD5.js → chunk-6UZFVXQF.js} +17 -101
- package/dist/{chunk-NNY6LMSC.js → chunk-77U6SH5A.js} +1 -1
- package/dist/{chunk-YN6WOTBF.js → chunk-AYCMTRVC.js} +622 -79
- package/dist/{chunk-JQN6CRSC.js → chunk-CHY5YLLV.js} +11 -40
- package/dist/{chunk-5BKZJMZV.js → chunk-EZ5SNNFS.js} +79 -38
- package/dist/{chunk-3OTECDNH.js → chunk-FULEQIRQ.js} +31 -23
- package/dist/{chunk-2ILTJC35.js → chunk-LQMDV75O.js} +205 -11
- package/dist/{chunk-IPOFBAIM.js → chunk-LX437ZTY.js} +439 -154
- package/dist/chunk-MHGCPC2V.js +35 -0
- package/dist/chunk-NZ5WCMTY.js +91 -0
- package/dist/chunk-TXRWKSNH.js +927 -0
- package/dist/{chunk-5TIF3FIE.js → chunk-UXJ5OO6P.js} +16 -14
- package/dist/index.d.ts +125 -129
- package/dist/index.js +180 -73
- package/dist/manifest.json +6 -0
- package/dist/providers/imessage/index.d.ts +6 -14
- package/dist/providers/imessage/index.js +9 -6
- package/dist/providers/index.d.ts +5 -2
- package/dist/providers/index.js +18 -10
- package/dist/providers/slack/index.d.ts +1 -2
- package/dist/providers/slack/index.js +5 -4
- package/dist/providers/telegram/index.d.ts +45 -0
- package/dist/providers/telegram/index.js +13 -0
- package/dist/providers/terminal/index.d.ts +18 -422
- package/dist/providers/terminal/index.js +7 -5
- package/dist/providers/whatsapp-business/index.d.ts +1 -1
- package/dist/providers/whatsapp-business/index.js +7 -5
- package/dist/types-BujGKBin.d.ts +82 -0
- package/dist/{types-DcQ5a7PK.d.ts → types-YqCNUDIt.d.ts} +204 -26
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h1>Spectrum</h1>
|
|
3
3
|
<p><strong>Bring agents to any interface.</strong></p>
|
|
4
|
+
|
|
5
|
+
Photon (photon.codes) builds Spectrum, a multi-channel agent framework that makes AI agents reachable over real conversation surfaces like iMessage, SMS, and email instead of trapping them in web chat.
|
|
6
|
+
|
|
4
7
|
<p>
|
|
5
8
|
<a href="https://www.npmjs.com/package/spectrum-ts"><img src="https://img.shields.io/npm/v/spectrum-ts.svg?style=flat&colorA=1a1a1a&colorB=3178c6" alt="npm version" /></a>
|
|
6
9
|
<a href="https://www.npmjs.com/package/spectrum-ts"><img src="https://img.shields.io/npm/dm/spectrum-ts.svg?style=flat&colorA=1a1a1a&colorB=3178c6" alt="npm downloads" /></a>
|
|
@@ -10,7 +13,13 @@
|
|
|
10
13
|
</p>
|
|
11
14
|
</div>
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
## About Photon
|
|
17
|
+
|
|
18
|
+
**[Photon](https://photon.codes)** builds infrastructure for AI agents that operate over real communication channels.
|
|
19
|
+
|
|
20
|
+
Spectrum is Photon’s open-source multi-channel agent framework, enabling AI agents to communicate through interfaces people already use—such as iMessage, SMS, email, Slack, Discord, and voice—instead of being confined to web chat.
|
|
21
|
+
|
|
22
|
+
Learn more at **https://photon.codes**.
|
|
14
23
|
|
|
15
24
|
## Getting Started
|
|
16
25
|
|
|
@@ -54,6 +63,7 @@ Visit **[docs.photon.codes](https://docs.photon.codes)** to view the full docume
|
|
|
54
63
|
|----------|---------|
|
|
55
64
|
| iMessage | `spectrum-ts/providers/imessage` |
|
|
56
65
|
| WhatsApp | `spectrum-ts/providers/whatsapp` |
|
|
66
|
+
| Telegram | `spectrum-ts/providers/telegram` |
|
|
57
67
|
| Terminal | `spectrum-ts/providers/terminal` |
|
|
58
68
|
| Custom | `definePlatform` from `spectrum-ts` |
|
|
59
69
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import './attachment-
|
|
1
|
+
import './attachment-WePAHfcH.js';
|
|
2
2
|
import vCard from 'vcf';
|
|
3
3
|
import z__default from 'zod';
|
|
4
|
-
import { U as User, C as ContentBuilder, M as Message,
|
|
4
|
+
import { U as User, C as ContentBuilder, M as Message, e as Space, h as ContentInput } from './types-YqCNUDIt.js';
|
|
5
5
|
|
|
6
6
|
declare const nameSchema: z__default.ZodObject<{
|
|
7
7
|
formatted: z__default.ZodOptional<z__default.ZodString>;
|
|
@@ -140,6 +140,43 @@ declare const asGroup: (input: {
|
|
|
140
140
|
}) => Group;
|
|
141
141
|
declare function group(...items: [ContentInput, ContentInput, ...ContentInput[]]): ContentBuilder;
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Maps one chunk emitted by a stream to the incremental text it carries.
|
|
145
|
+
* Return a string to emit, or `null`/`undefined` to skip the chunk (e.g. for
|
|
146
|
+
* control events that carry no text).
|
|
147
|
+
*/
|
|
148
|
+
type DeltaExtractor<T> = (chunk: T) => string | null | undefined;
|
|
149
|
+
/**
|
|
150
|
+
* Anything the stream overloads of `text()` and `markdown()` accept as a
|
|
151
|
+
* source. The builder normalizes all of these to an internal
|
|
152
|
+
* `AsyncIterable<string>` of text deltas:
|
|
153
|
+
*
|
|
154
|
+
* - the Vercel AI SDK `streamText()` result (its `.textStream` is picked up
|
|
155
|
+
* automatically — pass either the whole result or `.textStream` directly),
|
|
156
|
+
* - a raw `AsyncIterable<T>` (e.g. an OpenAI / Anthropic streaming response),
|
|
157
|
+
* - a raw `ReadableStream<T>` of chunks.
|
|
158
|
+
*/
|
|
159
|
+
type StreamTextSource<T = unknown> = {
|
|
160
|
+
textStream: AsyncIterable<string> | ReadableStream<string>;
|
|
161
|
+
} | AsyncIterable<T> | ReadableStream<T>;
|
|
162
|
+
interface TextStreamOptions<T = unknown> {
|
|
163
|
+
/**
|
|
164
|
+
* Map each chunk to its incremental text. Omit to rely on built-in
|
|
165
|
+
* auto-detection of the common SDK shapes (OpenAI chat/responses, Anthropic
|
|
166
|
+
* messages, AI SDK text streams, and plain strings).
|
|
167
|
+
*/
|
|
168
|
+
extract?: DeltaExtractor<T>;
|
|
169
|
+
}
|
|
170
|
+
declare const streamTextSchema: z__default.ZodObject<{
|
|
171
|
+
type: z__default.ZodLiteral<"streamText">;
|
|
172
|
+
stream: z__default.ZodCustom<() => AsyncIterable<string>, () => AsyncIterable<string>>;
|
|
173
|
+
format: z__default.ZodOptional<z__default.ZodEnum<{
|
|
174
|
+
markdown: "markdown";
|
|
175
|
+
plain: "plain";
|
|
176
|
+
}>>;
|
|
177
|
+
}, z__default.core.$strip>;
|
|
178
|
+
type StreamText = z__default.infer<typeof streamTextSchema>;
|
|
179
|
+
|
|
143
180
|
declare const pollChoiceSchema: z__default.ZodObject<{
|
|
144
181
|
title: z__default.ZodString;
|
|
145
182
|
}, z__default.core.$strip>;
|
|
@@ -185,28 +222,6 @@ declare const option: (title: string) => PollChoice;
|
|
|
185
222
|
declare function poll(title: string, options: PollChoiceInput[]): ContentBuilder;
|
|
186
223
|
declare function poll(title: string, ...options: PollChoiceInput[]): ContentBuilder;
|
|
187
224
|
|
|
188
|
-
declare const reactionSchema: z__default.ZodObject<{
|
|
189
|
-
type: z__default.ZodLiteral<"reaction">;
|
|
190
|
-
emoji: z__default.ZodString;
|
|
191
|
-
target: z__default.ZodCustom<Message<string, User, Space<unknown>>, Message<string, User, Space<unknown>>>;
|
|
192
|
-
}, z__default.core.$strip>;
|
|
193
|
-
type Reaction = z__default.infer<typeof reactionSchema>;
|
|
194
|
-
declare const asReaction: (input: {
|
|
195
|
-
emoji: string;
|
|
196
|
-
target: Message;
|
|
197
|
-
}) => Reaction;
|
|
198
|
-
/**
|
|
199
|
-
* Construct a `reaction` content value targeting the given message.
|
|
200
|
-
*
|
|
201
|
-
* `space.send(reaction(emoji, message))` is sugar for `message.react(emoji)`.
|
|
202
|
-
* Reactions are fire-and-forget — the returned `Message` will be `undefined`
|
|
203
|
-
* because platforms do not surface a message id for reactions.
|
|
204
|
-
*
|
|
205
|
-
* To react to a message known only by id, resolve it first via
|
|
206
|
-
* `space.getMessage(id)`.
|
|
207
|
-
*/
|
|
208
|
-
declare function reaction(emoji: string, target: Message): ContentBuilder;
|
|
209
|
-
|
|
210
225
|
declare const richlinkSchema: z__default.ZodObject<{
|
|
211
226
|
type: z__default.ZodLiteral<"richlink">;
|
|
212
227
|
url: z__default.ZodURL;
|
|
@@ -239,7 +254,27 @@ declare const textSchema: z__default.ZodObject<{
|
|
|
239
254
|
text: z__default.ZodString;
|
|
240
255
|
}, z__default.core.$strip>;
|
|
241
256
|
declare const asText: (text: string) => z__default.infer<typeof textSchema>;
|
|
242
|
-
|
|
257
|
+
/**
|
|
258
|
+
* Send plain text — a static string or a streaming LLM response.
|
|
259
|
+
*
|
|
260
|
+
* `text("hi")` sends one message. `text(source)` wraps a text stream so it
|
|
261
|
+
* can be sent like any other content; delivery is platform-specific —
|
|
262
|
+
* iMessage (remote) sends the first chunk as a real message and then edits it
|
|
263
|
+
* in place as more text arrives; Telegram (private chats) animates a native
|
|
264
|
+
* draft preview and persists the final text as one message. Platforms that
|
|
265
|
+
* can't stream wait for the stream to finish and deliver the accumulated text
|
|
266
|
+
* as one plain message.
|
|
267
|
+
*
|
|
268
|
+
* A stream source accepts whatever the popular SDKs return (the AI SDK
|
|
269
|
+
* `streamText()` result, OpenAI / Anthropic streaming responses, or any
|
|
270
|
+
* `AsyncIterable` / `ReadableStream`); pass `options.extract` for any chunk
|
|
271
|
+
* shape the built-in detection doesn't recognize. A stream can only be sent
|
|
272
|
+
* once. Options apply to stream sources only — they are ignored for strings.
|
|
273
|
+
*
|
|
274
|
+
* For text written in markdown, use `markdown()` instead.
|
|
275
|
+
*/
|
|
276
|
+
declare function text(source: string): ContentBuilder;
|
|
277
|
+
declare function text<T = unknown>(source: StreamTextSource<T>, options?: TextStreamOptions<T>): ContentBuilder;
|
|
243
278
|
|
|
244
279
|
declare const voiceSchema: z__default.ZodObject<{
|
|
245
280
|
type: z__default.ZodLiteral<"voice">;
|
|
@@ -266,4 +301,4 @@ declare function voice(input: VoiceInput, options?: {
|
|
|
266
301
|
duration?: number;
|
|
267
302
|
}): ContentBuilder;
|
|
268
303
|
|
|
269
|
-
export {
|
|
304
|
+
export { asVoice as A, type ContactInput as C, type DeltaExtractor as D, type Group as G, type Poll as P, type Richlink as R, type StreamTextSource as S, type TextStreamOptions as T, type Voice as V, type Contact as a, type ContactAddress as b, type ContactDetails as c, type ContactEmail as d, type ContactName as e, type ContactOrg as f, type ContactPhone as g, type PollChoice as h, type PollChoiceInput as i, type PollOption as j, type StreamText as k, contact as l, custom as m, group as n, option as o, poll as p, asContact as q, richlink as r, asCustom as s, text as t, asGroup as u, voice as v, asPoll as w, asPollOption as x, asRichlink as y, asText as z };
|
package/dist/authoring.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { c as asAttachment } from './attachment-
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
1
|
+
export { c as asAttachment } from './attachment-WePAHfcH.js';
|
|
2
|
+
export { q as asContact, s as asCustom, u as asGroup, w as asPoll, x as asPollOption, y as asRichlink, z as asText, A as asVoice } from './authoring-DDh3muGT.js';
|
|
3
|
+
export { d as ProviderMessageRecord, $ as asReaction } from './types-YqCNUDIt.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
import 'vcf';
|
|
6
6
|
import 'hotscript';
|
package/dist/authoring.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
-
asGroup,
|
|
4
3
|
asRichlink
|
|
5
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-CHY5YLLV.js";
|
|
5
|
+
import {
|
|
6
|
+
asGroup
|
|
7
|
+
} from "./chunk-MHGCPC2V.js";
|
|
6
8
|
import {
|
|
7
9
|
asVoice
|
|
8
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-77U6SH5A.js";
|
|
9
11
|
import {
|
|
10
12
|
asPoll,
|
|
11
13
|
asPollOption
|
|
12
14
|
} from "./chunk-2D27WW5B.js";
|
|
13
15
|
import {
|
|
14
16
|
asContact
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-NZ5WCMTY.js";
|
|
18
|
+
import "./chunk-6UZFVXQF.js";
|
|
16
19
|
import {
|
|
17
20
|
asAttachment,
|
|
18
21
|
asCustom,
|
|
19
22
|
asReaction,
|
|
20
23
|
asText
|
|
21
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-LQMDV75O.js";
|
|
22
25
|
export {
|
|
23
26
|
asAttachment,
|
|
24
27
|
asContact,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/fusor/event.ts
|
|
4
|
+
var FUSOR_EVENT_BRAND = /* @__PURE__ */ Symbol.for("spectrum.fusor.event");
|
|
5
|
+
var FUSOR_MESSAGES_CHANNEL = "messages";
|
|
6
|
+
function fusorEvent(name, data) {
|
|
7
|
+
return { [FUSOR_EVENT_BRAND]: true, name, data };
|
|
8
|
+
}
|
|
9
|
+
function isFusorEvent(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && value[FUSOR_EVENT_BRAND] === true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/fusor/types.ts
|
|
14
|
+
var FUSOR_BRAND = /* @__PURE__ */ Symbol.for("spectrum.fusor.client");
|
|
15
|
+
|
|
16
|
+
// src/fusor/index.ts
|
|
17
|
+
function fusor(platform, verify) {
|
|
18
|
+
return {
|
|
19
|
+
[FUSOR_BRAND]: true,
|
|
20
|
+
platform,
|
|
21
|
+
verify
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function isFusorClient(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && value[FUSOR_BRAND] === true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
FUSOR_MESSAGES_CHANNEL,
|
|
30
|
+
fusorEvent,
|
|
31
|
+
isFusorEvent,
|
|
32
|
+
fusor,
|
|
33
|
+
isFusorClient
|
|
34
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/utils/cloud.ts
|
|
4
|
+
var SPECTRUM_CLOUD_URL = process.env.SPECTRUM_CLOUD_URL ?? "https://spectrum.photon.codes";
|
|
5
|
+
var SpectrumCloudError = class extends Error {
|
|
6
|
+
status;
|
|
7
|
+
code;
|
|
8
|
+
constructor(status, code, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "SpectrumCloudError";
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.code = code;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var request = async (path, init) => {
|
|
16
|
+
const response = await fetch(`${SPECTRUM_CLOUD_URL}${path}`, init);
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
const body = await response.text().catch(() => "");
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(body);
|
|
21
|
+
throw new SpectrumCloudError(
|
|
22
|
+
response.status,
|
|
23
|
+
parsed.code,
|
|
24
|
+
parsed.message
|
|
25
|
+
);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (error instanceof SpectrumCloudError) {
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
throw new SpectrumCloudError(
|
|
31
|
+
response.status,
|
|
32
|
+
"UNKNOWN",
|
|
33
|
+
body || response.statusText
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const json = await response.json();
|
|
38
|
+
if (!json.succeed) {
|
|
39
|
+
throw new SpectrumCloudError(
|
|
40
|
+
response.status,
|
|
41
|
+
"UNKNOWN",
|
|
42
|
+
"Server returned succeed=false"
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return json.data;
|
|
46
|
+
};
|
|
47
|
+
var basicAuth = (projectId, projectSecret) => `Basic ${btoa(`${projectId}:${projectSecret}`)}`;
|
|
48
|
+
var cloud = {
|
|
49
|
+
getProject: (projectId, projectSecret) => request(`/projects/${projectId}/`, {
|
|
50
|
+
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
51
|
+
}),
|
|
52
|
+
getSubscription: (projectId) => request(`/projects/${projectId}/billing/subscription`),
|
|
53
|
+
issueImessageTokens: (projectId, projectSecret) => request(`/projects/${projectId}/imessage/tokens`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
56
|
+
}),
|
|
57
|
+
getImessageInfo: (projectId) => request(`/projects/${projectId}/imessage/`),
|
|
58
|
+
issueWhatsappBusinessTokens: (projectId, projectSecret) => request(`/projects/${projectId}/whatsapp-business/tokens`, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
61
|
+
}),
|
|
62
|
+
issueSlackTokens: (projectId, projectSecret) => request(`/projects/${projectId}/slack/tokens`, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
65
|
+
}),
|
|
66
|
+
issueFusorToken: (projectId, projectSecret) => request(`/projects/${projectId}/fusor/token`, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
69
|
+
}),
|
|
70
|
+
getPlatforms: (projectId) => request(`/projects/${projectId}/platforms/`),
|
|
71
|
+
togglePlatform: (projectId, projectSecret, platform, enabled) => request(`/projects/${projectId}/platforms/`, {
|
|
72
|
+
method: "PATCH",
|
|
73
|
+
headers: {
|
|
74
|
+
Authorization: basicAuth(projectId, projectSecret),
|
|
75
|
+
"Content-Type": "application/json"
|
|
76
|
+
},
|
|
77
|
+
body: JSON.stringify({ platform, enabled })
|
|
78
|
+
})
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
SpectrumCloudError,
|
|
83
|
+
cloud
|
|
84
|
+
};
|
|
@@ -1,83 +1,5 @@
|
|
|
1
1
|
import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
|
|
2
2
|
|
|
3
|
-
// src/utils/cloud.ts
|
|
4
|
-
var SPECTRUM_CLOUD_URL = process.env.SPECTRUM_CLOUD_URL ?? "https://spectrum.photon.codes";
|
|
5
|
-
var SpectrumCloudError = class extends Error {
|
|
6
|
-
status;
|
|
7
|
-
code;
|
|
8
|
-
constructor(status, code, message) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.name = "SpectrumCloudError";
|
|
11
|
-
this.status = status;
|
|
12
|
-
this.code = code;
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
var request = async (path, init) => {
|
|
16
|
-
const response = await fetch(`${SPECTRUM_CLOUD_URL}${path}`, init);
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
const body = await response.text().catch(() => "");
|
|
19
|
-
try {
|
|
20
|
-
const parsed = JSON.parse(body);
|
|
21
|
-
throw new SpectrumCloudError(
|
|
22
|
-
response.status,
|
|
23
|
-
parsed.code,
|
|
24
|
-
parsed.message
|
|
25
|
-
);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
if (error instanceof SpectrumCloudError) {
|
|
28
|
-
throw error;
|
|
29
|
-
}
|
|
30
|
-
throw new SpectrumCloudError(
|
|
31
|
-
response.status,
|
|
32
|
-
"UNKNOWN",
|
|
33
|
-
body || response.statusText
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
const json = await response.json();
|
|
38
|
-
if (!json.succeed) {
|
|
39
|
-
throw new SpectrumCloudError(
|
|
40
|
-
response.status,
|
|
41
|
-
"UNKNOWN",
|
|
42
|
-
"Server returned succeed=false"
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
return json.data;
|
|
46
|
-
};
|
|
47
|
-
var basicAuth = (projectId, projectSecret) => `Basic ${btoa(`${projectId}:${projectSecret}`)}`;
|
|
48
|
-
var cloud = {
|
|
49
|
-
getProject: (projectId, projectSecret) => request(`/projects/${projectId}/`, {
|
|
50
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
51
|
-
}),
|
|
52
|
-
getSubscription: (projectId) => request(`/projects/${projectId}/billing/subscription`),
|
|
53
|
-
issueImessageTokens: (projectId, projectSecret) => request(`/projects/${projectId}/imessage/tokens`, {
|
|
54
|
-
method: "POST",
|
|
55
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
56
|
-
}),
|
|
57
|
-
getImessageInfo: (projectId) => request(`/projects/${projectId}/imessage/`),
|
|
58
|
-
issueWhatsappBusinessTokens: (projectId, projectSecret) => request(`/projects/${projectId}/whatsapp-business/tokens`, {
|
|
59
|
-
method: "POST",
|
|
60
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
61
|
-
}),
|
|
62
|
-
issueSlackTokens: (projectId, projectSecret) => request(`/projects/${projectId}/slack/tokens`, {
|
|
63
|
-
method: "POST",
|
|
64
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
65
|
-
}),
|
|
66
|
-
issueFusorToken: (projectId, projectSecret) => request(`/projects/${projectId}/fusor/token`, {
|
|
67
|
-
method: "POST",
|
|
68
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
69
|
-
}),
|
|
70
|
-
getPlatforms: (projectId) => request(`/projects/${projectId}/platforms/`),
|
|
71
|
-
togglePlatform: (projectId, projectSecret, platform, enabled) => request(`/projects/${projectId}/platforms/`, {
|
|
72
|
-
method: "PATCH",
|
|
73
|
-
headers: {
|
|
74
|
-
Authorization: basicAuth(projectId, projectSecret),
|
|
75
|
-
"Content-Type": "application/json"
|
|
76
|
-
},
|
|
77
|
-
body: JSON.stringify({ platform, enabled })
|
|
78
|
-
})
|
|
79
|
-
};
|
|
80
|
-
|
|
81
3
|
// src/utils/stream.ts
|
|
82
4
|
import { Repeater } from "@repeaterjs/repeater";
|
|
83
5
|
function createAsyncQueue() {
|
|
@@ -190,6 +112,16 @@ function broadcast(source) {
|
|
|
190
112
|
let terminalError;
|
|
191
113
|
let pumpPromise;
|
|
192
114
|
let closed = false;
|
|
115
|
+
const closeConsumers = (error) => {
|
|
116
|
+
if (consumers.size === 0) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const current = Array.from(consumers);
|
|
120
|
+
consumers.clear();
|
|
121
|
+
for (const consumer of current) {
|
|
122
|
+
consumer.end(error);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
193
125
|
const startPump = () => {
|
|
194
126
|
if (pumping || terminated) {
|
|
195
127
|
return;
|
|
@@ -198,35 +130,35 @@ function broadcast(source) {
|
|
|
198
130
|
pumpPromise = (async () => {
|
|
199
131
|
try {
|
|
200
132
|
for await (const value of source) {
|
|
201
|
-
|
|
133
|
+
if (terminated) {
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
for (const consumer of Array.from(consumers)) {
|
|
202
137
|
consumer.deliveries = consumer.deliveries.then(
|
|
203
138
|
() => consumer.emit(value).catch(() => {
|
|
204
139
|
})
|
|
205
140
|
);
|
|
206
141
|
}
|
|
207
142
|
}
|
|
143
|
+
if (terminated) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
208
146
|
terminated = true;
|
|
209
147
|
await Promise.allSettled(
|
|
210
148
|
Array.from(consumers, (consumer) => consumer.deliveries)
|
|
211
149
|
);
|
|
212
|
-
|
|
213
|
-
consumer.end();
|
|
214
|
-
}
|
|
215
|
-
consumers.clear();
|
|
150
|
+
closeConsumers();
|
|
216
151
|
} catch (error) {
|
|
217
152
|
terminated = true;
|
|
218
153
|
terminalError = error;
|
|
219
|
-
|
|
220
|
-
consumer.end(error);
|
|
221
|
-
}
|
|
222
|
-
consumers.clear();
|
|
154
|
+
closeConsumers(error);
|
|
223
155
|
}
|
|
224
156
|
})();
|
|
225
157
|
};
|
|
226
158
|
return {
|
|
227
159
|
subscribe() {
|
|
228
160
|
return stream((emit, end) => {
|
|
229
|
-
if (terminated) {
|
|
161
|
+
if (terminated || closed) {
|
|
230
162
|
end(terminalError);
|
|
231
163
|
return;
|
|
232
164
|
}
|
|
@@ -247,27 +179,17 @@ function broadcast(source) {
|
|
|
247
179
|
return;
|
|
248
180
|
}
|
|
249
181
|
closed = true;
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
} finally {
|
|
256
|
-
if (!terminated) {
|
|
257
|
-
terminated = true;
|
|
258
|
-
for (const consumer of consumers) {
|
|
259
|
-
consumer.end();
|
|
260
|
-
}
|
|
261
|
-
consumers.clear();
|
|
262
|
-
}
|
|
182
|
+
terminated = true;
|
|
183
|
+
closeConsumers();
|
|
184
|
+
await source.close().catch(ignoreCleanupError);
|
|
185
|
+
if (pumpPromise) {
|
|
186
|
+
await pumpPromise.catch(ignoreCleanupError);
|
|
263
187
|
}
|
|
264
188
|
}
|
|
265
189
|
};
|
|
266
190
|
}
|
|
267
191
|
|
|
268
192
|
export {
|
|
269
|
-
SpectrumCloudError,
|
|
270
|
-
cloud,
|
|
271
193
|
createAsyncQueue,
|
|
272
194
|
stream,
|
|
273
195
|
mergeStreams,
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
readSchema
|
|
4
|
-
} from "./chunk-2ILTJC35.js";
|
|
5
2
|
|
|
6
3
|
// src/utils/vcard.ts
|
|
7
4
|
import vCard from "vcf";
|
|
@@ -350,109 +347,28 @@ var writePhoto = async (card, photo) => {
|
|
|
350
347
|
type: photoTypeParam(photo.mimeType)
|
|
351
348
|
});
|
|
352
349
|
};
|
|
353
|
-
var toVCard = async (
|
|
354
|
-
if (typeof
|
|
355
|
-
return
|
|
350
|
+
var toVCard = async (contact) => {
|
|
351
|
+
if (typeof contact.raw === "string" && contact.raw.startsWith("BEGIN:VCARD")) {
|
|
352
|
+
return contact.raw;
|
|
356
353
|
}
|
|
357
354
|
const card = new vCard();
|
|
358
|
-
writeName(card,
|
|
359
|
-
writePhones(card,
|
|
360
|
-
writeEmails(card,
|
|
361
|
-
writeAddresses(card,
|
|
362
|
-
writeOrg(card,
|
|
363
|
-
writeUrls(card,
|
|
364
|
-
if (
|
|
365
|
-
card.set("bday",
|
|
366
|
-
}
|
|
367
|
-
if (
|
|
368
|
-
card.set("note",
|
|
369
|
-
}
|
|
370
|
-
await writePhoto(card,
|
|
355
|
+
writeName(card, contact.name);
|
|
356
|
+
writePhones(card, contact.phones);
|
|
357
|
+
writeEmails(card, contact.emails);
|
|
358
|
+
writeAddresses(card, contact.addresses);
|
|
359
|
+
writeOrg(card, contact.org);
|
|
360
|
+
writeUrls(card, contact.urls);
|
|
361
|
+
if (contact.birthday) {
|
|
362
|
+
card.set("bday", contact.birthday);
|
|
363
|
+
}
|
|
364
|
+
if (contact.note) {
|
|
365
|
+
card.set("note", contact.note);
|
|
366
|
+
}
|
|
367
|
+
await writePhoto(card, contact.photo);
|
|
371
368
|
return card.toString();
|
|
372
369
|
};
|
|
373
370
|
|
|
374
|
-
// src/content/contact.ts
|
|
375
|
-
import vCard2 from "vcf";
|
|
376
|
-
import z from "zod";
|
|
377
|
-
var userRefSchema = z.object({
|
|
378
|
-
__platform: z.string(),
|
|
379
|
-
id: z.string()
|
|
380
|
-
});
|
|
381
|
-
var nameSchema = z.object({
|
|
382
|
-
formatted: z.string().optional(),
|
|
383
|
-
first: z.string().optional(),
|
|
384
|
-
last: z.string().optional(),
|
|
385
|
-
middle: z.string().optional(),
|
|
386
|
-
prefix: z.string().optional(),
|
|
387
|
-
suffix: z.string().optional()
|
|
388
|
-
});
|
|
389
|
-
var phoneTypeSchema = z.enum(["mobile", "home", "work", "other"]);
|
|
390
|
-
var emailTypeSchema = z.enum(["home", "work", "other"]);
|
|
391
|
-
var addressTypeSchema = z.enum(["home", "work", "other"]);
|
|
392
|
-
var phoneSchema = z.object({
|
|
393
|
-
value: z.string(),
|
|
394
|
-
type: phoneTypeSchema.optional()
|
|
395
|
-
});
|
|
396
|
-
var emailSchema = z.object({
|
|
397
|
-
value: z.string(),
|
|
398
|
-
type: emailTypeSchema.optional()
|
|
399
|
-
});
|
|
400
|
-
var addressSchema = z.object({
|
|
401
|
-
street: z.string().optional(),
|
|
402
|
-
city: z.string().optional(),
|
|
403
|
-
region: z.string().optional(),
|
|
404
|
-
postalCode: z.string().optional(),
|
|
405
|
-
country: z.string().optional(),
|
|
406
|
-
type: addressTypeSchema.optional()
|
|
407
|
-
});
|
|
408
|
-
var orgSchema = z.object({
|
|
409
|
-
name: z.string().optional(),
|
|
410
|
-
title: z.string().optional(),
|
|
411
|
-
department: z.string().optional()
|
|
412
|
-
});
|
|
413
|
-
var photoSchema = z.object({
|
|
414
|
-
mimeType: z.string(),
|
|
415
|
-
read: readSchema
|
|
416
|
-
});
|
|
417
|
-
var contactSchema = z.object({
|
|
418
|
-
type: z.literal("contact"),
|
|
419
|
-
user: userRefSchema.optional(),
|
|
420
|
-
name: nameSchema.optional(),
|
|
421
|
-
phones: z.array(phoneSchema).optional(),
|
|
422
|
-
emails: z.array(emailSchema).optional(),
|
|
423
|
-
addresses: z.array(addressSchema).optional(),
|
|
424
|
-
org: orgSchema.optional(),
|
|
425
|
-
urls: z.array(z.string()).optional(),
|
|
426
|
-
birthday: z.string().optional(),
|
|
427
|
-
note: z.string().optional(),
|
|
428
|
-
photo: photoSchema.optional(),
|
|
429
|
-
raw: z.unknown().optional()
|
|
430
|
-
});
|
|
431
|
-
var asContact = (input) => contactSchema.parse({ type: "contact", ...input });
|
|
432
|
-
var isUser = (value) => typeof value === "object" && value !== null && "__platform" in value && "id" in value && typeof value.__platform === "string" && typeof value.id === "string";
|
|
433
|
-
function contact(input, details) {
|
|
434
|
-
return {
|
|
435
|
-
build: async () => {
|
|
436
|
-
if (typeof input === "string") {
|
|
437
|
-
return asContact(fromVCard(input));
|
|
438
|
-
}
|
|
439
|
-
if (input instanceof vCard2) {
|
|
440
|
-
return asContact(fromVCard(input.toString()));
|
|
441
|
-
}
|
|
442
|
-
if (isUser(input)) {
|
|
443
|
-
return asContact({
|
|
444
|
-
user: { __platform: input.__platform, id: input.id },
|
|
445
|
-
...details
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
return asContact(input);
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
|
|
453
371
|
export {
|
|
454
372
|
fromVCard,
|
|
455
|
-
toVCard
|
|
456
|
-
asContact,
|
|
457
|
-
contact
|
|
373
|
+
toVCard
|
|
458
374
|
};
|