@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,70 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
/** Opaque reply addresses route a response without exposing a user or session id. */
|
|
3
|
+
export class EmailThreadAddressing {
|
|
4
|
+
#secret;
|
|
5
|
+
#local;
|
|
6
|
+
#domain;
|
|
7
|
+
inboxAddress;
|
|
8
|
+
constructor(secret, inboxAddress) {
|
|
9
|
+
if (typeof secret !== 'string' || secret.length < 32) {
|
|
10
|
+
throw new Error('Email thread secret must contain at least 32 characters');
|
|
11
|
+
}
|
|
12
|
+
const inbox = email(inboxAddress).toLowerCase();
|
|
13
|
+
const at = inbox.lastIndexOf('@');
|
|
14
|
+
this.#secret = secret;
|
|
15
|
+
this.#local = inbox.slice(0, at);
|
|
16
|
+
this.#domain = inbox.slice(at + 1);
|
|
17
|
+
this.inboxAddress = inbox;
|
|
18
|
+
}
|
|
19
|
+
async replyAddress(threadId) {
|
|
20
|
+
const compact = compactUuid(threadId);
|
|
21
|
+
return `${this.#local}+r${compact}.${await this.#signature(compact)}@${this.#domain}`;
|
|
22
|
+
}
|
|
23
|
+
async threadHint(recipients) {
|
|
24
|
+
const prefix = `${this.#local}+r`;
|
|
25
|
+
for (const raw of recipients) {
|
|
26
|
+
const address = email(raw, false);
|
|
27
|
+
if (!address)
|
|
28
|
+
continue;
|
|
29
|
+
const at = address.lastIndexOf('@');
|
|
30
|
+
if (address.slice(at + 1).toLowerCase() !== this.#domain)
|
|
31
|
+
continue;
|
|
32
|
+
const local = address.slice(0, at);
|
|
33
|
+
if (!local.toLowerCase().startsWith(prefix))
|
|
34
|
+
continue;
|
|
35
|
+
const [compact, received] = local.slice(prefix.length).split('.');
|
|
36
|
+
const normalizedCompact = compact?.toLowerCase();
|
|
37
|
+
if (!normalizedCompact || !received || !/^[0-9a-f]{32}$/.test(normalizedCompact))
|
|
38
|
+
continue;
|
|
39
|
+
if (!constantTime(received, await this.#signature(normalizedCompact)))
|
|
40
|
+
continue;
|
|
41
|
+
return `${normalizedCompact.slice(0, 8)}-${normalizedCompact.slice(8, 12)}-${normalizedCompact.slice(12, 16)}-${normalizedCompact.slice(16, 20)}-${normalizedCompact.slice(20)}`;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
async #signature(compact) {
|
|
46
|
+
return createHmac('sha256', this.#secret).update(compact).digest().subarray(0, 16).toString('base64url');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function compactUuid(value) {
|
|
50
|
+
const compact = String(value).trim().toLowerCase().replaceAll('-', '');
|
|
51
|
+
if (!/^[0-9a-f]{32}$/.test(compact))
|
|
52
|
+
throw new Error('Email thread id must be a UUID');
|
|
53
|
+
return compact;
|
|
54
|
+
}
|
|
55
|
+
function email(value, required = true) {
|
|
56
|
+
const match = String(value).trim().match(/<?([^<>\s]+@[^<>\s]+)>?$/);
|
|
57
|
+
const address = match?.[1] ?? '';
|
|
58
|
+
if (!/^[^@]+@[^@]+$/.test(address)) {
|
|
59
|
+
if (!required)
|
|
60
|
+
return '';
|
|
61
|
+
throw new Error('Email inbox address is invalid');
|
|
62
|
+
}
|
|
63
|
+
return address;
|
|
64
|
+
}
|
|
65
|
+
function constantTime(left, right) {
|
|
66
|
+
const a = Buffer.from(left);
|
|
67
|
+
const b = Buffer.from(right);
|
|
68
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=thread-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-token.js","sourceRoot":"","sources":["../../../src/email/thread-token.ts"],"names":[],"mappings":"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"}
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export type ChannelsErrorCode = 'validation' | 'forbidden' | 'not_found' | 'provider' | 'internal';
|
|
1
|
+
export type ChannelsErrorCode = 'validation' | 'forbidden' | 'not_found' | 'provider' | 'internal' | 'runtime_unavailable' | 'runtime_transport' | 'runtime_unauthorized' | 'runtime_protocol';
|
|
2
2
|
export declare class ChannelsError extends Error {
|
|
3
3
|
readonly code: ChannelsErrorCode;
|
|
4
|
-
|
|
4
|
+
readonly status?: number | undefined;
|
|
5
|
+
constructor(code: ChannelsErrorCode, message: string, status?: number | undefined);
|
|
5
6
|
}
|
package/dist/src/errors.js
CHANGED
package/dist/src/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,aAAc,SAAQ,KAAK;IAE3B;IAEA;IAHX,YACW,IAAuB,EAChC,OAAe,EACN,MAAe;QAExB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,SAAI,GAAJ,IAAI,CAAmB;QAEvB,WAAM,GAAN,MAAM,CAAS;QAGxB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF"}
|
package/dist/src/http.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ChannelPrincipal, ChannelsService } from './contract.js';
|
|
2
|
+
import type { MachineInboxService } from './inbox/service.js';
|
|
2
3
|
export type AuthenticateChannelsRequest = (request: Request) => Promise<ChannelPrincipal>;
|
|
3
4
|
export declare function createChannelsApi(options: {
|
|
4
5
|
readonly service: ChannelsService;
|
|
5
6
|
readonly authenticate: AuthenticateChannelsRequest;
|
|
7
|
+
readonly inbox?: MachineInboxService;
|
|
6
8
|
}): (request: Request) => Promise<Response>;
|
package/dist/src/http.js
CHANGED
|
@@ -2,21 +2,57 @@ import { ChannelsError } from './errors.js';
|
|
|
2
2
|
export function createChannelsApi(options) {
|
|
3
3
|
return async (request) => {
|
|
4
4
|
try {
|
|
5
|
-
const
|
|
5
|
+
const principal = await options.authenticate(request);
|
|
6
|
+
const sdk = options.service.for(principal);
|
|
6
7
|
const url = new URL(request.url);
|
|
7
8
|
const parts = url.pathname.split('/').filter(Boolean).map(decodeURIComponent);
|
|
8
9
|
const method = request.method.toUpperCase();
|
|
9
10
|
if (parts[0] !== 'v1')
|
|
10
11
|
return json(404, { error: 'Not found' });
|
|
11
|
-
if (parts[1] === '
|
|
12
|
+
if (parts[1] === 'messages' && parts.length === 2 && method === 'POST') {
|
|
12
13
|
const body = await objectBody(request);
|
|
13
|
-
|
|
14
|
+
const sessionId = request.headers.get('x-amalgm-session-id')?.trim();
|
|
15
|
+
if (sessionId && !principal.computerId) {
|
|
16
|
+
throw new ChannelsError('forbidden', 'Session context requires machine identity');
|
|
17
|
+
}
|
|
18
|
+
return json(202, await sdk.send({
|
|
14
19
|
message: String(body.message ?? ''),
|
|
15
20
|
...(body.title === undefined ? {} : { title: String(body.title) }),
|
|
16
21
|
...(body.channel === undefined ? {} : { channel: body.channel }),
|
|
17
22
|
...(body.idempotencyKey === undefined ? {} : { idempotencyKey: String(body.idempotencyKey) }),
|
|
23
|
+
}, sessionId ? { sessionId } : {}));
|
|
24
|
+
}
|
|
25
|
+
if (parts[1] === 'machine' && parts[2] === 'events' && parts.length === 3 && method === 'GET') {
|
|
26
|
+
if (!options.inbox)
|
|
27
|
+
return json(404, { error: 'Not found' });
|
|
28
|
+
const machine = options.inbox.for(principal);
|
|
29
|
+
return eventResponse((signal) => machine.events(signal), request.signal);
|
|
30
|
+
}
|
|
31
|
+
if (parts[1] === 'machine' && parts[2] === 'inbox' && parts[3] === 'claim'
|
|
32
|
+
&& parts.length === 4 && method === 'POST') {
|
|
33
|
+
if (!options.inbox)
|
|
34
|
+
return json(404, { error: 'Not found' });
|
|
35
|
+
const body = await objectBody(request);
|
|
36
|
+
return json(200, await options.inbox.for(principal).claim({
|
|
37
|
+
...(body.leaseSeconds === undefined ? {} : { leaseSeconds: Number(body.leaseSeconds) }),
|
|
18
38
|
}));
|
|
19
39
|
}
|
|
40
|
+
if (parts[1] === 'machine' && parts[2] === 'inbox' && parts[3]
|
|
41
|
+
&& parts[4] === 'accept' && parts.length === 5 && method === 'POST') {
|
|
42
|
+
if (!options.inbox)
|
|
43
|
+
return json(404, { error: 'Not found' });
|
|
44
|
+
const body = await objectBody(request);
|
|
45
|
+
return json(200, await options.inbox.for(principal).accept({
|
|
46
|
+
id: parts[3], leaseToken: String(body.leaseToken ?? ''),
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
if (parts[1] === 'machine' && parts[2] === 'inbox' && parts[3]
|
|
50
|
+
&& parts[4] === 'release' && parts.length === 5 && method === 'POST') {
|
|
51
|
+
if (!options.inbox)
|
|
52
|
+
return json(404, { error: 'Not found' });
|
|
53
|
+
const body = await objectBody(request);
|
|
54
|
+
return json(200, await options.inbox.for(principal).release({ id: parts[3], leaseToken: String(body.leaseToken ?? '') }, String(body.error ?? '')));
|
|
55
|
+
}
|
|
20
56
|
if (parts[1] === 'deliveries' && parts.length === 2 && method === 'GET') {
|
|
21
57
|
return json(200, await sdk.list({
|
|
22
58
|
...(url.searchParams.has('status') ? { status: url.searchParams.get('status') } : {}),
|
|
@@ -40,6 +76,51 @@ export function createChannelsApi(options) {
|
|
|
40
76
|
}
|
|
41
77
|
};
|
|
42
78
|
}
|
|
79
|
+
function eventResponse(source, requestSignal) {
|
|
80
|
+
const encoder = new TextEncoder();
|
|
81
|
+
const abort = new AbortController();
|
|
82
|
+
const onRequestAbort = () => abort.abort();
|
|
83
|
+
requestSignal.addEventListener('abort', onRequestAbort, { once: true });
|
|
84
|
+
let heartbeat = null;
|
|
85
|
+
const stream = new ReadableStream({
|
|
86
|
+
start(controller) {
|
|
87
|
+
heartbeat = setInterval(() => controller.enqueue(encoder.encode(': keepalive\n\n')), 15_000);
|
|
88
|
+
heartbeat.unref?.();
|
|
89
|
+
void (async () => {
|
|
90
|
+
try {
|
|
91
|
+
for await (const event of source(abort.signal)) {
|
|
92
|
+
controller.enqueue(encoder.encode(`event: ${event}\ndata: {}\n\n`));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (!abort.signal.aborted)
|
|
97
|
+
controller.error(error);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
if (heartbeat)
|
|
101
|
+
clearInterval(heartbeat);
|
|
102
|
+
requestSignal.removeEventListener('abort', onRequestAbort);
|
|
103
|
+
if (!abort.signal.aborted)
|
|
104
|
+
controller.close();
|
|
105
|
+
}
|
|
106
|
+
})();
|
|
107
|
+
},
|
|
108
|
+
cancel() {
|
|
109
|
+
abort.abort();
|
|
110
|
+
if (heartbeat)
|
|
111
|
+
clearInterval(heartbeat);
|
|
112
|
+
requestSignal.removeEventListener('abort', onRequestAbort);
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
return new Response(stream, {
|
|
116
|
+
headers: {
|
|
117
|
+
'cache-control': 'no-cache, no-store',
|
|
118
|
+
connection: 'keep-alive',
|
|
119
|
+
'content-type': 'text/event-stream',
|
|
120
|
+
'x-accel-buffering': 'no',
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
43
124
|
async function objectBody(request) {
|
|
44
125
|
const body = await request.json().catch(() => null);
|
|
45
126
|
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
package/dist/src/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAK5C,MAAM,UAAU,iBAAiB,CAAC,OAIjC;IACC,OAAO,KAAK,EAAE,OAAgB,EAAqB,EAAE;QACnD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YACtD,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;YAC9E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;YAChE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACvE,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;gBACvC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,EAAE,IAAI,EAAE,CAAC;gBACrE,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;oBACvC,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,2CAA2C,CAAC,CAAC;gBACpF,CAAC;gBACD,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,IAAI,CAAC;oBAC9B,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;oBACnC,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBAClE,GAAG,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAgB,EAAE,CAAC;oBACzE,GAAG,CAAC,IAAI,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;iBAC9F,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtC,CAAC;YACD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC9F,IAAI,CAAC,OAAO,CAAC,KAAK;oBAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC7D,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC7C,OAAO,aAAa,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC3E,CAAC;YACD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO;mBACrE,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC7C,IAAI,CAAC,OAAO,CAAC,KAAK;oBAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC7D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;gBACvC,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC;oBACxD,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;iBACxF,CAAC,CAAC,CAAC;YACN,CAAC;YACD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC;mBACzD,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtE,IAAI,CAAC,OAAO,CAAC,KAAK;oBAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC7D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;gBACvC,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;oBACzD,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;iBACxD,CAAC,CAAC,CAAC;YACN,CAAC;YACD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC;mBACzD,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACvE,IAAI,CAAC,OAAO,CAAC,KAAK;oBAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC7D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;gBACvC,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,CACzD,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,EAC3D,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CACzB,CAAC,CAAC;YACL,CAAC;YACD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,YAAY,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACxE,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,IAAI,CAAC;oBAC9B,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC9F,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC1F,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC9F,CAAC,CAAC,CAAC;YACN,CAAC;YACD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,YAAY,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACpF,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBACzC,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;YAC/F,CAAC;YACD,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,aAAa;gBAAE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAChH,MAAM,IAAI,GAAG,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;YACzF,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE;gBAC3E,KAAK,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,sBAAsB,EAAE,IAAI;aACtF,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CACpB,MAAmE,EACnE,aAA0B;IAE1B,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IACpC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC3C,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,IAAI,SAAS,GAA0C,IAAI,CAAC;IAC5D,MAAM,MAAM,GAAG,IAAI,cAAc,CAAa;QAC5C,KAAK,CAAC,UAAU;YACd,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YAC7F,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;YACpB,KAAK,CAAC,KAAK,IAAI,EAAE;gBACf,IAAI,CAAC;oBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC/C,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,KAAK,gBAAgB,CAAC,CAAC,CAAC;oBACtE,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;wBAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACrD,CAAC;wBAAS,CAAC;oBACT,IAAI,SAAS;wBAAE,aAAa,CAAC,SAAS,CAAC,CAAC;oBACxC,aAAa,CAAC,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;oBAC3D,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;wBAAE,UAAU,CAAC,KAAK,EAAE,CAAC;gBAChD,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;QACP,CAAC;QACD,MAAM;YACJ,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,IAAI,SAAS;gBAAE,aAAa,CAAC,SAAS,CAAC,CAAC;YACxC,aAAa,CAAC,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QAC7D,CAAC;KACF,CAAC,CAAC;IACH,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;QAC1B,OAAO,EAAE;YACP,eAAe,EAAE,oBAAoB;YACrC,UAAU,EAAE,YAAY;YACxB,cAAc,EAAE,mBAAmB;YACnC,mBAAmB,EAAE,IAAI;SAC1B;KACF,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAgB;IACxC,MAAM,IAAI,GAAY,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC7D,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,oCAAoC,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,IAA+B,CAAC;AACzC,CAAC;AAED,SAAS,IAAI,CAAC,MAAc,EAAE,IAAa;IACzC,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,MAAM,CAAC,IAA2B;IACzC,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,GAAG,CAAC;IACtC,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,GAAG,CAAC;IACrC,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,GAAG,CAAC;IACrC,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,GAAG,CAAC;IACpC,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MachineInbox } from './contract.js';
|
|
2
|
+
export type MachineInboxHeaders = (method: string, url: string) => Promise<Readonly<Record<string, string>>> | Readonly<Record<string, string>>;
|
|
3
|
+
export declare function createMachineInboxClient(options: Readonly<{
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
headers: MachineInboxHeaders;
|
|
6
|
+
fetch?: typeof globalThis.fetch;
|
|
7
|
+
}>): MachineInbox;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { channelsApiError } from '../api-error.js';
|
|
2
|
+
export function createMachineInboxClient(options) {
|
|
3
|
+
const base = options.baseUrl.replace(/\/$/, '');
|
|
4
|
+
const fetch = options.fetch ?? globalThis.fetch;
|
|
5
|
+
async function request(path, body) {
|
|
6
|
+
const url = `${base}${path}`;
|
|
7
|
+
const response = await fetch(url, {
|
|
8
|
+
method: 'POST',
|
|
9
|
+
headers: {
|
|
10
|
+
accept: 'application/json',
|
|
11
|
+
'content-type': 'application/json',
|
|
12
|
+
...await options.headers('POST', url),
|
|
13
|
+
},
|
|
14
|
+
body: JSON.stringify(body),
|
|
15
|
+
});
|
|
16
|
+
const payload = await response.json().catch(() => ({}));
|
|
17
|
+
if (!response.ok)
|
|
18
|
+
throw channelsApiError(response.status, payload);
|
|
19
|
+
return payload;
|
|
20
|
+
}
|
|
21
|
+
const client = Object.freeze({
|
|
22
|
+
claim(input = {}) {
|
|
23
|
+
return request('/v1/machine/inbox/claim', input);
|
|
24
|
+
},
|
|
25
|
+
accept(message) {
|
|
26
|
+
return request(`/v1/machine/inbox/${encodeURIComponent(message.id)}/accept`, {
|
|
27
|
+
leaseToken: message.leaseToken,
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
release(message, error) {
|
|
31
|
+
return request(`/v1/machine/inbox/${encodeURIComponent(message.id)}/release`, {
|
|
32
|
+
leaseToken: message.leaseToken,
|
|
33
|
+
error,
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
events(signal) {
|
|
37
|
+
return eventStream(base, options.headers, fetch, signal);
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
return client;
|
|
41
|
+
}
|
|
42
|
+
async function* eventStream(base, headers, fetch, signal) {
|
|
43
|
+
const url = `${base}/v1/machine/events`;
|
|
44
|
+
const response = await fetch(url, {
|
|
45
|
+
method: 'GET',
|
|
46
|
+
headers: { accept: 'text/event-stream', ...await headers('GET', url) },
|
|
47
|
+
redirect: 'error',
|
|
48
|
+
signal,
|
|
49
|
+
});
|
|
50
|
+
if (!response.ok || !response.body) {
|
|
51
|
+
const payload = await response.json().catch(() => ({}));
|
|
52
|
+
throw channelsApiError(response.status, payload);
|
|
53
|
+
}
|
|
54
|
+
const decoder = new TextDecoder();
|
|
55
|
+
let buffer = '';
|
|
56
|
+
const reader = response.body.getReader();
|
|
57
|
+
try {
|
|
58
|
+
for (;;) {
|
|
59
|
+
const result = await reader.read();
|
|
60
|
+
if (result.done)
|
|
61
|
+
break;
|
|
62
|
+
buffer += decoder.decode(result.value, { stream: true }).replaceAll('\r\n', '\n');
|
|
63
|
+
for (;;) {
|
|
64
|
+
const boundary = buffer.indexOf('\n\n');
|
|
65
|
+
if (boundary < 0)
|
|
66
|
+
break;
|
|
67
|
+
const frame = buffer.slice(0, boundary);
|
|
68
|
+
buffer = buffer.slice(boundary + 2);
|
|
69
|
+
const event = frame.split('\n').find((line) => line.startsWith('event:'))?.slice(6).trim();
|
|
70
|
+
if (event === 'ready' || event === 'message')
|
|
71
|
+
yield event;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
reader.releaseLock();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/inbox/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface ClaimedInboundMessage {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly channel: 'email';
|
|
4
|
+
readonly threadId: string;
|
|
5
|
+
readonly sessionId: string;
|
|
6
|
+
readonly startsSession: boolean;
|
|
7
|
+
readonly subject: string;
|
|
8
|
+
readonly message: string;
|
|
9
|
+
readonly providerMessageId: string;
|
|
10
|
+
readonly receivedAt: string;
|
|
11
|
+
readonly leaseToken: string;
|
|
12
|
+
readonly attempts: number;
|
|
13
|
+
}
|
|
14
|
+
export interface InboundLease {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly leaseToken: string;
|
|
17
|
+
}
|
|
18
|
+
export interface MachineInbox {
|
|
19
|
+
claim(input?: Readonly<{
|
|
20
|
+
leaseSeconds?: number;
|
|
21
|
+
}>): Promise<readonly ClaimedInboundMessage[]>;
|
|
22
|
+
accept(message: InboundLease): Promise<boolean>;
|
|
23
|
+
release(message: InboundLease, error: string): Promise<boolean>;
|
|
24
|
+
events(signal: AbortSignal): AsyncIterable<'ready' | 'message'>;
|
|
25
|
+
}
|
|
26
|
+
export interface MachineInboxRepository {
|
|
27
|
+
claim(userId: string, computerId: string, limit: number, leaseSeconds: number): Promise<readonly ClaimedInboundMessage[]>;
|
|
28
|
+
accept(userId: string, computerId: string, message: InboundLease, now: Date): Promise<boolean>;
|
|
29
|
+
release(userId: string, computerId: string, message: InboundLease, error: string, now: Date): Promise<boolean>;
|
|
30
|
+
}
|
|
31
|
+
/** Admission returns after the local Chat turn exists durably, not after it finishes. */
|
|
32
|
+
export interface InboundExecutionAdmission {
|
|
33
|
+
readonly completion: Promise<unknown>;
|
|
34
|
+
}
|
|
35
|
+
export interface InboundMessageExecutor {
|
|
36
|
+
admit(message: ClaimedInboundMessage): Promise<InboundExecutionAdmission>;
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/inbox/contract.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MachineEventStream } from './service.js';
|
|
2
|
+
/** Process-local fanout. Durable inbox rows, not this hub, own correctness. */
|
|
3
|
+
export declare class MachineEventHub {
|
|
4
|
+
#private;
|
|
5
|
+
readonly stream: MachineEventStream;
|
|
6
|
+
publish(userId: string, computerId: string): void;
|
|
7
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Process-local fanout. Durable inbox rows, not this hub, own correctness. */
|
|
2
|
+
export class MachineEventHub {
|
|
3
|
+
#listeners = new Map();
|
|
4
|
+
stream = (userId, computerId, signal) => {
|
|
5
|
+
const key = `${userId}:${computerId}`;
|
|
6
|
+
const queue = ['ready'];
|
|
7
|
+
let resume = null;
|
|
8
|
+
const listener = (event) => {
|
|
9
|
+
queue.push(event);
|
|
10
|
+
resume?.();
|
|
11
|
+
resume = null;
|
|
12
|
+
};
|
|
13
|
+
const listeners = this.#listeners.get(key) ?? new Set();
|
|
14
|
+
listeners.add(listener);
|
|
15
|
+
this.#listeners.set(key, listeners);
|
|
16
|
+
return iterable(queue, signal, () => {
|
|
17
|
+
resume?.();
|
|
18
|
+
resume = null;
|
|
19
|
+
}, (next) => { resume = next; }, () => {
|
|
20
|
+
listeners.delete(listener);
|
|
21
|
+
if (!listeners.size)
|
|
22
|
+
this.#listeners.delete(key);
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
publish(userId, computerId) {
|
|
26
|
+
for (const listener of this.#listeners.get(`${userId}:${computerId}`) ?? [])
|
|
27
|
+
listener('message');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function* iterable(queue, signal, abort, wait, close) {
|
|
31
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
32
|
+
try {
|
|
33
|
+
while (!signal.aborted) {
|
|
34
|
+
const event = queue.shift();
|
|
35
|
+
if (event)
|
|
36
|
+
yield event;
|
|
37
|
+
else
|
|
38
|
+
await new Promise((resolve) => wait(resolve));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
signal.removeEventListener('abort', abort);
|
|
43
|
+
close();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/inbox/events.ts"],"names":[],"mappings":"AAKA,+EAA+E;AAC/E,MAAM,OAAO,eAAe;IACjB,UAAU,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE9C,MAAM,GAAuB,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE;QACnE,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;QACtC,MAAM,KAAK,GAAY,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,MAAM,GAAwB,IAAI,CAAC;QACvC,MAAM,QAAQ,GAAa,CAAC,KAAK,EAAE,EAAE;YACnC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClB,MAAM,EAAE,EAAE,CAAC;YACX,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,EAAY,CAAC;QAClE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACpC,OAAO,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE;YAClC,MAAM,EAAE,EAAE,CAAC;YACX,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE;YACpC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,IAAI;gBAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,CAAC,MAAc,EAAE,UAAkB;QACxC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC,IAAI,EAAE;YAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IACnG,CAAC;CACF;AAED,KAAK,SAAS,CAAC,CAAC,QAAQ,CACtB,KAAc,EACd,MAAmB,EACnB,KAAiB,EACjB,IAAkC,EAClC,KAAiB;IAEjB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,KAAK;gBAAE,MAAM,KAAK,CAAC;;gBAClB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC3C,KAAK,EAAE,CAAC;IACV,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { InboundMessageExecutor, MachineInbox } from './contract.js';
|
|
2
|
+
export interface ChannelMachineRunnerOptions {
|
|
3
|
+
readonly inbox: MachineInbox;
|
|
4
|
+
readonly executor: InboundMessageExecutor;
|
|
5
|
+
readonly leaseSeconds?: number;
|
|
6
|
+
readonly reconnectMaxMs?: number;
|
|
7
|
+
readonly log?: (event: string, details?: Readonly<Record<string, unknown>>) => void;
|
|
8
|
+
}
|
|
9
|
+
/** Event-driven machine claimant. The only retry timer reconnects the event stream. */
|
|
10
|
+
export declare function createChannelMachineRunner(options: ChannelMachineRunnerOptions): Readonly<{
|
|
11
|
+
start(): void;
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
drain: () => Promise<void>;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** Event-driven machine claimant. The only retry timer reconnects the event stream. */
|
|
2
|
+
export function createChannelMachineRunner(options) {
|
|
3
|
+
const leaseSeconds = integer(options.leaseSeconds ?? 60, 30, 900, 'leaseSeconds');
|
|
4
|
+
const reconnectMaxMs = integer(options.reconnectMaxMs ?? 30_000, 1_000, 300_000, 'reconnectMaxMs');
|
|
5
|
+
const log = options.log ?? (() => { });
|
|
6
|
+
let controller = null;
|
|
7
|
+
let running = null;
|
|
8
|
+
const drain = async () => {
|
|
9
|
+
for (;;) {
|
|
10
|
+
const [message] = await options.inbox.claim({ leaseSeconds });
|
|
11
|
+
if (!message)
|
|
12
|
+
return;
|
|
13
|
+
try {
|
|
14
|
+
const admitted = await options.executor.admit(message);
|
|
15
|
+
if (!await options.inbox.accept(message)) {
|
|
16
|
+
throw new Error('Inbound acceptance lease was lost');
|
|
17
|
+
}
|
|
18
|
+
log('channels.inbound.accepted', {
|
|
19
|
+
messageId: message.id,
|
|
20
|
+
threadId: message.threadId,
|
|
21
|
+
sessionId: message.sessionId,
|
|
22
|
+
});
|
|
23
|
+
await admitted.completion.catch((error) => {
|
|
24
|
+
log('channels.inbound.turn.failed', { messageId: message.id, error: safe(error) });
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
await options.inbox.release(message, safe(error)).catch(() => false);
|
|
29
|
+
log('channels.inbound.released', { messageId: message.id, error: safe(error) });
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const loop = async (signal) => {
|
|
35
|
+
let failures = 0;
|
|
36
|
+
while (!signal.aborted) {
|
|
37
|
+
try {
|
|
38
|
+
await drain();
|
|
39
|
+
for await (const _event of options.inbox.events(signal)) {
|
|
40
|
+
failures = 0;
|
|
41
|
+
await drain();
|
|
42
|
+
}
|
|
43
|
+
if (!signal.aborted)
|
|
44
|
+
throw new Error('Channels event stream closed');
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (signal.aborted)
|
|
48
|
+
return;
|
|
49
|
+
failures += 1;
|
|
50
|
+
const retryInMs = Math.min(reconnectMaxMs, 1_000 * (2 ** Math.min(failures - 1, 8)));
|
|
51
|
+
log('channels.events.disconnected', { error: safe(error), retryInMs });
|
|
52
|
+
await wait(retryInMs, signal);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
return Object.freeze({
|
|
57
|
+
start() {
|
|
58
|
+
if (running)
|
|
59
|
+
return;
|
|
60
|
+
controller = new AbortController();
|
|
61
|
+
running = loop(controller.signal).finally(() => { running = null; controller = null; });
|
|
62
|
+
},
|
|
63
|
+
async close() {
|
|
64
|
+
controller?.abort();
|
|
65
|
+
await running;
|
|
66
|
+
},
|
|
67
|
+
drain,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function integer(value, minimum, maximum, name) {
|
|
71
|
+
if (!Number.isInteger(value) || value < minimum || value > maximum) {
|
|
72
|
+
throw new Error(`${name} must be an integer from ${minimum} to ${maximum}`);
|
|
73
|
+
}
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
function safe(error) {
|
|
77
|
+
return (error instanceof Error ? error.message : String(error)).replace(/[\r\n]+/g, ' ').slice(0, 500);
|
|
78
|
+
}
|
|
79
|
+
function wait(milliseconds, signal) {
|
|
80
|
+
return new Promise((resolve) => {
|
|
81
|
+
if (signal.aborted)
|
|
82
|
+
return resolve();
|
|
83
|
+
const timer = setTimeout(done, milliseconds);
|
|
84
|
+
const abort = () => done();
|
|
85
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
86
|
+
function done() {
|
|
87
|
+
clearTimeout(timer);
|
|
88
|
+
signal.removeEventListener('abort', abort);
|
|
89
|
+
resolve();
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/inbox/runner.ts"],"names":[],"mappings":"AAUA,uFAAuF;AACvF,MAAM,UAAU,0BAA0B,CAAC,OAAoC;IAC7E,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;IAClF,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,IAAI,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;IACnG,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACtC,IAAI,UAAU,GAA2B,IAAI,CAAC;IAC9C,IAAI,OAAO,GAAyB,IAAI,CAAC;IAEzC,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;QACvB,SAAS,CAAC;YACR,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC;YAC9D,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACvD,IAAI,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;oBACzC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBACvD,CAAC;gBACD,GAAG,CAAC,2BAA2B,EAAE;oBAC/B,SAAS,EAAE,OAAO,CAAC,EAAE;oBACrB,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;iBAC7B,CAAC,CAAC;gBACH,MAAM,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBACxC,GAAG,CAAC,8BAA8B,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACrF,CAAC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;gBACrE,GAAG,CAAC,2BAA2B,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAChF,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,KAAK,EAAE,MAAmB,EAAE,EAAE;QACzC,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,KAAK,EAAE,CAAC;gBACd,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;oBACxD,QAAQ,GAAG,CAAC,CAAC;oBACb,MAAM,KAAK,EAAE,CAAC;gBAChB,CAAC;gBACD,IAAI,CAAC,MAAM,CAAC,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YACvE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,MAAM,CAAC,OAAO;oBAAE,OAAO;gBAC3B,QAAQ,IAAI,CAAC,CAAC;gBACd,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrF,GAAG,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;gBACvE,MAAM,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,KAAK;YACH,IAAI,OAAO;gBAAE,OAAO;YACpB,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACnC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,CAAC;QACD,KAAK,CAAC,KAAK;YACT,UAAU,EAAE,KAAK,EAAE,CAAC;YACpB,MAAM,OAAO,CAAC;QAChB,CAAC;QACD,KAAK;KACN,CAAC,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,KAAa,EAAE,OAAe,EAAE,OAAe,EAAE,IAAY;IAC5E,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,OAAO,IAAI,KAAK,GAAG,OAAO,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,4BAA4B,OAAO,OAAO,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,IAAI,CAAC,KAAc;IAC1B,OAAO,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACzG,CAAC;AAED,SAAS,IAAI,CAAC,YAAoB,EAAE,MAAmB;IACrD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,OAAO,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,SAAS,IAAI;YACX,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC3C,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ChannelPrincipal } from '../contract.js';
|
|
2
|
+
import type { MachineInbox, MachineInboxRepository } from './contract.js';
|
|
3
|
+
export type MachineEventStream = (userId: string, computerId: string, signal: AbortSignal) => AsyncIterable<'ready' | 'message'>;
|
|
4
|
+
export interface MachineInboxService {
|
|
5
|
+
for(principal: ChannelPrincipal): MachineInbox;
|
|
6
|
+
}
|
|
7
|
+
export declare function createMachineInboxService(repository: MachineInboxRepository, events: MachineEventStream, options?: Readonly<{
|
|
8
|
+
now?: () => Date;
|
|
9
|
+
}>): MachineInboxService;
|