spectrum-ts 1.9.2 → 1.11.3

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.
@@ -1,16 +1,18 @@
1
1
  import {
2
2
  asVoice
3
- } from "./chunk-TN54TDTQ.js";
3
+ } from "./chunk-EW5XWI3Y.js";
4
+ import {
5
+ asContact,
6
+ fromVCard,
7
+ toVCard
8
+ } from "./chunk-LCJMR75R.js";
4
9
  import {
5
10
  UnsupportedError,
6
11
  asAttachment,
7
- asContact,
8
12
  asCustom,
9
13
  definePlatform,
10
- fromVCard,
11
- reactionSchema,
12
- toVCard
13
- } from "./chunk-XZSBR26X.js";
14
+ reactionSchema
15
+ } from "./chunk-3BTOWGQL.js";
14
16
 
15
17
  // src/providers/terminal/index.ts
16
18
  import { spawn } from "child_process";
@@ -2,7 +2,7 @@ import {
2
2
  bufferToStream,
3
3
  readSchema,
4
4
  streamSchema
5
- } from "./chunk-XZSBR26X.js";
5
+ } from "./chunk-3BTOWGQL.js";
6
6
 
7
7
  // src/content/voice.ts
8
8
  import { createReadStream } from "fs";
@@ -2,29 +2,33 @@ import {
2
2
  asGroup,
3
3
  asRichlink,
4
4
  groupSchema
5
- } from "./chunk-5NHNMN4H.js";
5
+ } from "./chunk-YM4OAVPX.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-HWADNTQF.js";
14
+ } from "./chunk-YKWKZ2PZ.js";
15
+ import {
16
+ asContact,
17
+ fromVCard,
18
+ toVCard
19
+ } from "./chunk-LCJMR75R.js";
13
20
  import {
14
21
  UnsupportedError,
15
22
  asAttachment,
16
- asContact,
17
23
  asCustom,
18
24
  asText,
19
25
  attachmentSchema,
20
26
  definePlatform,
21
- fromVCard,
22
27
  reactionSchema,
23
28
  readSchema,
24
29
  text,
25
- textSchema,
26
- toVCard
27
- } from "./chunk-XZSBR26X.js";
30
+ textSchema
31
+ } from "./chunk-3BTOWGQL.js";
28
32
 
29
33
  // src/providers/imessage/index.ts
30
34
  import { createClient as createClient2, MessageEffect as MessageEffect2 } from "@photon-ai/advanced-imessage";
@@ -65,10 +69,10 @@ var resolveMimeType = (input, mimeType) => {
65
69
  "Unable to resolve MIME type for background. Pass options.mimeType explicitly."
66
70
  );
67
71
  };
68
- var cachedRead = (read) => {
72
+ var cachedRead = (read2) => {
69
73
  let cached;
70
74
  return () => {
71
- cached ??= read().catch((err) => {
75
+ cached ??= read2().catch((err) => {
72
76
  cached = void 0;
73
77
  throw err;
74
78
  });
@@ -87,13 +91,13 @@ function background(input, options) {
87
91
  };
88
92
  }
89
93
  const mimeType = resolveMimeType(input, options?.mimeType);
90
- const read = typeof input === "string" ? cachedRead(() => readFile(input)) : cachedRead(async () => input);
94
+ const read2 = typeof input === "string" ? cachedRead(() => readFile(input)) : cachedRead(async () => input);
91
95
  return {
92
96
  build: async () => backgroundSchema.parse({
93
97
  type: "background",
94
98
  __platform: "iMessage",
95
99
  __fireAndForget: true,
96
- action: { kind: "set", read, mimeType }
100
+ action: { kind: "set", read: read2, mimeType }
97
101
  })
98
102
  };
99
103
  }
@@ -141,38 +145,68 @@ function effect(input, messageEffect) {
141
145
  };
142
146
  }
143
147
 
148
+ // src/providers/imessage/content/read.ts
149
+ import z3 from "zod";
150
+ var isMessage = (v) => typeof v === "object" && v !== null && "id" in v && "content" in v;
151
+ var readSchema2 = z3.object({
152
+ type: z3.literal("read"),
153
+ __platform: z3.literal("iMessage"),
154
+ __fireAndForget: z3.literal(true),
155
+ target: z3.custom(isMessage, {
156
+ message: "read target must be a Message"
157
+ })
158
+ });
159
+ var isRead = (v) => readSchema2.safeParse(v).success;
160
+ function read(target) {
161
+ return {
162
+ build: async () => {
163
+ if (target.direction !== "inbound") {
164
+ throw new Error(
165
+ `read() target must be an inbound message (got direction "${target.direction}", message id "${target.id}")`
166
+ );
167
+ }
168
+ return readSchema2.parse({
169
+ type: "read",
170
+ __platform: "iMessage",
171
+ __fireAndForget: true,
172
+ target
173
+ });
174
+ }
175
+ };
176
+ }
177
+
144
178
  // src/providers/imessage/auth.ts
145
179
  import { createClient } from "@photon-ai/advanced-imessage";
146
180
 
147
181
  // src/providers/imessage/types.ts
148
182
  import { IMessageSDK } from "@photon-ai/imessage-kit";
149
- import z3 from "zod";
183
+ import z4 from "zod";
150
184
  var SHARED_PHONE = "shared";
151
185
  var isLocal = (client) => client instanceof IMessageSDK;
152
- var clientEntry = z3.object({
153
- address: z3.string(),
154
- token: z3.string(),
155
- phone: z3.string()
186
+ var clientEntry = z4.object({
187
+ address: z4.string(),
188
+ token: z4.string(),
189
+ phone: z4.string()
156
190
  });
157
- var configSchema = z3.union([
158
- z3.object({ local: z3.literal(true) }),
159
- z3.object({
160
- local: z3.literal(false).optional().default(false),
161
- clients: clientEntry.or(z3.array(clientEntry)).optional()
191
+ var configSchema = z4.union([
192
+ z4.object({ local: z4.literal(true) }),
193
+ z4.object({
194
+ local: z4.literal(false).optional().default(false),
195
+ clients: clientEntry.or(z4.array(clientEntry)).optional()
162
196
  })
163
197
  ]);
164
- var userSchema = z3.object({});
165
- var spaceSchema = z3.object({
166
- id: z3.string(),
167
- type: z3.enum(["dm", "group"]),
168
- phone: z3.string()
198
+ var userSchema = z4.object({});
199
+ var spaceSchema = z4.object({
200
+ id: z4.string(),
201
+ type: z4.enum(["dm", "group"]),
202
+ phone: z4.string()
169
203
  });
170
- var spaceParamsSchema = z3.object({
171
- phone: z3.string().optional()
204
+ var spaceParamsSchema = z4.object({
205
+ phone: z4.string().optional()
172
206
  });
173
- var messageSchema = z3.object({
174
- partIndex: z3.number().int().nonnegative().optional(),
175
- parentId: z3.string().optional()
207
+ var messageSchema = z4.object({
208
+ partIndex: z4.number().int().nonnegative().optional(),
209
+ parentId: z4.string().optional()
176
210
  });
177
211
 
178
212
  // src/providers/imessage/auth.ts
@@ -1017,6 +1051,11 @@ var reactToMessage = async (remote, spaceId, target, reaction) => {
1017
1051
  }
1018
1052
  };
1019
1053
 
1054
+ // src/providers/imessage/remote/read.ts
1055
+ var markRead = async (remote, spaceId) => {
1056
+ await remote.chats.markRead(toChatGuid(spaceId));
1057
+ };
1058
+
1020
1059
  // src/utils/audio.ts
1021
1060
  import { spawn } from "child_process";
1022
1061
  import { mkdtemp as mkdtemp2, readFile as readFile3, rm as rm2, writeFile as writeFile2 } from "fs/promises";
@@ -1879,6 +1918,9 @@ var stopTyping = async (remote, spaceId) => {
1879
1918
  // src/providers/imessage/remote/api.ts
1880
1919
  var messages4 = (clients) => messages3(clients);
1881
1920
  var setBackground2 = async (remote, spaceId, content) => setBackground(remote, spaceId, content);
1921
+ var markRead2 = async (remote, spaceId) => {
1922
+ await markRead(remote, spaceId);
1923
+ };
1882
1924
  var startTyping2 = async (remote, spaceId) => {
1883
1925
  await startTyping(remote, spaceId);
1884
1926
  };
@@ -1954,6 +1996,17 @@ var handleBackground = async (client, space, content) => {
1954
1996
  const remote = clientForPhone(client, space.phone);
1955
1997
  await setBackground2(remote, space.id, content);
1956
1998
  };
1999
+ var handleRead = async (client, space) => {
2000
+ if (isLocal(client)) {
2001
+ throw UnsupportedError.action(
2002
+ "read",
2003
+ "iMessage (local mode)",
2004
+ "marking chats as read requires remote iMessage"
2005
+ );
2006
+ }
2007
+ const remote = clientForPhone(client, space.phone);
2008
+ await markRead2(remote, space.id);
2009
+ };
1957
2010
  var imessage = definePlatform("iMessage", {
1958
2011
  config: configSchema,
1959
2012
  static: {
@@ -2032,14 +2085,28 @@ var imessage = definePlatform("iMessage", {
2032
2085
  },
2033
2086
  actions: {
2034
2087
  // Sugar: `space.background(input, opts?)` →
2035
- // `space.send(background(input, opts?))`. Wired through the universal
2088
+ // `space.send(background(input, opts?))`. Routed through the universal
2036
2089
  // send pipeline so the unsupported-content + warn-and-skip path on
2037
2090
  // local-mode iMessage is identical to the canonical form.
2038
- background
2091
+ background: async (space, input, opts) => {
2092
+ await space.send(background(input, opts));
2093
+ },
2094
+ // Sugar: `space.read(message)` → `space.send(read(message))`.
2095
+ read: async (space, message) => {
2096
+ await space.send(read(message));
2097
+ }
2039
2098
  }
2040
2099
  },
2041
2100
  message: {
2042
- schema: messageSchema
2101
+ schema: messageSchema,
2102
+ actions: {
2103
+ // Sugar: `message.read()` → `message.space.send(read(self))`.
2104
+ // `buildMessage` injects the message as the first argument; callers
2105
+ // pass nothing.
2106
+ read: async (message) => {
2107
+ await message.space.send(read(message));
2108
+ }
2109
+ }
2043
2110
  },
2044
2111
  messages: ({ client }) => isLocal(client) ? messages2(client) : messages4(client),
2045
2112
  send: async ({ space, content, client }) => {
@@ -2102,6 +2169,10 @@ var imessage = definePlatform("iMessage", {
2102
2169
  await handleBackground(client, space, content);
2103
2170
  return;
2104
2171
  }
2172
+ if (isRead(content)) {
2173
+ await handleRead(client, space);
2174
+ return;
2175
+ }
2105
2176
  if (isLocal(client)) {
2106
2177
  return await send2(client, space.id, content);
2107
2178
  }
@@ -2122,5 +2193,6 @@ var imessage = definePlatform("iMessage", {
2122
2193
  export {
2123
2194
  background,
2124
2195
  effect,
2196
+ read,
2125
2197
  imessage
2126
2198
  };
@@ -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
+ };