spectrum-ts 1.9.2 → 1.12.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-TN54TDTQ.js → chunk-4TXLNBGE.js} +1 -1
- package/dist/{chunk-N3ZKMTSG.js → chunk-7Z3QGRGI.js} +8 -6
- package/dist/chunk-E7AXYNOZ.js +524 -0
- package/dist/{chunk-7O5BCLGQ.js → chunk-FPYXHZZA.js} +191 -97
- package/dist/chunk-KO67KDBD.js +61 -0
- package/dist/chunk-L3VXHUVY.js +457 -0
- package/dist/{chunk-5NHNMN4H.js → chunk-UFJZIZDO.js} +1 -1
- package/dist/{chunk-OR3VGVML.js → chunk-VQOW7X7U.js} +8 -4
- package/dist/{chunk-XZSBR26X.js → chunk-YDHES53X.js} +189 -500
- package/dist/{chunk-HWADNTQF.js → chunk-YKWKZ2PZ.js} +4 -59
- package/dist/index.d.ts +210 -85
- package/dist/index.js +17 -9
- package/dist/photo-content-BQF42prd.d.ts +13 -0
- package/dist/providers/imessage/index.d.ts +32 -5
- package/dist/providers/imessage/index.js +10 -6
- package/dist/providers/index.d.ts +4 -1
- package/dist/providers/index.js +13 -7
- package/dist/providers/slack/index.d.ts +47 -0
- package/dist/providers/slack/index.js +8 -0
- package/dist/providers/terminal/index.d.ts +46 -10
- package/dist/providers/terminal/index.js +4 -3
- package/dist/providers/whatsapp-business/index.d.ts +2 -2
- package/dist/providers/whatsapp-business/index.js +5 -3
- package/dist/{types-lUyzRurY.d.ts → types-BzW4gInA.d.ts} +231 -104
- package/package.json +12 -1
|
@@ -2,98 +2,56 @@ import {
|
|
|
2
2
|
asGroup,
|
|
3
3
|
asRichlink,
|
|
4
4
|
groupSchema
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-UFJZIZDO.js";
|
|
6
6
|
import {
|
|
7
7
|
asPoll,
|
|
8
|
-
asPollOption
|
|
8
|
+
asPollOption
|
|
9
|
+
} from "./chunk-KO67KDBD.js";
|
|
10
|
+
import {
|
|
9
11
|
cloud,
|
|
10
12
|
mergeStreams,
|
|
11
13
|
stream
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-YKWKZ2PZ.js";
|
|
15
|
+
import {
|
|
16
|
+
asContact,
|
|
17
|
+
fromVCard,
|
|
18
|
+
toVCard
|
|
19
|
+
} from "./chunk-L3VXHUVY.js";
|
|
13
20
|
import {
|
|
14
21
|
UnsupportedError,
|
|
15
22
|
asAttachment,
|
|
16
|
-
asContact,
|
|
17
23
|
asCustom,
|
|
18
24
|
asText,
|
|
19
25
|
attachmentSchema,
|
|
26
|
+
buildPhotoAction,
|
|
20
27
|
definePlatform,
|
|
21
|
-
|
|
28
|
+
photoActionSchema,
|
|
22
29
|
reactionSchema,
|
|
23
|
-
readSchema,
|
|
24
30
|
text,
|
|
25
|
-
textSchema
|
|
26
|
-
|
|
27
|
-
} from "./chunk-XZSBR26X.js";
|
|
31
|
+
textSchema
|
|
32
|
+
} from "./chunk-YDHES53X.js";
|
|
28
33
|
|
|
29
34
|
// src/providers/imessage/index.ts
|
|
30
35
|
import { createClient as createClient2, MessageEffect as MessageEffect2 } from "@photon-ai/advanced-imessage";
|
|
31
36
|
import { IMessageSDK as IMessageSDK2 } from "@photon-ai/imessage-kit";
|
|
32
37
|
|
|
33
38
|
// src/providers/imessage/content/background.ts
|
|
34
|
-
import { readFile } from "fs/promises";
|
|
35
|
-
import { basename } from "path";
|
|
36
|
-
import { lookup as lookupMimeType } from "mime-types";
|
|
37
39
|
import z from "zod";
|
|
38
|
-
var backgroundActionSchema = z.discriminatedUnion("kind", [
|
|
39
|
-
z.object({
|
|
40
|
-
kind: z.literal("set"),
|
|
41
|
-
read: readSchema,
|
|
42
|
-
mimeType: z.string().nonempty()
|
|
43
|
-
}),
|
|
44
|
-
z.object({ kind: z.literal("clear") })
|
|
45
|
-
]);
|
|
46
40
|
var backgroundSchema = z.object({
|
|
47
41
|
type: z.literal("background"),
|
|
48
42
|
__platform: z.literal("iMessage"),
|
|
49
43
|
__fireAndForget: z.literal(true),
|
|
50
|
-
action:
|
|
44
|
+
action: photoActionSchema
|
|
51
45
|
});
|
|
52
46
|
var isBackground = (v) => backgroundSchema.safeParse(v).success;
|
|
53
|
-
var CLEAR_SENTINEL = "clear";
|
|
54
|
-
var resolveMimeType = (input, mimeType) => {
|
|
55
|
-
if (mimeType) {
|
|
56
|
-
return mimeType;
|
|
57
|
-
}
|
|
58
|
-
if (typeof input === "string") {
|
|
59
|
-
const resolved = lookupMimeType(basename(input));
|
|
60
|
-
if (resolved) {
|
|
61
|
-
return resolved;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
throw new Error(
|
|
65
|
-
"Unable to resolve MIME type for background. Pass options.mimeType explicitly."
|
|
66
|
-
);
|
|
67
|
-
};
|
|
68
|
-
var cachedRead = (read) => {
|
|
69
|
-
let cached;
|
|
70
|
-
return () => {
|
|
71
|
-
cached ??= read().catch((err) => {
|
|
72
|
-
cached = void 0;
|
|
73
|
-
throw err;
|
|
74
|
-
});
|
|
75
|
-
return cached;
|
|
76
|
-
};
|
|
77
|
-
};
|
|
78
47
|
function background(input, options) {
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
build: async () => backgroundSchema.parse({
|
|
82
|
-
type: "background",
|
|
83
|
-
__platform: "iMessage",
|
|
84
|
-
__fireAndForget: true,
|
|
85
|
-
action: { kind: "clear" }
|
|
86
|
-
})
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
const mimeType = resolveMimeType(input, options?.mimeType);
|
|
90
|
-
const read = typeof input === "string" ? cachedRead(() => readFile(input)) : cachedRead(async () => input);
|
|
48
|
+
const action = buildPhotoAction(input, options, "background");
|
|
91
49
|
return {
|
|
92
50
|
build: async () => backgroundSchema.parse({
|
|
93
51
|
type: "background",
|
|
94
52
|
__platform: "iMessage",
|
|
95
53
|
__fireAndForget: true,
|
|
96
|
-
action
|
|
54
|
+
action
|
|
97
55
|
})
|
|
98
56
|
};
|
|
99
57
|
}
|
|
@@ -141,38 +99,68 @@ function effect(input, messageEffect) {
|
|
|
141
99
|
};
|
|
142
100
|
}
|
|
143
101
|
|
|
102
|
+
// src/providers/imessage/content/read.ts
|
|
103
|
+
import z3 from "zod";
|
|
104
|
+
var isMessage = (v) => typeof v === "object" && v !== null && "id" in v && "content" in v;
|
|
105
|
+
var readSchema = z3.object({
|
|
106
|
+
type: z3.literal("read"),
|
|
107
|
+
__platform: z3.literal("iMessage"),
|
|
108
|
+
__fireAndForget: z3.literal(true),
|
|
109
|
+
target: z3.custom(isMessage, {
|
|
110
|
+
message: "read target must be a Message"
|
|
111
|
+
})
|
|
112
|
+
});
|
|
113
|
+
var isRead = (v) => readSchema.safeParse(v).success;
|
|
114
|
+
function read(target) {
|
|
115
|
+
return {
|
|
116
|
+
build: async () => {
|
|
117
|
+
if (target.direction !== "inbound") {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`read() target must be an inbound message (got direction "${target.direction}", message id "${target.id}")`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return readSchema.parse({
|
|
123
|
+
type: "read",
|
|
124
|
+
__platform: "iMessage",
|
|
125
|
+
__fireAndForget: true,
|
|
126
|
+
target
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
144
132
|
// src/providers/imessage/auth.ts
|
|
145
133
|
import { createClient } from "@photon-ai/advanced-imessage";
|
|
146
134
|
|
|
147
135
|
// src/providers/imessage/types.ts
|
|
148
136
|
import { IMessageSDK } from "@photon-ai/imessage-kit";
|
|
149
|
-
import
|
|
137
|
+
import z4 from "zod";
|
|
150
138
|
var SHARED_PHONE = "shared";
|
|
151
139
|
var isLocal = (client) => client instanceof IMessageSDK;
|
|
152
|
-
var clientEntry =
|
|
153
|
-
address:
|
|
154
|
-
token:
|
|
155
|
-
phone:
|
|
140
|
+
var clientEntry = z4.object({
|
|
141
|
+
address: z4.string(),
|
|
142
|
+
token: z4.string(),
|
|
143
|
+
phone: z4.string()
|
|
156
144
|
});
|
|
157
|
-
var configSchema =
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
local:
|
|
161
|
-
clients: clientEntry.or(
|
|
145
|
+
var configSchema = z4.union([
|
|
146
|
+
z4.object({ local: z4.literal(true) }),
|
|
147
|
+
z4.object({
|
|
148
|
+
local: z4.literal(false).optional().default(false),
|
|
149
|
+
clients: clientEntry.or(z4.array(clientEntry)).optional()
|
|
162
150
|
})
|
|
163
151
|
]);
|
|
164
|
-
var userSchema =
|
|
165
|
-
var spaceSchema =
|
|
166
|
-
id:
|
|
167
|
-
type:
|
|
168
|
-
phone:
|
|
152
|
+
var userSchema = z4.object({});
|
|
153
|
+
var spaceSchema = z4.object({
|
|
154
|
+
id: z4.string(),
|
|
155
|
+
type: z4.enum(["dm", "group"]),
|
|
156
|
+
phone: z4.string()
|
|
169
157
|
});
|
|
170
|
-
var spaceParamsSchema =
|
|
171
|
-
phone:
|
|
158
|
+
var spaceParamsSchema = z4.object({
|
|
159
|
+
phone: z4.string().optional()
|
|
172
160
|
});
|
|
173
|
-
var messageSchema =
|
|
174
|
-
partIndex:
|
|
175
|
-
parentId:
|
|
161
|
+
var messageSchema = z4.object({
|
|
162
|
+
partIndex: z4.number().int().nonnegative().optional(),
|
|
163
|
+
parentId: z4.string().optional()
|
|
176
164
|
});
|
|
177
165
|
|
|
178
166
|
// src/providers/imessage/auth.ts
|
|
@@ -298,7 +286,7 @@ import { setTimeout as sleep } from "timers/promises";
|
|
|
298
286
|
|
|
299
287
|
// src/providers/imessage/local/attachments.ts
|
|
300
288
|
import { createReadStream } from "fs";
|
|
301
|
-
import { readFile
|
|
289
|
+
import { readFile } from "fs/promises";
|
|
302
290
|
import { Readable } from "stream";
|
|
303
291
|
|
|
304
292
|
// src/providers/imessage/shared/vcard.ts
|
|
@@ -329,7 +317,7 @@ var readLocalAttachment = async (att) => {
|
|
|
329
317
|
`iMessage attachment ${att.id} has no local file available on disk`
|
|
330
318
|
);
|
|
331
319
|
}
|
|
332
|
-
return
|
|
320
|
+
return readFile(att.localPath);
|
|
333
321
|
};
|
|
334
322
|
var toAttachmentContent = (att) => {
|
|
335
323
|
const { localPath } = att;
|
|
@@ -448,7 +436,7 @@ var messages = (client) => stream((emit, end) => {
|
|
|
448
436
|
// src/providers/imessage/local/send.ts
|
|
449
437
|
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
450
438
|
import { tmpdir } from "os";
|
|
451
|
-
import { basename
|
|
439
|
+
import { basename, join } from "path";
|
|
452
440
|
|
|
453
441
|
// src/providers/imessage/shared/errors.ts
|
|
454
442
|
var IMESSAGE_PLATFORM = "iMessage";
|
|
@@ -464,7 +452,7 @@ var synthRecord = (spaceId, content) => ({
|
|
|
464
452
|
timestamp: /* @__PURE__ */ new Date()
|
|
465
453
|
});
|
|
466
454
|
var sendTempFile = async (client, spaceId, name, data) => {
|
|
467
|
-
const safeName =
|
|
455
|
+
const safeName = basename(name) || DEFAULT_ATTACHMENT_NAME;
|
|
468
456
|
const dir = await mkdtemp(join(tmpdir(), "spectrum-"));
|
|
469
457
|
const tmp = join(dir, safeName);
|
|
470
458
|
await writeFile(tmp, data);
|
|
@@ -528,6 +516,20 @@ var parseChildId = (id) => {
|
|
|
528
516
|
};
|
|
529
517
|
};
|
|
530
518
|
|
|
519
|
+
// src/providers/imessage/remote/avatar.ts
|
|
520
|
+
var setIcon = async (remote, spaceId, content) => {
|
|
521
|
+
const chat = toChatGuid(spaceId);
|
|
522
|
+
if (content.action.kind === "clear") {
|
|
523
|
+
await remote.groups.removeIcon(chat);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const buffer = await content.action.read();
|
|
527
|
+
await remote.groups.setIcon(
|
|
528
|
+
chat,
|
|
529
|
+
new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
530
|
+
);
|
|
531
|
+
};
|
|
532
|
+
|
|
531
533
|
// src/providers/imessage/remote/background.ts
|
|
532
534
|
var setBackground = async (remote, spaceId, content) => {
|
|
533
535
|
const chat = toChatGuid(spaceId);
|
|
@@ -1017,9 +1019,19 @@ var reactToMessage = async (remote, spaceId, target, reaction) => {
|
|
|
1017
1019
|
}
|
|
1018
1020
|
};
|
|
1019
1021
|
|
|
1022
|
+
// src/providers/imessage/remote/read.ts
|
|
1023
|
+
var markRead = async (remote, spaceId) => {
|
|
1024
|
+
await remote.chats.markRead(toChatGuid(spaceId));
|
|
1025
|
+
};
|
|
1026
|
+
|
|
1027
|
+
// src/providers/imessage/remote/rename.ts
|
|
1028
|
+
var setDisplayName = async (remote, spaceId, content) => {
|
|
1029
|
+
await remote.groups.setDisplayName(toChatGuid(spaceId), content.displayName);
|
|
1030
|
+
};
|
|
1031
|
+
|
|
1020
1032
|
// src/utils/audio.ts
|
|
1021
1033
|
import { spawn } from "child_process";
|
|
1022
|
-
import { mkdtemp as mkdtemp2, readFile as
|
|
1034
|
+
import { mkdtemp as mkdtemp2, readFile as readFile2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
1023
1035
|
import { tmpdir as tmpdir2 } from "os";
|
|
1024
1036
|
import { join as join2 } from "path";
|
|
1025
1037
|
var M4A_BRANDS = /* @__PURE__ */ new Set([
|
|
@@ -1126,7 +1138,7 @@ var transcodeToM4a = async (buffer) => {
|
|
|
1126
1138
|
if (code !== 0) {
|
|
1127
1139
|
throw new Error(`ffmpeg conversion failed (exit ${code}): ${stderr}`);
|
|
1128
1140
|
}
|
|
1129
|
-
const out = await
|
|
1141
|
+
const out = await readFile2(outPath);
|
|
1130
1142
|
return { buffer: out, duration: parseDuration(stderr) };
|
|
1131
1143
|
} finally {
|
|
1132
1144
|
await rm2(dir, { recursive: true, force: true }).catch(() => {
|
|
@@ -1879,6 +1891,11 @@ var stopTyping = async (remote, spaceId) => {
|
|
|
1879
1891
|
// src/providers/imessage/remote/api.ts
|
|
1880
1892
|
var messages4 = (clients) => messages3(clients);
|
|
1881
1893
|
var setBackground2 = async (remote, spaceId, content) => setBackground(remote, spaceId, content);
|
|
1894
|
+
var setDisplayName2 = async (remote, spaceId, content) => setDisplayName(remote, spaceId, content);
|
|
1895
|
+
var setIcon2 = async (remote, spaceId, content) => setIcon(remote, spaceId, content);
|
|
1896
|
+
var markRead2 = async (remote, spaceId) => {
|
|
1897
|
+
await markRead(remote, spaceId);
|
|
1898
|
+
};
|
|
1882
1899
|
var startTyping2 = async (remote, spaceId) => {
|
|
1883
1900
|
await startTyping(remote, spaceId);
|
|
1884
1901
|
};
|
|
@@ -1954,6 +1971,64 @@ var handleBackground = async (client, space, content) => {
|
|
|
1954
1971
|
const remote = clientForPhone(client, space.phone);
|
|
1955
1972
|
await setBackground2(remote, space.id, content);
|
|
1956
1973
|
};
|
|
1974
|
+
var handleRead = async (client, space) => {
|
|
1975
|
+
if (isLocal(client)) {
|
|
1976
|
+
throw UnsupportedError.action(
|
|
1977
|
+
"read",
|
|
1978
|
+
"iMessage (local mode)",
|
|
1979
|
+
"marking chats as read requires remote iMessage"
|
|
1980
|
+
);
|
|
1981
|
+
}
|
|
1982
|
+
const remote = clientForPhone(client, space.phone);
|
|
1983
|
+
await markRead2(remote, space.id);
|
|
1984
|
+
};
|
|
1985
|
+
var handleTyping = async (client, space, state) => {
|
|
1986
|
+
if (isLocal(client)) {
|
|
1987
|
+
return;
|
|
1988
|
+
}
|
|
1989
|
+
const remote = clientForPhone(client, space.phone);
|
|
1990
|
+
if (state === "start") {
|
|
1991
|
+
await startTyping2(remote, space.id);
|
|
1992
|
+
} else {
|
|
1993
|
+
await stopTyping2(remote, space.id);
|
|
1994
|
+
}
|
|
1995
|
+
};
|
|
1996
|
+
var handleRename = async (client, space, content) => {
|
|
1997
|
+
if (isLocal(client)) {
|
|
1998
|
+
throw UnsupportedError.action(
|
|
1999
|
+
"rename",
|
|
2000
|
+
"iMessage (local mode)",
|
|
2001
|
+
"renaming chats requires remote iMessage"
|
|
2002
|
+
);
|
|
2003
|
+
}
|
|
2004
|
+
if (space.type !== "group") {
|
|
2005
|
+
throw UnsupportedError.action(
|
|
2006
|
+
"rename",
|
|
2007
|
+
"iMessage",
|
|
2008
|
+
"only group chats can be renamed (this space is a DM)"
|
|
2009
|
+
);
|
|
2010
|
+
}
|
|
2011
|
+
const remote = clientForPhone(client, space.phone);
|
|
2012
|
+
await setDisplayName2(remote, space.id, content);
|
|
2013
|
+
};
|
|
2014
|
+
var handleAvatar = async (client, space, content) => {
|
|
2015
|
+
if (isLocal(client)) {
|
|
2016
|
+
throw UnsupportedError.action(
|
|
2017
|
+
"avatar",
|
|
2018
|
+
"iMessage (local mode)",
|
|
2019
|
+
"setting group avatars requires remote iMessage"
|
|
2020
|
+
);
|
|
2021
|
+
}
|
|
2022
|
+
if (space.type !== "group") {
|
|
2023
|
+
throw UnsupportedError.action(
|
|
2024
|
+
"avatar",
|
|
2025
|
+
"iMessage",
|
|
2026
|
+
"only group chats have avatars (this space is a DM)"
|
|
2027
|
+
);
|
|
2028
|
+
}
|
|
2029
|
+
const remote = clientForPhone(client, space.phone);
|
|
2030
|
+
await setIcon2(remote, space.id, content);
|
|
2031
|
+
};
|
|
1957
2032
|
var imessage = definePlatform("iMessage", {
|
|
1958
2033
|
config: configSchema,
|
|
1959
2034
|
static: {
|
|
@@ -2032,14 +2107,28 @@ var imessage = definePlatform("iMessage", {
|
|
|
2032
2107
|
},
|
|
2033
2108
|
actions: {
|
|
2034
2109
|
// Sugar: `space.background(input, opts?)` →
|
|
2035
|
-
// `space.send(background(input, opts?))`.
|
|
2110
|
+
// `space.send(background(input, opts?))`. Routed through the universal
|
|
2036
2111
|
// send pipeline so the unsupported-content + warn-and-skip path on
|
|
2037
2112
|
// local-mode iMessage is identical to the canonical form.
|
|
2038
|
-
background
|
|
2113
|
+
background: async (space, input, opts) => {
|
|
2114
|
+
await space.send(background(input, opts));
|
|
2115
|
+
},
|
|
2116
|
+
// Sugar: `space.read(message)` → `space.send(read(message))`.
|
|
2117
|
+
read: async (space, message) => {
|
|
2118
|
+
await space.send(read(message));
|
|
2119
|
+
}
|
|
2039
2120
|
}
|
|
2040
2121
|
},
|
|
2041
2122
|
message: {
|
|
2042
|
-
schema: messageSchema
|
|
2123
|
+
schema: messageSchema,
|
|
2124
|
+
actions: {
|
|
2125
|
+
// Sugar: `message.read()` → `message.space.send(read(self))`.
|
|
2126
|
+
// `buildMessage` injects the message as the first argument; callers
|
|
2127
|
+
// pass nothing.
|
|
2128
|
+
read: async (message) => {
|
|
2129
|
+
await message.space.send(read(message));
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2043
2132
|
},
|
|
2044
2133
|
messages: ({ client }) => isLocal(client) ? messages2(client) : messages4(client),
|
|
2045
2134
|
send: async ({ space, content, client }) => {
|
|
@@ -2083,25 +2172,29 @@ var imessage = definePlatform("iMessage", {
|
|
|
2083
2172
|
return;
|
|
2084
2173
|
}
|
|
2085
2174
|
if (content.type === "typing") {
|
|
2086
|
-
|
|
2087
|
-
return;
|
|
2088
|
-
}
|
|
2089
|
-
const remote2 = clientForPhone(client, space.phone);
|
|
2090
|
-
if (content.state === "start") {
|
|
2091
|
-
await startTyping2(remote2, space.id);
|
|
2092
|
-
} else {
|
|
2093
|
-
await stopTyping2(remote2, space.id);
|
|
2094
|
-
}
|
|
2175
|
+
await handleTyping(client, space, content.state);
|
|
2095
2176
|
return;
|
|
2096
2177
|
}
|
|
2097
2178
|
if (content.type === "edit") {
|
|
2098
2179
|
await handleEdit(client, space, content);
|
|
2099
2180
|
return;
|
|
2100
2181
|
}
|
|
2182
|
+
if (content.type === "rename") {
|
|
2183
|
+
await handleRename(client, space, content);
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
if (content.type === "avatar") {
|
|
2187
|
+
await handleAvatar(client, space, content);
|
|
2188
|
+
return;
|
|
2189
|
+
}
|
|
2101
2190
|
if (isBackground(content)) {
|
|
2102
2191
|
await handleBackground(client, space, content);
|
|
2103
2192
|
return;
|
|
2104
2193
|
}
|
|
2194
|
+
if (isRead(content)) {
|
|
2195
|
+
await handleRead(client, space);
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2105
2198
|
if (isLocal(client)) {
|
|
2106
2199
|
return await send2(client, space.id, content);
|
|
2107
2200
|
}
|
|
@@ -2122,5 +2215,6 @@ var imessage = definePlatform("iMessage", {
|
|
|
2122
2215
|
export {
|
|
2123
2216
|
background,
|
|
2124
2217
|
effect,
|
|
2218
|
+
read,
|
|
2125
2219
|
imessage
|
|
2126
2220
|
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/content/poll.ts
|
|
2
|
+
import z from "zod";
|
|
3
|
+
var pollChoiceSchema = z.object({
|
|
4
|
+
title: z.string().nonempty()
|
|
5
|
+
});
|
|
6
|
+
var pollSchema = z.object({
|
|
7
|
+
type: z.literal("poll"),
|
|
8
|
+
title: z.string().nonempty().max(300),
|
|
9
|
+
options: z.array(pollChoiceSchema).min(2).max(10)
|
|
10
|
+
});
|
|
11
|
+
var pollOptionSchema = z.object({
|
|
12
|
+
type: z.literal("poll_option"),
|
|
13
|
+
option: pollChoiceSchema,
|
|
14
|
+
poll: pollSchema,
|
|
15
|
+
selected: z.boolean(),
|
|
16
|
+
title: z.string().nonempty()
|
|
17
|
+
}).superRefine((value, ctx) => {
|
|
18
|
+
if (value.title !== value.option.title) {
|
|
19
|
+
ctx.addIssue({
|
|
20
|
+
code: "custom",
|
|
21
|
+
message: "poll_option title must match option.title",
|
|
22
|
+
path: ["title"]
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (!value.poll.options.some(
|
|
26
|
+
(pollOption) => pollOption.title === value.option.title
|
|
27
|
+
)) {
|
|
28
|
+
ctx.addIssue({
|
|
29
|
+
code: "custom",
|
|
30
|
+
message: "poll_option option must exist in poll.options",
|
|
31
|
+
path: ["option"]
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
var asPoll = (input) => pollSchema.parse({ type: "poll", ...input });
|
|
36
|
+
var asPollOption = (input) => pollOptionSchema.parse({
|
|
37
|
+
type: "poll_option",
|
|
38
|
+
...input,
|
|
39
|
+
title: input.option.title
|
|
40
|
+
});
|
|
41
|
+
var option = (title) => ({ title });
|
|
42
|
+
var normalize = (raw) => typeof raw === "string" ? { title: raw } : { title: raw.title };
|
|
43
|
+
var collectOptions = (args) => {
|
|
44
|
+
const [first] = args;
|
|
45
|
+
if (args.length === 1 && Array.isArray(first)) {
|
|
46
|
+
return first;
|
|
47
|
+
}
|
|
48
|
+
return args;
|
|
49
|
+
};
|
|
50
|
+
function poll(title, ...rest) {
|
|
51
|
+
return {
|
|
52
|
+
build: async () => asPoll({ title, options: collectOptions(rest).map(normalize) })
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
asPoll,
|
|
58
|
+
asPollOption,
|
|
59
|
+
option,
|
|
60
|
+
poll
|
|
61
|
+
};
|