@amalgm/channels 0.1.1 → 0.1.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.
- package/PURPOSE.md +48 -13
- package/README.md +64 -6
- package/dist/host/auth.js +7 -3
- package/dist/host/auth.js.map +1 -1
- package/dist/host/config.d.ts +3 -1
- package/dist/host/config.js +3 -1
- package/dist/host/config.js.map +1 -1
- package/dist/host/inbox-repository.d.ts +10 -0
- package/dist/host/inbox-repository.js +57 -0
- package/dist/host/inbox-repository.js.map +1 -0
- package/dist/host/index.d.ts +4 -0
- package/dist/host/index.js +4 -0
- package/dist/host/index.js.map +1 -1
- package/dist/host/ingress-repository.d.ts +10 -0
- package/dist/host/ingress-repository.js +61 -0
- package/dist/host/ingress-repository.js.map +1 -0
- package/dist/host/main.js +32 -3
- package/dist/host/main.js.map +1 -1
- package/dist/host/repository.d.ts +4 -3
- package/dist/host/repository.js +23 -3
- package/dist/host/repository.js.map +1 -1
- package/dist/host/resend-webhook.d.ts +14 -0
- package/dist/host/resend-webhook.js +172 -0
- package/dist/host/resend-webhook.js.map +1 -0
- package/dist/host/resend.js +4 -0
- package/dist/host/resend.js.map +1 -1
- package/dist/host/server.d.ts +2 -1
- package/dist/host/server.js +85 -17
- package/dist/host/server.js.map +1 -1
- package/dist/host/wakeups.d.ts +22 -0
- package/dist/host/wakeups.js +30 -0
- package/dist/host/wakeups.js.map +1 -0
- package/dist/src/api-error.d.ts +2 -0
- package/dist/src/api-error.js +13 -0
- package/dist/src/api-error.js.map +1 -0
- package/dist/src/cli/arguments.d.ts +20 -0
- package/dist/src/cli/arguments.js +46 -0
- package/dist/src/cli/arguments.js.map +1 -0
- package/dist/src/cli/input.d.ts +6 -0
- package/dist/src/cli/input.js +38 -0
- package/dist/src/cli/input.js.map +1 -0
- package/dist/src/cli/main.d.ts +7 -0
- package/dist/src/cli/main.js +27 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/run.d.ts +13 -0
- package/dist/src/cli/run.js +47 -0
- package/dist/src/cli/run.js.map +1 -0
- package/dist/src/cli/shell-runtime.d.ts +9 -0
- package/dist/src/cli/shell-runtime.js +106 -0
- package/dist/src/cli/shell-runtime.js.map +1 -0
- package/dist/src/cli-main.d.ts +2 -0
- package/dist/src/cli-main.js +4 -0
- package/dist/src/cli-main.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.js +4 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/client.js +5 -4
- package/dist/src/client.js.map +1 -1
- package/dist/src/command-surface.d.ts +23 -0
- package/dist/src/command-surface.js +53 -0
- package/dist/src/command-surface.js.map +1 -0
- package/dist/src/contract.d.ts +33 -7
- package/dist/src/email/blocks.d.ts +7 -0
- package/dist/src/email/blocks.js +43 -0
- package/dist/src/email/blocks.js.map +1 -0
- package/dist/src/email/escape.d.ts +3 -0
- package/dist/src/email/escape.js +19 -0
- package/dist/src/email/escape.js.map +1 -0
- package/dist/src/email/inbound.d.ts +83 -0
- package/dist/src/email/inbound.js +162 -0
- package/dist/src/email/inbound.js.map +1 -0
- package/dist/src/email/inline.d.ts +1 -0
- package/dist/src/email/inline.js +31 -0
- package/dist/src/email/inline.js.map +1 -0
- package/dist/src/email/markdown.d.ts +1 -0
- package/dist/src/email/markdown.js +117 -0
- package/dist/src/email/markdown.js.map +1 -0
- package/dist/src/email/notification.d.ts +2 -0
- package/dist/src/email/notification.js +18 -0
- package/dist/src/email/notification.js.map +1 -0
- package/dist/src/email/styles.d.ts +33 -0
- package/dist/src/email/styles.js +34 -0
- package/dist/src/email/styles.js.map +1 -0
- package/dist/src/email/system.d.ts +13 -0
- package/dist/src/email/system.js +31 -0
- package/dist/src/email/system.js.map +1 -0
- package/dist/src/email/thread-token.d.ts +8 -0
- package/dist/src/email/thread-token.js +70 -0
- package/dist/src/email/thread-token.js.map +1 -0
- package/dist/src/errors.d.ts +3 -2
- package/dist/src/errors.js +3 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/http.d.ts +2 -0
- package/dist/src/http.js +84 -3
- package/dist/src/http.js.map +1 -1
- package/dist/src/inbox/client.d.ts +7 -0
- package/dist/src/inbox/client.js +79 -0
- package/dist/src/inbox/client.js.map +1 -0
- package/dist/src/inbox/contract.d.ts +37 -0
- package/dist/src/inbox/contract.js +2 -0
- package/dist/src/inbox/contract.js.map +1 -0
- package/dist/src/inbox/events.d.ts +7 -0
- package/dist/src/inbox/events.js +46 -0
- package/dist/src/inbox/events.js.map +1 -0
- package/dist/src/inbox/runner.d.ts +14 -0
- package/dist/src/inbox/runner.js +93 -0
- package/dist/src/inbox/runner.js.map +1 -0
- package/dist/src/inbox/service.d.ts +9 -0
- package/dist/src/inbox/service.js +56 -0
- package/dist/src/inbox/service.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp.js +20 -52
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/service.js +7 -3
- package/dist/src/service.js.map +1 -1
- package/dist/src/validation.d.ts +2 -2
- package/dist/src/validation.js +2 -2
- package/dist/src/validation.js.map +1 -1
- package/dist/src/worker.d.ts +4 -1
- package/dist/src/worker.js +27 -5
- package/dist/src/worker.js.map +1 -1
- package/package.json +12 -5
- package/skills/channels/SKILL.md +14 -14
- package/supabase/migrations/20260903000000_bidirectional_email.sql +630 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { ChannelsError } from '../errors.js';
|
|
3
|
+
export async function readChannelsCliInput(input, ports) {
|
|
4
|
+
if (input.kind === 'empty')
|
|
5
|
+
return {};
|
|
6
|
+
let source;
|
|
7
|
+
try {
|
|
8
|
+
if (input.kind === 'inline')
|
|
9
|
+
source = input.value;
|
|
10
|
+
else if (input.kind === 'file')
|
|
11
|
+
source = await (ports.readFile ?? readFile)(input.filename);
|
|
12
|
+
else
|
|
13
|
+
source = await (ports.readStdin ?? readStdin)();
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
throw new ChannelsError('validation', `Cannot read Channels command input: ${message(error)}`);
|
|
17
|
+
}
|
|
18
|
+
let value;
|
|
19
|
+
try {
|
|
20
|
+
value = JSON.parse(source);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new ChannelsError('validation', 'Channels command input must be valid JSON');
|
|
24
|
+
}
|
|
25
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
26
|
+
throw new ChannelsError('validation', 'Channels command input must be a JSON object');
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
const readFile = (filename) => fs.readFile(filename, 'utf8');
|
|
31
|
+
async function readStdin() {
|
|
32
|
+
const chunks = [];
|
|
33
|
+
for await (const chunk of process.stdin)
|
|
34
|
+
chunks.push(Buffer.from(chunk));
|
|
35
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
36
|
+
}
|
|
37
|
+
const message = (error) => error instanceof Error ? error.message : String(error);
|
|
38
|
+
//# sourceMappingURL=input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../../src/cli/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAQ7C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAuB,EACvB,KAA4B;IAE5B,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,EAAE,CAAC;IACtC,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC;aAC7C,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;;YACvF,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,SAAS,CAAC,EAAE,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,uCAAuC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,2CAA2C,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,8CAA8C,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,KAAgC,CAAC;AAC1C,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAErE,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ChannelsCliIo } from './run.js';
|
|
2
|
+
export interface ChannelsCliMainOptions extends ChannelsCliIo {
|
|
3
|
+
readonly argv?: string[];
|
|
4
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
5
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
6
|
+
}
|
|
7
|
+
export declare function runChannelsCliMain(options?: ChannelsCliMainOptions): Promise<number>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {} from '../command-surface.js';
|
|
2
|
+
import { ChannelsError } from '../errors.js';
|
|
3
|
+
import { runChannelsCli } from './run.js';
|
|
4
|
+
import { createShellChannelsCommands } from './shell-runtime.js';
|
|
5
|
+
export function runChannelsCliMain(options = {}) {
|
|
6
|
+
const argv = options.argv ?? process.argv.slice(2);
|
|
7
|
+
const env = options.env ?? process.env;
|
|
8
|
+
return runChannelsCli(argv, lazyCommands(() => commandsFromEnvironment(env, options.fetch)), options);
|
|
9
|
+
}
|
|
10
|
+
function commandsFromEnvironment(env, fetch) {
|
|
11
|
+
const runtimeUrl = env.AMALGM_CHANNELS_RUNTIME_URL || env.AMALGM_MCP_URL;
|
|
12
|
+
const runtimeToken = env.AMALGM_RUNTIME_TOKEN;
|
|
13
|
+
if (!runtimeUrl || !runtimeToken) {
|
|
14
|
+
throw new ChannelsError('runtime_unavailable', 'A running Amalgm Shell runtime is required (AMALGM_MCP_URL and AMALGM_RUNTIME_TOKEN)');
|
|
15
|
+
}
|
|
16
|
+
return createShellChannelsCommands({ runtimeUrl, runtimeToken, ...(fetch ? { fetch } : {}) });
|
|
17
|
+
}
|
|
18
|
+
function lazyCommands(open) {
|
|
19
|
+
let commands;
|
|
20
|
+
return {
|
|
21
|
+
execute(name, input, context) {
|
|
22
|
+
commands ??= open();
|
|
23
|
+
return commands.execute(name, input, context);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/cli/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAsB,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAQjE,MAAM,UAAU,kBAAkB,CAAC,UAAkC,EAAE;IACrE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,OAAO,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACxG,CAAC;AAED,SAAS,uBAAuB,CAC9B,GAAsB,EACtB,KAA0C;IAE1C,MAAM,UAAU,GAAG,GAAG,CAAC,2BAA2B,IAAI,GAAG,CAAC,cAAc,CAAC;IACzE,MAAM,YAAY,GAAG,GAAG,CAAC,oBAAoB,CAAC;IAC9C,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,EAAE,CAAC;QACjC,MAAM,IAAI,aAAa,CACrB,qBAAqB,EACrB,sFAAsF,CACvF,CAAC;IACJ,CAAC;IACD,OAAO,2BAA2B,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAChG,CAAC;AAED,SAAS,YAAY,CAAC,IAA4B;IAChD,IAAI,QAAsC,CAAC;IAC3C,OAAO;QACL,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO;YAC1B,QAAQ,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ChannelsCommands } from '../command-surface.js';
|
|
2
|
+
import type { Channels } from '../contract.js';
|
|
3
|
+
import { type ChannelsCliInputPorts } from './input.js';
|
|
4
|
+
interface Output {
|
|
5
|
+
write(chunk: string): unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface ChannelsCliIo extends ChannelsCliInputPorts {
|
|
8
|
+
stdout?: Output;
|
|
9
|
+
stderr?: Output;
|
|
10
|
+
}
|
|
11
|
+
export declare const channelsCliHelp = "amalgm channels \u2014 deliberate messages over user channels\n\nUsage:\n amalgm channels send [--input JSON | --file PATH | --stdin]\n amalgm-channels send [--input JSON | --file PATH | --stdin]\n\nCommands (identical to the Channels MCP task surface):\n send Send one durable message to the current user\n\nInput is one JSON object with message, channel, and optional title and\nidempotency_key fields. The current channel is \"email\". Output is one JSON\nsuccess or error envelope. The recipient is always the signed-in user.\n";
|
|
12
|
+
export declare function runChannelsCli(argv: string[], backend: Channels | ChannelsCommands, io?: ChannelsCliIo): Promise<number>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createChannelsCommands } from '../command-surface.js';
|
|
2
|
+
import { ChannelsError } from '../errors.js';
|
|
3
|
+
import { parseChannelsCliArguments } from './arguments.js';
|
|
4
|
+
import { readChannelsCliInput } from './input.js';
|
|
5
|
+
export const channelsCliHelp = `amalgm channels — deliberate messages over user channels
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
amalgm channels send [--input JSON | --file PATH | --stdin]
|
|
9
|
+
amalgm-channels send [--input JSON | --file PATH | --stdin]
|
|
10
|
+
|
|
11
|
+
Commands (identical to the Channels MCP task surface):
|
|
12
|
+
send Send one durable message to the current user
|
|
13
|
+
|
|
14
|
+
Input is one JSON object with message, channel, and optional title and
|
|
15
|
+
idempotency_key fields. The current channel is "email". Output is one JSON
|
|
16
|
+
success or error envelope. The recipient is always the signed-in user.
|
|
17
|
+
`;
|
|
18
|
+
export async function runChannelsCli(argv, backend, io = {}) {
|
|
19
|
+
const stdout = io.stdout ?? process.stdout;
|
|
20
|
+
const stderr = io.stderr ?? process.stderr;
|
|
21
|
+
try {
|
|
22
|
+
const parsed = parseChannelsCliArguments(argv);
|
|
23
|
+
if (parsed.kind === 'help') {
|
|
24
|
+
stdout.write(channelsCliHelp);
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
const input = await readChannelsCliInput(parsed.input, io);
|
|
28
|
+
const commands = isCommands(backend) ? backend : createChannelsCommands(backend);
|
|
29
|
+
stdout.write(`${JSON.stringify({ result: await commands.execute(parsed.command, input) })}\n`);
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
stderr.write(`${JSON.stringify(failure(error))}\n`);
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function isCommands(value) {
|
|
38
|
+
return 'execute' in value && typeof value.execute === 'function';
|
|
39
|
+
}
|
|
40
|
+
function failure(error) {
|
|
41
|
+
return { error: {
|
|
42
|
+
code: error instanceof ChannelsError ? error.code : 'internal',
|
|
43
|
+
message: error instanceof Error ? error.message : String(error),
|
|
44
|
+
...(error instanceof ChannelsError && error.status !== undefined ? { status: error.status } : {}),
|
|
45
|
+
} };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAyB,MAAM,uBAAuB,CAAC;AAEtF,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAA8B,MAAM,YAAY,CAAC;AAS9E,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;CAY9B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAc,EACd,OAAoC,EACpC,KAAoB,EAAE;IAEtB,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAC3C,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAC9B,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;QACjF,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC/F,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;QACpD,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAkC;IACpD,OAAO,SAAS,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,CAAC;AACnE,CAAC;AAED,SAAS,OAAO,CAAC,KAAc;IAC7B,OAAO,EAAE,KAAK,EAAE;YACd,IAAI,EAAE,KAAK,YAAY,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU;YAC9D,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAC/D,GAAG,CAAC,KAAK,YAAY,aAAa,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClG,EAAE,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ChannelsCommands } from '../command-surface.js';
|
|
2
|
+
export interface ShellChannelsCommandOptions {
|
|
3
|
+
readonly runtimeUrl: string;
|
|
4
|
+
readonly runtimeToken: string;
|
|
5
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
6
|
+
readonly requestTimeoutMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function createShellChannelsCommands(options: ShellChannelsCommandOptions): ChannelsCommands;
|
|
9
|
+
export declare function shellChannelsEndpoint(runtimeUrl: string): string;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { channelsCommandDefinition, } from '../command-surface.js';
|
|
2
|
+
import { ChannelsError } from '../errors.js';
|
|
3
|
+
export function createShellChannelsCommands(options) {
|
|
4
|
+
const endpoint = shellChannelsEndpoint(options.runtimeUrl);
|
|
5
|
+
const token = options.runtimeToken.trim();
|
|
6
|
+
if (!token)
|
|
7
|
+
throw new ChannelsError('validation', 'AMALGM_RUNTIME_TOKEN is required');
|
|
8
|
+
const request = options.fetch ?? globalThis.fetch;
|
|
9
|
+
const timeout = options.requestTimeoutMs ?? 15_000;
|
|
10
|
+
let requestId = 0;
|
|
11
|
+
return Object.freeze({
|
|
12
|
+
async execute(name, input = {}) {
|
|
13
|
+
const definition = channelsCommandDefinition(name);
|
|
14
|
+
const id = `amalgm-channels-cli-${++requestId}`;
|
|
15
|
+
let response;
|
|
16
|
+
try {
|
|
17
|
+
response = await request(endpoint, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: {
|
|
20
|
+
accept: 'application/json',
|
|
21
|
+
'content-type': 'application/json',
|
|
22
|
+
'x-amalgm-runtime-token': token,
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
jsonrpc: '2.0', id, method: 'tools/call',
|
|
26
|
+
params: { name: definition.mcpName, arguments: input },
|
|
27
|
+
}),
|
|
28
|
+
signal: AbortSignal.timeout(timeout),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw new ChannelsError('runtime_transport', `Amalgm Shell runtime request failed: ${message(error)}`);
|
|
33
|
+
}
|
|
34
|
+
const payload = await jsonResponse(response);
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
throw new ChannelsError(response.status === 401 ? 'runtime_unauthorized' : 'runtime_transport', response.status === 401
|
|
37
|
+
? 'The Amalgm Shell runtime rejected the local admission token'
|
|
38
|
+
: `Amalgm Shell runtime returned ${response.status}`, response.status);
|
|
39
|
+
}
|
|
40
|
+
if (!payload || payload.jsonrpc !== '2.0' || payload.id !== id) {
|
|
41
|
+
throw new ChannelsError('runtime_protocol', 'Amalgm Shell runtime returned invalid JSON-RPC');
|
|
42
|
+
}
|
|
43
|
+
if (payload.error) {
|
|
44
|
+
throw new ChannelsError('runtime_protocol', payload.error.message || 'Amalgm Shell runtime failed');
|
|
45
|
+
}
|
|
46
|
+
return toolResult(payload.result);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function shellChannelsEndpoint(runtimeUrl) {
|
|
51
|
+
let url;
|
|
52
|
+
try {
|
|
53
|
+
url = new URL(runtimeUrl);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
throw new ChannelsError('validation', 'AMALGM_MCP_URL must be an absolute loopback URL');
|
|
57
|
+
}
|
|
58
|
+
const loopback = ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
|
|
59
|
+
if (!loopback || !['http:', 'https:'].includes(url.protocol) || url.username || url.password) {
|
|
60
|
+
throw new ChannelsError('validation', 'AMALGM_MCP_URL must be an absolute loopback URL');
|
|
61
|
+
}
|
|
62
|
+
if (!url.pathname.endsWith('/mcp/channels'))
|
|
63
|
+
url.pathname = '/mcp/channels';
|
|
64
|
+
url.search = '';
|
|
65
|
+
url.hash = '';
|
|
66
|
+
return url.toString();
|
|
67
|
+
}
|
|
68
|
+
async function jsonResponse(response) {
|
|
69
|
+
const bytes = new Uint8Array(await response.arrayBuffer().catch((error) => {
|
|
70
|
+
throw new ChannelsError('runtime_transport', `Cannot read Amalgm Shell runtime response: ${message(error)}`);
|
|
71
|
+
}));
|
|
72
|
+
if (bytes.byteLength > 2 * 1024 * 1024) {
|
|
73
|
+
throw new ChannelsError('runtime_protocol', 'Amalgm Shell runtime response is too large');
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(Buffer.from(bytes).toString('utf8'));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function toolResult(value) {
|
|
83
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
84
|
+
throw new ChannelsError('runtime_protocol', 'Channels MCP returned an invalid tool result');
|
|
85
|
+
}
|
|
86
|
+
const result = value;
|
|
87
|
+
if (result.isError === true) {
|
|
88
|
+
const error = result.structuredContent?.error;
|
|
89
|
+
throw new ChannelsError(channelsErrorCode(error?.code), typeof error?.message === 'string' ? error.message : 'Channels command failed', typeof error?.status === 'number' ? error.status : undefined);
|
|
90
|
+
}
|
|
91
|
+
if (!result.structuredContent || !Object.hasOwn(result.structuredContent, 'result')) {
|
|
92
|
+
throw new ChannelsError('runtime_protocol', 'Channels MCP returned no structured result');
|
|
93
|
+
}
|
|
94
|
+
return result.structuredContent.result;
|
|
95
|
+
}
|
|
96
|
+
function channelsErrorCode(value) {
|
|
97
|
+
const known = [
|
|
98
|
+
'validation', 'forbidden', 'not_found', 'provider', 'internal',
|
|
99
|
+
'runtime_unavailable', 'runtime_transport', 'runtime_unauthorized', 'runtime_protocol',
|
|
100
|
+
];
|
|
101
|
+
return typeof value === 'string' && known.includes(value)
|
|
102
|
+
? value
|
|
103
|
+
: 'internal';
|
|
104
|
+
}
|
|
105
|
+
const message = (error) => error instanceof Error ? error.message : String(error);
|
|
106
|
+
//# sourceMappingURL=shell-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-runtime.js","sourceRoot":"","sources":["../../../src/cli/shell-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-main.js","sourceRoot":"","sources":["../../src/cli-main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,CAAC,QAAQ,GAAG,MAAM,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { channelsCliHelp, runChannelsCli, type ChannelsCliIo } from './cli/run.js';
|
|
2
|
+
export { createShellChannelsCommands, shellChannelsEndpoint, type ShellChannelsCommandOptions, } from './cli/shell-runtime.js';
|
|
3
|
+
export { runChannelsCliMain, type ChannelsCliMainOptions } from './cli/main.js';
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAsB,MAAM,cAAc,CAAC;AACnF,OAAO,EACL,2BAA2B,EAC3B,qBAAqB,GAEtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAA+B,MAAM,eAAe,CAAC"}
|
package/dist/src/client.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ChannelsError } from './errors.js';
|
|
2
|
+
import { channelsApiError } from './api-error.js';
|
|
2
3
|
export function createChannelsClient(options) {
|
|
3
4
|
const base = options.baseUrl.replace(/\/$/, '');
|
|
4
5
|
const fetch = options.fetch ?? globalThis.fetch;
|
|
5
|
-
async function request(path, method, body) {
|
|
6
|
+
async function request(path, method, body, extraHeaders = {}) {
|
|
6
7
|
const url = `${base}${path}`;
|
|
7
8
|
const response = await fetch(url, {
|
|
8
9
|
method,
|
|
@@ -10,17 +11,17 @@ export function createChannelsClient(options) {
|
|
|
10
11
|
accept: 'application/json',
|
|
11
12
|
...(body === undefined ? {} : { 'content-type': 'application/json' }),
|
|
12
13
|
...await options.headers(method, url),
|
|
14
|
+
...extraHeaders,
|
|
13
15
|
},
|
|
14
16
|
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
15
17
|
});
|
|
16
18
|
const payload = await response.json().catch(() => ({}));
|
|
17
19
|
if (!response.ok)
|
|
18
|
-
throw
|
|
19
|
-
? payload.code : response.status >= 500 ? 'internal' : 'validation', payload.error ?? `Channels API returned ${response.status}`);
|
|
20
|
+
throw channelsApiError(response.status, payload);
|
|
20
21
|
return payload;
|
|
21
22
|
}
|
|
22
23
|
return Object.freeze({
|
|
23
|
-
|
|
24
|
+
send: (input, context = {}) => request('/v1/messages', 'POST', input, context.sessionId ? { 'x-amalgm-session-id': context.sessionId } : {}),
|
|
24
25
|
list: (query = {}) => request(`/v1/deliveries${queryString(query)}`, 'GET'),
|
|
25
26
|
get: async (deliveryId) => {
|
|
26
27
|
try {
|
package/dist/src/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAOlD,MAAM,UAAU,oBAAoB,CAAC,OAIpC;IACC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IAEhD,KAAK,UAAU,OAAO,CACpB,IAAY,EACZ,MAAc,EACd,IAAc,EACd,eAAiD,EAAE;QAEnD,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM;YACN,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;gBACrE,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;gBACrC,GAAG,YAAY;aAChB;YACD,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAsC,CAAC;QAC7F,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,gBAAgB,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnE,OAAO,OAAY,CAAC;IACtB,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,CAAC,KAAuB,EAAE,UAA8B,EAAE,EAAE,EAAE,CAAC,OAAO,CAC1E,cAAc,EACd,MAAM,EACN,KAAK,EACL,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CACtE;QACD,IAAI,EAAE,CAAC,QAAwB,EAAE,EAAE,EAAE,CAAC,OAAO,CAAe,iBAAiB,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC;QACzG,GAAG,EAAE,KAAK,EAAE,UAAkB,EAAE,EAAE;YAChC,IAAI,CAAC;gBACH,OAAO,MAAM,OAAO,CAAW,kBAAkB,kBAAkB,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC5F,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,KAAK,YAAY,aAAa,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;oBAAE,OAAO,IAAI,CAAC;gBAC9E,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,KAAqB;IACxC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IACjF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9G,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod/v3';
|
|
2
|
+
import type { ChannelSendContext, Channels } from './contract.js';
|
|
3
|
+
export type ChannelsCommandName = 'send';
|
|
4
|
+
export interface ChannelsCommandDefinition {
|
|
5
|
+
readonly name: ChannelsCommandName;
|
|
6
|
+
readonly mcpName: 'amalgm_channels_send';
|
|
7
|
+
readonly title: string;
|
|
8
|
+
readonly description: string;
|
|
9
|
+
readonly inputShape: z.ZodRawShape;
|
|
10
|
+
readonly annotations: Readonly<{
|
|
11
|
+
readOnlyHint: boolean;
|
|
12
|
+
destructiveHint: boolean;
|
|
13
|
+
idempotentHint: boolean;
|
|
14
|
+
openWorldHint: boolean;
|
|
15
|
+
}>;
|
|
16
|
+
invoke(channels: Channels, input: unknown, context?: ChannelSendContext): Promise<unknown>;
|
|
17
|
+
}
|
|
18
|
+
export interface ChannelsCommands {
|
|
19
|
+
execute(name: ChannelsCommandName, input?: unknown, context?: ChannelSendContext): Promise<unknown>;
|
|
20
|
+
}
|
|
21
|
+
export declare const channelsCommandDefinitions: readonly ChannelsCommandDefinition[];
|
|
22
|
+
export declare function channelsCommandDefinition(name: string): ChannelsCommandDefinition;
|
|
23
|
+
export declare function createChannelsCommands(channels: Channels): ChannelsCommands;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod/v3';
|
|
2
|
+
import { ChannelsError } from './errors.js';
|
|
3
|
+
const sendSchema = z.object({
|
|
4
|
+
message: z.string().min(1).max(4_000).describe('Message body in Markdown.'),
|
|
5
|
+
title: z.string().min(1).max(160).optional().describe('Short message title.'),
|
|
6
|
+
channel: z.enum(['email']).describe('External channel. Email is currently supported.'),
|
|
7
|
+
idempotency_key: z.string().min(1).max(200).optional()
|
|
8
|
+
.describe('Stable key for safe retries of this exact message.'),
|
|
9
|
+
}).strict();
|
|
10
|
+
export const channelsCommandDefinitions = Object.freeze([
|
|
11
|
+
Object.freeze({
|
|
12
|
+
name: 'send',
|
|
13
|
+
mcpName: 'amalgm_channels_send',
|
|
14
|
+
title: 'Send to current user',
|
|
15
|
+
description: 'Send one deliberate, durable message to the current Amalgm user over the selected channel. Ordinary assistant output is not delivered. The caller cannot select another recipient.',
|
|
16
|
+
inputShape: sendSchema.shape,
|
|
17
|
+
annotations: Object.freeze({
|
|
18
|
+
readOnlyHint: false,
|
|
19
|
+
destructiveHint: false,
|
|
20
|
+
idempotentHint: true,
|
|
21
|
+
openWorldHint: true,
|
|
22
|
+
}),
|
|
23
|
+
async invoke(channels, input, context = {}) {
|
|
24
|
+
const value = parse(sendSchema, input);
|
|
25
|
+
return channels.send({
|
|
26
|
+
message: value.message,
|
|
27
|
+
channel: value.channel,
|
|
28
|
+
...(value.title === undefined ? {} : { title: value.title }),
|
|
29
|
+
...(value.idempotency_key === undefined ? {} : { idempotencyKey: value.idempotency_key }),
|
|
30
|
+
}, context);
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
]);
|
|
34
|
+
export function channelsCommandDefinition(name) {
|
|
35
|
+
const definition = channelsCommandDefinitions.find((candidate) => candidate.name === name);
|
|
36
|
+
if (!definition)
|
|
37
|
+
throw new ChannelsError('validation', `Unknown Channels command: ${name}`);
|
|
38
|
+
return definition;
|
|
39
|
+
}
|
|
40
|
+
export function createChannelsCommands(channels) {
|
|
41
|
+
return Object.freeze({
|
|
42
|
+
execute(name, input = {}, context = {}) {
|
|
43
|
+
return channelsCommandDefinition(name).invoke(channels, input, context);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function parse(schema, value) {
|
|
48
|
+
const result = schema.safeParse(value);
|
|
49
|
+
if (result.success)
|
|
50
|
+
return result.data;
|
|
51
|
+
throw new ChannelsError('validation', result.error.issues.map(({ path, message }) => (`${path.length ? path.join('.') : 'input'}: ${message}`)).join('; '));
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=command-surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-surface.js","sourceRoot":"","sources":["../../src/command-surface.ts"],"names":[],"mappings":"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"}
|
package/dist/src/contract.d.ts
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
export type ChannelScope = 'channels:read' | 'channels:send';
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
1
|
+
export type ChannelScope = 'channels:read' | 'channels:send' | 'channels:receive';
|
|
2
|
+
export type ChannelType = 'email';
|
|
3
|
+
export type ChannelPreference = 'auto' | ChannelType;
|
|
4
|
+
export type DeliveryStatus = 'pending' | 'sending' | 'sent' | 'delivered' | 'failed';
|
|
4
5
|
export interface ChannelPrincipal {
|
|
5
6
|
readonly userId: string;
|
|
7
|
+
readonly computerId?: string;
|
|
6
8
|
readonly scopes: readonly ChannelScope[];
|
|
7
9
|
}
|
|
8
|
-
export interface
|
|
10
|
+
export interface SendMessageInput {
|
|
9
11
|
readonly message: string;
|
|
10
12
|
readonly title?: string;
|
|
11
13
|
readonly channel?: ChannelPreference;
|
|
12
14
|
readonly idempotencyKey?: string;
|
|
13
15
|
}
|
|
16
|
+
/** Trusted local context. This is never part of the agent-visible tool input. */
|
|
17
|
+
export interface ChannelSendContext {
|
|
18
|
+
readonly sessionId?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface NormalizedSendMessage {
|
|
21
|
+
readonly message: string;
|
|
22
|
+
readonly title: string;
|
|
23
|
+
readonly channel: ChannelPreference;
|
|
24
|
+
readonly idempotencyKey: string;
|
|
25
|
+
}
|
|
14
26
|
export interface Delivery {
|
|
15
27
|
readonly id: string;
|
|
16
28
|
readonly channel: Exclude<ChannelPreference, 'auto'>;
|
|
@@ -23,6 +35,8 @@ export interface Delivery {
|
|
|
23
35
|
readonly updatedAt: string;
|
|
24
36
|
readonly deliveredAt?: string;
|
|
25
37
|
readonly providerId?: string;
|
|
38
|
+
readonly threadId?: string;
|
|
39
|
+
readonly sessionId?: string;
|
|
26
40
|
readonly error?: string;
|
|
27
41
|
}
|
|
28
42
|
export interface DeliveryPage {
|
|
@@ -43,7 +57,7 @@ export interface NormalizedListDeliveries {
|
|
|
43
57
|
readonly offset: number;
|
|
44
58
|
}
|
|
45
59
|
export interface Channels {
|
|
46
|
-
|
|
60
|
+
send(input: SendMessageInput, context?: ChannelSendContext): Promise<Delivery>;
|
|
47
61
|
list(query?: ListDeliveries): Promise<DeliveryPage>;
|
|
48
62
|
get(deliveryId: string): Promise<Delivery | null>;
|
|
49
63
|
}
|
|
@@ -59,14 +73,23 @@ export interface PendingDelivery {
|
|
|
59
73
|
readonly idempotencyKey: string;
|
|
60
74
|
readonly leaseToken: string;
|
|
61
75
|
readonly attempts: number;
|
|
76
|
+
readonly thread: Readonly<{
|
|
77
|
+
id: string;
|
|
78
|
+
sessionId: string;
|
|
79
|
+
subject: string;
|
|
80
|
+
messageId: string;
|
|
81
|
+
replyToMessageId?: string;
|
|
82
|
+
references: readonly string[];
|
|
83
|
+
}>;
|
|
62
84
|
}
|
|
63
85
|
export interface DeliveryRepository {
|
|
64
|
-
enqueue(userId: string, input:
|
|
86
|
+
enqueue(userId: string, computerId: string | undefined, input: NormalizedSendMessage, context: ChannelSendContext): Promise<Delivery>;
|
|
65
87
|
list(userId: string, query: NormalizedListDeliveries): Promise<DeliveryPage>;
|
|
66
88
|
get(userId: string, deliveryId: string): Promise<Delivery | null>;
|
|
67
89
|
claim(limit: number, leaseSeconds: number): Promise<readonly PendingDelivery[]>;
|
|
68
|
-
|
|
90
|
+
markSent(delivery: PendingDelivery, providerId: string, now: Date): Promise<boolean>;
|
|
69
91
|
fail(delivery: PendingDelivery, error: string, now: Date): Promise<boolean>;
|
|
92
|
+
nextWorkAt(): Promise<Date | null>;
|
|
70
93
|
}
|
|
71
94
|
export interface RecipientDirectory {
|
|
72
95
|
emailForUser(userId: string): Promise<string>;
|
|
@@ -76,7 +99,10 @@ export interface EmailProvider {
|
|
|
76
99
|
to: string;
|
|
77
100
|
subject: string;
|
|
78
101
|
text: string;
|
|
102
|
+
html: string;
|
|
79
103
|
idempotencyKey: string;
|
|
104
|
+
replyTo?: string;
|
|
105
|
+
headers?: Readonly<Record<string, string>>;
|
|
80
106
|
}>): Promise<{
|
|
81
107
|
readonly providerId: string;
|
|
82
108
|
}>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function paragraph(lines: readonly string[]): string;
|
|
2
|
+
export declare function heading(level: number, text: string): string;
|
|
3
|
+
export declare function list(ordered: boolean, items: readonly string[]): string;
|
|
4
|
+
export declare function quote(lines: readonly string[]): string;
|
|
5
|
+
export declare function codeBlock(language: string, source: string): string;
|
|
6
|
+
export declare function divider(): string;
|
|
7
|
+
export declare function table(rows: readonly (readonly string[])[]): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { escapeText } from './escape.js';
|
|
2
|
+
import { renderInline } from './inline.js';
|
|
3
|
+
import { BLOCK, EMAIL } from './styles.js';
|
|
4
|
+
export function paragraph(lines) {
|
|
5
|
+
return `<p style="margin:0;line-height:${BLOCK.paragraphLineHeight};color:${EMAIL.color.text}">${renderInline(lines.join(' '))}</p>`;
|
|
6
|
+
}
|
|
7
|
+
export function heading(level, text) {
|
|
8
|
+
const safeLevel = Math.min(Math.max(level, 1), 6);
|
|
9
|
+
const size = BLOCK.headingSizes[safeLevel - 1];
|
|
10
|
+
return `<h${safeLevel} style="margin:0;font-size:${size}px;font-weight:${BLOCK.headingWeight};color:${EMAIL.color.text};line-height:${BLOCK.headingLineHeight}">${renderInline(text)}</h${safeLevel}>`;
|
|
11
|
+
}
|
|
12
|
+
export function list(ordered, items) {
|
|
13
|
+
const tag = ordered ? 'ol' : 'ul';
|
|
14
|
+
const children = items.map((item) => `<li style="margin:4px 0;padding:${BLOCK.listItemPaddingY}px 0;line-height:${BLOCK.listItemLineHeight};color:${EMAIL.color.text}">${renderInline(item)}</li>`).join('');
|
|
15
|
+
return `<${tag} style="margin:0;padding-left:${BLOCK.listPaddingLeft}px;color:${EMAIL.color.text}">${children}</${tag}>`;
|
|
16
|
+
}
|
|
17
|
+
export function quote(lines) {
|
|
18
|
+
return `<blockquote style="margin:0;line-height:1.75;font-style:italic;padding:0 0 0 ${BLOCK.quotePaddingLeft}px;border-left:3px solid ${EMAIL.color.grid};color:${EMAIL.color.secondary}">${renderInline(lines.join(' '))}</blockquote>`;
|
|
19
|
+
}
|
|
20
|
+
export function codeBlock(language, source) {
|
|
21
|
+
const label = escapeText(language.trim().toLowerCase() || 'text');
|
|
22
|
+
return `<div style="background:${EMAIL.color.background};border:1px solid ${EMAIL.color.border};border-radius:${BLOCK.codeRadius}px;overflow:hidden;margin:0">` +
|
|
23
|
+
`<div style="padding:7.5px ${BLOCK.codePadding}px;border-bottom:1px solid ${EMAIL.color.border};font-size:11.25px;color:${EMAIL.color.muted};font-family:${EMAIL.font.mono};text-transform:lowercase">${label}</div>` +
|
|
24
|
+
`<pre style="background:${EMAIL.color.background};padding:${BLOCK.codePadding}px;font-size:12px;font-family:${EMAIL.font.mono};color:${EMAIL.color.text};overflow-x:auto;margin:0;line-height:1.6"><code>${escapeText(source.trimEnd())}</code></pre></div>`;
|
|
25
|
+
}
|
|
26
|
+
export function divider() {
|
|
27
|
+
return `<hr style="border:0;border-top:1px solid ${EMAIL.color.border};margin:0">`;
|
|
28
|
+
}
|
|
29
|
+
export function table(rows) {
|
|
30
|
+
const width = Math.max(...rows.map((row) => row.length));
|
|
31
|
+
const body = rows.map((row, rowIndex) => {
|
|
32
|
+
const tag = rowIndex === 0 ? 'th' : 'td';
|
|
33
|
+
const cells = Array.from({ length: width }, (_, column) => {
|
|
34
|
+
const right = column === width - 1 ? '' : `border-right:1px solid ${EMAIL.color.grid};`;
|
|
35
|
+
const bottom = rowIndex === rows.length - 1 ? '' : `border-bottom:1px solid ${EMAIL.color.grid};`;
|
|
36
|
+
const header = rowIndex === 0 ? 'background:#0c0b0a;font-weight:500;' : '';
|
|
37
|
+
return `<${tag} style="padding:${BLOCK.tableCellPaddingY}px ${BLOCK.tableCellPaddingX}px;text-align:left;vertical-align:top;font-size:14px;line-height:1.5;${right}${bottom}${header}color:${EMAIL.color.text}">${renderInline(row[column] ?? '')}</${tag}>`;
|
|
38
|
+
}).join('');
|
|
39
|
+
return `<tr>${cells}</tr>`;
|
|
40
|
+
}).join('');
|
|
41
|
+
return `<div style="border:1px solid ${EMAIL.color.grid};border-radius:${BLOCK.tableRadius}px;overflow:hidden;margin:0"><table style="width:100%;border-collapse:collapse">${body}</table></div>`;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../../src/email/blocks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,UAAU,SAAS,CAAC,KAAwB;IAChD,OAAO,kCAAkC,KAAK,CAAC,mBAAmB,UAAU,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACvI,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,IAAY;IACjD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAC/C,OAAO,KAAK,SAAS,8BAA8B,IAAI,kBAAkB,KAAK,CAAC,aAAa,UAAU,KAAK,CAAC,KAAK,CAAC,IAAI,gBAAgB,KAAK,CAAC,iBAAiB,KAAK,YAAY,CAAC,IAAI,CAAC,MAAM,SAAS,GAAG,CAAC;AACzM,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,OAAgB,EAAE,KAAwB;IAC7D,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAClC,mCAAmC,KAAK,CAAC,gBAAgB,oBAAoB,KAAK,CAAC,kBAAkB,UAAU,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,IAAI,CAAC,OAAO,CAC9J,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,OAAO,IAAI,GAAG,iCAAiC,KAAK,CAAC,eAAe,YAAY,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,KAAK,GAAG,GAAG,CAAC;AAC3H,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,KAAwB;IAC5C,OAAO,gFAAgF,KAAK,CAAC,gBAAgB,4BAA4B,KAAK,CAAC,KAAK,CAAC,IAAI,UAAU,KAAK,CAAC,KAAK,CAAC,SAAS,KAAK,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,eAAe,CAAC;AAC5O,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,MAAc;IACxD,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,CAAC;IAClE,OAAO,0BAA0B,KAAK,CAAC,KAAK,CAAC,UAAU,qBAAqB,KAAK,CAAC,KAAK,CAAC,MAAM,kBAAkB,KAAK,CAAC,UAAU,+BAA+B;QAC7J,6BAA6B,KAAK,CAAC,WAAW,8BAA8B,KAAK,CAAC,KAAK,CAAC,MAAM,4BAA4B,KAAK,CAAC,KAAK,CAAC,KAAK,gBAAgB,KAAK,CAAC,IAAI,CAAC,IAAI,8BAA8B,KAAK,QAAQ;QACrN,0BAA0B,KAAK,CAAC,KAAK,CAAC,UAAU,YAAY,KAAK,CAAC,WAAW,iCAAiC,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,KAAK,CAAC,KAAK,CAAC,IAAI,oDAAoD,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,qBAAqB,CAAC;AACjQ,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,OAAO,4CAA4C,KAAK,CAAC,KAAK,CAAC,MAAM,aAAa,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAoC;IACxD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;QACtC,MAAM,GAAG,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACzC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YACxD,MAAM,KAAK,GAAG,MAAM,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,0BAA0B,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC;YACxF,MAAM,MAAM,GAAG,QAAQ,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,2BAA2B,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC;YAClG,MAAM,MAAM,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3E,OAAO,IAAI,GAAG,mBAAmB,KAAK,CAAC,iBAAiB,MAAM,KAAK,CAAC,iBAAiB,wEAAwE,KAAK,GAAG,MAAM,GAAG,MAAM,SAAS,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC;QAC/P,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACZ,OAAO,OAAO,KAAK,OAAO,CAAC;IAC7B,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,gCAAgC,KAAK,CAAC,KAAK,CAAC,IAAI,kBAAkB,KAAK,CAAC,WAAW,mFAAmF,IAAI,gBAAgB,CAAC;AACpM,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function escapeText(value) {
|
|
2
|
+
return value
|
|
3
|
+
.replaceAll('&', '&')
|
|
4
|
+
.replaceAll('<', '<')
|
|
5
|
+
.replaceAll('>', '>');
|
|
6
|
+
}
|
|
7
|
+
export function escapeAttribute(value) {
|
|
8
|
+
return escapeText(value).replaceAll('"', '"').replaceAll("'", ''');
|
|
9
|
+
}
|
|
10
|
+
export function safeLink(value) {
|
|
11
|
+
try {
|
|
12
|
+
const url = new URL(value);
|
|
13
|
+
return url.protocol === 'https:' || url.protocol === 'http:' ? url.toString() : null;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=escape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape.js","sourceRoot":"","sources":["../../../src/email/escape.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACvF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|