spectrum-ts 0.3.0 → 0.4.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.
@@ -0,0 +1,165 @@
1
+ // src/content/attachment.ts
2
+ import { createReadStream } from "fs";
3
+ import { readFile, stat } from "fs/promises";
4
+ import { basename } from "path";
5
+ import { Readable } from "stream";
6
+ import { lookup as lookupMimeType } from "mime-types";
7
+ import z from "zod";
8
+ var DEFAULT_ATTACHMENT_NAME = "attachment";
9
+ var readSchema = z.function({
10
+ input: [],
11
+ output: z.promise(z.instanceof(Buffer))
12
+ });
13
+ var streamSchema = z.function({
14
+ input: [],
15
+ output: z.promise(z.instanceof(ReadableStream))
16
+ });
17
+ var attachmentSchema = z.object({
18
+ type: z.literal("attachment"),
19
+ name: z.string().nonempty(),
20
+ mimeType: z.string().nonempty(),
21
+ size: z.number().int().nonnegative().optional(),
22
+ read: readSchema,
23
+ stream: streamSchema
24
+ });
25
+ var resolveAttachmentName = (input, name) => name || (typeof input === "string" ? basename(input) : DEFAULT_ATTACHMENT_NAME);
26
+ var resolveAttachmentMimeType = (name, mimeType) => {
27
+ if (mimeType) {
28
+ return mimeType;
29
+ }
30
+ const resolvedMimeType = lookupMimeType(name);
31
+ if (!resolvedMimeType) {
32
+ throw new Error(
33
+ `Unable to resolve MIME type for attachment "${name}". Pass options.mimeType explicitly.`
34
+ );
35
+ }
36
+ return resolvedMimeType;
37
+ };
38
+ var bufferToStream = (buf) => new ReadableStream({
39
+ start(controller) {
40
+ controller.enqueue(buf);
41
+ controller.close();
42
+ }
43
+ });
44
+ var asAttachment = (input) => {
45
+ let cached;
46
+ const read = () => {
47
+ cached ??= input.read().catch((err) => {
48
+ cached = void 0;
49
+ throw err;
50
+ });
51
+ return cached;
52
+ };
53
+ const stream2 = input.stream ?? (async () => bufferToStream(await read()));
54
+ return attachmentSchema.parse({
55
+ type: "attachment",
56
+ name: input.name,
57
+ mimeType: input.mimeType,
58
+ size: input.size,
59
+ read,
60
+ stream: stream2
61
+ });
62
+ };
63
+ function attachment(input, options) {
64
+ return {
65
+ build: async () => {
66
+ const name = resolveAttachmentName(input, options?.name);
67
+ const mimeType = resolveAttachmentMimeType(name, options?.mimeType);
68
+ if (typeof input === "string") {
69
+ const stats = await stat(input);
70
+ return asAttachment({
71
+ name,
72
+ mimeType,
73
+ size: stats.size,
74
+ read: () => readFile(input),
75
+ stream: async () => Readable.toWeb(
76
+ createReadStream(input)
77
+ )
78
+ });
79
+ }
80
+ return asAttachment({
81
+ name,
82
+ mimeType,
83
+ size: input.byteLength,
84
+ read: async () => input,
85
+ stream: async () => bufferToStream(input)
86
+ });
87
+ }
88
+ };
89
+ }
90
+
91
+ // src/content/custom.ts
92
+ import z2 from "zod";
93
+ var customSchema = z2.object({
94
+ type: z2.literal("custom"),
95
+ raw: z2.unknown()
96
+ });
97
+ var asCustom = (raw) => customSchema.parse({ type: "custom", raw });
98
+ function custom(raw) {
99
+ return {
100
+ build: async () => asCustom(raw)
101
+ };
102
+ }
103
+
104
+ // src/utils/stream.ts
105
+ import { Repeater } from "@repeaterjs/repeater";
106
+ function stream(setup) {
107
+ const repeater = new Repeater(async (push, stop) => {
108
+ const emit = (value) => {
109
+ Promise.resolve(push(value)).catch((error) => {
110
+ stop(error);
111
+ return void 0;
112
+ });
113
+ };
114
+ const end = (error) => {
115
+ stop(error);
116
+ };
117
+ const cleanup = await setup(emit, end);
118
+ try {
119
+ await stop;
120
+ } finally {
121
+ await cleanup?.();
122
+ }
123
+ });
124
+ return Object.assign(repeater, {
125
+ close: async () => {
126
+ await repeater.return(void 0);
127
+ }
128
+ });
129
+ }
130
+ function mergeStreams(streams) {
131
+ return stream((emit, end) => {
132
+ if (streams.length === 0) {
133
+ end();
134
+ return;
135
+ }
136
+ let openStreams = streams.length;
137
+ const workers = streams.map(async (source) => {
138
+ try {
139
+ for await (const value of source) {
140
+ emit(value);
141
+ }
142
+ } catch (error) {
143
+ end(error);
144
+ } finally {
145
+ openStreams -= 1;
146
+ if (openStreams === 0) {
147
+ end();
148
+ }
149
+ }
150
+ });
151
+ return async () => {
152
+ await Promise.allSettled(streams.map((source) => source.close()));
153
+ await Promise.allSettled(workers);
154
+ };
155
+ });
156
+ }
157
+
158
+ export {
159
+ asAttachment,
160
+ attachment,
161
+ asCustom,
162
+ custom,
163
+ stream,
164
+ mergeStreams
165
+ };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as ContentBuilder, 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, M as Message } from './types-DuE2hXuJ.js';
2
- export { A as AnyPlatformDef, E as EventProducer, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage, U as User } from './types-DuE2hXuJ.js';
1
+ import { C as ContentBuilder, 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, M as Message } from './types-BdWMydUJ.js';
2
+ export { A as AnyPlatformDef, E as EventProducer, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage, U as User } from './types-BdWMydUJ.js';
3
3
  import z__default from 'zod';
4
4
  export { M as ManagedStream, m as mergeStreams, s as stream } from './stream-DGy4geUK.js';
5
5
  import 'hotscript';
package/dist/index.js CHANGED
@@ -3,13 +3,11 @@ import {
3
3
  cloud
4
4
  } from "./chunk-HXM64ENV.js";
5
5
  import {
6
- attachment
7
- } from "./chunk-ZRSCHSLZ.js";
8
- import {
6
+ attachment,
9
7
  custom,
10
8
  mergeStreams,
11
9
  stream
12
- } from "./chunk-V2PK557T.js";
10
+ } from "./chunk-5XW4CAWS.js";
13
11
  import {
14
12
  definePlatform,
15
13
  resolveContents,
@@ -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-DuE2hXuJ.js';
6
+ import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-BdWMydUJ.js';
7
7
  import * as zod_v4_core from 'zod/v4/core';
8
8
  import 'hotscript';
9
9
 
@@ -2,10 +2,11 @@ import {
2
2
  cloud
3
3
  } from "../../chunk-HXM64ENV.js";
4
4
  import {
5
+ asAttachment,
5
6
  asCustom,
6
7
  mergeStreams,
7
8
  stream
8
- } from "../../chunk-V2PK557T.js";
9
+ } from "../../chunk-5XW4CAWS.js";
9
10
  import {
10
11
  asText,
11
12
  definePlatform
@@ -102,23 +103,62 @@ async function disposeCloudAuth(clients) {
102
103
  }
103
104
 
104
105
  // src/providers/imessage/local.ts
106
+ import { createReadStream } from "fs";
105
107
  import { unlink, writeFile } from "fs/promises";
106
108
  import { tmpdir } from "os";
107
109
  import { join } from "path";
110
+ import { Readable } from "stream";
111
+ import {
112
+ readAttachmentBytes
113
+ } from "@photon-ai/imessage-kit";
114
+ var DEFAULT_ATTACHMENT_NAME = "attachment";
108
115
  var toSpace = (message) => ({
109
116
  id: message.chatId,
110
117
  type: message.chatKind === "group" ? "group" : "dm"
111
118
  });
112
- var toMessage = (message) => ({
113
- id: message.id,
114
- content: { type: "text", text: message.text ?? "" },
115
- sender: { id: message.participant ?? "" },
116
- space: toSpace(message),
117
- timestamp: message.createdAt
118
- });
119
- var messages = (client) => stream((emit) => {
119
+ var toMessages = (message) => {
120
+ const base = {
121
+ sender: { id: message.participant ?? "" },
122
+ space: toSpace(message),
123
+ timestamp: message.createdAt
124
+ };
125
+ if (message.attachments.length > 0) {
126
+ return message.attachments.map((att) => {
127
+ const { localPath } = att;
128
+ return {
129
+ ...base,
130
+ id: `${message.id}:${att.id}`,
131
+ content: asAttachment({
132
+ name: att.fileName ?? DEFAULT_ATTACHMENT_NAME,
133
+ mimeType: att.mimeType,
134
+ size: att.sizeBytes,
135
+ read: () => readAttachmentBytes(att),
136
+ stream: localPath ? async () => Readable.toWeb(
137
+ createReadStream(localPath)
138
+ ) : void 0
139
+ })
140
+ };
141
+ });
142
+ }
143
+ return [
144
+ {
145
+ ...base,
146
+ id: message.id,
147
+ content: { type: "text", text: message.text ?? "" }
148
+ }
149
+ ];
150
+ };
151
+ var messages = (client) => stream((emit, end) => {
120
152
  client.startWatching({
121
- onMessage: (message) => emit(toMessage(message))
153
+ onMessage: (message) => {
154
+ try {
155
+ for (const m of toMessages(message)) {
156
+ emit(m);
157
+ }
158
+ } catch (error) {
159
+ end(error);
160
+ }
161
+ }
122
162
  });
123
163
  return () => client.stopWatching();
124
164
  });
@@ -129,7 +169,7 @@ var send = async (client, spaceId, content) => {
129
169
  break;
130
170
  case "attachment": {
131
171
  const tmp = join(tmpdir(), `spectrum-${Date.now()}-${content.name}`);
132
- await writeFile(tmp, content.data);
172
+ await writeFile(tmp, await content.read());
133
173
  try {
134
174
  await client.send(spaceId, { attachments: [tmp] });
135
175
  } finally {
@@ -152,18 +192,38 @@ import {
152
192
  var TAPBACK_NAMES = new Set(
153
193
  Object.values(Reaction).filter((r) => r !== "emoji" && r !== "sticker")
154
194
  );
155
- var toMessage2 = (event) => {
195
+ var baseMessage = (event) => ({
196
+ sender: { id: event.message.sender?.address ?? "" },
197
+ space: {
198
+ id: event.chatGuid,
199
+ type: event.chatGuid.includes(";+;") ? "group" : "dm"
200
+ },
201
+ timestamp: event.timestamp
202
+ });
203
+ var toMessages2 = (client, event) => {
204
+ const base = baseMessage(event);
205
+ const messageGuidStr = event.message.guid;
206
+ if (event.message.attachments.length > 0) {
207
+ return event.message.attachments.map((info) => ({
208
+ ...base,
209
+ id: `${messageGuidStr}:${info.guid}`,
210
+ content: asAttachment({
211
+ name: info.fileName,
212
+ mimeType: info.mimeType,
213
+ size: info.totalBytes,
214
+ read: async () => Buffer.from(await client.attachments.downloadBuffer(info.guid)),
215
+ stream: async () => client.attachments.download(info.guid).stream
216
+ })
217
+ }));
218
+ }
156
219
  const text = event.message.text;
157
- return {
158
- id: event.message.guid,
159
- content: text ? asText(text) : asCustom(event.message),
160
- sender: { id: event.message.sender?.address ?? "" },
161
- space: {
162
- id: event.chatGuid,
163
- type: event.chatGuid.includes(";+;") ? "group" : "dm"
164
- },
165
- timestamp: event.timestamp
166
- };
220
+ return [
221
+ {
222
+ ...base,
223
+ id: messageGuidStr,
224
+ content: text ? asText(text) : asCustom(event.message)
225
+ }
226
+ ];
167
227
  };
168
228
  var clientStream = (client) => {
169
229
  const sub = client.messages.subscribe("message.received");
@@ -171,7 +231,9 @@ var clientStream = (client) => {
171
231
  (async () => {
172
232
  try {
173
233
  for await (const event of sub) {
174
- emit(toMessage2(event));
234
+ for (const message of toMessages2(client, event)) {
235
+ emit(message);
236
+ }
175
237
  }
176
238
  end();
177
239
  } catch (e) {
@@ -207,7 +269,7 @@ var send2 = async (clients, spaceId, content) => {
207
269
  break;
208
270
  case "attachment": {
209
271
  const attachment = await remote.attachments.upload({
210
- data: content.data,
272
+ data: await content.read(),
211
273
  fileName: content.name,
212
274
  mimeType: content.mimeType
213
275
  });
@@ -233,7 +295,7 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
233
295
  break;
234
296
  case "attachment": {
235
297
  const attachment = await remote.attachments.upload({
236
- data: content.data,
298
+ data: await content.read(),
237
299
  fileName: content.name,
238
300
  mimeType: content.mimeType
239
301
  });
@@ -1,4 +1,4 @@
1
- import { d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DuE2hXuJ.js';
1
+ import { d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-BdWMydUJ.js';
2
2
  import * as node_readline from 'node:readline';
3
3
  import z__default from 'zod';
4
4
  import 'hotscript';
@@ -1,7 +1,7 @@
1
1
  import { M as ManagedStream } from '../../stream-DGy4geUK.js';
2
2
  import * as z from 'zod';
3
3
  import z__default from 'zod';
4
- import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DuE2hXuJ.js';
4
+ import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-BdWMydUJ.js';
5
5
  import * as zod_v4_core from 'zod/v4/core';
6
6
  import { WhatsAppClient } from '@photon-ai/whatsapp-business';
7
7
  import 'hotscript';
@@ -1,10 +1,8 @@
1
1
  import {
2
- asAttachment
3
- } from "../../chunk-ZRSCHSLZ.js";
4
- import {
2
+ asAttachment,
5
3
  asCustom,
6
4
  stream
7
- } from "../../chunk-V2PK557T.js";
5
+ } from "../../chunk-5XW4CAWS.js";
8
6
  import {
9
7
  asText,
10
8
  definePlatform
@@ -16,17 +14,14 @@ import {
16
14
  } from "@photon-ai/whatsapp-business";
17
15
 
18
16
  // src/providers/whatsapp-business/messages.ts
19
- var toMessage = async (client, msg) => {
20
- const content = await mapContent(client, msg.content);
21
- return {
22
- id: msg.id,
23
- content,
24
- sender: { id: msg.from },
25
- space: { id: msg.from },
26
- timestamp: msg.timestamp
27
- };
28
- };
29
- var mapContent = async (client, content) => {
17
+ var toMessage = (client, msg) => ({
18
+ id: msg.id,
19
+ content: mapContent(client, msg.content),
20
+ sender: { id: msg.from },
21
+ space: { id: msg.from },
22
+ timestamp: msg.timestamp
23
+ });
24
+ var mapContent = (client, content) => {
30
25
  switch (content.type) {
31
26
  case "text":
32
27
  return asText(content.body);
@@ -34,7 +29,7 @@ var mapContent = async (client, content) => {
34
29
  case "video":
35
30
  case "audio":
36
31
  case "document":
37
- return downloadMedia(client, content.media);
32
+ return lazyMedia(client, content.media);
38
33
  case "sticker":
39
34
  return asCustom({ whatsapp_type: "sticker", ...content.sticker });
40
35
  case "location":
@@ -58,27 +53,26 @@ var mapContent = async (client, content) => {
58
53
  return asCustom({ whatsapp_type: "unknown" });
59
54
  }
60
55
  };
61
- var downloadMedia = async (client, media) => {
62
- try {
63
- const { url } = await client.media.getUrl(media.id);
64
- const response = await fetch(url);
65
- if (!response.ok) {
66
- throw new Error(`Media download failed: ${response.status}`);
67
- }
68
- const data = Buffer.from(await response.arrayBuffer());
69
- return asAttachment({
70
- data,
71
- mimeType: media.mimeType,
72
- name: media.filename ?? `media-${media.id}`
73
- });
74
- } catch {
75
- return asCustom({
76
- whatsapp_type: "media_error",
77
- mediaId: media.id,
78
- mimeType: media.mimeType
79
- });
56
+ var fetchMedia = async (client, mediaId) => {
57
+ const { url } = await client.media.getUrl(mediaId);
58
+ const response = await fetch(url);
59
+ if (!response.ok) {
60
+ throw new Error(`Media download failed: ${response.status}`);
80
61
  }
62
+ return response;
81
63
  };
64
+ var lazyMedia = (client, media) => asAttachment({
65
+ name: media.filename ?? `media-${media.id}`,
66
+ mimeType: media.mimeType,
67
+ read: async () => Buffer.from(await (await fetchMedia(client, media.id)).arrayBuffer()),
68
+ stream: async () => {
69
+ const response = await fetchMedia(client, media.id);
70
+ if (!response.body) {
71
+ throw new Error("Media response missing body");
72
+ }
73
+ return response.body;
74
+ }
75
+ });
82
76
  var mimeToMediaType = (mimeType) => {
83
77
  if (mimeType.startsWith("image/")) {
84
78
  return "image";
@@ -99,8 +93,7 @@ var messages = (client) => {
99
93
  (async () => {
100
94
  try {
101
95
  for await (const event of eventStream) {
102
- const msg = await toMessage(client, event.message);
103
- emit(msg);
96
+ emit(toMessage(client, event.message));
104
97
  }
105
98
  end();
106
99
  } catch (e) {
@@ -117,7 +110,7 @@ var send = async (client, spaceId, content) => {
117
110
  break;
118
111
  case "attachment": {
119
112
  const { mediaId } = await client.media.upload({
120
- file: content.data,
113
+ file: await content.read(),
121
114
  mimeType: content.mimeType,
122
115
  filename: content.name
123
116
  });
@@ -150,7 +143,7 @@ var replyToMessage = async (client, spaceId, messageId, content) => {
150
143
  break;
151
144
  case "attachment": {
152
145
  const { mediaId } = await client.media.upload({
153
- file: content.data,
146
+ file: await content.read(),
154
147
  mimeType: content.mimeType,
155
148
  filename: content.name
156
149
  });
@@ -9,9 +9,11 @@ declare const contentSchema: z__default.ZodDiscriminatedUnion<[z__default.ZodObj
9
9
  raw: z__default.ZodUnknown;
10
10
  }, z__default.core.$strip>, z__default.ZodObject<{
11
11
  type: z__default.ZodLiteral<"attachment">;
12
- data: z__default.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>;
13
- mimeType: z__default.ZodString;
14
12
  name: z__default.ZodString;
13
+ mimeType: z__default.ZodString;
14
+ size: z__default.ZodOptional<z__default.ZodNumber>;
15
+ read: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
16
+ stream: z__default.ZodFunction<z__default.ZodTuple<readonly [], null>, z__default.ZodPromise<z__default.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
15
17
  }, z__default.core.$strip>], "type">;
16
18
  type Content = z__default.infer<typeof contentSchema>;
17
19
  interface ContentBuilder {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spectrum-ts",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -19,9 +19,9 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "@photon-ai/advanced-imessage": "^0.4.2",
22
+ "@photon-ai/advanced-imessage": "^0.4.3",
23
23
  "@photon-ai/whatsapp-business": "^0.1.1",
24
- "@photon-ai/imessage-kit": "^3.0.0-rc.1",
24
+ "@photon-ai/imessage-kit": "^3.0.0-rc.2",
25
25
  "@repeaterjs/repeater": "^3.0.6",
26
26
  "better-grpc": "^0.3.2",
27
27
  "mime-types": "^3.0.1",
@@ -1,73 +0,0 @@
1
- // src/content/custom.ts
2
- import z from "zod";
3
- var customSchema = z.object({
4
- type: z.literal("custom"),
5
- raw: z.unknown()
6
- });
7
- var asCustom = (raw) => customSchema.parse({ type: "custom", raw });
8
- function custom(raw) {
9
- return {
10
- build: async () => asCustom(raw)
11
- };
12
- }
13
-
14
- // src/utils/stream.ts
15
- import { Repeater } from "@repeaterjs/repeater";
16
- function stream(setup) {
17
- const repeater = new Repeater(async (push, stop) => {
18
- const emit = (value) => {
19
- Promise.resolve(push(value)).catch((error) => {
20
- stop(error);
21
- return void 0;
22
- });
23
- };
24
- const end = (error) => {
25
- stop(error);
26
- };
27
- const cleanup = await setup(emit, end);
28
- try {
29
- await stop;
30
- } finally {
31
- await cleanup?.();
32
- }
33
- });
34
- return Object.assign(repeater, {
35
- close: async () => {
36
- await repeater.return(void 0);
37
- }
38
- });
39
- }
40
- function mergeStreams(streams) {
41
- return stream((emit, end) => {
42
- if (streams.length === 0) {
43
- end();
44
- return;
45
- }
46
- let openStreams = streams.length;
47
- const workers = streams.map(async (source) => {
48
- try {
49
- for await (const value of source) {
50
- emit(value);
51
- }
52
- } catch (error) {
53
- end(error);
54
- } finally {
55
- openStreams -= 1;
56
- if (openStreams === 0) {
57
- end();
58
- }
59
- }
60
- });
61
- return async () => {
62
- await Promise.allSettled(streams.map((source) => source.close()));
63
- await Promise.allSettled(workers);
64
- };
65
- });
66
- }
67
-
68
- export {
69
- asCustom,
70
- custom,
71
- stream,
72
- mergeStreams
73
- };
@@ -1,44 +0,0 @@
1
- // src/content/attachment.ts
2
- import { readFile } from "fs/promises";
3
- import { basename } from "path";
4
- import { lookup as lookupMimeType } from "mime-types";
5
- import z from "zod";
6
- var DEFAULT_ATTACHMENT_NAME = "attachment";
7
- var attachmentSchema = z.object({
8
- type: z.literal("attachment"),
9
- data: z.instanceof(Buffer),
10
- mimeType: z.string().nonempty(),
11
- name: z.string().nonempty()
12
- });
13
- var resolveAttachmentName = (input, name) => name || (typeof input === "string" ? basename(input) : DEFAULT_ATTACHMENT_NAME);
14
- var resolveAttachmentMimeType = (name, mimeType) => {
15
- if (mimeType) {
16
- return mimeType;
17
- }
18
- const resolvedMimeType = lookupMimeType(name);
19
- if (!resolvedMimeType) {
20
- throw new Error(
21
- `Unable to resolve MIME type for attachment "${name}". Pass options.mimeType explicitly.`
22
- );
23
- }
24
- return resolvedMimeType;
25
- };
26
- var asAttachment = (input) => attachmentSchema.parse({ type: "attachment", ...input });
27
- function attachment(input, options) {
28
- return {
29
- build: async () => {
30
- const data = typeof input === "string" ? await readFile(input) : input;
31
- const name = resolveAttachmentName(input, options?.name);
32
- return asAttachment({
33
- data,
34
- mimeType: resolveAttachmentMimeType(name, options?.mimeType),
35
- name
36
- });
37
- }
38
- };
39
- }
40
-
41
- export {
42
- asAttachment,
43
- attachment
44
- };