@agentuity/runtime 0.0.42 → 0.0.44
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/AGENTS.md +11 -9
- package/README.md +4 -4
- package/dist/_context.d.ts +12 -4
- package/dist/_context.d.ts.map +1 -1
- package/dist/_server.d.ts +7 -4
- package/dist/_server.d.ts.map +1 -1
- package/dist/_services.d.ts +13 -2
- package/dist/_services.d.ts.map +1 -1
- package/dist/_util.d.ts +1 -1
- package/dist/_util.d.ts.map +1 -1
- package/dist/_waituntil.d.ts +1 -3
- package/dist/_waituntil.d.ts.map +1 -1
- package/dist/agent.d.ts +41 -14
- package/dist/agent.d.ts.map +1 -1
- package/dist/app.d.ts +90 -8
- package/dist/app.d.ts.map +1 -1
- package/dist/eval.d.ts +79 -0
- package/dist/eval.d.ts.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/io/email.d.ts +77 -0
- package/dist/io/email.d.ts.map +1 -0
- package/dist/logger/console.d.ts +21 -1
- package/dist/logger/console.d.ts.map +1 -1
- package/dist/logger/index.d.ts +0 -1
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/user.d.ts +2 -2
- package/dist/logger/user.d.ts.map +1 -1
- package/dist/otel/config.d.ts +3 -1
- package/dist/otel/config.d.ts.map +1 -1
- package/dist/otel/console.d.ts +2 -1
- package/dist/otel/console.d.ts.map +1 -1
- package/dist/otel/exporters/index.d.ts +4 -0
- package/dist/otel/exporters/index.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-log-exporter.d.ts +36 -0
- package/dist/otel/exporters/jsonl-log-exporter.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-metric-exporter.d.ts +40 -0
- package/dist/otel/exporters/jsonl-metric-exporter.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-trace-exporter.d.ts +36 -0
- package/dist/otel/exporters/jsonl-trace-exporter.d.ts.map +1 -0
- package/dist/otel/http.d.ts.map +1 -1
- package/dist/otel/logger.d.ts +15 -11
- package/dist/otel/logger.d.ts.map +1 -1
- package/dist/otel/otel.d.ts +8 -2
- package/dist/otel/otel.d.ts.map +1 -1
- package/dist/router.d.ts +4 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/services/evalrun/composite.d.ts +21 -0
- package/dist/services/evalrun/composite.d.ts.map +1 -0
- package/dist/services/evalrun/http.d.ts +24 -0
- package/dist/services/evalrun/http.d.ts.map +1 -0
- package/dist/services/evalrun/index.d.ts +5 -0
- package/dist/services/evalrun/index.d.ts.map +1 -0
- package/dist/services/evalrun/json.d.ts +21 -0
- package/dist/services/evalrun/json.d.ts.map +1 -0
- package/dist/services/evalrun/local.d.ts +19 -0
- package/dist/services/evalrun/local.d.ts.map +1 -0
- package/dist/services/local/_db.d.ts +4 -0
- package/dist/services/local/_db.d.ts.map +1 -0
- package/dist/services/local/_router.d.ts +3 -0
- package/dist/services/local/_router.d.ts.map +1 -0
- package/dist/services/local/_util.d.ts +18 -0
- package/dist/services/local/_util.d.ts.map +1 -0
- package/dist/services/local/index.d.ts +8 -0
- package/dist/services/local/index.d.ts.map +1 -0
- package/dist/services/local/keyvalue.d.ts +10 -0
- package/dist/services/local/keyvalue.d.ts.map +1 -0
- package/dist/services/local/objectstore.d.ts +11 -0
- package/dist/services/local/objectstore.d.ts.map +1 -0
- package/dist/services/local/stream.d.ts +10 -0
- package/dist/services/local/stream.d.ts.map +1 -0
- package/dist/services/local/vector.d.ts +13 -0
- package/dist/services/local/vector.d.ts.map +1 -0
- package/dist/services/session/composite.d.ts +21 -0
- package/dist/services/session/composite.d.ts.map +1 -0
- package/dist/services/session/http.d.ts +23 -0
- package/dist/services/session/http.d.ts.map +1 -0
- package/dist/services/session/index.d.ts +5 -0
- package/dist/services/session/index.d.ts.map +1 -0
- package/dist/services/session/json.d.ts +22 -0
- package/dist/services/session/json.d.ts.map +1 -0
- package/dist/services/session/local.d.ts +19 -0
- package/dist/services/session/local.d.ts.map +1 -0
- package/dist/session.d.ts +70 -0
- package/dist/session.d.ts.map +1 -0
- package/package.json +10 -6
- package/src/_config.ts +1 -1
- package/src/_context.ts +19 -16
- package/src/_server.ts +284 -42
- package/src/_services.ts +147 -34
- package/src/_util.ts +2 -3
- package/src/_waituntil.ts +5 -153
- package/src/agent.ts +667 -65
- package/src/app.ts +159 -13
- package/src/eval.ts +95 -0
- package/src/index.ts +6 -1
- package/src/io/email.ts +173 -0
- package/src/logger/console.ts +222 -15
- package/src/logger/index.ts +0 -1
- package/src/logger/user.ts +8 -4
- package/src/otel/config.ts +7 -44
- package/src/otel/console.ts +9 -4
- package/src/otel/exporters/README.md +217 -0
- package/src/otel/exporters/index.ts +3 -0
- package/src/otel/exporters/jsonl-log-exporter.ts +113 -0
- package/src/otel/exporters/jsonl-metric-exporter.ts +120 -0
- package/src/otel/exporters/jsonl-trace-exporter.ts +121 -0
- package/src/otel/http.ts +3 -1
- package/src/otel/logger.ts +106 -41
- package/src/otel/otel.ts +43 -22
- package/src/router.ts +44 -4
- package/src/services/evalrun/composite.ts +34 -0
- package/src/services/evalrun/http.ts +112 -0
- package/src/services/evalrun/index.ts +4 -0
- package/src/services/evalrun/json.ts +46 -0
- package/src/services/evalrun/local.ts +28 -0
- package/src/services/local/README.md +1576 -0
- package/src/services/local/_db.ts +182 -0
- package/src/services/local/_router.ts +86 -0
- package/src/services/local/_util.ts +49 -0
- package/src/services/local/index.ts +7 -0
- package/src/services/local/keyvalue.ts +118 -0
- package/src/services/local/objectstore.ts +152 -0
- package/src/services/local/stream.ts +296 -0
- package/src/services/local/vector.ts +264 -0
- package/src/services/session/composite.ts +33 -0
- package/src/services/session/http.ts +64 -0
- package/src/services/session/index.ts +4 -0
- package/src/services/session/json.ts +42 -0
- package/src/services/session/local.ts +28 -0
- package/src/session.ts +284 -0
- package/dist/_unauthenticated.d.ts +0 -26
- package/dist/_unauthenticated.d.ts.map +0 -1
- package/src/_unauthenticated.ts +0 -126
package/src/app.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/** biome-ignore-all lint/suspicious/noExplicitAny: any are ok */
|
|
1
3
|
import { type Env as HonoEnv, Hono } from 'hono';
|
|
2
|
-
import { cors } from 'hono/cors';
|
|
3
|
-
import { createServer, getLogger } from './_server';
|
|
4
|
+
import type { cors } from 'hono/cors';
|
|
4
5
|
import type { Logger } from './logger';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
import { createServer, getLogger } from './_server';
|
|
7
|
+
import type { Meter, Tracer } from '@opentelemetry/api';
|
|
8
|
+
import type {
|
|
9
|
+
KeyValueStorage,
|
|
10
|
+
ObjectStorage,
|
|
11
|
+
SessionEventProvider,
|
|
12
|
+
EvalRunEventProvider,
|
|
13
|
+
StreamStorage,
|
|
14
|
+
VectorStorage,
|
|
15
|
+
SessionStartEvent,
|
|
11
16
|
} from '@agentuity/core';
|
|
17
|
+
import type { Email } from './io/email';
|
|
18
|
+
import type { Agent, AgentContext } from './agent';
|
|
19
|
+
import type { ThreadProvider, SessionProvider, Session, Thread } from './session';
|
|
20
|
+
import type WaitUntilHandler from './_waituntil';
|
|
12
21
|
|
|
13
22
|
type CorsOptions = Parameters<typeof cors>[0];
|
|
14
23
|
|
|
@@ -21,10 +30,42 @@ export interface AppConfig {
|
|
|
21
30
|
* Override the default services
|
|
22
31
|
*/
|
|
23
32
|
services?: {
|
|
33
|
+
/**
|
|
34
|
+
* if true (default false), will use local services and override any others
|
|
35
|
+
*/
|
|
36
|
+
useLocal?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* the KeyValueStorage to override instead of the default
|
|
39
|
+
*/
|
|
24
40
|
keyvalue?: KeyValueStorage;
|
|
41
|
+
/**
|
|
42
|
+
* the ObjectStorage to override instead of the default
|
|
43
|
+
*/
|
|
25
44
|
object?: ObjectStorage;
|
|
45
|
+
/**
|
|
46
|
+
* the StreamStorage to override instead of the default
|
|
47
|
+
*/
|
|
26
48
|
stream?: StreamStorage;
|
|
49
|
+
/**
|
|
50
|
+
* the VectorStorage to override instead of the default
|
|
51
|
+
*/
|
|
27
52
|
vector?: VectorStorage;
|
|
53
|
+
/**
|
|
54
|
+
* the ThreadProvider to override instead of the default
|
|
55
|
+
*/
|
|
56
|
+
thread?: ThreadProvider;
|
|
57
|
+
/**
|
|
58
|
+
* the SessionProvider to override instead of the default
|
|
59
|
+
*/
|
|
60
|
+
session?: SessionProvider;
|
|
61
|
+
/**
|
|
62
|
+
* the SessionEventProvider to override instead of the default
|
|
63
|
+
*/
|
|
64
|
+
sessionEvent?: SessionEventProvider;
|
|
65
|
+
/**
|
|
66
|
+
* the EvalRunEventProvider to override instead of the default
|
|
67
|
+
*/
|
|
68
|
+
evalRunEvent?: EvalRunEventProvider;
|
|
28
69
|
};
|
|
29
70
|
}
|
|
30
71
|
|
|
@@ -32,20 +73,125 @@ export interface Variables {
|
|
|
32
73
|
logger: Logger;
|
|
33
74
|
meter: Meter;
|
|
34
75
|
tracer: Tracer;
|
|
76
|
+
email?: Email;
|
|
77
|
+
sessionId: string;
|
|
78
|
+
thread: Thread;
|
|
79
|
+
session: Session;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type TriggerType = SessionStartEvent['trigger'];
|
|
83
|
+
|
|
84
|
+
export interface PrivateVariables {
|
|
85
|
+
waitUntilHandler: WaitUntilHandler;
|
|
86
|
+
routeId?: string;
|
|
87
|
+
agentIds: Set<string>;
|
|
88
|
+
trigger: TriggerType;
|
|
35
89
|
}
|
|
36
90
|
|
|
37
91
|
export interface Env extends HonoEnv {
|
|
38
92
|
Variables: Variables;
|
|
39
93
|
}
|
|
40
94
|
|
|
95
|
+
type AppEventMap = {
|
|
96
|
+
'agent.started': [Agent<any, any, any>, AgentContext];
|
|
97
|
+
'agent.completed': [Agent<any, any, any>, AgentContext];
|
|
98
|
+
'agent.errored': [Agent<any, any, any>, AgentContext, Error];
|
|
99
|
+
'session.started': [Session];
|
|
100
|
+
'session.completed': [Session];
|
|
101
|
+
'thread.created': [Thread];
|
|
102
|
+
'thread.destroyed': [Thread];
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
type AppEventCallback<K extends keyof AppEventMap> = (
|
|
106
|
+
eventName: K,
|
|
107
|
+
...args: AppEventMap[K]
|
|
108
|
+
) => void | Promise<void>;
|
|
109
|
+
|
|
110
|
+
export class App {
|
|
111
|
+
/**
|
|
112
|
+
* the router instance
|
|
113
|
+
*/
|
|
114
|
+
readonly router: Hono<Env>;
|
|
115
|
+
/**
|
|
116
|
+
* the server instance
|
|
117
|
+
*/
|
|
118
|
+
readonly server: ReturnType<typeof createServer>;
|
|
119
|
+
/**
|
|
120
|
+
* the logger instance
|
|
121
|
+
*/
|
|
122
|
+
readonly logger: Logger;
|
|
123
|
+
|
|
124
|
+
private eventListeners = new Map<keyof AppEventMap, Set<AppEventCallback<any>>>();
|
|
125
|
+
|
|
126
|
+
constructor(config?: AppConfig) {
|
|
127
|
+
this.router = new Hono<Env>();
|
|
128
|
+
this.server = createServer(this.router, config);
|
|
129
|
+
this.logger = getLogger() as Logger;
|
|
130
|
+
setGlobalApp(this);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
addEventListener<K extends keyof AppEventMap>(
|
|
134
|
+
eventName: K,
|
|
135
|
+
callback: AppEventCallback<K>
|
|
136
|
+
): void {
|
|
137
|
+
let callbacks = this.eventListeners.get(eventName);
|
|
138
|
+
if (!callbacks) {
|
|
139
|
+
callbacks = new Set();
|
|
140
|
+
this.eventListeners.set(eventName, callbacks);
|
|
141
|
+
}
|
|
142
|
+
callbacks.add(callback);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
removeEventListener<K extends keyof AppEventMap>(
|
|
146
|
+
eventName: K,
|
|
147
|
+
callback: AppEventCallback<K>
|
|
148
|
+
): void {
|
|
149
|
+
const callbacks = this.eventListeners.get(eventName);
|
|
150
|
+
if (!callbacks) return;
|
|
151
|
+
callbacks.delete(callback);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async fireEvent<K extends keyof AppEventMap>(
|
|
155
|
+
eventName: K,
|
|
156
|
+
...args: AppEventMap[K]
|
|
157
|
+
): Promise<void> {
|
|
158
|
+
const callbacks = this.eventListeners.get(eventName);
|
|
159
|
+
if (!callbacks || callbacks.size === 0) return;
|
|
160
|
+
|
|
161
|
+
for (const callback of callbacks) {
|
|
162
|
+
await callback(eventName, ...args);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let globalApp: App | null = null;
|
|
168
|
+
|
|
169
|
+
function setGlobalApp(app: App): void {
|
|
170
|
+
globalApp = app;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function getApp(): App | null {
|
|
174
|
+
return globalApp;
|
|
175
|
+
}
|
|
176
|
+
|
|
41
177
|
/**
|
|
42
178
|
* create a new app instance
|
|
43
179
|
*
|
|
44
180
|
* @returns App instance
|
|
45
181
|
*/
|
|
46
|
-
export function createApp(config?: AppConfig) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
182
|
+
export function createApp(config?: AppConfig): App {
|
|
183
|
+
return new App(config);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* fire a global event
|
|
188
|
+
*
|
|
189
|
+
* @param eventName
|
|
190
|
+
* @param args
|
|
191
|
+
*/
|
|
192
|
+
export async function fireEvent<K extends keyof AppEventMap>(
|
|
193
|
+
eventName: K,
|
|
194
|
+
...args: AppEventMap[K]
|
|
195
|
+
) {
|
|
196
|
+
await globalApp?.fireEvent(eventName, ...args);
|
|
51
197
|
}
|
package/src/eval.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import type { StandardSchemaV1 } from '@agentuity/core';
|
|
3
|
+
import type { AgentContext } from './agent';
|
|
4
|
+
|
|
5
|
+
// Eval SDK types
|
|
6
|
+
export type EvalContext = AgentContext;
|
|
7
|
+
|
|
8
|
+
export type EvalRunResultMetadata = {
|
|
9
|
+
reason: string;
|
|
10
|
+
// biome-ignore lint/suspicious/noExplicitAny: metadata can contain any type of data
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type EvalRunResultBinary = {
|
|
15
|
+
success: true;
|
|
16
|
+
passed: boolean;
|
|
17
|
+
metadata: EvalRunResultMetadata;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type EvalRunResultScore = {
|
|
21
|
+
success: true;
|
|
22
|
+
score: number; // 0-1 range
|
|
23
|
+
metadata: EvalRunResultMetadata;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type EvalRunResultError = {
|
|
27
|
+
success: false;
|
|
28
|
+
error: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type EvalRunResult = EvalRunResultBinary | EvalRunResultScore | EvalRunResultError;
|
|
32
|
+
|
|
33
|
+
export type CreateEvalRunRequest = {
|
|
34
|
+
projectId: string;
|
|
35
|
+
sessionId: string;
|
|
36
|
+
spanId: string;
|
|
37
|
+
result: EvalRunResult;
|
|
38
|
+
evalId: string;
|
|
39
|
+
promptHash?: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type InternalEvalMetadata = {
|
|
43
|
+
/**
|
|
44
|
+
* the unique identifier for this eval and project
|
|
45
|
+
*/
|
|
46
|
+
id: string;
|
|
47
|
+
/**
|
|
48
|
+
* the folder name for the eval
|
|
49
|
+
*/
|
|
50
|
+
identifier: string;
|
|
51
|
+
/**
|
|
52
|
+
* the relative path to the eval from the root project directory
|
|
53
|
+
*/
|
|
54
|
+
filename: string;
|
|
55
|
+
/**
|
|
56
|
+
* a unique version for the eval. computed as the SHA256 contents of the file.
|
|
57
|
+
*/
|
|
58
|
+
version: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type ExternalEvalMetadata = {
|
|
62
|
+
/**
|
|
63
|
+
* the human readable name for the eval (identifier is used if not specified)
|
|
64
|
+
*/
|
|
65
|
+
name: string;
|
|
66
|
+
/**
|
|
67
|
+
* the human readable description for the eval (empty if not provided)
|
|
68
|
+
*/
|
|
69
|
+
description: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type EvalMetadata = InternalEvalMetadata & ExternalEvalMetadata;
|
|
73
|
+
|
|
74
|
+
type InferSchemaInput<T> = T extends StandardSchemaV1 ? StandardSchemaV1.InferInput<T> : any;
|
|
75
|
+
type InferSchemaOutput<T> = T extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<T> : any;
|
|
76
|
+
|
|
77
|
+
export type EvalFunction<TInput = any, TOutput = any> = TInput extends undefined
|
|
78
|
+
? TOutput extends undefined
|
|
79
|
+
? (ctx: EvalContext) => Promise<EvalRunResult>
|
|
80
|
+
: (ctx: EvalContext, output: TOutput) => Promise<EvalRunResult>
|
|
81
|
+
: TOutput extends undefined
|
|
82
|
+
? (ctx: EvalContext, input: TInput) => Promise<EvalRunResult>
|
|
83
|
+
: (ctx: EvalContext, input: TInput, output: TOutput) => Promise<EvalRunResult>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The Eval handler interface.
|
|
87
|
+
*/
|
|
88
|
+
export type Eval<
|
|
89
|
+
TInput extends StandardSchemaV1 | undefined = any,
|
|
90
|
+
TOutput extends StandardSchemaV1 | undefined = any,
|
|
91
|
+
> = {
|
|
92
|
+
metadata: EvalMetadata;
|
|
93
|
+
handler: EvalFunction<InferSchemaInput<TInput>, InferSchemaOutput<TOutput>>;
|
|
94
|
+
} & (TInput extends StandardSchemaV1 ? { inputSchema: TInput } : { inputSchema?: never }) &
|
|
95
|
+
(TOutput extends StandardSchemaV1 ? { outputSchema: TOutput } : { outputSchema?: never });
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export * from './agent';
|
|
2
2
|
export * from './app';
|
|
3
3
|
export * from './router';
|
|
4
|
+
export * from './eval';
|
|
5
|
+
export * from './session';
|
|
4
6
|
export type { Logger } from './logger';
|
|
5
|
-
export {
|
|
7
|
+
export { getRouter } from './_server';
|
|
8
|
+
export { Email, parseEmail } from './io/email';
|
|
9
|
+
export * from './services/evalrun';
|
|
10
|
+
export { getEvalRunEventProvider } from './_services';
|
package/src/io/email.ts
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { type ParsedMail, type Headers, simpleParser } from 'mailparser';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A class representing an email with common information for processing.
|
|
5
|
+
*
|
|
6
|
+
* This class wraps the parsed email message and provides convenient accessor methods
|
|
7
|
+
* for common email properties like subject, sender, recipient, body content, etc.
|
|
8
|
+
*/
|
|
9
|
+
export class Email {
|
|
10
|
+
private readonly _message: ParsedMail;
|
|
11
|
+
|
|
12
|
+
constructor(data: ParsedMail) {
|
|
13
|
+
this._message = data;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
toString(): string {
|
|
17
|
+
return `[Email id=${this.messageId()},from=${this.fromEmail()},subject=${this.subject()}]`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The date of the email.
|
|
22
|
+
*/
|
|
23
|
+
date(): Date | null {
|
|
24
|
+
return this._message.date ?? null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The message ID of the email.
|
|
29
|
+
*/
|
|
30
|
+
messageId(): string | null {
|
|
31
|
+
return this._message.messageId ?? null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The headers of the email.
|
|
36
|
+
*/
|
|
37
|
+
headers(): Headers {
|
|
38
|
+
return this._message.headers;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The email address of the recipient or null if there is no recipient.
|
|
43
|
+
*
|
|
44
|
+
* If the email has multiple recipients, the email addresses are comma separated.
|
|
45
|
+
*/
|
|
46
|
+
to(): string | null {
|
|
47
|
+
if (!this._message.to) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(this._message.to)) {
|
|
51
|
+
return this._message.to
|
|
52
|
+
.map((addr) => (addr.text ?? '').trim())
|
|
53
|
+
.filter((text) => text.length > 0)
|
|
54
|
+
.join(', ');
|
|
55
|
+
}
|
|
56
|
+
if (typeof this._message.to === 'object' && 'text' in this._message.to) {
|
|
57
|
+
return this._message.to.text ? this._message.to.text.trim() : null;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The email address of the sender or null if there is no sender.
|
|
64
|
+
*/
|
|
65
|
+
fromEmail(): string | null {
|
|
66
|
+
return this._message.from?.value[0]?.address ?? null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The name of the sender or null if there is no name.
|
|
71
|
+
*/
|
|
72
|
+
fromName(): string | null {
|
|
73
|
+
return this._message.from?.value[0]?.name ?? null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The email address of the first recipient or null if there is no recipient.
|
|
78
|
+
*/
|
|
79
|
+
toEmail(): string | null {
|
|
80
|
+
if (!this._message.to) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(this._message.to)) {
|
|
84
|
+
return this._message.to[0]?.value[0]?.address ?? null;
|
|
85
|
+
}
|
|
86
|
+
if (typeof this._message.to === 'object' && 'value' in this._message.to) {
|
|
87
|
+
return this._message.to.value[0]?.address ?? null;
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The name of the first recipient or null if there is no name.
|
|
94
|
+
*/
|
|
95
|
+
toName(): string | null {
|
|
96
|
+
if (!this._message.to) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
if (Array.isArray(this._message.to)) {
|
|
100
|
+
return this._message.to[0]?.value[0]?.name ?? null;
|
|
101
|
+
}
|
|
102
|
+
if (typeof this._message.to === 'object' && 'value' in this._message.to) {
|
|
103
|
+
return this._message.to.value[0]?.name ?? null;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The subject of the email or null if there is no subject.
|
|
110
|
+
*/
|
|
111
|
+
subject(): string | null {
|
|
112
|
+
return this._message.subject ?? null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The plain text body of the email or null if there is no plain text body.
|
|
117
|
+
*/
|
|
118
|
+
text(): string | null {
|
|
119
|
+
return this._message.text ?? null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The HTML body of the email or null if there is no HTML body.
|
|
124
|
+
*/
|
|
125
|
+
html(): string | null {
|
|
126
|
+
return this._message.html ? this._message.html : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The attachments of the email or an empty array if there are no attachments.
|
|
131
|
+
*
|
|
132
|
+
* Note: Attachment handling is minimal in this implementation.
|
|
133
|
+
* For full attachment support with SSRF protection, see the sdk-js implementation.
|
|
134
|
+
*/
|
|
135
|
+
attachments(): Array<{ filename: string; contentType: string }> {
|
|
136
|
+
if (!this._message.attachments || this._message.attachments.length === 0) {
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
return this._message.attachments.map((att: { filename?: string; contentType?: string }) => ({
|
|
140
|
+
filename: att.filename ?? 'unknown',
|
|
141
|
+
contentType: att.contentType ?? 'application/octet-stream',
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Parse an email from a buffer and return an Email object.
|
|
148
|
+
*
|
|
149
|
+
* @param data - The raw RFC822 email message as a Buffer
|
|
150
|
+
* @returns A promise that resolves to an Email object
|
|
151
|
+
* @throws Error if the email cannot be parsed or if the input is not a valid RFC822 message
|
|
152
|
+
*/
|
|
153
|
+
export async function parseEmail(data: Buffer): Promise<Email> {
|
|
154
|
+
if (data.length === 0) {
|
|
155
|
+
throw new Error('Failed to parse email: empty buffer');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const first16KB = data.slice(0, 16384).toString('utf-8', 0, Math.min(data.length, 16384));
|
|
159
|
+
const hasHeaders = /(^|\r?\n)[!-9;-~]+:\s/.test(first16KB);
|
|
160
|
+
|
|
161
|
+
if (!hasHeaders) {
|
|
162
|
+
throw new Error('Failed to parse email: missing headers');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const message = await simpleParser(data);
|
|
167
|
+
return new Email(message);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
throw new Error(
|
|
170
|
+
`Failed to parse email: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|